You've already forked immich
							
							
				mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 00:18:28 +02:00 
			
		
		
		
	* feat: delta sync * fix: ignore iCloud assets * feat: dev logs * add full sync button * remove photo_manager dep for sync * misc logs and fix * add time taken to DLog * fix: build release iOS * ios sync go brrr * rename local sync service * update isar fork * rename to platform assets / albums * fix ci check --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex <alex.tran1502@gmail.com>
		
			
				
	
	
		
			126 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
| 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;
 | |
| }
 |