diff --git a/mobile/lib/modules/asset_viewer/providers/scroll_notifier.provider.dart b/mobile/lib/modules/asset_viewer/providers/scroll_notifier.provider.dart new file mode 100644 index 0000000000..a5423554d0 --- /dev/null +++ b/mobile/lib/modules/asset_viewer/providers/scroll_notifier.provider.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; + +final scrollToTopNotifierProvider = ScrollNotifier(); + +class ScrollNotifier with ChangeNotifier { + void scrollToTop() { + notifyListeners(); + } +} diff --git a/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart b/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart index 5a2787ecf8..c2e3df2027 100644 --- a/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart +++ b/mobile/lib/modules/home/ui/asset_grid/immich_asset_grid.dart @@ -3,6 +3,7 @@ import 'dart:collection'; import 'package:collection/collection.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:immich_mobile/modules/asset_viewer/providers/scroll_notifier.provider.dart'; import 'package:immich_mobile/modules/home/ui/asset_grid/thumbnail_image.dart'; import 'package:immich_mobile/shared/models/asset.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; @@ -234,6 +235,30 @@ class ImmichAssetGridState extends State { return true; } + @override + void initState() { + super.initState(); + scrollToTopNotifierProvider.addListener(_scrollToTop); + } + + @override + void dispose() { + scrollToTopNotifierProvider.removeListener(_scrollToTop); + super.dispose(); + } + + void _scrollToTop() { + // for some reason, this is necessary as well in order + // to correctly reposition the drag thumb scroll bar + _itemScrollController.jumpTo( + index: 0, + ); + _itemScrollController.scrollTo( + index: 0, + duration: const Duration(milliseconds: 200), + ); + } + @override Widget build(BuildContext context) { return WillPopScope( diff --git a/mobile/lib/shared/views/tab_controller_page.dart b/mobile/lib/shared/views/tab_controller_page.dart index 6fe7d7254a..9881b58c2a 100644 --- a/mobile/lib/shared/views/tab_controller_page.dart +++ b/mobile/lib/shared/views/tab_controller_page.dart @@ -3,6 +3,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/asset_viewer/providers/scroll_notifier.provider.dart'; import 'package:immich_mobile/modules/home/providers/multiselect.provider.dart'; import 'package:immich_mobile/routing/router.dart'; @@ -16,6 +17,11 @@ class TabControllerPage extends ConsumerWidget { labelType: NavigationRailLabelType.all, selectedIndex: tabsRouter.activeIndex, onDestinationSelected: (index) { + // Selected Photos while it is active + if (tabsRouter.activeIndex == 0 && index == 0) { + // Scroll to top + scrollToTopNotifierProvider.scrollToTop(); + } HapticFeedback.selectionClick(); tabsRouter.setActiveIndex(index); }, @@ -60,51 +66,14 @@ class TabControllerPage extends ConsumerWidget { ); } - // ignore: unused_element bottomNavigationBar(TabsRouter tabsRouter) { - return BottomNavigationBar( - selectedLabelStyle: const TextStyle( - fontSize: 13, - fontWeight: FontWeight.w600, - ), - unselectedLabelStyle: const TextStyle( - fontSize: 13, - fontWeight: FontWeight.w600, - ), - currentIndex: tabsRouter.activeIndex, - onTap: (index) { - HapticFeedback.selectionClick(); - tabsRouter.setActiveIndex(index); - }, - items: [ - BottomNavigationBarItem( - label: 'tab_controller_nav_photos'.tr(), - icon: const Icon(Icons.photo_outlined), - activeIcon: const Icon(Icons.photo), - ), - BottomNavigationBarItem( - label: 'tab_controller_nav_search'.tr(), - icon: const Icon(Icons.search_rounded), - activeIcon: const Icon(Icons.search), - ), - BottomNavigationBarItem( - label: 'tab_controller_nav_sharing'.tr(), - icon: const Icon(Icons.group_outlined), - activeIcon: const Icon(Icons.group), - ), - BottomNavigationBarItem( - label: 'tab_controller_nav_library'.tr(), - icon: const Icon(Icons.photo_album_outlined), - activeIcon: const Icon(Icons.photo_album_rounded), - ) - ], - ); - } - - experimentalNavigationBar(TabsRouter tabsRouter) { return NavigationBar( selectedIndex: tabsRouter.activeIndex, onDestinationSelected: (index) { + if (tabsRouter.activeIndex == 0 && index == 0) { + // Scroll to top + scrollToTopNotifierProvider.scrollToTop(); + } HapticFeedback.selectionClick(); tabsRouter.setActiveIndex(index); }, @@ -179,7 +148,7 @@ class TabControllerPage extends ConsumerWidget { final Widget body; if (constraints.maxWidth < medium) { // Normal phone width - bottom = experimentalNavigationBar(tabsRouter); + bottom = bottomNavigationBar(tabsRouter); body = FadeTransition( opacity: animation, child: child,