From 4ea985b8f8f5b75aadcab421466597bff766bcc3 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Thu, 26 Mar 2020 10:56:02 +0900 Subject: [PATCH] drawer on all pages --- lib/main.dart | 29 ++- lib/model/collection_lens.dart | 2 +- ..._page.dart => all_collection_app_bar.dart} | 70 ++------ ...ion_drawer.dart => collection_drawer.dart} | 167 +++++++++--------- ...lection_page.dart => collection_page.dart} | 48 ++--- lib/widgets/common/aves_logo.dart | 23 +++ lib/widgets/debug_page.dart | 7 +- .../fullscreen/info/location_section.dart | 7 +- lib/widgets/fullscreen/info/xmp_section.dart | 9 +- 9 files changed, 179 insertions(+), 183 deletions(-) rename lib/widgets/album/{all_collection_page.dart => all_collection_app_bar.dart} (68%) rename lib/widgets/album/{all_collection_drawer.dart => collection_drawer.dart} (71%) rename lib/widgets/album/{filtered_collection_page.dart => collection_page.dart} (61%) create mode 100644 lib/widgets/common/aves_logo.dart diff --git a/lib/main.dart b/lib/main.dart index 6d952ad9a..197be41ea 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,10 +1,10 @@ +import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_file_service.dart'; import 'package:aves/model/settings.dart'; import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/viewer_service.dart'; -import 'package:aves/widgets/album/all_collection_drawer.dart'; -import 'package:aves/widgets/album/all_collection_page.dart'; +import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; import 'package:aves/widgets/common/providers/media_store_collection_provider.dart'; import 'package:aves/widgets/fullscreen/fullscreen_page.dart'; @@ -13,6 +13,7 @@ import 'package:flutter/services.dart'; import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:pedantic/pedantic.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:provider/provider.dart'; import 'package:screen/screen.dart'; void main() { @@ -104,24 +105,14 @@ class _HomePageState extends State { ? SingleFullscreenPage( entry: _sharedEntry, ) - : const MediaStoreCollectionPage(); + : MediaStoreCollectionProvider( + child: Consumer( + builder: (context, collection, child) => CollectionPage( + collection: collection, + ), + ), + ); }), ); } } - -class MediaStoreCollectionPage extends StatelessWidget { - const MediaStoreCollectionPage(); - - @override - Widget build(BuildContext context) { - debugPrint('$runtimeType build'); - return const MediaStoreCollectionProvider( - child: Scaffold( - body: AllCollectionPage(), - drawer: AllCollectionDrawer(), - resizeToAvoidBottomInset: false, - ), - ); - } -} diff --git a/lib/model/collection_lens.dart b/lib/model/collection_lens.dart index ffc5befc5..02888c5f6 100644 --- a/lib/model/collection_lens.dart +++ b/lib/model/collection_lens.dart @@ -23,7 +23,7 @@ class CollectionLens with ChangeNotifier { List filters, GroupFactor groupFactor, SortFactor sortFactor, - }) : this.filters = filters ?? [], + }) : this.filters = [if (filters != null) ...filters.where((f) => f != null)], this.groupFactor = groupFactor ?? GroupFactor.month, this.sortFactor = sortFactor ?? SortFactor.date { _subscriptions.add(source.eventBus.on().listen((e) => onEntryAdded())); diff --git a/lib/widgets/album/all_collection_page.dart b/lib/widgets/album/all_collection_app_bar.dart similarity index 68% rename from lib/widgets/album/all_collection_page.dart rename to lib/widgets/album/all_collection_app_bar.dart index a44184ced..13d24dedc 100644 --- a/lib/widgets/album/all_collection_page.dart +++ b/lib/widgets/album/all_collection_app_bar.dart @@ -1,29 +1,15 @@ import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/settings.dart'; import 'package:aves/widgets/album/search_delegate.dart'; -import 'package:aves/widgets/album/thumbnail_collection.dart'; import 'package:aves/widgets/common/menu_row.dart'; -import 'package:aves/widgets/debug_page.dart'; import 'package:aves/widgets/stats.dart'; import 'package:flutter/material.dart'; import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:pedantic/pedantic.dart'; import 'package:provider/provider.dart'; -class AllCollectionPage extends StatelessWidget { - const AllCollectionPage(); - - @override - Widget build(BuildContext context) { - debugPrint('$runtimeType build'); - return ThumbnailCollection( - appBar: _AllCollectionAppBar(), - ); - } -} - -class _AllCollectionAppBar extends SliverAppBar { - _AllCollectionAppBar() +class AllCollectionAppBar extends SliverAppBar { + AllCollectionAppBar() : super( title: const Text('All'), actions: _buildActions(), @@ -45,44 +31,40 @@ class _AllCollectionAppBar extends SliverAppBar { ), Builder( builder: (context) => Consumer( - builder: (context, collection, child) => PopupMenuButton( + builder: (context, collection, child) => PopupMenuButton( itemBuilder: (context) => [ PopupMenuItem( - value: AlbumAction.sortByDate, + value: CollectionAction.sortByDate, child: MenuRow(text: 'Sort by date', checked: collection.sortFactor == SortFactor.date), ), PopupMenuItem( - value: AlbumAction.sortBySize, + value: CollectionAction.sortBySize, child: MenuRow(text: 'Sort by size', checked: collection.sortFactor == SortFactor.size), ), PopupMenuItem( - value: AlbumAction.sortByName, + value: CollectionAction.sortByName, child: MenuRow(text: 'Sort by name', checked: collection.sortFactor == SortFactor.name), ), const PopupMenuDivider(), if (collection.sortFactor == SortFactor.date) ...[ PopupMenuItem( - value: AlbumAction.groupByAlbum, + value: CollectionAction.groupByAlbum, child: MenuRow(text: 'Group by album', checked: collection.groupFactor == GroupFactor.album), ), PopupMenuItem( - value: AlbumAction.groupByMonth, + value: CollectionAction.groupByMonth, child: MenuRow(text: 'Group by month', checked: collection.groupFactor == GroupFactor.month), ), PopupMenuItem( - value: AlbumAction.groupByDay, + value: CollectionAction.groupByDay, child: MenuRow(text: 'Group by day', checked: collection.groupFactor == GroupFactor.day), ), const PopupMenuDivider(), ], PopupMenuItem( - value: AlbumAction.stats, + value: CollectionAction.stats, child: MenuRow(text: 'Stats', icon: OMIcons.pieChart), ), - PopupMenuItem( - value: AlbumAction.debug, - child: MenuRow(text: 'Debug', icon: OMIcons.whatshot), - ), ], onSelected: (action) => _onActionSelected(context, collection, action), ), @@ -91,54 +73,40 @@ class _AllCollectionAppBar extends SliverAppBar { ]; } - static void _onActionSelected(BuildContext context, CollectionLens collection, AlbumAction action) async { + static void _onActionSelected(BuildContext context, CollectionLens collection, CollectionAction action) async { // wait for the popup menu to hide before proceeding with the action await Future.delayed(const Duration(milliseconds: 300)); switch (action) { - case AlbumAction.debug: - unawaited(_goToDebug(context, collection)); - break; - case AlbumAction.stats: + case CollectionAction.stats: unawaited(_goToStats(context, collection)); break; - case AlbumAction.groupByAlbum: + case CollectionAction.groupByAlbum: settings.collectionGroupFactor = GroupFactor.album; collection.group(GroupFactor.album); break; - case AlbumAction.groupByMonth: + case CollectionAction.groupByMonth: settings.collectionGroupFactor = GroupFactor.month; collection.group(GroupFactor.month); break; - case AlbumAction.groupByDay: + case CollectionAction.groupByDay: settings.collectionGroupFactor = GroupFactor.day; collection.group(GroupFactor.day); break; - case AlbumAction.sortByDate: + case CollectionAction.sortByDate: settings.collectionSortFactor = SortFactor.date; collection.sort(SortFactor.date); break; - case AlbumAction.sortBySize: + case CollectionAction.sortBySize: settings.collectionSortFactor = SortFactor.size; collection.sort(SortFactor.size); break; - case AlbumAction.sortByName: + case CollectionAction.sortByName: settings.collectionSortFactor = SortFactor.name; collection.sort(SortFactor.name); break; } } - static Future _goToDebug(BuildContext context, CollectionLens collection) { - return Navigator.push( - context, - MaterialPageRoute( - builder: (context) => DebugPage( - entries: collection.sortedEntries, - ), - ), - ); - } - static Future _goToStats(BuildContext context, CollectionLens collection) { return Navigator.push( context, @@ -151,4 +119,4 @@ class _AllCollectionAppBar extends SliverAppBar { } } -enum AlbumAction { debug, stats, groupByAlbum, groupByMonth, groupByDay, sortByDate, sortBySize, sortByName } +enum CollectionAction { stats, groupByAlbum, groupByMonth, groupByDay, sortByDate, sortBySize, sortByName } diff --git a/lib/widgets/album/all_collection_drawer.dart b/lib/widgets/album/collection_drawer.dart similarity index 71% rename from lib/widgets/album/all_collection_drawer.dart rename to lib/widgets/album/collection_drawer.dart index 667aa61b0..02ab1d338 100644 --- a/lib/widgets/album/all_collection_drawer.dart +++ b/lib/widgets/album/collection_drawer.dart @@ -5,108 +5,92 @@ import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/collection_source.dart'; import 'package:aves/utils/android_file_utils.dart'; import 'package:aves/utils/color_utils.dart'; -import 'package:aves/widgets/album/filtered_collection_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:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:provider/provider.dart'; -class AllCollectionDrawer extends StatefulWidget { - const AllCollectionDrawer(); +class CollectionDrawer extends StatefulWidget { + final CollectionSource source; + + const CollectionDrawer({@required this.source}); @override - _AllCollectionDrawerState createState() => _AllCollectionDrawerState(); + _CollectionDrawerState createState() => _CollectionDrawerState(); } -class _AllCollectionDrawerState extends State { +class _CollectionDrawerState extends State { bool _albumsExpanded = false, _tagsExpanded = false, _countriesExpanded = false; + CollectionSource get source => widget.source; + @override Widget build(BuildContext context) { - final collection = Provider.of(context); - final source = collection.source; - - final header = DrawerHeader( + final header = Container( decoration: BoxDecoration( - color: Theme.of(context).accentColor, + border: Border( + bottom: Divider.createBorderSide(context), + ), ), - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - CircleAvatar( - backgroundColor: Colors.white, - radius: 44, - child: Padding( - padding: const EdgeInsets.only(top: 6.0), - child: SvgPicture.asset( - 'assets/aves_logo.svg', - width: 64, + child: Container( + padding: const EdgeInsets.all(16), + color: Theme.of(context).accentColor, + child: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const AvesLogo(size: 64), + const SizedBox(width: 16), + const Text( + 'Aves', + style: TextStyle( + fontSize: 44, + fontFamily: 'Concourse Caps', ), ), - ), - const SizedBox(width: 16), - const Text( - 'Aves', - style: TextStyle( - fontSize: 44, - fontFamily: 'Concourse Caps', - ), - ), - ], - ), - const SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row(children: [ - const Icon(OMIcons.photoLibrary), - const SizedBox(width: 4), - Text('${collection.imageCount}'), - ]), - Row(children: [ - const Icon(OMIcons.videoLibrary), - const SizedBox(width: 4), - Text('${collection.videoCount}'), - ]), - Row(children: [ - const Icon(OMIcons.photoAlbum), - const SizedBox(width: 4), - Text('${source.albumCount}'), - ]), - ], - ), - ], + ], + ), + ], + ), ), ), ); + final allMediaEntry = _FilteredCollectionNavTile( + source: source, + leading: const Icon(OMIcons.photo), + title: 'All media', + filter: null, + ); + final videoEntry = _FilteredCollectionNavTile( + source: source, + leading: const Icon(OMIcons.movie), + title: 'Videos', + filter: VideoFilter(), + ); final gifEntry = _FilteredCollectionNavTile( - collection: collection, + source: source, leading: const Icon(OMIcons.gif), title: 'GIFs', filter: GifFilter(), ); - final videoEntry = _FilteredCollectionNavTile( - collection: collection, - leading: const Icon(OMIcons.videoLibrary), - title: 'Videos', - filter: VideoFilter(), - ); final buildAlbumEntry = (album) => _FilteredCollectionNavTile( - collection: collection, + source: source, leading: IconUtils.getAlbumIcon(context, album), title: CollectionSource.getUniqueAlbumName(album, source.sortedAlbums), dense: true, filter: AlbumFilter(album), ); final buildTagEntry = (tag) => _FilteredCollectionNavTile( - collection: collection, + source: source, leading: Icon( - OMIcons.label, + OMIcons.localOffer, color: stringToColor(tag), ), title: tag, @@ -114,7 +98,7 @@ class _AllCollectionDrawerState extends State { filter: TagFilter(tag), ); final buildCountryEntry = (country) => _FilteredCollectionNavTile( - collection: collection, + source: source, leading: Icon( OMIcons.place, color: stringToColor(country), @@ -141,10 +125,11 @@ class _AllCollectionDrawerState extends State { final countries = source.sortedCountries; final tags = source.sortedTags; - final drawerItems = [ + final drawerItems = [ header, - gifEntry, + allMediaEntry, videoEntry, + gifEntry, if (specialAlbums.isNotEmpty) ...[ const Divider(), ...specialAlbums.map(buildAlbumEntry), @@ -202,7 +187,7 @@ class _AllCollectionDrawerState extends State { top: false, bottom: false, child: ExpansionTile( - leading: const Icon(OMIcons.label), + leading: const Icon(OMIcons.localOffer), title: Row( children: [ const Text('Tags'), @@ -219,6 +204,28 @@ class _AllCollectionDrawerState extends State { children: tags.map(buildTagEntry).toList(), ), ), + if (kDebugMode) ...[ + const Divider(), + SafeArea( + top: false, + bottom: false, + child: ListTile( + leading: const Icon(OMIcons.whatshot), + title: const Text('Debug'), + onTap: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => DebugPage( + source: source, + ), + ), + ); + }, + ), + ), + ], ]; return Drawer( @@ -244,14 +251,14 @@ class _AllCollectionDrawerState extends State { } class _FilteredCollectionNavTile extends StatelessWidget { - final CollectionLens collection; + final CollectionSource source; final Widget leading; final String title; final bool dense; final CollectionFilter filter; const _FilteredCollectionNavTile({ - @required this.collection, + @required this.source, @required this.leading, @required this.title, bool dense, @@ -268,16 +275,18 @@ class _FilteredCollectionNavTile extends StatelessWidget { title: Text(title), dense: dense, onTap: () { - Navigator.pop(context); - Navigator.push( + Navigator.pushAndRemoveUntil( context, MaterialPageRoute( - builder: (context) => FilteredCollectionPage( - collection: collection, - filter: filter, + builder: (context) => CollectionPage( + collection: CollectionLens( + source: source, + filters: [filter], + ), title: title, ), ), + (route) => false, ); }, ), diff --git a/lib/widgets/album/filtered_collection_page.dart b/lib/widgets/album/collection_page.dart similarity index 61% rename from lib/widgets/album/filtered_collection_page.dart rename to lib/widgets/album/collection_page.dart index fb452a19e..9ad522030 100644 --- a/lib/widgets/album/filtered_collection_page.dart +++ b/lib/widgets/album/collection_page.dart @@ -1,6 +1,6 @@ -import 'package:aves/model/collection_filters.dart'; import 'package:aves/model/collection_lens.dart'; -import 'package:aves/widgets/album/all_collection_page.dart'; +import 'package:aves/widgets/album/all_collection_app_bar.dart'; +import 'package:aves/widgets/album/collection_drawer.dart'; import 'package:aves/widgets/album/thumbnail_collection.dart'; import 'package:aves/widgets/common/menu_row.dart'; import 'package:aves/widgets/common/providers/media_query_data_provider.dart'; @@ -9,30 +9,36 @@ import 'package:flutter/material.dart'; import 'package:outline_material_icons/outline_material_icons.dart'; import 'package:provider/provider.dart'; -class FilteredCollectionPage extends StatelessWidget { +class CollectionPage extends StatelessWidget { final CollectionLens collection; - final CollectionFilter filter; final String title; - FilteredCollectionPage({Key key, CollectionLens collection, this.filter, this.title}) - : this.collection = CollectionLens.from(collection, filter), - super(key: key); + const CollectionPage({ + Key key, + @required this.collection, + this.title, + }) : super(key: key); @override Widget build(BuildContext context) { return MediaQueryDataProvider( - child: Scaffold( - body: ChangeNotifierProvider.value( - value: collection, - child: ThumbnailCollection( - appBar: SliverAppBar( - title: Text(title), - actions: _buildActions(), - floating: true, - ), + child: ChangeNotifierProvider.value( + value: collection, + child: Scaffold( + body: ThumbnailCollection( + appBar: collection.filters.isEmpty + ? AllCollectionAppBar() + : SliverAppBar( + title: Text(title), + actions: _buildActions(), + floating: true, + ), ), + drawer: CollectionDrawer( + source: collection.source, + ), + resizeToAvoidBottomInset: false, ), - resizeToAvoidBottomInset: false, ), ); } @@ -41,10 +47,10 @@ class FilteredCollectionPage extends StatelessWidget { return [ Builder( builder: (context) => Consumer( - builder: (context, collection, child) => PopupMenuButton( + builder: (context, collection, child) => PopupMenuButton( itemBuilder: (context) => [ PopupMenuItem( - value: AlbumAction.stats, + value: CollectionAction.stats, child: MenuRow(text: 'Stats', icon: OMIcons.pieChart), ), ], @@ -55,9 +61,9 @@ class FilteredCollectionPage extends StatelessWidget { ]; } - static void _onActionSelected(BuildContext context, CollectionLens collection, AlbumAction action) { + static void _onActionSelected(BuildContext context, CollectionLens collection, CollectionAction action) { switch (action) { - case AlbumAction.stats: + case CollectionAction.stats: _goToStats(context, collection); break; default: diff --git a/lib/widgets/common/aves_logo.dart b/lib/widgets/common/aves_logo.dart new file mode 100644 index 000000000..a458013e9 --- /dev/null +++ b/lib/widgets/common/aves_logo.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +class AvesLogo extends StatelessWidget { + final double size; + + const AvesLogo({@required this.size}); + + @override + Widget build(BuildContext context) { + return CircleAvatar( + backgroundColor: Colors.white, + radius: size / 2, + child: Padding( + padding: EdgeInsets.only(top: size / 15), + child: SvgPicture.asset( + 'assets/aves_logo.svg', + width: size / 1.4, + ), + ), + ); + } +} diff --git a/lib/widgets/debug_page.dart b/lib/widgets/debug_page.dart index 4948dbbcd..f4b1e3d1e 100644 --- a/lib/widgets/debug_page.dart +++ b/lib/widgets/debug_page.dart @@ -1,3 +1,4 @@ +import 'package:aves/model/collection_source.dart'; import 'package:aves/model/image_entry.dart'; import 'package:aves/model/image_metadata.dart'; import 'package:aves/model/metadata_db.dart'; @@ -8,9 +9,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; class DebugPage extends StatefulWidget { - final List entries; + final CollectionSource source; - const DebugPage({this.entries}); + const DebugPage({this.source}); @override State createState() => DebugPageState(); @@ -21,7 +22,7 @@ class DebugPageState extends State { Future> _dbMetadataLoader; Future> _dbAddressLoader; - List get entries => widget.entries; + List get entries => widget.source.entries; @override void initState() { diff --git a/lib/widgets/fullscreen/info/location_section.dart b/lib/widgets/fullscreen/info/location_section.dart index dfea5439b..3d649e956 100644 --- a/lib/widgets/fullscreen/info/location_section.dart +++ b/lib/widgets/fullscreen/info/location_section.dart @@ -4,7 +4,7 @@ import 'package:aves/model/image_entry.dart'; import 'package:aves/model/settings.dart'; import 'package:aves/utils/android_app_service.dart'; import 'package:aves/utils/geo_utils.dart'; -import 'package:aves/widgets/album/filtered_collection_page.dart'; +import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart'; import 'package:aves/widgets/fullscreen/info/navigation_button.dart'; import 'package:flutter/material.dart'; @@ -130,9 +130,8 @@ class _LocationSectionState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => FilteredCollectionPage( - collection: collection, - filter: CountryFilter(country), + builder: (context) => CollectionPage( + collection: CollectionLens.from(collection, CountryFilter(country)), title: country, ), ), diff --git a/lib/widgets/fullscreen/info/xmp_section.dart b/lib/widgets/fullscreen/info/xmp_section.dart index 8bc0c8662..911fd907f 100644 --- a/lib/widgets/fullscreen/info/xmp_section.dart +++ b/lib/widgets/fullscreen/info/xmp_section.dart @@ -1,7 +1,7 @@ import 'package:aves/model/collection_filters.dart'; import 'package:aves/model/collection_lens.dart'; import 'package:aves/model/image_entry.dart'; -import 'package:aves/widgets/album/filtered_collection_page.dart'; +import 'package:aves/widgets/album/collection_page.dart'; import 'package:aves/widgets/fullscreen/info/info_page.dart'; import 'package:aves/widgets/fullscreen/info/navigation_button.dart'; import 'package:collection/collection.dart'; @@ -26,7 +26,7 @@ class XmpTagSectionSliver extends AnimatedWidget { tags.isEmpty ? [] : [ - const SectionRow(OMIcons.label), + const SectionRow(OMIcons.localOffer), Padding( padding: const EdgeInsets.symmetric(horizontal: NavigationButton.buttonBorderWidth / 2), child: Wrap( @@ -49,9 +49,8 @@ class XmpTagSectionSliver extends AnimatedWidget { Navigator.push( context, MaterialPageRoute( - builder: (context) => FilteredCollectionPage( - collection: collection, - filter: TagFilter(tag), + builder: (context) => CollectionPage( + collection: CollectionLens.from(collection, TagFilter(tag)), title: tag, ), ),