export: support view mode

This commit is contained in:
Thibault Deckers 2021-01-25 14:38:07 +09:00
parent 218db5d091
commit c332e125bb
5 changed files with 66 additions and 26 deletions

View file

@ -164,6 +164,8 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
return _filterEntryCountMap.putIfAbsent(filter, () => _rawEntries.where((entry) => filter.filter(entry)).length); return _filterEntryCountMap.putIfAbsent(filter, () => _rawEntries.where((entry) => filter.filter(entry)).length);
} }
bool get initialized => false;
Future<void> init(); Future<void> init();
Future<void> refresh(); Future<void> refresh();

View file

@ -13,6 +13,11 @@ import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:pedantic/pedantic.dart'; import 'package:pedantic/pedantic.dart';
class MediaStoreSource extends CollectionSource { class MediaStoreSource extends CollectionSource {
bool _initialized = false;
@override
bool get initialized => _initialized;
@override @override
Future<void> init() async { Future<void> init() async {
final stopwatch = Stopwatch()..start(); final stopwatch = Stopwatch()..start();
@ -29,6 +34,7 @@ class MediaStoreSource extends CollectionSource {
settings.catalogTimeZone = currentTimeZone; settings.catalogTimeZone = currentTimeZone;
} }
await loadDates(); // 100ms for 5400 entries await loadDates(); // 100ms for 5400 entries
_initialized = true;
debugPrint('$runtimeType init done, elapsed=${stopwatch.elapsed}'); debugPrint('$runtimeType init done, elapsed=${stopwatch.elapsed}');
} }

View file

@ -2,10 +2,14 @@ import 'package:aves/model/actions/chip_actions.dart';
import 'package:aves/model/actions/move_type.dart'; import 'package:aves/model/actions/move_type.dart';
import 'package:aves/model/filters/album.dart'; import 'package:aves/model/filters/album.dart';
import 'package:aves/model/settings/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/collection_source.dart';
import 'package:aves/model/source/enums.dart'; import 'package:aves/model/source/enums.dart';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.dart'; import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/collection/empty.dart'; import 'package:aves/widgets/collection/empty.dart';
import 'package:aves/widgets/common/app_bar_subtitle.dart';
import 'package:aves/widgets/common/basic/menu_row.dart';
import 'package:aves/widgets/common/basic/query_bar.dart'; import 'package:aves/widgets/common/basic/query_bar.dart';
import 'package:aves/widgets/dialogs/create_album_dialog.dart'; import 'package:aves/widgets/dialogs/create_album_dialog.dart';
import 'package:aves/widgets/filter_grids/albums_page.dart'; import 'package:aves/widgets/filter_grids/albums_page.dart';
@ -13,8 +17,10 @@ import 'package:aves/widgets/filter_grids/common/chip_set_action_delegate.dart';
import 'package:aves/widgets/filter_grids/common/filter_grid_page.dart'; import 'package:aves/widgets/filter_grids/common/filter_grid_page.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
class AlbumPickPage extends StatefulWidget { class AlbumPickPage extends StatefulWidget {
static const routeName = '/album_pick'; static const routeName = '/album_pick';
@ -39,15 +45,18 @@ class _AlbumPickPageState extends State<AlbumPickPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget appBar = AlbumPickAppBar( Widget appBar = AlbumPickAppBar(
source: source,
moveType: widget.moveType, moveType: widget.moveType,
actionDelegate: AlbumChipSetActionDelegate(source: source), actionDelegate: AlbumChipSetActionDelegate(source: source),
queryNotifier: _queryNotifier, queryNotifier: _queryNotifier,
); );
return Selector<Settings, ChipSortFactor>( return Selector<Settings, Tuple2<AlbumChipGroupFactor, ChipSortFactor>>(
selector: (context, s) => s.albumSortFactor, selector: (context, s) => Tuple2(s.albumGroupFactor, s.albumSortFactor),
builder: (context, sortFactor, child) { builder: (context, s, child) {
return FilterGridPage<AlbumFilter>( return StreamBuilder(
stream: source.eventBus.on<AlbumsChangedEvent>(),
builder: (context, snapshot) => FilterGridPage<AlbumFilter>(
source: source, source: source,
appBar: appBar, appBar: appBar,
filterSections: AlbumListPage.getAlbumEntries(source), filterSections: AlbumListPage.getAlbumEntries(source),
@ -65,6 +74,7 @@ class _AlbumPickPageState extends State<AlbumPickPage> {
settingsRouteKey: AlbumListPage.routeName, settingsRouteKey: AlbumListPage.routeName,
appBarHeight: AlbumPickAppBar.preferredHeight, appBarHeight: AlbumPickAppBar.preferredHeight,
onTap: (filter) => Navigator.pop<String>(context, (filter as AlbumFilter)?.album), onTap: (filter) => Navigator.pop<String>(context, (filter as AlbumFilter)?.album),
),
); );
}, },
); );
@ -72,6 +82,7 @@ class _AlbumPickPageState extends State<AlbumPickPage> {
} }
class AlbumPickAppBar extends StatelessWidget { class AlbumPickAppBar extends StatelessWidget {
final CollectionSource source;
final MoveType moveType; final MoveType moveType;
final AlbumChipSetActionDelegate actionDelegate; final AlbumChipSetActionDelegate actionDelegate;
final ValueNotifier<String> queryNotifier; final ValueNotifier<String> queryNotifier;
@ -79,6 +90,7 @@ class AlbumPickAppBar extends StatelessWidget {
static const preferredHeight = kToolbarHeight + AlbumFilterBar.preferredHeight; static const preferredHeight = kToolbarHeight + AlbumFilterBar.preferredHeight;
const AlbumPickAppBar({ const AlbumPickAppBar({
@required this.source,
@required this.moveType, @required this.moveType,
@required this.actionDelegate, @required this.actionDelegate,
@required this.queryNotifier, @required this.queryNotifier,
@ -101,7 +113,10 @@ class AlbumPickAppBar extends StatelessWidget {
return SliverAppBar( return SliverAppBar(
leading: BackButton(), leading: BackButton(),
title: SourceStateAwareAppBarTitle(
title: Text(title()), title: Text(title()),
source: source,
),
bottom: AlbumFilterBar( bottom: AlbumFilterBar(
filterNotifier: queryNotifier, filterNotifier: queryNotifier,
), ),
@ -119,10 +134,23 @@ class AlbumPickAppBar extends StatelessWidget {
}, },
tooltip: 'Create album', tooltip: 'Create album',
), ),
IconButton( PopupMenuButton<ChipSetAction>(
icon: Icon(AIcons.sort), itemBuilder: (context) {
onPressed: () => actionDelegate.onActionSelected(context, ChipSetAction.sort), return [
tooltip: 'Sort…', PopupMenuItem(
value: ChipSetAction.sort,
child: MenuRow(text: 'Sort…', icon: AIcons.sort),
),
PopupMenuItem(
value: ChipSetAction.group,
child: MenuRow(text: 'Group…', icon: AIcons.group),
),
];
},
onSelected: (action) {
// wait for the popup menu to hide before proceeding with the action
Future.delayed(Durations.popupMenuAnimation * timeDilation, () => actionDelegate.onActionSelected(context, action));
},
), ),
], ],
floating: true, floating: true,

View file

@ -92,7 +92,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate {
builder: (context) => AvesSelectionDialog<AlbumChipGroupFactor>( builder: (context) => AvesSelectionDialog<AlbumChipGroupFactor>(
initialValue: settings.albumGroupFactor, initialValue: settings.albumGroupFactor,
options: { options: {
AlbumChipGroupFactor.importance: 'By importance', AlbumChipGroupFactor.importance: 'By tier',
AlbumChipGroupFactor.volume: 'By storage volume', AlbumChipGroupFactor.volume: 'By storage volume',
AlbumChipGroupFactor.none: 'Do not group', AlbumChipGroupFactor.none: 'Do not group',
}, },

View file

@ -153,6 +153,10 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix
Future<void> _showExportDialog(BuildContext context, AvesEntry entry) async { Future<void> _showExportDialog(BuildContext context, AvesEntry entry) async {
final source = context.read<CollectionSource>(); final source = context.read<CollectionSource>();
if (!source.initialized) {
await source.init();
unawaited(source.refresh());
}
final destinationAlbum = await Navigator.push( final destinationAlbum = await Navigator.push(
context, context,
MaterialPageRoute<String>( MaterialPageRoute<String>(