Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

Commit

Permalink
[State Restoration] Material Dialogs, Cupertino Dialogs, CupertinoTab…
Browse files Browse the repository at this point in the history
…Scaffold/TabView, CupertinoTextFields (#409)

* Cupertino alert, text field and tab bar demo state restoration

* Make one material dialog restorable

* Finish up state restoration for material dialogs

* Action sheet state restoration, rootNavigator feedback
  • Loading branch information
Shi-Hao Hong authored Feb 23, 2021
1 parent e2cfe22 commit 752ca54
Show file tree
Hide file tree
Showing 9 changed files with 1,767 additions and 899 deletions.
Binary file modified golden_test/goldens/home_page_desktop_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified golden_test/goldens/home_page_desktop_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified golden_test/goldens/home_page_mobile_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified golden_test/goldens/home_page_mobile_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2,029 changes: 1,357 additions & 672 deletions lib/codeviewer/code_segments.dart

Large diffs are not rendered by default.

385 changes: 243 additions & 142 deletions lib/demos/cupertino/cupertino_alert_demo.dart

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions lib/demos/cupertino/cupertino_tab_bar_demo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class CupertinoTabBarDemo extends StatelessWidget {
return DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
child: CupertinoTabScaffold(
restorationId: 'cupertino_tab_scaffold',
tabBar: CupertinoTabBar(
items: [
for (final tabInfo in _tabInfo)
Expand All @@ -49,6 +50,7 @@ class CupertinoTabBarDemo extends StatelessWidget {
),
tabBuilder: (context, index) {
return CupertinoTabView(
restorationScopeId: 'cupertino_tab_view_$index',
builder: (context) => _CupertinoDemoTab(
title: _tabInfo[index].title,
icon: _tabInfo[index].icon,
Expand Down
4 changes: 4 additions & 0 deletions lib/demos/cupertino/cupertino_text_field_demo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ class CupertinoTextFieldDemo extends StatelessWidget {
),
child: SafeArea(
child: ListView(
restorationId: 'text_field_demo_list_view',
padding: const EdgeInsets.all(16),
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: CupertinoTextField(
restorationId: 'email_address_text_field',
placeholder: localizations.demoTextFieldEmail,
keyboardType: TextInputType.emailAddress,
clearButtonMode: OverlayVisibilityMode.editing,
Expand All @@ -34,13 +36,15 @@ class CupertinoTextFieldDemo extends StatelessWidget {
Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: CupertinoTextField(
restorationId: 'login_password_text_field',
placeholder: localizations.rallyLoginPassword,
clearButtonMode: OverlayVisibilityMode.editing,
obscureText: true,
autocorrect: false,
),
),
CupertinoTextField(
restorationId: 'pin_number_text_field',
prefix: const Icon(
CupertinoIcons.padlock_solid,
size: 28,
Expand Down
246 changes: 161 additions & 85 deletions lib/demos/material/dialog_demo.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,79 @@ import 'package:flutter_gen/gen_l10n/gallery_localizations.dart';

// BEGIN dialogDemo

class DialogDemo extends StatelessWidget {
class DialogDemo extends StatefulWidget {
DialogDemo({Key key, @required this.type}) : super(key: key);

final DialogDemoType type;

@override
_DialogDemoState createState() => _DialogDemoState();
}

class _DialogDemoState extends State<DialogDemo> with RestorationMixin {
RestorableRouteFuture<String> _alertDialogRoute;
RestorableRouteFuture<String> _alertDialogWithTitleRoute;
RestorableRouteFuture<String> _simpleDialogRoute;

@override
String get restorationId => 'dialog_demo';

@override
void restoreState(RestorationBucket oldBucket, bool initialRestore) {
registerForRestoration(
_alertDialogRoute,
'alert_demo_dialog_route',
);
registerForRestoration(
_alertDialogWithTitleRoute,
'alert_demo_with_title_dialog_route',
);
registerForRestoration(
_simpleDialogRoute,
'simple_dialog_route',
);
}

// Displays the popped String value in a snackbar.
void _showInSnackBar(String value) {
// The value passed to Navigator.pop() or null.
if (value != null) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
GalleryLocalizations.of(context).dialogSelectedOption(value),
),
),
);
}
}

@override
void initState() {
super.initState();
_alertDialogRoute = RestorableRouteFuture<String>(
onPresent: (navigator, arguments) {
return navigator.restorablePush(_alertDialogDemoRoute);
},
onComplete: _showInSnackBar,
);
_alertDialogWithTitleRoute = RestorableRouteFuture<String>(
onPresent: (navigator, arguments) {
return navigator.restorablePush(_alertDialogWithTitleDemoRoute);
},
onComplete: _showInSnackBar,
);
_simpleDialogRoute = RestorableRouteFuture<String>(
onPresent: (navigator, arguments) {
return navigator.restorablePush(_simpleDialogDemoRoute);
},
onComplete: _showInSnackBar,
);
}

String _title(BuildContext context) {
switch (type) {
switch (widget.type) {
case DialogDemoType.alert:
return GalleryLocalizations.of(context).demoAlertDialogTitle;
case DialogDemoType.alertTitle:
Expand All @@ -29,101 +95,111 @@ class DialogDemo extends StatelessWidget {
return '';
}

Future<void> _showDemoDialog<T>({BuildContext context, Widget child}) async {
child = ApplyTextOptions(
child: Theme(
data: Theme.of(context),
child: child,
),
);
final value = await showDialog<T>(
context: context,
builder: (context) => child,
);
// The value passed to Navigator.pop() or null.
if (value != null && value is String) {
ScaffoldMessenger.of(context).hideCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content:
Text(GalleryLocalizations.of(context).dialogSelectedOption(value)),
));
}
}

void _showAlertDialog(BuildContext context) {
static Route<String> _alertDialogDemoRoute(
BuildContext context,
Object arguments,
) {
final theme = Theme.of(context);
final dialogTextStyle = theme.textTheme.subtitle1
.copyWith(color: theme.textTheme.caption.color);
_showDemoDialog<String>(

return DialogRoute<String>(
context: context,
child: AlertDialog(
content: Text(
GalleryLocalizations.of(context).dialogDiscardTitle,
style: dialogTextStyle,
builder: (context) => ApplyTextOptions(
child: AlertDialog(
content: Text(
GalleryLocalizations.of(context).dialogDiscardTitle,
style: dialogTextStyle,
),
actions: [
_DialogButton(text: GalleryLocalizations.of(context).dialogCancel),
_DialogButton(text: GalleryLocalizations.of(context).dialogDiscard),
],
),
actions: [
_DialogButton(text: GalleryLocalizations.of(context).dialogCancel),
_DialogButton(text: GalleryLocalizations.of(context).dialogDiscard),
],
),
);
}

void _showAlertDialogWithTitle(BuildContext context) {
static Route<String> _alertDialogWithTitleDemoRoute(
BuildContext context,
Object arguments,
) {
final theme = Theme.of(context);
final dialogTextStyle = theme.textTheme.subtitle1
.copyWith(color: theme.textTheme.caption.color);
_showDemoDialog<String>(

return DialogRoute<String>(
context: context,
child: AlertDialog(
title: Text(GalleryLocalizations.of(context).dialogLocationTitle),
content: Text(
GalleryLocalizations.of(context).dialogLocationDescription,
style: dialogTextStyle,
builder: (context) => ApplyTextOptions(
child: AlertDialog(
title: Text(GalleryLocalizations.of(context).dialogLocationTitle),
content: Text(
GalleryLocalizations.of(context).dialogLocationDescription,
style: dialogTextStyle,
),
actions: [
_DialogButton(
text: GalleryLocalizations.of(context).dialogDisagree),
_DialogButton(text: GalleryLocalizations.of(context).dialogAgree),
],
),
actions: [
_DialogButton(text: GalleryLocalizations.of(context).dialogDisagree),
_DialogButton(text: GalleryLocalizations.of(context).dialogAgree),
],
),
);
}

void _showSimpleDialog(BuildContext context) {
static Route<String> _simpleDialogDemoRoute(
BuildContext context,
Object arguments,
) {
final theme = Theme.of(context);
_showDemoDialog<String>(

return DialogRoute<String>(
context: context,
child: SimpleDialog(
title: Text(GalleryLocalizations.of(context).dialogSetBackup),
children: [
_DialogDemoItem(
icon: Icons.account_circle,
color: theme.colorScheme.primary,
text: 'username@gmail.com',
),
_DialogDemoItem(
icon: Icons.account_circle,
color: theme.colorScheme.secondary,
text: 'user02@gmail.com',
),
_DialogDemoItem(
icon: Icons.add_circle,
text: GalleryLocalizations.of(context).dialogAddAccount,
color: theme.disabledColor,
),
],
builder: (context) => ApplyTextOptions(
child: SimpleDialog(
title: Text(GalleryLocalizations.of(context).dialogSetBackup),
children: [
_DialogDemoItem(
icon: Icons.account_circle,
color: theme.colorScheme.primary,
text: 'username@gmail.com',
),
_DialogDemoItem(
icon: Icons.account_circle,
color: theme.colorScheme.secondary,
text: 'user02@gmail.com',
),
_DialogDemoItem(
icon: Icons.add_circle,
text: GalleryLocalizations.of(context).dialogAddAccount,
color: theme.disabledColor,
),
],
),
),
);
}

static Route<void> _fullscreenDialogRoute(
BuildContext context,
Object arguments,
) {
return MaterialPageRoute<void>(
builder: (context) => _FullScreenDialogDemo(),
fullscreenDialog: true,
);
}

@override
Widget build(BuildContext context) {
return Navigator(
// Adding [ValueKey] to make sure that the widget gets rebuilt when
// changing type.
key: ValueKey(type),
key: ValueKey(widget.type),
restorationScopeId: 'navigator',
onGenerateRoute: (settings) {
return _NoAnimationMaterialPageRoute<void>(
settings: settings,
builder: (context) => Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
Expand All @@ -133,24 +209,19 @@ class DialogDemo extends StatelessWidget {
child: ElevatedButton(
child: Text(GalleryLocalizations.of(context).dialogShow),
onPressed: () {
switch (type) {
switch (widget.type) {
case DialogDemoType.alert:
_showAlertDialog(context);
_alertDialogRoute.present();
break;
case DialogDemoType.alertTitle:
_showAlertDialogWithTitle(context);
_alertDialogWithTitleRoute.present();
break;
case DialogDemoType.simple:
_showSimpleDialog(context);
_simpleDialogRoute.present();
break;
case DialogDemoType.fullscreen:
Navigator.push<void>(
context,
MaterialPageRoute(
builder: (context) => _FullScreenDialogDemo(),
fullscreenDialog: true,
),
);
Navigator.restorablePush<void>(
context, _fullscreenDialogRoute);
break;
}
},
Expand All @@ -171,14 +242,19 @@ class _NoAnimationMaterialPageRoute<T> extends MaterialPageRoute<T> {
bool maintainState = true,
bool fullscreenDialog = false,
}) : super(
builder: builder,
maintainState: maintainState,
settings: settings,
fullscreenDialog: fullscreenDialog);
builder: builder,
maintainState: maintainState,
settings: settings,
fullscreenDialog: fullscreenDialog,
);

@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
Widget buildTransitions(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return child;
}
}
Expand All @@ -193,7 +269,7 @@ class _DialogButton extends StatelessWidget {
return TextButton(
child: Text(text),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop(text);
Navigator.of(context).pop(text);
},
);
}
Expand All @@ -215,7 +291,7 @@ class _DialogDemoItem extends StatelessWidget {
Widget build(BuildContext context) {
return SimpleDialogOption(
onPressed: () {
Navigator.of(context, rootNavigator: true).pop(text);
Navigator.of(context).pop(text);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
Expand Down

0 comments on commit 752ca54

Please sign in to comment.