mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
fix(mobile): ensure current asset is set in asset viewer (#21504)
This commit is contained in:
parent
f06b054087
commit
873f7921da
5 changed files with 64 additions and 34 deletions
|
|
@ -59,6 +59,18 @@ class AssetViewer extends ConsumerStatefulWidget {
|
|||
|
||||
@override
|
||||
ConsumerState createState() => _AssetViewerState();
|
||||
|
||||
static void setAsset(WidgetRef ref, BaseAsset asset) {
|
||||
// Always holds the current asset from the timeline
|
||||
ref.read(assetViewerProvider.notifier).setAsset(asset);
|
||||
// The currentAssetNotifier actually holds the current asset that is displayed
|
||||
// which could be stack children as well
|
||||
ref.read(currentAssetNotifier.notifier).setAsset(asset);
|
||||
if (asset.isVideo || asset.isMotionPhoto) {
|
||||
ref.read(videoPlaybackValueProvider.notifier).reset();
|
||||
ref.read(videoPlayerControlsProvider.notifier).pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const double _kBottomSheetMinimumExtent = 0.4;
|
||||
|
|
@ -99,13 +111,12 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
assert(ref.read(currentAssetNotifier) != null, "Current asset should not be null when opening the AssetViewer");
|
||||
pageController = PageController(initialPage: widget.initialIndex);
|
||||
platform = widget.platform ?? const LocalPlatform();
|
||||
totalAssets = ref.read(timelineServiceProvider).totalAssets;
|
||||
bottomSheetController = DraggableScrollableController();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_onAssetChanged(widget.initialIndex);
|
||||
});
|
||||
WidgetsBinding.instance.addPostFrameCallback(_onAssetInit);
|
||||
reloadSubscription = EventStream.shared.listen(_onEvent);
|
||||
heroOffset = widget.heroOffset ?? TabsRouterScope.of(context)?.controller.activeIndex ?? 0;
|
||||
}
|
||||
|
|
@ -143,26 +154,9 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||
return provider.resolve(ImageConfiguration.empty)..addListener(_dummyListener);
|
||||
}
|
||||
|
||||
void _onAssetChanged(int index) async {
|
||||
// Validate index bounds and try to get asset, loading buffer if needed
|
||||
void _precacheAssets(int index) {
|
||||
final timelineService = ref.read(timelineServiceProvider);
|
||||
final asset = await timelineService.getAssetAsync(index);
|
||||
|
||||
if (asset == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Always holds the current asset from the timeline
|
||||
ref.read(assetViewerProvider.notifier).setAsset(asset);
|
||||
// The currentAssetNotifier actually holds the current asset that is displayed
|
||||
// which could be stack children as well
|
||||
ref.read(currentAssetNotifier.notifier).setAsset(asset);
|
||||
if (asset.isVideo || asset.isMotionPhoto) {
|
||||
ref.read(videoPlaybackValueProvider.notifier).reset();
|
||||
ref.read(videoPlayerControlsProvider.notifier).pause();
|
||||
}
|
||||
|
||||
unawaited(ref.read(timelineServiceProvider).preCacheAssets(index));
|
||||
unawaited(timelineService.preCacheAssets(index));
|
||||
_cancelTimers();
|
||||
// This will trigger the pre-caching of adjacent assets ensuring
|
||||
// that they are ready when the user navigates to them.
|
||||
|
|
@ -181,12 +175,29 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||
_nextPreCacheStream = nextAsset != null ? _precacheImage(nextAsset) : null;
|
||||
});
|
||||
_delayedOperations.add(timer);
|
||||
|
||||
_handleCasting(asset);
|
||||
}
|
||||
|
||||
void _handleCasting(BaseAsset asset) {
|
||||
void _onAssetInit(Duration _) {
|
||||
_precacheAssets(widget.initialIndex);
|
||||
_handleCasting();
|
||||
}
|
||||
|
||||
void _onAssetChanged(int index) async {
|
||||
final timelineService = ref.read(timelineServiceProvider);
|
||||
final asset = await timelineService.getAssetAsync(index);
|
||||
if (asset == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AssetViewer.setAsset(ref, asset);
|
||||
_precacheAssets(index);
|
||||
_handleCasting();
|
||||
}
|
||||
|
||||
void _handleCasting() {
|
||||
if (!ref.read(castProvider).isCasting) return;
|
||||
final asset = ref.read(currentAssetNotifier);
|
||||
if (asset == null) return;
|
||||
|
||||
// hide any casting snackbars if they exist
|
||||
context.scaffoldMessenger.hideCurrentSnackBar();
|
||||
|
|
@ -597,7 +608,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||
if (asset == null) return;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_handleCasting(asset);
|
||||
_handleCasting();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -75,14 +75,23 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier<AssetViewerState> {
|
|||
}
|
||||
|
||||
void setAsset(BaseAsset? asset) {
|
||||
if (asset == state.currentAsset) {
|
||||
return;
|
||||
}
|
||||
state = state.copyWith(currentAsset: asset, stackIndex: 0);
|
||||
}
|
||||
|
||||
void setOpacity(int opacity) {
|
||||
if (opacity == state.backgroundOpacity) {
|
||||
return;
|
||||
}
|
||||
state = state.copyWith(backgroundOpacity: opacity, showingControls: opacity == 255 ? true : state.showingControls);
|
||||
}
|
||||
|
||||
void setBottomSheet(bool showing) {
|
||||
if (showing == state.showingBottomSheet) {
|
||||
return;
|
||||
}
|
||||
state = state.copyWith(showingBottomSheet: showing, showingControls: showing ? true : state.showingControls);
|
||||
if (showing) {
|
||||
ref.read(videoPlayerControlsProvider.notifier).pause();
|
||||
|
|
@ -90,6 +99,9 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier<AssetViewerState> {
|
|||
}
|
||||
|
||||
void setControls(bool isShowing) {
|
||||
if (isShowing == state.showingControls) {
|
||||
return;
|
||||
}
|
||||
state = state.copyWith(showingControls: isShowing);
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +110,9 @@ class AssetViewerStateNotifier extends AutoDisposeNotifier<AssetViewerState> {
|
|||
}
|
||||
|
||||
void setStackIndex(int index) {
|
||||
if (index == state.stackIndex) {
|
||||
return;
|
||||
}
|
||||
state = state.copyWith(stackIndex: index);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.page.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/thumbnail_tile.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/fixed/row.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/timeline/header.widget.dart';
|
||||
|
|
@ -155,6 +156,7 @@ class _AssetTileWidget extends ConsumerWidget {
|
|||
} else {
|
||||
await ref.read(timelineServiceProvider).loadAssets(assetIndex, 1);
|
||||
ref.read(isPlayingMotionVideoProvider.notifier).playing = false;
|
||||
AssetViewer.setAsset(ref, asset);
|
||||
ctx.pushRoute(
|
||||
AssetViewerRoute(
|
||||
initialIndex: assetIndex,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue