mirror of
https://github.com/immich-app/immich.git
synced 2026-05-18 03:10:24 +03:00
thumbnail bench
This commit is contained in:
@@ -147,7 +147,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
||||
}
|
||||
|
||||
void _onAssetInit(Duration timeStamp) {
|
||||
_preloader.preload(widget.initialIndex, context.sizeData);
|
||||
// _preloader.preload(widget.initialIndex, context.sizeData);
|
||||
_handleCasting();
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
||||
if (asset == null) return;
|
||||
|
||||
AssetViewer._setAsset(ref, asset);
|
||||
_preloader.preload(index, context.sizeData);
|
||||
// _preloader.preload(index, context.sizeData);
|
||||
_handleCasting();
|
||||
_stackChildrenKeepAlive?.close();
|
||||
_stackChildrenKeepAlive = ref.read(stackChildrenNotifier(asset).notifier).ref.keepAlive();
|
||||
|
||||
@@ -8,11 +8,16 @@ import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/thumb_hash_provider.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
||||
import 'package:immich_mobile/utils/image_load_histogram.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
final log = Logger('ThumbnailWidget');
|
||||
|
||||
enum ThumbhashMode { enabled, disabled, only }
|
||||
enum ImageType { thumbnail }
|
||||
|
||||
final remoteImageHistogram = Histogram<ImageType>(maxSamples: 8192, values: ImageType.values);
|
||||
|
||||
int thumbnailId = 0;
|
||||
|
||||
class Thumbnail extends StatefulWidget {
|
||||
final ImageProvider? imageProvider;
|
||||
@@ -111,8 +116,11 @@ class _ThumbnailState extends State<Thumbnail> with SingleTickerProviderStateMix
|
||||
if (imageProvider == null) return;
|
||||
|
||||
final imageStream = _imageStream = imageProvider.resolve(ImageConfiguration.empty);
|
||||
final stopwatch = Stopwatch();
|
||||
final curThumbnailId = thumbnailId++;
|
||||
final imageStreamListener = _imageStreamListener = ImageStreamListener(
|
||||
(ImageInfo imageInfo, bool synchronousCall) {
|
||||
stopwatch.stop();
|
||||
_stopListeningToThumbhashStream();
|
||||
if (!mounted) {
|
||||
imageInfo.dispose();
|
||||
@@ -123,7 +131,27 @@ class _ThumbnailState extends State<Thumbnail> with SingleTickerProviderStateMix
|
||||
return;
|
||||
}
|
||||
|
||||
if ((synchronousCall && _providerImage == null) || !_isVisible()) {
|
||||
final renderObject = context.findRenderObject() as RenderBox?;
|
||||
final double topLeft;
|
||||
final double bottomRight;
|
||||
final double contextHeight = context.height;
|
||||
if (renderObject == null || !renderObject.attached) {
|
||||
topLeft = double.maxFinite;
|
||||
bottomRight = double.maxFinite;
|
||||
} else {
|
||||
topLeft = renderObject.localToGlobal(Offset.zero).dy;
|
||||
bottomRight = renderObject.localToGlobal(Offset(renderObject.size.width, renderObject.size.height)).dy;
|
||||
}
|
||||
remoteImageHistogram.record(
|
||||
ImageType.thumbnail,
|
||||
stopwatch.elapsedMicroseconds,
|
||||
topLeft.toInt(),
|
||||
bottomRight.toInt(),
|
||||
contextHeight.toInt(),
|
||||
curThumbnailId,
|
||||
);
|
||||
|
||||
if ((synchronousCall && _providerImage == null) || !(topLeft < contextHeight && bottomRight > 0)) {
|
||||
_fadeController.value = 1.0;
|
||||
} else if (_fadeController.isAnimating) {
|
||||
_fadeController.forward();
|
||||
@@ -146,6 +174,7 @@ class _ThumbnailState extends State<Thumbnail> with SingleTickerProviderStateMix
|
||||
_stopListeningToImageStream();
|
||||
},
|
||||
);
|
||||
stopwatch.start();
|
||||
imageStream.addListener(imageStreamListener);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||
@@ -17,6 +18,7 @@ import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/download_status_floating_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/constants.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/scrubber.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/segment.model.dart';
|
||||
@@ -140,10 +142,14 @@ class _SliverTimeline extends ConsumerStatefulWidget {
|
||||
ConsumerState createState() => _SliverTimelineState();
|
||||
}
|
||||
|
||||
class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
||||
class _SliverTimelineState extends ConsumerState<_SliverTimeline> with SingleTickerProviderStateMixin {
|
||||
late final ScrollController _scrollController;
|
||||
StreamSubscription? _eventSubscription;
|
||||
|
||||
Ticker? _autoScrollTicker;
|
||||
Duration _lastTickTime = Duration.zero;
|
||||
static const _autoScrollVelocity = 4800.0; // pixels per second
|
||||
|
||||
// Drag selection state
|
||||
bool _dragging = false;
|
||||
TimelineAssetIndex? _dragAnchorIndex;
|
||||
@@ -246,11 +252,52 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_stopAutoScroll();
|
||||
_scrollController.dispose();
|
||||
_eventSubscription?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _toggleAutoScroll() {
|
||||
if (_autoScrollTicker?.isActive ?? false) {
|
||||
_stopAutoScroll();
|
||||
} else {
|
||||
_startAutoScroll();
|
||||
}
|
||||
}
|
||||
|
||||
void _startAutoScroll() {
|
||||
_lastTickTime = Duration.zero;
|
||||
_autoScrollTicker = createTicker(_onAutoScrollTick)..start();
|
||||
}
|
||||
|
||||
void _stopAutoScroll() {
|
||||
_autoScrollTicker?.stop();
|
||||
_autoScrollTicker?.dispose();
|
||||
_autoScrollTicker = null;
|
||||
}
|
||||
|
||||
void _onAutoScrollTick(Duration elapsed) {
|
||||
if (_lastTickTime == Duration.zero) {
|
||||
_lastTickTime = elapsed;
|
||||
return;
|
||||
}
|
||||
|
||||
final deltaSeconds = (elapsed - _lastTickTime).inMicroseconds / 1000000.0;
|
||||
_lastTickTime = elapsed;
|
||||
|
||||
final newOffset = _scrollController.offset + (_autoScrollVelocity * deltaSeconds);
|
||||
final maxOffset = _scrollController.position.maxScrollExtent;
|
||||
if (newOffset >= maxOffset || remoteImageHistogram.count(ImageType.thumbnail) >= remoteImageHistogram.maxSamples) {
|
||||
_scrollController.jumpTo(newOffset.clamp(0, maxOffset));
|
||||
_stopAutoScroll();
|
||||
remoteImageHistogram.logAll();
|
||||
remoteImageHistogram.save();
|
||||
} else {
|
||||
_scrollController.jumpTo(newOffset);
|
||||
}
|
||||
}
|
||||
|
||||
void _scrollToDate(DateTime date) {
|
||||
final asyncSegments = ref.read(timelineSegmentProvider);
|
||||
asyncSegments.whenData((segments) {
|
||||
@@ -434,6 +481,16 @@ class _SliverTimelineState extends ConsumerState<_SliverTimeline> {
|
||||
controller: _scrollController,
|
||||
child: RawGestureDetector(
|
||||
gestures: {
|
||||
SerialTapGestureRecognizer: GestureRecognizerFactoryWithHandlers<SerialTapGestureRecognizer>(
|
||||
() => SerialTapGestureRecognizer(),
|
||||
(SerialTapGestureRecognizer tap) {
|
||||
tap.onSerialTapDown = (details) {
|
||||
if (details.count == 3) {
|
||||
_toggleAutoScroll();
|
||||
}
|
||||
};
|
||||
},
|
||||
),
|
||||
CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers<CustomScaleGestureRecognizer>(
|
||||
() => CustomScaleGestureRecognizer(),
|
||||
(CustomScaleGestureRecognizer scale) {
|
||||
|
||||
Reference in New Issue
Block a user