From 25f53e0d864259c06f07e3b7dd093f8631e7f596 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Tue, 20 Jan 2026 22:35:59 +1100 Subject: [PATCH 1/4] Move preferences button to About dialog --- lib/src/widgets/solid_about_button.dart | 20 +++++++++ lib/src/widgets/solid_about_models.dart | 6 +++ .../widgets/solid_overflow_menu_helpers.dart | 19 -------- lib/src/widgets/solid_scaffold.dart | 5 --- .../solid_scaffold_appbar_actions.dart | 18 +------- .../solid_scaffold_appbar_builder.dart | 43 +----------------- ...solid_scaffold_appbar_ordered_actions.dart | 45 ------------------- .../solid_scaffold_appbar_overflow.dart | 41 ----------------- lib/src/widgets/solid_scaffold_helpers.dart | 4 -- .../solid_scaffold_widget_builder.dart | 1 - 10 files changed, 29 insertions(+), 173 deletions(-) diff --git a/lib/src/widgets/solid_about_button.dart b/lib/src/widgets/solid_about_button.dart index f62b994..b5f65b0 100644 --- a/lib/src/widgets/solid_about_button.dart +++ b/lib/src/widgets/solid_about_button.dart @@ -40,6 +40,7 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:solidui/src/constants/about.dart'; import 'package:solidui/src/widgets/solid_about_models.dart'; +import 'package:solidui/src/widgets/solid_preferences_dialog.dart'; /// A button that shows an About dialogue when pressed. @@ -304,6 +305,25 @@ class SolidAbout { children.addAll(config.children ?? []); } + // Add Layout Preferences button if enabled. + + if (config.showLayoutPreferences) { + children.add(const Gap(AboutConstants.contentVerticalSpacing)); + children.add(const Divider()); + children.add( + Builder( + builder: (dialogContext) => TextButton.icon( + icon: const Icon(Icons.tune), + label: const Text('AppBar Layout Preferences'), + onPressed: () { + Navigator.of(dialogContext).pop(); + SolidPreferencesDialog.show(context); + }, + ), + ), + ); + } + showAboutDialog( context: context, applicationName: applicationName, diff --git a/lib/src/widgets/solid_about_models.dart b/lib/src/widgets/solid_about_models.dart index d37784d..833e7b3 100644 --- a/lib/src/widgets/solid_about_models.dart +++ b/lib/src/widgets/solid_about_models.dart @@ -95,6 +95,11 @@ class SolidAboutConfig { final VoidCallback? onPressed; + /// Whether to show Layout Preferences button in the About dialogue. + /// Defaults to true, allowing users to configure AppBar button layout. + + final bool showLayoutPreferences; + const SolidAboutConfig({ this.enabled = true, this.icon, @@ -110,6 +115,7 @@ class SolidAboutConfig { this.priority = 999, this.tooltip, this.onPressed, + this.showLayoutPreferences = true, }); /// Returns the icon to display for the About button. diff --git a/lib/src/widgets/solid_overflow_menu_helpers.dart b/lib/src/widgets/solid_overflow_menu_helpers.dart index b5f7596..62475f1 100644 --- a/lib/src/widgets/solid_overflow_menu_helpers.dart +++ b/lib/src/widgets/solid_overflow_menu_helpers.dart @@ -52,7 +52,6 @@ class SolidOverflowMenuHelpers { SolidAboutConfig aboutConfig, bool hasThemeToggleInOverflow, bool hasAboutInOverflow, { - bool hasPreferencesInOverflow = false, bool hasLogoutInOverflow = false, }) { List> items = []; @@ -72,8 +71,6 @@ class SolidOverflowMenuHelpers { ); } else if (actionItem.id == SolidAppBarActionIds.logout) { _addLogout(items, hasLogoutInOverflow); - } else if (actionItem.id == SolidAppBarActionIds.preferences) { - _addPreferences(items, hasPreferencesInOverflow); } else if (actionItem.id == SolidAppBarActionIds.about) { _addAbout(items, hasAboutInOverflow, aboutConfig); } else if (actionItem.id.startsWith('action_')) { @@ -137,22 +134,6 @@ class SolidOverflowMenuHelpers { ); } - static void _addPreferences(List> items, bool show) { - if (!show) return; - items.add( - const PopupMenuItem( - value: 'preferences', - child: Row( - children: [ - Icon(Icons.tune), - SizedBox(width: 8), - Text('AppBar Layout Preferences'), - ], - ), - ), - ); - } - static void _addAbout( List> items, bool show, diff --git a/lib/src/widgets/solid_scaffold.dart b/lib/src/widgets/solid_scaffold.dart index bb63eb1..8b02991 100644 --- a/lib/src/widgets/solid_scaffold.dart +++ b/lib/src/widgets/solid_scaffold.dart @@ -247,10 +247,6 @@ class SolidScaffold extends StatefulWidget { final bool hideNavRail; - /// Whether to show the AppBar Layout Preferences button. - - final bool showAppBarLayoutPreferences; - const SolidScaffold({ super.key, this.menu, @@ -293,7 +289,6 @@ class SolidScaffold extends StatefulWidget { this.themeToggle, this.aboutConfig, this.hideNavRail = false, - this.showAppBarLayoutPreferences = false, }); @override diff --git a/lib/src/widgets/solid_scaffold_appbar_actions.dart b/lib/src/widgets/solid_scaffold_appbar_actions.dart index 6c4e0f8..18097e8 100644 --- a/lib/src/widgets/solid_scaffold_appbar_actions.dart +++ b/lib/src/widgets/solid_scaffold_appbar_actions.dart @@ -119,21 +119,6 @@ class SolidAppBarActionsManager { ); } - // Add AppBar Layout Preferences button. - // Default: show in AppBar, after custom actions but before Logout/About. - - actionEntries.add( - _ActionEntry( - item: const SolidAppBarActionItem( - id: SolidAppBarActionIds.preferences, - label: 'AppBar Layout Preferences', - icon: Icons.tune, - showInOverflow: false, // Show in AppBar by default. - ), - initialIndex: 300, // Layout Preferences after custom/overflow actions. - ), - ); - // Add Logout button. // Default: show in AppBar. @@ -145,7 +130,7 @@ class SolidAppBarActionsManager { icon: Icons.logout, showInOverflow: false, // Show in AppBar by default. ), - initialIndex: 400, // Logout button after Preferences. + initialIndex: 300, // Logout button after custom/overflow actions. ), ); @@ -220,7 +205,6 @@ class SolidAppBarActionsManager { expectedIds.addAll([ SolidAppBarActionIds.logout, SolidAppBarActionIds.about, - SolidAppBarActionIds.preferences, ]); // Check if any expected ID is missing. diff --git a/lib/src/widgets/solid_scaffold_appbar_builder.dart b/lib/src/widgets/solid_scaffold_appbar_builder.dart index 61b4047..3bb2996 100644 --- a/lib/src/widgets/solid_scaffold_appbar_builder.dart +++ b/lib/src/widgets/solid_scaffold_appbar_builder.dart @@ -31,11 +31,9 @@ library; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; -import 'package:markdown_tooltip/markdown_tooltip.dart'; import 'package:solidui/src/widgets/solid_about_models.dart'; import 'package:solidui/src/widgets/solid_nav_models.dart'; -import 'package:solidui/src/widgets/solid_preferences_dialog.dart'; import 'package:solidui/src/widgets/solid_scaffold_appbar_actions.dart'; import 'package:solidui/src/widgets/solid_scaffold_appbar_ordered_actions.dart'; import 'package:solidui/src/widgets/solid_scaffold_appbar_overflow.dart'; @@ -59,8 +57,9 @@ class SolidScaffoldAppBarBuilder { double narrowScreenThreshold, { bool hideNavRail = false, void Function(BuildContext)? onLogout, - bool showPreferences = false, }) { + SolidAppBarActionsManager.initializeIfNeeded(config, themeToggle); + final isWideScreen = !hideNavRail && SolidScaffoldHelpers.isWideScreen( context, @@ -98,9 +97,7 @@ class SolidScaffoldAppBarBuilder { themeToggleCallback: themeToggleCallback, aboutConfig: aboutConfig, context: context, - showPreferences: showPreferences, onLogout: onLogout, - buildPreferencesButton: _buildPreferencesButton, ); actions.addAll(orderedActions); @@ -115,9 +112,7 @@ class SolidScaffoldAppBarBuilder { themeToggleCallback, aboutConfig, context, - showPreferences: showPreferences, onLogout: onLogout, - onShowPreferences: _showPreferencesDialog, ); return AppBar( @@ -127,38 +122,4 @@ class SolidScaffoldAppBarBuilder { actions: actions.isEmpty ? null : actions, ); } - - /// Builds the layout preferences button for AppBar. - - static Widget _buildPreferencesButton( - BuildContext context, - SolidAppBarConfig config, - SolidThemeToggleConfig? themeToggle, - ) { - return MarkdownTooltip( - message: ''' - - **AppBar Layout Preferences:** Configure button layout settings. - Customise the AppBar button order and visibility. - - ''', - child: IconButton( - icon: const Icon(Icons.tune), - onPressed: () => _showPreferencesDialog(context, config, themeToggle), - ), - ); - } - - /// Shows the AppBar layout preferences dialogue. - - static void _showPreferencesDialog( - BuildContext context, - SolidAppBarConfig config, - SolidThemeToggleConfig? themeToggle, - ) { - // Initialise AppBar actions in preferences if not already done. - - SolidAppBarActionsManager.initializeIfNeeded(config, themeToggle); - SolidPreferencesDialog.show(context); - } } diff --git a/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart b/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart index 6ffc652..4a5c022 100644 --- a/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart +++ b/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart @@ -57,12 +57,6 @@ class SolidAppBarOrderedActionsBuilder { required VoidCallback? themeToggleCallback, required SolidAboutConfig aboutConfig, required BuildContext context, - required bool showPreferences, - required Widget Function( - BuildContext, - SolidAppBarConfig, - SolidThemeToggleConfig?, - ) buildPreferencesButton, void Function(BuildContext)? onLogout, }) { final List<_OrderedAction> orderedActions = []; @@ -78,15 +72,6 @@ class SolidAppBarOrderedActionsBuilder { themeToggleCallback, ); _addCustomActions(orderedActions, config, screenWidth, isNarrowScreen); - _addPreferencesButton( - orderedActions, - showPreferences, - isNarrowScreen, - context, - config, - themeToggle, - buildPreferencesButton, - ); _addOverflowItems(orderedActions, config, isNarrowScreen); _addLogoutButton(orderedActions, onLogout, isNarrowScreen, context); _addAboutButton( @@ -182,36 +167,6 @@ class SolidAppBarOrderedActionsBuilder { } } - static void _addPreferencesButton( - List<_OrderedAction> orderedActions, - bool showPreferences, - bool isNarrowScreen, - BuildContext context, - SolidAppBarConfig config, - SolidThemeToggleConfig? themeToggle, - Widget Function(BuildContext, SolidAppBarConfig, SolidThemeToggleConfig?) - buildPreferencesButton, - ) { - if (!showPreferences) return; - - final actionConfig = SolidAppBarActionsManager.getActionConfig( - SolidAppBarActionIds.preferences, - ); - - const isVisible = true; // Preferences button cannot be hidden. - final isInOverflow = actionConfig?.showInOverflow ?? false; - final order = actionConfig?.order ?? 300; - - if (isVisible && (!isNarrowScreen || !isInOverflow)) { - orderedActions.add( - _OrderedAction( - order: order, - widget: buildPreferencesButton(context, config, themeToggle), - ), - ); - } - } - static void _addOverflowItems( List<_OrderedAction> orderedActions, SolidAppBarConfig config, diff --git a/lib/src/widgets/solid_scaffold_appbar_overflow.dart b/lib/src/widgets/solid_scaffold_appbar_overflow.dart index 86fd20f..86e2c06 100644 --- a/lib/src/widgets/solid_scaffold_appbar_overflow.dart +++ b/lib/src/widgets/solid_scaffold_appbar_overflow.dart @@ -52,13 +52,7 @@ class SolidAppBarOverflowHandler { VoidCallback? themeToggleCallback, SolidAboutConfig aboutConfig, BuildContext context, { - bool showPreferences = false, void Function(BuildContext)? onLogout, - required void Function( - BuildContext, - SolidAppBarConfig, - SolidThemeToggleConfig?, - ) onShowPreferences, }) { // Use narrowScreenThreshold to determine when to show overflow menu. @@ -85,16 +79,11 @@ class SolidAppBarOverflowHandler { forceOverflow: true, ), context, - hasPreferencesInOverflow: shouldShowPreferencesInOverflow( - showPreferences, - forceOverflow: true, - ), hasLogoutInOverflow: shouldShowLogoutInOverflow( onLogout != null, forceOverflow: true, ), onLogout: onLogout, - onShowPreferences: onShowPreferences, ), ); } @@ -163,27 +152,6 @@ class SolidAppBarOverflowHandler { return isInOverflow; } - /// Determines if preferences should be shown in overflow menu. - - static bool shouldShowPreferencesInOverflow( - bool showPreferences, { - bool forceOverflow = false, - }) { - if (!showPreferences) return false; - final actionConfig = SolidAppBarActionsManager.getActionConfig( - SolidAppBarActionIds.preferences, - ); - // Preferences button is always visible (forced true). - - final isInOverflow = actionConfig?.showInOverflow ?? false; - - // On narrow screens, only show in overflow if showInOverflow = true. - // Buttons marked as "add to appbar" (showInOverflow = false) stay in AppBar. - - if (forceOverflow) return isInOverflow; - return isInOverflow; - } - /// Builds the overflow menu. /// Uses Builder to ensure context is valid during callbacks. @@ -196,14 +164,8 @@ class SolidAppBarOverflowHandler { bool hasThemeToggleInOverflow, bool hasAboutInOverflow, BuildContext parentContext, { - bool hasPreferencesInOverflow = false, bool hasLogoutInOverflow = false, void Function(BuildContext)? onLogout, - required void Function( - BuildContext, - SolidAppBarConfig, - SolidThemeToggleConfig?, - ) onShowPreferences, }) { final overflowMenuItems = SolidScaffoldHelpers.buildOverflowMenuItems( config, @@ -212,7 +174,6 @@ class SolidAppBarOverflowHandler { aboutConfig, hasThemeToggleInOverflow, hasAboutInOverflow, - hasPreferencesInOverflow: hasPreferencesInOverflow, hasLogoutInOverflow: hasLogoutInOverflow, ); @@ -237,8 +198,6 @@ class SolidAppBarOverflowHandler { SolidAbout.show(context, aboutConfig); } - } else if (id == 'preferences') { - onShowPreferences(context, config, themeToggle); } else if (id == 'logout') { onLogout?.call(context); } else if (id.startsWith('action_')) { diff --git a/lib/src/widgets/solid_scaffold_helpers.dart b/lib/src/widgets/solid_scaffold_helpers.dart index 95a7f97..f1a82ab 100644 --- a/lib/src/widgets/solid_scaffold_helpers.dart +++ b/lib/src/widgets/solid_scaffold_helpers.dart @@ -132,7 +132,6 @@ class SolidScaffoldHelpers { SolidAboutConfig aboutConfig, bool hasThemeToggleInOverflow, bool hasAboutInOverflow, { - bool hasPreferencesInOverflow = false, bool hasLogoutInOverflow = false, }) => SolidOverflowMenuHelpers.buildOverflowMenuItems( @@ -142,7 +141,6 @@ class SolidScaffoldHelpers { aboutConfig, hasThemeToggleInOverflow, hasAboutInOverflow, - hasPreferencesInOverflow: hasPreferencesInOverflow, hasLogoutInOverflow: hasLogoutInOverflow, ); @@ -255,7 +253,6 @@ class SolidScaffoldHelpers { String Function() getVersionToDisplay, { bool hideNavRail = false, void Function(BuildContext)? onLogout, - bool showPreferences = false, }) { if (appBar == null) return null; if (appBar is! SolidAppBarConfig) return null; @@ -271,7 +268,6 @@ class SolidScaffoldHelpers { narrowScreenThreshold, hideNavRail: hideNavRail, onLogout: onLogout, - showPreferences: showPreferences, ); } diff --git a/lib/src/widgets/solid_scaffold_widget_builder.dart b/lib/src/widgets/solid_scaffold_widget_builder.dart index a6085e7..e7aabe5 100644 --- a/lib/src/widgets/solid_scaffold_widget_builder.dart +++ b/lib/src/widgets/solid_scaffold_widget_builder.dart @@ -115,7 +115,6 @@ class SolidScaffoldWidgetBuilder { getVersionToDisplay, hideNavRail: widget.hideNavRail, onLogout: widget.onLogout, - showPreferences: widget.showAppBarLayoutPreferences, ), ), buildDrawer: () { From 82859aac175313a6c0e923f77782b864fed5858c Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Wed, 21 Jan 2026 21:58:12 +1100 Subject: [PATCH 2/4] Add DEFAULT button --- lib/src/widgets/solid_about_button.dart | 17 ++-- .../solid_preferences_button_order.dart | 39 +++------ lib/src/widgets/solid_preferences_dialog.dart | 79 +++++++++++++++---- 3 files changed, 87 insertions(+), 48 deletions(-) diff --git a/lib/src/widgets/solid_about_button.dart b/lib/src/widgets/solid_about_button.dart index b5f65b0..ac76a83 100644 --- a/lib/src/widgets/solid_about_button.dart +++ b/lib/src/widgets/solid_about_button.dart @@ -312,13 +312,16 @@ class SolidAbout { children.add(const Divider()); children.add( Builder( - builder: (dialogContext) => TextButton.icon( - icon: const Icon(Icons.tune), - label: const Text('AppBar Layout Preferences'), - onPressed: () { - Navigator.of(dialogContext).pop(); - SolidPreferencesDialog.show(context); - }, + builder: (dialogContext) => Align( + alignment: Alignment.centerLeft, + child: TextButton.icon( + icon: const Icon(Icons.tune), + label: const Text('AppBar Layout Preferences'), + onPressed: () { + Navigator.of(dialogContext).pop(); + SolidPreferencesDialog.show(context); + }, + ), ), ), ); diff --git a/lib/src/widgets/solid_preferences_button_order.dart b/lib/src/widgets/solid_preferences_button_order.dart index a33fa32..30ff86d 100644 --- a/lib/src/widgets/solid_preferences_button_order.dart +++ b/lib/src/widgets/solid_preferences_button_order.dart @@ -171,35 +171,20 @@ class _SolidPreferencesButtonItem extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ // Visibility toggle. - // Disabled for AppBar Layout Preferences button (cannot be hidden). - - if (action.id == SolidAppBarActionIds.preferences) - MarkdownTooltip( - message: 'AppBar Layout Preferences button is always visible', - child: IconButton( - icon: Icon( - Icons.visibility, - size: 20, - color: theme.colorScheme.onSurface.withValues(alpha: 0.38), - ), - onPressed: null, // Disabled. - ), - ) - else - MarkdownTooltip( - message: action.isVisible ? 'Hide button' : 'Show button', - child: IconButton( - icon: Icon( - action.isVisible ? Icons.visibility : Icons.visibility_off, - size: 20, - color: action.isVisible - ? theme.colorScheme.primary - : theme.colorScheme.onSurface.withValues(alpha: 0.38), - ), - onPressed: () => - onVisibilityChanged(index, !action.isVisible), + + MarkdownTooltip( + message: action.isVisible ? 'Hide button' : 'Show button', + child: IconButton( + icon: Icon( + action.isVisible ? Icons.visibility : Icons.visibility_off, + size: 20, + color: action.isVisible + ? theme.colorScheme.primary + : theme.colorScheme.onSurface.withValues(alpha: 0.38), ), + onPressed: () => onVisibilityChanged(index, !action.isVisible), ), + ), // Overflow toggle. diff --git a/lib/src/widgets/solid_preferences_dialog.dart b/lib/src/widgets/solid_preferences_dialog.dart index 85411bd..080613b 100644 --- a/lib/src/widgets/solid_preferences_dialog.dart +++ b/lib/src/widgets/solid_preferences_dialog.dart @@ -105,20 +105,6 @@ class _SolidPreferencesDialogState extends State { void _onVisibilityChanged(int index, bool? value) { if (value == null) return; - - // Prevent hiding AppBar Layout Preferences button - - final action = _appBarActions[index]; - if (action.id == SolidAppBarActionIds.preferences && value == false) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('AppBar Layout Preferences button cannot be hidden'), - duration: Duration(seconds: 2), - ), - ); - return; - } - setState(() { _appBarActions[index] = _appBarActions[index].copyWith(isVisible: value); }); @@ -134,6 +120,64 @@ class _SolidPreferencesDialogState extends State { Navigator.of(context).pop(); } + void _resetToDefault() { + setState(() { + // Reset all actions to default values: visible, not in overflow, + // and sorted by their default order based on button type. + + final resetActions = []; + for (final action in _appBarActions) { + resetActions.add( + action.copyWith( + showInOverflow: false, + isVisible: true, + order: _getDefaultOrderForAction(action.id), + ), + ); + } + + // Sort by the default order. + + resetActions.sort((a, b) => a.order.compareTo(b.order)); + + // Reassign sequential order values after sorting. + + for (int i = 0; i < resetActions.length; i++) { + resetActions[i] = resetActions[i].copyWith(order: i); + } + + _appBarActions = resetActions; + }); + } + + /// Returns the default order index for an action based on its ID. + /// This mirrors the initialIndex values in SolidAppBarActionsManager. + + int _getDefaultOrderForAction(String actionId) { + // Theme toggle: 0. + + if (actionId == SolidAppBarActionIds.themeToggle) return 0; + + // Custom actions: 100+. + + if (actionId.startsWith('action_')) { + final index = int.tryParse(actionId.replaceFirst('action_', '')) ?? 0; + return 100 + index; + } + + // Logout: 300. + + if (actionId == SolidAppBarActionIds.logout) return 300; + + // About: 900. + + if (actionId == SolidAppBarActionIds.about) return 900; + + // Other items (overflow items): 200+. + + return 200; + } + @override Widget build(BuildContext context) { final theme = Theme.of(context); @@ -168,6 +212,13 @@ class _SolidPreferencesDialogState extends State { ), ), actions: [ + // Default button on the left. + + TextButton( + onPressed: _resetToDefault, + child: const Text('Default'), + ), + const Spacer(), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), From b623354d7ea72e1b7a139e79efc183b02972ab34 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Wed, 21 Jan 2026 22:09:48 +1100 Subject: [PATCH 3/4] Fix ParentDataWidget exception --- lib/src/widgets/solid_preferences_dialog.dart | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/src/widgets/solid_preferences_dialog.dart b/lib/src/widgets/solid_preferences_dialog.dart index 080613b..e94ca8e 100644 --- a/lib/src/widgets/solid_preferences_dialog.dart +++ b/lib/src/widgets/solid_preferences_dialog.dart @@ -211,21 +211,27 @@ class _SolidPreferencesDialogState extends State { ), ), ), + actionsPadding: const EdgeInsets.fromLTRB(24, 0, 24, 24), actions: [ - // Default button on the left. - - TextButton( - onPressed: _resetToDefault, - child: const Text('Default'), - ), - const Spacer(), - TextButton( - onPressed: () => Navigator.of(context).pop(), - child: const Text('Cancel'), - ), - FilledButton( - onPressed: _savePreferences, - child: const Text('Save'), + Row( + children: [ + // Default button on the left. + + TextButton( + onPressed: _resetToDefault, + child: const Text('Default'), + ), + const Spacer(), + TextButton( + onPressed: () => Navigator.of(context).pop(), + child: const Text('Cancel'), + ), + const SizedBox(width: 8), + FilledButton( + onPressed: _savePreferences, + child: const Text('Save'), + ), + ], ), ], ); From d70fe1e29e6b6082a70891943184c88fb65e5fd8 Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Thu, 22 Jan 2026 01:09:26 +1100 Subject: [PATCH 4/4] Fix the missing logout button issue --- lib/src/widgets/solid_scaffold.dart | 12 ++++- .../solid_scaffold_appbar_actions.dart | 51 +++++++++++-------- .../solid_scaffold_appbar_builder.dart | 6 ++- .../solid_scaffold_widget_builder.dart | 23 +++++++-- 4 files changed, 67 insertions(+), 25 deletions(-) diff --git a/lib/src/widgets/solid_scaffold.dart b/lib/src/widgets/solid_scaffold.dart index 8b02991..4af4e8f 100644 --- a/lib/src/widgets/solid_scaffold.dart +++ b/lib/src/widgets/solid_scaffold.dart @@ -34,6 +34,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:solidui/src/constants/navigation.dart'; +import 'package:solidui/src/handlers/solid_auth_handler.dart'; import 'package:solidui/src/services/solid_security_key_notifier.dart'; import 'package:solidui/src/services/solid_security_key_service.dart'; import 'package:solidui/src/utils/solid_notifications.dart'; @@ -150,10 +151,18 @@ class SolidScaffold extends StatefulWidget { final SolidNavUserInfo? userInfo; - /// Optional logout callback. + /// Optional custom logout callback. + /// If null and [showLogout] is true, the built-in + /// [SolidAuthHandler.instance.handleLogout] will be used. final void Function(BuildContext)? onLogout; + /// Whether to show the logout button. + /// Defaults to true. When true and [onLogout] is null, the built-in + /// [SolidAuthHandler.instance.handleLogout] will be used automatically. + + final bool showLogout; + /// Optional alert dialogue callback. final void Function(BuildContext, String, String?)? onShowAlert; @@ -266,6 +275,7 @@ class SolidScaffold extends StatefulWidget { this.statusBar, this.userInfo, this.onLogout, + this.showLogout = true, this.onShowAlert, this.narrowScreenThreshold = NavigationConstants.narrowScreenThreshold, this.backgroundColor, diff --git a/lib/src/widgets/solid_scaffold_appbar_actions.dart b/lib/src/widgets/solid_scaffold_appbar_actions.dart index 18097e8..604c0a0 100644 --- a/lib/src/widgets/solid_scaffold_appbar_actions.dart +++ b/lib/src/widgets/solid_scaffold_appbar_actions.dart @@ -41,17 +41,22 @@ class SolidAppBarActionsManager { /// Initialises AppBar actions in preferences notifier if empty or missing /// items. Dynamically handles all buttons from config.actions and /// config.overflowItems in addition to standard buttons. + /// + /// The [hasLogout] parameter indicates whether the application has provided + /// a logout callback. If false, the logout button will not be added to the + /// preferences list. static void initializeIfNeeded( SolidAppBarConfig config, - SolidThemeToggleConfig? themeToggle, - ) { + SolidThemeToggleConfig? themeToggle, { + bool hasLogout = false, + }) { // Check if we need to add missing buttons (standard or custom). final existingActions = solidPreferencesNotifier.appBarActions; final needsInit = existingActions.isEmpty; - final needsMerge = - !needsInit && _hasMissingButtons(existingActions, config, themeToggle); + final needsMerge = !needsInit && + _hasMissingButtons(existingActions, config, themeToggle, hasLogout); if (!needsInit && !needsMerge) return; @@ -119,20 +124,22 @@ class SolidAppBarActionsManager { ); } - // Add Logout button. + // Add Logout button if the application has provided a logout callback. // Default: show in AppBar. - actionEntries.add( - _ActionEntry( - item: const SolidAppBarActionItem( - id: SolidAppBarActionIds.logout, - label: 'Logout', - icon: Icons.logout, - showInOverflow: false, // Show in AppBar by default. + if (hasLogout) { + actionEntries.add( + _ActionEntry( + item: const SolidAppBarActionItem( + id: SolidAppBarActionIds.logout, + label: 'Logout', + icon: Icons.logout, + showInOverflow: false, // Show in AppBar by default. + ), + initialIndex: 300, // Logout button after custom/overflow actions. ), - initialIndex: 300, // Logout button after custom/overflow actions. - ), - ); + ); + } // Add About button. // Default: show in AppBar, rightmost position. @@ -174,6 +181,7 @@ class SolidAppBarActionsManager { List actions, SolidAppBarConfig config, SolidThemeToggleConfig? themeToggle, + bool hasLogout, ) { final existingIds = actions.map((a) => a.id).toSet(); @@ -200,12 +208,15 @@ class SolidAppBarActionsManager { expectedIds.add(item.id); } - // Standard buttons that should always exist. + // Logout button (only if application has provided a logout callback). + + if (hasLogout) { + expectedIds.add(SolidAppBarActionIds.logout); + } + + // About button should always exist. - expectedIds.addAll([ - SolidAppBarActionIds.logout, - SolidAppBarActionIds.about, - ]); + expectedIds.add(SolidAppBarActionIds.about); // Check if any expected ID is missing. diff --git a/lib/src/widgets/solid_scaffold_appbar_builder.dart b/lib/src/widgets/solid_scaffold_appbar_builder.dart index 3bb2996..953e112 100644 --- a/lib/src/widgets/solid_scaffold_appbar_builder.dart +++ b/lib/src/widgets/solid_scaffold_appbar_builder.dart @@ -58,7 +58,11 @@ class SolidScaffoldAppBarBuilder { bool hideNavRail = false, void Function(BuildContext)? onLogout, }) { - SolidAppBarActionsManager.initializeIfNeeded(config, themeToggle); + SolidAppBarActionsManager.initializeIfNeeded( + config, + themeToggle, + hasLogout: onLogout != null, + ); final isWideScreen = !hideNavRail && SolidScaffoldHelpers.isWideScreen( diff --git a/lib/src/widgets/solid_scaffold_widget_builder.dart b/lib/src/widgets/solid_scaffold_widget_builder.dart index e7aabe5..a6217d9 100644 --- a/lib/src/widgets/solid_scaffold_widget_builder.dart +++ b/lib/src/widgets/solid_scaffold_widget_builder.dart @@ -30,6 +30,7 @@ library; import 'package:flutter/material.dart'; +import 'package:solidui/src/handlers/solid_auth_handler.dart'; import 'package:solidui/src/widgets/solid_about_models.dart'; import 'package:solidui/src/widgets/solid_nav_drawer.dart'; import 'package:solidui/src/widgets/solid_nav_models.dart'; @@ -42,6 +43,18 @@ import 'package:solidui/src/widgets/solid_theme_notifier.dart'; /// Widget builder specifically for SolidScaffold. class SolidScaffoldWidgetBuilder { + /// Returns the effective logout callback. + /// If [showLogout] is true and [onLogout] is null, returns the built-in + /// [SolidAuthHandler.instance.handleLogout]. Otherwise returns [onLogout]. + + static void Function(BuildContext)? _getEffectiveLogout( + SolidScaffold widget, + ) { + if (!widget.showLogout) return null; + return widget.onLogout ?? + (context) => SolidAuthHandler.instance.handleLogout(context); + } + /// Builds a default SolidNavUserInfo from available scaffold configuration. static SolidNavUserInfo? _buildDefaultUserInfo( @@ -82,6 +95,10 @@ class SolidScaffoldWidgetBuilder { required String Function() getVersionToDisplay, String? currentWebId, }) { + // Get the effective logout callback (built-in or custom). + + final effectiveLogout = _getEffectiveLogout(widget); + return SolidScaffoldBuildHelper.buildScaffold( context: context, scaffoldKey: scaffoldKey, @@ -114,7 +131,7 @@ class SolidScaffoldWidgetBuilder { shouldShowVersion, getVersionToDisplay, hideNavRail: widget.hideNavRail, - onLogout: widget.onLogout, + onLogout: effectiveLogout, ), ), buildDrawer: () { @@ -128,8 +145,8 @@ class SolidScaffoldWidgetBuilder { tabs: SolidScaffoldHelpers.convertToNavTabs(widget.menu), selectedIndex: currentSelectedIndex, onTabSelected: onMenuSelected, - onLogout: widget.onLogout, - showLogout: widget.onLogout != null, + onLogout: effectiveLogout, + showLogout: effectiveLogout != null, ); }, endDrawer: widget.endDrawer,