feat: MD3 app bars

Fixed #123 spent @2h
pull/126/head
Inex Code 2022-10-04 13:34:56 +03:00 committed by Gitea
parent 571e32ecff
commit 129eb76a04
9 changed files with 170 additions and 163 deletions

View File

@ -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;

View File

@ -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,
);
}

View File

@ -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<Widget> 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,
),
),
floatingActionButton: hasFlashButton ? const BrandFab() : null,
body: ListView(
padding: const EdgeInsets.all(16.0),
children: <Widget>[
if (heroIcon != null)
Container(
alignment: Alignment.bottomLeft,
child: Icon(
heroIcon,
Widget build(final BuildContext context) {
final Widget heroIconWidget = this.heroIconWidget ??
Icon(
heroIcon ?? Icons.help,
size: 48.0,
),
),
const SizedBox(height: 8.0),
if (heroTitle != null)
Text(
heroTitle!,
style: Theme.of(context).textTheme.headlineMedium!.copyWith(
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,
],
),
),
textAlign: TextAlign.start,
),
const SizedBox(height: 8.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: TextAlign.start,
textAlign: hasHeroIcon ? TextAlign.center : TextAlign.start,
),
]),
),
),
SliverPadding(
padding: const EdgeInsets.all(16.0),
sliver: SliverList(
delegate: SliverChildListDelegate(children),
),
),
const SizedBox(height: 16.0),
...children,
],
),
),
);
}
}

View File

@ -91,7 +91,6 @@ class _DnsDetailsPageState extends State<DnsDetailsPage> {
if (!isReady) {
return BrandHeroScreen(
hasBackButton: true,
headerTitle: '',
heroIcon: BrandIcons.globe,
heroTitle: 'domain.screen_title'.tr(),
heroSubtitle: 'not_ready_card.in_menu'.tr(),

View File

@ -16,7 +16,8 @@ class AboutApplicationPage extends StatelessWidget {
preferredSize: const Size.fromHeight(52),
child: BrandHeader(
title: 'about_application_page.title'.tr(),
hasBackButton: true),
hasBackButton: true,
),
),
body: ListView(
padding: paddingH15V0,

View File

@ -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';

View File

@ -47,14 +47,18 @@ class _SelectTimezoneState extends State<SelectTimezone> {
@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(
body: SafeArea(
child: ListView(
controller: controller,
children: locations
.asMap()
@ -124,5 +128,6 @@ class _SelectTimezoneState extends State<SelectTimezone> {
.values
.toList(),
),
),
);
}

View File

@ -47,25 +47,14 @@ class _ServicePageState extends State<ServicePage> {
return BrandHeroScreen(
hasBackButton: true,
children: [
Container(
alignment: Alignment.center,
child: SvgPicture.string(
heroIconWidget: 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),
heroTitle: service.displayName,
children: [
ServiceStatusCard(status: service.status),
const SizedBox(height: 16),
if (service.url != null)

View File

@ -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<RootUserFormCubit>().userName,