Browse Source

fix(mobile): Prevents duplicate taps navigating to the same route twice (#1855)

martyfuhry 2 years ago
parent
commit
4ed96cf1bd

+ 2 - 3
mobile/lib/main.dart

@@ -141,9 +141,8 @@ class ImmichAppState extends ConsumerState<ImmichApp>
 
         ref.watch(releaseInfoProvider.notifier).checkGithubReleaseInfo();
 
-        ref
-            .watch(notificationPermissionProvider.notifier)
-            .getNotificationPermission();
+        ref.watch(notificationPermissionProvider.notifier)
+          .getNotificationPermission();
 
         ref.read(iOSBackgroundSettingsProvider.notifier).refresh();
 

+ 17 - 0
mobile/lib/routing/duplicate_guard.dart

@@ -0,0 +1,17 @@
+import 'package:auto_route/auto_route.dart';
+import 'package:flutter/foundation.dart';
+
+/// Guards against duplicate navigation to this route
+class DuplicateGuard extends AutoRouteGuard {
+  DuplicateGuard();
+  @override
+  void onNavigation(NavigationResolver resolver, StackRouter router) async {
+    // Duplicate navigation
+    if (resolver.route.name == router.current.name) {
+      debugPrint('DuplicateGuard: Preventing duplicate route navigation for ${resolver.route.name}');
+      resolver.next(false);
+    } else {
+      resolver.next(true);
+    }
+  }
+}

+ 35 - 21
mobile/lib/routing/router.dart

@@ -23,6 +23,7 @@ import 'package:immich_mobile/modules/search/views/search_page.dart';
 import 'package:immich_mobile/modules/search/views/search_result_page.dart';
 import 'package:immich_mobile/modules/settings/views/settings_page.dart';
 import 'package:immich_mobile/routing/auth_guard.dart';
+import 'package:immich_mobile/routing/duplicate_guard.dart';
 import 'package:immich_mobile/shared/models/asset.dart';
 import 'package:immich_mobile/shared/models/album.dart';
 import 'package:immich_mobile/shared/providers/api.provider.dart';
@@ -38,49 +39,58 @@ part 'router.gr.dart';
   replaceInRouteName: 'Page,Route',
   routes: <AutoRoute>[
     AutoRoute(page: SplashScreenPage, initial: true),
-    AutoRoute(page: LoginPage),
+    AutoRoute(page: LoginPage,
+      guards: [
+        DuplicateGuard,
+      ],
+    ),
     AutoRoute(page: ChangePasswordPage),
     CustomRoute(
       page: TabControllerPage,
-      guards: [AuthGuard],
+      guards: [AuthGuard, DuplicateGuard],
       children: [
-        AutoRoute(page: HomePage, guards: [AuthGuard]),
-        AutoRoute(page: SearchPage, guards: [AuthGuard]),
-        AutoRoute(page: SharingPage, guards: [AuthGuard]),
-        AutoRoute(page: LibraryPage, guards: [AuthGuard])
+        AutoRoute(page: HomePage, guards: [AuthGuard, DuplicateGuard]),
+        AutoRoute(page: SearchPage, guards: [AuthGuard, DuplicateGuard]),
+        AutoRoute(page: SharingPage, guards: [AuthGuard, DuplicateGuard]),
+        AutoRoute(page: LibraryPage, guards: [AuthGuard, DuplicateGuard])
       ],
       transitionsBuilder: TransitionsBuilders.fadeIn,
     ),
-    AutoRoute(page: GalleryViewerPage, guards: [AuthGuard]),
-    AutoRoute(page: VideoViewerPage, guards: [AuthGuard]),
-    AutoRoute(page: BackupControllerPage, guards: [AuthGuard]),
-    AutoRoute(page: SearchResultPage, guards: [AuthGuard]),
-    AutoRoute(page: CreateAlbumPage, guards: [AuthGuard]),
-    AutoRoute(page: FavoritesPage, guards: [AuthGuard]),
+    AutoRoute(page: GalleryViewerPage, guards: [AuthGuard, DuplicateGuard]),
+    AutoRoute(page: VideoViewerPage, guards: [AuthGuard, DuplicateGuard]),
+    AutoRoute(page: BackupControllerPage, guards: [AuthGuard, DuplicateGuard]),
+    AutoRoute(page: SearchResultPage, guards: [AuthGuard, DuplicateGuard]),
+    AutoRoute(page: CreateAlbumPage, guards: [AuthGuard, DuplicateGuard]),
+    AutoRoute(page: FavoritesPage, guards: [AuthGuard, DuplicateGuard]),
     CustomRoute<AssetSelectionPageResult?>(
       page: AssetSelectionPage,
-      guards: [AuthGuard],
+      guards: [AuthGuard, DuplicateGuard],
       transitionsBuilder: TransitionsBuilders.slideBottom,
     ),
     CustomRoute<List<String>>(
       page: SelectUserForSharingPage,
-      guards: [AuthGuard],
+      guards: [AuthGuard, DuplicateGuard],
       transitionsBuilder: TransitionsBuilders.slideBottom,
     ),
-    AutoRoute(page: AlbumViewerPage, guards: [AuthGuard]),
+    AutoRoute(page: AlbumViewerPage, guards: [AuthGuard, DuplicateGuard]),
     CustomRoute<List<String>?>(
       page: SelectAdditionalUserForSharingPage,
-      guards: [AuthGuard],
+      guards: [AuthGuard, DuplicateGuard],
       transitionsBuilder: TransitionsBuilders.slideBottom,
     ),
-    AutoRoute(page: BackupAlbumSelectionPage, guards: [AuthGuard]),
-    AutoRoute(page: AlbumPreviewPage, guards: [AuthGuard]),
+    AutoRoute(page: BackupAlbumSelectionPage, guards: [AuthGuard, DuplicateGuard]),
+    AutoRoute(page: AlbumPreviewPage, guards: [AuthGuard, DuplicateGuard]),
     CustomRoute(
       page: FailedBackupStatusPage,
-      guards: [AuthGuard],
+      guards: [AuthGuard, DuplicateGuard],
       transitionsBuilder: TransitionsBuilders.slideBottom,
     ),
-    AutoRoute(page: SettingsPage, guards: [AuthGuard]),
+    AutoRoute(page: SettingsPage, 
+      guards: [
+        AuthGuard,
+        DuplicateGuard,
+      ],
+    ),
     CustomRoute(
       page: AppLogPage,
       transitionsBuilder: TransitionsBuilders.slideBottom,
@@ -91,7 +101,11 @@ class AppRouter extends _$AppRouter {
   // ignore: unused_field
   final ApiService _apiService;
 
-  AppRouter(this._apiService) : super(authGuard: AuthGuard(_apiService));
+  AppRouter(this._apiService) 
+      : super(
+          authGuard: AuthGuard(_apiService), 
+          duplicateGuard: DuplicateGuard(),
+        );
 }
 
 final appRouterProvider =

+ 499 - 200
mobile/lib/routing/router.gr.dart

@@ -13,9 +13,13 @@
 part of 'router.dart';
 
 class _$AppRouter extends RootStackRouter {
-  _$AppRouter(
-      {GlobalKey<NavigatorState>? navigatorKey, required this.authGuard})
-      : super(navigatorKey);
+  _$AppRouter({
+    GlobalKey<NavigatorState>? navigatorKey,
+    required this.duplicateGuard,
+    required this.authGuard,
+  }) : super(navigatorKey);
+
+  final DuplicateGuard duplicateGuard;
 
   final AuthGuard authGuard;
 
@@ -23,211 +27,386 @@ class _$AppRouter extends RootStackRouter {
   final Map<String, PageFactory> pagesMap = {
     SplashScreenRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const SplashScreenPage());
+        routeData: routeData,
+        child: const SplashScreenPage(),
+      );
     },
     LoginRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const LoginPage());
+        routeData: routeData,
+        child: const LoginPage(),
+      );
     },
     ChangePasswordRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const ChangePasswordPage());
