always keep home as the first route in navigator stack, apply double back exit policy to filter grid pages

This commit is contained in:
Thibault Deckers 2020-09-04 22:01:11 +09:00
parent da26ccdc87
commit 751f2fcacc
9 changed files with 87 additions and 70 deletions

View file

@ -104,6 +104,14 @@ class Settings extends ChangeNotifier {
set svgBackground(int newValue) => setAndNotify(svgBackgroundKey, newValue);
// utils
// `RoutePredicate`
RoutePredicate navRemoveRoutePredicate(String pushedRouteName) {
final home = homePage.routeName;
return (route) => pushedRouteName != home && route.settings?.name == home;
}
// convenience methods
// ignore: avoid_positional_boolean_parameters

View file

@ -32,7 +32,7 @@ class _DoubleBackPopScopeState extends State<DoubleBackPopScope> with FeedbackMi
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
if (!Navigator.of(context).canPop() && settings.mustBackTwiceToExit && !_backOnce) {
if (!Navigator.canPop(context) && settings.mustBackTwiceToExit && !_backOnce) {
_backOnce = true;
_stopBackTimer();
_backTimer = Timer(Durations.doubleBackTimerDelay, () => _backOnce = false);

View file

@ -39,6 +39,7 @@ class CollectionNavTile extends StatelessWidget {
}
void _goToCollection(BuildContext context) {
Navigator.pop(context);
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
@ -50,7 +51,7 @@ class CollectionNavTile extends StatelessWidget {
sortFactor: settings.collectionSortFactor,
)),
),
(route) => false,
settings.navRemoveRoutePredicate(CollectionPage.routeName),
);
}
}

View file

@ -1,5 +1,6 @@
import 'dart:ui';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/utils/flutter_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -41,12 +42,14 @@ class NavTile extends StatelessWidget {
onTap: () {
Navigator.pop(context);
if (routeName != context.currentRouteName) {
Navigator.push(
context,
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: pageBuilder,
));
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
settings: RouteSettings(name: routeName),
builder: pageBuilder,
),
settings.navRemoveRoutePredicate(routeName),
);
}
},
selected: context.currentRouteName == routeName,

View file

@ -10,6 +10,7 @@ import 'package:aves/widgets/album/collection_page.dart';
import 'package:aves/widgets/common/app_bar_subtitle.dart';
import 'package:aves/widgets/common/aves_filter_chip.dart';
import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart';
import 'package:aves/widgets/common/double_back_pop.dart';
import 'package:aves/widgets/drawer/app_drawer.dart';
import 'package:aves/widgets/filter_grids/decorated_filter_chip.dart';
import 'package:flutter/material.dart';
@ -64,7 +65,7 @@ class FilterNavigationPage extends StatelessWidget {
sortFactor: settings.collectionSortFactor,
)),
),
(route) => false,
settings.navRemoveRoutePredicate(CollectionPage.routeName),
),
);
}
@ -96,66 +97,68 @@ class FilterGridPage extends StatelessWidget {
Widget build(BuildContext context) {
return MediaQueryDataProvider(
child: Scaffold(
body: SafeArea(
child: Selector<MediaQueryData, double>(
selector: (c, mq) => mq.size.width,
builder: (c, mqWidth, child) {
final columnCount = (mqWidth / maxCrossAxisExtent).ceil();
return AnimationLimiter(
child: CustomScrollView(
slivers: [
appBar,
filterKeys.isEmpty
? SliverFillRemaining(
child: emptyBuilder(),
hasScrollBody: false,
)
: SliverPadding(
padding: EdgeInsets.all(AvesFilterChip.outlineWidth),
sliver: SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, i) {
final key = filterKeys[i];
final child = DecoratedFilterChip(
source: source,
filter: filterBuilder(key),
entry: filterEntries[key],
onPressed: onPressed,
);
return AnimationConfiguration.staggeredGrid(
position: i,
columnCount: columnCount,
duration: Durations.staggeredAnimation,
delay: Durations.staggeredAnimationDelay,
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: child,
body: DoubleBackPopScope(
child: SafeArea(
child: Selector<MediaQueryData, double>(
selector: (c, mq) => mq.size.width,
builder: (c, mqWidth, child) {
final columnCount = (mqWidth / maxCrossAxisExtent).ceil();
return AnimationLimiter(
child: CustomScrollView(
slivers: [
appBar,
filterKeys.isEmpty
? SliverFillRemaining(
child: emptyBuilder(),
hasScrollBody: false,
)
: SliverPadding(
padding: EdgeInsets.all(AvesFilterChip.outlineWidth),
sliver: SliverGrid(
delegate: SliverChildBuilderDelegate(
(context, i) {
final key = filterKeys[i];
final child = DecoratedFilterChip(
source: source,
filter: filterBuilder(key),
entry: filterEntries[key],
onPressed: onPressed,
);
return AnimationConfiguration.staggeredGrid(
position: i,
columnCount: columnCount,
duration: Durations.staggeredAnimation,
delay: Durations.staggeredAnimationDelay,
child: SlideAnimation(
verticalOffset: 50.0,
child: FadeInAnimation(
child: child,
),
),
),
);
},
childCount: filterKeys.length,
),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
);
},
childCount: filterKeys.length,
),
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: maxCrossAxisExtent,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
),
),
),
),
SliverToBoxAdapter(
child: Selector<MediaQueryData, double>(
selector: (context, mq) => mq.viewInsets.bottom,
builder: (context, mqViewInsetsBottom, child) {
return SizedBox(height: mqViewInsetsBottom);
},
SliverToBoxAdapter(
child: Selector<MediaQueryData, double>(
selector: (context, mq) => mq.viewInsets.bottom,
builder: (context, mqViewInsetsBottom, child) {
return SizedBox(height: mqViewInsetsBottom);
},
),
),
),
],
),
);
},
],
),
);
},
),
),
),
drawer: AppDrawer(

View file

@ -3,6 +3,7 @@ import 'dart:math';
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/image_entry.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/utils/change_notifier.dart';
import 'package:aves/utils/durations.dart';
@ -278,7 +279,7 @@ class FullscreenBodyState extends State<FullscreenBody> with SingleTickerProvide
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(collection.derive(filter)),
),
(route) => false,
settings.navRemoveRoutePredicate(CollectionPage.routeName),
);
}

View file

@ -1,4 +1,5 @@
import 'package:aves/model/filters/filters.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/widgets/album/collection_page.dart';
@ -93,7 +94,7 @@ class FilterTable extends StatelessWidget {
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(collection.derive(filter)),
),
(route) => false,
settings.navRemoveRoutePredicate(CollectionPage.routeName),
);
}
}

View file

@ -5,6 +5,7 @@ import 'package:aves/model/filters/location.dart';
import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/filters/tag.dart';
import 'package:aves/model/image_entry.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/utils/color_utils.dart';
import 'package:aves/utils/constants.dart';
@ -241,7 +242,7 @@ class StatsPage extends StatelessWidget {
settings: RouteSettings(name: CollectionPage.routeName),
builder: (context) => CollectionPage(collection.derive(filter)),
),
(route) => false,
settings.navRemoveRoutePredicate(CollectionPage.routeName),
);
}
}

View file

@ -104,13 +104,12 @@ class _WelcomePageState extends State<WelcomePage> {
onPressed: _hasAcceptedTerms
? () {
settings.hasAcceptedTerms = true;
Navigator.pushAndRemoveUntil(
Navigator.pushReplacement(
context,
MaterialPageRoute(
settings: RouteSettings(name: HomePage.routeName),
builder: (context) => HomePage(),
),
(route) => false,
);
}
: null,