app bar: show cataloguing/locating progress
This commit is contained in:
parent
755e75dc6a
commit
1be8853e63
4 changed files with 76 additions and 36 deletions
|
@ -116,7 +116,7 @@ class _HomePageState extends State<HomePage> {
|
||||||
|
|
||||||
Future<void> _initViewerEntry({@required String uri, @required String mimeType}) async {
|
Future<void> _initViewerEntry({@required String uri, @required String mimeType}) async {
|
||||||
_viewerEntry = await ImageFileService.getImageEntry(uri, mimeType);
|
_viewerEntry = await ImageFileService.getImageEntry(uri, mimeType);
|
||||||
// cataloging is essential for geolocation and video rotation
|
// cataloguing is essential for geolocation and video rotation
|
||||||
await _viewerEntry.catalog();
|
await _viewerEntry.catalog();
|
||||||
unawaited(_viewerEntry.locate());
|
unawaited(_viewerEntry.locate());
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,7 +250,7 @@ class CollectionSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SourceState { loading, cataloging, locating, ready }
|
enum SourceState { loading, cataloguing, locating, ready }
|
||||||
|
|
||||||
class AddressMetadataChangedEvent {}
|
class AddressMetadataChangedEvent {}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:async';
|
||||||
import 'package:aves/main.dart';
|
import 'package:aves/main.dart';
|
||||||
import 'package:aves/model/collection_lens.dart';
|
import 'package:aves/model/collection_lens.dart';
|
||||||
import 'package:aves/model/collection_source.dart';
|
import 'package:aves/model/collection_source.dart';
|
||||||
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/settings.dart';
|
import 'package:aves/model/settings.dart';
|
||||||
import 'package:aves/utils/constants.dart';
|
import 'package:aves/utils/constants.dart';
|
||||||
import 'package:aves/widgets/album/filter_bar.dart';
|
import 'package:aves/widgets/album/filter_bar.dart';
|
||||||
|
@ -135,23 +136,6 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
ValueListenableBuilder<SourceState>(
|
ValueListenableBuilder<SourceState>(
|
||||||
valueListenable: collection.source.stateNotifier,
|
valueListenable: collection.source.stateNotifier,
|
||||||
builder: (context, sourceState, child) {
|
builder: (context, sourceState, child) {
|
||||||
String subtitle;
|
|
||||||
switch (sourceState) {
|
|
||||||
case SourceState.loading:
|
|
||||||
subtitle = 'Loading';
|
|
||||||
break;
|
|
||||||
case SourceState.cataloging:
|
|
||||||
subtitle = 'Cataloging';
|
|
||||||
break;
|
|
||||||
case SourceState.locating:
|
|
||||||
subtitle = 'Locating';
|
|
||||||
break;
|
|
||||||
case SourceState.ready:
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
final subtitleStyle = Theme.of(context).textTheme.caption;
|
|
||||||
final progressIndicatorSize = subtitleStyle.fontSize;
|
|
||||||
return AnimatedSwitcher(
|
return AnimatedSwitcher(
|
||||||
duration: Duration(milliseconds: (300 * timeDilation).toInt()),
|
duration: Duration(milliseconds: (300 * timeDilation).toInt()),
|
||||||
transitionBuilder: (child, animation) => FadeTransition(
|
transitionBuilder: (child, animation) => FadeTransition(
|
||||||
|
@ -161,23 +145,10 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
sizeFactor: animation,
|
sizeFactor: animation,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: subtitle == null
|
child: sourceState == SourceState.ready
|
||||||
? const SizedBox.shrink()
|
? const SizedBox.shrink()
|
||||||
: Row(
|
: SourceStateSubtitle(
|
||||||
mainAxisSize: MainAxisSize.min,
|
source: collection.source,
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(1),
|
|
||||||
width: progressIndicatorSize,
|
|
||||||
height: progressIndicatorSize,
|
|
||||||
margin: const EdgeInsetsDirectional.only(end: 8),
|
|
||||||
child: const CircularProgressIndicator(strokeWidth: 1),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'$subtitle',
|
|
||||||
style: subtitleStyle,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -387,3 +358,72 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CollectionAction { copy, move, select, selectAll, selectNone, stats, groupByAlbum, groupByMonth, groupByDay, sortByDate, sortBySize, sortByName }
|
enum CollectionAction { copy, move, select, selectAll, selectNone, stats, groupByAlbum, groupByMonth, groupByDay, sortByDate, sortBySize, sortByName }
|
||||||
|
|
||||||
|
class SourceStateSubtitle extends StatefulWidget {
|
||||||
|
final CollectionSource source;
|
||||||
|
|
||||||
|
const SourceStateSubtitle({@required this.source});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SourceStateSubtitleState createState() => _SourceStateSubtitleState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SourceStateSubtitleState extends State<SourceStateSubtitle> {
|
||||||
|
Timer _progressTimer;
|
||||||
|
|
||||||
|
CollectionSource get source => widget.source;
|
||||||
|
|
||||||
|
SourceState get sourceState => source.stateNotifier.value;
|
||||||
|
|
||||||
|
List<ImageEntry> get entries => source.entries;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_progressTimer = Timer.periodic(const Duration(milliseconds: 1000), (timer) => setState(() {}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_progressTimer.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
String subtitle;
|
||||||
|
double progress;
|
||||||
|
switch (sourceState) {
|
||||||
|
case SourceState.loading:
|
||||||
|
subtitle = 'Loading';
|
||||||
|
break;
|
||||||
|
case SourceState.cataloguing:
|
||||||
|
subtitle = 'Cataloguing';
|
||||||
|
progress = entries.where((entry) => entry.isCatalogued).length.toDouble() / entries.length;
|
||||||
|
break;
|
||||||
|
case SourceState.locating:
|
||||||
|
subtitle = 'Locating';
|
||||||
|
progress = entries.where((entry) => entry.isLocated).length.toDouble() / entries.length;
|
||||||
|
break;
|
||||||
|
case SourceState.ready:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
final subtitleStyle = Theme.of(context).textTheme.caption;
|
||||||
|
return subtitle == null
|
||||||
|
? const SizedBox.shrink()
|
||||||
|
: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(subtitle, style: subtitleStyle),
|
||||||
|
if (progress != null && progress > 0) ...[
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
NumberFormat.percentPattern().format(progress),
|
||||||
|
style: subtitleStyle.copyWith(color: Colors.white30),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ class MediaStoreSource {
|
||||||
source.addAll(allEntries);
|
source.addAll(allEntries);
|
||||||
// TODO reduce setup time until here
|
// TODO reduce setup time until here
|
||||||
source.updateAlbums(); // <50ms
|
source.updateAlbums(); // <50ms
|
||||||
source.stateNotifier.value = SourceState.cataloging;
|
source.stateNotifier.value = SourceState.cataloguing;
|
||||||
await source.loadCatalogMetadata(); // 400ms for 5400 entries
|
await source.loadCatalogMetadata(); // 400ms for 5400 entries
|
||||||
await source.catalogEntries(); // <50ms
|
await source.catalogEntries(); // <50ms
|
||||||
source.stateNotifier.value = SourceState.locating;
|
source.stateNotifier.value = SourceState.locating;
|
||||||
|
|
Loading…
Reference in a new issue