mosaic: refresh layout on aspect ratio change

This commit is contained in:
Thibault Deckers 2022-10-02 11:43:53 +02:00
parent ba2c06f2ea
commit a80cbfa8f5
5 changed files with 77 additions and 47 deletions

View file

@ -26,7 +26,7 @@ import 'package:country_code/country_code.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:latlong2/latlong.dart'; import 'package:latlong2/latlong.dart';
enum EntryDataType { basic, catalog, address, references } enum EntryDataType { basic, aspectRatio, catalog, address, references }
class AvesEntry { class AvesEntry {
// `sizeBytes`, `dateModifiedSecs` can be missing in viewer mode // `sizeBytes`, `dateModifiedSecs` can be missing in viewer mode

View file

@ -126,6 +126,7 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
if (newFields.isNotEmpty) { if (newFields.isNotEmpty) {
dataTypes.addAll({ dataTypes.addAll({
EntryDataType.basic, EntryDataType.basic,
EntryDataType.aspectRatio,
EntryDataType.catalog, EntryDataType.catalog,
}); });
} }
@ -309,14 +310,18 @@ extension ExtraAvesEntryMetadataEdition on AvesEntry {
} }
Future<Set<EntryDataType>> removeMetadata(Set<MetadataType> types) async { Future<Set<EntryDataType>> removeMetadata(Set<MetadataType> types) async {
final Set<EntryDataType> dataTypes = {};
final newFields = await metadataEditService.removeTypes(this, types); final newFields = await metadataEditService.removeTypes(this, types);
return newFields.isEmpty if (newFields.isNotEmpty) {
? {} dataTypes.addAll({
: { EntryDataType.basic,
EntryDataType.basic, EntryDataType.aspectRatio,
EntryDataType.catalog, EntryDataType.catalog,
EntryDataType.address, EntryDataType.address,
}; });
}
return dataTypes;
} }
static void editIptcValues(List<Map<String, dynamic>> iptc, int record, int tag, Set<String> values) { static void editIptcValues(List<Map<String, dynamic>> iptc, int record, int tag, Set<String> values) {

View file

@ -395,16 +395,25 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
Future<void> refreshEntry(AvesEntry entry, Set<EntryDataType> dataTypes) async { Future<void> refreshEntry(AvesEntry entry, Set<EntryDataType> dataTypes) async {
await entry.refresh(background: false, persist: true, dataTypes: dataTypes, geocoderLocale: settings.appliedLocale); await entry.refresh(background: false, persist: true, dataTypes: dataTypes, geocoderLocale: settings.appliedLocale);
// update/delete in DB
final id = entry.id; final id = entry.id;
if (dataTypes.contains(EntryDataType.catalog)) { await Future.forEach(EntryDataType.values, (dataType) async {
await metadataDb.updateCatalogMetadata(id, entry.catalogMetadata); switch (dataType) {
onCatalogMetadataChanged(); case EntryDataType.aspectRatio:
} onAspectRatioChanged();
if (dataTypes.contains(EntryDataType.address)) { break;
await metadataDb.updateAddress(id, entry.addressDetails); case EntryDataType.catalog:
onAddressMetadataChanged(); await metadataDb.updateCatalogMetadata(id, entry.catalogMetadata);
} onCatalogMetadataChanged();
break;
case EntryDataType.address:
await metadataDb.updateAddress(id, entry.addressDetails);
onAddressMetadataChanged();
break;
case EntryDataType.basic:
case EntryDataType.references:
break;
}
});
updateDerivedFilters({entry}); updateDerivedFilters({entry});
eventBus.fire(EntryRefreshedEvent({entry})); eventBus.fire(EntryRefreshedEvent({entry}));
@ -449,6 +458,8 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
state = SourceState.ready; state = SourceState.ready;
} }
void onAspectRatioChanged() => eventBus.fire(AspectRatioChangedEvent());
// monitoring // monitoring
bool _monitoring = true; bool _monitoring = true;
@ -502,3 +513,5 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
} }
} }
} }
class AspectRatioChangedEvent {}

View file

