fetch encoded bytes for video cover

This commit is contained in:
Thibault Deckers 2025-04-03 22:58:23 +02:00
parent 32202cc603
commit 1fd3d77bf9
10 changed files with 31 additions and 27 deletions

View file

@ -10,7 +10,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
@immutable
class UriImage extends ImageProvider<UriImage> with EquatableMixin {
class FullImage extends ImageProvider<FullImage> with EquatableMixin {
final String uri, mimeType;
final int? pageId, rotationDegrees, sizeBytes;
final bool isFlipped, isAnimated;
@ -19,7 +19,7 @@ class UriImage extends ImageProvider<UriImage> with EquatableMixin {
@override
List<Object?> get props => [uri, pageId, rotationDegrees, isFlipped, isAnimated, scale];
const UriImage({
const FullImage({
required this.uri,
required this.mimeType,
required this.pageId,
@ -31,12 +31,12 @@ class UriImage extends ImageProvider<UriImage> with EquatableMixin {
});
@override
Future<UriImage> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<UriImage>(this);
Future<FullImage> obtainKey(ImageConfiguration configuration) {
return SynchronousFuture<FullImage>(this);
}
@override
ImageStreamCompleter loadImage(UriImage key, ImageDecoderCallback decode) {
ImageStreamCompleter loadImage(FullImage key, ImageDecoderCallback decode) {
final chunkEvents = StreamController<ImageChunkEvent>();
return MultiFrameImageStreamCompleter(
@ -59,11 +59,11 @@ class UriImage extends ImageProvider<UriImage> with EquatableMixin {
case MimeTypes.svg:
return false;
default:
return !isAnimated;
return !isAnimated && !MimeTypes.isVideo(mimeType);
}
}
Future<ui.Codec> _loadAsync(UriImage key, ImageDecoderCallback decode, StreamController<ImageChunkEvent> chunkEvents) async {
Future<ui.Codec> _loadAsync(FullImage key, ImageDecoderCallback decode, StreamController<ImageChunkEvent> chunkEvents) async {
assert(key == this);
final request = ImageRequest(

View file

@ -1,7 +1,7 @@
import 'dart:async';
import 'package:aves/image_providers/full_image_provider.dart';
import 'package:aves/image_providers/thumbnail_provider.dart';
import 'package:aves/image_providers/uri_image_provider.dart';
import 'package:flutter/foundation.dart';
class EntryCache {
@ -30,7 +30,7 @@ class EntryCache {
int? pageId;
// evict fullscreen image
await UriImage(
await FullImage(
uri: uri,
mimeType: mimeType,
pageId: pageId,

View file

@ -1,8 +1,8 @@
import 'dart:math';
import 'package:aves/image_providers/full_image_provider.dart';
import 'package:aves/image_providers/region_provider.dart';
import 'package:aves/image_providers/thumbnail_provider.dart';
import 'package:aves/image_providers/uri_image_provider.dart';
import 'package:aves/model/entry/cache.dart';
import 'package:aves/model/entry/entry.dart';
import 'package:aves/utils/math_utils.dart';
@ -49,7 +49,7 @@ extension ExtraAvesEntryImages on AvesEntry {
));
}
UriImage get uriImage => UriImage(
FullImage get fullImage => FullImage(
uri: uri,
mimeType: mimeType,
pageId: pageId,

View file

@ -157,7 +157,7 @@ class MappedGeoTiff with MapOverlay {
String get id => entry.uri;
@override
ImageProvider get imageProvider => entry.uriImage;
ImageProvider get imageProvider => entry.fullImage;
@override
bool get canOverlay => center != null;

View file

@ -9,6 +9,7 @@ import 'package:aves/services/common/output_buffer.dart';
import 'package:aves/services/common/service_policy.dart';
import 'package:aves/services/common/services.dart';
import 'package:aves/services/media/byte_receiving_codec.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:streams_channel/streams_channel.dart';
@ -328,7 +329,7 @@ class PlatformMediaFetchService implements MediaFetchService {
}
@immutable
class ImageRequest {
class ImageRequest extends Equatable {
final String uri;
final String mimeType;
final int? rotationDegrees;
@ -338,14 +339,17 @@ class ImageRequest {
final int? sizeBytes;
final BytesReceivedCallback? onBytesReceived;
@override
List<Object?> get props => [uri, mimeType, rotationDegrees, isFlipped, isAnimated, pageId, sizeBytes, onBytesReceived];
const ImageRequest(
this.uri,
this.mimeType, {
required this.rotationDegrees,
required this.isFlipped,
required this.isAnimated,
required this.pageId,
required this.sizeBytes,
this.onBytesReceived,
});
this.uri,
this.mimeType, {
required this.rotationDegrees,
required this.isFlipped,
required this.isAnimated,
required this.pageId,
required this.sizeBytes,
this.onBytesReceived,
});
}

View file

@ -118,7 +118,7 @@ class EntryPrinter with FeedbackMixin {
}
} else {
return pdf.Image(
await flutterImageProvider(entry.uriImage),
await flutterImageProvider(entry.fullImage),
fit: _fit,
);
}

View file

@ -172,7 +172,7 @@ class WallpaperButtons extends StatelessWidget with FeedbackMixin {
} else {
// provider image is already rotated, but not cropped
needCrop = true;
provider = entry.uriImage;
provider = entry.fullImage;
}
}
if (provider == null) return null;

View file

@ -90,7 +90,7 @@ class _PanoramaPageState extends State<PanoramaPage> {
}
},
child: Image(
image: entry.uriImage,
image: entry.fullImage,
),
),
Positioned(

View file

@ -63,7 +63,7 @@ class _RasterImageViewState extends State<RasterImageView> {
region: fullImageRegion,
);
} else {
return entry.uriImage;
return entry.fullImage;
}
}

View file

@ -58,7 +58,7 @@ class _VideoCoverState extends State<VideoCover> {
Size get videoDisplaySize => widget.videoDisplaySize;
// use the high res photo as cover for the video part of a motion photo
ImageProvider get videoCoverUriImage => (mainEntry.isMotionPhoto ? mainEntry : entry).uriImage;
ImageProvider get videoCoverUriImage => (mainEntry.isMotionPhoto ? mainEntry : entry).fullImage;
@override
void initState() {