mirror of
https://github.com/immich-app/immich.git
synced 2025-12-23 17:25:11 +03:00
refactor(mobile): backup album selection (#8053)
* feat(mobile): include album with 0 assets as album option for backup * Show icon instead of thumbnail * Handle backupProgress state transition correctly to always load the backup info * remove todo comment
This commit is contained in:
@@ -11,17 +11,16 @@ import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||
|
||||
class AlbumInfoCard extends HookConsumerWidget {
|
||||
final Uint8List? imageData;
|
||||
final AvailableAlbum albumInfo;
|
||||
final AvailableAlbum album;
|
||||
|
||||
const AlbumInfoCard({super.key, this.imageData, required this.albumInfo});
|
||||
const AlbumInfoCard({super.key, required this.album});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bool isSelected =
|
||||
ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo);
|
||||
ref.watch(backupProvider).selectedBackupAlbums.contains(album);
|
||||
final bool isExcluded =
|
||||
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
|
||||
ref.watch(backupProvider).excludedBackupAlbums.contains(album);
|
||||
final isDarkTheme = context.isDarkTheme;
|
||||
|
||||
ColorFilter selectedFilter = ColorFilter.mode(
|
||||
@@ -82,9 +81,9 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
HapticFeedback.selectionClick();
|
||||
|
||||
if (isSelected) {
|
||||
ref.read(backupProvider.notifier).removeAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).removeAlbumForBackup(album);
|
||||
} else {
|
||||
ref.read(backupProvider.notifier).addAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).addAlbumForBackup(album);
|
||||
}
|
||||
},
|
||||
onDoubleTap: () {
|
||||
@@ -92,13 +91,11 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
|
||||
if (isExcluded) {
|
||||
// Remove from exclude album list
|
||||
ref
|
||||
.read(backupProvider.notifier)
|
||||
.removeExcludedAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).removeExcludedAlbumForBackup(album);
|
||||
} else {
|
||||
// Add to exclude album list
|
||||
|
||||
if (albumInfo.id == 'isAll' || albumInfo.name == 'Recents') {
|
||||
if (album.id == 'isAll' || album.name == 'Recents') {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'Cannot exclude album contains all assets',
|
||||
@@ -108,9 +105,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
ref
|
||||
.read(backupProvider.notifier)
|
||||
.addExcludedAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).addExcludedAlbumForBackup(album);
|
||||
}
|
||||
},
|
||||
child: Card(
|
||||
@@ -136,14 +131,12 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
children: [
|
||||
ColorFiltered(
|
||||
colorFilter: buildImageFilter(),
|
||||
child: Image(
|
||||
child: const Image(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
image: imageData != null
|
||||
? MemoryImage(imageData!)
|
||||
: const AssetImage(
|
||||
'assets/immich-logo.png',
|
||||
) as ImageProvider,
|
||||
image: AssetImage(
|
||||
'assets/immich-logo.png',
|
||||
),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
@@ -168,7 +161,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
albumInfo.name,
|
||||
album.name,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: context.primaryColor,
|
||||
@@ -182,7 +175,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
if (snapshot.hasData) {
|
||||
return Text(
|
||||
snapshot.data.toString() +
|
||||
(albumInfo.isAll
|
||||
(album.isAll
|
||||
? " (${'backup_all'.tr()})"
|
||||
: ""),
|
||||
style: TextStyle(
|
||||
@@ -193,7 +186,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
}
|
||||
return const Text("0");
|
||||
}),
|
||||
future: albumInfo.assetCount,
|
||||
future: album.assetCount,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -202,7 +195,7 @@ class AlbumInfoCard extends HookConsumerWidget {
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
context.pushRoute(
|
||||
AlbumPreviewRoute(album: albumInfo.albumEntity),
|
||||
AlbumPreviewRoute(album: album.albumEntity),
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
|
||||
@@ -11,47 +11,26 @@ import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||
|
||||
class AlbumInfoListTile extends HookConsumerWidget {
|
||||
final Uint8List? imageData;
|
||||
final AvailableAlbum albumInfo;
|
||||
final AvailableAlbum album;
|
||||
|
||||
const AlbumInfoListTile({super.key, this.imageData, required this.albumInfo});
|
||||
const AlbumInfoListTile({super.key, required this.album});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bool isSelected =
|
||||
ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo);
|
||||
ref.watch(backupProvider).selectedBackupAlbums.contains(album);
|
||||
final bool isExcluded =
|
||||
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
|
||||
|
||||
ColorFilter selectedFilter = ColorFilter.mode(
|
||||
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);
|
||||
|
||||
ref.watch(backupProvider).excludedBackupAlbums.contains(album);
|
||||
var assetCount = useState(0);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
albumInfo.assetCount.then((value) => assetCount.value = value);
|
||||
album.assetCount.then((value) => assetCount.value = value);
|
||||
return null;
|
||||
},
|
||||
[albumInfo],
|
||||
[album],
|
||||
);
|
||||
|
||||
buildImageFilter() {
|
||||
if (isSelected) {
|
||||
return selectedFilter;
|
||||
} else if (isExcluded) {
|
||||
return excludedFilter;
|
||||
} else {
|
||||
return unselectedFilter;
|
||||
}
|
||||
}
|
||||
|
||||
buildTileColor() {
|
||||
if (isSelected) {
|
||||
return context.isDarkTheme
|
||||
@@ -66,19 +45,38 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
buildIcon() {
|
||||
if (isSelected) {
|
||||
return const Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: Colors.green,
|
||||
);
|
||||
}
|
||||
|
||||
if (isExcluded) {
|
||||
return const Icon(
|
||||
Icons.remove_circle_rounded,
|
||||
color: Colors.red,
|
||||
);
|
||||
}
|
||||
|
||||
return Icon(
|
||||
Icons.circle,
|
||||
color: context.isDarkTheme ? Colors.grey[400] : Colors.black45,
|
||||
);
|
||||
}
|
||||
|
||||
return GestureDetector(
|
||||
onDoubleTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
|
||||
if (isExcluded) {
|
||||
// Remove from exclude album list
|
||||
ref
|
||||
.read(backupProvider.notifier)
|
||||
.removeExcludedAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).removeExcludedAlbumForBackup(album);
|
||||
} else {
|
||||
// Add to exclude album list
|
||||
|
||||
if (albumInfo.id == 'isAll' || albumInfo.name == 'Recents') {
|
||||
if (album.id == 'isAll' || album.name == 'Recents') {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'Cannot exclude album contains all assets',
|
||||
@@ -88,9 +86,7 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
||||
return;
|
||||
}
|
||||
|
||||
ref
|
||||
.read(backupProvider.notifier)
|
||||
.addExcludedAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).addExcludedAlbumForBackup(album);
|
||||
}
|
||||
},
|
||||
child: ListTile(
|
||||
@@ -99,33 +95,14 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
if (isSelected) {
|
||||
ref.read(backupProvider.notifier).removeAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).removeAlbumForBackup(album);
|
||||
} else {
|
||||
ref.read(backupProvider.notifier).addAlbumForBackup(albumInfo);
|
||||
ref.read(backupProvider.notifier).addAlbumForBackup(album);
|
||||
}
|
||||
},
|
||||
leading: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: SizedBox(
|
||||
height: 80,
|
||||
width: 80,
|
||||
child: ColorFiltered(
|
||||
colorFilter: buildImageFilter(),
|
||||
child: Image(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
image: imageData != null
|
||||
? MemoryImage(imageData!)
|
||||
: const AssetImage(
|
||||
'assets/immich-logo.png',
|
||||
) as ImageProvider,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
leading: buildIcon(),
|
||||
title: Text(
|
||||
albumInfo.name,
|
||||
album.name,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
@@ -135,7 +112,7 @@ class AlbumInfoListTile extends HookConsumerWidget {
|
||||
trailing: IconButton(
|
||||
onPressed: () {
|
||||
context.pushRoute(
|
||||
AlbumPreviewRoute(album: albumInfo.albumEntity),
|
||||
AlbumPreviewRoute(album: album.albumEntity),
|
||||
);
|
||||
},
|
||||
icon: Icon(
|
||||
|
||||
Reference in New Issue
Block a user