diff --git a/lib/theming/factory/app_theme_factory.dart b/lib/theming/factory/app_theme_factory.dart index c44be7a3..65bb1648 100644 --- a/lib/theming/factory/app_theme_factory.dart +++ b/lib/theming/factory/app_theme_factory.dart @@ -66,11 +66,6 @@ abstract class AppThemeFactory { typography: appTypography, useMaterial3: true, scaffoldBackgroundColor: colorScheme.background, - appBarTheme: AppBarTheme( - elevation: 0, - backgroundColor: colorScheme.primary, - foregroundColor: colorScheme.onPrimary, - ), ); return materialThemeData; diff --git a/lib/ui/components/brand_header/brand_header.dart b/lib/ui/components/brand_header/brand_header.dart index 7366298b..fa643710 100644 --- a/lib/ui/components/brand_header/brand_header.dart +++ b/lib/ui/components/brand_header/brand_header.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; -import 'package:selfprivacy/ui/components/brand_text/brand_text.dart'; class BrandHeader extends StatelessWidget { const BrandHeader({ @@ -15,25 +13,17 @@ class BrandHeader extends StatelessWidget { final VoidCallback? onBackButtonPressed; @override - Widget build(final BuildContext context) => Container( - height: 52, - alignment: Alignment.centerLeft, - padding: EdgeInsets.only( - left: hasBackButton ? 1 : 15, + Widget build(final BuildContext context) => AppBar( + title: Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Text(title), ), - child: Row( - children: [ - if (hasBackButton) ...[ - IconButton( - icon: const Icon(BrandIcons.arrowLeft), + leading: hasBackButton + ? IconButton( + icon: const Icon(Icons.arrow_back), onPressed: onBackButtonPressed ?? () => Navigator.of(context).pop(), - ), - const SizedBox(width: 10), - ], - BrandText.h4(title), - const Spacer(), - ], - ), + ) + : null, ); } diff --git a/lib/ui/components/brand_hero_screen/brand_hero_screen.dart b/lib/ui/components/brand_hero_screen/brand_hero_screen.dart index cdccc8d2..b36cb2d9 100644 --- a/lib/ui/components/brand_hero_screen/brand_hero_screen.dart +++ b/lib/ui/components/brand_hero_screen/brand_hero_screen.dart @@ -1,74 +1,102 @@ import 'package:flutter/material.dart'; -import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/pre_styled_buttons/flash_fab.dart'; class BrandHeroScreen extends StatelessWidget { const BrandHeroScreen({ required this.children, final super.key, - this.headerTitle = '', this.hasBackButton = true, this.hasFlashButton = true, this.heroIcon, - this.heroTitle, + this.heroIconWidget, + this.heroTitle = '', this.heroSubtitle, this.onBackButtonPressed, }); final List children; - final String headerTitle; final bool hasBackButton; final bool hasFlashButton; final IconData? heroIcon; - final String? heroTitle; + final Widget? heroIconWidget; + final String heroTitle; final String? heroSubtitle; final VoidCallback? onBackButtonPressed; @override - Widget build(final BuildContext context) => SafeArea( - child: Scaffold( - appBar: PreferredSize( - preferredSize: const Size.fromHeight(52.0), - child: BrandHeader( - title: headerTitle, - hasBackButton: hasBackButton, - onBackButtonPressed: onBackButtonPressed, + Widget build(final BuildContext context) { + final Widget heroIconWidget = this.heroIconWidget ?? + Icon( + heroIcon ?? Icons.help, + size: 48.0, + color: Theme.of(context).colorScheme.onBackground, + ); + final bool hasHeroIcon = heroIcon != null || this.heroIconWidget != null; + const EdgeInsetsGeometry heroTitlePadding = EdgeInsets.only( + bottom: 12.0, + top: 16.0, + ); + + return Scaffold( + floatingActionButton: hasFlashButton ? const BrandFab() : null, + body: CustomScrollView( + slivers: [ + SliverAppBar( + expandedHeight: hasHeroIcon ? 160.0 : 96.0, + pinned: true, + stretch: true, + leading: hasBackButton + ? IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: onBackButtonPressed ?? + () => Navigator.of(context).pop(), + ) + : null, + flexibleSpace: FlexibleSpaceBar( + title: Text( + heroTitle, + style: Theme.of(context).textTheme.titleLarge?.copyWith( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + expandedTitleScale: 1.2, + centerTitle: true, + collapseMode: CollapseMode.pin, + titlePadding: heroTitlePadding, + background: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (hasHeroIcon) heroIconWidget, + ], + ), ), ), - floatingActionButton: hasFlashButton ? const BrandFab() : null, - body: ListView( - padding: const EdgeInsets.all(16.0), - children: [ - if (heroIcon != null) - Container( - alignment: Alignment.bottomLeft, - child: Icon( - heroIcon, - size: 48.0, + if (heroSubtitle != null) + SliverPadding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 4.0, + ), + sliver: SliverList( + delegate: SliverChildListDelegate([ + Text( + heroSubtitle!, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: Theme.of(context).colorScheme.onBackground, + ), + textAlign: hasHeroIcon ? TextAlign.center : TextAlign.start, ), - ), - const SizedBox(height: 8.0), - if (heroTitle != null) - Text( - heroTitle!, - style: Theme.of(context).textTheme.headlineMedium!.copyWith( - color: Theme.of(context).colorScheme.onBackground, - ), - textAlign: TextAlign.start, - ), - const SizedBox(height: 8.0), - if (heroSubtitle != null) - Text( - heroSubtitle!, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.onBackground, - ), - textAlign: TextAlign.start, - ), - const SizedBox(height: 16.0), - ...children, - ], + ]), + ), + ), + SliverPadding( + padding: const EdgeInsets.all(16.0), + sliver: SliverList( + delegate: SliverChildListDelegate(children), + ), ), - ), - ); + ], + ), + ); + } } diff --git a/lib/ui/pages/dns_details/dns_details.dart b/lib/ui/pages/dns_details/dns_details.dart index 5a93a53e..3308a068 100644 --- a/lib/ui/pages/dns_details/dns_details.dart +++ b/lib/ui/pages/dns_details/dns_details.dart @@ -91,7 +91,6 @@ class _DnsDetailsPageState extends State { if (!isReady) { return BrandHeroScreen( hasBackButton: true, - headerTitle: '', heroIcon: BrandIcons.globe, heroTitle: 'domain.screen_title'.tr(), heroSubtitle: 'not_ready_card.in_menu'.tr(), diff --git a/lib/ui/pages/more/about_application.dart b/lib/ui/pages/more/about_application.dart index 664dce3e..9b545678 100644 --- a/lib/ui/pages/more/about_application.dart +++ b/lib/ui/pages/more/about_application.dart @@ -15,8 +15,9 @@ class AboutApplicationPage extends StatelessWidget { appBar: PreferredSize( preferredSize: const Size.fromHeight(52), child: BrandHeader( - title: 'about_application_page.title'.tr(), - hasBackButton: true), + title: 'about_application_page.title'.tr(), + hasBackButton: true, + ), ), body: ListView( padding: paddingH15V0, diff --git a/lib/ui/pages/server_details/server_details_screen.dart b/lib/ui/pages/server_details/server_details_screen.dart index d1eada36..0b4ac005 100644 --- a/lib/ui/pages/server_details/server_details_screen.dart +++ b/lib/ui/pages/server_details/server_details_screen.dart @@ -12,7 +12,6 @@ import 'package:selfprivacy/logic/models/auto_upgrade_settings.dart'; import 'package:selfprivacy/logic/models/job.dart'; import 'package:selfprivacy/ui/components/brand_button/segmented_buttons.dart'; import 'package:selfprivacy/ui/components/brand_cards/filled_card.dart'; -import 'package:selfprivacy/ui/components/brand_header/brand_header.dart'; import 'package:selfprivacy/ui/components/brand_hero_screen/brand_hero_screen.dart'; import 'package:selfprivacy/ui/components/brand_icons/brand_icons.dart'; import 'package:selfprivacy/ui/components/brand_loader/brand_loader.dart'; diff --git a/lib/ui/pages/server_details/time_zone/time_zone.dart b/lib/ui/pages/server_details/time_zone/time_zone.dart index 1711a59b..6a7349c9 100644 --- a/lib/ui/pages/server_details/time_zone/time_zone.dart +++ b/lib/ui/pages/server_details/time_zone/time_zone.dart @@ -47,82 +47,87 @@ class _SelectTimezoneState extends State { @override Widget build(final BuildContext context) => Scaffold( - appBar: PreferredSize( - preferredSize: const Size.fromHeight(52), - child: BrandHeader( - title: 'server.select_timezone'.tr(), - hasBackButton: true, + appBar: AppBar( + title: Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Text('server.select_timezone'.tr()), + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () => Navigator.of(context).pop(), ), ), - body: ListView( - controller: controller, - children: locations - .asMap() - .map((final key, final value) { - final duration = - Duration(milliseconds: value.currentTimeZone.offset); - final area = value.currentTimeZone.abbreviation - .replaceAll(RegExp(r'[\d+()-]'), ''); + body: SafeArea( + child: ListView( + controller: controller, + children: locations + .asMap() + .map((final key, final value) { + final duration = + Duration(milliseconds: value.currentTimeZone.offset); + final area = value.currentTimeZone.abbreviation + .replaceAll(RegExp(r'[\d+()-]'), ''); - String timezoneName = value.name; - if (context.locale.toString() == 'ru') { - timezoneName = russian[value.name] ?? - () { - final arr = value.name.split('/')..removeAt(0); - return arr.join('/'); - }(); - } + String timezoneName = value.name; + if (context.locale.toString() == 'ru') { + timezoneName = russian[value.name] ?? + () { + final arr = value.name.split('/')..removeAt(0); + return arr.join('/'); + }(); + } - return MapEntry( - key, - Container( - height: 75, - padding: const EdgeInsets.symmetric(horizontal: 20), - decoration: const BoxDecoration( - border: Border( - bottom: BorderSide( - color: BrandColors.dividerColor, + return MapEntry( + key, + Container( + height: 75, + padding: const EdgeInsets.symmetric(horizontal: 20), + decoration: const BoxDecoration( + border: Border( + bottom: BorderSide( + color: BrandColors.dividerColor, + ), + ), + ), + child: InkWell( + onTap: () { + context + .read() + .repository + .setTimezone( + timezoneName, + ); + Navigator.of(context).pop(); + }, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + BrandText.body1( + timezoneName, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + BrandText.small( + 'GMT ${duration.toDayHourMinuteFormat()} ${area.isNotEmpty ? '($area)' : ''}', + style: const TextStyle( + fontSize: 13, + ), + ), + ], + ), ), ), ), - child: InkWell( - onTap: () { - context - .read() - .repository - .setTimezone( - timezoneName, - ); - Navigator.of(context).pop(); - }, - child: Container( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - BrandText.body1( - timezoneName, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - BrandText.small( - 'GMT ${duration.toDayHourMinuteFormat()} ${area.isNotEmpty ? '($area)' : ''}', - style: const TextStyle( - fontSize: 13, - ), - ), - ], - ), - ), - ), - ), - ); - }) - .values - .toList(), + ); + }) + .values + .toList(), + ), ), ); } diff --git a/lib/ui/pages/services/service_page.dart b/lib/ui/pages/services/service_page.dart index ad398072..f4685802 100644 --- a/lib/ui/pages/services/service_page.dart +++ b/lib/ui/pages/services/service_page.dart @@ -47,25 +47,14 @@ class _ServicePageState extends State { return BrandHeroScreen( hasBackButton: true, + heroIconWidget: SvgPicture.string( + service.svgIcon, + width: 48.0, + height: 48.0, + color: Theme.of(context).colorScheme.onBackground, + ), + heroTitle: service.displayName, children: [ - Container( - alignment: Alignment.center, - child: SvgPicture.string( - service.svgIcon, - width: 48.0, - height: 48.0, - color: Theme.of(context).colorScheme.onBackground, - ), - ), - const SizedBox(height: 16), - Text( - service.displayName, - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headlineMedium!.copyWith( - color: Theme.of(context).colorScheme.onBackground, - ), - ), - const SizedBox(height: 16), ServiceStatusCard(status: service.status), const SizedBox(height: 16), if (service.url != null) diff --git a/lib/ui/pages/setup/initializing.dart b/lib/ui/pages/setup/initializing.dart index ff4c0748..102c5a9b 100644 --- a/lib/ui/pages/setup/initializing.dart +++ b/lib/ui/pages/setup/initializing.dart @@ -415,7 +415,8 @@ class InitializingPage extends StatelessWidget { BrandText.h2('initializing.create_master_account'.tr()), const SizedBox(height: 10), BrandText.body2( - 'initializing.enter_nickname_and_password'.tr()), + 'initializing.enter_nickname_and_password'.tr(), + ), const Spacer(), CubitFormTextField( formFieldCubit: context.read().userName,