|
@@ -44,6 +44,7 @@ class HomePage extends HookConsumerWidget {
|
|
|
final sharedAlbums = ref.watch(sharedAlbumProvider);
|
|
|
final albumService = ref.watch(albumServiceProvider);
|
|
|
final currentUser = ref.watch(currentUserProvider);
|
|
|
+ final timelineUsers = ref.watch(timelineUsersIdsProvider);
|
|
|
final trashEnabled =
|
|
|
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
|
|
|
|
|
@@ -55,6 +56,7 @@ class HomePage extends HookConsumerWidget {
|
|
|
() {
|
|
|
ref.read(websocketProvider.notifier).connect();
|
|
|
Future(() => ref.read(assetProvider.notifier).getAllAsset());
|
|
|
+ ref.read(assetProvider.notifier).getPartnerAssets();
|
|
|
ref.read(albumProvider.notifier).getAllAlbums();
|
|
|
ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums();
|
|
|
ref.read(serverInfoProvider.notifier).getServerInfo();
|
|
@@ -84,20 +86,49 @@ class HomePage extends HookConsumerWidget {
|
|
|
SelectionAssetState.fromSelection(selectedAssets);
|
|
|
}
|
|
|
|
|
|
- List<Asset> remoteOnlySelection({String? localErrorMessage}) {
|
|
|
- final Set<Asset> assets = selection.value;
|
|
|
+ errorBuilder(String? msg) => msg != null && msg.isNotEmpty
|
|
|
+ ? () => ImmichToast.show(
|
|
|
+ context: context,
|
|
|
+ msg: msg,
|
|
|
+ gravity: ToastGravity.BOTTOM,
|
|
|
+ )
|
|
|
+ : null;
|
|
|
+
|
|
|
+ Iterable<Asset> remoteOnly(
|
|
|
+ Iterable<Asset> assets, {
|
|
|
+ void Function()? errorCallback,
|
|
|
+ }) {
|
|
|
final bool onlyRemote = assets.every((e) => e.isRemote);
|
|
|
if (!onlyRemote) {
|
|
|
- if (localErrorMessage != null && localErrorMessage.isNotEmpty) {
|
|
|
- ImmichToast.show(
|
|
|
- context: context,
|
|
|
- msg: localErrorMessage,
|
|
|
- gravity: ToastGravity.BOTTOM,
|
|
|
- );
|
|
|
- }
|
|
|
- return assets.where((a) => a.isRemote).toList();
|
|
|
+ if (errorCallback != null) errorCallback();
|
|
|
+ return assets.where((a) => a.isRemote);
|
|
|
}
|
|
|
- return assets.toList();
|
|
|
+ return assets;
|
|
|
+ }
|
|
|
+
|
|
|
+ Iterable<Asset> ownedOnly(
|
|
|
+ Iterable<Asset> assets, {
|
|
|
+ void Function()? errorCallback,
|
|
|
+ }) {
|
|
|
+ if (currentUser == null) return [];
|
|
|
+ final userId = currentUser.isarId;
|
|
|
+ final bool onlyOwned = assets.every((e) => e.ownerId == userId);
|
|
|
+ if (!onlyOwned) {
|
|
|
+ if (errorCallback != null) errorCallback();
|
|
|
+ return assets.where((a) => a.ownerId == userId);
|
|
|
+ }
|
|
|
+ return assets;
|
|
|
+ }
|
|
|
+
|
|
|
+ Iterable<Asset> ownedRemoteSelection({
|
|
|
+ String? localErrorMessage,
|
|
|
+ String? ownerErrorMessage,
|
|
|
+ }) {
|
|
|
+ final assets = selection.value;
|
|
|
+ return remoteOnly(
|
|
|
+ ownedOnly(assets, errorCallback: errorBuilder(ownerErrorMessage)),
|
|
|
+ errorCallback: errorBuilder(localErrorMessage),
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
void onShareAssets(bool shareLocal) {
|
|
@@ -105,7 +136,7 @@ class HomePage extends HookConsumerWidget {
|
|
|
if (shareLocal) {
|
|
|
handleShareAssets(ref, context, selection.value.toList());
|
|
|
} else {
|
|
|
- final ids = remoteOnlySelection().map((e) => e.remoteId!);
|
|
|
+ final ids = ownedRemoteSelection().map((e) => e.remoteId!);
|
|
|
context.autoPush(SharedLinkEditRoute(assetsList: ids.toList()));
|
|
|
}
|
|
|
processing.value = false;
|
|
@@ -115,11 +146,12 @@ class HomePage extends HookConsumerWidget {
|
|
|
void onFavoriteAssets() async {
|
|
|
processing.value = true;
|
|
|
try {
|
|
|
- final remoteAssets = remoteOnlySelection(
|
|
|
+ final remoteAssets = ownedRemoteSelection(
|
|
|
localErrorMessage: 'home_page_favorite_err_local'.tr(),
|
|
|
+ ownerErrorMessage: 'home_page_favorite_err_partner'.tr(),
|
|
|
);
|
|
|
if (remoteAssets.isNotEmpty) {
|
|
|
- await handleFavoriteAssets(ref, context, remoteAssets);
|
|
|
+ await handleFavoriteAssets(ref, context, remoteAssets.toList());
|
|
|
}
|
|
|
} finally {
|
|
|
processing.value = false;
|
|
@@ -130,10 +162,11 @@ class HomePage extends HookConsumerWidget {
|
|
|
void onArchiveAsset() async {
|
|
|
processing.value = true;
|
|
|
try {
|
|
|
- final remoteAssets = remoteOnlySelection(
|
|
|
+ final remoteAssets = ownedRemoteSelection(
|
|
|
localErrorMessage: 'home_page_archive_err_local'.tr(),
|
|
|
+ ownerErrorMessage: 'home_page_archive_err_partner'.tr(),
|
|
|
);
|
|
|
- await handleArchiveAssets(ref, context, remoteAssets);
|
|
|
+ await handleArchiveAssets(ref, context, remoteAssets.toList());
|
|
|
} finally {
|
|
|
processing.value = false;
|
|
|
selectionEnabledHook.value = false;
|
|
@@ -143,12 +176,16 @@ class HomePage extends HookConsumerWidget {
|
|
|
void onDelete() async {
|
|
|
processing.value = true;
|
|
|
try {
|
|
|
+ final toDelete = ownedOnly(
|
|
|
+ selection.value,
|
|
|
+ errorCallback: errorBuilder('home_page_delete_err_partner'.tr()),
|
|
|
+ ).toList();
|
|
|
await ref
|
|
|
.read(assetProvider.notifier)
|
|
|
- .deleteAssets(selection.value, force: !trashEnabled);
|
|
|
+ .deleteAssets(toDelete, force: !trashEnabled);
|
|
|
|
|
|
- final hasRemote = selection.value.any((a) => a.isRemote);
|
|
|
- final assetOrAssets = selection.value.length > 1 ? 'assets' : 'asset';
|
|
|
+ final hasRemote = toDelete.any((a) => a.isRemote);
|
|
|
+ final assetOrAssets = toDelete.length > 1 ? 'assets' : 'asset';
|
|
|
final trashOrRemoved =
|
|
|
!trashEnabled ? 'deleted permanently' : 'trashed';
|
|
|
if (hasRemote) {
|
|
@@ -180,8 +217,9 @@ class HomePage extends HookConsumerWidget {
|
|
|
void onAddToAlbum(Album album) async {
|
|
|
processing.value = true;
|
|
|
try {
|
|
|
- final Iterable<Asset> assets = remoteOnlySelection(
|
|
|
+ final Iterable<Asset> assets = ownedRemoteSelection(
|
|
|
localErrorMessage: "home_page_add_to_album_err_local".tr(),
|
|
|
+ ownerErrorMessage: "home_page_album_err_partner".tr(),
|
|
|
);
|
|
|
if (assets.isEmpty) {
|
|
|
return;
|
|
@@ -228,8 +266,9 @@ class HomePage extends HookConsumerWidget {
|
|
|
void onCreateNewAlbum() async {
|
|
|
processing.value = true;
|
|
|
try {
|
|
|
- final Iterable<Asset> assets = remoteOnlySelection(
|
|
|
+ final Iterable<Asset> assets = ownedRemoteSelection(
|
|
|
localErrorMessage: "home_page_add_to_album_err_local".tr(),
|
|
|
+ ownerErrorMessage: "home_page_album_err_partner".tr(),
|
|
|
);
|
|
|
if (assets.isEmpty) {
|
|
|
return;
|
|
@@ -270,6 +309,9 @@ class HomePage extends HookConsumerWidget {
|
|
|
Future<void> refreshAssets() async {
|
|
|
final fullRefresh = refreshCount.value > 0;
|
|
|
await ref.read(assetProvider.notifier).getAllAsset(clear: fullRefresh);
|
|
|
+ if (timelineUsers.length > 1) {
|
|
|
+ await ref.read(assetProvider.notifier).getPartnerAssets();
|
|
|
+ }
|
|
|
if (fullRefresh) {
|
|
|
// refresh was forced: user requested another refresh within 2 seconds
|
|
|
refreshCount.value = 0;
|
|
@@ -330,7 +372,13 @@ class HomePage extends HookConsumerWidget {
|
|
|
bottom: false,
|
|
|
child: Stack(
|
|
|
children: [
|
|
|
- ref.watch(assetsProvider(currentUser?.isarId)).when(
|
|
|
+ ref
|
|
|
+ .watch(
|
|
|
+ timelineUsers.length > 1
|
|
|
+ ? multiUserAssetsProvider(timelineUsers)
|
|
|
+ : assetsProvider(currentUser?.isarId),
|
|
|
+ )
|
|
|
+ .when(
|
|
|
data: (data) => data.isEmpty
|
|
|
? buildLoadingIndicator()
|
|
|
: ImmichAssetGrid(
|
|
@@ -338,11 +386,10 @@ class HomePage extends HookConsumerWidget {
|
|
|
listener: selectionListener,
|
|
|
selectionActive: selectionEnabledHook.value,
|
|
|
onRefresh: refreshAssets,
|
|
|
- topWidget: (currentUser != null &&
|
|
|
- currentUser.memoryEnabled != null &&
|
|
|
- currentUser.memoryEnabled!)
|
|
|
- ? const MemoryLane()
|
|
|
- : const SizedBox(),
|
|
|
+ topWidget:
|
|
|
+ (currentUser != null && currentUser.memoryEnabled)
|
|
|
+ ? const MemoryLane()
|
|
|
+ : const SizedBox(),
|
|
|
showStack: true,
|
|
|
),
|
|
|
error: (error, _) => Center(child: Text(error.toString())),
|