+        routeData: routeData,
+        child: const ChangePasswordPage(),
+      );
     },
     TabControllerRoute.name: (routeData) {
       return CustomPage<dynamic>(
-          routeData: routeData,
-          child: const TabControllerPage(),
-          transitionsBuilder: TransitionsBuilders.fadeIn,
-          opaque: true,
-          barrierDismissible: false);
+        routeData: routeData,
+        child: const TabControllerPage(),
+        transitionsBuilder: TransitionsBuilders.fadeIn,
+        opaque: true,
+        barrierDismissible: false,
+      );
     },
     GalleryViewerRoute.name: (routeData) {
       final args = routeData.argsAs<GalleryViewerRouteArgs>();
       return MaterialPageX<dynamic>(
-          routeData: routeData,
-          child: GalleryViewerPage(
-              key: args.key, assetList: args.assetList, asset: args.asset));
+        routeData: routeData,
+        child: GalleryViewerPage(
+          key: args.key,
+          assetList: args.assetList,
+          asset: args.asset,
+        ),
+      );
     },
     VideoViewerRoute.name: (routeData) {
       final args = routeData.argsAs<VideoViewerRouteArgs>();
       return MaterialPageX<dynamic>(
-          routeData: routeData,
-          child: VideoViewerPage(
-              key: args.key,
-              asset: args.asset,
-              isMotionVideo: args.isMotionVideo,
-              onVideoEnded: args.onVideoEnded));
+        routeData: routeData,
+        child: VideoViewerPage(
+          key: args.key,
+          asset: args.asset,
+          isMotionVideo: args.isMotionVideo,
+          onVideoEnded: args.onVideoEnded,
+          onPlaying: args.onPlaying,
+          onPaused: args.onPaused,
+        ),
+      );
     },
     BackupControllerRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const BackupControllerPage());
