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

View file

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

View file

@ -1,8 +1,8 @@
import 'dart:math'; 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/region_provider.dart';
import 'package:aves/image_providers/thumbnail_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/cache.dart';
import 'package:aves/model/entry/entry.dart'; import 'package:aves/model/entry/entry.dart';
import 'package:aves/utils/math_utils.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, uri: uri,
mimeType: mimeType, mimeType: mimeType,
pageId: pageId, pageId: pageId,

View file

@ -157,7 +157,7 @@ class MappedGeoTiff with MapOverlay {
String get id => entry.uri; String get id => entry.uri;
@override @override
ImageProvider get imageProvider => entry.uriImage; ImageProvider get imageProvider => entry.fullImage;
@override @override
bool get canOverlay => center != null; 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/service_policy.dart';
import 'package:aves/services/common/services.dart'; import 'package:aves/services/common/services.dart';
import 'package:aves/services/media/byte_receiving_codec.dart'; import 'package:aves/services/media/byte_receiving_codec.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:streams_channel/streams_channel.dart'; import 'package:streams_channel/streams_channel.dart';
@ -328,7 +329,7 @@ class PlatformMediaFetchService implements MediaFetchService {
} }
@immutable @immutable
class ImageRequest { class ImageRequest extends Equatable {
final String uri; final String uri;
final String mimeType; final String mimeType;
final int? rotationDegrees; final int? rotationDegrees;
@ -338,14 +339,17 @@ class ImageRequest {
final int? sizeBytes; final int? sizeBytes;
final BytesReceivedCallback? onBytesReceived; final BytesReceivedCallback? onBytesReceived;
@override
List<Object?> get props => [uri, mimeType, rotationDegrees, isFlipped, isAnimated, pageId, sizeBytes, onBytesReceived];
const ImageRequest( const ImageRequest(
this.uri, this.uri,
this.mimeType, { this.mimeType, {
required this.rotationDegrees, required this.rotationDegrees,
required this.isFlipped, required this.isFlipped,
required this.isAnimated, required this.isAnimated,
required this.pageId, required this.pageId,
required this.sizeBytes, required this.sizeBytes,
this.onBytesReceived, this.onBytesReceived,
}); });
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -58,7 +58,7 @@ class _VideoCoverState extends State<VideoCover> {
Size get videoDisplaySize => widget.videoDisplaySize; Size get videoDisplaySize => widget.videoDisplaySize;
// use the high res photo as cover for the video part of a motion photo // 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 @override
void initState() { void initState() {