From 7d8f56b4835b5c97aa608e630d9505cf3a39429b Mon Sep 17 00:00:00 2001 From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Date: Fri, 11 Jul 2025 01:55:18 +0530 Subject: [PATCH] chore: hero animations (#19860) * remove herocontrollerscope * handle heroOffset in new timeline --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex --- mobile/lib/main.dart | 5 +++-- mobile/lib/pages/common/tab_controller.page.dart | 14 +++++--------- mobile/lib/pages/common/tab_shell.page.dart | 8 ++------ .../widgets/asset_viewer/asset_viewer.page.dart | 8 ++++++-- .../widgets/images/thumbnail_tile.widget.dart | 5 ++++- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index 1b63e303f7..bf79c28361 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -23,12 +23,12 @@ import 'package:immich_mobile/providers/theme.provider.dart'; import 'package:immich_mobile/routing/app_navigation_observer.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/services/background.service.dart'; +import 'package:immich_mobile/services/deep_link.service.dart'; import 'package:immich_mobile/services/local_notification.service.dart'; import 'package:immich_mobile/theme/dynamic_theme.dart'; import 'package:immich_mobile/theme/theme_data.dart'; import 'package:immich_mobile/utils/bootstrap.dart'; import 'package:immich_mobile/utils/cache/widgets_binding.dart'; -import 'package:immich_mobile/services/deep_link.service.dart'; import 'package:immich_mobile/utils/download.dart'; import 'package:immich_mobile/utils/http_ssl_options.dart'; import 'package:immich_mobile/utils/migration.dart'; @@ -253,7 +253,8 @@ class ImmichAppState extends ConsumerState ), routerConfig: router.config( deepLinkBuilder: _deepLinkBuilder, - navigatorObservers: () => [AppNavigationObserver(ref: ref)], + navigatorObservers: () => + [AppNavigationObserver(ref: ref), HeroController()], ), ), ); diff --git a/mobile/lib/pages/common/tab_controller.page.dart b/mobile/lib/pages/common/tab_controller.page.dart index 0188d953dc..e713b3f8da 100644 --- a/mobile/lib/pages/common/tab_controller.page.dart +++ b/mobile/lib/pages/common/tab_controller.page.dart @@ -4,13 +4,13 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/providers/album/album.provider.dart'; +import 'package:immich_mobile/providers/asset.provider.dart'; import 'package:immich_mobile/providers/asset_viewer/scroll_notifier.provider.dart'; +import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; import 'package:immich_mobile/providers/multiselect.provider.dart'; import 'package:immich_mobile/providers/search/search_input_focus.provider.dart'; -import 'package:immich_mobile/routing/router.dart'; -import 'package:immich_mobile/providers/asset.provider.dart'; -import 'package:immich_mobile/providers/haptic_feedback.provider.dart'; import 'package:immich_mobile/providers/tab.provider.dart'; +import 'package:immich_mobile/routing/router.dart'; @RoutePage() class TabControllerPage extends HookConsumerWidget { @@ -158,10 +158,6 @@ class TabControllerPage extends HookConsumerWidget { ), builder: (context, child) { final tabsRouter = AutoTabsRouter.of(context); - final heroedChild = HeroControllerScope( - controller: HeroController(), - child: child, - ); return PopScope( canPop: tabsRouter.activeIndex == 0, onPopInvokedWithResult: (didPop, _) => @@ -173,10 +169,10 @@ class TabControllerPage extends HookConsumerWidget { children: [ navigationRail(tabsRouter), const VerticalDivider(), - Expanded(child: heroedChild), + Expanded(child: child), ], ) - : heroedChild, + : child, bottomNavigationBar: multiselectEnabled || isScreenLandscape ? null : bottomNavigationBar(tabsRouter), diff --git a/mobile/lib/pages/common/tab_shell.page.dart b/mobile/lib/pages/common/tab_shell.page.dart index d5d53360b0..4eab0e32cf 100644 --- a/mobile/lib/pages/common/tab_shell.page.dart +++ b/mobile/lib/pages/common/tab_shell.page.dart @@ -127,10 +127,6 @@ class TabShellPage extends ConsumerWidget { ), builder: (context, child) { final tabsRouter = AutoTabsRouter.of(context); - final heroedChild = HeroControllerScope( - controller: HeroController(), - child: child, - ); return PopScope( canPop: tabsRouter.activeIndex == 0, onPopInvokedWithResult: (didPop, _) => @@ -142,10 +138,10 @@ class TabShellPage extends ConsumerWidget { children: [ navigationRail(tabsRouter), const VerticalDivider(), - Expanded(child: heroedChild), + Expanded(child: child), ], ) - : heroedChild, + : child, bottomNavigationBar: _BottomNavigationBar( tabsRouter: tabsRouter, destinations: navigationDestinations, diff --git a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart index 0f0b5a5a67..e759d6c2e0 100644 --- a/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart +++ b/mobile/lib/presentation/widgets/asset_viewer/asset_viewer.page.dart @@ -71,6 +71,7 @@ class _AssetViewerState extends ConsumerState { StreamSubscription? reloadSubscription; late Platform platform; + late final int heroOffset; late PhotoViewControllerValue initialPhotoViewState; bool? hasDraggedDown; bool isSnapping = false; @@ -98,6 +99,7 @@ class _AssetViewerState extends ConsumerState { _onAssetChanged(widget.initialIndex); }); reloadSubscription = EventStream.shared.listen(_onEvent); + heroOffset = TabsRouterScope.of(context)?.controller.activeIndex ?? 0; } @override @@ -487,7 +489,8 @@ class _AssetViewerState extends ConsumerState { return PhotoViewGalleryPageOptions( key: ValueKey(asset.heroTag), imageProvider: getFullImageProvider(asset, size: size), - heroAttributes: PhotoViewHeroAttributes(tag: asset.heroTag), + heroAttributes: + PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'), filterQuality: FilterQuality.high, tightMode: true, initialScale: PhotoViewComputedScale.contained * 0.999, @@ -521,7 +524,8 @@ class _AssetViewerState extends ConsumerState { onDragUpdate: _onDragUpdate, onDragEnd: _onDragEnd, onTapDown: _onTapDown, - heroAttributes: PhotoViewHeroAttributes(tag: asset.heroTag), + heroAttributes: + PhotoViewHeroAttributes(tag: '${asset.heroTag}_$heroOffset'), filterQuality: FilterQuality.high, initialScale: PhotoViewComputedScale.contained * 0.99, maxScale: 1.0, diff --git a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart index d7261c927e..7e3776adb2 100644 --- a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart +++ b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart @@ -1,3 +1,4 @@ +import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; @@ -25,6 +26,8 @@ class ThumbnailTile extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + final heroOffset = TabsRouterScope.of(context)?.controller.activeIndex ?? 0; + final assetContainerColor = context.isDarkTheme ? context.primaryColor.darken(amount: 0.4) : context.primaryColor.lighten(amount: 0.75); @@ -64,7 +67,7 @@ class ThumbnailTile extends ConsumerWidget { children: [ Positioned.fill( child: Hero( - tag: asset.heroTag, + tag: '${asset.heroTag}_$heroOffset', child: Thumbnail( asset: asset, fit: fit,