+        routeData: routeData,
+        child: const BackupControllerPage(),
+      );
     },
     SearchResultRoute.name: (routeData) {
       final args = routeData.argsAs<SearchResultRouteArgs>();
       return MaterialPageX<dynamic>(
-          routeData: routeData,
-          child: SearchResultPage(key: args.key, searchTerm: args.searchTerm));
+        routeData: routeData,
+        child: SearchResultPage(
+          key: args.key,
+          searchTerm: args.searchTerm,
+        ),
+      );
     },
     CreateAlbumRoute.name: (routeData) {
       final args = routeData.argsAs<CreateAlbumRouteArgs>();
       return MaterialPageX<dynamic>(
-          routeData: routeData,
-          child: CreateAlbumPage(
-              key: args.key,
-              isSharedAlbum: args.isSharedAlbum,
-              initialAssets: args.initialAssets));
+        routeData: routeData,
+        child: CreateAlbumPage(
+          key: args.key,
+          isSharedAlbum: args.isSharedAlbum,
+          initialAssets: args.initialAssets,
+        ),
+      );
     },
     FavoritesRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const FavoritesPage());
+        routeData: routeData,
+        child: const FavoritesPage(),
+      );
     },
     AssetSelectionRoute.name: (routeData) {
       return CustomPage<AssetSelectionPageResult?>(
-          routeData: routeData,
-          child: const AssetSelectionPage(),
-          transitionsBuilder: TransitionsBuilders.slideBottom,
-          opaque: true,
-          barrierDismissible: false);
+        routeData: routeData,
+        child: const AssetSelectionPage(),
+        transitionsBuilder: TransitionsBuilders.slideBottom,
+        opaque: true,
+        barrierDismissible: false,
+      );
     },
     SelectUserForSharingRoute.name: (routeData) {
       return CustomPage<List<String>>(
-          routeData: routeData,
-          child: const SelectUserForSharingPage(),
-          transitionsBuilder: TransitionsBuilders.slideBottom,
-          opaque: true,
-          barrierDismissible: false);
+        routeData: routeData,
+        child: const SelectUserForSharingPage(),
+        transitionsBuilder: TransitionsBuilders.slideBottom,
+        opaque: true,
+        barrierDismissible: false,
+      );
     },
     AlbumViewerRoute.name: (routeData) {
       final args = routeData.argsAs<AlbumViewerRouteArgs>();
       return MaterialPageX<dynamic>(
-          routeData: routeData,
-          child: AlbumViewerPage(key: args.key, albumId: args.albumId));
+        routeData: routeData,
+        child: AlbumViewerPage(
+          key: args.key,
+          albumId: args.albumId,
+        ),
+      );
     },
     SelectAdditionalUserForSharingRoute.name: (routeData) {
       final args = routeData.argsAs<SelectAdditionalUserForSharingRouteArgs>();
       return CustomPage<List<String>?>(
-          routeData: routeData,
-          child: SelectAdditionalUserForSharingPage(
-              key: args.key, album: args.album),
-          transitionsBuilder: TransitionsBuilders.slideBottom,
-          opaque: true,
-          barrierDismissible: false);
+        routeData: routeData,
+        child: SelectAdditionalUserForSharingPage(
+          key: args.key,
+          album: args.album,
+        ),
+        transitionsBuilder: TransitionsBuilders.slideBottom,
+        opaque: true,
+        barrierDismissible: false,
+      );
     },
     BackupAlbumSelectionRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const BackupAlbumSelectionPage());
+        routeData: routeData,
+        child: const BackupAlbumSelectionPage(),
+      );
     },
     AlbumPreviewRoute.name: (routeData) {
       final args = routeData.argsAs<AlbumPreviewRouteArgs>();
       return MaterialPageX<dynamic>(
-          routeData: routeData,
-          child: AlbumPreviewPage(key: args.key, album: args.album));
+        routeData: routeData,
+        child: AlbumPreviewPage(
+          key: args.key,
+          album: args.album,
+        ),
+      );
     },
     FailedBackupStatusRoute.name: (routeData) {
       return CustomPage<dynamic>(
-          routeData: routeData,
-          child: const FailedBackupStatusPage(),
-          transitionsBuilder: TransitionsBuilders.slideBottom,
-          opaque: true,
-          barrierDismissible: false);
+        routeData: routeData,
+        child: const FailedBackupStatusPage(),
+        transitionsBuilder: TransitionsBuilders.slideBottom,
+        opaque: true,
+        barrierDismissible: false,
+      );
     },
     SettingsRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const SettingsPage());