@ -7,6 +7,7 @@ import 'package:aves/model/filters/favourite.dart';
import 'package:aves/model/filters/mime.dart'; import 'package:aves/model/filters/mime.dart';
import 'package:aves/model/settings/settings.dart'; import 'package:aves/model/settings/settings.dart';
import 'package:aves/model/source/collection_lens.dart'; import 'package:aves/model/source/collection_lens.dart';
import 'package:aves/model/source/collection_source.dart';
import 'package:aves/model/source/enums/enums.dart'; import 'package:aves/model/source/enums/enums.dart';
import 'package:aves/model/source/section_keys.dart'; import 'package:aves/model/source/section_keys.dart';
import 'package:aves/ref/mime_types.dart'; import 'package:aves/ref/mime_types.dart';
@ -117,12 +118,13 @@ class _CollectionGridContent extends StatelessWidget {
final columnCount = c.item2; final columnCount = c.item2;
final tileSpacing = c.item3; final tileSpacing = c.item3;
final horizontalPadding = c.item4; final horizontalPadding = c.item4;
final source = collection.source;
return GridTheme( return GridTheme(
extent: thumbnailExtent, extent: thumbnailExtent,
child: EntryListDetailsTheme( child: EntryListDetailsTheme(
extent: thumbnailExtent, extent: thumbnailExtent,
child: ValueListenableBuilder<SourceState>( child: ValueListenableBuilder<SourceState>(
valueListenable: collection.source.stateNotifier, valueListenable: source.stateNotifier,
builder: (context, sourceState, child) { builder: (context, sourceState, child) {
late final Duration tileAnimationDelay; late final Duration tileAnimationDelay;
if (sourceState == SourceState.ready) { if (sourceState == SourceState.ready) {
@ -132,33 +134,37 @@ class _CollectionGridContent extends StatelessWidget {
} else { } else {
tileAnimationDelay = Duration.zero; tileAnimationDelay = Duration.zero;
} }
return SectionedEntryListLayoutProvider(
collection: collection, return StreamBuilder(
selectable: selectable, stream: source.eventBus.on<AspectRatioChangedEvent>(),
scrollableWidth: scrollableWidth, builder: (context, snapshot) => SectionedEntryListLayoutProvider(
tileLayout: tileLayout, collection: collection,
columnCount: columnCount, selectable: selectable,
spacing: tileSpacing, scrollableWidth: scrollableWidth,
horizontalPadding: horizontalPadding, tileLayout: tileLayout,
tileExtent: thumbnailExtent, columnCount: columnCount,
tileBuilder: (entry, tileSize) { spacing: tileSpacing,
final extent = tileSize.shortestSide; horizontalPadding: horizontalPadding,
return AnimatedBuilder( tileExtent: thumbnailExtent,
animation: favourites, tileBuilder: (entry, tileSize) {
builder: (context, child) { final extent = tileSize.shortestSide;
return InteractiveTile( return AnimatedBuilder(
key: ValueKey(entry.id), animation: favourites,
collection: collection, builder: (context, child) {
entry: entry, return InteractiveTile(
thumbnailExtent: extent, key: ValueKey(entry.id),
tileLayout: tileLayout, collection: collection,
isScrollingNotifier: _isScrollingNotifier, entry: entry,
); thumbnailExtent: extent,
}, tileLayout: tileLayout,
); isScrollingNotifier: _isScrollingNotifier,
}, );
tileAnimationDelay: tileAnimationDelay, },
child: child!, );
},
tileAnimationDelay: tileAnimationDelay,
child: child!,
),
); );
}, },
child: child, child: child,

View file

@ -370,6 +370,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
Set<String> obsoleteTags = todoItems.expand((entry) => entry.tags).toSet(); Set<String> obsoleteTags = todoItems.expand((entry) => entry.tags).toSet();
Set<String> obsoleteCountryCodes = todoItems.where((entry) => entry.hasAddress).map((entry) => entry.addressDetails?.countryCode).whereNotNull().toSet(); Set<String> obsoleteCountryCodes = todoItems.where((entry) => entry.hasAddress).map((entry) => entry.addressDetails?.countryCode).whereNotNull().toSet();
final Set<EntryDataType> dataTypes = {};
final source = context.read<CollectionSource>(); final source = context.read<CollectionSource>();
source.pauseMonitoring(); source.pauseMonitoring();
var cancelled = false; var cancelled = false;
@ -379,8 +380,9 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
if (cancelled) { if (cancelled) {
return ImageOpEvent(success: true, skipped: true, uri: entry.uri); return ImageOpEvent(success: true, skipped: true, uri: entry.uri);
} else { } else {
final dataTypes = await op(entry); final opDataTypes = await op(entry);
return ImageOpEvent(success: dataTypes.isNotEmpty, skipped: false, uri: entry.uri); dataTypes.addAll(opDataTypes);
return ImageOpEvent(success: opDataTypes.isNotEmpty, skipped: false, uri: entry.uri);
} }
}).asBroadcastStream(), }).asBroadcastStream(),
itemCount: todoCount, itemCount: todoCount,
@ -402,6 +404,10 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware
} }
})); }));
if (dataTypes.contains(EntryDataType.aspectRatio)) {
source.onAspectRatioChanged();
}
if (showResult) { if (showResult) {
final l10n = context.l10n; final l10n = context.l10n;
final successCount = successOps.length; final successCount = successOps.length;