From 67f873b3f53b8759f74f7a9183c2eb5eeb70ceb6 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 1 Sep 2020 14:48:56 +0900 Subject: [PATCH 1/9] navigation: tap back twice to exit refactored selection dialogs --- lib/main.dart | 53 ++++----- lib/model/settings.dart | 63 +++++++---- lib/utils/constants.dart | 7 -- lib/utils/durations.dart | 1 + lib/widgets/album/app_bar.dart | 40 ++++--- lib/widgets/album/collection_page.dart | 5 +- .../action_delegates/chip_sort_dialog.dart | 59 ---------- .../collection_group_dialog.dart | 58 ---------- .../collection_sort_dialog.dart | 60 ----------- .../action_delegates/create_album_dialog.dart | 2 +- .../entry_action_delegate.dart | 2 +- .../action_delegates/map_style_dialog.dart | 51 --------- .../action_delegates/permission_aware.dart | 2 +- .../action_delegates/rename_entry_dialog.dart | 3 +- .../selection_action_delegate.dart | 2 +- .../common/{dialog.dart => aves_dialog.dart} | 0 lib/widgets/common/aves_selection_dialog.dart | 61 +++++++++++ lib/widgets/common/double_back_pop.dart | 54 ++++++++++ lib/widgets/common/highlight_title.dart | 43 ++++++++ lib/widgets/filter_grids/albums_page.dart | 11 +- lib/widgets/fullscreen/info/maps/common.dart | 8 +- .../fullscreen/info/metadata_section.dart | 44 +------- lib/widgets/home_page.dart | 6 +- lib/widgets/settings/coordinate_format.dart | 31 ------ lib/widgets/settings/launch_page.dart | 31 ------ lib/widgets/settings/settings_page.dart | 101 ++++++++++++------ lib/widgets/settings/svg_background.dart | 54 +++++----- pubspec.lock | 7 ++ pubspec.yaml | 1 + 29 files changed, 396 insertions(+), 464 deletions(-) delete mode 100644 lib/widgets/common/action_delegates/chip_sort_dialog.dart delete mode 100644 lib/widgets/common/action_delegates/collection_group_dialog.dart delete mode 100644 lib/widgets/common/action_delegates/collection_sort_dialog.dart delete mode 100644 lib/widgets/common/action_delegates/map_style_dialog.dart rename lib/widgets/common/{dialog.dart => aves_dialog.dart} (100%) create mode 100644 lib/widgets/common/aves_selection_dialog.dart create mode 100644 lib/widgets/common/double_back_pop.dart create mode 100644 lib/widgets/common/highlight_title.dart delete mode 100644 lib/widgets/settings/coordinate_format.dart delete mode 100644 lib/widgets/settings/launch_page.dart diff --git a/lib/main.dart b/lib/main.dart index 7bbaa237c..ed07ea752 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ import 'package:aves/widgets/welcome_page.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:overlay_support/overlay_support.dart'; void main() { // HttpClient.enableTimelineLogging = true; // enable network traffic logging @@ -41,34 +42,36 @@ class _AvesAppState extends State { // place the settings provider above `MaterialApp` // so it can be used during navigation transitions return SettingsProvider( - child: MaterialApp( - title: 'Aves', - theme: ThemeData( - brightness: Brightness.dark, - accentColor: accentColor, - scaffoldBackgroundColor: Colors.grey[900], - buttonColor: accentColor, - toggleableActiveColor: accentColor, - tooltipTheme: TooltipThemeData( - verticalOffset: 32, - ), - appBarTheme: AppBarTheme( - textTheme: TextTheme( - headline6: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - fontFamily: 'Concourse Caps', + child: OverlaySupport( + child: MaterialApp( + title: 'Aves', + theme: ThemeData( + brightness: Brightness.dark, + accentColor: accentColor, + scaffoldBackgroundColor: Colors.grey[900], + buttonColor: accentColor, + toggleableActiveColor: accentColor, + tooltipTheme: TooltipThemeData( + verticalOffset: 32, + ), + appBarTheme: AppBarTheme( + textTheme: TextTheme( + headline6: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + fontFamily: 'Concourse Caps', + ), ), ), ), - ), - home: FutureBuilder( - future: _appSetup, - builder: (context, snapshot) { - if (snapshot.hasError) return Icon(AIcons.error); - if (snapshot.connectionState != ConnectionState.done) return Scaffold(); - return settings.hasAcceptedTerms ? HomePage() : WelcomePage(); - }, + home: FutureBuilder( + future: _appSetup, + builder: (context, snapshot) { + if (snapshot.hasError) return Icon(AIcons.error); + if (snapshot.connectionState != ConnectionState.done) return Scaffold(); + return settings.hasAcceptedTerms ? HomePage() : WelcomePage(); + }, + ), ), ), ); diff --git a/lib/model/settings.dart b/lib/model/settings.dart index f99b3e77c..97b2116e2 100644 --- a/lib/model/settings.dart +++ b/lib/model/settings.dart @@ -16,18 +16,27 @@ class Settings extends ChangeNotifier { Settings._private(); - // preferences + // app + static const hasAcceptedTermsKey = 'has_accepted_terms'; + static const mustBackTwiceToExitKey = 'must_back_twice_to_exit'; + static const homePageKey = 'home_page'; static const catalogTimeZoneKey = 'catalog_time_zone'; + + // collection static const collectionGroupFactorKey = 'collection_group_factor'; static const collectionSortFactorKey = 'collection_sort_factor'; static const collectionTileExtentKey = 'collection_tile_extent'; - static const hasAcceptedTermsKey = 'has_accepted_terms'; + + // filter grids + static const albumSortFactorKey = 'album_sort_factor'; + + // info static const infoMapStyleKey = 'info_map_style'; static const infoMapZoomKey = 'info_map_zoom'; - static const launchPageKey = 'launch_page'; static const coordinateFormatKey = 'coordinates_format'; + + // rendering static const svgBackgroundKey = 'svg_background'; - static const albumSortFactorKey = 'album_sort_factor'; Future init() async { _prefs = await SharedPreferences.getInstance(); @@ -37,10 +46,26 @@ class Settings extends ChangeNotifier { return _prefs.clear(); } + // app + + bool get hasAcceptedTerms => getBoolOrDefault(hasAcceptedTermsKey, false); + + set hasAcceptedTerms(bool newValue) => setAndNotify(hasAcceptedTermsKey, newValue); + + bool get mustBackTwiceToExit => getBoolOrDefault(mustBackTwiceToExitKey, true); + + set mustBackTwiceToExit(bool newValue) => setAndNotify(mustBackTwiceToExitKey, newValue); + + HomePageSetting get homePage => getEnumOrDefault(homePageKey, HomePageSetting.collection, HomePageSetting.values); + + set homePage(HomePageSetting newValue) => setAndNotify(homePageKey, newValue.toString()); + String get catalogTimeZone => _prefs.getString(catalogTimeZoneKey) ?? ''; set catalogTimeZone(String newValue) => setAndNotify(catalogTimeZoneKey, newValue); + // collection + EntryGroupFactor get collectionGroupFactor => getEnumOrDefault(collectionGroupFactorKey, EntryGroupFactor.month, EntryGroupFactor.values); set collectionGroupFactor(EntryGroupFactor newValue) => setAndNotify(collectionGroupFactorKey, newValue.toString()); @@ -53,6 +78,14 @@ class Settings extends ChangeNotifier { set collectionTileExtent(double newValue) => setAndNotify(collectionTileExtentKey, newValue); + // filter grids + + ChipSortFactor get albumSortFactor => getEnumOrDefault(albumSortFactorKey, ChipSortFactor.name, ChipSortFactor.values); + + set albumSortFactor(ChipSortFactor newValue) => setAndNotify(albumSortFactorKey, newValue.toString()); + + // info + EntryMapStyle get infoMapStyle => getEnumOrDefault(infoMapStyleKey, EntryMapStyle.stamenWatercolor, EntryMapStyle.values); set infoMapStyle(EntryMapStyle newValue) => setAndNotify(infoMapStyleKey, newValue.toString()); @@ -61,26 +94,16 @@ class Settings extends ChangeNotifier { set infoMapZoom(double newValue) => setAndNotify(infoMapZoomKey, newValue); - bool get hasAcceptedTerms => getBoolOrDefault(hasAcceptedTermsKey, false); - - set hasAcceptedTerms(bool newValue) => setAndNotify(hasAcceptedTermsKey, newValue); - - LaunchPage get launchPage => getEnumOrDefault(launchPageKey, LaunchPage.collection, LaunchPage.values); - - set launchPage(LaunchPage newValue) => setAndNotify(launchPageKey, newValue.toString()); - CoordinateFormat get coordinateFormat => getEnumOrDefault(coordinateFormatKey, CoordinateFormat.dms, CoordinateFormat.values); set coordinateFormat(CoordinateFormat newValue) => setAndNotify(coordinateFormatKey, newValue.toString()); + // rendering + int get svgBackground => _prefs.getInt(svgBackgroundKey) ?? 0xFFFFFFFF; set svgBackground(int newValue) => setAndNotify(svgBackgroundKey, newValue); - ChipSortFactor get albumSortFactor => getEnumOrDefault(albumSortFactorKey, ChipSortFactor.date, ChipSortFactor.values); - - set albumSortFactor(ChipSortFactor newValue) => setAndNotify(albumSortFactorKey, newValue.toString()); - // convenience methods // ignore: avoid_positional_boolean_parameters @@ -126,14 +149,14 @@ class Settings extends ChangeNotifier { } } -enum LaunchPage { collection, albums } +enum HomePageSetting { collection, albums } -extension ExtraLaunchPage on LaunchPage { +extension ExtraHomePageSetting on HomePageSetting { String get name { switch (this) { - case LaunchPage.collection: + case HomePageSetting.collection: return 'All Media'; - case LaunchPage.albums: + case HomePageSetting.albums: return 'Albums'; default: return toString(); diff --git a/lib/utils/constants.dart b/lib/utils/constants.dart index 32158651d..658ff6763 100644 --- a/lib/utils/constants.dart +++ b/lib/utils/constants.dart @@ -10,13 +10,6 @@ class Constants { color: Color(0xFFEEEEEE), fontSize: 20, fontFamily: 'Concourse Caps', - shadows: [ - Shadow( - offset: Offset(0, 2), - blurRadius: 3, - color: Color(0xFF212121), - ), - ], ); static const List androidDependencies = [ diff --git a/lib/utils/durations.dart b/lib/utils/durations.dart index 3bb1e1a4d..f4d7c2a26 100644 --- a/lib/utils/durations.dart +++ b/lib/utils/durations.dart @@ -31,4 +31,5 @@ class Durations { static const collectionScalingCompleteNotificationDelay = Duration(milliseconds: 300); static const videoProgressTimerInterval = Duration(milliseconds: 300); static Duration staggeredAnimationDelay = Durations.staggeredAnimation ~/ 6 * timeDilation; + static const doubleBackTimerDelay = Duration(milliseconds: 1000); } diff --git a/lib/widgets/album/app_bar.dart b/lib/widgets/album/app_bar.dart index fc370dfcc..bb7d9fade 100644 --- a/lib/widgets/album/app_bar.dart +++ b/lib/widgets/album/app_bar.dart @@ -7,10 +7,9 @@ import 'package:aves/model/source/enums.dart'; import 'package:aves/utils/durations.dart'; import 'package:aves/widgets/album/filter_bar.dart'; import 'package:aves/widgets/album/search/search_delegate.dart'; -import 'package:aves/widgets/common/action_delegates/collection_group_dialog.dart'; -import 'package:aves/widgets/common/action_delegates/collection_sort_dialog.dart'; import 'package:aves/widgets/common/action_delegates/selection_action_delegate.dart'; import 'package:aves/widgets/common/app_bar_subtitle.dart'; +import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart'; import 'package:aves/widgets/common/entry_actions.dart'; import 'package:aves/widgets/common/icons.dart'; @@ -296,23 +295,40 @@ class _CollectionAppBarState extends State with SingleTickerPr unawaited(_goToStats()); break; case CollectionAction.group: - final factor = await showDialog( + final value = await showDialog( context: context, - builder: (context) => CollectionGroupDialog(), + builder: (context) => AvesSelectionDialog( + initialValue: settings.collectionGroupFactor, + options: { + EntryGroupFactor.album: 'By album', + EntryGroupFactor.month: 'By month', + EntryGroupFactor.day: 'By day', + EntryGroupFactor.none: 'Do not group', + }, + title: 'Group', + ), ); - if (factor != null) { - settings.collectionGroupFactor = factor; - collection.group(factor); + if (value != null) { + settings.collectionGroupFactor = value; + collection.group(value); } break; case CollectionAction.sort: - final factor = await showDialog( + final value = await showDialog( context: context, - builder: (context) => CollectionSortDialog(initialValue: settings.collectionSortFactor), + builder: (context) => AvesSelectionDialog( + initialValue: settings.collectionSortFactor, + options: { + EntrySortFactor.date: 'By date', + EntrySortFactor.size: 'By size', + EntrySortFactor.name: 'By album & file name', + }, + title: 'Sort', + ), ); - if (factor != null) { - settings.collectionSortFactor = factor; - collection.sort(factor); + if (value != null) { + settings.collectionSortFactor = value; + collection.sort(value); } break; } diff --git a/lib/widgets/album/collection_page.dart b/lib/widgets/album/collection_page.dart index d1c942e0a..7349dc8ef 100644 --- a/lib/widgets/album/collection_page.dart +++ b/lib/widgets/album/collection_page.dart @@ -2,6 +2,7 @@ import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/widgets/album/thumbnail_collection.dart'; import 'package:aves/widgets/app_drawer.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; +import 'package:aves/widgets/common/double_back_pop.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -26,7 +27,9 @@ class CollectionPage extends StatelessWidget { } return SynchronousFuture(true); }, - child: ThumbnailCollection(), + child: DoubleBackPopScope( + child: ThumbnailCollection(), + ), ), drawer: AppDrawer( source: collection.source, diff --git a/lib/widgets/common/action_delegates/chip_sort_dialog.dart b/lib/widgets/common/action_delegates/chip_sort_dialog.dart deleted file mode 100644 index 9308343b4..000000000 --- a/lib/widgets/common/action_delegates/chip_sort_dialog.dart +++ /dev/null @@ -1,59 +0,0 @@ -import 'package:aves/model/source/enums.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -import '../dialog.dart'; - -class ChipSortDialog extends StatefulWidget { - final ChipSortFactor initialValue; - - const ChipSortDialog({@required this.initialValue}); - - @override - _ChipSortDialogState createState() => _ChipSortDialogState(); -} - -class _ChipSortDialogState extends State { - ChipSortFactor _selectedSort; - - @override - void initState() { - super.initState(); - _selectedSort = widget.initialValue; - } - - @override - Widget build(BuildContext context) { - return AvesDialog( - title: 'Sort', - scrollableContent: [ - _buildRadioListTile(ChipSortFactor.date, 'By date'), - _buildRadioListTile(ChipSortFactor.name, 'By name'), - ], - actions: [ - FlatButton( - onPressed: () => Navigator.pop(context), - child: Text('Cancel'.toUpperCase()), - ), - FlatButton( - key: Key('apply-button'), - onPressed: () => Navigator.pop(context, _selectedSort), - child: Text('Apply'.toUpperCase()), - ), - ], - ); - } - - Widget _buildRadioListTile(ChipSortFactor value, String title) => RadioListTile( - key: Key(value.toString()), - value: value, - groupValue: _selectedSort, - onChanged: (sort) => setState(() => _selectedSort = sort), - title: Text( - title, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - ); -} diff --git a/lib/widgets/common/action_delegates/collection_group_dialog.dart b/lib/widgets/common/action_delegates/collection_group_dialog.dart deleted file mode 100644 index 66f898734..000000000 --- a/lib/widgets/common/action_delegates/collection_group_dialog.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:aves/model/settings.dart'; -import 'package:aves/model/source/enums.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -import '../dialog.dart'; - -class CollectionGroupDialog extends StatefulWidget { - @override - _CollectionGroupDialogState createState() => _CollectionGroupDialogState(); -} - -class _CollectionGroupDialogState extends State { - EntryGroupFactor _selectedGroup; - - @override - void initState() { - super.initState(); - _selectedGroup = settings.collectionGroupFactor; - } - - @override - Widget build(BuildContext context) { - return AvesDialog( - title: 'Group', - scrollableContent: [ - _buildRadioListTile(EntryGroupFactor.album, 'By album'), - _buildRadioListTile(EntryGroupFactor.month, 'By month'), - _buildRadioListTile(EntryGroupFactor.day, 'By day'), - _buildRadioListTile(EntryGroupFactor.none, 'Do not group'), - ], - actions: [ - FlatButton( - onPressed: () => Navigator.pop(context), - child: Text('Cancel'.toUpperCase()), - ), - FlatButton( - key: Key('apply-button'), - onPressed: () => Navigator.pop(context, _selectedGroup), - child: Text('Apply'.toUpperCase()), - ), - ], - ); - } - - Widget _buildRadioListTile(EntryGroupFactor value, String title) => RadioListTile( - key: Key(value.toString()), - value: value, - groupValue: _selectedGroup, - onChanged: (group) => setState(() => _selectedGroup = group), - title: Text( - title, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - ); -} diff --git a/lib/widgets/common/action_delegates/collection_sort_dialog.dart b/lib/widgets/common/action_delegates/collection_sort_dialog.dart deleted file mode 100644 index 302ef203b..000000000 --- a/lib/widgets/common/action_delegates/collection_sort_dialog.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:aves/model/source/enums.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -import '../dialog.dart'; - -class CollectionSortDialog extends StatefulWidget { - final EntrySortFactor initialValue; - - const CollectionSortDialog({@required this.initialValue}); - - @override - _CollectionSortDialogState createState() => _CollectionSortDialogState(); -} - -class _CollectionSortDialogState extends State { - EntrySortFactor _selectedSort; - - @override - void initState() { - super.initState(); - _selectedSort = widget.initialValue; - } - - @override - Widget build(BuildContext context) { - return AvesDialog( - title: 'Sort', - scrollableContent: [ - _buildRadioListTile(EntrySortFactor.date, 'By date'), - _buildRadioListTile(EntrySortFactor.size, 'By size'), - _buildRadioListTile(EntrySortFactor.name, 'By album & file name'), - ], - actions: [ - FlatButton( - onPressed: () => Navigator.pop(context), - child: Text('Cancel'.toUpperCase()), - ), - FlatButton( - key: Key('apply-button'), - onPressed: () => Navigator.pop(context, _selectedSort), - child: Text('Apply'.toUpperCase()), - ), - ], - ); - } - - Widget _buildRadioListTile(EntrySortFactor value, String title) => RadioListTile( - key: Key(value.toString()), - value: value, - groupValue: _selectedSort, - onChanged: (sort) => setState(() => _selectedSort = sort), - title: Text( - title, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - ); -} diff --git a/lib/widgets/common/action_delegates/create_album_dialog.dart b/lib/widgets/common/action_delegates/create_album_dialog.dart index a32dfcf53..801255497 100644 --- a/lib/widgets/common/action_delegates/create_album_dialog.dart +++ b/lib/widgets/common/action_delegates/create_album_dialog.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:path/path.dart'; -import '../dialog.dart'; +import '../aves_dialog.dart'; class CreateAlbumDialog extends StatefulWidget { @override diff --git a/lib/widgets/common/action_delegates/entry_action_delegate.dart b/lib/widgets/common/action_delegates/entry_action_delegate.dart index ad52a6441..368acd591 100644 --- a/lib/widgets/common/action_delegates/entry_action_delegate.dart +++ b/lib/widgets/common/action_delegates/entry_action_delegate.dart @@ -7,7 +7,7 @@ import 'package:aves/services/image_file_service.dart'; import 'package:aves/widgets/common/action_delegates/feedback.dart'; import 'package:aves/widgets/common/action_delegates/permission_aware.dart'; import 'package:aves/widgets/common/action_delegates/rename_entry_dialog.dart'; -import 'package:aves/widgets/common/dialog.dart'; +import 'package:aves/widgets/common/aves_dialog.dart'; import 'package:aves/widgets/common/entry_actions.dart'; import 'package:aves/widgets/common/image_providers/uri_image_provider.dart'; import 'package:aves/widgets/fullscreen/debug.dart'; diff --git a/lib/widgets/common/action_delegates/map_style_dialog.dart b/lib/widgets/common/action_delegates/map_style_dialog.dart deleted file mode 100644 index a9b0fd3d2..000000000 --- a/lib/widgets/common/action_delegates/map_style_dialog.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:aves/model/settings.dart'; -import 'package:aves/widgets/fullscreen/info/location_section.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -import '../dialog.dart'; - -class MapStyleDialog extends StatefulWidget { - @override - _MapStyleDialogState createState() => _MapStyleDialogState(); -} - -class _MapStyleDialogState extends State { - EntryMapStyle _selectedStyle; - - @override - void initState() { - super.initState(); - _selectedStyle = settings.infoMapStyle; - } - - @override - Widget build(BuildContext context) { - return AvesDialog( - title: 'Map Style', - scrollableContent: EntryMapStyle.values.map((style) => _buildRadioListTile(style, style.name)).toList(), - actions: [ - FlatButton( - onPressed: () => Navigator.pop(context), - child: Text('Cancel'.toUpperCase()), - ), - FlatButton( - onPressed: () => Navigator.pop(context, _selectedStyle), - child: Text('Apply'.toUpperCase()), - ), - ], - ); - } - - Widget _buildRadioListTile(EntryMapStyle style, String title) => RadioListTile( - value: style, - groupValue: _selectedStyle, - onChanged: (style) => setState(() => _selectedStyle = style), - title: Text( - title, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - ); -} diff --git a/lib/widgets/common/action_delegates/permission_aware.dart b/lib/widgets/common/action_delegates/permission_aware.dart index d1df692b5..b020c627e 100644 --- a/lib/widgets/common/action_delegates/permission_aware.dart +++ b/lib/widgets/common/action_delegates/permission_aware.dart @@ -2,7 +2,7 @@ import 'package:aves/model/image_entry.dart'; import 'package:aves/services/android_file_service.dart'; import 'package:flutter/material.dart'; -import '../dialog.dart'; +import '../aves_dialog.dart'; mixin PermissionAwareMixin { Future checkStoragePermission(BuildContext context, Iterable entries) { diff --git a/lib/widgets/common/action_delegates/rename_entry_dialog.dart b/lib/widgets/common/action_delegates/rename_entry_dialog.dart index 33cee0309..4e3106a47 100644 --- a/lib/widgets/common/action_delegates/rename_entry_dialog.dart +++ b/lib/widgets/common/action_delegates/rename_entry_dialog.dart @@ -1,7 +1,8 @@ import 'package:aves/model/image_entry.dart'; -import 'package:aves/widgets/common/dialog.dart'; import 'package:flutter/material.dart'; +import '../aves_dialog.dart'; + class RenameEntryDialog extends StatefulWidget { final ImageEntry entry; diff --git a/lib/widgets/common/action_delegates/selection_action_delegate.dart b/lib/widgets/common/action_delegates/selection_action_delegate.dart index 24faeadee..b3bf36570 100644 --- a/lib/widgets/common/action_delegates/selection_action_delegate.dart +++ b/lib/widgets/common/action_delegates/selection_action_delegate.dart @@ -14,7 +14,7 @@ import 'package:aves/widgets/album/empty.dart'; import 'package:aves/widgets/common/action_delegates/create_album_dialog.dart'; import 'package:aves/widgets/common/action_delegates/feedback.dart'; import 'package:aves/widgets/common/action_delegates/permission_aware.dart'; -import 'package:aves/widgets/common/dialog.dart'; +import 'package:aves/widgets/common/aves_dialog.dart'; import 'package:aves/widgets/common/entry_actions.dart'; import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/filter_grids/filter_grid_page.dart'; diff --git a/lib/widgets/common/dialog.dart b/lib/widgets/common/aves_dialog.dart similarity index 100% rename from lib/widgets/common/dialog.dart rename to lib/widgets/common/aves_dialog.dart diff --git a/lib/widgets/common/aves_selection_dialog.dart b/lib/widgets/common/aves_selection_dialog.dart new file mode 100644 index 000000000..4165183ba --- /dev/null +++ b/lib/widgets/common/aves_selection_dialog.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import 'aves_dialog.dart'; + +class AvesSelectionDialog extends StatefulWidget { + final T initialValue; + final Map options; + final String title; + + const AvesSelectionDialog({ + @required this.initialValue, + @required this.options, + @required this.title, + }); + + @override + _AvesSelectionDialogState createState() => _AvesSelectionDialogState(); +} + +class _AvesSelectionDialogState extends State { + T _selectedValue; + + @override + void initState() { + super.initState(); + _selectedValue = widget.initialValue; + } + + @override + Widget build(BuildContext context) { + return AvesDialog( + title: widget.title, + scrollableContent: widget.options.entries.map((kv) => _buildRadioListTile(kv.key, kv.value)).toList(), + actions: [ + FlatButton( + onPressed: () => Navigator.pop(context), + child: Text('Cancel'.toUpperCase()), + ), + FlatButton( + key: Key('apply-button'), + onPressed: () => Navigator.pop(context, _selectedValue), + child: Text('Apply'.toUpperCase()), + ), + ], + ); + } + + Widget _buildRadioListTile(T value, String title) => RadioListTile( + key: Key(value.toString()), + value: value, + groupValue: _selectedValue, + onChanged: (v) => setState(() => _selectedValue = v), + title: Text( + title, + softWrap: false, + overflow: TextOverflow.fade, + maxLines: 1, + ), + ); +} diff --git a/lib/widgets/common/double_back_pop.dart b/lib/widgets/common/double_back_pop.dart new file mode 100644 index 000000000..583a9563f --- /dev/null +++ b/lib/widgets/common/double_back_pop.dart @@ -0,0 +1,54 @@ +import 'dart:async'; + +import 'package:aves/model/settings.dart'; +import 'package:aves/utils/durations.dart'; +import 'package:aves/widgets/common/action_delegates/feedback.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:overlay_support/overlay_support.dart'; + +class DoubleBackPopScope extends StatefulWidget { + final Widget child; + + const DoubleBackPopScope({ + @required this.child, + }); + + @override + _DoubleBackPopScopeState createState() => _DoubleBackPopScopeState(); +} + +class _DoubleBackPopScopeState extends State with FeedbackMixin { + bool _backOnce = false; + Timer _backTimer; + + @override + void dispose() { + _stopBackTimer(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () { + if (!Navigator.of(context).canPop() && settings.mustBackTwiceToExit && !_backOnce) { + _backOnce = true; + _stopBackTimer(); + _backTimer = Timer(Durations.doubleBackTimerDelay, () => _backOnce = false); + toast( + 'Tap “back” again to exit.', + duration: Durations.doubleBackTimerDelay, + ); + return SynchronousFuture(false); + } + return SynchronousFuture(true); + }, + child: widget.child, + ); + } + + void _stopBackTimer() { + _backTimer?.cancel(); + } +} diff --git a/lib/widgets/common/highlight_title.dart b/lib/widgets/common/highlight_title.dart new file mode 100644 index 000000000..1fbb5cab7 --- /dev/null +++ b/lib/widgets/common/highlight_title.dart @@ -0,0 +1,43 @@ +import 'package:aves/utils/color_utils.dart'; +import 'package:aves/widgets/common/fx/highlight_decoration.dart'; +import 'package:flutter/material.dart'; + +class HighlightTitle extends StatelessWidget { + final String name; + final double fontSize; + + const HighlightTitle( + this.name, { + this.fontSize = 20, + }); + + @override + Widget build(BuildContext context) { + return Align( + alignment: AlignmentDirectional.centerStart, + child: Container( + decoration: HighlightDecoration( + color: stringToColor(name), + ), + margin: EdgeInsets.symmetric(vertical: 4.0), + child: Text( + name, + style: TextStyle( + shadows: [ + Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 2, + ) + ], + fontSize: fontSize, + fontFamily: 'Concourse Caps', + ), + softWrap: false, + overflow: TextOverflow.fade, + maxLines: 1, + ), + ), + ); + } +} diff --git a/lib/widgets/filter_grids/albums_page.dart b/lib/widgets/filter_grids/albums_page.dart index 67078e0d8..b696941e3 100644 --- a/lib/widgets/filter_grids/albums_page.dart +++ b/lib/widgets/filter_grids/albums_page.dart @@ -7,7 +7,7 @@ import 'package:aves/model/source/enums.dart'; import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/durations.dart'; import 'package:aves/widgets/album/empty.dart'; -import 'package:aves/widgets/common/action_delegates/chip_sort_dialog.dart'; +import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/common/menu_row.dart'; import 'package:aves/widgets/filter_grids/filter_grid_page.dart'; @@ -117,7 +117,14 @@ class AlbumListPage extends StatelessWidget { case ChipAction.sort: final factor = await showDialog( context: context, - builder: (context) => ChipSortDialog(initialValue: settings.albumSortFactor), + builder: (context) => AvesSelectionDialog( + initialValue: settings.albumSortFactor, + options: { + ChipSortFactor.date: 'By date', + ChipSortFactor.name: 'By name', + }, + title: 'Sort', + ), ); if (factor != null) { settings.albumSortFactor = factor; diff --git a/lib/widgets/fullscreen/info/maps/common.dart b/lib/widgets/fullscreen/info/maps/common.dart index 3440a6665..7cbb51131 100644 --- a/lib/widgets/fullscreen/info/maps/common.dart +++ b/lib/widgets/fullscreen/info/maps/common.dart @@ -1,6 +1,6 @@ import 'package:aves/model/settings.dart'; import 'package:aves/services/android_app_service.dart'; -import 'package:aves/widgets/common/action_delegates/map_style_dialog.dart'; +import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/borders.dart'; import 'package:aves/widgets/common/fx/blurred.dart'; import 'package:aves/widgets/common/icons.dart'; @@ -70,7 +70,11 @@ class MapButtonPanel extends StatelessWidget { onPressed: () async { final style = await showDialog( context: context, - builder: (context) => MapStyleDialog(), + builder: (context) => AvesSelectionDialog( + initialValue: settings.infoMapStyle, + options: Map.fromEntries(EntryMapStyle.values.map((v) => MapEntry(v, v.name))), + title: 'Map Style', + ), ); if (style != null) { settings.infoMapStyle = style; diff --git a/lib/widgets/fullscreen/info/metadata_section.dart b/lib/widgets/fullscreen/info/metadata_section.dart index fb3cf769e..11bfda26d 100644 --- a/lib/widgets/fullscreen/info/metadata_section.dart +++ b/lib/widgets/fullscreen/info/metadata_section.dart @@ -3,8 +3,7 @@ import 'dart:collection'; import 'package:aves/model/image_entry.dart'; import 'package:aves/services/metadata_service.dart'; -import 'package:aves/utils/color_utils.dart'; -import 'package:aves/widgets/common/fx/highlight_decoration.dart'; +import 'package:aves/widgets/common/highlight_title.dart'; import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart'; import 'package:expansion_tile_card/expansion_tile_card.dart'; @@ -90,7 +89,10 @@ class _MetadataSectionSliverState extends State with Auto key: Key('tilecard-${dir.name}'), value: dir.name, expandedNotifier: _expandedDirectoryNotifier, - title: _DirectoryTitle(dir.name), + title: HighlightTitle( + dir.name, + fontSize: 18, + ), children: [ Divider(thickness: 1.0, height: 1.0), Container( @@ -138,42 +140,6 @@ class _MetadataSectionSliverState extends State with Auto bool get wantKeepAlive => true; } -class _DirectoryTitle extends StatelessWidget { - final String name; - - const _DirectoryTitle(this.name); - - @override - Widget build(BuildContext context) { - return Align( - alignment: Alignment.centerLeft, - child: Container( - decoration: HighlightDecoration( - color: stringToColor(name), - ), - margin: EdgeInsets.symmetric(vertical: 4.0), - child: Text( - name, - style: TextStyle( - shadows: [ - Shadow( - color: Colors.black, - offset: Offset(1, 1), - blurRadius: 2, - ) - ], - fontSize: 18, - fontFamily: 'Concourse Caps', - ), - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - ), - ); - } -} - class _MetadataDirectory { final String name; final SplayTreeMap tags; diff --git a/lib/widgets/home_page.dart b/lib/widgets/home_page.dart index 05931e7c0..732aa78a0 100644 --- a/lib/widgets/home_page.dart +++ b/lib/widgets/home_page.dart @@ -103,11 +103,11 @@ class _HomePageState extends State { return SingleFullscreenPage(entry: _viewerEntry); } if (_mediaStore != null) { - switch (settings.launchPage) { - case LaunchPage.albums: + switch (settings.homePage) { + case HomePageSetting.albums: return AlbumListPage(source: _mediaStore); break; - case LaunchPage.collection: + case HomePageSetting.collection: return CollectionPage(CollectionLens( source: _mediaStore, groupFactor: settings.collectionGroupFactor, diff --git a/lib/widgets/settings/coordinate_format.dart b/lib/widgets/settings/coordinate_format.dart deleted file mode 100644 index 47b0d93a2..000000000 --- a/lib/widgets/settings/coordinate_format.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:aves/model/settings.dart'; -import 'package:flutter/material.dart'; - -class CoordinateFormatSelector extends StatefulWidget { - @override - _CoordinateFormatSelectorState createState() => _CoordinateFormatSelectorState(); -} - -class _CoordinateFormatSelectorState extends State { - @override - Widget build(BuildContext context) { - return DropdownButton( - items: CoordinateFormat.values - .map((selected) => DropdownMenuItem( - value: selected, - child: Text( - selected.name, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - )) - .toList(), - value: settings.coordinateFormat, - onChanged: (selected) { - settings.coordinateFormat = selected; - setState(() {}); - }, - ); - } -} diff --git a/lib/widgets/settings/launch_page.dart b/lib/widgets/settings/launch_page.dart deleted file mode 100644 index 321f4bbbc..000000000 --- a/lib/widgets/settings/launch_page.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:aves/model/settings.dart'; -import 'package:flutter/material.dart'; - -class LaunchPageSelector extends StatefulWidget { - @override - _LaunchPageSelectorState createState() => _LaunchPageSelectorState(); -} - -class _LaunchPageSelectorState extends State { - @override - Widget build(BuildContext context) { - return DropdownButton( - items: LaunchPage.values - .map((selected) => DropdownMenuItem( - value: selected, - child: Text( - selected.name, - softWrap: false, - overflow: TextOverflow.fade, - maxLines: 1, - ), - )) - .toList(), - value: settings.launchPage, - onChanged: (selected) { - settings.launchPage = selected; - setState(() {}); - }, - ); - } -} diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 2a32044c2..0866c6cae 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -1,9 +1,10 @@ -import 'package:aves/utils/constants.dart'; +import 'package:aves/model/settings.dart'; +import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; -import 'package:aves/widgets/settings/coordinate_format.dart'; -import 'package:aves/widgets/settings/launch_page.dart'; +import 'package:aves/widgets/common/highlight_title.dart'; import 'package:aves/widgets/settings/svg_background.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class SettingsPage extends StatelessWidget { @override @@ -16,35 +17,57 @@ class SettingsPage extends StatelessWidget { title: Text('Preferences'), ), body: SafeArea( - child: ListView( - padding: EdgeInsets.all(16), - children: [ - Text('General', style: Constants.titleTextStyle), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text('Launch page:'), - SizedBox(width: 8), - Flexible(child: LaunchPageSelector()), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text('SVG background:'), - SizedBox(width: 8), - Flexible(child: SvgBackgroundSelector()), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text('Coordinate format:'), - SizedBox(width: 8), - Flexible(child: CoordinateFormatSelector()), - ], - ), - ], + child: Consumer( + builder: (context, settings, child) => ListView( + padding: EdgeInsets.symmetric(vertical: 16), + children: [ + SectionTitle('Navigation'), + ListTile( + title: Text('Home'), + subtitle: Text(settings.homePage.name), + onTap: () async { + final value = await showDialog( + context: context, + builder: (context) => AvesSelectionDialog( + initialValue: settings.homePage, + options: Map.fromEntries(HomePageSetting.values.map((v) => MapEntry(v, v.name))), + title: 'Home', + ), + ); + if (value != null) { + settings.homePage = value; + } + }, + ), + SwitchListTile( + value: settings.mustBackTwiceToExit, + onChanged: (v) => settings.mustBackTwiceToExit = v, + title: Text('Tap “back” twice to exit'), + ), + SectionTitle('Display'), + ListTile( + title: Text('SVG background'), + trailing: SvgBackgroundSelector(), + ), + ListTile( + title: Text('Coordinate format'), + subtitle: Text(settings.coordinateFormat.name), + onTap: () async { + final value = await showDialog( + context: context, + builder: (context) => AvesSelectionDialog( + initialValue: settings.coordinateFormat, + options: Map.fromEntries(CoordinateFormat.values.map((v) => MapEntry(v, v.name))), + title: 'Coordinate Format', + ), + ); + if (value != null) { + settings.coordinateFormat = value; + } + }, + ), + ], + ), ), ), ), @@ -52,3 +75,17 @@ class SettingsPage extends StatelessWidget { ); } } + +class SectionTitle extends StatelessWidget { + final String text; + + const SectionTitle(this.text); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: 16, top: 6, right: 16, bottom: 12), + child: HighlightTitle(text), + ); + } +} diff --git a/lib/widgets/settings/svg_background.dart b/lib/widgets/settings/svg_background.dart index 780ec1cb7..fc2497b3d 100644 --- a/lib/widgets/settings/svg_background.dart +++ b/lib/widgets/settings/svg_background.dart @@ -11,33 +11,35 @@ class _SvgBackgroundSelectorState extends State { @override Widget build(BuildContext context) { const radius = 24.0; - return DropdownButton( - items: [0xFFFFFFFF, 0xFF000000, 0x00000000].map((selected) { - return DropdownMenuItem( - value: selected, - child: Container( - height: radius, - width: radius, - decoration: BoxDecoration( - color: Color(selected), - border: AvesCircleBorder.build(context), - shape: BoxShape.circle, + return DropdownButtonHideUnderline( + child: DropdownButton( + items: [0xFFFFFFFF, 0xFF000000, 0x00000000].map((selected) { + return DropdownMenuItem( + value: selected, + child: Container( + height: radius, + width: radius, + decoration: BoxDecoration( + color: Color(selected), + border: AvesCircleBorder.build(context), + shape: BoxShape.circle, + ), + child: selected == 0 + ? Icon( + Icons.clear, + size: 20, + color: Colors.white30, + ) + : null, ), - child: selected == 0 - ? Icon( - Icons.clear, - size: 20, - color: Colors.white30, - ) - : null, - ), - ); - }).toList(), - value: settings.svgBackground, - onChanged: (selected) { - settings.svgBackground = selected; - setState(() {}); - }, + ); + }).toList(), + value: settings.svgBackground, + onChanged: (selected) { + settings.svgBackground = selected; + setState(() {}); + }, + ), ); } } diff --git a/pubspec.lock b/pubspec.lock index 10e5d7d0b..dccce0a00 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -466,6 +466,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.1.1" + overlay_support: + dependency: "direct main" + description: + name: overlay_support + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" package_config: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index e1ca0fab9..14a2061d3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -63,6 +63,7 @@ dependencies: intl: latlong: # for flutter_map outline_material_icons: + overlay_support: package_info: palette_generator: pdf: From daedad57fa87a76b7b740f6a5b3e1dba1f54ac57 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 3 Sep 2020 13:20:42 +0900 Subject: [PATCH 2/9] current route identification --- .github/workflows/check.yml | 2 + lib/model/settings.dart | 2 +- lib/utils/flutter_utils.dart | 5 ++ lib/widgets/about/about_page.dart | 2 + lib/widgets/album/app_bar.dart | 6 +- lib/widgets/album/collection_page.dart | 2 + lib/widgets/album/grid/list_sliver.dart | 3 +- lib/widgets/app_drawer.dart | 47 +++++++------ .../entry_action_delegate.dart | 1 + lib/widgets/common/icons.dart | 2 +- lib/widgets/common/routes.dart | 33 ++++++++++ .../transparent_material_page_route.dart | 16 ----- lib/widgets/debug_page.dart | 2 + lib/widgets/filter_grids/albums_page.dart | 2 + lib/widgets/filter_grids/countries_page.dart | 2 + .../filter_grids/filter_grid_page.dart | 1 + lib/widgets/filter_grids/tags_page.dart | 2 + lib/widgets/fullscreen/debug.dart | 2 + lib/widgets/fullscreen/fullscreen_body.dart | 3 +- lib/widgets/fullscreen/fullscreen_page.dart | 4 ++ lib/widgets/fullscreen/overlay/top.dart | 2 +- lib/widgets/home_page.dart | 66 +++++++++++-------- lib/widgets/settings/settings_page.dart | 2 + lib/widgets/stats/filter_table.dart | 1 + lib/widgets/stats/stats.dart | 3 + lib/widgets/welcome_page.dart | 1 + test_driver/app_test.dart | 2 +- 27 files changed, 147 insertions(+), 69 deletions(-) create mode 100644 lib/utils/flutter_utils.dart create mode 100644 lib/widgets/common/routes.dart delete mode 100644 lib/widgets/common/transparent_material_page_route.dart diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 5510adbf4..4adf69e21 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -5,6 +5,8 @@ on: branches: - develop +# TODO TLAD run `flutter format -l 1000 .` and fail if any + jobs: build: name: Check code quality. diff --git a/lib/model/settings.dart b/lib/model/settings.dart index 97b2116e2..d5c644a51 100644 --- a/lib/model/settings.dart +++ b/lib/model/settings.dart @@ -155,7 +155,7 @@ extension ExtraHomePageSetting on HomePageSetting { String get name { switch (this) { case HomePageSetting.collection: - return 'All Media'; + return 'Collection'; case HomePageSetting.albums: return 'Albums'; default: diff --git a/lib/utils/flutter_utils.dart b/lib/utils/flutter_utils.dart new file mode 100644 index 000000000..3f06767b8 --- /dev/null +++ b/lib/utils/flutter_utils.dart @@ -0,0 +1,5 @@ +import 'package:flutter/widgets.dart'; + +extension ExtraContext on BuildContext { + String get currentRouteName => ModalRoute.of(this)?.settings?.name; +} diff --git a/lib/widgets/about/about_page.dart b/lib/widgets/about/about_page.dart index 8ac977f39..6e35112f6 100644 --- a/lib/widgets/about/about_page.dart +++ b/lib/widgets/about/about_page.dart @@ -7,6 +7,8 @@ import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:package_info/package_info.dart'; class AboutPage extends StatelessWidget { + static const routeName = '/about'; + @override Widget build(BuildContext context) { return Scaffold( diff --git a/lib/widgets/album/app_bar.dart b/lib/widgets/album/app_bar.dart index bb7d9fade..f55698bef 100644 --- a/lib/widgets/album/app_bar.dart +++ b/lib/widgets/album/app_bar.dart @@ -134,7 +134,10 @@ class _CollectionAppBarState extends State with SingleTickerPr Widget _buildAppBarTitle() { if (collection.isBrowsing) { - Widget title = Text(AvesApp.mode == AppMode.pick ? 'Select' : 'Aves', key: Key('appbar-title')); + Widget title = Text( + AvesApp.mode == AppMode.pick ? 'Select' : 'Collection', + key: Key('appbar-title'), + ); if (AvesApp.mode == AppMode.main) { title = SourceStateAwareAppBarTitle( title: title, @@ -345,6 +348,7 @@ class _CollectionAppBarState extends State with SingleTickerPr return Navigator.push( context, MaterialPageRoute( + settings: RouteSettings(name: StatsPage.routeName), builder: (context) => StatsPage( collection: collection, ), diff --git a/lib/widgets/album/collection_page.dart b/lib/widgets/album/collection_page.dart index 7349dc8ef..05a2dafbf 100644 --- a/lib/widgets/album/collection_page.dart +++ b/lib/widgets/album/collection_page.dart @@ -8,6 +8,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class CollectionPage extends StatelessWidget { + static const routeName = '/collection'; + final CollectionLens collection; const CollectionPage(this.collection); diff --git a/lib/widgets/album/grid/list_sliver.dart b/lib/widgets/album/grid/list_sliver.dart index dc8845a33..9e4006779 100644 --- a/lib/widgets/album/grid/list_sliver.dart +++ b/lib/widgets/album/grid/list_sliver.dart @@ -5,7 +5,7 @@ import 'package:aves/services/viewer_service.dart'; import 'package:aves/widgets/album/grid/list_known_extent.dart'; import 'package:aves/widgets/album/grid/list_section_layout.dart'; import 'package:aves/widgets/album/thumbnail/decorated.dart'; -import 'package:aves/widgets/common/transparent_material_page_route.dart'; +import 'package:aves/widgets/common/routes.dart'; import 'package:aves/widgets/fullscreen/fullscreen_page.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -85,6 +85,7 @@ class GridThumbnail extends StatelessWidget { Navigator.push( context, TransparentMaterialPageRoute( + settings: RouteSettings(name: MultiFullscreenPage.routeName), pageBuilder: (c, a, sa) => MultiFullscreenPage( collection: collection, initialEntry: entry, diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart index 0de8f56a2..47ccdccc5 100644 --- a/lib/widgets/app_drawer.dart +++ b/lib/widgets/app_drawer.dart @@ -12,6 +12,7 @@ import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/location.dart'; import 'package:aves/model/source/tag.dart'; import 'package:aves/utils/android_file_utils.dart'; +import 'package:aves/utils/flutter_utils.dart'; import 'package:aves/widgets/about/about_page.dart'; import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/common/aves_logo.dart'; @@ -75,10 +76,10 @@ class _AppDrawerState extends State { ), ); - final allMediaEntry = _FilteredCollectionNavTile( + final allCollectionEntry = _FilteredCollectionNavTile( source: source, - leading: Icon(AIcons.allMedia), - title: 'All media', + leading: Icon(AIcons.allCollection), + title: 'All collection', filter: null, ); final videoEntry = _FilteredCollectionNavTile( @@ -99,7 +100,7 @@ class _AppDrawerState extends State { child: ListTile( leading: Icon(AIcons.settings), title: Text('Preferences'), - onTap: () => _goTo((_) => SettingsPage()), + onTap: () => _goTo(SettingsPage.routeName, (_) => SettingsPage()), ), ); final aboutEntry = SafeArea( @@ -108,20 +109,20 @@ class _AppDrawerState extends State { child: ListTile( leading: Icon(AIcons.info), title: Text('About'), - onTap: () => _goTo((_) => AboutPage()), + onTap: () => _goTo(AboutPage.routeName, (_) => AboutPage()), ), ); final drawerItems = [ header, - allMediaEntry, + allCollectionEntry, videoEntry, favouriteEntry, _buildSpecialAlbumSection(), Divider(), - _buildRegularAlbumSection(), - _buildCountrySection(), - _buildTagSection(), + _buildAlbumListEntry(), + _buildCountryListEntry(), + _buildTagListEntry(), Divider(), settingsEntry, aboutEntry, @@ -133,7 +134,7 @@ class _AppDrawerState extends State { child: ListTile( leading: Icon(AIcons.debug), title: Text('Debug'), - onTap: () => _goTo((_) => DebugPage(source: source)), + onTap: () => _goTo(DebugPage.routeName, (_) => DebugPage(source: source)), ), ), ], @@ -184,7 +185,7 @@ class _AppDrawerState extends State { builder: (context, snapshot) { final specialAlbums = source.sortedAlbums.where((album) { final type = androidFileUtils.getAlbumType(album); - return type != AlbumType.regular && type != AlbumType.app; + return [AlbumType.camera, AlbumType.screenshots].contains(type); }); if (specialAlbums.isEmpty) return SizedBox.shrink(); @@ -197,7 +198,7 @@ class _AppDrawerState extends State { }); } - Widget _buildRegularAlbumSection() { + Widget _buildAlbumListEntry() { return SafeArea( top: false, bottom: false, @@ -215,12 +216,12 @@ class _AppDrawerState extends State { ), ); }), - onTap: () => _goTo((_) => AlbumListPage(source: source)), + onTap: () => _goTo(AlbumListPage.routeName, (_) => AlbumListPage(source: source)), ), ); } - Widget _buildCountrySection() { + Widget _buildCountryListEntry() { return SafeArea( top: false, bottom: false, @@ -237,12 +238,12 @@ class _AppDrawerState extends State { ), ); }), - onTap: () => _goTo((_) => CountryListPage(source: source)), + onTap: () => _goTo(CountryListPage.routeName, (_) => CountryListPage(source: source)), ), ); } - Widget _buildTagSection() { + Widget _buildTagListEntry() { return SafeArea( top: false, bottom: false, @@ -259,14 +260,21 @@ class _AppDrawerState extends State { ), ); }), - onTap: () => _goTo((_) => TagListPage(source: source)), + onTap: () => _goTo(TagListPage.routeName, (_) => TagListPage(source: source)), ), ); } - void _goTo(WidgetBuilder builder) { + void _goTo(String routeName, WidgetBuilder builder) { Navigator.pop(context); - Navigator.push(context, MaterialPageRoute(builder: builder)); + if (routeName != context.currentRouteName) { + Navigator.push( + context, + MaterialPageRoute( + settings: RouteSettings(name: routeName), + builder: builder, + )); + } } } @@ -306,6 +314,7 @@ class _FilteredCollectionNavTile extends StatelessWidget { Navigator.pushAndRemoveUntil( context, MaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), builder: (context) => CollectionPage(CollectionLens( source: source, filters: [filter], diff --git a/lib/widgets/common/action_delegates/entry_action_delegate.dart b/lib/widgets/common/action_delegates/entry_action_delegate.dart index 368acd591..4aac59c72 100644 --- a/lib/widgets/common/action_delegates/entry_action_delegate.dart +++ b/lib/widgets/common/action_delegates/entry_action_delegate.dart @@ -174,6 +174,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin { Navigator.push( context, MaterialPageRoute( + settings: RouteSettings(name: FullscreenDebugPage.routeName), builder: (context) => FullscreenDebugPage(entry: entry), ), ); diff --git a/lib/widgets/common/icons.dart b/lib/widgets/common/icons.dart index fba2069dd..42d2f9f2c 100644 --- a/lib/widgets/common/icons.dart +++ b/lib/widgets/common/icons.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import 'package:outline_material_icons/outline_material_icons.dart'; class AIcons { - static const IconData allMedia = OMIcons.collections; + static const IconData allCollection = OMIcons.collections; static const IconData image = OMIcons.photo; static const IconData video = OMIcons.movie; static const IconData vector = OMIcons.code; diff --git a/lib/widgets/common/routes.dart b/lib/widgets/common/routes.dart new file mode 100644 index 000000000..a5ac9d079 --- /dev/null +++ b/lib/widgets/common/routes.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; + +class DirectMaterialPageRoute extends PageRouteBuilder { + DirectMaterialPageRoute({ + RouteSettings settings, + @required WidgetBuilder builder, + }) : super( + settings: settings, + transitionDuration: Duration.zero, + pageBuilder: (c, a, sa) => builder(c), + ); + + @override + Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + return child; + } +} + +class TransparentMaterialPageRoute extends PageRouteBuilder { + TransparentMaterialPageRoute({ + RouteSettings settings, + @required RoutePageBuilder pageBuilder, + }) : super(settings: settings, pageBuilder: pageBuilder); + + @override + bool get opaque => false; + + @override + Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { + final theme = Theme.of(context).pageTransitionsTheme; + return theme.buildTransitions(this, context, animation, secondaryAnimation, child); + } +} diff --git a/lib/widgets/common/transparent_material_page_route.dart b/lib/widgets/common/transparent_material_page_route.dart deleted file mode 100644 index 30f52855a..000000000 --- a/lib/widgets/common/transparent_material_page_route.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:flutter/material.dart'; - -class TransparentMaterialPageRoute extends PageRouteBuilder { - TransparentMaterialPageRoute({ - @required RoutePageBuilder pageBuilder, - }) : super(pageBuilder: pageBuilder); - - @override - bool get opaque => false; - - @override - Widget buildTransitions(BuildContext context, Animation animation, Animation secondaryAnimation, Widget child) { - final theme = Theme.of(context).pageTransitionsTheme; - return theme.buildTransitions(this, context, animation, secondaryAnimation, child); - } -} diff --git a/lib/widgets/debug_page.dart b/lib/widgets/debug_page.dart index bc046a965..e770d2cf8 100644 --- a/lib/widgets/debug_page.dart +++ b/lib/widgets/debug_page.dart @@ -18,6 +18,8 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:outline_material_icons/outline_material_icons.dart'; class DebugPage extends StatefulWidget { + static const routeName = '/debug'; + final CollectionSource source; const DebugPage({this.source}); diff --git a/lib/widgets/filter_grids/albums_page.dart b/lib/widgets/filter_grids/albums_page.dart index b696941e3..ec6b817b6 100644 --- a/lib/widgets/filter_grids/albums_page.dart +++ b/lib/widgets/filter_grids/albums_page.dart @@ -17,6 +17,8 @@ import 'package:flutter/scheduler.dart'; import 'package:provider/provider.dart'; class AlbumListPage extends StatelessWidget { + static const routeName = '/albums'; + final CollectionSource source; const AlbumListPage({@required this.source}); diff --git a/lib/widgets/filter_grids/countries_page.dart b/lib/widgets/filter_grids/countries_page.dart index 243babe8a..c9098f568 100644 --- a/lib/widgets/filter_grids/countries_page.dart +++ b/lib/widgets/filter_grids/countries_page.dart @@ -7,6 +7,8 @@ import 'package:aves/widgets/filter_grids/filter_grid_page.dart'; import 'package:flutter/material.dart'; class CountryListPage extends StatelessWidget { + static const routeName = '/countries'; + final CollectionSource source; const CountryListPage({@required this.source}); diff --git a/lib/widgets/filter_grids/filter_grid_page.dart b/lib/widgets/filter_grids/filter_grid_page.dart index 95ef0665a..72663f830 100644 --- a/lib/widgets/filter_grids/filter_grid_page.dart +++ b/lib/widgets/filter_grids/filter_grid_page.dart @@ -56,6 +56,7 @@ class FilterNavigationPage extends StatelessWidget { onPressed: (filter) => Navigator.pushAndRemoveUntil( context, MaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), builder: (context) => CollectionPage(CollectionLens( source: source, filters: [filter], diff --git a/lib/widgets/filter_grids/tags_page.dart b/lib/widgets/filter_grids/tags_page.dart index 27fee464c..4b4693f89 100644 --- a/lib/widgets/filter_grids/tags_page.dart +++ b/lib/widgets/filter_grids/tags_page.dart @@ -7,6 +7,8 @@ import 'package:aves/widgets/filter_grids/filter_grid_page.dart'; import 'package:flutter/material.dart'; class TagListPage extends StatelessWidget { + static const routeName = '/tags'; + final CollectionSource source; const TagListPage({@required this.source}); diff --git a/lib/widgets/fullscreen/debug.dart b/lib/widgets/fullscreen/debug.dart index 173e773e6..713062394 100644 --- a/lib/widgets/fullscreen/debug.dart +++ b/lib/widgets/fullscreen/debug.dart @@ -10,6 +10,8 @@ import 'package:flutter/material.dart'; import 'package:tuple/tuple.dart'; class FullscreenDebugPage extends StatefulWidget { + static const routeName = '/fullscreen/debug'; + final ImageEntry entry; const FullscreenDebugPage({@required this.entry}); diff --git a/lib/widgets/fullscreen/fullscreen_body.dart b/lib/widgets/fullscreen/fullscreen_body.dart index 2e408e7e7..0e5113c0a 100644 --- a/lib/widgets/fullscreen/fullscreen_body.dart +++ b/lib/widgets/fullscreen/fullscreen_body.dart @@ -275,6 +275,7 @@ class FullscreenBodyState extends State with SingleTickerProvide Navigator.pushAndRemoveUntil( context, MaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), builder: (context) => CollectionPage(collection.derive(filter)), ), (route) => false, @@ -323,7 +324,7 @@ class FullscreenBodyState extends State with SingleTickerProvide } void _onLeave() { - if (!ModalRoute.of(context).canPop) { + if (!Navigator.canPop(context)) { // exit app when trying to pop a fullscreen page that is a viewer for a single entry exit(0); } diff --git a/lib/widgets/fullscreen/fullscreen_page.dart b/lib/widgets/fullscreen/fullscreen_page.dart index 32ddf1507..142bfd344 100644 --- a/lib/widgets/fullscreen/fullscreen_page.dart +++ b/lib/widgets/fullscreen/fullscreen_page.dart @@ -5,6 +5,8 @@ import 'package:aves/widgets/fullscreen/fullscreen_body.dart'; import 'package:flutter/material.dart'; class MultiFullscreenPage extends AnimatedWidget { + static const routeName = '/fullscreen'; + final CollectionLens collection; final ImageEntry initialEntry; @@ -30,6 +32,8 @@ class MultiFullscreenPage extends AnimatedWidget { } class SingleFullscreenPage extends StatelessWidget { + static const routeName = '/fullscreen'; + final ImageEntry entry; const SingleFullscreenPage({ diff --git a/lib/widgets/fullscreen/overlay/top.dart b/lib/widgets/fullscreen/overlay/top.dart index e46490484..ab648cc10 100644 --- a/lib/widgets/fullscreen/overlay/top.dart +++ b/lib/widgets/fullscreen/overlay/top.dart @@ -126,7 +126,7 @@ class _TopOverlayRow extends StatelessWidget { children: [ OverlayButton( scale: scale, - child: ModalRoute.of(context)?.canPop ?? true ? BackButton() : CloseButton(), + child: Navigator.canPop(context) ? BackButton() : CloseButton(), ), Spacer(), ...quickActions.map(_buildOverlayButton), diff --git a/lib/widgets/home_page.dart b/lib/widgets/home_page.dart index 732aa78a0..f80382a47 100644 --- a/lib/widgets/home_page.dart +++ b/lib/widgets/home_page.dart @@ -7,7 +7,7 @@ import 'package:aves/services/viewer_service.dart'; import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/common/data_providers/media_store_collection_provider.dart'; -import 'package:aves/widgets/common/icons.dart'; +import 'package:aves/widgets/common/routes.dart'; import 'package:aves/widgets/filter_grids/albums_page.dart'; import 'package:aves/widgets/fullscreen/fullscreen_page.dart'; import 'package:flutter/material.dart'; @@ -17,6 +17,8 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:screen/screen.dart'; class HomePage extends StatefulWidget { + static const routeName = '/'; + const HomePage(); @override @@ -26,16 +28,18 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { MediaStoreSource _mediaStore; ImageEntry _viewerEntry; - Future _appSetup; @override void initState() { super.initState(); - _appSetup = _setup(); + _setup(); imageCache.maximumSizeBytes = 512 * (1 << 20); Screen.keepOn(true); } + @override + Widget build(BuildContext context) => Scaffold(); + Future _setup() async { final permissions = await [ Permission.storage, @@ -80,6 +84,8 @@ class _HomePageState extends State { await _mediaStore.init(); unawaited(_mediaStore.refresh()); } + + unawaited(Navigator.pushReplacement(context, _getRedirectRoute())); } Future _initViewerEntry({@required String uri, @required String mimeType}) async { @@ -92,30 +98,36 @@ class _HomePageState extends State { return entry; } - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: _appSetup, - builder: (context, snapshot) { - if (snapshot.hasError) return Icon(AIcons.error); - if (snapshot.connectionState != ConnectionState.done) return Scaffold(); - if (AvesApp.mode == AppMode.view) { - return SingleFullscreenPage(entry: _viewerEntry); + Route _getRedirectRoute() { + switch (AvesApp.mode) { + case AppMode.view: + return DirectMaterialPageRoute( + settings: RouteSettings(name: SingleFullscreenPage.routeName), + builder: (_) => SingleFullscreenPage(entry: _viewerEntry), + ); + case AppMode.main: + case AppMode.pick: + if (_mediaStore != null) { + switch (settings.homePage) { + case HomePageSetting.albums: + return DirectMaterialPageRoute( + settings: RouteSettings(name: AlbumListPage.routeName), + builder: (_) => AlbumListPage(source: _mediaStore), + ); + case HomePageSetting.collection: + return DirectMaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), + builder: (_) => CollectionPage( + CollectionLens( + source: _mediaStore, + groupFactor: settings.collectionGroupFactor, + sortFactor: settings.collectionSortFactor, + ), + ), + ); } - if (_mediaStore != null) { - switch (settings.homePage) { - case HomePageSetting.albums: - return AlbumListPage(source: _mediaStore); - break; - case HomePageSetting.collection: - return CollectionPage(CollectionLens( - source: _mediaStore, - groupFactor: settings.collectionGroupFactor, - sortFactor: settings.collectionSortFactor, - )); - } - } - return SizedBox.shrink(); - }); + } + } + return null; } } diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 0866c6cae..4962b7ff0 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -7,6 +7,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class SettingsPage extends StatelessWidget { + static const routeName = '/settings'; + @override Widget build(BuildContext context) { return MediaQueryDataProvider( diff --git a/lib/widgets/stats/filter_table.dart b/lib/widgets/stats/filter_table.dart index 1646c06ec..6db934778 100644 --- a/lib/widgets/stats/filter_table.dart +++ b/lib/widgets/stats/filter_table.dart @@ -90,6 +90,7 @@ class FilterTable extends StatelessWidget { Navigator.pushAndRemoveUntil( context, MaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), builder: (context) => CollectionPage(collection.derive(filter)), ), (route) => false, diff --git a/lib/widgets/stats/stats.dart b/lib/widgets/stats/stats.dart index df58d04ac..d4db446c5 100644 --- a/lib/widgets/stats/stats.dart +++ b/lib/widgets/stats/stats.dart @@ -20,6 +20,8 @@ import 'package:intl/intl.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; class StatsPage extends StatelessWidget { + static const routeName = '/collection/stats'; + final CollectionLens collection; final Map entryCountPerCountry = {}, entryCountPerPlace = {}, entryCountPerTag = {}; @@ -236,6 +238,7 @@ class StatsPage extends StatelessWidget { Navigator.pushAndRemoveUntil( context, MaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), builder: (context) => CollectionPage(collection.derive(filter)), ), (route) => false, diff --git a/lib/widgets/welcome_page.dart b/lib/widgets/welcome_page.dart index 04a853983..4dcdb23f9 100644 --- a/lib/widgets/welcome_page.dart +++ b/lib/widgets/welcome_page.dart @@ -107,6 +107,7 @@ class _WelcomePageState extends State { Navigator.pushAndRemoveUntil( context, MaterialPageRoute( + settings: RouteSettings(name: HomePage.routeName), builder: (context) => HomePage(), ), (route) => false, diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index cc1c6cb94..c826681b1 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -56,7 +56,7 @@ void agreeToTerms() { await driver.tap(find.byValueKey('continue-button')); await driver.waitUntilNoTransientCallbacks(); - expect(await driver.getText(find.byValueKey('appbar-title')), 'Aves'); + expect(await driver.getText(find.byValueKey('appbar-title')), 'Collection'); }); } From 80644f036b6294ddfabf0ea9129d8dc0f089c3c1 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 3 Sep 2020 13:39:42 +0900 Subject: [PATCH 3/9] apply album list page settings to move/copy album selection page --- .../selection_action_delegate.dart | 3 +- lib/widgets/filter_grids/albums_page.dart | 86 ++++++++++--------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/lib/widgets/common/action_delegates/selection_action_delegate.dart b/lib/widgets/common/action_delegates/selection_action_delegate.dart index b3bf36570..b58772ebe 100644 --- a/lib/widgets/common/action_delegates/selection_action_delegate.dart +++ b/lib/widgets/common/action_delegates/selection_action_delegate.dart @@ -17,6 +17,7 @@ import 'package:aves/widgets/common/action_delegates/permission_aware.dart'; import 'package:aves/widgets/common/aves_dialog.dart'; import 'package:aves/widgets/common/entry_actions.dart'; import 'package:aves/widgets/common/icons.dart'; +import 'package:aves/widgets/filter_grids/albums_page.dart'; import 'package:aves/widgets/filter_grids/filter_grid_page.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -89,7 +90,7 @@ class SelectionActionDelegate with FeedbackMixin, PermissionAwareMixin { ], floating: true, ), - filterEntries: source.getAlbumEntries(), + filterEntries: AlbumListPage.getAlbumEntries(source), filterBuilder: (s) => AlbumFilter(s, source.getUniqueAlbumName(s)), emptyBuilder: () => EmptyContent( icon: AIcons.album, diff --git a/lib/widgets/filter_grids/albums_page.dart b/lib/widgets/filter_grids/albums_page.dart index ec6b817b6..0c6cd486e 100644 --- a/lib/widgets/filter_grids/albums_page.dart +++ b/lib/widgets/filter_grids/albums_page.dart @@ -37,7 +37,7 @@ class AlbumListPage extends StatelessWidget { source: source, title: 'Albums', actions: _buildActions(), - filterEntries: _getAlbumEntries(), + filterEntries: getAlbumEntries(source), filterBuilder: (s) => AlbumFilter(s, source.getUniqueAlbumName(s)), emptyBuilder: () => EmptyContent( icon: AIcons.album, @@ -51,47 +51,6 @@ class AlbumListPage extends StatelessWidget { ); } - Map _getAlbumEntries() { - final entriesByDate = source.sortedEntriesForFilterList; - final albumEntries = source.sortedAlbums.map((album) { - return MapEntry( - album, - entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null), - ); - }).toList(); - - switch (settings.albumSortFactor) { - case ChipSortFactor.date: - albumEntries.sort((a, b) { - final c = b.value.bestDate?.compareTo(a.value.bestDate) ?? -1; - return c != 0 ? c : compareAsciiUpperCase(a.key, b.key); - }); - return Map.fromEntries(albumEntries); - case ChipSortFactor.name: - default: - final regularAlbums = [], appAlbums = [], specialAlbums = []; - for (var album in source.sortedAlbums) { - switch (androidFileUtils.getAlbumType(album)) { - case AlbumType.regular: - regularAlbums.add(album); - break; - case AlbumType.app: - appAlbums.add(album); - break; - default: - specialAlbums.add(album); - break; - } - } - return Map.fromEntries([...specialAlbums, ...appAlbums, ...regularAlbums].map((album) { - return MapEntry( - album, - entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null), - ); - })); - } - } - List _buildActions() { return [ Builder( @@ -134,4 +93,47 @@ class AlbumListPage extends StatelessWidget { break; } } + + // common with album selection page to move/copy entries + + static Map getAlbumEntries(CollectionSource source) { + final entriesByDate = source.sortedEntriesForFilterList; + final albumEntries = source.sortedAlbums.map((album) { + return MapEntry( + album, + entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null), + ); + }).toList(); + + switch (settings.albumSortFactor) { + case ChipSortFactor.date: + albumEntries.sort((a, b) { + final c = b.value.bestDate?.compareTo(a.value.bestDate) ?? -1; + return c != 0 ? c : compareAsciiUpperCase(a.key, b.key); + }); + return Map.fromEntries(albumEntries); + case ChipSortFactor.name: + default: + final regularAlbums = [], appAlbums = [], specialAlbums = []; + for (var album in source.sortedAlbums) { + switch (androidFileUtils.getAlbumType(album)) { + case AlbumType.regular: + regularAlbums.add(album); + break; + case AlbumType.app: + appAlbums.add(album); + break; + default: + specialAlbums.add(album); + break; + } + } + return Map.fromEntries([...specialAlbums, ...appAlbums, ...regularAlbums].map((album) { + return MapEntry( + album, + entriesByDate.firstWhere((entry) => entry.directory == album, orElse: () => null), + ); + })); + } + } } From ad397f0afcf4bffd8ac05b720a89ca1f345db3b6 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 3 Sep 2020 20:35:07 +0900 Subject: [PATCH 4/9] refactored drawer --- lib/widgets/album/collection_page.dart | 2 +- lib/widgets/app_drawer.dart | 328 ------------------ lib/widgets/drawer/app_drawer.dart | 228 ++++++++++++ lib/widgets/drawer/collection_tile.dart | 56 +++ lib/widgets/drawer/tile.dart | 56 +++ .../filter_grids/filter_grid_page.dart | 2 +- test_driver/app_test.dart | 2 +- 7 files changed, 343 insertions(+), 331 deletions(-) delete mode 100644 lib/widgets/app_drawer.dart create mode 100644 lib/widgets/drawer/app_drawer.dart create mode 100644 lib/widgets/drawer/collection_tile.dart create mode 100644 lib/widgets/drawer/tile.dart diff --git a/lib/widgets/album/collection_page.dart b/lib/widgets/album/collection_page.dart index 05a2dafbf..8be4a541e 100644 --- a/lib/widgets/album/collection_page.dart +++ b/lib/widgets/album/collection_page.dart @@ -1,8 +1,8 @@ import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/widgets/album/thumbnail_collection.dart'; -import 'package:aves/widgets/app_drawer.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:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; diff --git a/lib/widgets/app_drawer.dart b/lib/widgets/app_drawer.dart deleted file mode 100644 index 47ccdccc5..000000000 --- a/lib/widgets/app_drawer.dart +++ /dev/null @@ -1,328 +0,0 @@ -import 'dart:ui'; - -import 'package:aves/model/filters/album.dart'; -import 'package:aves/model/filters/favourite.dart'; -import 'package:aves/model/filters/filters.dart'; -import 'package:aves/model/filters/mime.dart'; -import 'package:aves/model/mime_types.dart'; -import 'package:aves/model/settings.dart'; -import 'package:aves/model/source/album.dart'; -import 'package:aves/model/source/collection_lens.dart'; -import 'package:aves/model/source/collection_source.dart'; -import 'package:aves/model/source/location.dart'; -import 'package:aves/model/source/tag.dart'; -import 'package:aves/utils/android_file_utils.dart'; -import 'package:aves/utils/flutter_utils.dart'; -import 'package:aves/widgets/about/about_page.dart'; -import 'package:aves/widgets/album/collection_page.dart'; -import 'package:aves/widgets/common/aves_logo.dart'; -import 'package:aves/widgets/common/icons.dart'; -import 'package:aves/widgets/debug_page.dart'; -import 'package:aves/widgets/filter_grids/albums_page.dart'; -import 'package:aves/widgets/filter_grids/countries_page.dart'; -import 'package:aves/widgets/filter_grids/tags_page.dart'; -import 'package:aves/widgets/settings/settings_page.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; - -class AppDrawer extends StatefulWidget { - final CollectionSource source; - - const AppDrawer({@required this.source}); - - @override - _AppDrawerState createState() => _AppDrawerState(); -} - -class _AppDrawerState extends State { - CollectionSource get source => widget.source; - - @override - Widget build(BuildContext context) { - final header = Container( - decoration: BoxDecoration( - border: Border( - bottom: Divider.createBorderSide(context), - ), - ), - child: Container( - padding: EdgeInsets.all(16), - color: Theme.of(context).accentColor, - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Align( - alignment: AlignmentDirectional.centerStart, - child: Wrap( - spacing: 16, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - AvesLogo(size: 64), - Text( - 'Aves', - style: TextStyle( - fontSize: 44, - fontFamily: 'Concourse Caps', - ), - ), - ], - ), - ), - ], - ), - ), - ), - ); - - final allCollectionEntry = _FilteredCollectionNavTile( - source: source, - leading: Icon(AIcons.allCollection), - title: 'All collection', - filter: null, - ); - final videoEntry = _FilteredCollectionNavTile( - source: source, - leading: Icon(AIcons.video), - title: 'Videos', - filter: MimeFilter(MimeTypes.anyVideo), - ); - final favouriteEntry = _FilteredCollectionNavTile( - source: source, - leading: Icon(AIcons.favourite), - title: 'Favourites', - filter: FavouriteFilter(), - ); - final settingsEntry = SafeArea( - top: false, - bottom: false, - child: ListTile( - leading: Icon(AIcons.settings), - title: Text('Preferences'), - onTap: () => _goTo(SettingsPage.routeName, (_) => SettingsPage()), - ), - ); - final aboutEntry = SafeArea( - top: false, - bottom: false, - child: ListTile( - leading: Icon(AIcons.info), - title: Text('About'), - onTap: () => _goTo(AboutPage.routeName, (_) => AboutPage()), - ), - ); - - final drawerItems = [ - header, - allCollectionEntry, - videoEntry, - favouriteEntry, - _buildSpecialAlbumSection(), - Divider(), - _buildAlbumListEntry(), - _buildCountryListEntry(), - _buildTagListEntry(), - Divider(), - settingsEntry, - aboutEntry, - if (kDebugMode) ...[ - Divider(), - SafeArea( - top: false, - bottom: false, - child: ListTile( - leading: Icon(AIcons.debug), - title: Text('Debug'), - onTap: () => _goTo(DebugPage.routeName, (_) => DebugPage(source: source)), - ), - ), - ], - ]; - - return Drawer( - child: Selector( - selector: (c, mq) => mq.viewInsets.bottom, - builder: (c, mqViewInsetsBottom, child) { - return SingleChildScrollView( - padding: EdgeInsets.only(bottom: mqViewInsetsBottom), - child: Theme( - data: Theme.of(context).copyWith( - // color used by `ExpansionTile` for leading icon - unselectedWidgetColor: Colors.white, - ), - child: Column( - children: drawerItems, - ), - ), - ); - }, - ), - ); - } - - Widget _buildAlbumEntry(String album, {bool dense = true}) { - final uniqueName = source.getUniqueAlbumName(album); - return _FilteredCollectionNavTile( - source: source, - leading: IconUtils.getAlbumIcon(context: context, album: album), - title: uniqueName, - trailing: androidFileUtils.isOnRemovableStorage(album) - ? Icon( - AIcons.removableStorage, - size: 16, - color: Colors.grey, - ) - : null, - dense: dense, - filter: AlbumFilter(album, uniqueName), - ); - } - - Widget _buildSpecialAlbumSection() { - return StreamBuilder( - stream: source.eventBus.on(), - builder: (context, snapshot) { - final specialAlbums = source.sortedAlbums.where((album) { - final type = androidFileUtils.getAlbumType(album); - return [AlbumType.camera, AlbumType.screenshots].contains(type); - }); - - if (specialAlbums.isEmpty) return SizedBox.shrink(); - return Column( - children: [ - Divider(), - ...specialAlbums.map((album) => _buildAlbumEntry(album, dense: false)), - ], - ); - }); - } - - Widget _buildAlbumListEntry() { - return SafeArea( - top: false, - bottom: false, - child: ListTile( - key: Key('albums-tile'), - leading: Icon(AIcons.album), - title: Text('Albums'), - trailing: StreamBuilder( - stream: source.eventBus.on(), - builder: (context, snapshot) { - return Text( - '${source.sortedAlbums.length}', - style: TextStyle( - color: Colors.white.withOpacity(.6), - ), - ); - }), - onTap: () => _goTo(AlbumListPage.routeName, (_) => AlbumListPage(source: source)), - ), - ); - } - - Widget _buildCountryListEntry() { - return SafeArea( - top: false, - bottom: false, - child: ListTile( - leading: Icon(AIcons.location), - title: Text('Countries'), - trailing: StreamBuilder( - stream: source.eventBus.on(), - builder: (context, snapshot) { - return Text( - '${source.sortedCountries.length}', - style: TextStyle( - color: Colors.white.withOpacity(.6), - ), - ); - }), - onTap: () => _goTo(CountryListPage.routeName, (_) => CountryListPage(source: source)), - ), - ); - } - - Widget _buildTagListEntry() { - return SafeArea( - top: false, - bottom: false, - child: ListTile( - leading: Icon(AIcons.tag), - title: Text('Tags'), - trailing: StreamBuilder( - stream: source.eventBus.on(), - builder: (context, snapshot) { - return Text( - '${source.sortedTags.length}', - style: TextStyle( - color: Colors.white.withOpacity(.6), - ), - ); - }), - onTap: () => _goTo(TagListPage.routeName, (_) => TagListPage(source: source)), - ), - ); - } - - void _goTo(String routeName, WidgetBuilder builder) { - Navigator.pop(context); - if (routeName != context.currentRouteName) { - Navigator.push( - context, - MaterialPageRoute( - settings: RouteSettings(name: routeName), - builder: builder, - )); - } - } -} - -class _FilteredCollectionNavTile extends StatelessWidget { - final CollectionSource source; - final Widget leading; - final String title; - final Widget trailing; - final bool dense; - final CollectionFilter filter; - - const _FilteredCollectionNavTile({ - @required this.source, - @required this.leading, - @required this.title, - this.trailing, - bool dense, - @required this.filter, - }) : dense = dense ?? false; - - @override - Widget build(BuildContext context) { - return SafeArea( - top: false, - bottom: false, - child: ListTile( - leading: leading, - title: Text(title), - trailing: trailing, - dense: dense, - onTap: () => _goToCollection(context), - ), - ); - } - - void _goToCollection(BuildContext context) { - Navigator.pushAndRemoveUntil( - context, - MaterialPageRoute( - settings: RouteSettings(name: CollectionPage.routeName), - builder: (context) => CollectionPage(CollectionLens( - source: source, - filters: [filter], - groupFactor: settings.collectionGroupFactor, - sortFactor: settings.collectionSortFactor, - )), - ), - (route) => false, - ); - } -} diff --git a/lib/widgets/drawer/app_drawer.dart b/lib/widgets/drawer/app_drawer.dart new file mode 100644 index 000000000..54eb6d4fd --- /dev/null +++ b/lib/widgets/drawer/app_drawer.dart @@ -0,0 +1,228 @@ +import 'dart:ui'; + +import 'package:aves/model/filters/album.dart'; +import 'package:aves/model/filters/favourite.dart'; +import 'package:aves/model/filters/mime.dart'; +import 'package:aves/model/mime_types.dart'; +import 'package:aves/model/source/album.dart'; +import 'package:aves/model/source/collection_source.dart'; +import 'package:aves/model/source/location.dart'; +import 'package:aves/model/source/tag.dart'; +import 'package:aves/utils/android_file_utils.dart'; +import 'package:aves/widgets/about/about_page.dart'; +import 'package:aves/widgets/common/aves_logo.dart'; +import 'package:aves/widgets/common/icons.dart'; +import 'package:aves/widgets/debug_page.dart'; +import 'package:aves/widgets/drawer/collection_tile.dart'; +import 'package:aves/widgets/drawer/tile.dart'; +import 'package:aves/widgets/filter_grids/albums_page.dart'; +import 'package:aves/widgets/filter_grids/countries_page.dart'; +import 'package:aves/widgets/filter_grids/tags_page.dart'; +import 'package:aves/widgets/settings/settings_page.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +class AppDrawer extends StatefulWidget { + final CollectionSource source; + + const AppDrawer({@required this.source}); + + @override + _AppDrawerState createState() => _AppDrawerState(); +} + +class _AppDrawerState extends State { + CollectionSource get source => widget.source; + + @override + Widget build(BuildContext context) { + final header = Container( + decoration: BoxDecoration( + border: Border( + bottom: Divider.createBorderSide(context), + ), + ), + child: Container( + padding: EdgeInsets.all(16), + color: Theme.of(context).accentColor, + child: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Align( + alignment: AlignmentDirectional.centerStart, + child: Wrap( + spacing: 16, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + AvesLogo(size: 64), + Text( + 'Aves', + style: TextStyle( + fontSize: 44, + fontFamily: 'Concourse Caps', + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + + final drawerItems = [ + header, + allCollectionTile, + videoTile, + favouriteTile, + _buildSpecialAlbumSection(), + Divider(), + albumListTile, + countryListTile, + tagListTile, + Divider(), + settingsTile, + aboutTile, + if (kDebugMode) ...[ + Divider(), + debugTile, + ], + ]; + + return Drawer( + child: Selector( + selector: (c, mq) => mq.viewInsets.bottom, + builder: (c, mqViewInsetsBottom, child) { + return SingleChildScrollView( + padding: EdgeInsets.only(bottom: mqViewInsetsBottom), + child: Theme( + data: Theme.of(context).copyWith( + // color used by `ExpansionTile` for leading icon + unselectedWidgetColor: Colors.white, + ), + child: Column( + children: drawerItems, + ), + ), + ); + }, + ), + ); + } + + Widget _buildAlbumTile(String album) { + final uniqueName = source.getUniqueAlbumName(album); + return CollectionNavTile( + source: source, + leading: IconUtils.getAlbumIcon(context: context, album: album), + title: uniqueName, + trailing: androidFileUtils.isOnRemovableStorage(album) + ? Icon( + AIcons.removableStorage, + size: 16, + color: Colors.grey, + ) + : null, + filter: AlbumFilter(album, uniqueName), + ); + } + + Widget _buildSpecialAlbumSection() { + return StreamBuilder( + stream: source.eventBus.on(), + builder: (context, snapshot) { + final specialAlbums = source.sortedAlbums.where((album) { + final type = androidFileUtils.getAlbumType(album); + return [AlbumType.camera, AlbumType.screenshots].contains(type); + }); + + if (specialAlbums.isEmpty) return SizedBox.shrink(); + return Column( + children: [ + Divider(), + ...specialAlbums.map(_buildAlbumTile), + ], + ); + }); + } + + // tiles + + Widget get allCollectionTile => CollectionNavTile( + source: source, + leading: Icon(AIcons.allCollection), + title: 'All collection', + filter: null, + ); + + Widget get videoTile => CollectionNavTile( + source: source, + leading: Icon(AIcons.video), + title: 'Videos', + filter: MimeFilter(MimeTypes.anyVideo), + ); + + Widget get favouriteTile => CollectionNavTile( + source: source, + leading: Icon(AIcons.favourite), + title: 'Favourites', + filter: FavouriteFilter(), + ); + + Widget get albumListTile => NavTile( + icon: AIcons.album, + title: 'Albums', + trailing: StreamBuilder( + stream: source.eventBus.on(), + builder: (context, _) => Text('${source.sortedAlbums.length}'), + ), + routeName: AlbumListPage.routeName, + pageBuilder: (_) => AlbumListPage(source: source), + ); + + Widget get countryListTile => NavTile( + icon: AIcons.location, + title: 'Countries', + trailing: StreamBuilder( + stream: source.eventBus.on(), + builder: (context, _) => Text('${source.sortedCountries.length}'), + ), + routeName: CountryListPage.routeName, + pageBuilder: (_) => CountryListPage(source: source), + ); + + Widget get tagListTile => NavTile( + icon: AIcons.tag, + title: 'Tags', + trailing: StreamBuilder( + stream: source.eventBus.on(), + builder: (context, _) => Text('${source.sortedTags.length}'), + ), + routeName: TagListPage.routeName, + pageBuilder: (_) => TagListPage(source: source), + ); + + Widget get settingsTile => NavTile( + icon: AIcons.settings, + title: 'Preferences', + routeName: SettingsPage.routeName, + pageBuilder: (_) => SettingsPage(), + ); + + Widget get aboutTile => NavTile( + icon: AIcons.info, + title: 'About', + routeName: AboutPage.routeName, + pageBuilder: (_) => AboutPage(), + ); + + Widget get debugTile => NavTile( + icon: AIcons.debug, + title: 'Debug', + routeName: DebugPage.routeName, + pageBuilder: (_) => DebugPage(source: source), + ); +} diff --git a/lib/widgets/drawer/collection_tile.dart b/lib/widgets/drawer/collection_tile.dart new file mode 100644 index 000000000..cd9d739cb --- /dev/null +++ b/lib/widgets/drawer/collection_tile.dart @@ -0,0 +1,56 @@ +import 'package:aves/model/filters/filters.dart'; +import 'package:aves/model/settings.dart'; +import 'package:aves/model/source/collection_lens.dart'; +import 'package:aves/model/source/collection_source.dart'; +import 'package:aves/widgets/album/collection_page.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class CollectionNavTile extends StatelessWidget { + final CollectionSource source; + final Widget leading; + final String title; + final Widget trailing; + final bool dense; + final CollectionFilter filter; + + const CollectionNavTile({ + @required this.source, + @required this.leading, + @required this.title, + this.trailing, + bool dense, + @required this.filter, + }) : dense = dense ?? false; + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + bottom: false, + child: ListTile( + leading: leading, + title: Text(title), + trailing: trailing, + dense: dense, + onTap: () => _goToCollection(context), + ), + ); + } + + void _goToCollection(BuildContext context) { + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + settings: RouteSettings(name: CollectionPage.routeName), + builder: (context) => CollectionPage(CollectionLens( + source: source, + filters: [filter], + groupFactor: settings.collectionGroupFactor, + sortFactor: settings.collectionSortFactor, + )), + ), + (route) => false, + ); + } +} diff --git a/lib/widgets/drawer/tile.dart b/lib/widgets/drawer/tile.dart new file mode 100644 index 000000000..4b51362bd --- /dev/null +++ b/lib/widgets/drawer/tile.dart @@ -0,0 +1,56 @@ +import 'dart:ui'; + +import 'package:aves/utils/flutter_utils.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class NavTile extends StatelessWidget { + final IconData icon; + final String title; + final Widget trailing; + final String routeName; + final WidgetBuilder pageBuilder; + + const NavTile({ + @required this.icon, + @required this.title, + this.trailing, + @required this.routeName, + @required this.pageBuilder, + }); + + @override + Widget build(BuildContext context) { + return SafeArea( + top: false, + bottom: false, + child: ListTile( + key: Key('$title-tile'), + leading: Icon(icon), + title: Text(title), + trailing: trailing != null + ? Builder( + builder: (context) => DefaultTextStyle.merge( + style: TextStyle( + color: IconTheme.of(context).color.withOpacity(.6), + ), + child: trailing, + ), + ) + : null, + onTap: () { + Navigator.pop(context); + if (routeName != context.currentRouteName) { + Navigator.push( + context, + MaterialPageRoute( + settings: RouteSettings(name: routeName), + builder: pageBuilder, + )); + } + }, + selected: context.currentRouteName == routeName, + ), + ); + } +} diff --git a/lib/widgets/filter_grids/filter_grid_page.dart b/lib/widgets/filter_grids/filter_grid_page.dart index 72663f830..c526562dc 100644 --- a/lib/widgets/filter_grids/filter_grid_page.dart +++ b/lib/widgets/filter_grids/filter_grid_page.dart @@ -7,10 +7,10 @@ import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/utils/durations.dart'; import 'package:aves/widgets/album/collection_page.dart'; -import 'package:aves/widgets/app_drawer.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/drawer/app_drawer.dart'; import 'package:aves/widgets/filter_grids/decorated_filter_chip.dart'; import 'package:flutter/material.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; diff --git a/test_driver/app_test.dart b/test_driver/app_test.dart index c826681b1..d096e431a 100644 --- a/test_driver/app_test.dart +++ b/test_driver/app_test.dart @@ -91,7 +91,7 @@ void selectFirstAlbum() { await driver.tap(find.byValueKey('appbar-leading-button')); await driver.waitUntilNoTransientCallbacks(); - await driver.tap(find.byValueKey('albums-tile')); + await driver.tap(find.byValueKey('Albums-tile')); await driver.waitUntilNoTransientCallbacks(); await driver.tap(find.descendant( From da26ccdc873c27be06515516fb4a9fb13f4003df Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 3 Sep 2020 20:45:17 +0900 Subject: [PATCH 5/9] changed settings dir structure --- lib/main.dart | 2 +- lib/model/settings/coordinate_format.dart | 28 +++++++++++ lib/model/settings/home_page.dart | 28 +++++++++++ lib/model/{ => settings}/settings.dart | 47 ++----------------- lib/model/source/collection_lens.dart | 2 +- lib/widgets/album/app_bar.dart | 2 +- .../album/grid/tile_extent_manager.dart | 2 +- lib/widgets/album/thumbnail/vector.dart | 2 +- .../media_store_collection_provider.dart | 2 +- .../data_providers/settings_provider.dart | 2 +- lib/widgets/common/double_back_pop.dart | 2 +- lib/widgets/debug_page.dart | 2 +- lib/widgets/drawer/collection_tile.dart | 2 +- lib/widgets/filter_grids/albums_page.dart | 2 +- .../filter_grids/filter_grid_page.dart | 2 +- lib/widgets/fullscreen/image_view.dart | 2 +- .../fullscreen/info/location_section.dart | 3 +- lib/widgets/fullscreen/info/maps/common.dart | 2 +- .../fullscreen/info/maps/google_map.dart | 2 +- .../fullscreen/info/maps/leaflet_map.dart | 2 +- lib/widgets/fullscreen/overlay/bottom.dart | 3 +- lib/widgets/home_page.dart | 3 +- lib/widgets/settings/settings_page.dart | 4 +- lib/widgets/settings/svg_background.dart | 2 +- lib/widgets/welcome_page.dart | 2 +- 25 files changed, 86 insertions(+), 66 deletions(-) create mode 100644 lib/model/settings/coordinate_format.dart create mode 100644 lib/model/settings/home_page.dart rename lib/model/{ => settings}/settings.dart (83%) diff --git a/lib/main.dart b/lib/main.dart index ed07ea752..ed627f0e8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/common/data_providers/settings_provider.dart'; import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/home_page.dart'; diff --git a/lib/model/settings/coordinate_format.dart b/lib/model/settings/coordinate_format.dart new file mode 100644 index 000000000..be88e0ca1 --- /dev/null +++ b/lib/model/settings/coordinate_format.dart @@ -0,0 +1,28 @@ +import 'package:aves/utils/geo_utils.dart'; +import 'package:tuple/tuple.dart'; + +enum CoordinateFormat { dms, decimal } + +extension ExtraCoordinateFormat on CoordinateFormat { + String get name { + switch (this) { + case CoordinateFormat.dms: + return 'DMS'; + case CoordinateFormat.decimal: + return 'Decimal degrees'; + default: + return toString(); + } + } + + String format(Tuple2 latLng) { + switch (this) { + case CoordinateFormat.dms: + return toDMS(latLng).join(', '); + case CoordinateFormat.decimal: + return [latLng.item1, latLng.item2].map((n) => n.toStringAsFixed(6)).join(', '); + default: + return toString(); + } + } +} diff --git a/lib/model/settings/home_page.dart b/lib/model/settings/home_page.dart new file mode 100644 index 000000000..9cb131bbf --- /dev/null +++ b/lib/model/settings/home_page.dart @@ -0,0 +1,28 @@ +import 'package:aves/widgets/album/collection_page.dart'; +import 'package:aves/widgets/filter_grids/albums_page.dart'; + +enum HomePageSetting { collection, albums } + +extension ExtraHomePageSetting on HomePageSetting { + String get name { + switch (this) { + case HomePageSetting.collection: + return 'Collection'; + case HomePageSetting.albums: + return 'Albums'; + default: + return toString(); + } + } + + String get routeName { + switch (this) { + case HomePageSetting.collection: + return CollectionPage.routeName; + case HomePageSetting.albums: + return AlbumListPage.routeName; + default: + return toString(); + } + } +} diff --git a/lib/model/settings.dart b/lib/model/settings/settings.dart similarity index 83% rename from lib/model/settings.dart rename to lib/model/settings/settings.dart index d5c644a51..c0eff5b5c 100644 --- a/lib/model/settings.dart +++ b/lib/model/settings/settings.dart @@ -1,11 +1,11 @@ -import 'package:aves/utils/geo_utils.dart'; +import 'package:aves/model/settings/coordinate_format.dart'; +import 'package:aves/model/settings/home_page.dart'; import 'package:aves/widgets/fullscreen/info/location_section.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tuple/tuple.dart'; -import 'source/enums.dart'; +import '../source/enums.dart'; final Settings settings = Settings._private(); @@ -148,44 +148,3 @@ class Settings extends ChangeNotifier { } } } - -enum HomePageSetting { collection, albums } - -extension ExtraHomePageSetting on HomePageSetting { - String get name { - switch (this) { - case HomePageSetting.collection: - return 'Collection'; - case HomePageSetting.albums: - return 'Albums'; - default: - return toString(); - } - } -} - -enum CoordinateFormat { dms, decimal } - -extension ExtraCoordinateFormat on CoordinateFormat { - String get name { - switch (this) { - case CoordinateFormat.dms: - return 'DMS'; - case CoordinateFormat.decimal: - return 'Decimal degrees'; - default: - return toString(); - } - } - - String format(Tuple2 latLng) { - switch (this) { - case CoordinateFormat.dms: - return toDMS(latLng).join(', '); - case CoordinateFormat.decimal: - return [latLng.item1, latLng.item2].map((n) => n.toStringAsFixed(6)).join(', '); - default: - return toString(); - } - } -} diff --git a/lib/model/source/collection_lens.dart b/lib/model/source/collection_lens.dart index 0b0849833..85361c504 100644 --- a/lib/model/source/collection_lens.dart +++ b/lib/model/source/collection_lens.dart @@ -4,7 +4,7 @@ import 'dart:collection'; import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/tag.dart'; import 'package:aves/utils/android_file_utils.dart'; diff --git a/lib/widgets/album/app_bar.dart b/lib/widgets/album/app_bar.dart index f55698bef..9c9aa5d88 100644 --- a/lib/widgets/album/app_bar.dart +++ b/lib/widgets/album/app_bar.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:aves/main.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/enums.dart'; import 'package:aves/utils/durations.dart'; diff --git a/lib/widgets/album/grid/tile_extent_manager.dart b/lib/widgets/album/grid/tile_extent_manager.dart index ff85ac095..5b920bde9 100644 --- a/lib/widgets/album/grid/tile_extent_manager.dart +++ b/lib/widgets/album/grid/tile_extent_manager.dart @@ -1,6 +1,6 @@ import 'dart:math'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:flutter/widgets.dart'; class TileExtentManager { diff --git a/lib/widgets/album/thumbnail/vector.dart b/lib/widgets/album/thumbnail/vector.dart index 47a658fb2..58f71609d 100644 --- a/lib/widgets/album/thumbnail/vector.dart +++ b/lib/widgets/album/thumbnail/vector.dart @@ -1,5 +1,5 @@ import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/common/image_providers/uri_picture_provider.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; diff --git a/lib/widgets/common/data_providers/media_store_collection_provider.dart b/lib/widgets/common/data_providers/media_store_collection_provider.dart index a2ecb86e1..46188e218 100644 --- a/lib/widgets/common/data_providers/media_store_collection_provider.dart +++ b/lib/widgets/common/data_providers/media_store_collection_provider.dart @@ -3,7 +3,7 @@ import 'dart:math'; import 'package:aves/model/favourite_repo.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/metadata_db.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/services/image_file_service.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/common/data_providers/settings_provider.dart b/lib/widgets/common/data_providers/settings_provider.dart index f5295c26c..a47b5329b 100644 --- a/lib/widgets/common/data_providers/settings_provider.dart +++ b/lib/widgets/common/data_providers/settings_provider.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:flutter/widgets.dart'; import 'package:provider/provider.dart'; diff --git a/lib/widgets/common/double_back_pop.dart b/lib/widgets/common/double_back_pop.dart index 583a9563f..b24b75834 100644 --- a/lib/widgets/common/double_back_pop.dart +++ b/lib/widgets/common/double_back_pop.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/utils/durations.dart'; import 'package:aves/widgets/common/action_delegates/feedback.dart'; import 'package:flutter/foundation.dart'; diff --git a/lib/widgets/debug_page.dart b/lib/widgets/debug_page.dart index e770d2cf8..575fa727a 100644 --- a/lib/widgets/debug_page.dart +++ b/lib/widgets/debug_page.dart @@ -4,7 +4,7 @@ import 'package:aves/model/favourite_repo.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_metadata.dart'; import 'package:aves/model/metadata_db.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/services/android_app_service.dart'; import 'package:aves/services/image_file_service.dart'; diff --git a/lib/widgets/drawer/collection_tile.dart b/lib/widgets/drawer/collection_tile.dart index cd9d739cb..89f7c9429 100644 --- a/lib/widgets/drawer/collection_tile.dart +++ b/lib/widgets/drawer/collection_tile.dart @@ -1,5 +1,5 @@ import 'package:aves/model/filters/filters.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/widgets/album/collection_page.dart'; diff --git a/lib/widgets/filter_grids/albums_page.dart b/lib/widgets/filter_grids/albums_page.dart index 0c6cd486e..c2b3d34b8 100644 --- a/lib/widgets/filter_grids/albums_page.dart +++ b/lib/widgets/filter_grids/albums_page.dart @@ -1,6 +1,6 @@ import 'package:aves/model/filters/album.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/album.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/model/source/enums.dart'; diff --git a/lib/widgets/filter_grids/filter_grid_page.dart b/lib/widgets/filter_grids/filter_grid_page.dart index c526562dc..a64e4d7fb 100644 --- a/lib/widgets/filter_grids/filter_grid_page.dart +++ b/lib/widgets/filter_grids/filter_grid_page.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:aves/model/filters/filters.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_source.dart'; import 'package:aves/utils/durations.dart'; diff --git a/lib/widgets/fullscreen/image_view.dart b/lib/widgets/fullscreen/image_view.dart index eef223a91..15b94d533 100644 --- a/lib/widgets/fullscreen/image_view.dart +++ b/lib/widgets/fullscreen/image_view.dart @@ -1,5 +1,5 @@ import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/album/empty.dart'; import 'package:aves/widgets/common/icons.dart'; import 'package:aves/widgets/common/image_providers/thumbnail_provider.dart'; diff --git a/lib/widgets/fullscreen/info/location_section.dart b/lib/widgets/fullscreen/info/location_section.dart index d1cc15d2f..70ce9abf6 100644 --- a/lib/widgets/fullscreen/info/location_section.dart +++ b/lib/widgets/fullscreen/info/location_section.dart @@ -1,6 +1,7 @@ import 'package:aves/model/filters/location.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/coordinate_format.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/widgets/common/aves_filter_chip.dart'; import 'package:aves/widgets/common/icons.dart'; diff --git a/lib/widgets/fullscreen/info/maps/common.dart b/lib/widgets/fullscreen/info/maps/common.dart index 7cbb51131..a1e24be9e 100644 --- a/lib/widgets/fullscreen/info/maps/common.dart +++ b/lib/widgets/fullscreen/info/maps/common.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/services/android_app_service.dart'; import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/borders.dart'; diff --git a/lib/widgets/fullscreen/info/maps/google_map.dart b/lib/widgets/fullscreen/info/maps/google_map.dart index 6b83f0362..1480e1085 100644 --- a/lib/widgets/fullscreen/info/maps/google_map.dart +++ b/lib/widgets/fullscreen/info/maps/google_map.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/fullscreen/info/location_section.dart'; import 'package:aves/widgets/fullscreen/info/maps/common.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/fullscreen/info/maps/leaflet_map.dart b/lib/widgets/fullscreen/info/maps/leaflet_map.dart index 2a06df8dc..570a71511 100644 --- a/lib/widgets/fullscreen/info/maps/leaflet_map.dart +++ b/lib/widgets/fullscreen/info/maps/leaflet_map.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/fullscreen/info/maps/common.dart'; import 'package:aves/widgets/fullscreen/info/maps/scale_layer.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/fullscreen/overlay/bottom.dart b/lib/widgets/fullscreen/overlay/bottom.dart index 506385831..51933c597 100644 --- a/lib/widgets/fullscreen/overlay/bottom.dart +++ b/lib/widgets/fullscreen/overlay/bottom.dart @@ -3,7 +3,8 @@ import 'dart:ui'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_metadata.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/coordinate_format.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/services/metadata_service.dart'; import 'package:aves/utils/constants.dart'; import 'package:aves/widgets/common/fx/blurred.dart'; diff --git a/lib/widgets/home_page.dart b/lib/widgets/home_page.dart index f80382a47..a2181ee51 100644 --- a/lib/widgets/home_page.dart +++ b/lib/widgets/home_page.dart @@ -1,6 +1,7 @@ import 'package:aves/main.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/home_page.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/services/image_file_service.dart'; import 'package:aves/services/viewer_service.dart'; diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 4962b7ff0..0bd009cac 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -1,4 +1,6 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/coordinate_format.dart'; +import 'package:aves/model/settings/home_page.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/common/aves_selection_dialog.dart'; import 'package:aves/widgets/common/data_providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/highlight_title.dart'; diff --git a/lib/widgets/settings/svg_background.dart b/lib/widgets/settings/svg_background.dart index fc2497b3d..b022a2671 100644 --- a/lib/widgets/settings/svg_background.dart +++ b/lib/widgets/settings/svg_background.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/widgets/common/borders.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/welcome_page.dart b/lib/widgets/welcome_page.dart index 4dcdb23f9..e719d7909 100644 --- a/lib/widgets/welcome_page.dart +++ b/lib/widgets/welcome_page.dart @@ -1,4 +1,4 @@ -import 'package:aves/model/settings.dart'; +import 'package:aves/model/settings/settings.dart'; import 'package:aves/utils/durations.dart'; import 'package:aves/widgets/common/aves_logo.dart'; import 'package:aves/widgets/common/labeled_checkbox.dart'; From 751f2fcacc1a170b2908cc014e13e24d5beeecf6 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 4 Sep 2020 22:01:11 +0900 Subject: [PATCH 6/9] always keep home as the first route in navigator stack, apply double back exit policy to filter grid pages --- lib/model/settings/settings.dart | 8 ++ lib/widgets/common/double_back_pop.dart | 2 +- lib/widgets/drawer/collection_tile.dart | 3 +- lib/widgets/drawer/tile.dart | 15 ++- .../filter_grids/filter_grid_page.dart | 117 +++++++++--------- lib/widgets/fullscreen/fullscreen_body.dart | 3 +- lib/widgets/stats/filter_table.dart | 3 +- lib/widgets/stats/stats.dart | 3 +- lib/widgets/welcome_page.dart | 3 +- 9 files changed, 87 insertions(+), 70 deletions(-) diff --git a/lib/model/settings/settings.dart b/lib/model/settings/settings.dart index c0eff5b5c..03ee79fbf 100644 --- a/lib/model/settings/settings.dart +++ b/lib/model/settings/settings.dart @@ -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 diff --git a/lib/widgets/common/double_back_pop.dart b/lib/widgets/common/double_back_pop.dart index b24b75834..dda008461 100644 --- a/lib/widgets/common/double_back_pop.dart +++ b/lib/widgets/common/double_back_pop.dart @@ -32,7 +32,7 @@ class _DoubleBackPopScopeState extends State 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); diff --git a/lib/widgets/drawer/collection_tile.dart b/lib/widgets/drawer/collection_tile.dart index 89f7c9429..2acada773 100644 --- a/lib/widgets/drawer/collection_tile.dart +++ b/lib/widgets/drawer/collection_tile.dart @@ -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), ); } } diff --git a/lib/widgets/drawer/tile.dart b/lib/widgets/drawer/tile.dart index 4b51362bd..6ac50d08b 100644 --- a/lib/widgets/drawer/tile.dart +++ b/lib/widgets/drawer/tile.dart @@ -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, diff --git a/lib/widgets/filter_grids/filter_grid_page.dart b/lib/widgets/filter_grids/filter_grid_page.dart index a64e4d7fb..4c198d059 100644 --- a/lib/widgets/filter_grids/filter_grid_page.dart +++ b/lib/widgets/filter_grids/filter_grid_page.dart @@ -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( - 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( + 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( - selector: (context, mq) => mq.viewInsets.bottom, - builder: (context, mqViewInsetsBottom, child) { - return SizedBox(height: mqViewInsetsBottom); - }, + SliverToBoxAdapter( + child: Selector( + selector: (context, mq) => mq.viewInsets.bottom, + builder: (context, mqViewInsetsBottom, child) { + return SizedBox(height: mqViewInsetsBottom); + }, + ), ), - ), - ], - ), - ); - }, + ], + ), + ); + }, + ), ), ), drawer: AppDrawer( diff --git a/lib/widgets/fullscreen/fullscreen_body.dart b/lib/widgets/fullscreen/fullscreen_body.dart index 0e5113c0a..81e29e9d0 100644 --- a/lib/widgets/fullscreen/fullscreen_body.dart +++ b/lib/widgets/fullscreen/fullscreen_body.dart @@ -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 with SingleTickerProvide settings: RouteSettings(name: CollectionPage.routeName), builder: (context) => CollectionPage(collection.derive(filter)), ), - (route) => false, + settings.navRemoveRoutePredicate(CollectionPage.routeName), ); } diff --git a/lib/widgets/stats/filter_table.dart b/lib/widgets/stats/filter_table.dart index 6db934778..ec3fb536c 100644 --- a/lib/widgets/stats/filter_table.dart +++ b/lib/widgets/stats/filter_table.dart @@ -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), ); } } diff --git a/lib/widgets/stats/stats.dart b/lib/widgets/stats/stats.dart index d4db446c5..2370e7261 100644 --- a/lib/widgets/stats/stats.dart +++ b/lib/widgets/stats/stats.dart @@ -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), ); } } diff --git a/lib/widgets/welcome_page.dart b/lib/widgets/welcome_page.dart index e719d7909..b1e1cc4e6 100644 --- a/lib/widgets/welcome_page.dart +++ b/lib/widgets/welcome_page.dart @@ -104,13 +104,12 @@ class _WelcomePageState extends State { onPressed: _hasAcceptedTerms ? () { settings.hasAcceptedTerms = true; - Navigator.pushAndRemoveUntil( + Navigator.pushReplacement( context, MaterialPageRoute( settings: RouteSettings(name: HomePage.routeName), builder: (context) => HomePage(), ), - (route) => false, ); } : null, From 48606a9e39bfbfa5475ba5bab360fd76b6b80409 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 4 Sep 2020 22:10:30 +0900 Subject: [PATCH 7/9] apply directly when tapping option in selection dialogs --- lib/widgets/common/aves_selection_dialog.dart | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/widgets/common/aves_selection_dialog.dart b/lib/widgets/common/aves_selection_dialog.dart index 4165183ba..a681e8df7 100644 --- a/lib/widgets/common/aves_selection_dialog.dart +++ b/lib/widgets/common/aves_selection_dialog.dart @@ -37,11 +37,6 @@ class _AvesSelectionDialogState extends State { onPressed: () => Navigator.pop(context), child: Text('Cancel'.toUpperCase()), ), - FlatButton( - key: Key('apply-button'), - onPressed: () => Navigator.pop(context, _selectedValue), - child: Text('Apply'.toUpperCase()), - ), ], ); } @@ -50,7 +45,11 @@ class _AvesSelectionDialogState extends State { key: Key(value.toString()), value: value, groupValue: _selectedValue, - onChanged: (v) => setState(() => _selectedValue = v), + onChanged: (v) { + _selectedValue = v; + Navigator.pop(context, _selectedValue); + setState(() {}); + }, title: Text( title, softWrap: false, From 68ce71e6d1ebcb53d78f50eba69fc7d6bd1b6f54 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 4 Sep 2020 22:10:49 +0900 Subject: [PATCH 8/9] changed settings page name --- lib/widgets/drawer/app_drawer.dart | 2 +- lib/widgets/settings/settings_page.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/widgets/drawer/app_drawer.dart b/lib/widgets/drawer/app_drawer.dart index 54eb6d4fd..aaa1088ab 100644 --- a/lib/widgets/drawer/app_drawer.dart +++ b/lib/widgets/drawer/app_drawer.dart @@ -207,7 +207,7 @@ class _AppDrawerState extends State { Widget get settingsTile => NavTile( icon: AIcons.settings, - title: 'Preferences', + title: 'Settings', routeName: SettingsPage.routeName, pageBuilder: (_) => SettingsPage(), ); diff --git a/lib/widgets/settings/settings_page.dart b/lib/widgets/settings/settings_page.dart index 0bd009cac..d58633709 100644 --- a/lib/widgets/settings/settings_page.dart +++ b/lib/widgets/settings/settings_page.dart @@ -18,7 +18,7 @@ class SettingsPage extends StatelessWidget { length: 4, child: Scaffold( appBar: AppBar( - title: Text('Preferences'), + title: Text('Settings'), ), body: SafeArea( child: Consumer( From bcb32cd91986ae8d569571c0607059b99ed4bc12 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Fri, 4 Sep 2020 22:13:47 +0900 Subject: [PATCH 9/9] version bump --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 14a2061d3..f5c521fa7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.1.8+20 +version: 1.1.9+21 # video_player (as of v0.10.8+2, backed by ExoPlayer): # - does not support content URIs (by default, but trivial by fork)