From 9493b39d94873f1aef8c9da246ce23cbfc42c8eb Mon Sep 17 00:00:00 2001 From: Ahmed Elsayed Date: Fri, 28 Jul 2023 17:55:27 +0300 Subject: [PATCH] Prefer Material over Platform Widgets for root widgets --- .metadata | 2 +- lib/app.dart | 39 +++--- .../components/login_form_component.dart | 41 +++++- .../components/login_text_fields_section.dart | 70 ---------- .../sign_in_screen/sign_in_screen.dart | 2 +- .../sign_in_screen_compact.dart | 4 +- .../sign_in_screen/sign_in_screen_medium.dart | 4 +- .../locale/presentation/utils/app_locale.dart | 8 +- .../theme/presentation/utils/app_theme.dart | 6 +- .../presentation/utils/themes/i_theme.dart | 16 ++- .../presentation/utils/themes/theme_dark.dart | 44 +++++- .../utils/themes/theme_light.dart | 44 +++++- .../appbar_with_icon_component.dart | 2 +- .../presentation/helpers/platform_helper.dart | 18 ++- .../presentation/helpers/theme_helper.dart | 4 +- ...caffold.dart => full_screen_scaffold.dart} | 14 +- .../screens/nested_screen_scaffold.dart | 28 +--- .../no_internet_screen.dart | 2 +- .../no_internet_screen_compact.dart | 4 +- .../route_error_screen.dart | 2 +- .../route_error_screen_compact.dart | 4 +- .../screens/splash_screen/splash_screen.dart | 2 +- .../splash_screen/splash_screen_compact.dart | 4 +- lib/core/presentation/styles/font_styles.dart | 5 +- lib/core/presentation/styles/sizes.dart | 2 +- .../presentation/utils/window_size_class.dart | 37 ----- .../presentation/widgets/custom_app_bar.dart | 69 +++++++++ .../widgets/custom_app_bar_widget.dart | 132 ------------------ .../presentation/widgets/custom_text.dart | 1 - .../{ => legacy}/custom_text_form_field.dart | 12 +- .../full_screen_platform_scaffold.dart | 34 +++++ .../platform_widgets/platform_app.dart | 2 +- .../platform_widgets/platform_app_bar.dart | 7 +- .../platform_base_consumer_widget.dart | 6 +- .../platform_icon_button.dart | 9 +- .../platform_widgets/platform_nav_bar.dart | 9 +- .../platform_widgets/platform_page_route.dart | 4 +- .../platform_widgets/platform_scaffold.dart | 16 +-- .../platform_tab_scaffold.dart | 4 +- .../platform_text_form_field.dart | 5 +- .../platform_widgets/platform_appbar.dart | 45 ++++++ .../platform_base_widget.dart | 5 +- .../platform_widgets/platform_icons.dart | 47 +++---- ..._builders.dart => responsive_layouts.dart} | 38 ++++- ...bar_widget.dart => status_bar_spacer.dart} | 20 +-- .../dialogs/cancel_order_dialog.dart | 13 +- .../dialogs/cancel_order_note_component.dart | 50 ------- .../screens/home_screen/home_screen.dart | 2 +- .../components/bottom_nav_bar_component.dart | 57 -------- ..._component.dart => home_shell_appbar.dart} | 51 ++----- .../components/home_shell_bottom_nav_bar.dart | 57 ++++++++ .../home_shell_navigation_rail.dart | 47 +++++++ .../screens/home_shell_screen.dart | 116 +++++++++------ .../screens/map_screen/map_screen.dart | 2 +- .../map_screen/map_screen_compact.dart | 1 - .../components/profile_form_component.dart | 26 +++- .../profile_text_fields_section.dart | 63 --------- .../profile_screen/profile_screen.dart | 2 +- .../widgets/titled_text_field_item.dart | 66 +++------ .../language_screen/language_screen.dart | 2 +- .../settings_screen/settings_screen.dart | 2 +- lib/l10n/app_ar.arb | 1 - lib/l10n/app_en.arb | 1 - pubspec.lock | 18 ++- pubspec.yaml | 2 + .../helpers/platform_helper_test.dart | 10 +- 66 files changed, 717 insertions(+), 745 deletions(-) delete mode 100644 lib/auth/presentation/components/login_text_fields_section.dart rename lib/core/presentation/screens/{full_screen_platform_scaffold.dart => full_screen_scaffold.dart} (67%) delete mode 100644 lib/core/presentation/utils/window_size_class.dart create mode 100644 lib/core/presentation/widgets/custom_app_bar.dart delete mode 100644 lib/core/presentation/widgets/custom_app_bar_widget.dart rename lib/core/presentation/widgets/{ => legacy}/custom_text_form_field.dart (92%) create mode 100644 lib/core/presentation/widgets/legacy/platform_widgets/full_screen_platform_scaffold.dart rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_app.dart (97%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_app_bar.dart (93%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_base_consumer_widget.dart (79%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_icon_button.dart (87%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_nav_bar.dart (89%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_page_route.dart (88%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_scaffold.dart (86%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_tab_scaffold.dart (97%) rename lib/core/presentation/widgets/{ => legacy}/platform_widgets/platform_text_form_field.dart (96%) create mode 100644 lib/core/presentation/widgets/platform_widgets/platform_appbar.dart rename lib/core/presentation/widgets/responsive_widgets/{widget_builders.dart => responsive_layouts.dart} (55%) rename lib/core/presentation/widgets/{empty_appbar_widget.dart => status_bar_spacer.dart} (63%) delete mode 100644 lib/features/home/presentation/components/dialogs/cancel_order_note_component.dart delete mode 100755 lib/features/home_shell/presentation/components/bottom_nav_bar_component.dart rename lib/features/home_shell/presentation/components/{tab_appbar_component.dart => home_shell_appbar.dart} (56%) create mode 100755 lib/features/home_shell/presentation/components/home_shell_bottom_nav_bar.dart create mode 100755 lib/features/home_shell/presentation/components/home_shell_navigation_rail.dart delete mode 100644 lib/features/profile/presentation/components/profile_text_fields_section.dart diff --git a/.metadata b/.metadata index 13603293..bd1207f9 100644 --- a/.metadata +++ b/.metadata @@ -15,7 +15,7 @@ migration: - platform: root create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 - - platform: macos + - platform: web create_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 base_revision: f468f3366c26a5092eb964a230ce7892fda8f2f8 diff --git a/lib/app.dart b/lib/app.dart index 7da40b4a..34f5375e 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -8,7 +8,6 @@ import 'core/presentation/routing/app_router.dart'; import 'core/presentation/routing/navigation_service.dart'; import 'core/presentation/utils/riverpod_framework.dart'; import 'core/presentation/utils/scroll_behaviors.dart'; -import 'core/presentation/widgets/platform_widgets/platform_app.dart'; class MyApp extends HookConsumerWidget { const MyApp({super.key}); @@ -23,26 +22,24 @@ class MyApp extends HookConsumerWidget { final theme = ref.watch(currentAppThemeProvider); final locale = ref.watch(currentAppLocaleProvider); - return Theme( - data: theme.getThemeData(), - child: PlatformApp( - routerConfig: router, - builder: (_, child) { - return ScrollConfiguration( - behavior: MainScrollBehavior(), - child: GestureDetector( - onTap: NavigationService.removeFocus, - child: child, - ), - ); - }, - title: 'Deliverzler', - color: Theme.of(context).colorScheme.primary, - locale: Locale(locale.code), - localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, - debugShowCheckedModeBanner: false, - ), + return MaterialApp.router( + routerConfig: router, + builder: (_, child) { + return ScrollConfiguration( + behavior: MainScrollBehavior(), + child: GestureDetector( + onTap: NavigationService.removeFocus, + child: child, + ), + ); + }, + title: 'Deliverzler', + debugShowCheckedModeBanner: false, + color: Theme.of(context).colorScheme.primary, + theme: theme.getThemeData(locale.fontFamily), + locale: Locale(locale.code), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, ); } } diff --git a/lib/auth/presentation/components/login_form_component.dart b/lib/auth/presentation/components/login_form_component.dart index c920771e..d1f8e280 100644 --- a/lib/auth/presentation/components/login_form_component.dart +++ b/lib/auth/presentation/components/login_form_component.dart @@ -6,9 +6,9 @@ import '../../../core/presentation/utils/event.dart'; import '../../../core/presentation/utils/fp_framework.dart'; import '../../../core/presentation/utils/riverpod_framework.dart'; import '../../../core/presentation/widgets/custom_button.dart'; +import '../../../core/presentation/widgets/platform_widgets/platform_icons.dart'; import '../../domain/sign_in_with_email.dart'; import '../providers/sign_in_provider.dart'; -import 'login_text_fields_section.dart'; class LoginFormComponent extends HookConsumerWidget { const LoginFormComponent({super.key}); @@ -33,9 +33,42 @@ class LoginFormComponent extends HookConsumerWidget { key: loginFormKey, child: Column( children: [ - LoginTextFieldsSection( - emailController: emailController, - passwordController: passwordController, + TextFormField( + key: const ValueKey('login_email'), + controller: emailController, + decoration: InputDecoration( + hintText: tr(context).email, + suffixIcon: Padding( + padding: EdgeInsetsDirectional.only( + end: Theme.of(context).inputDecorationTheme.contentPadding!.horizontal / 2, + ), + child: Icon(PlatformIcons.mail), + ), + suffixIconConstraints: const BoxConstraints(), + ), + validator: SignInWithEmail.validateEmail(context), + textInputAction: TextInputAction.next, + keyboardType: TextInputType.emailAddress, + ), + const SizedBox( + height: Sizes.textFieldMarginV24, + ), + TextFormField( + key: const ValueKey('login_password'), + controller: passwordController, + decoration: InputDecoration( + hintText: tr(context).password, + suffixIcon: Padding( + padding: EdgeInsetsDirectional.only( + end: Theme.of(context).inputDecorationTheme.contentPadding!.horizontal / 2, + ), + child: Icon(PlatformIcons.password), + ), + suffixIconConstraints: const BoxConstraints(), + ), + validator: SignInWithEmail.validatePassword(context), + textInputAction: TextInputAction.go, + obscureText: true, onFieldSubmitted: ref.isLoading(signInStateProvider) ? null : (_) => signIn(), ), const SizedBox( diff --git a/lib/auth/presentation/components/login_text_fields_section.dart b/lib/auth/presentation/components/login_text_fields_section.dart deleted file mode 100644 index 2b9d2230..00000000 --- a/lib/auth/presentation/components/login_text_fields_section.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import '../../../core/core_features/theme/presentation/utils/themes/cupertino_custom_theme.dart'; -import '../../../core/presentation/helpers/localization_helper.dart'; -import '../../../core/presentation/styles/sizes.dart'; -import '../../../core/presentation/widgets/custom_text_form_field.dart'; -import '../../../core/presentation/widgets/platform_widgets/platform_icons.dart'; -import '../../../core/presentation/widgets/platform_widgets/platform_widget.dart'; -import '../../domain/sign_in_with_email.dart'; - -class LoginTextFieldsSection extends StatelessWidget { - const LoginTextFieldsSection({ - required this.emailController, - required this.passwordController, - required this.onFieldSubmitted, - super.key, - }); - - final TextEditingController emailController; - final TextEditingController passwordController; - final ValueChanged? onFieldSubmitted; - - @override - Widget build(BuildContext context) { - return PlatformWidget( - material: (_) { - return Column( - children: _sharedItemComponent(context, true), - ); - }, - cupertino: (_) { - return CupertinoFormSection.insetGrouped( - decoration: CupertinoCustomTheme.cupertinoFormSectionDecoration(context), - backgroundColor: Colors.transparent, - margin: EdgeInsets.zero, - children: _sharedItemComponent(context, false), - ); - }, - ); - } - - List _sharedItemComponent(BuildContext context, bool isMaterial) { - return [ - CustomTextFormField( - key: const ValueKey('login_email'), - hintText: tr(context).email, - controller: emailController, - validator: SignInWithEmail.validateEmail(context), - textInputAction: TextInputAction.next, - keyboardType: TextInputType.emailAddress, - suffix: Icon(PlatformIcons.mail), - ), - if (isMaterial) - const SizedBox( - height: Sizes.textFieldMarginV24, - ), - CustomTextFormField( - key: const ValueKey('login_password'), - hintText: tr(context).password, - controller: passwordController, - validator: SignInWithEmail.validatePassword(context), - textInputAction: TextInputAction.go, - obscureText: true, - suffix: Icon(PlatformIcons.password), - onFieldSubmitted: onFieldSubmitted, - ), - ]; - } -} diff --git a/lib/auth/presentation/screens/sign_in_screen/sign_in_screen.dart b/lib/auth/presentation/screens/sign_in_screen/sign_in_screen.dart index 1b40f781..de5a2268 100755 --- a/lib/auth/presentation/screens/sign_in_screen/sign_in_screen.dart +++ b/lib/auth/presentation/screens/sign_in_screen/sign_in_screen.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../../../core/presentation/utils/riverpod_framework.dart'; -import '../../../../core/presentation/widgets/responsive_widgets/widget_builders.dart'; +import '../../../../core/presentation/widgets/responsive_widgets/responsive_layouts.dart'; import '../../providers/sign_in_provider.dart'; import 'sign_in_screen_compact.dart'; import 'sign_in_screen_medium.dart'; diff --git a/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_compact.dart b/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_compact.dart index 61ceca0f..e64f3438 100755 --- a/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_compact.dart +++ b/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_compact.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../core/presentation/screens/full_screen_platform_scaffold.dart'; +import '../../../../core/presentation/screens/full_screen_scaffold.dart'; import '../../../../core/presentation/styles/sizes.dart'; import '../../../../gen/my_assets.dart'; import '../../components/login_content_component.dart'; @@ -11,7 +11,7 @@ class SignInScreenCompact extends StatelessWidget { @override Widget build(BuildContext context) { - return FullScreenPlatformScaffold( + return FullScreenScaffold( body: CustomScrollView( slivers: [ SliverFillRemaining( diff --git a/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_medium.dart b/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_medium.dart index 64bd17b7..79c89a71 100755 --- a/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_medium.dart +++ b/lib/auth/presentation/screens/sign_in_screen/sign_in_screen_medium.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../core/presentation/screens/full_screen_platform_scaffold.dart'; +import '../../../../core/presentation/screens/full_screen_scaffold.dart'; import '../../../../core/presentation/styles/sizes.dart'; import '../../../../gen/my_assets.dart'; import '../../components/login_content_component.dart'; @@ -11,7 +11,7 @@ class SignInScreenMedium extends StatelessWidget { @override Widget build(BuildContext context) { - return FullScreenPlatformScaffold( + return FullScreenScaffold( body: CustomScrollView( slivers: [ SliverFillRemaining( diff --git a/lib/core/core_features/locale/presentation/utils/app_locale.dart b/lib/core/core_features/locale/presentation/utils/app_locale.dart index c8f82b0c..781404fa 100644 --- a/lib/core/core_features/locale/presentation/utils/app_locale.dart +++ b/lib/core/core_features/locale/presentation/utils/app_locale.dart @@ -2,15 +2,17 @@ import 'package:flutter/material.dart'; import '../../../../../gen/my_assets.dart'; import '../../../../presentation/helpers/localization_helper.dart'; +import '../../../../presentation/styles/font_styles.dart'; enum AppLocale { - english('en', MyAssets.ASSETS_ICONS_LANGUAGES_ICONS_ENGLISH_PNG), - arabic('ar', MyAssets.ASSETS_ICONS_LANGUAGES_ICONS_ARABIC_PNG); + english('en', MyAssets.ASSETS_ICONS_LANGUAGES_ICONS_ENGLISH_PNG, FontStyles.familyPoppins), + arabic('ar', MyAssets.ASSETS_ICONS_LANGUAGES_ICONS_ARABIC_PNG, FontStyles.familyTajawal); - const AppLocale(this.code, this.flag); + const AppLocale(this.code, this.flag, this.fontFamily); final String code; final String flag; + final String fontFamily; } extension LanguageExtension on AppLocale { diff --git a/lib/core/core_features/theme/presentation/utils/app_theme.dart b/lib/core/core_features/theme/presentation/utils/app_theme.dart index 7c0a5df4..bc21eb2d 100644 --- a/lib/core/core_features/theme/presentation/utils/app_theme.dart +++ b/lib/core/core_features/theme/presentation/utils/app_theme.dart @@ -10,10 +10,10 @@ enum AppTheme { } extension ThemeExtension on AppTheme { - ThemeData getThemeData() { + ThemeData getThemeData(String fontFamily) { return switch (this) { - AppTheme.light => ThemeLight().getThemeData(), - AppTheme.dark => ThemeDark().getThemeData(), + AppTheme.light => ThemeLight().getThemeData(fontFamily), + AppTheme.dark => ThemeDark().getThemeData(fontFamily), }; } diff --git a/lib/core/core_features/theme/presentation/utils/themes/i_theme.dart b/lib/core/core_features/theme/presentation/utils/themes/i_theme.dart index aeaaa83b..55cab8b2 100644 --- a/lib/core/core_features/theme/presentation/utils/themes/i_theme.dart +++ b/lib/core/core_features/theme/presentation/utils/themes/i_theme.dart @@ -16,10 +16,14 @@ abstract class ITheme { abstract final Color scaffoldBackgroundColor; - abstract final Color bottomAppBarColor; + abstract final NavigationBarThemeData navigationBarTheme; + + abstract final NavigationRailThemeData navigationRailTheme; abstract final TextTheme textTheme; + abstract final TextTheme primaryTextTheme; + abstract final Color hintColor; abstract final TextSelectionThemeData textSelectionTheme; @@ -38,23 +42,27 @@ abstract class ITheme { } extension ThemeExtension on ITheme { - ThemeData getThemeData() { + //TODO(AHMED): useMaterial3 + ThemeData getThemeData(String fontFamily) { return baseTheme.copyWith( appBarTheme: appBarTheme, scaffoldBackgroundColor: scaffoldBackgroundColor, + navigationBarTheme: navigationBarTheme, + navigationRailTheme: navigationRailTheme, primaryColor: primaryColor, colorScheme: colorScheme, + textTheme: textTheme.apply(fontFamily: fontFamily), + primaryTextTheme: primaryTextTheme.apply(fontFamily: fontFamily), iconTheme: iconTheme, buttonTheme: buttonTheme, toggleButtonsTheme: toggleButtonsTheme, - textTheme: textTheme, hintColor: hintColor, textSelectionTheme: textSelectionTheme, inputDecorationTheme: inputDecorationTheme, cardTheme: cardTheme, extensions: [ this.customColors, - ], bottomAppBarTheme: BottomAppBarTheme(color: bottomAppBarColor), + ], ); } } diff --git a/lib/core/core_features/theme/presentation/utils/themes/theme_dark.dart b/lib/core/core_features/theme/presentation/utils/themes/theme_dark.dart index 5ad1260c..cca45c04 100755 --- a/lib/core/core_features/theme/presentation/utils/themes/theme_dark.dart +++ b/lib/core/core_features/theme/presentation/utils/themes/theme_dark.dart @@ -39,15 +39,37 @@ class ThemeDark implements ITheme { late final Color scaffoldBackgroundColor = appColors.scaffoldBGColor; @override - late final Color bottomAppBarColor = appColors.bottomNavBarColor; + late final NavigationBarThemeData navigationBarTheme = NavigationBarThemeData( + backgroundColor: appColors.bottomNavBarColor, + surfaceTintColor: Colors.transparent, + shadowColor: appColors.bottomNavBarColor, + indicatorColor: Colors.blue.shade100, + labelTextStyle: MaterialStateProperty.resolveWith((states) { + return TextStyle( + color: appColors.customColors.font14Color, + fontSize: Sizes.font12, + ); + }), + elevation: 4, + ); + + @override + late final NavigationRailThemeData navigationRailTheme = NavigationRailThemeData( + backgroundColor: appColors.bottomNavBarColor, + elevation: 4, + ); @override late final TextTheme textTheme = TextTheme( titleMedium: TextStyle( color: appColors.textFieldSubtitle1Color, + fontSize: Sizes.font14, ), ); + @override + late final TextTheme primaryTextTheme = baseTheme.primaryTextTheme; + @override late final Color hintColor = appColors.textFieldHintColor; @@ -58,7 +80,17 @@ class ThemeDark implements ITheme { @override late final InputDecorationTheme inputDecorationTheme = InputDecorationTheme( + contentPadding: const EdgeInsets.symmetric( + vertical: Sizes.textFieldPaddingV14, + horizontal: Sizes.textFieldPaddingH14, + ), + isDense: true, + filled: true, fillColor: appColors.textFieldFillColor, + hintStyle: TextStyle( + fontSize: Sizes.font12, + color: appColors.textFieldHintColor, + ), prefixIconColor: appColors.textFieldPrefixIconColor, suffixIconColor: appColors.textFieldSuffixIconColor, border: OutlineInputBorder( @@ -97,8 +129,18 @@ class ThemeDark implements ITheme { width: 0.8, ), ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: const BorderRadius.all( + Radius.circular(Sizes.textFieldR12), + ), + borderSide: BorderSide( + color: appColors.textFieldErrorBorderColor, + width: 0.8, + ), + ), errorStyle: TextStyle( color: appColors.textFieldErrorStyleColor, + fontSize: Sizes.font12, ), ); diff --git a/lib/core/core_features/theme/presentation/utils/themes/theme_light.dart b/lib/core/core_features/theme/presentation/utils/themes/theme_light.dart index 6e272f22..b3f9b294 100755 --- a/lib/core/core_features/theme/presentation/utils/themes/theme_light.dart +++ b/lib/core/core_features/theme/presentation/utils/themes/theme_light.dart @@ -39,15 +39,37 @@ class ThemeLight implements ITheme { late final Color scaffoldBackgroundColor = appColors.scaffoldBGColor; @override - late final Color bottomAppBarColor = appColors.bottomNavBarColor; + late final NavigationBarThemeData navigationBarTheme = NavigationBarThemeData( + backgroundColor: appColors.bottomNavBarColor, + surfaceTintColor: Colors.transparent, + shadowColor: appColors.bottomNavBarColor, + indicatorColor: appColors.secondary.withOpacity(0.24), + labelTextStyle: MaterialStateProperty.resolveWith((states) { + return TextStyle( + color: appColors.customColors.font14Color, + fontSize: Sizes.font12, + ); + }), + elevation: 4, + ); + + @override + late final NavigationRailThemeData navigationRailTheme = NavigationRailThemeData( + backgroundColor: appColors.bottomNavBarColor, + elevation: 4, + ); @override late final TextTheme textTheme = TextTheme( titleMedium: TextStyle( color: appColors.textFieldSubtitle1Color, + fontSize: Sizes.font14, ), ); + @override + late final TextTheme primaryTextTheme = baseTheme.primaryTextTheme; + @override late final Color hintColor = appColors.textFieldHintColor; @@ -58,7 +80,17 @@ class ThemeLight implements ITheme { @override late final InputDecorationTheme inputDecorationTheme = InputDecorationTheme( + contentPadding: const EdgeInsets.symmetric( + vertical: Sizes.textFieldPaddingV14, + horizontal: Sizes.textFieldPaddingH14, + ), + isDense: true, + filled: true, fillColor: appColors.textFieldFillColor, + hintStyle: TextStyle( + fontSize: Sizes.font12, + color: appColors.textFieldHintColor, + ), prefixIconColor: appColors.textFieldPrefixIconColor, suffixIconColor: appColors.textFieldSuffixIconColor, border: OutlineInputBorder( @@ -97,8 +129,18 @@ class ThemeLight implements ITheme { width: 0.8, ), ), + focusedErrorBorder: OutlineInputBorder( + borderRadius: const BorderRadius.all( + Radius.circular(Sizes.textFieldR12), + ), + borderSide: BorderSide( + color: appColors.textFieldErrorBorderColor, + width: 0.8, + ), + ), errorStyle: TextStyle( color: appColors.textFieldErrorStyleColor, + fontSize: Sizes.font12, ), ); diff --git a/lib/core/presentation/components/appbar_with_icon_component.dart b/lib/core/presentation/components/appbar_with_icon_component.dart index b44b47e8..728aea3a 100644 --- a/lib/core/presentation/components/appbar_with_icon_component.dart +++ b/lib/core/presentation/components/appbar_with_icon_component.dart @@ -5,7 +5,6 @@ import '../styles/sizes.dart'; import '../widgets/custom_text.dart'; class AppBarWithIconComponent extends StatelessWidget { - const AppBarWithIconComponent({ required this.icon, required this.title, @@ -17,6 +16,7 @@ class AppBarWithIconComponent extends StatelessWidget { @override Widget build(BuildContext context) { return Row( + mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ ImageIcon( diff --git a/lib/core/presentation/helpers/platform_helper.dart b/lib/core/presentation/helpers/platform_helper.dart index 18a446c6..72a359b6 100644 --- a/lib/core/presentation/helpers/platform_helper.dart +++ b/lib/core/presentation/helpers/platform_helper.dart @@ -1,11 +1,21 @@ -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' show TargetPlatform, defaultTargetPlatform, kIsWeb; abstract class PlatformHelper { - static bool isMaterialApp() { + static bool _matchPlatform(List platforms) => + platforms.any((p) => defaultTargetPlatform == p); + + static bool get isMobileDevice => + !kIsWeb && (_matchPlatform([TargetPlatform.iOS, TargetPlatform.android])); + static bool get isDesktopDevice => + !kIsWeb && + _matchPlatform([TargetPlatform.macOS, TargetPlatform.windows, TargetPlatform.linux]); + static bool get isMobileDeviceOrWeb => kIsWeb || isMobileDevice; + static bool get isDesktopDeviceOrWeb => kIsWeb || isDesktopDevice; + + static bool get isMaterialApp { if (kIsWeb) return true; - if (defaultTargetPlatform == TargetPlatform.iOS || - defaultTargetPlatform == TargetPlatform.macOS) { + if (_matchPlatform([TargetPlatform.iOS, TargetPlatform.macOS, TargetPlatform.linux])) { return false; } else { return true; diff --git a/lib/core/presentation/helpers/theme_helper.dart b/lib/core/presentation/helpers/theme_helper.dart index c17ebe0f..de06bb07 100644 --- a/lib/core/presentation/helpers/theme_helper.dart +++ b/lib/core/presentation/helpers/theme_helper.dart @@ -24,13 +24,13 @@ SystemUiOverlayStyle getFullScreenOverlayStyle( ? SystemUiOverlayStyle.dark.copyWith( //For Android statusBarColor: Colors.transparent, - systemNavigationBarColor: Theme.of(context).scaffoldBackgroundColor, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, systemNavigationBarIconBrightness: Brightness.dark, ) : SystemUiOverlayStyle.light.copyWith( //For Android statusBarColor: Colors.transparent, - systemNavigationBarColor: Theme.of(context).scaffoldBackgroundColor, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, systemNavigationBarIconBrightness: Brightness.light, ); } diff --git a/lib/core/presentation/screens/full_screen_platform_scaffold.dart b/lib/core/presentation/screens/full_screen_scaffold.dart similarity index 67% rename from lib/core/presentation/screens/full_screen_platform_scaffold.dart rename to lib/core/presentation/screens/full_screen_scaffold.dart index e07eae66..1d1dd59f 100644 --- a/lib/core/presentation/screens/full_screen_platform_scaffold.dart +++ b/lib/core/presentation/screens/full_screen_scaffold.dart @@ -4,24 +4,28 @@ import '../../core_features/theme/presentation/providers/current_app_theme_provi import '../../core_features/theme/presentation/utils/app_theme.dart'; import '../helpers/theme_helper.dart'; import '../utils/riverpod_framework.dart'; -import '../widgets/platform_widgets/platform_scaffold.dart'; +import '../widgets/status_bar_spacer.dart'; -class FullScreenPlatformScaffold extends ConsumerWidget { - const FullScreenPlatformScaffold({ +class FullScreenScaffold extends ConsumerWidget { + const FullScreenScaffold({ required this.body, + this.hasStatusBarSpace = false, + this.statusBarColor, this.darkOverlays, super.key, }); final Widget body; + final bool hasStatusBarSpace; + final Color? statusBarColor; final bool? darkOverlays; @override Widget build(BuildContext context, WidgetRef ref) { final currentTheme = ref.watch(currentAppThemeProvider); - return PlatformScaffold( - hasEmptyAppbar: false, + return Scaffold( + appBar: hasStatusBarSpace ? StatusBarSpacer(statusBarColor: statusBarColor) : null, body: AnnotatedRegion( value: getFullScreenOverlayStyle( context, diff --git a/lib/core/presentation/screens/nested_screen_scaffold.dart b/lib/core/presentation/screens/nested_screen_scaffold.dart index c65daa8c..5f0f82b3 100644 --- a/lib/core/presentation/screens/nested_screen_scaffold.dart +++ b/lib/core/presentation/screens/nested_screen_scaffold.dart @@ -1,47 +1,21 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../../../features/home_shell/presentation/components/tab_appbar_component.dart'; -import '../styles/sizes.dart'; -import '../widgets/platform_widgets/platform_widget.dart'; - //This is necessary with nested navigation to prevent transparent background of nested screens when navigating class NestedScreenScaffold extends StatelessWidget { const NestedScreenScaffold({ required this.body, this.backgroundColor, - this.resizeToAvoidBottomInset = true, - this.hasAppBar = true, super.key, }); final Widget body; final Color? backgroundColor; - final bool resizeToAvoidBottomInset; - final bool hasAppBar; @override Widget build(BuildContext context) { return ColoredBox( color: backgroundColor ?? Theme.of(context).scaffoldBackgroundColor, - child: PlatformWidget( - material: (_) { - return body; - }, - cupertino: (_) { - return CupertinoPageScaffold( - navigationBar: hasAppBar - ? TabAppBarComponent( - toolbarHeight: Sizes.appBarHeight56, - backgroundColor: Theme.of(context).appBarTheme.backgroundColor, - ) - : null, - backgroundColor: backgroundColor ?? Theme.of(context).scaffoldBackgroundColor, - resizeToAvoidBottomInset: resizeToAvoidBottomInset, - child: body, - ); - }, - ), + child: body, ); } } diff --git a/lib/core/presentation/screens/no_internet_screen/no_internet_screen.dart b/lib/core/presentation/screens/no_internet_screen/no_internet_screen.dart index 43f1230d..8dc03c1d 100755 --- a/lib/core/presentation/screens/no_internet_screen/no_internet_screen.dart +++ b/lib/core/presentation/screens/no_internet_screen/no_internet_screen.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import '../../routing/app_router.dart'; import '../../utils/riverpod_framework.dart'; -import '../../widgets/responsive_widgets/widget_builders.dart'; +import '../../widgets/responsive_widgets/responsive_layouts.dart'; import 'no_internet_screen_compact.dart'; class NoInternetScreen extends HookConsumerWidget { diff --git a/lib/core/presentation/screens/no_internet_screen/no_internet_screen_compact.dart b/lib/core/presentation/screens/no_internet_screen/no_internet_screen_compact.dart index 8c03c5e0..5ad70eb8 100755 --- a/lib/core/presentation/screens/no_internet_screen/no_internet_screen_compact.dart +++ b/lib/core/presentation/screens/no_internet_screen/no_internet_screen_compact.dart @@ -2,14 +2,14 @@ import 'package:flutter/material.dart'; import '../../components/no_internet_error_component.dart'; import '../../styles/sizes.dart'; -import '../../widgets/platform_widgets/platform_scaffold.dart'; +import '../full_screen_scaffold.dart'; class NoInternetScreenCompact extends StatelessWidget { const NoInternetScreenCompact({super.key}); @override Widget build(BuildContext context) { - return const PlatformScaffold( + return const FullScreenScaffold( body: CustomScrollView( slivers: [ SliverFillRemaining( diff --git a/lib/core/presentation/screens/route_error_screen/route_error_screen.dart b/lib/core/presentation/screens/route_error_screen/route_error_screen.dart index 560b8155..339ac673 100755 --- a/lib/core/presentation/screens/route_error_screen/route_error_screen.dart +++ b/lib/core/presentation/screens/route_error_screen/route_error_screen.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import '../../routing/app_router.dart'; import '../../utils/riverpod_framework.dart'; -import '../../widgets/responsive_widgets/widget_builders.dart'; +import '../../widgets/responsive_widgets/responsive_layouts.dart'; import 'route_error_screen_compact.dart'; class RouteErrorScreen extends HookConsumerWidget { diff --git a/lib/core/presentation/screens/route_error_screen/route_error_screen_compact.dart b/lib/core/presentation/screens/route_error_screen/route_error_screen_compact.dart index 63f940d6..675490c1 100755 --- a/lib/core/presentation/screens/route_error_screen/route_error_screen_compact.dart +++ b/lib/core/presentation/screens/route_error_screen/route_error_screen_compact.dart @@ -2,14 +2,14 @@ import 'package:flutter/material.dart'; import '../../components/route_error_component.dart'; import '../../styles/sizes.dart'; -import '../../widgets/platform_widgets/platform_scaffold.dart'; +import '../full_screen_scaffold.dart'; class ErrorScreenCompact extends StatelessWidget { const ErrorScreenCompact({super.key}); @override Widget build(BuildContext context) { - return const PlatformScaffold( + return const FullScreenScaffold( body: CustomScrollView( slivers: [ SliverFillRemaining( diff --git a/lib/core/presentation/screens/splash_screen/splash_screen.dart b/lib/core/presentation/screens/splash_screen/splash_screen.dart index ca88247e..4cb950cb 100755 --- a/lib/core/presentation/screens/splash_screen/splash_screen.dart +++ b/lib/core/presentation/screens/splash_screen/splash_screen.dart @@ -6,7 +6,7 @@ import '../../hooks/fade_in_controller_hook.dart'; import '../../providers/splash_providers.dart'; import '../../routing/app_router.dart'; import '../../utils/riverpod_framework.dart'; -import '../../widgets/responsive_widgets/widget_builders.dart'; +import '../../widgets/responsive_widgets/responsive_layouts.dart'; import 'splash_screen_compact.dart'; class SplashScreen extends HookConsumerWidget { diff --git a/lib/core/presentation/screens/splash_screen/splash_screen_compact.dart b/lib/core/presentation/screens/splash_screen/splash_screen_compact.dart index c5dca8e5..dfc22a70 100755 --- a/lib/core/presentation/screens/splash_screen/splash_screen_compact.dart +++ b/lib/core/presentation/screens/splash_screen/splash_screen_compact.dart @@ -8,7 +8,7 @@ import '../../helpers/localization_helper.dart'; import '../../styles/font_styles.dart'; import '../../styles/sizes.dart'; import '../../widgets/custom_text.dart'; -import '../full_screen_platform_scaffold.dart'; +import '../full_screen_scaffold.dart'; class SplashScreenCompact extends StatelessWidget { const SplashScreenCompact({ @@ -20,7 +20,7 @@ class SplashScreenCompact extends StatelessWidget { @override Widget build(BuildContext context) { - return FullScreenPlatformScaffold( + return FullScreenScaffold( body: Stack( alignment: Alignment.center, children: [ diff --git a/lib/core/presentation/styles/font_styles.dart b/lib/core/presentation/styles/font_styles.dart index f1cc2241..6e00f9aa 100755 --- a/lib/core/presentation/styles/font_styles.dart +++ b/lib/core/presentation/styles/font_styles.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; -import '../helpers/localization_helper.dart'; import 'sizes.dart'; class FontStyles { - static String fontFamily(BuildContext context) => tr(context).fontFamily; + static const String familyPoppins = 'Poppins'; + static const String familyTajawal = 'Tajawal'; static const fontWeightBlack = FontWeight.w900; static const fontWeightExtraBold = FontWeight.w800; @@ -19,7 +19,6 @@ class FontStyles { static TextStyle mapSearchBarFontStyle(BuildContext context) => TextStyle( fontSize: Sizes.font16, color: Theme.of(context).textTheme.titleMedium!.color, - fontFamily: fontFamily(context), fontWeight: fontWeightNormal, ); } diff --git a/lib/core/presentation/styles/sizes.dart b/lib/core/presentation/styles/sizes.dart index ec8ca8df..809821df 100755 --- a/lib/core/presentation/styles/sizes.dart +++ b/lib/core/presentation/styles/sizes.dart @@ -115,7 +115,7 @@ abstract class Sizes { //AppBar static const double appBarHeight56 = 56; - static const double appBarButtonR32 = 32; + static const double appBarLeadingWidth = 68; //Drawer static const double drawerWidth240 = 240; diff --git a/lib/core/presentation/utils/window_size_class.dart b/lib/core/presentation/utils/window_size_class.dart deleted file mode 100644 index a84b60ad..00000000 --- a/lib/core/presentation/utils/window_size_class.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -//Abiding to Material 3 Design guidelines: -//https://m3.material.io/foundations/adaptive-design/large-screens/overview -enum WindowSizeClass { - compact(0), - medium(600), - expanded(840); - - const WindowSizeClass(this.breakpoint); - - final int breakpoint; -} - -WindowSizeClass getWindowClass(Size size) { - late final double deviceWidth; - - //Use width=Size.width rather than width=Size.shortest when on Web/Desktop. - //This fixes when window's height is adjusted but the width is still wide, should - //be considered expanded instead of medium/compact. - if (kIsWeb || Platform.isMacOS || Platform.isWindows || Platform.isLinux) { - deviceWidth = size.width; - } else { - deviceWidth = size.shortestSide; - } - - if (deviceWidth >= WindowSizeClass.expanded.breakpoint) { - return WindowSizeClass.expanded; - } - if (deviceWidth >= WindowSizeClass.medium.breakpoint) { - return WindowSizeClass.medium; - } - return WindowSizeClass.compact; -} diff --git a/lib/core/presentation/widgets/custom_app_bar.dart b/lib/core/presentation/widgets/custom_app_bar.dart new file mode 100644 index 00000000..4cc7e442 --- /dev/null +++ b/lib/core/presentation/widgets/custom_app_bar.dart @@ -0,0 +1,69 @@ +import 'package:flutter/material.dart'; + +import '../routing/navigation_service.dart'; +import '../styles/sizes.dart'; + +class CustomAppBar extends StatelessWidget { + const CustomAppBar({ + this.title, + this.centerTitle = false, + this.hasBackButton = false, + this.result, + this.trailingActions, + this.appBarPadding = EdgeInsets.zero, + this.backgroundColor, + this.statusBarColor, + super.key, + }); + + final Widget? title; + final bool centerTitle; + final bool hasBackButton; + final Object? result; + final List? trailingActions; + final EdgeInsetsGeometry? appBarPadding; + final Color? backgroundColor; + final Color? statusBarColor; + + @override + Widget build(BuildContext context) { + return Container( + color: backgroundColor ?? Theme.of(context).appBarTheme.backgroundColor, + // This is helpful for adding symmetric padding for the whole appbar. + padding: appBarPadding, + child: AppBar( + leading: hasBackButton ? CustomBackButton(result: result) : null, + leadingWidth: Sizes.appBarLeadingWidth, + automaticallyImplyLeading: false, + title: title, + centerTitle: centerTitle, + titleSpacing: 0, + actions: trailingActions, + backgroundColor: backgroundColor, + systemOverlayStyle: Theme.of(context) + .appBarTheme + .systemOverlayStyle + ?.copyWith(statusBarColor: statusBarColor), + ), + ); + } +} + +class CustomBackButton extends StatelessWidget { + const CustomBackButton({ + required this.result, + super.key, + }); + final dynamic result; + + @override + Widget build(BuildContext context) { + return FittedBox( + fit: BoxFit.scaleDown, + child: BackButton( + color: Theme.of(context).iconTheme.color, + onPressed: () => NavigationService.pop(context, result: result), + ), + ); + } +} diff --git a/lib/core/presentation/widgets/custom_app_bar_widget.dart b/lib/core/presentation/widgets/custom_app_bar_widget.dart deleted file mode 100644 index 9cd5484f..00000000 --- a/lib/core/presentation/widgets/custom_app_bar_widget.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../routing/navigation_service.dart'; -import '../styles/sizes.dart'; -import 'platform_widgets/platform_app_bar.dart'; -import 'platform_widgets/platform_icon_button.dart'; -import 'platform_widgets/platform_icons.dart'; - -class CustomAppBar extends PlatformAppBar { - CustomAppBar( - BuildContext context, { - super.key, - double? height = Sizes.appBarHeight56, - Color? backgroundColor, - GlobalKey? scaffoldKey, - super.title, - bool centerTitle = false, - bool hasBackButton = false, - dynamic result, - bool hasMenuButton = false, - Widget? customLeading, - List? trailingActions, - double elevation = 0, - }) : super( - toolbarHeight: height, - backgroundColor: - backgroundColor ?? Theme.of(context).appBarTheme.backgroundColor, - leading: hasBackButton - ? CustomBackButton(result: result) - : hasMenuButton - ? CustomMenuButton(scaffoldKey: scaffoldKey!) - : customLeading, - automaticallyImplyLeading: false, - actions: [ - if (trailingActions != null) ...trailingActions, - if (hasBackButton) - const SizedBox( - width: Sizes.appBarButtonR32 * 2, - ), - if (hasMenuButton) - const SizedBox( - width: Sizes.appBarButtonR32 * 2, - ), - ], - materialData: MaterialAppBarData( - centerTitle: centerTitle, - elevation: elevation, - leadingWidth: Sizes.appBarButtonR32 * 2, - titleSpacing: Sizes.paddingH20, - ), - cupertinoData: const CupertinoNavigationBarData( - transitionBetweenRoutes: false, - border: Border(bottom: BorderSide(color: Colors.transparent)), - ), - ); -} - -class CustomBackButton extends StatelessWidget { - - const CustomBackButton({ - required this.result, - this.color, - this.padding, - this.isLTROnly = false, - super.key, - }); - final dynamic result; - final Color? color; - final EdgeInsets? padding; - final bool isLTROnly; - - @override - Widget build(BuildContext context) { - return PlatformIconButton( - onPressed: () => NavigationService.pop(context, result: result), - icon: Icon( - PlatformIcons.back, - color: color ?? Theme.of(context).iconTheme.color, - size: Sizes.appBarButtonR32, - textDirection: isLTROnly ? TextDirection.ltr : null, - ), - padding: padding ?? - const EdgeInsets.symmetric( - horizontal: Sizes.appBarButtonR32 / 2, - ), - materialData: const MaterialIconButtonData( - constraints: BoxConstraints(), - splashColor: Colors.transparent, - highlightColor: Colors.transparent, - ), - cupertinoData: const CupertinoButtonData( - minSize: 0, - alignment: Alignment.center, - ), - ); - } -} - -class CustomMenuButton extends StatelessWidget { - - const CustomMenuButton({ - required this.scaffoldKey, - super.key, - }); - final GlobalKey scaffoldKey; - - @override - Widget build(BuildContext context) { - return PlatformIconButton( - onPressed: () { - scaffoldKey.currentState?.openDrawer(); - }, - icon: Icon( - Icons.menu_rounded, - size: Sizes.appBarButtonR32, - color: Theme.of(context).colorScheme.primary, - ), - padding: const EdgeInsets.symmetric( - horizontal: Sizes.appBarButtonR32 / 2, - ), - materialData: const MaterialIconButtonData( - constraints: BoxConstraints(), - splashColor: Colors.transparent, - highlightColor: Colors.transparent, - ), - cupertinoData: const CupertinoButtonData( - minSize: 0, - alignment: Alignment.center, - ), - ); - } -} diff --git a/lib/core/presentation/widgets/custom_text.dart b/lib/core/presentation/widgets/custom_text.dart index 94541811..be7ef773 100644 --- a/lib/core/presentation/widgets/custom_text.dart +++ b/lib/core/presentation/widgets/custom_text.dart @@ -35,7 +35,6 @@ class CustomText extends Text { fontSize: size, fontWeight: weight, decoration: underline ? TextDecoration.underline : null, - fontFamily: FontStyles.fontFamily(context), ), ); diff --git a/lib/core/presentation/widgets/custom_text_form_field.dart b/lib/core/presentation/widgets/legacy/custom_text_form_field.dart similarity index 92% rename from lib/core/presentation/widgets/custom_text_form_field.dart rename to lib/core/presentation/widgets/legacy/custom_text_form_field.dart index 93bba02d..c3d11986 100644 --- a/lib/core/presentation/widgets/custom_text_form_field.dart +++ b/lib/core/presentation/widgets/legacy/custom_text_form_field.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import '../helpers/platform_helper.dart'; -import '../styles/font_styles.dart'; -import '../styles/sizes.dart'; +import '../../helpers/platform_helper.dart'; +import '../../styles/font_styles.dart'; +import '../../styles/sizes.dart'; import 'platform_widgets/platform_text_form_field.dart'; class CustomTextFormField extends StatelessWidget { @@ -69,7 +69,6 @@ class CustomTextFormField extends StatelessWidget { style: TextStyle( color: Theme.of(context).textTheme.titleMedium?.color, fontSize: Sizes.font14, - fontFamily: FontStyles.fontFamily(context), ), cursorColor: Theme.of(context).textSelectionTheme.cursorColor, materialData: MaterialTextFormFieldData( @@ -85,7 +84,6 @@ class CustomTextFormField extends StatelessWidget { hintText: hintText, hintStyle: TextStyle( fontSize: Sizes.font12, - fontFamily: FontStyles.fontFamily(context), color: Theme.of(context).hintColor, ), prefixIcon: materialPrefix, @@ -105,7 +103,6 @@ class CustomTextFormField extends StatelessWidget { color: Theme.of(context).inputDecorationTheme.errorStyle?.color, fontWeight: FontStyles.fontWeightNormal, fontSize: Sizes.font12, - fontFamily: FontStyles.fontFamily(context), ), errorMaxLines: errorMaxLines, border: Theme.of(context).inputDecorationTheme.border, @@ -125,14 +122,13 @@ class CustomTextFormField extends StatelessWidget { placeHolder: hintText, placeholderStyle: TextStyle( fontSize: Sizes.font12, - fontFamily: FontStyles.fontFamily(context), color: Theme.of(context).hintColor, ), prefix: cupertinoPrefix, ), ), //Add suffix manually for iOS https://github.com/flutter/flutter/issues/103385 - if (suffix != null && !PlatformHelper.isMaterialApp()) + if (suffix != null && !PlatformHelper.isMaterialApp) PositionedDirectional( top: (contentPadding?.top ?? Sizes.textFieldPaddingV10) * 1.5, end: Sizes.paddingH14, diff --git a/lib/core/presentation/widgets/legacy/platform_widgets/full_screen_platform_scaffold.dart b/lib/core/presentation/widgets/legacy/platform_widgets/full_screen_platform_scaffold.dart new file mode 100644 index 00000000..fa322803 --- /dev/null +++ b/lib/core/presentation/widgets/legacy/platform_widgets/full_screen_platform_scaffold.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; + +import '../../../../core_features/theme/presentation/providers/current_app_theme_provider.dart'; +import '../../../../core_features/theme/presentation/utils/app_theme.dart'; +import '../../../helpers/theme_helper.dart'; +import '../../../utils/riverpod_framework.dart'; +import 'platform_scaffold.dart'; + +class FullScreenPlatformScaffold extends ConsumerWidget { + const FullScreenPlatformScaffold({ + required this.body, + this.darkOverlays, + super.key, + }); + + final Widget body; + final bool? darkOverlays; + + @override + Widget build(BuildContext context, WidgetRef ref) { + final currentTheme = ref.watch(currentAppThemeProvider); + + return PlatformScaffold( + hasStatusBarSpace: false, + body: AnnotatedRegion( + value: getFullScreenOverlayStyle( + context, + darkOverlays: darkOverlays ?? currentTheme == AppTheme.light, + ), + child: body, + ), + ); + } +} diff --git a/lib/core/presentation/widgets/platform_widgets/platform_app.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_app.dart similarity index 97% rename from lib/core/presentation/widgets/platform_widgets/platform_app.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_app.dart index 7f8f37a9..5e602014 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_app.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_app.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'platform_base_widget.dart'; +import '../../platform_widgets/platform_base_widget.dart'; class PlatformApp extends PlatformBaseWidget { const PlatformApp({ diff --git a/lib/core/presentation/widgets/platform_widgets/platform_app_bar.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_app_bar.dart similarity index 93% rename from lib/core/presentation/widgets/platform_widgets/platform_app_bar.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_app_bar.dart index e3a3b570..8da912a8 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_app_bar.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_app_bar.dart @@ -1,8 +1,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../../styles/sizes.dart'; -import 'platform_base_widget.dart'; +import '../../../styles/sizes.dart'; +import '../../platform_widgets/platform_base_widget.dart'; class PlatformAppBar extends PlatformBaseWidget { const PlatformAppBar({ @@ -50,8 +50,7 @@ class PlatformAppBar extends PlatformBaseWidget { return SizedBox( //Have to add height here in addition to PreferredSizeWidget.. //https://github.com/flutter/flutter/issues/112326 - height: Sizes.statusBarHeight + - (toolbarHeight ?? kMinInteractiveDimensionCupertino), + height: Sizes.statusBarHeight + (toolbarHeight ?? kMinInteractiveDimensionCupertino), child: CupertinoNavigationBar( key: widgetKey, backgroundColor: backgroundColor, diff --git a/lib/core/presentation/widgets/platform_widgets/platform_base_consumer_widget.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_base_consumer_widget.dart similarity index 79% rename from lib/core/presentation/widgets/platform_widgets/platform_base_consumer_widget.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_base_consumer_widget.dart index 0c16ded1..94796e18 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_base_consumer_widget.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_base_consumer_widget.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import '../../helpers/platform_helper.dart'; -import '../../utils/riverpod_framework.dart'; +import '../../../helpers/platform_helper.dart'; +import '../../../utils/riverpod_framework.dart'; /// Base class to be extended by all platform widgets abstract class PlatformBaseConsumerWidget @@ -10,7 +10,7 @@ abstract class PlatformBaseConsumerWidget @override Widget build(BuildContext context, WidgetRef ref) { - return PlatformHelper.isMaterialApp() + return PlatformHelper.isMaterialApp ? createMaterialWidget(context, ref) : createCupertinoWidget(context, ref); } diff --git a/lib/core/presentation/widgets/platform_widgets/platform_icon_button.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_icon_button.dart similarity index 87% rename from lib/core/presentation/widgets/platform_widgets/platform_icon_button.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_icon_button.dart index 9a663c87..02f29eb9 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_icon_button.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_icon_button.dart @@ -1,12 +1,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'platform_base_widget.dart'; +import '../../platform_widgets/platform_base_widget.dart'; -class PlatformIconButton - extends PlatformBaseWidget { +class PlatformIconButton extends PlatformBaseWidget { const PlatformIconButton({ - required this.icon, required this.onPressed, super.key, + required this.icon, + required this.onPressed, + super.key, this.widgetKey, this.padding, this.materialData, diff --git a/lib/core/presentation/widgets/platform_widgets/platform_nav_bar.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_nav_bar.dart similarity index 89% rename from lib/core/presentation/widgets/platform_widgets/platform_nav_bar.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_nav_bar.dart index a49d520c..c25cfcdf 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_nav_bar.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_nav_bar.dart @@ -1,12 +1,13 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'platform_base_widget.dart'; +import '../../platform_widgets/platform_base_widget.dart'; -class PlatformNavBar - extends PlatformBaseWidget { +class PlatformNavBar extends PlatformBaseWidget { const PlatformNavBar({ - required this.materialData, required this.cupertinoData, super.key, + required this.materialData, + required this.cupertinoData, + super.key, this.widgetKey, this.currentIndex = 0, this.onTap, diff --git a/lib/core/presentation/widgets/platform_widgets/platform_page_route.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_page_route.dart similarity index 88% rename from lib/core/presentation/widgets/platform_widgets/platform_page_route.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_page_route.dart index a0bfa208..1ddb9036 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_page_route.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_page_route.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../../helpers/platform_helper.dart'; +import '../../../helpers/platform_helper.dart'; PageRoute platformPageRoute({ required WidgetBuilder builder, @@ -10,7 +10,7 @@ PageRoute platformPageRoute({ bool fullscreenDialog = false, String? iosTitle, }) { - if (PlatformHelper.isMaterialApp()) { + if (PlatformHelper.isMaterialApp) { return MaterialPageRoute( builder: builder, settings: settings, diff --git a/lib/core/presentation/widgets/platform_widgets/platform_scaffold.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_scaffold.dart similarity index 86% rename from lib/core/presentation/widgets/platform_widgets/platform_scaffold.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_scaffold.dart index 9fb5ddd5..cb97942b 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_scaffold.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_scaffold.dart @@ -1,15 +1,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../empty_appbar_widget.dart'; -import 'platform_base_widget.dart'; +import '../../status_bar_spacer.dart'; +import '../../platform_widgets/platform_base_widget.dart'; class PlatformScaffold extends PlatformBaseWidget { const PlatformScaffold({ required this.body, this.widgetKey, this.platformAppBar, - this.hasEmptyAppbar = true, + this.hasStatusBarSpace = true, this.backgroundColor, this.materialData, super.key, @@ -17,7 +17,7 @@ class PlatformScaffold extends PlatformBaseWidget { final Key? widgetKey; final Object? platformAppBar; - final bool hasEmptyAppbar; + final bool hasStatusBarSpace; final Widget body; final Color? backgroundColor; final MaterialScaffoldData? materialData; @@ -28,8 +28,8 @@ class PlatformScaffold extends PlatformBaseWidget { key: widgetKey, appBar: platformAppBar != null ? platformAppBar! as PreferredSizeWidget - : hasEmptyAppbar - ? EmptyAppBar( + : hasStatusBarSpace + ? StatusBarSpacer( statusBarColor: materialData?.statusBarColor, ) : null, @@ -47,8 +47,8 @@ class PlatformScaffold extends PlatformBaseWidget { key: widgetKey, navigationBar: platformAppBar != null ? platformAppBar! as ObstructingPreferredSizeWidget - : hasEmptyAppbar - ? const EmptyAppBar( + : hasStatusBarSpace + ? const StatusBarSpacer( //It's not allowed to set statusBarColor for iOS without an appbar. statusBarColor: Colors.transparent, ) diff --git a/lib/core/presentation/widgets/platform_widgets/platform_tab_scaffold.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_tab_scaffold.dart similarity index 97% rename from lib/core/presentation/widgets/platform_widgets/platform_tab_scaffold.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_tab_scaffold.dart index e65c44c6..7139907f 100644 --- a/lib/core/presentation/widgets/platform_widgets/platform_tab_scaffold.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_tab_scaffold.dart @@ -1,9 +1,9 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import '../../utils/riverpod_framework.dart'; -import 'platform_base_consumer_widget.dart'; +import '../../../utils/riverpod_framework.dart'; import 'platform_nav_bar.dart'; +import 'platform_base_consumer_widget.dart'; typedef IndexedAppBarBuilder = dynamic Function( BuildContext context, diff --git a/lib/core/presentation/widgets/platform_widgets/platform_text_form_field.dart b/lib/core/presentation/widgets/legacy/platform_widgets/platform_text_form_field.dart similarity index 96% rename from lib/core/presentation/widgets/platform_widgets/platform_text_form_field.dart rename to lib/core/presentation/widgets/legacy/platform_widgets/platform_text_form_field.dart index 31d3fb47..30c9dc38 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_text_form_field.dart +++ b/lib/core/presentation/widgets/legacy/platform_widgets/platform_text_form_field.dart @@ -2,10 +2,9 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'platform_base_widget.dart'; +import '../../platform_widgets/platform_base_widget.dart'; -class PlatformTextFormField - extends PlatformBaseWidget { +class PlatformTextFormField extends PlatformBaseWidget { const PlatformTextFormField({ super.key, this.widgetKey, diff --git a/lib/core/presentation/widgets/platform_widgets/platform_appbar.dart b/lib/core/presentation/widgets/platform_widgets/platform_appbar.dart new file mode 100644 index 00000000..1b4e1698 --- /dev/null +++ b/lib/core/presentation/widgets/platform_widgets/platform_appbar.dart @@ -0,0 +1,45 @@ +import 'package:flutter/cupertino.dart'; + +import '../../styles/sizes.dart'; + +class PreferredAppBarSize extends Size { + PreferredAppBarSize(this.toolbarHeight, this.bottomHeight) + : super.fromHeight(toolbarHeight + bottomHeight); + + final double toolbarHeight; + final double bottomHeight; +} + +class PlatformAppBar extends StatelessWidget + implements PreferredSizeWidget, ObstructingPreferredSizeWidget { + PlatformAppBar({ + required this.appbar, + this.toolbarHeight = Sizes.appBarHeight56, + this.bottom, + this.backgroundColor, + super.key, + }) : preferredSize = PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height ?? 0.0); + + final Widget appbar; + + // ToolbarHeight for Android/iOS and BackgroundColor for iOS must be pre-initialized, and we are + // implementing PreferredSizeWidget, ObstructingPreferredSizeWidget to be able to only rebuild the appbar. + final double toolbarHeight; + final PreferredSizeWidget? bottom; + final Color? backgroundColor; + + @override + Widget build(BuildContext context) { + return appbar; + } + + @override + final Size preferredSize; + + @override + bool shouldFullyObstruct(BuildContext context) { + final backgroundColor = CupertinoDynamicColor.maybeResolve(this.backgroundColor, context) ?? + CupertinoTheme.of(context).barBackgroundColor; + return backgroundColor.alpha == 0xFF; + } +} diff --git a/lib/core/presentation/widgets/platform_widgets/platform_base_widget.dart b/lib/core/presentation/widgets/platform_widgets/platform_base_widget.dart index 725c3adf..6a193b14 100755 --- a/lib/core/presentation/widgets/platform_widgets/platform_base_widget.dart +++ b/lib/core/presentation/widgets/platform_widgets/platform_base_widget.dart @@ -3,13 +3,12 @@ import 'package:flutter/material.dart'; import '../../helpers/platform_helper.dart'; /// Base class to be extended by all platform widgets -abstract class PlatformBaseWidget - extends StatelessWidget { +abstract class PlatformBaseWidget extends StatelessWidget { const PlatformBaseWidget({super.key}); @override Widget build(BuildContext context) { - return PlatformHelper.isMaterialApp() + return PlatformHelper.isMaterialApp ? createMaterialWidget(context) : createCupertinoWidget(context); } diff --git a/lib/core/presentation/widgets/platform_widgets/platform_icons.dart b/lib/core/presentation/widgets/platform_widgets/platform_icons.dart index 6d3c6d91..e72a1a1f 100644 --- a/lib/core/presentation/widgets/platform_widgets/platform_icons.dart +++ b/lib/core/presentation/widgets/platform_widgets/platform_icons.dart @@ -4,45 +4,34 @@ import 'package:flutter/material.dart'; import '../../helpers/platform_helper.dart'; abstract class PlatformIcons { - static IconData get back => - PlatformHelper.isMaterialApp() ? Icons.arrow_back : CupertinoIcons.back; + static IconData get back => PlatformHelper.isMaterialApp ? Icons.arrow_back : CupertinoIcons.back; - static IconData get add => - PlatformHelper.isMaterialApp() ? Icons.add : CupertinoIcons.add; + static IconData get add => PlatformHelper.isMaterialApp ? Icons.add : CupertinoIcons.add; - static IconData get home => - PlatformHelper.isMaterialApp() ? Icons.home : CupertinoIcons.home; + static IconData get home => PlatformHelper.isMaterialApp ? Icons.home : CupertinoIcons.home; - static IconData get mail => - PlatformHelper.isMaterialApp() ? Icons.mail : CupertinoIcons.mail; + static IconData get mail => PlatformHelper.isMaterialApp ? Icons.mail : CupertinoIcons.mail; - static IconData get password => - PlatformHelper.isMaterialApp() ? Icons.password : Icons.password; + static IconData get password => PlatformHelper.isMaterialApp ? Icons.password : Icons.password; - static IconData get accountCircleSolid => PlatformHelper.isMaterialApp() - ? Icons.account_circle - : CupertinoIcons.person_crop_circle_fill; + static IconData get accountCircleSolid => + PlatformHelper.isMaterialApp ? Icons.account_circle : CupertinoIcons.person_crop_circle_fill; - static IconData get settingsSolid => PlatformHelper.isMaterialApp() - ? Icons.settings - : CupertinoIcons.settings_solid; + static IconData get settingsSolid => + PlatformHelper.isMaterialApp ? Icons.settings : CupertinoIcons.settings_solid; - static IconData get personSolid => PlatformHelper.isMaterialApp() - ? Icons.person - : CupertinoIcons.person_solid; + static IconData get personSolid => + PlatformHelper.isMaterialApp ? Icons.person : CupertinoIcons.person_solid; - static IconData get eyeSolid => PlatformHelper.isMaterialApp() - ? Icons.visibility - : CupertinoIcons.eye_solid; + static IconData get eyeSolid => + PlatformHelper.isMaterialApp ? Icons.visibility : CupertinoIcons.eye_solid; - static IconData get eyeSlashSolid => PlatformHelper.isMaterialApp() - ? Icons.visibility_off - : CupertinoIcons.eye_slash_fill; + static IconData get eyeSlashSolid => + PlatformHelper.isMaterialApp ? Icons.visibility_off : CupertinoIcons.eye_slash_fill; - static IconData get error => PlatformHelper.isMaterialApp() - ? Icons.error - : CupertinoIcons.exclamationmark_circle_fill; + static IconData get error => + PlatformHelper.isMaterialApp ? Icons.error : CupertinoIcons.exclamationmark_circle_fill; static IconData get checkMark => - PlatformHelper.isMaterialApp() ? Icons.check : CupertinoIcons.check_mark; + PlatformHelper.isMaterialApp ? Icons.check : CupertinoIcons.check_mark; } diff --git a/lib/core/presentation/widgets/responsive_widgets/widget_builders.dart b/lib/core/presentation/widgets/responsive_widgets/responsive_layouts.dart similarity index 55% rename from lib/core/presentation/widgets/responsive_widgets/widget_builders.dart rename to lib/core/presentation/widgets/responsive_widgets/responsive_layouts.dart index 4d12e3f3..1ce2b9c1 100644 --- a/lib/core/presentation/widgets/responsive_widgets/widget_builders.dart +++ b/lib/core/presentation/widgets/responsive_widgets/responsive_layouts.dart @@ -1,10 +1,39 @@ import 'package:flutter/material.dart'; -import '../../utils/window_size_class.dart'; +import '../../helpers/platform_helper.dart'; + +// TODO(AHMED): Migrate to BreakPoint from flutter_adaptive_scaffold?? +// Abiding to Material 3 Design guidelines: +// https://m3.material.io/foundations/adaptive-design/large-screens/overview +enum WindowSizeClass { + compact(0), + medium(600), + expanded(840); + + const WindowSizeClass(this.breakpoint); + + final int breakpoint; + + static WindowSizeClass determineWindowClass(Size size) { + // Use width rather than shortestSide when on Web/Desktop. + // Because when window's height is adjusted but the width is still wide, + // it should still be considered expanded instead of medium/compact. + final deviceWidth = PlatformHelper.isDesktopDeviceOrWeb ? size.width : size.shortestSide; + + if (deviceWidth >= WindowSizeClass.expanded.breakpoint) { + return WindowSizeClass.expanded; + } + if (deviceWidth >= WindowSizeClass.medium.breakpoint) { + return WindowSizeClass.medium; + } + return WindowSizeClass.compact; + } +} class WindowClassLayout extends StatelessWidget { const WindowClassLayout({ - required this.compact, super.key, + required this.compact, + super.key, this.medium, this.expanded, }); @@ -18,7 +47,7 @@ class WindowClassLayout extends StatelessWidget { return LayoutBuilder( builder: (context, constraints) { final size = Size(constraints.maxWidth, constraints.maxHeight); - final windowClass = getWindowClass(size); + final windowClass = WindowSizeClass.determineWindowClass(size); if (windowClass == WindowSizeClass.expanded) { if (expanded != null) return expanded!(context); @@ -39,7 +68,8 @@ class WindowClassLayout extends StatelessWidget { class OrientationLayout extends StatelessWidget { const OrientationLayout({ - required this.portrait, super.key, + required this.portrait, + super.key, this.landscape, }); diff --git a/lib/core/presentation/widgets/empty_appbar_widget.dart b/lib/core/presentation/widgets/status_bar_spacer.dart similarity index 63% rename from lib/core/presentation/widgets/empty_appbar_widget.dart rename to lib/core/presentation/widgets/status_bar_spacer.dart index 21234422..a9fec597 100644 --- a/lib/core/presentation/widgets/empty_appbar_widget.dart +++ b/lib/core/presentation/widgets/status_bar_spacer.dart @@ -2,18 +2,22 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -//This show StatusBar without an AppBar -class EmptyAppBar extends StatelessWidget +/// A widget that occupies the space of the status bar and customizes its appearance +/// without providing an actual app bar. +class StatusBarSpacer extends StatelessWidget implements PreferredSizeWidget, ObstructingPreferredSizeWidget { - const EmptyAppBar({ - this.systemOverlayStyle, + /// Creates a StatusBarSpacer. + /// It's a widget that occupies the space of the status bar and customizes its appearance + /// without providing an actual app bar. + const StatusBarSpacer({ this.statusBarColor, + this.systemOverlayStyle, this.elevation, super.key, }); - final SystemUiOverlayStyle? systemOverlayStyle; final Color? statusBarColor; + final SystemUiOverlayStyle? systemOverlayStyle; final double? elevation; @override @@ -25,7 +29,7 @@ class EmptyAppBar extends StatelessWidget .appBarTheme .systemOverlayStyle ?.copyWith(statusBarColor: statusBarColor), - elevation: elevation ?? Theme.of(context).appBarTheme.elevation, + elevation: elevation, ); } @@ -33,7 +37,5 @@ class EmptyAppBar extends StatelessWidget Size get preferredSize => const Size.fromHeight(0); @override - bool shouldFullyObstruct(BuildContext context) { - return true; - } + bool shouldFullyObstruct(BuildContext context) => true; } diff --git a/lib/features/home/presentation/components/dialogs/cancel_order_dialog.dart b/lib/features/home/presentation/components/dialogs/cancel_order_dialog.dart index bffb129f..eb6b140a 100644 --- a/lib/features/home/presentation/components/dialogs/cancel_order_dialog.dart +++ b/lib/features/home/presentation/components/dialogs/cancel_order_dialog.dart @@ -8,7 +8,6 @@ import '../../../../../core/presentation/styles/sizes.dart'; import '../../../../../core/presentation/utils/riverpod_framework.dart'; import '../../../../../core/presentation/widgets/custom_button.dart'; import '../../../../../core/presentation/widgets/custom_text.dart'; -import 'cancel_order_note_component.dart'; class CancelOrderDialog extends HookWidget { const CancelOrderDialog({super.key}); @@ -29,8 +28,16 @@ class CancelOrderDialog extends HookWidget { const SizedBox( height: Sizes.marginV12, ), - CancelOrderNoteComponent( - cancelNoteController: cancelNoteController, + TextFormField( + key: const ValueKey('cancel_note'), + controller: cancelNoteController, + decoration: InputDecoration( + hintText: '${tr(context).typeYourNote}...', + ), + textInputAction: TextInputAction.newline, + minLines: 1, + maxLines: 6, + maxLength: 200, ), const SizedBox( height: Sizes.marginV20, diff --git a/lib/features/home/presentation/components/dialogs/cancel_order_note_component.dart b/lib/features/home/presentation/components/dialogs/cancel_order_note_component.dart deleted file mode 100644 index a2771246..00000000 --- a/lib/features/home/presentation/components/dialogs/cancel_order_note_component.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import '../../../../../core/core_features/theme/presentation/utils/themes/cupertino_custom_theme.dart'; -import '../../../../../core/presentation/helpers/localization_helper.dart'; -import '../../../../../core/presentation/utils/riverpod_framework.dart'; -import '../../../../../core/presentation/widgets/custom_text_form_field.dart'; -import '../../../../../core/presentation/widgets/platform_widgets/platform_widget.dart'; - -class CancelOrderNoteComponent extends ConsumerWidget { - const CancelOrderNoteComponent({ - required this.cancelNoteController, - super.key, - }); - - final TextEditingController cancelNoteController; - - @override - Widget build(BuildContext context, WidgetRef ref) { - return PlatformWidget( - material: (_) { - return Column( - children: _sharedItemComponent(context, ref), - ); - }, - cupertino: (_) { - return CupertinoFormSection.insetGrouped( - decoration: - CupertinoCustomTheme.cupertinoFormSectionDecoration(context), - backgroundColor: Colors.transparent, - margin: EdgeInsets.zero, - children: _sharedItemComponent(context, ref), - ); - }, - ); - } - - List _sharedItemComponent(BuildContext context, WidgetRef ref) { - return [ - CustomTextFormField( - key: const ValueKey('cancel_note'), - hintText: '${tr(context).typeYourNote}...', - controller: cancelNoteController, - textInputAction: TextInputAction.newline, - maxLines: 6, - maxLength: 200, - ), - ]; - } -} diff --git a/lib/features/home/presentation/screens/home_screen/home_screen.dart b/lib/features/home/presentation/screens/home_screen/home_screen.dart index 735de4eb..16ca1bdd 100755 --- a/lib/features/home/presentation/screens/home_screen/home_screen.dart +++ b/lib/features/home/presentation/screens/home_screen/home_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../../core/presentation/widgets/responsive_widgets/widget_builders.dart'; +import '../../../../../core/presentation/widgets/responsive_widgets/responsive_layouts.dart'; import 'home_screen_compact.dart'; class HomeScreen extends StatelessWidget { diff --git a/lib/features/home_shell/presentation/components/bottom_nav_bar_component.dart b/lib/features/home_shell/presentation/components/bottom_nav_bar_component.dart deleted file mode 100755 index 85ae1eb1..00000000 --- a/lib/features/home_shell/presentation/components/bottom_nav_bar_component.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; - -import '../../../../core/core_features/theme/presentation/utils/colors/custom_colors.dart'; -import '../../../../core/presentation/styles/font_styles.dart'; -import '../../../../core/presentation/styles/sizes.dart'; -import '../../../../core/presentation/widgets/platform_widgets/platform_nav_bar.dart'; -import '../utils/tab_item.dart'; - -class BottomNavBarComponent extends PlatformNavBar { - BottomNavBarComponent( - BuildContext context, { - required TabItem currentTab, required ValueChanged onSelectTab, super.key, - }) : super( - currentIndex: currentTab.index, - onTap: (index) { - onSelectTab(TabItem.values[index]); - }, - backgroundColor: - Theme.of(context).bottomNavigationBarTheme.backgroundColor ?? - Theme.of(context).bottomAppBarTheme.color, - height: Sizes.bottomNavBarHeight60, - materialData: MaterialBottomNavBarData( - destinations: TabItem.values - .map((tabItem) => Theme( - data: Theme.of(context).copyWith( - navigationBarTheme: NavigationBarThemeData( - labelTextStyle: - MaterialStateProperty.resolveWith((states) { - return TextStyle( - color: customColors(context).font28Color, - fontSize: Sizes.font12, - fontFamily: FontStyles.fontFamily(context), - ); - }), - ), - ), - child: NavigationDestination( - icon: tabItem.getTabItemIcon(context), - selectedIcon: tabItem.getTabItemSelectedIcon(context), - label: tabItem.getTabItemLabel(context), - ), - ),) - .toList(), - elevation: 2, - ), - cupertinoData: CupertinoTabBarData( - items: TabItem.values - .map((tabItem) => BottomNavigationBarItem( - icon: tabItem.getTabItemIcon(context), - activeIcon: tabItem.getTabItemSelectedIcon(context), - label: tabItem.getTabItemLabel(context), - ),) - .toList(), - activeColor: Theme.of(context).colorScheme.primary, - ), - ); -} diff --git a/lib/features/home_shell/presentation/components/tab_appbar_component.dart b/lib/features/home_shell/presentation/components/home_shell_appbar.dart similarity index 56% rename from lib/features/home_shell/presentation/components/tab_appbar_component.dart rename to lib/features/home_shell/presentation/components/home_shell_appbar.dart index dffc2d21..aa4c4818 100755 --- a/lib/features/home_shell/presentation/components/tab_appbar_component.dart +++ b/lib/features/home_shell/presentation/components/home_shell_appbar.dart @@ -1,4 +1,3 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; @@ -7,40 +6,17 @@ import 'package:go_router/go_router.dart'; import '../../../../core/presentation/components/appbar_with_icon_component.dart'; import '../../../../core/presentation/helpers/localization_helper.dart'; import '../../../../core/presentation/routing/app_router.dart'; -import '../../../../core/presentation/widgets/custom_app_bar_widget.dart'; +import '../../../../core/presentation/widgets/custom_app_bar.dart'; import '../../../../core/presentation/widgets/custom_text.dart'; import '../../../../gen/my_assets.dart'; -/// The default height of the toolbar component of the [AppBar]. -const double kToolbarHeight = 56; - -class PreferredAppBarSize extends Size { - PreferredAppBarSize(this.toolbarHeight, this.bottomHeight) - : super.fromHeight((toolbarHeight ?? kToolbarHeight) + (bottomHeight ?? 0)); - - final double? toolbarHeight; - final double? bottomHeight; -} - -class TabAppBarComponent extends StatelessWidget - implements PreferredSizeWidget, ObstructingPreferredSizeWidget { - TabAppBarComponent({ - this.toolbarHeight, - this.bottom, - this.backgroundColor, - super.key, - }) : preferredSize = PreferredAppBarSize(toolbarHeight, bottom?.preferredSize.height); +class HomeShellAppBar extends StatelessWidget { + const HomeShellAppBar({super.key}); static final IList _noAppBarLocations = IListConst([ const MapRoute().location, ]); - //ToolbarHeight for Android/iOS and BackgroundColor for iOS must be pre-initialized, as we - //implementing PreferredSizeWidget, ObstructingPreferredSizeWidget to be able to rebuild only the appbar. - final double? toolbarHeight; - final PreferredSizeWidget? bottom; - final Color? backgroundColor; - @override Widget build(BuildContext context) { final location = GoRouterState.of(context).location; @@ -48,7 +24,6 @@ class TabAppBarComponent extends StatelessWidget /// Home Tab if (location == const HomeRoute().location) { return CustomAppBar( - context, centerTitle: true, title: CustomText.f20( context, @@ -61,7 +36,7 @@ class TabAppBarComponent extends StatelessWidget /// Profile Tab else if (location == const ProfileRoute().location) { return CustomAppBar( - context, + centerTitle: true, title: AppBarWithIconComponent( icon: MyAssets.ASSETS_ICONS_SCREENS_ICONS_PROFILE_PNG, title: tr(context).myProfile, @@ -72,7 +47,7 @@ class TabAppBarComponent extends StatelessWidget /// Settings Tab else if (location == const SettingsRoute().location) { return CustomAppBar( - context, + centerTitle: true, title: AppBarWithIconComponent( icon: MyAssets.ASSETS_ICONS_SCREENS_ICONS_SETTINGS_PNG, title: tr(context).settings, @@ -80,8 +55,8 @@ class TabAppBarComponent extends StatelessWidget ); } else if (location == const LanguageRoute().location) { return CustomAppBar( - context, hasBackButton: true, + centerTitle: true, title: AppBarWithIconComponent( icon: MyAssets.ASSETS_ICONS_SCREENS_ICONS_LANGUAGE_PNG, title: tr(context).language, @@ -89,23 +64,13 @@ class TabAppBarComponent extends StatelessWidget ); } - return CustomAppBar(context); - } - - @override - final Size preferredSize; - - @override - bool shouldFullyObstruct(BuildContext context) { - final backgroundColor = CupertinoDynamicColor.maybeResolve(this.backgroundColor, context) ?? - CupertinoTheme.of(context).barBackgroundColor; - return backgroundColor.alpha == 0xFF; + return const CustomAppBar(); } } extension StatefulNavigationShellX on StatefulNavigationShell { bool get currentLocationHasAppBar { final location = shellRouteContext.routerState.location; - return !TabAppBarComponent._noAppBarLocations.contains(location); + return !HomeShellAppBar._noAppBarLocations.contains(location); } } diff --git a/lib/features/home_shell/presentation/components/home_shell_bottom_nav_bar.dart b/lib/features/home_shell/presentation/components/home_shell_bottom_nav_bar.dart new file mode 100755 index 00000000..46035822 --- /dev/null +++ b/lib/features/home_shell/presentation/components/home_shell_bottom_nav_bar.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; + +import '../../../../core/presentation/styles/sizes.dart'; +import '../utils/tab_item.dart'; + +class HomeShellBottomNavBar extends StatelessWidget { + const HomeShellBottomNavBar({ + required this.currentTab, + required this.onSelectTab, + super.key, + }); + + final TabItem currentTab; + final ValueChanged onSelectTab; + + @override + Widget build(BuildContext context) { + return Theme( + //TODO(AHMED): remove when migrating the whole app to material3. + data: Theme.of(context).copyWith(useMaterial3: true), + child: PlatformNavBar( + height: Sizes.bottomNavBarHeight60, + currentIndex: currentTab.index, + itemChanged: (index) { + onSelectTab(TabItem.values[index]); + }, + material3: (_, __) { + return MaterialNavigationBarData( + items: TabItem.values + .map( + (tabItem) => NavigationDestination( + icon: tabItem.getTabItemIcon(context), + selectedIcon: tabItem.getTabItemSelectedIcon(context), + label: tabItem.getTabItemLabel(context), + ), + ) + .toList(), + ); + }, + cupertino: (_, __) { + return CupertinoTabBarData( + items: TabItem.values + .map( + (tabItem) => BottomNavigationBarItem( + icon: tabItem.getTabItemIcon(context), + activeIcon: tabItem.getTabItemSelectedIcon(context), + label: tabItem.getTabItemLabel(context), + ), + ) + .toList(), + ); + }, + ), + ); + } +} diff --git a/lib/features/home_shell/presentation/components/home_shell_navigation_rail.dart b/lib/features/home_shell/presentation/components/home_shell_navigation_rail.dart new file mode 100755 index 00000000..6be6d87b --- /dev/null +++ b/lib/features/home_shell/presentation/components/home_shell_navigation_rail.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart'; + +import '../../../../core/presentation/widgets/custom_text.dart'; +import '../utils/tab_item.dart'; + +class HomeShellNavigationRail extends StatelessWidget { + const HomeShellNavigationRail({ + required this.currentTab, + required this.onSelectTab, + this.extended = false, + super.key, + }); + + final TabItem currentTab; + final ValueChanged onSelectTab; + final bool extended; + + @override + Widget build(BuildContext context) { + return AdaptiveScaffold.standardNavigationRail( + padding: EdgeInsets.only( + right: Theme.of(context).navigationRailTheme.elevation!, + ), + selectedIndex: currentTab.index, + onDestinationSelected: (index) { + onSelectTab(TabItem.values[index]); + }, + extended: extended, + destinations: TabItem.values + .map( + (tabItem) => NavigationRailDestination( + icon: tabItem.getTabItemIcon(context), + selectedIcon: tabItem.getTabItemSelectedIcon(context), + label: CustomText.f12( + context, + tabItem.getTabItemLabel(context), + color: currentTab.index == tabItem.index + ? Theme.of(context).colorScheme.primary + : null, + ), + ), + ) + .toList(), + ); + } +} diff --git a/lib/features/home_shell/presentation/screens/home_shell_screen.dart b/lib/features/home_shell/presentation/screens/home_shell_screen.dart index 6bc8bc82..2b11254d 100755 --- a/lib/features/home_shell/presentation/screens/home_shell_screen.dart +++ b/lib/features/home_shell/presentation/screens/home_shell_screen.dart @@ -1,20 +1,21 @@ import 'package:flutter/material.dart'; +import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart'; import 'package:go_router/go_router.dart'; import '../../../../auth/presentation/providers/sign_out_provider.dart'; import '../../../../core/presentation/services/connection_stream_service.dart'; import '../../../../core/presentation/services/fcm_service/show_fcm_notification_provider.dart'; -import '../../../../core/presentation/styles/sizes.dart'; import '../../../../core/presentation/utils/fp_framework.dart'; import '../../../../core/presentation/utils/riverpod_framework.dart'; import '../../../../core/presentation/utils/toasts.dart'; -import '../../../../core/presentation/widgets/platform_widgets/platform_tab_scaffold.dart'; +import '../../../../core/presentation/widgets/platform_widgets/platform_appbar.dart'; import '../../../notifications/domain/app_notification.dart'; import '../../../notifications/presentation/providers/fcm_remote_message_providers.dart'; import '../../../notifications/presentation/providers/tapped_notification_provider.dart'; -import '../components/bottom_nav_bar_component.dart'; -import '../components/tab_appbar_component.dart'; +import '../components/home_shell_bottom_nav_bar.dart'; +import '../components/home_shell_appbar.dart'; +import '../components/home_shell_navigation_rail.dart'; import '../utils/tab_item.dart'; /// Builds the "shell" for the home by building a Scaffold with a persistent @@ -45,16 +46,29 @@ class HomeShellScreen extends HookConsumerWidget { ); }); - final selectedTab = - useState(TabItem.values[navigationShell.currentIndex]); + final selectedTab = useState(TabItem.values[navigationShell.currentIndex]); + + void onSelectTab(TabItem tab) { + selectedTab.value = tab; + // When navigating to a new branch, it's recommended to use the goBranch + // method, as doing so makes sure the last navigation state of the + // Navigator for the branch is restored. + navigationShell.goBranch( + tab.index, + // A common pattern when using bottom navigation bars is to support + // navigating to the initial location when tapping the item that is + // already active. This demonstrates how to support this behavior, + // using the initialLocation parameter of goBranch: + // initialLocation: tab.index == navigationShell.currentIndex, + ); + } ref.listen>( tappedNotificationProvider, (previous, next) { if (next is Some) { final notification = next.value; - selectedTab.value = TabItem.values - .firstWhere((tab) => tab.name == notification.tabName); + selectedTab.value = TabItem.values.firstWhere((tab) => tab.name == notification.tabName); final location = notification.routeLocation; if (location != null) context.go(location); @@ -72,44 +86,54 @@ class HomeShellScreen extends HookConsumerWidget { } return true; }, - child: PlatformTabScaffold( - materialData: MaterialTabScaffoldData( - // Using single persistent AppBar for all tabs and update it according to current location. - // This is necessary to avoid using nested scaffolds as it's discouraged by flutter - // (but You can use it anyway if you don't want the persistent AppBar behavior). - // While for iOS, we can use CupertinoTabScaffold which has tabBuilder/tabBar(BNB) - // and each nested screen can use CupertinoPageScaffold that can have individual Appbar. - appBar: navigationShell.currentLocationHasAppBar - ? TabAppBarComponent( - toolbarHeight: Sizes.appBarHeight56, - backgroundColor: - Theme.of(context).appBarTheme.backgroundColor, - ) - : null, - body: navigationShell, - ), - cupertinoData: CupertinoTabScaffoldData( - cupertinoTabBuilder: (context, index) { - return navigationShell; - }, - ), - bottomNavigationBar: BottomNavBarComponent( - context, - currentTab: selectedTab.value, - onSelectTab: (tab) { - selectedTab.value = tab; - // When navigating to a new branch, it's recommended to use the goBranch - // method, as doing so makes sure the last navigation state of the - // Navigator for the branch is restored. - navigationShell.goBranch( - tab.index, - // A common pattern when using bottom navigation bars is to support - // navigating to the initial location when tapping the item that is - // already active. This demonstrates how to support this behavior, - // using the initialLocation parameter of goBranch: - // initialLocation: tab.index == navigationShell.currentIndex, - ); - }, + child: Scaffold( + // Using single persistent AppBar for all tabs and update it according to current location. + // This is necessary to avoid using nested scaffolds as it's discouraged by flutter + // (but You can use it anyway if you don't want the persistent AppBar behavior). + appBar: navigationShell.currentLocationHasAppBar + ? PlatformAppBar( + appbar: const HomeShellAppBar(), + ) + : null, + body: AdaptiveLayout( + body: SlotLayout( + config: { + Breakpoints.standard: SlotLayout.from( + key: const Key('Body Standard'), + builder: (_) => navigationShell, + ), + }, + ), + bottomNavigation: SlotLayout( + config: { + Breakpoints.small: SlotLayout.from( + key: const Key('Bottom Navigation Small'), + builder: (_) => HomeShellBottomNavBar( + currentTab: selectedTab.value, + onSelectTab: onSelectTab, + ), + ) + }, + ), + primaryNavigation: SlotLayout( + config: { + Breakpoints.medium: SlotLayout.from( + key: const Key('Primary Navigation Medium'), + builder: (_) => HomeShellNavigationRail( + currentTab: selectedTab.value, + onSelectTab: onSelectTab, + ), + ), + Breakpoints.large: SlotLayout.from( + key: const Key('Primary Navigation Large'), + builder: (_) => HomeShellNavigationRail( + extended: true, + currentTab: selectedTab.value, + onSelectTab: onSelectTab, + ), + ), + }, + ), ), ), ); diff --git a/lib/features/map/presentation/screens/map_screen/map_screen.dart b/lib/features/map/presentation/screens/map_screen/map_screen.dart index 12b0af16..17951e59 100755 --- a/lib/features/map/presentation/screens/map_screen/map_screen.dart +++ b/lib/features/map/presentation/screens/map_screen/map_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../../core/presentation/widgets/responsive_widgets/widget_builders.dart'; +import '../../../../../core/presentation/widgets/responsive_widgets/responsive_layouts.dart'; import 'map_screen_compact.dart'; class MapScreen extends StatelessWidget { diff --git a/lib/features/map/presentation/screens/map_screen/map_screen_compact.dart b/lib/features/map/presentation/screens/map_screen/map_screen_compact.dart index 856cc904..3b5e62f5 100755 --- a/lib/features/map/presentation/screens/map_screen/map_screen_compact.dart +++ b/lib/features/map/presentation/screens/map_screen/map_screen_compact.dart @@ -73,7 +73,6 @@ class MapScreenCompact extends HookConsumerWidget { darkOverlays: currentTheme == AppTheme.light, ), child: NestedScreenScaffold( - hasAppBar: false, body: locationAsync.when( skipLoadingOnReload: true, skipLoadingOnRefresh: !locationAsync.hasError, diff --git a/lib/features/profile/presentation/components/profile_form_component.dart b/lib/features/profile/presentation/components/profile_form_component.dart index 04496a34..ff1187a5 100644 --- a/lib/features/profile/presentation/components/profile_form_component.dart +++ b/lib/features/profile/presentation/components/profile_form_component.dart @@ -9,7 +9,7 @@ import '../../../../core/presentation/utils/riverpod_framework.dart'; import '../../../../core/presentation/widgets/custom_button.dart'; import '../../domain/profile_details.dart'; import '../providers/profile_details_provider.dart'; -import 'profile_text_fields_section.dart'; +import '../widgets/titled_text_field_item.dart'; class ProfileFormComponent extends HookConsumerWidget { const ProfileFormComponent({super.key}); @@ -43,9 +43,27 @@ class ProfileFormComponent extends HookConsumerWidget { constraints: const BoxConstraints( maxWidth: Sizes.maxWidth360, ), - child: ProfileTextFieldsSection( - nameController: nameController, - mobileController: mobileController, + child: Column( + children: [ + TitledTextFieldItem( + controller: nameController, + title: tr(context).fullName, + hintText: tr(context).enterYourName, + validator: ProfileDetails.validateName(context), + keyboardType: TextInputType.name, + ), + const SizedBox( + height: Sizes.textFieldMarginV24, + ), + TitledTextFieldItem( + title: tr(context).mobileNumber, + controller: mobileController, + hintText: tr(context).enterYourNumber, + validator: ProfileDetails.validateMobile(context), + keyboardType: TextInputType.phone, + textInputAction: TextInputAction.done, + ), + ], ), ), const SizedBox( diff --git a/lib/features/profile/presentation/components/profile_text_fields_section.dart b/lib/features/profile/presentation/components/profile_text_fields_section.dart deleted file mode 100644 index 9991fb18..00000000 --- a/lib/features/profile/presentation/components/profile_text_fields_section.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -import '../../../../core/core_features/theme/presentation/utils/themes/cupertino_custom_theme.dart'; -import '../../../../core/presentation/helpers/localization_helper.dart'; -import '../../../../core/presentation/styles/sizes.dart'; -import '../../../../core/presentation/widgets/platform_widgets/platform_widget.dart'; -import '../../domain/profile_details.dart'; -import '../widgets/titled_text_field_item.dart'; - -class ProfileTextFieldsSection extends StatelessWidget { - const ProfileTextFieldsSection({ - required this.nameController, - required this.mobileController, - super.key, - }); - - final TextEditingController nameController; - final TextEditingController mobileController; - - @override - Widget build(BuildContext context) { - return PlatformWidget( - material: (_) { - return Column( - children: _sharedItemComponent(context, true), - ); - }, - cupertino: (_) { - return CupertinoFormSection.insetGrouped( - decoration: CupertinoCustomTheme.cupertinoFormSectionDecoration(context), - backgroundColor: Colors.transparent, - margin: EdgeInsets.zero, - children: _sharedItemComponent(context, false), - ); - }, - ); - } - - List _sharedItemComponent(BuildContext context, bool isMaterial) { - return [ - TitledTextFieldItem( - title: tr(context).fullName, - hint: tr(context).enterYourName, - controller: nameController, - validator: ProfileDetails.validateName(context), - keyboardType: TextInputType.name, - ), - if (isMaterial) - const SizedBox( - height: Sizes.textFieldMarginV24, - ), - TitledTextFieldItem( - title: tr(context).mobileNumber, - hint: tr(context).enterYourNumber, - controller: mobileController, - validator: ProfileDetails.validateMobile(context), - keyboardType: TextInputType.phone, - isLastTextField: true, - ), - ]; - } -} diff --git a/lib/features/profile/presentation/screens/profile_screen/profile_screen.dart b/lib/features/profile/presentation/screens/profile_screen/profile_screen.dart index 8e42d410..7eddaa73 100755 --- a/lib/features/profile/presentation/screens/profile_screen/profile_screen.dart +++ b/lib/features/profile/presentation/screens/profile_screen/profile_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../../core/presentation/widgets/responsive_widgets/widget_builders.dart'; +import '../../../../../core/presentation/widgets/responsive_widgets/responsive_layouts.dart'; import 'profile_screen_compact.dart'; import 'profile_screen_medium.dart'; diff --git a/lib/features/profile/presentation/widgets/titled_text_field_item.dart b/lib/features/profile/presentation/widgets/titled_text_field_item.dart index 4e6ad90c..dcc4fc5b 100644 --- a/lib/features/profile/presentation/widgets/titled_text_field_item.dart +++ b/lib/features/profile/presentation/widgets/titled_text_field_item.dart @@ -1,74 +1,48 @@ import 'package:flutter/material.dart'; -import '../../../../core/presentation/helpers/platform_helper.dart'; -import '../../../../core/presentation/styles/font_styles.dart'; import '../../../../core/presentation/styles/sizes.dart'; import '../../../../core/presentation/widgets/custom_text.dart'; -import '../../../../core/presentation/widgets/custom_text_form_field.dart'; class TitledTextFieldItem extends StatelessWidget { - const TitledTextFieldItem({ + required this.controller, required this.title, - required this.hint, - required this.validator, this.prefix, - this.suffix, - this.controller, + required this.hintText, + required this.validator, + this.textInputAction = TextInputAction.next, this.keyboardType, - this.isLastTextField = false, super.key, }); + final String title; - final String hint; - final Widget? prefix; - final Widget? suffix; final TextEditingController? controller; + final String hintText; final FormFieldValidator? validator; + final TextInputAction? textInputAction; final TextInputType? keyboardType; - final bool isLastTextField; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (PlatformHelper.isMaterialApp()) - Padding( - padding: const EdgeInsetsDirectional.only( - start: Sizes.paddingH4, - bottom: Sizes.paddingV8, - ), - child: CustomText.f16( - context, - title, - ), + Padding( + padding: const EdgeInsetsDirectional.only( + start: Sizes.paddingH4, + bottom: Sizes.paddingV8, ), - CustomTextFormField( + child: CustomText.f16( + context, + title, + ), + ), + TextFormField( + key: ValueKey(title), controller: controller, + decoration: InputDecoration(hintText: hintText), validator: validator, - textInputAction: - isLastTextField ? TextInputAction.done : TextInputAction.next, + textInputAction: textInputAction, keyboardType: keyboardType, - materialPrefix: prefix, - cupertinoPrefix: Row( - children: [ - SizedBox( - width: Sizes.textFieldPrefixWidth144, - child: CustomText.f18( - context, - title, - weight: FontStyles.fontWeightSemiBold, - ), - ), - const SizedBox( - width: Sizes.marginH6, - ), - if (prefix != null) prefix!, - ], - ), - suffix: suffix, - hintText: hint, - key: ValueKey(title), ), ], ); diff --git a/lib/features/settings/presentation/screens/language_screen/language_screen.dart b/lib/features/settings/presentation/screens/language_screen/language_screen.dart index 5ec8de51..6d537cda 100755 --- a/lib/features/settings/presentation/screens/language_screen/language_screen.dart +++ b/lib/features/settings/presentation/screens/language_screen/language_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../../core/presentation/widgets/responsive_widgets/widget_builders.dart'; +import '../../../../../core/presentation/widgets/responsive_widgets/responsive_layouts.dart'; import 'language_screen_compact.dart'; class LanguageScreen extends StatelessWidget { diff --git a/lib/features/settings/presentation/screens/settings_screen/settings_screen.dart b/lib/features/settings/presentation/screens/settings_screen/settings_screen.dart index 662a5b34..ae7dacd9 100755 --- a/lib/features/settings/presentation/screens/settings_screen/settings_screen.dart +++ b/lib/features/settings/presentation/screens/settings_screen/settings_screen.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import '../../../../../core/presentation/widgets/responsive_widgets/widget_builders.dart'; +import '../../../../../core/presentation/widgets/responsive_widgets/responsive_layouts.dart'; import 'settings_screen_compact.dart'; class SettingsScreen extends StatelessWidget { diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index da36f1f2..bdb04cb4 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -1,7 +1,6 @@ { "@_CORE": {}, "appName": "Deliverzler", - "fontFamily": "Tajawal", "noInternetConnection": "لا يوجد اتصال بالانترنت", "screenNotFound": "عذرًا! لم يتم العثور على الصفحة!", "goToHome": "الذهاب للصفحة الرئيسية", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 3ad59978..0d51d78d 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1,7 +1,6 @@ { "@_CORE": {}, "appName": "Deliverzler", - "fontFamily": "Poppins", "noInternetConnection": "No internet connection", "screenNotFound": "Oops! Screen not found!", "goToHome": "Go to Home", diff --git a/pubspec.lock b/pubspec.lock index 3aba4013..95b12db9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -486,6 +486,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_adaptive_scaffold: + dependency: "direct main" + description: + name: flutter_adaptive_scaffold + sha256: "4f448902314bc9b6cf820c85d5bad4de6489c0eff75dcedf5098f3a53ec981ee" + url: "https://pub.dev" + source: hosted + version: "0.1.6" flutter_blurhash: dependency: transitive description: @@ -563,6 +571,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + flutter_platform_widgets: + dependency: "direct main" + description: + name: flutter_platform_widgets + sha256: d55914d258ddff94474388a19be97f3096a83c58792b1857bc90935ebff6cade + url: "https://pub.dev" + source: hosted + version: "4.0.0-beta.3" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -1645,4 +1661,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.0.0 <4.0.0" - flutter: ">=3.7.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 2893f820..eb16f807 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -68,6 +68,8 @@ dependencies: timeago: ^3.4.0 # Widgets + flutter_platform_widgets: ^4.0.0-beta.3 + flutter_adaptive_scaffold: ^0.1.6 fluttertoast: ^8.2.2 qr_flutter: ^4.1.0 material_floating_search_bar: diff --git a/test/core/presentation/helpers/platform_helper_test.dart b/test/core/presentation/helpers/platform_helper_test.dart index b4c9f1c3..801763ab 100644 --- a/test/core/presentation/helpers/platform_helper_test.dart +++ b/test/core/presentation/helpers/platform_helper_test.dart @@ -19,7 +19,7 @@ void main() { // GIVEN setUpTargetPlatform(TargetPlatform.iOS); // WHEN - final result = PlatformHelper.isMaterialApp(); + final result = PlatformHelper.isMaterialApp; // THEN expect(result, false); }, @@ -31,7 +31,7 @@ void main() { // GIVEN setUpTargetPlatform(TargetPlatform.macOS); // WHEN - final result = PlatformHelper.isMaterialApp(); + final result = PlatformHelper.isMaterialApp; // THEN expect(result, false); }, @@ -43,7 +43,7 @@ void main() { // GIVEN setUpTargetPlatform(TargetPlatform.android); // WHEN - final result = PlatformHelper.isMaterialApp(); + final result = PlatformHelper.isMaterialApp; // THEN expect(result, true); }, @@ -55,7 +55,7 @@ void main() { // GIVEN setUpTargetPlatform(TargetPlatform.fuchsia); // WHEN - final result = PlatformHelper.isMaterialApp(); + final result = PlatformHelper.isMaterialApp; // THEN expect(result, true); }, @@ -67,7 +67,7 @@ void main() { // GIVEN setUpTargetPlatform(TargetPlatform.windows); // WHEN - final result = PlatformHelper.isMaterialApp(); + final result = PlatformHelper.isMaterialApp; // THEN expect(result, true); },