various fixes

This commit is contained in:
Thibault Deckers 2022-01-05 13:33:43 +09:00
parent 1a17f9546c
commit 862a8003fa
7 changed files with 51 additions and 18 deletions

View file

@ -49,6 +49,7 @@ class RegionProvider extends ImageProvider<RegionProviderKey> {
}
return await decode(bytes);
} catch (error) {
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
throw StateError('$mimeType region decoding failed (page $pageId)');
}

View file

@ -50,7 +50,8 @@ class ThumbnailProvider extends ImageProvider<ThumbnailProviderKey> {
}
return await decode(bytes);
} catch (error) {
debugPrint('$runtimeType _loadAsync failed with uri=$uri, error=$error');
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
throw StateError('$mimeType decoding failed (page $pageId)');
}
}

View file

@ -68,6 +68,7 @@ class UriImage extends ImageProvider<UriImage> with EquatableMixin {
}
return await decode(bytes);
} catch (error) {
// loading may fail if the provided MIME type is incorrect (e.g. the Media Store may report a JPEG as a TIFF)
debugPrint('$runtimeType _loadAsync failed with mimeType=$mimeType, uri=$uri, error=$error');
throw StateError('$mimeType decoding failed (page $pageId)');
} finally {

View file

@ -449,6 +449,7 @@ class AvesEntry {
CatalogMetadata? get catalogMetadata => _catalogMetadata;
set catalogMetadata(CatalogMetadata? newMetadata) {
final oldMimeType = mimeType;
final oldDateModifiedSecs = dateModifiedSecs;
final oldRotationDegrees = rotationDegrees;
final oldIsFlipped = isFlipped;
@ -459,7 +460,7 @@ class AvesEntry {
_tags = null;
metadataChangeNotifier.notify();
_onVisualFieldChanged(oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
_onVisualFieldChanged(oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
}
void clearMetadata() {
@ -583,6 +584,7 @@ class AvesEntry {
}
Future<void> applyNewFields(Map newFields, {required bool persist}) async {
final oldMimeType = mimeType;
final oldDateModifiedSecs = this.dateModifiedSecs;
final oldRotationDegrees = this.rotationDegrees;
final oldIsFlipped = this.isFlipped;
@ -622,7 +624,7 @@ class AvesEntry {
if (catalogMetadata != null) await metadataDb.saveMetadata({catalogMetadata!});
}
await _onVisualFieldChanged(oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
await _onVisualFieldChanged(oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
metadataChangeNotifier.notify();
}
@ -663,10 +665,10 @@ class AvesEntry {
return completer.future;
}
// when the entry image itself changed (e.g. after rotation)
Future<void> _onVisualFieldChanged(int? oldDateModifiedSecs, int oldRotationDegrees, bool oldIsFlipped) async {
if (oldDateModifiedSecs != dateModifiedSecs || oldRotationDegrees != rotationDegrees || oldIsFlipped != isFlipped) {
await EntryCache.evict(uri, mimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
// when the MIME type or the image itself changed (e.g. after rotation)
Future<void> _onVisualFieldChanged(String oldMimeType, int? oldDateModifiedSecs, int oldRotationDegrees, bool oldIsFlipped) async {
if ((!MimeTypes.refersToSameType(oldMimeType, mimeType) && !MimeTypes.isVideo(oldMimeType)) || oldDateModifiedSecs != dateModifiedSecs || oldRotationDegrees != rotationDegrees || oldIsFlipped != isFlipped) {
await EntryCache.evict(uri, oldMimeType, oldDateModifiedSecs, oldRotationDegrees, oldIsFlipped);
imageChangeNotifier.notify();
}
}

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'package:aves/image_providers/thumbnail_provider.dart';
import 'package:aves/image_providers/uri_image_provider.dart';
import 'package:flutter/foundation.dart';
class EntryCache {
// ordered descending
@ -19,9 +20,11 @@ class EntryCache {
String uri,
String mimeType,
int? dateModifiedSecs,
int oldRotationDegrees,
bool oldIsFlipped,
int rotationDegrees,
bool isFlipped,
) async {
debugPrint('Evict cached images for uri=$uri, mimeType=$mimeType, dateModifiedSecs=$dateModifiedSecs, rotationDegrees=$rotationDegrees, isFlipped=$isFlipped');
// TODO TLAD provide pageId parameter for multi page items, if someday image editing features are added for them
int? pageId;
@ -30,8 +33,8 @@ class EntryCache {
uri: uri,
mimeType: mimeType,
pageId: pageId,
rotationDegrees: oldRotationDegrees,
isFlipped: oldIsFlipped,
rotationDegrees: rotationDegrees,
isFlipped: isFlipped,
).evict();
// evict low quality thumbnail (without specified extents)
@ -40,8 +43,8 @@ class EntryCache {
mimeType: mimeType,
pageId: pageId,
dateModifiedSecs: dateModifiedSecs ?? 0,
rotationDegrees: oldRotationDegrees,
isFlipped: oldIsFlipped,
rotationDegrees: rotationDegrees,
isFlipped: isFlipped,
)).evict();
await Future.forEach<double>(
@ -51,8 +54,8 @@ class EntryCache {
mimeType: mimeType,
pageId: pageId,
dateModifiedSecs: dateModifiedSecs ?? 0,
rotationDegrees: oldRotationDegrees,
isFlipped: oldIsFlipped,
rotationDegrees: rotationDegrees,
isFlipped: isFlipped,
extent: extent,
)).evict());
}

View file

@ -2,6 +2,7 @@ class MimeTypes {
static const anyImage = 'image/*';
static const bmp = 'image/bmp';
static const bmpX = 'image/x-ms-bmp';
static const gif = 'image/gif';
static const heic = 'image/heic';
static const heif = 'image/heif';
@ -43,6 +44,8 @@ class MimeTypes {
static const avi = 'video/avi';
static const aviVnd = 'video/vnd.avi';
static const flv = 'video/flv';
static const flvX = 'video/x-flv';
static const mkv = 'video/x-matroska';
static const mov = 'video/quicktime';
static const mp2t = 'video/mp2t'; // .m2ts, .ts
@ -62,7 +65,7 @@ class MimeTypes {
// groups
// formats that support transparency
static const Set<String> alphaImages = {bmp, gif, ico, png, svg, tiff, webp};
static const Set<String> alphaImages = {bmp, bmpX, gif, ico, png, svg, tiff, webp};
static const Set<String> rawImages = {arw, cr2, crw, dcr, dng, erf, k25, kdc, mrw, nef, nrw, orf, pef, raf, raw, rw2, sr2, srf, srw, x3f};
@ -71,11 +74,33 @@ class MimeTypes {
static const Set<String> _knownOpaqueImages = {heic, heif, jpeg};
static const Set<String> _knownVideos = {avi, aviVnd, mkv, mov, mp2t, mp2ts, mp4, mpeg, ogv, webm};
static const Set<String> _knownVideos = {avi, aviVnd, flv, flvX, mkv, mov, mp2t, mp2ts, mp4, mpeg, ogv, webm};
static final Set<String> knownMediaTypes = {..._knownOpaqueImages, ...alphaImages, ...rawImages, ...undecodableImages, ..._knownVideos};
static bool isImage(String mimeType) => mimeType.startsWith('image');
static bool isVideo(String mimeType) => mimeType.startsWith('video');
static bool refersToSameType(String a, b) {
switch (a) {
case avi:
case aviVnd:
return [avi, aviVnd].contains(b);
case bmp:
case bmpX:
return [bmp, bmpX].contains(b);
case flv:
case flvX:
return [flv, flvX].contains(b);
case heic:
case heif:
return [heic, heif].contains(b);
case psdVnd:
case psdX:
return [psdVnd, psdX].contains(b);
default:
return a == b;
}
}
}

View file

@ -55,7 +55,7 @@ class InfoSearchDelegate extends SearchDelegate {
final l10n = context.l10n;
final suggestions = {
l10n.viewerInfoSearchSuggestionDate: 'date or time or when -timer -uptime -exposure -timeline -verbatim',
l10n.viewerInfoSearchSuggestionDescription: 'abstract or description or comment or textual or title',
l10n.viewerInfoSearchSuggestionDescription: 'abstract or description or comment or textual or title -line',
l10n.viewerInfoSearchSuggestionDimensions: 'width or height or dimension or framesize or imagelength',
l10n.viewerInfoSearchSuggestionResolution: 'resolution',
l10n.viewerInfoSearchSuggestionRights: 'rights or copyright or attribution or license or artist or creator or by-line or credit -tool',