mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	
							
								
								
									
										185
									
								
								mobile/lib/modules/backup/ui/album_info_card.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										185
									
								
								mobile/lib/modules/backup/ui/album_info_card.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,185 @@ | ||||
| import 'dart:typed_data'; | ||||
|  | ||||
| import 'package:auto_route/auto_route.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:flutter/services.dart'; | ||||
| import 'package:fluttertoast/fluttertoast.dart'; | ||||
| import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||||
| import 'package:immich_mobile/modules/backup/providers/backup.provider.dart'; | ||||
| import 'package:immich_mobile/routing/router.dart'; | ||||
| import 'package:immich_mobile/shared/ui/immich_toast.dart'; | ||||
| import 'package:photo_manager/photo_manager.dart'; | ||||
|  | ||||
| class AlbumInfoCard extends HookConsumerWidget { | ||||
|   final Uint8List? imageData; | ||||
|   final AssetPathEntity albumInfo; | ||||
|  | ||||
|   const AlbumInfoCard({Key? key, this.imageData, required this.albumInfo}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context, WidgetRef ref) { | ||||
|     final bool isSelected = ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo); | ||||
|     final bool isExcluded = ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo); | ||||
|  | ||||
|     ColorFilter selectedFilter = ColorFilter.mode(Theme.of(context).primaryColor.withAlpha(100), BlendMode.darken); | ||||
|     ColorFilter excludedFilter = ColorFilter.mode(Colors.red.withAlpha(75), BlendMode.darken); | ||||
|     ColorFilter unselectedFilter = const ColorFilter.mode(Colors.black, BlendMode.color); | ||||
|  | ||||
|     _buildSelectedTextBox() { | ||||
|       if (isSelected) { | ||||
|         return Chip( | ||||
|           visualDensity: VisualDensity.compact, | ||||
|           shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), | ||||
|           label: const Text( | ||||
|             "INCLUDED", | ||||
|             style: TextStyle(fontSize: 10, color: Colors.white, fontWeight: FontWeight.bold), | ||||
|           ), | ||||
|           backgroundColor: Theme.of(context).primaryColor, | ||||
|         ); | ||||
|       } else if (isExcluded) { | ||||
|         return Chip( | ||||
|           visualDensity: VisualDensity.compact, | ||||
|           shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)), | ||||
|           label: const Text( | ||||
|             "EXCLUDED", | ||||
|             style: TextStyle(fontSize: 10, color: Colors.white, fontWeight: FontWeight.bold), | ||||
|           ), | ||||
|           backgroundColor: Colors.red[300], | ||||
|         ); | ||||
|       } | ||||
|  | ||||
|       return Container(); | ||||
|     } | ||||
|  | ||||
|     _buildImageFilter() { | ||||
|       if (isSelected) { | ||||
|         return selectedFilter; | ||||
|       } else if (isExcluded) { | ||||
|         return excludedFilter; | ||||
|       } else { | ||||
|         return unselectedFilter; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return GestureDetector( | ||||
|       onTap: () { | ||||
|         HapticFeedback.selectionClick(); | ||||
|  | ||||
|         if (isSelected) { | ||||
|           if (ref.watch(backupProvider).selectedBackupAlbums.length == 1) { | ||||
|             ImmichToast.show( | ||||
|               context: context, | ||||
|               msg: "Cannot remove the only album", | ||||
|               toastType: ToastType.error, | ||||
|               gravity: ToastGravity.BOTTOM, | ||||
|             ); | ||||
|             return; | ||||
|           } | ||||
|  | ||||
|           ref.watch(backupProvider.notifier).removeAlbumForBackup(albumInfo); | ||||
|         } else { | ||||
|           ref.watch(backupProvider.notifier).addAlbumForBackup(albumInfo); | ||||
|         } | ||||
|       }, | ||||
|       onDoubleTap: () { | ||||
|         HapticFeedback.selectionClick(); | ||||
|  | ||||
|         if (isExcluded) { | ||||
|           ref.watch(backupProvider.notifier).removeExcludedAlbumForBackup(albumInfo); | ||||
|         } else { | ||||
|           if (ref.watch(backupProvider).selectedBackupAlbums.length == 1 && | ||||
|               ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo)) { | ||||
|             ImmichToast.show( | ||||
|               context: context, | ||||
|               msg: "Cannot exclude the only album", | ||||
|               toastType: ToastType.error, | ||||
|               gravity: ToastGravity.BOTTOM, | ||||
|             ); | ||||
|             return; | ||||
|           } | ||||
|  | ||||
|           ref.watch(backupProvider.notifier).addExcludedAlbumForBackup(albumInfo); | ||||
|         } | ||||
|       }, | ||||
|       child: Card( | ||||
|         margin: const EdgeInsets.all(1), | ||||
|         shape: RoundedRectangleBorder( | ||||
|           borderRadius: BorderRadius.circular(12), // if you need this | ||||
|           side: const BorderSide( | ||||
|             color: Color(0xFFC9C9C9), | ||||
|             width: 1, | ||||
|           ), | ||||
|         ), | ||||
|         elevation: 0, | ||||
|         borderOnForeground: false, | ||||
|         child: Column( | ||||
|           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|           children: [ | ||||
|             Stack( | ||||
|               children: [ | ||||
|                 Container( | ||||
|                   width: 200, | ||||
|                   height: 200, | ||||
|                   decoration: BoxDecoration( | ||||
|                     borderRadius: const BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)), | ||||
|                     image: DecorationImage( | ||||
|                       colorFilter: _buildImageFilter(), | ||||
|                       image: imageData != null | ||||
|                           ? MemoryImage(imageData!) | ||||
|                           : const AssetImage('assets/immich-logo-no-outline.png') as ImageProvider, | ||||
|                       fit: BoxFit.cover, | ||||
|                     ), | ||||
|                   ), | ||||
|                   child: null, | ||||
|                 ), | ||||
|                 Positioned(bottom: 10, left: 25, child: _buildSelectedTextBox()) | ||||
|               ], | ||||
|             ), | ||||
|             Padding( | ||||
|               padding: const EdgeInsets.only(top: 8.0), | ||||
|               child: Row( | ||||
|                 crossAxisAlignment: CrossAxisAlignment.center, | ||||
|                 children: [ | ||||
|                   SizedBox( | ||||
|                     width: 140, | ||||
|                     child: Padding( | ||||
|                       padding: const EdgeInsets.only(left: 25.0), | ||||
|                       child: Column( | ||||
|                         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                         children: [ | ||||
|                           Text( | ||||
|                             albumInfo.name, | ||||
|                             style: TextStyle( | ||||
|                                 fontSize: 14, color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold), | ||||
|                           ), | ||||
|                           Padding( | ||||
|                             padding: const EdgeInsets.only(top: 2.0), | ||||
|                             child: Text( | ||||
|                               albumInfo.assetCount.toString() + (albumInfo.isAll ? " (ALL)" : ""), | ||||
|                               style: TextStyle(fontSize: 12, color: Colors.grey[600]), | ||||
|                             ), | ||||
|                           ) | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|                   ), | ||||
|                   IconButton( | ||||
|                     onPressed: () { | ||||
|                       AutoRouter.of(context).push(AlbumPreviewRoute(album: albumInfo)); | ||||
|                     }, | ||||
|                     icon: Icon( | ||||
|                       Icons.image_outlined, | ||||
|                       color: Theme.of(context).primaryColor, | ||||
|                       size: 24, | ||||
|                     ), | ||||
|                     splashRadius: 25, | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										48
									
								
								mobile/lib/modules/backup/ui/backup_info_card.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								mobile/lib/modules/backup/ui/backup_info_card.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class BackupInfoCard extends StatelessWidget { | ||||
|   final String title; | ||||
|   final String subtitle; | ||||
|   final String info; | ||||
|   const BackupInfoCard({Key? key, required this.title, required this.subtitle, required this.info}) : super(key: key); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Card( | ||||
|       shape: RoundedRectangleBorder( | ||||
|         borderRadius: BorderRadius.circular(5), // if you need this | ||||
|         side: const BorderSide( | ||||
|           color: Colors.black12, | ||||
|           width: 1, | ||||
|         ), | ||||
|       ), | ||||
|       elevation: 0, | ||||
|       borderOnForeground: false, | ||||
|       child: ListTile( | ||||
|         minVerticalPadding: 15, | ||||
|         isThreeLine: true, | ||||
|         title: Text( | ||||
|           title, | ||||
|           style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 20), | ||||
|         ), | ||||
|         subtitle: Padding( | ||||
|           padding: const EdgeInsets.only(top: 8.0), | ||||
|           child: Text( | ||||
|             subtitle, | ||||
|             style: const TextStyle(color: Color(0xFF808080), fontSize: 12), | ||||
|           ), | ||||
|         ), | ||||
|         trailing: Column( | ||||
|           mainAxisAlignment: MainAxisAlignment.center, | ||||
|           children: [ | ||||
|             Text( | ||||
|               info, | ||||
|               style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold), | ||||
|             ), | ||||
|             const Text("assets"), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user