Add avatar-menu navigation style and inline Android search bar

- New Settings > Appearance > "Navigation menu" toggle
  (SettingsController.navMenuStyle, NooNavMenuStyle.drawer/avatarMenu):
  the hamburger-opens-a-Drawer pattern stays the default, or the avatar
  button opens a full-width dropdown (showAvatarMenu) instead, holding
  the same hidden-tabs + Settings content the drawer does. Removes one
  of the two top-corner targets the shell asks a thumb to reach, with
  no permanent chrome added.
- NooTopBar gains androidTitleReplacement so Android's top bar can swap
  its title for an inline search-field-styled launcher
  (ShellSearchLauncher) when search isn't in the bottom bar, instead of
  a bare search icon beside it.
- ShellAvatarButton's onTap/label are now overridable so AppTopBar can
  repoint it per the new setting without this file depending on
  avatar_menu.dart (which already depends on it for shared helpers).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-30 22:25:04 -04:00
co-authored by Claude Sonnet 5
parent 840ec4c301
commit e6d96a6f9f
11 changed files with 550 additions and 25 deletions
+17
View File
@@ -32,6 +32,7 @@ class SettingsController extends ChangeNotifier {
static const _prefSwipeLeftAction = 'ui_swipe_left_action';
static const _prefSwipeRightAction = 'ui_swipe_right_action';
static const _prefBottomBarStyle = 'ui_bottom_bar_style';
static const _prefNavMenuStyle = 'ui_nav_menu_style';
static const _prefSearchInBottomBar = 'ui_search_in_bottom_bar';
static const _prefAmoledDark = 'ui_amoled_dark';
static const _prefMediaProgressBarStyle = 'ui_media_progress_bar_style';
@@ -43,6 +44,7 @@ class SettingsController extends ChangeNotifier {
Color _seedColor = AppTheme.defaultAccent;
ThemeMode _themeMode = ThemeMode.system;
NooBottomBarStyle _bottomBarStyle = NooBottomBarStyle.attached;
NooNavMenuStyle _navMenuStyle = NooNavMenuStyle.drawer;
bool _searchInBottomBar = false;
bool _useDynamicColor = true;
bool _amoledDark = false;
@@ -86,6 +88,7 @@ class SettingsController extends ChangeNotifier {
Color get seedColor => _seedColor;
ThemeMode get themeMode => _themeMode;
NooBottomBarStyle get bottomBarStyle => _bottomBarStyle;
NooNavMenuStyle get navMenuStyle => _navMenuStyle;
bool get searchInBottomBar => _searchInBottomBar;
bool get useDynamicColor => _useDynamicColor;
bool get amoledDark => _amoledDark;
@@ -137,6 +140,13 @@ class SettingsController extends ChangeNotifier {
orElse: () => _bottomBarStyle,
);
}
final navMenuStyleName = prefs.getString(_prefNavMenuStyle);
if (navMenuStyleName != null) {
_navMenuStyle = NooNavMenuStyle.values.firstWhere(
(s) => s.name == navMenuStyleName,
orElse: () => _navMenuStyle,
);
}
_searchInBottomBar =
prefs.getBool(_prefSearchInBottomBar) ?? _searchInBottomBar;
_useDynamicColor =
@@ -287,6 +297,13 @@ class SettingsController extends ChangeNotifier {
_prefsFuture.then((p) => p.setString(_prefBottomBarStyle, style.name));
}
void setNavMenuStyle(NooNavMenuStyle style) {
if (_navMenuStyle == style) return;
_navMenuStyle = style;
notifyListeners();
_prefsFuture.then((p) => p.setString(_prefNavMenuStyle, style.name));
}
/// Turning this on lowers [maxVisibleTabs] by one, so re-enforces the cap
/// immediately in case the user already has a full 5 regular tabs pinned
/// - same cleanup [_enforceMaxVisibleTabs] already does for a fresh