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);
}
bool get initialized => false;
Future<void> init();
Future<void> refresh();

View file

@ -13,6 +13,11 @@ import 'package:flutter_native_timezone/flutter_native_timezone.dart';
import 'package:pedantic/pedantic.dart';
class MediaStoreSource extends CollectionSource {
bool _initialized = false;
@override
bool get initialized => _initialized;
@override
Future<void> init() async {
final stopwatch = Stopwatch()..start();
@ -29,6 +34,7 @@ class MediaStoreSource extends CollectionSource {
settings.catalogTimeZone = currentTimeZone;
}
await loadDates(); // 100ms for 5400 entries
_initialized = true;
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/filters/album.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';
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/icons.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/dialogs/create_album_dialog.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:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
class AlbumPickPage extends StatefulWidget {
static const routeName = '/album_pick';
@ -39,32 +45,36 @@ class _AlbumPickPageState extends State<AlbumPickPage> {
@override
Widget build(BuildContext context) {
Widget appBar = AlbumPickAppBar(
source: source,
moveType: widget.moveType,
actionDelegate: AlbumChipSetActionDelegate(source: source),
queryNotifier: _queryNotifier,
);
return Selector<Settings, ChipSortFactor>(
selector: (context, s) => s.albumSortFactor,
builder: (context, sortFactor, child) {
return FilterGridPage<AlbumFilter>(
source: source,
appBar: appBar,
filterSections: AlbumListPage.getAlbumEntries(source),
showHeaders: settings.albumGroupFactor != AlbumChipGroupFactor.none,
applyQuery: (filters, query) {
if (query == null || query.isEmpty) return filters;
query = query.toUpperCase();
return filters.where((item) => item.filter.uniqueName.toUpperCase().contains(query)).toList();
},
queryNotifier: _queryNotifier,
emptyBuilder: () => EmptyContent(
icon: AIcons.album,
text: 'No albums',
return Selector<Settings, Tuple2<AlbumChipGroupFactor, ChipSortFactor>>(
selector: (context, s) => Tuple2(s.albumGroupFactor, s.albumSortFactor),
builder: (context, s, child) {
return StreamBuilder(
stream: source.eventBus.on<AlbumsChangedEvent>(),
builder: (context, snapshot) => FilterGridPage<AlbumFilter>(
source: source,
appBar: appBar,
filterSections: AlbumListPage.getAlbumEntries(source),
showHeaders: settings.albumGroupFactor != AlbumChipGroupFactor.none,
applyQuery: (filters, query) {
if (query == null || query.isEmpty) return filters;
query = query.toUpperCase();
return filters.where((item) => item.filter.uniqueName.toUpperCase().contains(query)).toList();
},
queryNotifier: _queryNotifier,
emptyBuilder: () => EmptyContent(
icon: AIcons.album,
text: 'No albums',
),
settingsRouteKey: AlbumListPage.routeName,
appBarHeight: AlbumPickAppBar.preferredHeight,
onTap: (filter) => Navigator.pop<String>(context, (filter as AlbumFilter)?.album),
),
settingsRouteKey: AlbumListPage.routeName,
appBarHeight: AlbumPickAppBar.preferredHeight,
onTap: (filter) => Navigator.pop<String>(context, (filter as AlbumFilter)?.album),
);
},
);
@ -72,6 +82,7 @@ class _AlbumPickPageState extends State<AlbumPickPage> {
}
class AlbumPickAppBar extends StatelessWidget {
final CollectionSource source;
final MoveType moveType;
final AlbumChipSetActionDelegate actionDelegate;
final ValueNotifier<String> queryNotifier;
@ -79,6 +90,7 @@ class AlbumPickAppBar extends StatelessWidget {
static const preferredHeight = kToolbarHeight + AlbumFilterBar.preferredHeight;
const AlbumPickAppBar({
@required this.source,
@required this.moveType,
@required this.actionDelegate,
@required this.queryNotifier,
@ -101,7 +113,10 @@ class AlbumPickAppBar extends StatelessWidget {
return SliverAppBar(
leading: BackButton(),
title: Text(title()),
title: SourceStateAwareAppBarTitle(
title: Text(title()),
source: source,
),
bottom: AlbumFilterBar(
filterNotifier: queryNotifier,
),
@ -119,10 +134,23 @@ class AlbumPickAppBar extends StatelessWidget {
},
tooltip: 'Create album',
),
IconButton(
icon: Icon(AIcons.sort),
onPressed: () => actionDelegate.onActionSelected(context, ChipSetAction.sort),
tooltip: 'Sort…',
PopupMenuButton<ChipSetAction>(
itemBuilder: (context) {
return [
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,

View file

@ -92,7 +92,7 @@ class AlbumChipSetActionDelegate extends ChipSetActionDelegate {
builder: (context) => AvesSelectionDialog<AlbumChipGroupFactor>(
initialValue: settings.albumGroupFactor,
options: {
AlbumChipGroupFactor.importance: 'By importance',
AlbumChipGroupFactor.importance: 'By tier',
AlbumChipGroupFactor.volume: 'By storage volume',
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 {
final source = context.read<CollectionSource>();
if (!source.initialized) {
await source.init();
unawaited(source.refresh());
}
final destinationAlbum = await Navigator.push(
context,
MaterialPageRoute<String>(