+        routeData: routeData,
+        child: const SettingsPage(),
+      );
     },
     AppLogRoute.name: (routeData) {
       return CustomPage<dynamic>(
-          routeData: routeData,
-          child: const AppLogPage(),
-          transitionsBuilder: TransitionsBuilders.slideBottom,
-          opaque: true,
-          barrierDismissible: false);
+        routeData: routeData,
+        child: const AppLogPage(),
+        transitionsBuilder: TransitionsBuilders.slideBottom,
+        opaque: true,
+        barrierDismissible: false,
+      );
     },
     HomeRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const HomePage());
+        routeData: routeData,
+        child: const HomePage(),
+      );
     },
     SearchRoute.name: (routeData) {
       final args = routeData.argsAs<SearchRouteArgs>(
           orElse: () => const SearchRouteArgs());
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: SearchPage(key: args.key));
+        routeData: routeData,
+        child: SearchPage(key: args.key),
+      );
     },
     SharingRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const SharingPage());
+        routeData: routeData,
+        child: const SharingPage(),
+      );
     },
     LibraryRoute.name: (routeData) {
       return MaterialPageX<dynamic>(
-          routeData: routeData, child: const LibraryPage());
-    }
+        routeData: routeData,
+        child: const LibraryPage(),
+      );
+    },
   };
 
   @override
   List<RouteConfig> get routes => [
-        RouteConfig(SplashScreenRoute.name, path: '/'),
-        RouteConfig(LoginRoute.name, path: '/login-page'),
-        RouteConfig(ChangePasswordRoute.name, path: '/change-password-page'),
-        RouteConfig(TabControllerRoute.name,
-            path: '/tab-controller-page',
-            guards: [
-              authGuard
-            ],
-            children: [
-              RouteConfig(HomeRoute.name,
-                  path: 'home-page',
-                  parent: TabControllerRoute.name,
-                  guards: [authGuard]),
-              RouteConfig(SearchRoute.name,
-                  path: 'search-page',
-                  parent: TabControllerRoute.name,
-                  guards: [authGuard]),
-              RouteConfig(SharingRoute.name,
-                  path: 'sharing-page',
-                  parent: TabControllerRoute.name,
-                  guards: [authGuard]),
-              RouteConfig(LibraryRoute.name,
-                  path: 'library-page',
-                  parent: TabControllerRoute.name,
-                  guards: [authGuard])
-            ]),
-        RouteConfig(GalleryViewerRoute.name,
-            path: '/gallery-viewer-page', guards: [authGuard]),
-        RouteConfig(VideoViewerRoute.name,
-            path: '/video-viewer-page', guards: [authGuard]),
-        RouteConfig(BackupControllerRoute.name,
-            path: '/backup-controller-page', guards: [authGuard]),
-        RouteConfig(SearchResultRoute.name,
-            path: '/search-result-page', guards: [authGuard]),
-        RouteConfig(CreateAlbumRoute.name,
-            path: '/create-album-page', guards: [authGuard]),
-        RouteConfig(FavoritesRoute.name,
-            path: '/favorites-page', guards: [authGuard]),
-        RouteConfig(AssetSelectionRoute.name,
-            path: '/asset-selection-page', guards: [authGuard]),
-        RouteConfig(SelectUserForSharingRoute.name,
-            path: '/select-user-for-sharing-page', guards: [authGuard]),
-        RouteConfig(AlbumViewerRoute.name,
-            path: '/album-viewer-page', guards: [authGuard]),
-        RouteConfig(SelectAdditionalUserForSharingRoute.name,
-            path: '/select-additional-user-for-sharing-page',
-            guards: [authGuard]),
-        RouteConfig(BackupAlbumSelectionRoute.name,
-            path: '/backup-album-selection-page', guards: [authGuard]),
-        RouteConfig(AlbumPreviewRoute.name,
-            path: '/album-preview-page', guards: [authGuard]),
-        RouteConfig(FailedBackupStatusRoute.name,
-            path: '/failed-backup-status-page', guards: [authGuard]),
-        RouteConfig(SettingsRoute.name,
-            path: '/settings-page', guards: [authGuard]),
-        RouteConfig(AppLogRoute.name, path: '/app-log-page')
+        RouteConfig(
+          SplashScreenRoute.name,
+          path: '/',
+        ),
+        RouteConfig(
+          LoginRoute.name,
+          path: '/login-page',
+          guards: [duplicateGuard],
+        ),
+        RouteConfig(
+          ChangePasswordRoute.name,
+          path: '/change-password-page',
+        ),
+        RouteConfig(
+          TabControllerRoute.name,
+          path: '/tab-controller-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+          children: [
+            RouteConfig(
+              HomeRoute.name,
+              path: 'home-page',
+              parent: TabControllerRoute.name,
+              guards: [
+                authGuard,
+                duplicateGuard,
+              ],
+            ),
+            RouteConfig(
+              SearchRoute.name,
+              path: 'search-page',
+              parent: TabControllerRoute.name,
+              guards: [
+                authGuard,
+                duplicateGuard,
+              ],
+            ),
+            RouteConfig(
+              SharingRoute.name,
+              path: 'sharing-page',
+              parent: TabControllerRoute.name,
+              guards: [
+                authGuard,
+                duplicateGuard,
+              ],
+            ),
+            RouteConfig(
+              LibraryRoute.name,
+              path: 'library-page',
+              parent: TabControllerRoute.name,
+              guards: [
+                authGuard,
+                duplicateGuard,
+              ],
+            ),
+          ],
+        ),
+        RouteConfig(
+          GalleryViewerRoute.name,
+          path: '/gallery-viewer-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          VideoViewerRoute.name,
+          path: '/video-viewer-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          BackupControllerRoute.name,
+          path: '/backup-controller-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          SearchResultRoute.name,
+          path: '/search-result-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          CreateAlbumRoute.name,
+          path: '/create-album-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          FavoritesRoute.name,
+          path: '/favorites-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          AssetSelectionRoute.name,
+          path: '/asset-selection-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          SelectUserForSharingRoute.name,
+          path: '/select-user-for-sharing-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          AlbumViewerRoute.name,
+          path: '/album-viewer-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          SelectAdditionalUserForSharingRoute.name,
+          path: '/select-additional-user-for-sharing-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          BackupAlbumSelectionRoute.name,
+          path: '/backup-album-selection-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          AlbumPreviewRoute.name,
+          path: '/album-preview-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          FailedBackupStatusRoute.name,
+          path: '/failed-backup-status-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          SettingsRoute.name,
+          path: '/settings-page',
+          guards: [
+            authGuard,
+            duplicateGuard,
+          ],
+        ),
+        RouteConfig(
+          AppLogRoute.name,
+          path: '/app-log-page',
+        ),
       ];
 }
 
 /// generated route for
 /// [SplashScreenPage]
 class SplashScreenRoute extends PageRouteInfo<void> {
-  const SplashScreenRoute() : super(SplashScreenRoute.name, path: '/');
+  const SplashScreenRoute()
+      : super(
+          SplashScreenRoute.name,
+          path: '/',
+        );
 
   static const String name = 'SplashScreenRoute';
 }
