diff --git a/CHANGELOG.md b/CHANGELOG.md index a7f5ffc..5262111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ au](https://solidcommunity.au/docs/solidui) ## 0.4.0 Refine and Tune ++ Adds additional layout width checks [0.3.6 20260326 tonypioneer] + Add checkbox and new webid widgets to SolidLogin() [0.3.5 20260325 tonypioneer] + Add WebID to SetupWizard [0.3.4 20260325 tonypioneer] + Login again if webid changed [0.3.3 20260319 tonypioneer] diff --git a/lib/solidui.dart b/lib/solidui.dart index 78963f5..21a2d6a 100644 --- a/lib/solidui.dart +++ b/lib/solidui.dart @@ -41,6 +41,7 @@ export 'src/widgets/solid_nav_models.dart'; export 'src/widgets/solid_scaffold.dart'; export 'src/widgets/solid_scaffold_controller.dart'; +export 'src/widgets/solid_scaffold_helpers.dart' show SolidScaffoldHelpers; export 'src/widgets/solid_scaffold_models.dart'; export 'src/widgets/solid_status_bar.dart'; diff --git a/lib/src/constants/navigation.dart b/lib/src/constants/navigation.dart index 7f551e4..f3fd214 100644 --- a/lib/src/constants/navigation.dart +++ b/lib/src/constants/navigation.dart @@ -33,16 +33,21 @@ library; /// Navigation constants used throughout the application. class NavigationConstants { + /// The width threshold for determining very narrow screen layout. + + static const double veryNarrowScreenThreshold = 600.0; + /// The width threshold for determining narrow/wide screen layout. - /// - /// Screens wider than this value will use the navigation rail, - /// while narrower screens will use the navigation drawer. static const double narrowScreenThreshold = 800.0; - /// The width threshold for determining very narrow screen layout. + /// The width threshold for wide screen layout. - static const double veryNarrowScreenThreshold = 600.0; + static const double wideScreenThreshold = 900.0; + + /// The width threshold for very wide screen layout. + + static const double veryWideScreenThreshold = 1000.0; /// Minimum width for the navigation rail. diff --git a/lib/src/constants/ui_window.dart b/lib/src/constants/ui_window.dart index 408d2ac..f841f5f 100644 --- a/lib/src/constants/ui_window.dart +++ b/lib/src/constants/ui_window.dart @@ -30,33 +30,78 @@ library; import 'package:flutter/material.dart'; -/// Thresholds for window size. +import 'package:solidui/src/constants/navigation.dart'; + +/// Responsive layout helpers using [LayoutBuilder] constraints. class WindowSize { /// Small width threshold. - static const double smallWidthLimit = 600; + static const double smallWidthLimit = + NavigationConstants.veryNarrowScreenThreshold; /// Small height threshold. static const double smallHeightLimit = 600; - /// Boolean describing whether the parent widget is narrow. - /// Derived from the box constraints found by LayoutBuilder(). - /// - /// Arguments: - /// - [constraints] - The box constraints of the parent widget - /// where LayoutBuilder() was called. + /// Legacy method — equivalent to [isVeryNarrow]. bool isNarrowWindow(BoxConstraints constraints) { - final bool isNarrow; - if (constraints.maxWidth < WindowSize.smallWidthLimit) { - isNarrow = true; - } else { - isNarrow = false; - } + return isVeryNarrow(constraints); + } + + /// Whether [constraints] width is below the very narrow threshold. + + static bool isVeryNarrow( + BoxConstraints constraints, { + double threshold = NavigationConstants.veryNarrowScreenThreshold, + }) { + return constraints.maxWidth < threshold; + } - return isNarrow; + /// Whether [constraints] width falls in the narrow range, i.e. between + /// [veryNarrowThreshold] (inclusive) and [narrowThreshold] (exclusive). + + static bool isNarrow( + BoxConstraints constraints, { + double veryNarrowThreshold = NavigationConstants.veryNarrowScreenThreshold, + double narrowThreshold = NavigationConstants.narrowScreenThreshold, + }) { + return constraints.maxWidth >= veryNarrowThreshold && + constraints.maxWidth < narrowThreshold; + } + + /// Whether [constraints] width falls in the medium range, i.e. between + /// [narrowThreshold] (inclusive) and [wideThreshold] (exclusive). + + static bool isMedium( + BoxConstraints constraints, { + double narrowThreshold = NavigationConstants.narrowScreenThreshold, + double wideThreshold = NavigationConstants.wideScreenThreshold, + }) { + return constraints.maxWidth >= narrowThreshold && + constraints.maxWidth < wideThreshold; + } + + /// Whether [constraints] width falls in the wide range, i.e. between + /// [wideThreshold] (inclusive) and [veryWideThreshold] (exclusive). + + static bool isWide( + BoxConstraints constraints, { + double wideThreshold = NavigationConstants.wideScreenThreshold, + double veryWideThreshold = NavigationConstants.veryWideScreenThreshold, + }) { + return constraints.maxWidth >= wideThreshold && + constraints.maxWidth < veryWideThreshold; + } + + /// Whether [constraints] width exceeds the very wide threshold. + + static bool isVeryWide( + BoxConstraints constraints, { + double threshold = NavigationConstants.veryWideScreenThreshold, + }) { + return constraints.maxWidth >= threshold; } } @@ -87,9 +132,7 @@ class ListItemSize { final double cardAspectRatio; - // Derive card aspect ratio (width / height). - - if (constraints.maxWidth < WindowSize.smallWidthLimit) { + if (WindowSize.isVeryNarrow(constraints)) { cardAspectRatio = constraints.maxWidth / compressedItemHeight; } else { cardAspectRatio = constraints.maxWidth / uncompressedItemHeight; diff --git a/lib/src/screens/initial_setup_widgets/res_create_form_submission.dart b/lib/src/screens/initial_setup_widgets/res_create_form_submission.dart index c1d4282..7ccd850 100644 --- a/lib/src/screens/initial_setup_widgets/res_create_form_submission.dart +++ b/lib/src/screens/initial_setup_widgets/res_create_form_submission.dart @@ -59,7 +59,7 @@ ElevatedButton resCreateFormSubmission( // Use MediaQuery to determine the screen width and adjust the font size // accordingly. - final screenWidth = MediaQuery.of(context).size.width; + final screenWidth = MediaQuery.sizeOf(context).width; final isSmallDevice = screenWidth < 360; // A threshold for small devices, can be adjusted. diff --git a/lib/src/widgets/build_message_container.dart b/lib/src/widgets/build_message_container.dart index 75ae5ac..7f479ab 100644 --- a/lib/src/widgets/build_message_container.dart +++ b/lib/src/widgets/build_message_container.dart @@ -95,7 +95,7 @@ Container buildMsgBox( // ignore: unused_local_variable var isRTL = false; - final size = MediaQuery.of(context).size; + final size = MediaQuery.sizeOf(context); final loc = Localizations.maybeLocaleOf(context); final localeLanguageCode = loc?.languageCode; diff --git a/lib/src/widgets/shared_resources_table.dart b/lib/src/widgets/shared_resources_table.dart index cc872d3..1a1e9b7 100644 --- a/lib/src/widgets/shared_resources_table.dart +++ b/lib/src/widgets/shared_resources_table.dart @@ -49,7 +49,7 @@ Widget buildSharedResourcesTable( Map sharedResMap, Widget parentWidget, ) { - final cWidth = MediaQuery.of(context).size.width * 0.18; + final cWidth = MediaQuery.sizeOf(context).width * 0.18; DataColumn buildDataColumn(String title, String tooltip) { return DataColumn( label: Expanded(child: Center(child: Text(title))), diff --git a/lib/src/widgets/solid_file_helpers.dart b/lib/src/widgets/solid_file_helpers.dart index 992c22e..355b522 100644 --- a/lib/src/widgets/solid_file_helpers.dart +++ b/lib/src/widgets/solid_file_helpers.dart @@ -45,7 +45,7 @@ class SolidFileHelpers { if (forceWideScreen != null) { return forceWideScreen; } - return MediaQuery.of(context).size.width > 800; + return MediaQuery.sizeOf(context).width > 800; } /// Gets the effective browser height. @@ -54,7 +54,7 @@ class SolidFileHelpers { if (browserHeight != null) { return browserHeight; } - return MediaQuery.of(context).size.height * 0.7; + return MediaQuery.sizeOf(context).height * 0.7; } /// Gets the effective upload configuration, either from the provided config diff --git a/lib/src/widgets/solid_login_build_helper.dart b/lib/src/widgets/solid_login_build_helper.dart index b1be9f3..2923695 100644 --- a/lib/src/widgets/solid_login_build_helper.dart +++ b/lib/src/widgets/solid_login_build_helper.dart @@ -130,12 +130,12 @@ class SolidLoginBuildHelper { behavior: HitTestBehavior.deferToChild, child: SafeArea( child: DecoratedBox( - decoration: isNarrowScreen(context) + decoration: isNarrowLoginScreen(context) ? loginBoxDecor : const BoxDecoration(), child: Row( children: [ - isNarrowScreen(context) + isNarrowLoginScreen(context) ? Container() : Expanded( flex: 7, diff --git a/lib/src/widgets/solid_login_helper.dart b/lib/src/widgets/solid_login_helper.dart index fcbe575..a75b4b4 100644 --- a/lib/src/widgets/solid_login_helper.dart +++ b/lib/src/widgets/solid_login_helper.dart @@ -40,12 +40,12 @@ import 'package:markdown_tooltip/markdown_tooltip.dart'; const int narrowScreenLimit = 1175; const int veryNarrowScreenLimit = 750; -double screenWidth(BuildContext context) => MediaQuery.of(context).size.width; +double screenWidth(BuildContext context) => MediaQuery.sizeOf(context).width; -bool isNarrowScreen(BuildContext context) => +bool isNarrowLoginScreen(BuildContext context) => screenWidth(context) < narrowScreenLimit; -bool isVeryNarrowScreen(BuildContext context) => +bool isVeryNarrowLoginScreen(BuildContext context) => screenWidth(context) < veryNarrowScreenLimit; /// Button styles used in the Solid Login widget. diff --git a/lib/src/widgets/solid_login_panel.dart b/lib/src/widgets/solid_login_panel.dart index 8797986..0198802 100644 --- a/lib/src/widgets/solid_login_panel.dart +++ b/lib/src/widgets/solid_login_panel.dart @@ -112,7 +112,7 @@ class SolidLoginPanel { if (isRequired) Expanded( child: SizedBox( - width: MediaQuery.of(context).size.width * 0.5, + width: MediaQuery.sizeOf(context).width * 0.5, child: infoButton, ), ), @@ -178,7 +178,9 @@ class SolidLoginPanel { required SolidLoginThemeMode currentTheme, }) { final loginPanelInset = - (isVeryNarrowScreen(context) || !isNarrowScreen(context)) ? 0.05 : 0.25; + (isVeryNarrowLoginScreen(context) || !isNarrowLoginScreen(context)) + ? 0.05 + : 0.25; return Container( margin: EdgeInsets.symmetric( diff --git a/lib/src/widgets/solid_nav_bar.dart b/lib/src/widgets/solid_nav_bar.dart index 9d42f20..3ac8bf5 100644 --- a/lib/src/widgets/solid_nav_bar.dart +++ b/lib/src/widgets/solid_nav_bar.dart @@ -100,7 +100,7 @@ class SolidNavBar extends StatelessWidget { child: SingleChildScrollView( child: ConstrainedBox( constraints: BoxConstraints( - minHeight: MediaQuery.of(context).size.height, + minHeight: MediaQuery.sizeOf(context).height, ), child: IntrinsicHeight( child: NavigationRail( diff --git a/lib/src/widgets/solid_nav_drawer.dart b/lib/src/widgets/solid_nav_drawer.dart index 0344d13..94c4c30 100644 --- a/lib/src/widgets/solid_nav_drawer.dart +++ b/lib/src/widgets/solid_nav_drawer.dart @@ -167,7 +167,7 @@ class _SolidNavDrawerState extends State { ), ), child: ListView( - padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top), + padding: EdgeInsets.only(top: MediaQuery.paddingOf(context).top), children: [ if (widget.userInfo != null) SolidNavDrawerHeader.build( diff --git a/lib/src/widgets/solid_nav_drawer_header.dart b/lib/src/widgets/solid_nav_drawer_header.dart index 8379e29..8598145 100644 --- a/lib/src/widgets/solid_nav_drawer_header.dart +++ b/lib/src/widgets/solid_nav_drawer_header.dart @@ -58,7 +58,7 @@ class SolidNavDrawerHeader { return Container( padding: EdgeInsets.only( top: NavigationConstants.userHeaderTopPadding + - MediaQuery.of(context).padding.top, + MediaQuery.paddingOf(context).top, bottom: bottomPadding, ), decoration: BoxDecoration(color: theme.colorScheme.primaryContainer), diff --git a/lib/src/widgets/solid_scaffold_appbar_builder.dart b/lib/src/widgets/solid_scaffold_appbar_builder.dart index 4e820a5..fbb7c2e 100644 --- a/lib/src/widgets/solid_scaffold_appbar_builder.dart +++ b/lib/src/widgets/solid_scaffold_appbar_builder.dart @@ -59,6 +59,7 @@ class SolidScaffoldAppBarBuilder { bool showLogout = true, void Function(BuildContext)? onLogout, void Function(BuildContext)? onLogin, + required BoxConstraints constraints, }) { SolidAppBarActionsManager.initializeIfNeeded( config, @@ -66,19 +67,19 @@ class SolidScaffoldAppBarBuilder { hasLogout: showLogout, ); - final isWideScreen = !hideNavRail && - SolidScaffoldHelpers.isWideScreen(context, narrowScreenThreshold); - final screenWidth = MediaQuery.of(context).size.width; + final layoutWidth = constraints.maxWidth; + final isNarrowScreen = hideNavRail || + SolidScaffoldHelpers.isNarrowScreen( + constraints, + narrowThreshold: narrowScreenThreshold, + ) || + SolidScaffoldHelpers.isVeryNarrowScreen(constraints); final theme = Theme.of(context); - // Build action buttons. - List actions = []; - // Add version widget if configured and screen is not too narrow. - if (config.versionConfig != null && - screenWidth >= config.veryNarrowScreenThreshold && + layoutWidth >= config.veryNarrowScreenThreshold && shouldShowVersion) { actions.add( SolidScaffoldHelpers.buildVersionWidget( @@ -90,11 +91,9 @@ class SolidScaffoldAppBarBuilder { actions.add(const Gap(8)); } - // Build ordered actions based on preferences. - final orderedActions = SolidAppBarOrderedActionsBuilder.build( config: config, - screenWidth: screenWidth, + layoutWidth: layoutWidth, themeToggle: themeToggle, currentThemeMode: currentThemeMode, themeToggleCallback: themeToggleCallback, @@ -106,12 +105,10 @@ class SolidScaffoldAppBarBuilder { ); actions.addAll(orderedActions); - // Handle overflow menu if on narrow screen. - SolidAppBarOverflowHandler.handleOverflowMenu( actions, config, - screenWidth, + layoutWidth, themeToggle, currentThemeMode, themeToggleCallback, @@ -125,7 +122,7 @@ class SolidScaffoldAppBarBuilder { return AppBar( title: Text(config.title), backgroundColor: config.backgroundColor, - automaticallyImplyLeading: !isWideScreen, + automaticallyImplyLeading: isNarrowScreen, actions: actions.isEmpty ? null : actions, ); } diff --git a/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart b/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart index 1520fdc..69c1f04 100644 --- a/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart +++ b/lib/src/widgets/solid_scaffold_appbar_ordered_actions.dart @@ -52,7 +52,7 @@ class SolidAppBarOrderedActionsBuilder { static List build({ required SolidAppBarConfig config, - required double screenWidth, + required double layoutWidth, required SolidThemeToggleConfig? themeToggle, required ThemeMode currentThemeMode, required VoidCallback? themeToggleCallback, @@ -63,33 +63,33 @@ class SolidAppBarOrderedActionsBuilder { void Function(BuildContext)? onLogin, }) { final List<_OrderedAction> orderedActions = []; - final isNarrowScreen = screenWidth < config.narrowScreenThreshold; + final isVeryNarrowScreen = layoutWidth < config.veryNarrowScreenThreshold; _addThemeToggle( orderedActions, themeToggle, config, - screenWidth, - isNarrowScreen, + layoutWidth, + isVeryNarrowScreen, currentThemeMode, themeToggleCallback, ); - _addCustomActions(orderedActions, config, screenWidth, isNarrowScreen); - _addOverflowItems(orderedActions, config, isNarrowScreen); + _addCustomActions(orderedActions, config, layoutWidth, isVeryNarrowScreen); + _addOverflowItems(orderedActions, config, isVeryNarrowScreen); _addAuthButton( orderedActions, showLogout, onLogout, onLogin, - isNarrowScreen, + isVeryNarrowScreen, context, ); _addAboutButton( orderedActions, aboutConfig, config, - screenWidth, - isNarrowScreen, + layoutWidth, + isVeryNarrowScreen, ); orderedActions.sort((a, b) => a.order.compareTo(b.order)); @@ -100,8 +100,8 @@ class SolidAppBarOrderedActionsBuilder { List<_OrderedAction> orderedActions, SolidThemeToggleConfig? themeToggle, SolidAppBarConfig config, - double screenWidth, - bool isNarrowScreen, + double layoutWidth, + bool isVeryNarrowScreen, ThemeMode currentThemeMode, VoidCallback? themeToggleCallback, ) { @@ -115,11 +115,11 @@ class SolidAppBarOrderedActionsBuilder { final order = actionConfig?.order ?? 0; final shouldShow = isVisible && - (!isNarrowScreen || !isInOverflow) && + (!isVeryNarrowScreen || !isInOverflow) && SolidAppBarVisibilityHelper.shouldShowThemeToggle( themeToggle, config, - screenWidth, + layoutWidth, ); if (shouldShow) { @@ -139,8 +139,8 @@ class SolidAppBarOrderedActionsBuilder { static void _addCustomActions( List<_OrderedAction> orderedActions, SolidAppBarConfig config, - double screenWidth, - bool isNarrowScreen, + double layoutWidth, + bool isVeryNarrowScreen, ) { for (int i = 0; i < config.actions.length; i++) { final action = config.actions[i]; @@ -151,11 +151,11 @@ class SolidAppBarOrderedActionsBuilder { final order = actionConfig?.order ?? (100 + i); final shouldShow = isVisible && - (!isNarrowScreen || !isInOverflow) && + (!isVeryNarrowScreen || !isInOverflow) && SolidAppBarVisibilityHelper.shouldShowAction( action, config, - screenWidth, + layoutWidth, ); if (shouldShow) { @@ -180,7 +180,7 @@ class SolidAppBarOrderedActionsBuilder { static void _addOverflowItems( List<_OrderedAction> orderedActions, SolidAppBarConfig config, - bool isNarrowScreen, + bool isVeryNarrowScreen, ) { for (int i = 0; i < config.overflowItems.length; i++) { final item = config.overflowItems[i]; @@ -189,7 +189,7 @@ class SolidAppBarOrderedActionsBuilder { final isInOverflow = actionConfig?.showInOverflow ?? true; final order = actionConfig?.order ?? (200 + i); - if (isVisible && (!isNarrowScreen || !isInOverflow)) { + if (isVisible && (!isVeryNarrowScreen || !isInOverflow)) { Widget iconButton = IconButton( icon: Icon(item.icon), onPressed: item.onSelected, @@ -210,7 +210,7 @@ class SolidAppBarOrderedActionsBuilder { bool showLogout, void Function(BuildContext)? onLogout, void Function(BuildContext)? onLogin, - bool isNarrowScreen, + bool isVeryNarrowScreen, BuildContext context, ) { final actionConfig = SolidAppBarActionsManager.getActionConfig( @@ -220,7 +220,7 @@ class SolidAppBarOrderedActionsBuilder { final isInOverflow = actionConfig?.showInOverflow ?? false; final order = actionConfig?.order ?? 400; - if (isVisible && (!isNarrowScreen || !isInOverflow)) { + if (isVisible && (!isVeryNarrowScreen || !isInOverflow)) { orderedActions.add( _OrderedAction( order: order, @@ -238,12 +238,12 @@ class SolidAppBarOrderedActionsBuilder { List<_OrderedAction> orderedActions, SolidAboutConfig aboutConfig, SolidAppBarConfig config, - double screenWidth, - bool isNarrowScreen, + double layoutWidth, + bool isVeryNarrowScreen, ) { if (!aboutConfig.enabled || !aboutConfig.shouldShow( - screenWidth, + layoutWidth, config.narrowScreenThreshold, config.veryNarrowScreenThreshold, )) { @@ -257,7 +257,7 @@ class SolidAppBarOrderedActionsBuilder { final isInOverflow = actionConfig?.showInOverflow ?? false; final order = actionConfig?.order ?? 900; - if (isVisible && (!isNarrowScreen || !isInOverflow)) { + if (isVisible && (!isVeryNarrowScreen || !isInOverflow)) { orderedActions.add( _OrderedAction( order: order, diff --git a/lib/src/widgets/solid_scaffold_appbar_overflow.dart b/lib/src/widgets/solid_scaffold_appbar_overflow.dart index f31b654..f9e8ece 100644 --- a/lib/src/widgets/solid_scaffold_appbar_overflow.dart +++ b/lib/src/widgets/solid_scaffold_appbar_overflow.dart @@ -49,7 +49,7 @@ class SolidAppBarOverflowHandler { static void handleOverflowMenu( List actions, SolidAppBarConfig config, - double screenWidth, + double layoutWidth, SolidThemeToggleConfig? themeToggle, ThemeMode currentThemeMode, VoidCallback? themeToggleCallback, @@ -59,14 +59,12 @@ class SolidAppBarOverflowHandler { void Function(BuildContext)? onLogout, void Function(BuildContext)? onLogin, }) { - // Use narrowScreenThreshold to determine when to show overflow menu. + final isVeryNarrowScreen = layoutWidth < config.veryNarrowScreenThreshold; - final isNarrowScreen = screenWidth < config.narrowScreenThreshold; + // Only show overflow menu on very narrow screens. + // On wider screens, all buttons are displayed directly in AppBar. - // Only show overflow menu on narrow screens. - // On wide screens, all buttons are displayed directly in AppBar. - - if (!isNarrowScreen) return; + if (!isVeryNarrowScreen) return; actions.add( _buildOverflowMenu( diff --git a/lib/src/widgets/solid_scaffold_appbar_visibility.dart b/lib/src/widgets/solid_scaffold_appbar_visibility.dart index b203dad..213b05c 100644 --- a/lib/src/widgets/solid_scaffold_appbar_visibility.dart +++ b/lib/src/widgets/solid_scaffold_appbar_visibility.dart @@ -34,38 +34,40 @@ import 'package:solidui/src/widgets/solid_theme_models.dart'; /// Provides visibility checks for AppBar actions. class SolidAppBarVisibilityHelper { - /// Determines if an action should be shown based on screen width. + /// Determines if an action should be shown based on the available + /// layout width from [LayoutBuilder] constraints. static bool shouldShowAction( SolidAppBarAction action, SolidAppBarConfig config, - double screenWidth, + double layoutWidth, ) { if (!action.showOnVeryNarrowScreen && - screenWidth < config.veryNarrowScreenThreshold) { + layoutWidth < config.veryNarrowScreenThreshold) { return false; } else if (!action.showOnNarrowScreen && - screenWidth < config.narrowScreenThreshold) { + layoutWidth < config.narrowScreenThreshold) { return false; } return true; } - /// Determines if theme toggle should be shown. + /// Determines if theme toggle should be shown based on the available + /// layout width from [LayoutBuilder] constraints. static bool shouldShowThemeToggle( SolidThemeToggleConfig? themeToggle, SolidAppBarConfig config, - double screenWidth, + double layoutWidth, ) { if (themeToggle == null || !themeToggle.enabled) return false; if (!themeToggle.showInAppBarActions) return false; if (!themeToggle.showOnVeryNarrowScreen && - screenWidth < config.veryNarrowScreenThreshold) { + layoutWidth < config.veryNarrowScreenThreshold) { return false; } else if (!themeToggle.showOnNarrowScreen && - screenWidth < config.narrowScreenThreshold) { + layoutWidth < config.narrowScreenThreshold) { return false; } diff --git a/lib/src/widgets/solid_scaffold_build_helper.dart b/lib/src/widgets/solid_scaffold_build_helper.dart index 47ffd61..a46d94f 100644 --- a/lib/src/widgets/solid_scaffold_build_helper.dart +++ b/lib/src/widgets/solid_scaffold_build_helper.dart @@ -120,6 +120,7 @@ class SolidScaffoldBuildHelper { static Widget buildConfiguredScaffold({ required BuildContext context, + required BoxConstraints constraints, required GlobalKey scaffoldKey, required SolidScaffoldInternalConfig config, required bool isWideScreen, @@ -166,6 +167,7 @@ class SolidScaffoldBuildHelper { hideNavRail: config.hideNavRail, showLogout: config.onLogout != null, onLogout: config.onLogout, + constraints: constraints, ), ), buildDrawer: () { diff --git a/lib/src/widgets/solid_scaffold_helpers.dart b/lib/src/widgets/solid_scaffold_helpers.dart index e40c5c2..d6783b2 100644 --- a/lib/src/widgets/solid_scaffold_helpers.dart +++ b/lib/src/widgets/solid_scaffold_helpers.dart @@ -33,6 +33,7 @@ import 'package:flutter/material.dart'; import 'package:markdown_tooltip/markdown_tooltip.dart'; import 'package:version_widget/version_widget.dart'; +import 'package:solidui/src/constants/ui_window.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_overflow_menu_helpers.dart'; @@ -151,10 +152,43 @@ class SolidScaffoldHelpers { static List buildOverflowIconButtons(SolidAppBarConfig config) => SolidOverflowMenuHelpers.buildOverflowIconButtons(config); - /// Determines if screen is wide. + /// Delegates to [WindowSize.isNarrow] using [BoxConstraints]. - static bool isWideScreen(BuildContext context, double narrowScreenThreshold) { - return MediaQuery.of(context).size.width > narrowScreenThreshold; + static bool isNarrowScreen( + BoxConstraints constraints, { + double? narrowThreshold, + }) { + if (narrowThreshold != null) { + return WindowSize.isNarrow( + constraints, + narrowThreshold: narrowThreshold, + ); + } + return WindowSize.isNarrow(constraints); + } + + /// Delegates to [WindowSize.isVeryNarrow] using [BoxConstraints]. + + static bool isVeryNarrowScreen(BoxConstraints constraints) { + return WindowSize.isVeryNarrow(constraints); + } + + /// Delegates to [WindowSize.isMedium] using [BoxConstraints]. + + static bool isMedScreen(BoxConstraints constraints) { + return WindowSize.isMedium(constraints); + } + + /// Delegates to [WindowSize.isWide] using [BoxConstraints]. + + static bool isWideScreen(BoxConstraints constraints) { + return WindowSize.isWide(constraints); + } + + /// Delegates to [WindowSize.isVeryWide] using [BoxConstraints]. + + static bool isVeryWideScreen(BoxConstraints constraints) { + return WindowSize.isVeryWide(constraints); } /// Gets effective child widget. @@ -257,6 +291,7 @@ class SolidScaffoldHelpers { bool showLogout = true, void Function(BuildContext)? onLogout, void Function(BuildContext)? onLogin, + required BoxConstraints constraints, }) { if (appBar == null) return null; if (appBar is! SolidAppBarConfig) return null; @@ -274,6 +309,7 @@ class SolidScaffoldHelpers { showLogout: showLogout, onLogout: onLogout, onLogin: onLogin, + constraints: constraints, ); } diff --git a/lib/src/widgets/solid_scaffold_state.dart b/lib/src/widgets/solid_scaffold_state.dart index aba9363..c69323a 100644 --- a/lib/src/widgets/solid_scaffold_state.dart +++ b/lib/src/widgets/solid_scaffold_state.dart @@ -167,9 +167,14 @@ class SolidScaffoldState extends State { } } - bool _isWideScreen(BuildContext c) => - !widget.hideNavRail && - SolidScaffoldHelpers.isWideScreen(c, widget.narrowScreenThreshold); + bool _isNarrowScreen(BoxConstraints constraints) { + return widget.hideNavRail || + SolidScaffoldHelpers.isNarrowScreen( + constraints, + narrowThreshold: widget.narrowScreenThreshold, + ) || + SolidScaffoldHelpers.isVeryNarrowScreen(constraints); + } bool _getUsesInternalManagement() => _cachedUsesInternalManagement ??= SolidScaffoldHelpers.getUsesInternalManagement(widget.themeToggle); @@ -188,49 +193,54 @@ class SolidScaffoldState extends State { @override Widget build(BuildContext context) { - final isWide = _isWideScreen(context); - final isCompat = widget.menu == null; - final bodyContent = isCompat - ? widget.body - : SolidScaffoldLayoutBuilder.buildBody( - context, - isWide, - SolidScaffoldHelpers.convertToNavTabs(widget.menu), - _currentSelectedIndex, - SolidScaffoldHelpers.getEffectiveChild( - widget.menu, - _currentSelectedIndex, - widget.child, - widget.body, - widget.bodyOverride ?? widget.controller?.currentSubpage, - ), - _onMenuSelected, - widget.onShowAlert, - ); - - return NotificationListener( - onNotification: (n) { - Future.delayed(const Duration(milliseconds: 300), () { - securityKeyNotifier.refreshStatus(); - _loadCurrentWebId(); - }); - return true; + return LayoutBuilder( + builder: (context, constraints) { + final isNarrow = _isNarrowScreen(constraints); + final isCompat = widget.menu == null; + final bodyContent = isCompat + ? widget.body + : SolidScaffoldLayoutBuilder.buildBody( + context, + !isNarrow, + SolidScaffoldHelpers.convertToNavTabs(widget.menu), + _currentSelectedIndex, + SolidScaffoldHelpers.getEffectiveChild( + widget.menu, + _currentSelectedIndex, + widget.child, + widget.body, + widget.bodyOverride ?? widget.controller?.currentSubpage, + ), + _onMenuSelected, + widget.onShowAlert, + ); + + return NotificationListener( + onNotification: (n) { + Future.delayed(const Duration(milliseconds: 300), () { + securityKeyNotifier.refreshStatus(); + _loadCurrentWebId(); + }); + return true; + }, + child: SolidScaffoldWidgetBuilder.buildFromWidget( + context: context, + constraints: constraints, + scaffoldKey: _scaffoldKey, + widget: widget, + isWideScreen: !isNarrow, + isCompatibilityMode: isCompat, + bodyContent: bodyContent, + isKeySaved: _isKeySaved, + currentSelectedIndex: _currentSelectedIndex, + onMenuSelected: _onMenuSelected, + getUsesInternalManagement: _getUsesInternalManagement, + shouldShowVersion: _shouldShowVersion, + getVersionToDisplay: _getVersionToDisplay, + currentWebId: _currentWebId, + ), + ); }, - child: SolidScaffoldWidgetBuilder.buildFromWidget( - context: context, - scaffoldKey: _scaffoldKey, - widget: widget, - isWideScreen: isWide, - isCompatibilityMode: isCompat, - bodyContent: bodyContent, - isKeySaved: _isKeySaved, - currentSelectedIndex: _currentSelectedIndex, - onMenuSelected: _onMenuSelected, - getUsesInternalManagement: _getUsesInternalManagement, - shouldShowVersion: _shouldShowVersion, - getVersionToDisplay: _getVersionToDisplay, - currentWebId: _currentWebId, - ), ); } } diff --git a/lib/src/widgets/solid_scaffold_widget_builder.dart b/lib/src/widgets/solid_scaffold_widget_builder.dart index ef777a6..53c3070 100644 --- a/lib/src/widgets/solid_scaffold_widget_builder.dart +++ b/lib/src/widgets/solid_scaffold_widget_builder.dart @@ -114,6 +114,7 @@ class SolidScaffoldWidgetBuilder { static Widget buildFromWidget({ required BuildContext context, + required BoxConstraints constraints, required GlobalKey scaffoldKey, required SolidScaffold widget, required bool isWideScreen, @@ -127,8 +128,6 @@ class SolidScaffoldWidgetBuilder { required String Function() getVersionToDisplay, String? currentWebId, }) { - // Get the effective login/logout callbacks (built-in or custom). - final effectiveLogout = _getEffectiveLogout(widget); final effectiveLogin = _getEffectiveLogin(widget); @@ -167,6 +166,7 @@ class SolidScaffoldWidgetBuilder { showLogout: widget.showLogout, onLogout: effectiveLogout, onLogin: effectiveLogin, + constraints: constraints, ), ), buildDrawer: () { diff --git a/pubspec.yaml b/pubspec.yaml index 6bfbe33..d4b2155 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,10 +1,10 @@ name: solidui -description: "A UI library for building Solid applications with Flutter." -version: 0.3.5 +description: 'A UI library for building Solid applications with Flutter.' +version: 0.3.6 homepage: https://github.com/anusii/solidui environment: - sdk: ">=3.2.3 <4.0.0" + sdk: '>=3.2.3 <4.0.0' # To automatically upgrade package dependencies to the latest versions: #