mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-02 18:59:15 -05:00 
			
		
		
		
	feat(mobile): improved logging page experience (#2158)
* feat(mobile): improve logging page * Use new API for share file * removed unused code * Better safe area on the home screen * Added preparing share dialog to home screen
This commit is contained in:
		
							parent
							
								
									2dcccb37a0
								
							
						
					
					
						commit
						d6f2ca6aaa
					
				@ -27,6 +27,7 @@ import 'package:immich_mobile/shared/providers/websocket.provider.dart';
 | 
				
			|||||||
import 'package:immich_mobile/shared/services/share.service.dart';
 | 
					import 'package:immich_mobile/shared/services/share.service.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
 | 
					import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
 | 
					import 'package:immich_mobile/shared/ui/immich_toast.dart';
 | 
				
			||||||
 | 
					import 'package:immich_mobile/shared/ui/share_dialog.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class HomePage extends HookConsumerWidget {
 | 
					class HomePage extends HookConsumerWidget {
 | 
				
			||||||
  const HomePage({Key? key}) : super(key: key);
 | 
					  const HomePage({Key? key}) : super(key: key);
 | 
				
			||||||
@ -81,7 +82,19 @@ class HomePage extends HookConsumerWidget {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      void onShareAssets() {
 | 
					      void onShareAssets() {
 | 
				
			||||||
        ref.watch(shareServiceProvider).shareAssets(selection.value.toList());
 | 
					        showDialog(
 | 
				
			||||||
 | 
					          context: context,
 | 
				
			||||||
 | 
					          builder: (BuildContext buildContext) {
 | 
				
			||||||
 | 
					            ref
 | 
				
			||||||
 | 
					                .watch(shareServiceProvider)
 | 
				
			||||||
 | 
					                .shareAssets(selection.value.toList())
 | 
				
			||||||
 | 
					                .then((_) => Navigator.of(buildContext).pop());
 | 
				
			||||||
 | 
					            return const ShareDialog();
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          barrierDismissible: false,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // ref.watch(shareServiceProvider).shareAssets(selection.value.toList());
 | 
				
			||||||
        selectionEnabledHook.value = false;
 | 
					        selectionEnabledHook.value = false;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -244,6 +257,7 @@ class HomePage extends HookConsumerWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      return SafeArea(
 | 
					      return SafeArea(
 | 
				
			||||||
        top: true,
 | 
					        top: true,
 | 
				
			||||||
 | 
					        bottom: false,
 | 
				
			||||||
        child: Stack(
 | 
					        child: Stack(
 | 
				
			||||||
          children: [
 | 
					          children: [
 | 
				
			||||||
            ref.watch(assetProvider).renderList == null ||
 | 
					            ref.watch(assetProvider).renderList == null ||
 | 
				
			||||||
@ -261,17 +275,14 @@ class HomePage extends HookConsumerWidget {
 | 
				
			|||||||
                    onRefresh: refreshAssets,
 | 
					                    onRefresh: refreshAssets,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
            if (selectionEnabledHook.value)
 | 
					            if (selectionEnabledHook.value)
 | 
				
			||||||
              SafeArea(
 | 
					              ControlBottomAppBar(
 | 
				
			||||||
                bottom: true,
 | 
					                onShare: onShareAssets,
 | 
				
			||||||
                child: ControlBottomAppBar(
 | 
					                onFavorite: onFavoriteAssets,
 | 
				
			||||||
                  onShare: onShareAssets,
 | 
					                onDelete: onDelete,
 | 
				
			||||||
                  onFavorite: onFavoriteAssets,
 | 
					                onAddToAlbum: onAddToAlbum,
 | 
				
			||||||
                  onDelete: onDelete,
 | 
					                albums: albums,
 | 
				
			||||||
                  onAddToAlbum: onAddToAlbum,
 | 
					                sharedAlbums: sharedAlbums,
 | 
				
			||||||
                  albums: albums,
 | 
					                onCreateNewAlbum: onCreateNewAlbum,
 | 
				
			||||||
                  sharedAlbums: sharedAlbums,
 | 
					 | 
				
			||||||
                  onCreateNewAlbum: onCreateNewAlbum,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
@ -279,9 +290,11 @@ class HomePage extends HookConsumerWidget {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: HomePageAppBar(
 | 
					      appBar: !selectionEnabledHook.value
 | 
				
			||||||
        onPopBack: reloadAllAsset,
 | 
					          ? HomePageAppBar(
 | 
				
			||||||
      ),
 | 
					              onPopBack: reloadAllAsset,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          : null,
 | 
				
			||||||
      drawer: const ProfileDrawer(),
 | 
					      drawer: const ProfileDrawer(),
 | 
				
			||||||
      body: buildBody(),
 | 
					      body: buildBody(),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
				
			|||||||
@ -34,8 +34,10 @@ import 'package:immich_mobile/routing/duplicate_guard.dart';
 | 
				
			|||||||
import 'package:immich_mobile/routing/gallery_permission_guard.dart';
 | 
					import 'package:immich_mobile/routing/gallery_permission_guard.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/models/asset.dart';
 | 
					import 'package:immich_mobile/shared/models/asset.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/models/album.dart';
 | 
					import 'package:immich_mobile/shared/models/album.dart';
 | 
				
			||||||
 | 
					import 'package:immich_mobile/shared/models/logger_message.model.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/providers/api.provider.dart';
 | 
					import 'package:immich_mobile/shared/providers/api.provider.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/services/api.service.dart';
 | 
					import 'package:immich_mobile/shared/services/api.service.dart';
 | 
				
			||||||
 | 
					import 'package:immich_mobile/shared/views/app_log_detail_page.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/views/app_log_page.dart';
 | 
					import 'package:immich_mobile/shared/views/app_log_page.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/views/splash_screen.dart';
 | 
					import 'package:immich_mobile/shared/views/splash_screen.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/views/tab_controller_page.dart';
 | 
					import 'package:immich_mobile/shared/views/tab_controller_page.dart';
 | 
				
			||||||
@ -47,8 +49,12 @@ part 'router.gr.dart';
 | 
				
			|||||||
  replaceInRouteName: 'Page,Route',
 | 
					  replaceInRouteName: 'Page,Route',
 | 
				
			||||||
  routes: <AutoRoute>[
 | 
					  routes: <AutoRoute>[
 | 
				
			||||||
    AutoRoute(page: SplashScreenPage, initial: true),
 | 
					    AutoRoute(page: SplashScreenPage, initial: true),
 | 
				
			||||||
    AutoRoute(page: PermissionOnboardingPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(
 | 
				
			||||||
    AutoRoute(page: LoginPage,
 | 
					      page: PermissionOnboardingPage,
 | 
				
			||||||
 | 
					      guards: [AuthGuard, DuplicateGuard],
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    AutoRoute(
 | 
				
			||||||
 | 
					      page: LoginPage,
 | 
				
			||||||
      guards: [
 | 
					      guards: [
 | 
				
			||||||
        DuplicateGuard,
 | 
					        DuplicateGuard,
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
@ -65,7 +71,10 @@ part 'router.gr.dart';
 | 
				
			|||||||
      ],
 | 
					      ],
 | 
				
			||||||
      transitionsBuilder: TransitionsBuilders.fadeIn,
 | 
					      transitionsBuilder: TransitionsBuilders.fadeIn,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    AutoRoute(page: GalleryViewerPage, guards: [AuthGuard, DuplicateGuard, GalleryPermissionGuard]),
 | 
					    AutoRoute(
 | 
				
			||||||
 | 
					      page: GalleryViewerPage,
 | 
				
			||||||
 | 
					      guards: [AuthGuard, DuplicateGuard, GalleryPermissionGuard],
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
    AutoRoute(page: VideoViewerPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: VideoViewerPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
    AutoRoute(page: BackupControllerPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: BackupControllerPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
    AutoRoute(page: SearchResultPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: SearchResultPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
@ -75,7 +84,10 @@ part 'router.gr.dart';
 | 
				
			|||||||
    AutoRoute(page: FavoritesPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: FavoritesPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
    AutoRoute(page: AllVideosPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: AllVideosPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
    AutoRoute(page: AllMotionPhotosPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: AllMotionPhotosPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
    AutoRoute(page: RecentlyAddedPage, guards: [AuthGuard, DuplicateGuard],),
 | 
					    AutoRoute(
 | 
				
			||||||
 | 
					      page: RecentlyAddedPage,
 | 
				
			||||||
 | 
					      guards: [AuthGuard, DuplicateGuard],
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
    CustomRoute<AssetSelectionPageResult?>(
 | 
					    CustomRoute<AssetSelectionPageResult?>(
 | 
				
			||||||
      page: AssetSelectionPage,
 | 
					      page: AssetSelectionPage,
 | 
				
			||||||
      guards: [AuthGuard, DuplicateGuard],
 | 
					      guards: [AuthGuard, DuplicateGuard],
 | 
				
			||||||
@ -92,14 +104,18 @@ part 'router.gr.dart';
 | 
				
			|||||||
      guards: [AuthGuard, DuplicateGuard],
 | 
					      guards: [AuthGuard, DuplicateGuard],
 | 
				
			||||||
      transitionsBuilder: TransitionsBuilders.slideBottom,
 | 
					      transitionsBuilder: TransitionsBuilders.slideBottom,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    AutoRoute(page: BackupAlbumSelectionPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(
 | 
				
			||||||
 | 
					      page: BackupAlbumSelectionPage,
 | 
				
			||||||
 | 
					      guards: [AuthGuard, DuplicateGuard],
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
    AutoRoute(page: AlbumPreviewPage, guards: [AuthGuard, DuplicateGuard]),
 | 
					    AutoRoute(page: AlbumPreviewPage, guards: [AuthGuard, DuplicateGuard]),
 | 
				
			||||||
    CustomRoute(
 | 
					    CustomRoute(
 | 
				
			||||||
      page: FailedBackupStatusPage,
 | 
					      page: FailedBackupStatusPage,
 | 
				
			||||||
      guards: [AuthGuard, DuplicateGuard],
 | 
					      guards: [AuthGuard, DuplicateGuard],
 | 
				
			||||||
      transitionsBuilder: TransitionsBuilders.slideBottom,
 | 
					      transitionsBuilder: TransitionsBuilders.slideBottom,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    AutoRoute(page: SettingsPage, 
 | 
					    AutoRoute(
 | 
				
			||||||
 | 
					      page: SettingsPage,
 | 
				
			||||||
      guards: [
 | 
					      guards: [
 | 
				
			||||||
        AuthGuard,
 | 
					        AuthGuard,
 | 
				
			||||||
        DuplicateGuard,
 | 
					        DuplicateGuard,
 | 
				
			||||||
@ -109,6 +125,9 @@ part 'router.gr.dart';
 | 
				
			|||||||
      page: AppLogPage,
 | 
					      page: AppLogPage,
 | 
				
			||||||
      transitionsBuilder: TransitionsBuilders.slideBottom,
 | 
					      transitionsBuilder: TransitionsBuilders.slideBottom,
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
 | 
					    AutoRoute(
 | 
				
			||||||
 | 
					      page: AppLogDetailPage,
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
  ],
 | 
					  ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
class AppRouter extends _$AppRouter {
 | 
					class AppRouter extends _$AppRouter {
 | 
				
			||||||
@ -118,12 +137,17 @@ class AppRouter extends _$AppRouter {
 | 
				
			|||||||
  AppRouter(
 | 
					  AppRouter(
 | 
				
			||||||
    this._apiService,
 | 
					    this._apiService,
 | 
				
			||||||
    GalleryPermissionNotifier galleryPermissionNotifier,
 | 
					    GalleryPermissionNotifier galleryPermissionNotifier,
 | 
				
			||||||
    ) : super(
 | 
					  ) : super(
 | 
				
			||||||
          authGuard: AuthGuard(_apiService),
 | 
					          authGuard: AuthGuard(_apiService),
 | 
				
			||||||
          duplicateGuard: DuplicateGuard(),
 | 
					          duplicateGuard: DuplicateGuard(),
 | 
				
			||||||
          galleryPermissionGuard: GalleryPermissionGuard(galleryPermissionNotifier),
 | 
					          galleryPermissionGuard:
 | 
				
			||||||
 | 
					              GalleryPermissionGuard(galleryPermissionNotifier),
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
final appRouterProvider =
 | 
					final appRouterProvider = Provider(
 | 
				
			||||||
    Provider((ref) => AppRouter(ref.watch(apiServiceProvider), ref.watch(galleryPermissionNotifier.notifier)));
 | 
					  (ref) => AppRouter(
 | 
				
			||||||
 | 
					    ref.watch(apiServiceProvider),
 | 
				
			||||||
 | 
					    ref.watch(galleryPermissionNotifier.notifier),
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
				
			|||||||
@ -230,6 +230,16 @@ class _$AppRouter extends RootStackRouter {
 | 
				
			|||||||
        barrierDismissible: false,
 | 
					        barrierDismissible: false,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    AppLogDetailRoute.name: (routeData) {
 | 
				
			||||||
 | 
					      final args = routeData.argsAs<AppLogDetailRouteArgs>();
 | 
				
			||||||
 | 
					      return MaterialPageX<dynamic>(
 | 
				
			||||||
 | 
					        routeData: routeData,
 | 
				
			||||||
 | 
					        child: AppLogDetailPage(
 | 
				
			||||||
 | 
					          key: args.key,
 | 
				
			||||||
 | 
					          logMessage: args.logMessage,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    HomeRoute.name: (routeData) {
 | 
					    HomeRoute.name: (routeData) {
 | 
				
			||||||
      return MaterialPageX<dynamic>(
 | 
					      return MaterialPageX<dynamic>(
 | 
				
			||||||
        routeData: routeData,
 | 
					        routeData: routeData,
 | 
				
			||||||
@ -485,6 +495,10 @@ class _$AppRouter extends RootStackRouter {
 | 
				
			|||||||
          AppLogRoute.name,
 | 
					          AppLogRoute.name,
 | 
				
			||||||
          path: '/app-log-page',
 | 
					          path: '/app-log-page',
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					        RouteConfig(
 | 
				
			||||||
 | 
					          AppLogDetailRoute.name,
 | 
				
			||||||
 | 
					          path: '/app-log-detail-page',
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
      ];
 | 
					      ];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -974,6 +988,40 @@ class AppLogRoute extends PageRouteInfo<void> {
 | 
				
			|||||||
  static const String name = 'AppLogRoute';
 | 
					  static const String name = 'AppLogRoute';
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// generated route for
 | 
				
			||||||
 | 
					/// [AppLogDetailPage]
 | 
				
			||||||
 | 
					class AppLogDetailRoute extends PageRouteInfo<AppLogDetailRouteArgs> {
 | 
				
			||||||
 | 
					  AppLogDetailRoute({
 | 
				
			||||||
 | 
					    Key? key,
 | 
				
			||||||
 | 
					    required LoggerMessage logMessage,
 | 
				
			||||||
 | 
					  }) : super(
 | 
				
			||||||
 | 
					          AppLogDetailRoute.name,
 | 
				
			||||||
 | 
					          path: '/app-log-detail-page',
 | 
				
			||||||
 | 
					          args: AppLogDetailRouteArgs(
 | 
				
			||||||
 | 
					            key: key,
 | 
				
			||||||
 | 
					            logMessage: logMessage,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const String name = 'AppLogDetailRoute';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AppLogDetailRouteArgs {
 | 
				
			||||||
 | 
					  const AppLogDetailRouteArgs({
 | 
				
			||||||
 | 
					    this.key,
 | 
				
			||||||
 | 
					    required this.logMessage,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final Key? key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final LoggerMessage logMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return 'AppLogDetailRouteArgs{key: $key, logMessage: $logMessage}';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// generated route for
 | 
					/// generated route for
 | 
				
			||||||
/// [HomePage]
 | 
					/// [HomePage]
 | 
				
			||||||
class HomeRoute extends PageRouteInfo<void> {
 | 
					class HomeRoute extends PageRouteInfo<void> {
 | 
				
			||||||
 | 
				
			|||||||
@ -102,15 +102,13 @@ class ImmichLogger {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Share file
 | 
					    // Share file
 | 
				
			||||||
    // ignore: deprecated_member_use
 | 
					    await Share.shareXFiles(
 | 
				
			||||||
    await Share.shareFiles(
 | 
					      [XFile(filePath)],
 | 
				
			||||||
      [filePath],
 | 
					 | 
				
			||||||
      subject: "Immich logs $dateTime",
 | 
					      subject: "Immich logs $dateTime",
 | 
				
			||||||
      sharePositionOrigin: Rect.zero,
 | 
					      sharePositionOrigin: Rect.zero,
 | 
				
			||||||
 | 
					    ).then(
 | 
				
			||||||
 | 
					      (value) => logFile.delete(),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Clean up temp file
 | 
					 | 
				
			||||||
    await logFile.delete();
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Flush pending log messages to persistent storage
 | 
					  /// Flush pending log messages to persistent storage
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,6 @@ class ShareService {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ignore: deprecated_member_use
 | 
					 | 
				
			||||||
    Share.shareXFiles(
 | 
					    Share.shareXFiles(
 | 
				
			||||||
      await Future.wait(downloadedXFiles),
 | 
					      await Future.wait(downloadedXFiles),
 | 
				
			||||||
      sharePositionOrigin: Rect.zero,
 | 
					      sharePositionOrigin: Rect.zero,
 | 
				
			||||||
 | 
				
			|||||||
@ -369,7 +369,6 @@ class SyncService {
 | 
				
			|||||||
    List<AssetPathEntity> onDevice, [
 | 
					    List<AssetPathEntity> onDevice, [
 | 
				
			||||||
    Set<String>? excludedAssets,
 | 
					    Set<String>? excludedAssets,
 | 
				
			||||||
  ]) async {
 | 
					  ]) async {
 | 
				
			||||||
    _log.info("Syncing ${onDevice.length} albums from device: $onDevice");
 | 
					 | 
				
			||||||
    onDevice.sort((a, b) => a.id.compareTo(b.id));
 | 
					    onDevice.sort((a, b) => a.id.compareTo(b.id));
 | 
				
			||||||
    final List<Album> inDb =
 | 
					    final List<Album> inDb =
 | 
				
			||||||
        await _db.albums.where().localIdIsNotNull().sortByLocalId().findAll();
 | 
					        await _db.albums.where().localIdIsNotNull().sortByLocalId().findAll();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										190
									
								
								mobile/lib/shared/views/app_log_detail_page.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								mobile/lib/shared/views/app_log_detail_page.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
				
			||||||
 | 
					import 'package:immich_mobile/shared/models/logger_message.model.dart';
 | 
				
			||||||
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AppLogDetailPage extends HookConsumerWidget {
 | 
				
			||||||
 | 
					  const AppLogDetailPage({super.key, required this.logMessage});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final LoggerMessage logMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context, WidgetRef ref) {
 | 
				
			||||||
 | 
					    var isDarkMode = Theme.of(context).brightness == Brightness.dark;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buildStackMessage(String stackTrace) {
 | 
				
			||||||
 | 
					      return Padding(
 | 
				
			||||||
 | 
					        padding: const EdgeInsets.all(8.0),
 | 
				
			||||||
 | 
					        child: Column(
 | 
				
			||||||
 | 
					          crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
 | 
					          children: [
 | 
				
			||||||
 | 
					            Row(
 | 
				
			||||||
 | 
					              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
				
			||||||
 | 
					              crossAxisAlignment: CrossAxisAlignment.center,
 | 
				
			||||||
 | 
					              children: [
 | 
				
			||||||
 | 
					                Padding(
 | 
				
			||||||
 | 
					                  padding: const EdgeInsets.only(bottom: 8.0),
 | 
				
			||||||
 | 
					                  child: Text(
 | 
				
			||||||
 | 
					                    "STACK TRACES",
 | 
				
			||||||
 | 
					                    style: TextStyle(
 | 
				
			||||||
 | 
					                      fontSize: 12.0,
 | 
				
			||||||
 | 
					                      color: Theme.of(context).primaryColor,
 | 
				
			||||||
 | 
					                      fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                IconButton(
 | 
				
			||||||
 | 
					                  onPressed: () {
 | 
				
			||||||
 | 
					                    Clipboard.setData(ClipboardData(text: stackTrace))
 | 
				
			||||||
 | 
					                        .then((_) {
 | 
				
			||||||
 | 
					                      ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
 | 
					                        const SnackBar(content: Text("Copied to clipboard")),
 | 
				
			||||||
 | 
					                      );
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  icon: Icon(
 | 
				
			||||||
 | 
					                    Icons.copy,
 | 
				
			||||||
 | 
					                    size: 16.0,
 | 
				
			||||||
 | 
					                    color: Theme.of(context).primaryColor,
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Container(
 | 
				
			||||||
 | 
					              decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
 | 
				
			||||||
 | 
					                borderRadius: BorderRadius.circular(15.0),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              child: Padding(
 | 
				
			||||||
 | 
					                padding: const EdgeInsets.all(8.0),
 | 
				
			||||||
 | 
					                child: SelectableText(
 | 
				
			||||||
 | 
					                  stackTrace,
 | 
				
			||||||
 | 
					                  style: const TextStyle(
 | 
				
			||||||
 | 
					                    fontSize: 12.0,
 | 
				
			||||||
 | 
					                    fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                    fontFamily: "Inconsolata",
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buildLogMessage(String message) {
 | 
				
			||||||
 | 
					      return Padding(
 | 
				
			||||||
 | 
					        padding: const EdgeInsets.all(8.0),
 | 
				
			||||||
 | 
					        child: Column(
 | 
				
			||||||
 | 
					          crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
 | 
					          children: [
 | 
				
			||||||
 | 
					            Row(
 | 
				
			||||||
 | 
					              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
				
			||||||
 | 
					              crossAxisAlignment: CrossAxisAlignment.center,
 | 
				
			||||||
 | 
					              children: [
 | 
				
			||||||
 | 
					                Padding(
 | 
				
			||||||
 | 
					                  padding: const EdgeInsets.only(bottom: 8.0),
 | 
				
			||||||
 | 
					                  child: Text(
 | 
				
			||||||
 | 
					                    "MESSAGE",
 | 
				
			||||||
 | 
					                    style: TextStyle(
 | 
				
			||||||
 | 
					                      fontSize: 12.0,
 | 
				
			||||||
 | 
					                      color: Theme.of(context).primaryColor,
 | 
				
			||||||
 | 
					                      fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                IconButton(
 | 
				
			||||||
 | 
					                  onPressed: () {
 | 
				
			||||||
 | 
					                    Clipboard.setData(ClipboardData(text: message)).then((_) {
 | 
				
			||||||
 | 
					                      ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
 | 
					                        const SnackBar(content: Text("Copied to clipboard")),
 | 
				
			||||||
 | 
					                      );
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  icon: Icon(
 | 
				
			||||||
 | 
					                    Icons.copy,
 | 
				
			||||||
 | 
					                    size: 16.0,
 | 
				
			||||||
 | 
					                    color: Theme.of(context).primaryColor,
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Container(
 | 
				
			||||||
 | 
					              decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
 | 
				
			||||||
 | 
					                borderRadius: BorderRadius.circular(15.0),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              child: Padding(
 | 
				
			||||||
 | 
					                padding: const EdgeInsets.all(8.0),
 | 
				
			||||||
 | 
					                child: SelectableText(
 | 
				
			||||||
 | 
					                  message,
 | 
				
			||||||
 | 
					                  style: const TextStyle(
 | 
				
			||||||
 | 
					                    fontSize: 12.0,
 | 
				
			||||||
 | 
					                    fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                    fontFamily: "Inconsolata",
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    buildLogContext1(String context1) {
 | 
				
			||||||
 | 
					      return Padding(
 | 
				
			||||||
 | 
					        padding: const EdgeInsets.all(8.0),
 | 
				
			||||||
 | 
					        child: Column(
 | 
				
			||||||
 | 
					          crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
 | 
					          children: [
 | 
				
			||||||
 | 
					            Padding(
 | 
				
			||||||
 | 
					              padding: const EdgeInsets.only(bottom: 8.0),
 | 
				
			||||||
 | 
					              child: Text(
 | 
				
			||||||
 | 
					                "FROM",
 | 
				
			||||||
 | 
					                style: TextStyle(
 | 
				
			||||||
 | 
					                  fontSize: 12.0,
 | 
				
			||||||
 | 
					                  color: Theme.of(context).primaryColor,
 | 
				
			||||||
 | 
					                  fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            Container(
 | 
				
			||||||
 | 
					              decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                color: isDarkMode ? Colors.grey[900] : Colors.grey[200],
 | 
				
			||||||
 | 
					                borderRadius: BorderRadius.circular(15.0),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              child: Padding(
 | 
				
			||||||
 | 
					                padding: const EdgeInsets.all(8.0),
 | 
				
			||||||
 | 
					                child: SelectableText(
 | 
				
			||||||
 | 
					                  context1.toString(),
 | 
				
			||||||
 | 
					                  style: const TextStyle(
 | 
				
			||||||
 | 
					                    fontSize: 12.0,
 | 
				
			||||||
 | 
					                    fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					                    fontFamily: "Inconsolata",
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Scaffold(
 | 
				
			||||||
 | 
					      appBar: AppBar(
 | 
				
			||||||
 | 
					        title: const Text("Log Detail"),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      body: SafeArea(
 | 
				
			||||||
 | 
					        child: ListView(
 | 
				
			||||||
 | 
					          children: [
 | 
				
			||||||
 | 
					            buildLogMessage(logMessage.message),
 | 
				
			||||||
 | 
					            if (logMessage.context1 != null)
 | 
				
			||||||
 | 
					              buildLogContext1(logMessage.context1.toString()),
 | 
				
			||||||
 | 
					            if (logMessage.context2 != null)
 | 
				
			||||||
 | 
					              buildStackMessage(logMessage.context2.toString())
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter_hooks/flutter_hooks.dart';
 | 
					import 'package:flutter_hooks/flutter_hooks.dart';
 | 
				
			||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
					import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
				
			||||||
 | 
					import 'package:immich_mobile/routing/router.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/models/logger_message.model.dart';
 | 
					import 'package:immich_mobile/shared/models/logger_message.model.dart';
 | 
				
			||||||
import 'package:immich_mobile/shared/services/immich_logger.service.dart';
 | 
					import 'package:immich_mobile/shared/services/immich_logger.service.dart';
 | 
				
			||||||
import 'package:intl/intl.dart';
 | 
					import 'package:intl/intl.dart';
 | 
				
			||||||
@ -123,6 +124,12 @@ class AppLogPage extends HookConsumerWidget {
 | 
				
			|||||||
        itemBuilder: (context, index) {
 | 
					        itemBuilder: (context, index) {
 | 
				
			||||||
          var logMessage = logMessages.value[index];
 | 
					          var logMessage = logMessages.value[index];
 | 
				
			||||||
          return ListTile(
 | 
					          return ListTile(
 | 
				
			||||||
 | 
					            onTap: () => AutoRouter.of(context).push(
 | 
				
			||||||
 | 
					              AppLogDetailRoute(
 | 
				
			||||||
 | 
					                logMessage: logMessage,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            trailing: const Icon(Icons.arrow_forward_ios_rounded),
 | 
				
			||||||
            visualDensity: VisualDensity.compact,
 | 
					            visualDensity: VisualDensity.compact,
 | 
				
			||||||
            dense: true,
 | 
					            dense: true,
 | 
				
			||||||
            tileColor: getTileColor(logMessage.level),
 | 
					            tileColor: getTileColor(logMessage.level),
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user