mirror of
https://github.com/immich-app/immich.git
synced 2025-11-12 01:26:50 -05:00
add local media summary page
This commit is contained in:
parent
35c3f7211f
commit
1977458c79
@ -5,25 +5,31 @@ import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/providers/background_sync.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
|
||||
final _features = [
|
||||
_Feature(
|
||||
name: 'Sync Local',
|
||||
icon: Icons.photo_album_rounded,
|
||||
onTap: (ref) => ref.read(backgroundSyncProvider).syncLocal(),
|
||||
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncLocal(),
|
||||
),
|
||||
_Feature(
|
||||
name: 'Sync Remote',
|
||||
icon: Icons.refresh_rounded,
|
||||
onTap: (ref) => ref.read(backgroundSyncProvider).syncRemote(),
|
||||
onTap: (_, ref) => ref.read(backgroundSyncProvider).syncRemote(),
|
||||
),
|
||||
_Feature(
|
||||
name: 'WAL Checkpoint',
|
||||
icon: Icons.save_rounded,
|
||||
onTap: (ref) => ref
|
||||
onTap: (_, ref) => ref
|
||||
.read(driftProvider)
|
||||
.customStatement("pragma wal_checkpoint(truncate)"),
|
||||
),
|
||||
_Feature(
|
||||
name: 'Local Media Summary',
|
||||
icon: Icons.table_chart_rounded,
|
||||
onTap: (ctx, _) => ctx.pushRoute(const LocalMediaSummaryRoute()),
|
||||
),
|
||||
];
|
||||
|
||||
@RoutePage()
|
||||
@ -44,7 +50,7 @@ class FeatInDevPage extends StatelessWidget {
|
||||
builder: (ctx, ref, _) => ListTile(
|
||||
title: Text(feat.name),
|
||||
trailing: Icon(feat.icon),
|
||||
onTap: () => unawaited(feat.onTap(ref)),
|
||||
onTap: () => unawaited(feat.onTap(ctx, ref)),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -63,5 +69,5 @@ class _Feature {
|
||||
|
||||
final String name;
|
||||
final IconData icon;
|
||||
final Future<void> Function(WidgetRef _) onTap;
|
||||
final Future<void> Function(BuildContext, WidgetRef _) onTap;
|
||||
}
|
||||
|
||||
125
mobile/lib/presentation/pages/local_media_stat.page.dart
Normal file
125
mobile/lib/presentation/pages/local_media_stat.page.dart
Normal file
@ -0,0 +1,125 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/domain/models/local_album.model.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||
|
||||
final _stats = [
|
||||
_Stat(
|
||||
name: 'Local Assets',
|
||||
load: (db) => db.managers.localAssetEntity.count(),
|
||||
),
|
||||
_Stat(
|
||||
name: 'Local Albums',
|
||||
load: (db) => db.managers.localAlbumEntity.count(),
|
||||
),
|
||||
];
|
||||
|
||||
@RoutePage()
|
||||
class LocalMediaSummaryPage extends StatelessWidget {
|
||||
const LocalMediaSummaryPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Local Media Summary')),
|
||||
body: Consumer(
|
||||
builder: (ctx, ref, __) {
|
||||
final db = ref.watch(driftProvider);
|
||||
final albumsFuture = ref.watch(localAlbumRepository).getAll();
|
||||
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final stat = _stats[index];
|
||||
final countFuture = stat.load(db);
|
||||
return _Summary(name: stat.name, countFuture: countFuture);
|
||||
},
|
||||
itemCount: _stats.length,
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 15),
|
||||
child: Text(
|
||||
"Album summary",
|
||||
style: ctx.textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: albumsFuture,
|
||||
initialData: <LocalAlbum>[],
|
||||
builder: (_, snap) {
|
||||
final albums = snap.data!;
|
||||
if (albums.isEmpty) {
|
||||
return const SliverToBoxAdapter(child: SizedBox.shrink());
|
||||
}
|
||||
|
||||
albums.sortBy((a) => a.name);
|
||||
return SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final album = albums[index];
|
||||
final countFuture = db.managers.localAlbumAssetEntity
|
||||
.filter((f) => f.albumId.id.equals(album.id))
|
||||
.count();
|
||||
return _Summary(
|
||||
name: album.name,
|
||||
countFuture: countFuture,
|
||||
);
|
||||
},
|
||||
itemCount: albums.length,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ignore: prefer-single-widget-per-file
|
||||
class _Summary extends StatelessWidget {
|
||||
final String name;
|
||||
final Future<int> countFuture;
|
||||
|
||||
const _Summary({required this.name, required this.countFuture});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder<int>(
|
||||
future: countFuture,
|
||||
builder: (ctx, snapshot) {
|
||||
final Widget subtitle;
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
subtitle = const CircularProgressIndicator();
|
||||
} else if (snapshot.hasError) {
|
||||
subtitle = const Icon(Icons.error_rounded);
|
||||
} else {
|
||||
subtitle = Text('${snapshot.data ?? 0}');
|
||||
}
|
||||
return ListTile(title: Text(name), trailing: subtitle);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Stat {
|
||||
const _Stat({required this.name, required this.load});
|
||||
|
||||
final String name;
|
||||
final Future<int> Function(Drift _) load;
|
||||
}
|
||||
@ -62,6 +62,7 @@ import 'package:immich_mobile/pages/search/recently_taken.page.dart';
|
||||
import 'package:immich_mobile/pages/search/search.page.dart';
|
||||
import 'package:immich_mobile/pages/share_intent/share_intent.page.dart';
|
||||
import 'package:immich_mobile/presentation/pages/feat_in_development.page.dart';
|
||||
import 'package:immich_mobile/presentation/pages/local_media_stat.page.dart';
|
||||
import 'package:immich_mobile/providers/api.provider.dart';
|
||||
import 'package:immich_mobile/providers/gallery_permission.provider.dart';
|
||||
import 'package:immich_mobile/routing/auth_guard.dart';
|
||||
@ -294,6 +295,10 @@ class AppRouter extends RootStackRouter {
|
||||
page: FeatInDevRoute.page,
|
||||
guards: [_authGuard, _duplicateGuard],
|
||||
),
|
||||
AutoRoute(
|
||||
page: LocalMediaSummaryRoute.page,
|
||||
guards: [_authGuard, _duplicateGuard],
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@ -855,6 +855,22 @@ class LocalAlbumsRoute extends PageRouteInfo<void> {
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [LocalMediaSummaryPage]
|
||||
class LocalMediaSummaryRoute extends PageRouteInfo<void> {
|
||||
const LocalMediaSummaryRoute({List<PageRouteInfo>? children})
|
||||
: super(LocalMediaSummaryRoute.name, initialChildren: children);
|
||||
|
||||
static const String name = 'LocalMediaSummaryRoute';
|
||||
|
||||
static PageInfo page = PageInfo(
|
||||
name,
|
||||
builder: (data) {
|
||||
return const LocalMediaSummaryPage();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// generated route for
|
||||
/// [LoginPage]
|
||||
class LoginRoute extends PageRouteInfo<void> {
|
||||
|
||||
@ -179,7 +179,6 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
|
||||
child: action,
|
||||
),
|
||||
),
|
||||
if (kDebugMode)
|
||||
if (kDebugMode)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.science_rounded),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user