@@ -235,7 +414,11 @@ class SplashScreenRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [LoginPage]
 class LoginRoute extends PageRouteInfo<void> {
-  const LoginRoute() : super(LoginRoute.name, path: '/login-page');
+  const LoginRoute()
+      : super(
+          LoginRoute.name,
+          path: '/login-page',
+        );
 
   static const String name = 'LoginRoute';
 }
@@ -244,7 +427,10 @@ class LoginRoute extends PageRouteInfo<void> {
 /// [ChangePasswordPage]
 class ChangePasswordRoute extends PageRouteInfo<void> {
   const ChangePasswordRoute()
-      : super(ChangePasswordRoute.name, path: '/change-password-page');
+      : super(
+          ChangePasswordRoute.name,
+          path: '/change-password-page',
+        );
 
   static const String name = 'ChangePasswordRoute';
 }
@@ -253,8 +439,11 @@ class ChangePasswordRoute extends PageRouteInfo<void> {
 /// [TabControllerPage]
 class TabControllerRoute extends PageRouteInfo<void> {
   const TabControllerRoute({List<PageRouteInfo>? children})
-      : super(TabControllerRoute.name,
-            path: '/tab-controller-page', initialChildren: children);
+      : super(
+          TabControllerRoute.name,
+          path: '/tab-controller-page',
+          initialChildren: children,
+        );
 
   static const String name = 'TabControllerRoute';
 }
@@ -262,19 +451,29 @@ class TabControllerRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [GalleryViewerPage]
 class GalleryViewerRoute extends PageRouteInfo<GalleryViewerRouteArgs> {
-  GalleryViewerRoute(
-      {Key? key, required List<Asset> assetList, required Asset asset})
-      : super(GalleryViewerRoute.name,
-            path: '/gallery-viewer-page',
-            args: GalleryViewerRouteArgs(
-                key: key, assetList: assetList, asset: asset));
+  GalleryViewerRoute({
+    Key? key,
+    required List<Asset> assetList,
+    required Asset asset,
+  }) : super(
+          GalleryViewerRoute.name,
+          path: '/gallery-viewer-page',
+          args: GalleryViewerRouteArgs(
+            key: key,
+            assetList: assetList,
+            asset: asset,
+          ),
+        );
 
   static const String name = 'GalleryViewerRoute';
 }
 
 class GalleryViewerRouteArgs {
-  const GalleryViewerRouteArgs(
-      {this.key, required this.assetList, required this.asset});
+  const GalleryViewerRouteArgs({
+    this.key,
+    required this.assetList,
+    required this.asset,
+  });
 
   final Key? key;
 
@@ -291,28 +490,38 @@ class GalleryViewerRouteArgs {
 /// generated route for
 /// [VideoViewerPage]
 class VideoViewerRoute extends PageRouteInfo<VideoViewerRouteArgs> {
-  VideoViewerRoute(
-      {Key? key,
-      required Asset asset,
-      required bool isMotionVideo,
-      required void Function() onVideoEnded})
-      : super(VideoViewerRoute.name,
-            path: '/video-viewer-page',
-            args: VideoViewerRouteArgs(
-                key: key,
-                asset: asset,
-                isMotionVideo: isMotionVideo,
-                onVideoEnded: onVideoEnded));
+  VideoViewerRoute({
+    Key? key,
+    required Asset asset,
+    required bool isMotionVideo,
+    required void Function() onVideoEnded,
+    void Function()? onPlaying,
+    void Function()? onPaused,
+  }) : super(
+          VideoViewerRoute.name,
+          path: '/video-viewer-page',
+          args: VideoViewerRouteArgs(
+            key: key,
+            asset: asset,
+            isMotionVideo: isMotionVideo,
+            onVideoEnded: onVideoEnded,
+            onPlaying: onPlaying,
+            onPaused: onPaused,
+          ),
+        );
 
   static const String name = 'VideoViewerRoute';
 }
 
 class VideoViewerRouteArgs {
-  const VideoViewerRouteArgs(
-      {this.key,
-      required this.asset,
-      required this.isMotionVideo,
-      required this.onVideoEnded});
+  const VideoViewerRouteArgs({
+    this.key,
+    required this.asset,
+    required this.isMotionVideo,
+    required this.onVideoEnded,
+    this.onPlaying,
+    this.onPaused,
+  });
 
   final Key? key;
 
@@ -322,9 +531,13 @@ class VideoViewerRouteArgs {
 
   final void Function() onVideoEnded;
 
+  final void Function()? onPlaying;
+
+  final void Function()? onPaused;
+
   @override
   String toString() {
-    return 'VideoViewerRouteArgs{key: $key, asset: $asset, isMotionVideo: $isMotionVideo, onVideoEnded: $onVideoEnded}';
+    return 'VideoViewerRouteArgs{key: $key, asset: $asset, isMotionVideo: $isMotionVideo, onVideoEnded: $onVideoEnded, onPlaying: $onPlaying, onPaused: $onPaused}';
   }
 }
 
@@ -332,7 +545,10 @@ class VideoViewerRouteArgs {
 /// [BackupControllerPage]
 class BackupControllerRoute extends PageRouteInfo<void> {
   const BackupControllerRoute()
-      : super(BackupControllerRoute.name, path: '/backup-controller-page');
+      : super(
+          BackupControllerRoute.name,
+          path: '/backup-controller-page',
+        );
 
   static const String name = 'BackupControllerRoute';
 }
@@ -340,16 +556,26 @@ class BackupControllerRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [SearchResultPage]
 class SearchResultRoute extends PageRouteInfo<SearchResultRouteArgs> {
-  SearchResultRoute({Key? key, required String searchTerm})
-      : super(SearchResultRoute.name,
-            path: '/search-result-page',
-            args: SearchResultRouteArgs(key: key, searchTerm: searchTerm));
+  SearchResultRoute({
+    Key? key,
+    required String searchTerm,
+  }) : super(
+          SearchResultRoute.name,
+          path: '/search-result-page',
+          args: SearchResultRouteArgs(
+            key: key,
+            searchTerm: searchTerm,
+          ),
+        );
 
   static const String name = 'SearchResultRoute';
 }
 
 class SearchResultRouteArgs {
-  const SearchResultRouteArgs({this.key, required this.searchTerm});
+  const SearchResultRouteArgs({
+    this.key,
+    required this.searchTerm,
+  });
 
   final Key? key;
 
@@ -364,21 +590,29 @@ class SearchResultRouteArgs {
 /// generated route for
 /// [CreateAlbumPage]
 class CreateAlbumRoute extends PageRouteInfo<CreateAlbumRouteArgs> {
-  CreateAlbumRoute(
-      {Key? key, required bool isSharedAlbum, List<Asset>? initialAssets})
-      : super(CreateAlbumRoute.name,
-            path: '/create-album-page',
-            args: CreateAlbumRouteArgs(
-                key: key,
-                isSharedAlbum: isSharedAlbum,
-                initialAssets: initialAssets));
+  CreateAlbumRoute({
+    Key? key,
+    required bool isSharedAlbum,
+    List<Asset>? initialAssets,
+  }) : super(
+          CreateAlbumRoute.name,
+          path: '/create-album-page',
+          args: CreateAlbumRouteArgs(
+            key: key,
+            isSharedAlbum: isSharedAlbum,
+            initialAssets: initialAssets,
+          ),
+        );
 
   static const String name = 'CreateAlbumRoute';
 }
 
 class CreateAlbumRouteArgs {
-  const CreateAlbumRouteArgs(
-      {this.key, required this.isSharedAlbum, this.initialAssets});
+  const CreateAlbumRouteArgs({
+    this.key,
+    required this.isSharedAlbum,
+    this.initialAssets,
+  });
 
   final Key? key;
 
@@ -395,7 +629,11 @@ class CreateAlbumRouteArgs {
 /// generated route for
 /// [FavoritesPage]
 class FavoritesRoute extends PageRouteInfo<void> {
-  const FavoritesRoute() : super(FavoritesRoute.name, path: '/favorites-page');
+  const FavoritesRoute()
+      : super(
+          FavoritesRoute.name,
+          path: '/favorites-page',
+        );
 
   static const String name = 'FavoritesRoute';
 }
@@ -404,7 +642,10 @@ class FavoritesRoute extends PageRouteInfo<void> {
 /// [AssetSelectionPage]
 class AssetSelectionRoute extends PageRouteInfo<void> {
   const AssetSelectionRoute()
-      : super(AssetSelectionRoute.name, path: '/asset-selection-page');
+      : super(
+          AssetSelectionRoute.name,
+          path: '/asset-selection-page',
+        );
 
   static const String name = 'AssetSelectionRoute';
 }
@@ -413,8 +654,10 @@ class AssetSelectionRoute extends PageRouteInfo<void> {
 /// [SelectUserForSharingPage]
 class SelectUserForSharingRoute extends PageRouteInfo<void> {
   const SelectUserForSharingRoute()
-      : super(SelectUserForSharingRoute.name,
-            path: '/select-user-for-sharing-page');
+      : super(
+          SelectUserForSharingRoute.name,
+          path: '/select-user-for-sharing-page',
+        );
 
   static const String name = 'SelectUserForSharingRoute';
 }
@@ -422,16 +665,26 @@ class SelectUserForSharingRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [AlbumViewerPage]
 class AlbumViewerRoute extends PageRouteInfo<AlbumViewerRouteArgs> {
-  AlbumViewerRoute({Key? key, required String albumId})
-      : super(AlbumViewerRoute.name,
-            path: '/album-viewer-page',
-            args: AlbumViewerRouteArgs(key: key, albumId: albumId));
+  AlbumViewerRoute({
+    Key? key,
+    required String albumId,
+  }) : super(
+          AlbumViewerRoute.name,
+          path: '/album-viewer-page',
+          args: AlbumViewerRouteArgs(
+            key: key,
+            albumId: albumId,
+          ),
+        );
 
   static const String name = 'AlbumViewerRoute';
 }
 
 class AlbumViewerRouteArgs {
-  const AlbumViewerRouteArgs({this.key, required this.albumId});
+  const AlbumViewerRouteArgs({
+    this.key,
+    required this.albumId,
+  });
 
   final Key? key;
 
@@ -447,18 +700,26 @@ class AlbumViewerRouteArgs {
 /// [SelectAdditionalUserForSharingPage]
 class SelectAdditionalUserForSharingRoute
     extends PageRouteInfo<SelectAdditionalUserForSharingRouteArgs> {
-  SelectAdditionalUserForSharingRoute({Key? key, required Album album})
-      : super(SelectAdditionalUserForSharingRoute.name,
-            path: '/select-additional-user-for-sharing-page',
-            args: SelectAdditionalUserForSharingRouteArgs(
-                key: key, album: album));
+  SelectAdditionalUserForSharingRoute({
+    Key? key,
+    required Album album,
+  }) : super(
+          SelectAdditionalUserForSharingRoute.name,
+          path: '/select-additional-user-for-sharing-page',
+          args: SelectAdditionalUserForSharingRouteArgs(
+            key: key,
+            album: album,
+          ),
+        );
 
   static const String name = 'SelectAdditionalUserForSharingRoute';
 }
 
 class SelectAdditionalUserForSharingRouteArgs {
-  const SelectAdditionalUserForSharingRouteArgs(
-      {this.key, required this.album});
+  const SelectAdditionalUserForSharingRouteArgs({
+    this.key,
+    required this.album,
+  });
 
   final Key? key;
 
@@ -474,8 +735,10 @@ class SelectAdditionalUserForSharingRouteArgs {
 /// [BackupAlbumSelectionPage]
 class BackupAlbumSelectionRoute extends PageRouteInfo<void> {
   const BackupAlbumSelectionRoute()
-      : super(BackupAlbumSelectionRoute.name,
-            path: '/backup-album-selection-page');
+      : super(
+          BackupAlbumSelectionRoute.name,
+          path: '/backup-album-selection-page',
+        );
 
   static const String name = 'BackupAlbumSelectionRoute';
 }
@@ -483,16 +746,26 @@ class BackupAlbumSelectionRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [AlbumPreviewPage]
 class AlbumPreviewRoute extends PageRouteInfo<AlbumPreviewRouteArgs> {
-  AlbumPreviewRoute({Key? key, required AssetPathEntity album})
-      : super(AlbumPreviewRoute.name,
-            path: '/album-preview-page',
-            args: AlbumPreviewRouteArgs(key: key, album: album));
+  AlbumPreviewRoute({
+    Key? key,
+    required AssetPathEntity album,
+  }) : super(
+          AlbumPreviewRoute.name,
+          path: '/album-preview-page',
+          args: AlbumPreviewRouteArgs(
+            key: key,
+            album: album,
+          ),
+        );
 
   static const String name = 'AlbumPreviewRoute';
 }
 
 class AlbumPreviewRouteArgs {
-  const AlbumPreviewRouteArgs({this.key, required this.album});
+  const AlbumPreviewRouteArgs({
+    this.key,
+    required this.album,
+  });
 
   final Key? key;
 
@@ -508,7 +781,10 @@ class AlbumPreviewRouteArgs {
 /// [FailedBackupStatusPage]
 class FailedBackupStatusRoute extends PageRouteInfo<void> {
   const FailedBackupStatusRoute()
-      : super(FailedBackupStatusRoute.name, path: '/failed-backup-status-page');
+      : super(
+          FailedBackupStatusRoute.name,
+          path: '/failed-backup-status-page',
+        );
 
   static const String name = 'FailedBackupStatusRoute';
 }
@@ -516,7 +792,11 @@ class FailedBackupStatusRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [SettingsPage]
 class SettingsRoute extends PageRouteInfo<void> {
-  const SettingsRoute() : super(SettingsRoute.name, path: '/settings-page');
+  const SettingsRoute()
+      : super(
+          SettingsRoute.name,
+          path: '/settings-page',
+        );
 
   static const String name = 'SettingsRoute';
 }
@@ -524,7 +804,11 @@ class SettingsRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [AppLogPage]
 class AppLogRoute extends PageRouteInfo<void> {
-  const AppLogRoute() : super(AppLogRoute.name, path: '/app-log-page');
+  const AppLogRoute()
+      : super(
+          AppLogRoute.name,
+          path: '/app-log-page',
+        );
 
   static const String name = 'AppLogRoute';
 }
@@ -532,7 +816,11 @@ class AppLogRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [HomePage]
 class HomeRoute extends PageRouteInfo<void> {
-  const HomeRoute() : super(HomeRoute.name, path: 'home-page');
+  const HomeRoute()
+      : super(
+          HomeRoute.name,
+          path: 'home-page',
+        );
 
   static const String name = 'HomeRoute';
 }
@@ -541,8 +829,11 @@ class HomeRoute extends PageRouteInfo<void> {
 /// [SearchPage]
 class SearchRoute extends PageRouteInfo<SearchRouteArgs> {
   SearchRoute({Key? key})
-      : super(SearchRoute.name,
-            path: 'search-page', args: SearchRouteArgs(key: key));
+      : super(
+          SearchRoute.name,
+          path: 'search-page',
+          args: SearchRouteArgs(key: key),
+        );
 
   static const String name = 'SearchRoute';
 }
@@ -561,7 +852,11 @@ class SearchRouteArgs {
 /// generated route for
 /// [SharingPage]
 class SharingRoute extends PageRouteInfo<void> {
-  const SharingRoute() : super(SharingRoute.name, path: 'sharing-page');
+  const SharingRoute()
+      : super(
+          SharingRoute.name,
+          path: 'sharing-page',
+        );
 
   static const String name = 'SharingRoute';
 }
@@ -569,7 +864,11 @@ class SharingRoute extends PageRouteInfo<void> {
 /// generated route for
 /// [LibraryPage]
 class LibraryRoute extends PageRouteInfo<void> {
-  const LibraryRoute() : super(LibraryRoute.name, path: 'library-page');
+  const LibraryRoute()
+      : super(
+          LibraryRoute.name,
+          path: 'library-page',
+        );
 
   static const String name = 'LibraryRoute';
 }