mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
feat(mobile): Archive feature on mobile (#2258)
* update asset to include isArchive property * Not display archived assets on timeline * replace share button to archive button * Added archive page * Add bottom nav bar * clean up homepage * remove deadcode * improve on sync is archive * show archive asset correctly * better merge condition * Added back renderList to re-rendering don't jump around * Better way to handle showing archive assets * complete ArchiveSelectionNotifier * toggle archive * remove deadcode * fix unit tests * update assets in DB when changing assets * update asset state to reflect archived status * allow to archive assets via multi-select from timeline * fixed logic * Add options to bulk unarchive * regenerate api * Change position of toast message --------- Co-authored-by: Fynn Petersen-Frey <zoodyy@users.noreply.github.com>
This commit is contained in:
parent
635eee9e5e
commit
2e5cd986dd
27 changed files with 523 additions and 114 deletions
|
|
@ -51,14 +51,14 @@ class AddToAlbumBottomSheet extends HookConsumerWidget {
|
|||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'add_to_album_bottom_sheet_already_exists'.tr(
|
||||
namedArgs: { "album": album.name },
|
||||
namedArgs: {"album": album.name},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'add_to_album_bottom_sheet_added'.tr(
|
||||
namedArgs: { "album": album.name },
|
||||
namedArgs: {"album": album.name},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ class AddToAlbumBottomSheet extends HookConsumerWidget {
|
|||
}
|
||||
|
||||
return Card(
|
||||
elevation: 0,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(15),
|
||||
|
|
@ -99,8 +100,15 @@ class AddToAlbumBottomSheet extends HookConsumerWidget {
|
|||
style: Theme.of(context).textTheme.displayMedium,
|
||||
),
|
||||
TextButton.icon(
|
||||
icon: const Icon(Icons.add),
|
||||
label: Text('common_create_new_album'.tr()),
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
color: Theme.of(context).primaryColor,
|
||||
),
|
||||
label: Text(
|
||||
'common_create_new_album'.tr(),
|
||||
style:
|
||||
TextStyle(color: Theme.of(context).primaryColor),
|
||||
),
|
||||
onPressed: () {
|
||||
ref
|
||||
.watch(assetSelectionProvider.notifier)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,8 @@ class LibraryPage extends HookConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
final selectedAlbumSortOrder = useState(settings.getSetting(AppSettingsEnum.selectedAlbumSortOrder));
|
||||
final selectedAlbumSortOrder =
|
||||
useState(settings.getSetting(AppSettingsEnum.selectedAlbumSortOrder));
|
||||
|
||||
List<Album> sortedAlbums() {
|
||||
if (selectedAlbumSortOrder.value == 0) {
|
||||
|
|
@ -179,13 +180,13 @@ class LibraryPage extends HookConsumerWidget {
|
|||
label,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12.0,
|
||||
color: isDarkMode ? Colors.white : Colors.black,
|
||||
fontSize: 13.0,
|
||||
color: isDarkMode ? Colors.white : Colors.grey[800],
|
||||
),
|
||||
),
|
||||
),
|
||||
style: OutlinedButton.styleFrom(
|
||||
padding: const EdgeInsets.all(12),
|
||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||
backgroundColor: isDarkMode ? Colors.grey[900] : Colors.grey[50],
|
||||
side: BorderSide(
|
||||
color: isDarkMode ? Colors.grey[800]! : Colors.grey[300]!,
|
||||
|
|
@ -225,8 +226,8 @@ class LibraryPage extends HookConsumerWidget {
|
|||
}),
|
||||
const SizedBox(width: 12.0),
|
||||
buildLibraryNavButton(
|
||||
"library_page_sharing".tr(), Icons.group_outlined, () {
|
||||
AutoRouter.of(context).navigate(const SharingRoute());
|
||||
"library_page_archive".tr(), Icons.archive_outlined, () {
|
||||
AutoRouter.of(context).navigate(const ArchiveRoute());
|
||||
}),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
0
mobile/lib/modules/archive/models/store_model_here.txt
Normal file
0
mobile/lib/modules/archive/models/store_model_here.txt
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class ArchiveSelectionNotifier extends StateNotifier<Set<int>> {
|
||||
ArchiveSelectionNotifier(this.db, this.assetNotifier) : super({}) {
|
||||
state = db.assets
|
||||
.filter()
|
||||
.isArchivedEqualTo(true)
|
||||
.findAllSync()
|
||||
.map((e) => e.id)
|
||||
.toSet();
|
||||
}
|
||||
|
||||
final Isar db;
|
||||
final AssetNotifier assetNotifier;
|
||||
|
||||
void _setArchiveForAssetId(int id, bool archive) {
|
||||
if (!archive) {
|
||||
state = state.difference({id});
|
||||
} else {
|
||||
state = state.union({id});
|
||||
}
|
||||
}
|
||||
|
||||
bool _isArchive(int id) {
|
||||
return state.contains(id);
|
||||
}
|
||||
|
||||
Future<void> toggleArchive(Asset asset) async {
|
||||
if (!asset.isRemote) return;
|
||||
|
||||
_setArchiveForAssetId(asset.id, !_isArchive(asset.id));
|
||||
|
||||
await assetNotifier.toggleArchive(
|
||||
[asset],
|
||||
state.contains(asset.id),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> addToArchives(Iterable<Asset> assets) {
|
||||
state = state.union(assets.map((a) => a.id).toSet());
|
||||
return assetNotifier.toggleArchive(assets, true);
|
||||
}
|
||||
}
|
||||
|
||||
final archiveProvider =
|
||||
StateNotifierProvider<ArchiveSelectionNotifier, Set<int>>((ref) {
|
||||
return ArchiveSelectionNotifier(
|
||||
ref.watch(dbProvider),
|
||||
ref.watch(assetProvider.notifier),
|
||||
);
|
||||
});
|
||||
0
mobile/lib/modules/archive/ui/store_ui_here.txt
Normal file
0
mobile/lib/modules/archive/ui/store_ui_here.txt
Normal file
124
mobile/lib/modules/archive/views/archive_page.dart
Normal file
124
mobile/lib/modules/archive/views/archive_page.dart
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/models/store.dart';
|
||||
import 'package:immich_mobile/shared/models/user.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||
import 'package:immich_mobile/shared/ui/immich_toast.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class ArchivePage extends HookConsumerWidget {
|
||||
const ArchivePage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final User me = Store.get(StoreKey.currentUser);
|
||||
final query = ref
|
||||
.watch(dbProvider)
|
||||
.assets
|
||||
.filter()
|
||||
.ownerIdEqualTo(me.isarId)
|
||||
.isArchivedEqualTo(true);
|
||||
final stream = query.watch();
|
||||
final archivedAssets = useState<List<Asset>>([]);
|
||||
final selectionEnabledHook = useState(false);
|
||||
final selection = useState(<Asset>{});
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
query.findAll().then((value) => archivedAssets.value = value);
|
||||
final subscription = stream.listen((e) {
|
||||
archivedAssets.value = e;
|
||||
});
|
||||
// Cancel the subscription when the widget is disposed
|
||||
return subscription.cancel;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
void selectionListener(
|
||||
bool multiselect,
|
||||
Set<Asset> selectedAssets,
|
||||
) {
|
||||
selectionEnabledHook.value = multiselect;
|
||||
selection.value = selectedAssets;
|
||||
}
|
||||
|
||||
AppBar buildAppBar() {
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
onPressed: () => AutoRouter.of(context).pop(),
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
),
|
||||
centerTitle: true,
|
||||
automaticallyImplyLeading: false,
|
||||
title: const Text(
|
||||
'archive_page_title',
|
||||
).tr(args: [archivedAssets.value.length.toString()]),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildBottomBar() {
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: SizedBox(
|
||||
height: 64,
|
||||
child: Card(
|
||||
child: Column(
|
||||
children: [
|
||||
ListTile(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
leading: const Icon(
|
||||
Icons.unarchive_rounded,
|
||||
),
|
||||
title:
|
||||
const Text("Unarchive", style: TextStyle(fontSize: 14)),
|
||||
onTap: () {
|
||||
if (selection.value.isNotEmpty) {
|
||||
ref
|
||||
.watch(assetProvider.notifier)
|
||||
.toggleArchive(selection.value, false);
|
||||
|
||||
final assetOrAssets =
|
||||
selection.value.length > 1 ? 'assets' : 'asset';
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg:
|
||||
'Moved ${selection.value.length} $assetOrAssets to library',
|
||||
gravity: ToastGravity.CENTER,
|
||||
);
|
||||
}
|
||||
|
||||
selectionEnabledHook.value = false;
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: buildAppBar(),
|
||||
body: Stack(
|
||||
children: [
|
||||
ImmichAssetGrid(
|
||||
assets: archivedAssets.value,
|
||||
listener: selectionListener,
|
||||
selectionActive: selectionEnabledHook.value,
|
||||
),
|
||||
if (selectionEnabledHook.value) buildBottomBar()
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,6 @@ class TopControlAppBar extends HookConsumerWidget {
|
|||
required this.asset,
|
||||
required this.onMoreInfoPressed,
|
||||
required this.onDownloadPressed,
|
||||
required this.onSharePressed,
|
||||
required this.onDeletePressed,
|
||||
required this.onAddToAlbumPressed,
|
||||
required this.onToggleMotionVideo,
|
||||
required this.isPlayingMotionVideo,
|
||||
|
|
@ -22,10 +20,8 @@ class TopControlAppBar extends HookConsumerWidget {
|
|||
final Function onMoreInfoPressed;
|
||||
final VoidCallback? onDownloadPressed;
|
||||
final VoidCallback onToggleMotionVideo;
|
||||
final VoidCallback onDeletePressed;
|
||||
final VoidCallback onAddToAlbumPressed;
|
||||
final VoidCallback onFavorite;
|
||||
final Function onSharePressed;
|
||||
final bool isPlayingMotionVideo;
|
||||
final bool isFavorite;
|
||||
|
||||
|
|
@ -34,15 +30,15 @@ class TopControlAppBar extends HookConsumerWidget {
|
|||
const double iconSize = 18.0;
|
||||
|
||||
Widget buildFavoriteButton() {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
onFavorite();
|
||||
},
|
||||
icon: Icon(
|
||||
isFavorite ? Icons.star : Icons.star_border,
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
);
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
onFavorite();
|
||||
},
|
||||
icon: Icon(
|
||||
isFavorite ? Icons.star : Icons.star_border,
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return AppBar(
|
||||
|
|
@ -86,15 +82,6 @@ class TopControlAppBar extends HookConsumerWidget {
|
|||
color: Colors.grey[200],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
onSharePressed();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.ios_share_rounded,
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
),
|
||||
if (asset.isRemote)
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
|
|
@ -105,15 +92,6 @@ class TopControlAppBar extends HookConsumerWidget {
|
|||
color: Colors.grey[200],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
onDeletePressed();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.delete_outline_rounded,
|
||||
color: Colors.grey[200],
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
onMoreInfoPressed();
|
||||
|
|
|
|||
|
|
@ -231,11 +231,10 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||
|
||||
void addToAlbum(Asset addToAlbumAsset) {
|
||||
showModalBottomSheet(
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15.0),
|
||||
),
|
||||
barrierColor: Colors.transparent,
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
builder: (BuildContext _) {
|
||||
return AddToAlbumBottomSheet(
|
||||
|
|
@ -267,6 +266,19 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||
}
|
||||
}
|
||||
|
||||
shareAsset() {
|
||||
ref
|
||||
.watch(imageViewerStateProvider.notifier)
|
||||
.shareAsset(assetList[indexOfAsset.value], context);
|
||||
}
|
||||
|
||||
handleArchive(Asset asset) {
|
||||
ref
|
||||
.watch(assetProvider.notifier)
|
||||
.toggleArchive([asset], !asset.isArchived);
|
||||
AutoRouter.of(context).pop();
|
||||
}
|
||||
|
||||
buildAppBar() {
|
||||
final show = (showAppBar.value || // onTap has the final say
|
||||
(showAppBar.value && !isZoomed.value)) &&
|
||||
|
|
@ -297,16 +309,9 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||
context,
|
||||
);
|
||||
},
|
||||
onSharePressed: () {
|
||||
ref
|
||||
.watch(imageViewerStateProvider.notifier)
|
||||
.shareAsset(assetList[indexOfAsset.value], context);
|
||||
},
|
||||
onToggleMotionVideo: (() {
|
||||
isPlayingMotionVideo.value = !isPlayingMotionVideo.value;
|
||||
}),
|
||||
onDeletePressed: () =>
|
||||
handleDelete((assetList[indexOfAsset.value])),
|
||||
onAddToAlbumPressed: () =>
|
||||
addToAlbum(assetList[indexOfAsset.value]),
|
||||
),
|
||||
|
|
@ -314,6 +319,59 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||
);
|
||||
}
|
||||
|
||||
buildBottomBar() {
|
||||
final show = (showAppBar.value || // onTap has the final say
|
||||
(showAppBar.value && !isZoomed.value)) &&
|
||||
!isPlayingVideo.value;
|
||||
final currentAsset = assetList[indexOfAsset.value];
|
||||
|
||||
return AnimatedOpacity(
|
||||
duration: const Duration(milliseconds: 100),
|
||||
opacity: show ? 1.0 : 0.0,
|
||||
child: BottomNavigationBar(
|
||||
backgroundColor: Colors.black.withOpacity(0.4),
|
||||
unselectedIconTheme: const IconThemeData(color: Colors.white),
|
||||
selectedIconTheme: const IconThemeData(color: Colors.white),
|
||||
unselectedLabelStyle: const TextStyle(color: Colors.black),
|
||||
selectedLabelStyle: const TextStyle(color: Colors.black),
|
||||
showSelectedLabels: false,
|
||||
showUnselectedLabels: false,
|
||||
items: [
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.ios_share_rounded),
|
||||
label: 'Share',
|
||||
tooltip: 'Share',
|
||||
),
|
||||
BottomNavigationBarItem(
|
||||
icon: currentAsset.isArchived
|
||||
? const Icon(Icons.unarchive_rounded)
|
||||
: const Icon(Icons.archive_outlined),
|
||||
label: 'Archive',
|
||||
tooltip: 'Archive',
|
||||
),
|
||||
const BottomNavigationBarItem(
|
||||
icon: Icon(Icons.delete_outline),
|
||||
label: 'Delete',
|
||||
tooltip: 'Delete',
|
||||
),
|
||||
],
|
||||
onTap: (index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
shareAsset();
|
||||
break;
|
||||
case 1:
|
||||
handleArchive(assetList[indexOfAsset.value]);
|
||||
break;
|
||||
case 2:
|
||||
handleDelete(assetList[indexOfAsset.value]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.black,
|
||||
body: WillPopScope(
|
||||
|
|
@ -481,6 +539,12 @@ class GalleryViewerPage extends HookConsumerWidget {
|
|||
right: 0,
|
||||
child: buildAppBar(),
|
||||
),
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: buildBottomBar(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ class RenderList {
|
|||
|
||||
final groups = _groupAssets(allAssets, groupBy);
|
||||
|
||||
groups.entries.sortedBy((e) =>e.key).reversed.forEach((entry) {
|
||||
groups.entries.sortedBy((e) => e.key).reversed.forEach((entry) {
|
||||
final date = entry.key;
|
||||
final assets = entry.value;
|
||||
|
||||
|
|
|
|||
|
|
@ -50,10 +50,9 @@ class ImmichAssetGrid extends HookConsumerWidget {
|
|||
// Unfortunately, using the transition animation itself didn't
|
||||
// seem to work reliably. So instead, wait until the duration of the
|
||||
// animation has elapsed to re-enable the hero animations
|
||||
Future.delayed(transitionDuration)
|
||||
.then((_) {
|
||||
enableHeroAnimations.value = true;
|
||||
});
|
||||
Future.delayed(transitionDuration).then((_) {
|
||||
enableHeroAnimations.value = true;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import 'package:immich_mobile/shared/models/album.dart';
|
|||
class ControlBottomAppBar extends ConsumerWidget {
|
||||
final Function onShare;
|
||||
final Function onFavorite;
|
||||
final Function onArchive;
|
||||
final Function onDelete;
|
||||
final Function(Album album) onAddToAlbum;
|
||||
final void Function() onCreateNewAlbum;
|
||||
|
|
@ -20,6 +21,7 @@ class ControlBottomAppBar extends ConsumerWidget {
|
|||
Key? key,
|
||||
required this.onShare,
|
||||
required this.onFavorite,
|
||||
required this.onArchive,
|
||||
required this.onDelete,
|
||||
required this.sharedAlbums,
|
||||
required this.albums,
|
||||
|
|
@ -62,6 +64,11 @@ class ControlBottomAppBar extends ConsumerWidget {
|
|||
);
|
||||
},
|
||||
),
|
||||
ControlBoxButton(
|
||||
iconData: Icons.archive,
|
||||
label: "control_bottom_app_bar_archive".tr(),
|
||||
onPressed: () => onArchive(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ class HomePage extends HookConsumerWidget {
|
|||
barrierDismissible: false,
|
||||
);
|
||||
|
||||
// ref.watch(shareServiceProvider).shareAssets(selection.value.toList());
|
||||
selectionEnabledHook.value = false;
|
||||
}
|
||||
|
||||
|
|
@ -132,6 +131,24 @@ class HomePage extends HookConsumerWidget {
|
|||
selectionEnabledHook.value = false;
|
||||
}
|
||||
|
||||
void onArchiveAsset() {
|
||||
final remoteAssets = remoteOnlySelection(
|
||||
localErrorMessage: 'home_page_archive_err_local'.tr(),
|
||||
);
|
||||
if (remoteAssets.isNotEmpty) {
|
||||
ref.watch(assetProvider.notifier).toggleArchive(remoteAssets, true);
|
||||
|
||||
final assetOrAssets = remoteAssets.length > 1 ? 'assets' : 'asset';
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: 'Moved ${remoteAssets.length} $assetOrAssets to archive',
|
||||
gravity: ToastGravity.CENTER,
|
||||
);
|
||||
}
|
||||
|
||||
selectionEnabledHook.value = false;
|
||||
}
|
||||
|
||||
void onDelete() {
|
||||
ref.watch(assetProvider.notifier).deleteAssets(selection.value);
|
||||
selectionEnabledHook.value = false;
|
||||
|
|
@ -265,7 +282,7 @@ class HomePage extends HookConsumerWidget {
|
|||
? buildLoadingIndicator()
|
||||
: ImmichAssetGrid(
|
||||
renderList: ref.watch(assetProvider).renderList!,
|
||||
assets: ref.watch(assetProvider).allAssets,
|
||||
assets: ref.read(assetProvider).allAssets,
|
||||
assetsPerRow: appSettingService
|
||||
.getSetting(AppSettingsEnum.tilesPerRow),
|
||||
showStorageIndicator: appSettingService
|
||||
|
|
@ -278,6 +295,7 @@ class HomePage extends HookConsumerWidget {
|
|||
ControlBottomAppBar(
|
||||
onShare: onShareAssets,
|
||||
onFavorite: onFavoriteAssets,
|
||||
onArchive: onArchiveAsset,
|
||||
onDelete: onDelete,
|
||||
onAddToAlbum: onAddToAlbum,
|
||||
albums: albums,
|
||||
|
|
@ -291,9 +309,7 @@ class HomePage extends HookConsumerWidget {
|
|||
|
||||
return Scaffold(
|
||||
appBar: !selectionEnabledHook.value
|
||||
? HomePageAppBar(
|
||||
onPopBack: reloadAllAsset,
|
||||
)
|
||||
? HomePageAppBar(onPopBack: reloadAllAsset)
|
||||
: null,
|
||||
drawer: const ProfileDrawer(),
|
||||
body: buildBody(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue