1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

refactor(mobile): stack only through merging from timeline (#4598)

* mobile: remove stack selection page

* mobile: require at-least 2 assets to stack

* mobile: sort stack children by fileCreatedAt

---------

Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong 2023-10-22 20:07:27 +00:00 committed by GitHub
parent 013da0aa3d
commit 9b418642a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 22 additions and 73 deletions

View File

@ -46,5 +46,6 @@ final assetStackProvider =
.isArchivedEqualTo(false) .isArchivedEqualTo(false)
.isTrashedEqualTo(false) .isTrashedEqualTo(false)
.stackParentIdEqualTo(asset.remoteId) .stackParentIdEqualTo(asset.remoteId)
.sortByFileCreatedAtDesc()
.findAll(); .findAll();
}); });

View File

@ -4,33 +4,38 @@ class SelectionAssetState {
final bool hasRemote; final bool hasRemote;
final bool hasLocal; final bool hasLocal;
final bool hasMerged; final bool hasMerged;
final int selectedCount;
const SelectionAssetState({ const SelectionAssetState({
this.hasRemote = false, this.hasRemote = false,
this.hasLocal = false, this.hasLocal = false,
this.hasMerged = false, this.hasMerged = false,
this.selectedCount = 0,
}); });
SelectionAssetState copyWith({ SelectionAssetState copyWith({
bool? hasRemote, bool? hasRemote,
bool? hasLocal, bool? hasLocal,
bool? hasMerged, bool? hasMerged,
int? selectedCount,
}) { }) {
return SelectionAssetState( return SelectionAssetState(
hasRemote: hasRemote ?? this.hasRemote, hasRemote: hasRemote ?? this.hasRemote,
hasLocal: hasLocal ?? this.hasLocal, hasLocal: hasLocal ?? this.hasLocal,
hasMerged: hasMerged ?? this.hasMerged, hasMerged: hasMerged ?? this.hasMerged,
selectedCount: selectedCount ?? this.selectedCount,
); );
} }
SelectionAssetState.fromSelection(Set<Asset> selection) SelectionAssetState.fromSelection(Set<Asset> selection)
: hasLocal = selection.any((e) => e.storage == AssetState.local), : hasLocal = selection.any((e) => e.storage == AssetState.local),
hasMerged = selection.any((e) => e.storage == AssetState.merged), hasMerged = selection.any((e) => e.storage == AssetState.merged),
hasRemote = selection.any((e) => e.storage == AssetState.remote); hasRemote = selection.any((e) => e.storage == AssetState.remote),
selectedCount = selection.length;
@override @override
String toString() => String toString() =>
'SelectionAssetState(hasRemote: $hasRemote, hasMerged: $hasMerged, hasMerged: $hasMerged)'; 'SelectionAssetState(hasRemote: $hasRemote, hasMerged: $hasMerged, hasMerged: $hasMerged, selectedCount: $selectedCount)';
@override @override
bool operator ==(covariant SelectionAssetState other) { bool operator ==(covariant SelectionAssetState other) {
@ -38,10 +43,14 @@ class SelectionAssetState {
return other.hasRemote == hasRemote && return other.hasRemote == hasRemote &&
other.hasLocal == hasLocal && other.hasLocal == hasLocal &&
other.hasMerged == hasMerged; other.hasMerged == hasMerged &&
other.selectedCount == selectedCount;
} }
@override @override
int get hashCode => int get hashCode =>
hasRemote.hashCode ^ hasLocal.hashCode ^ hasMerged.hashCode; hasRemote.hashCode ^
hasLocal.hashCode ^
hasMerged.hashCode ^
selectedCount.hashCode;
} }

View File

@ -94,7 +94,7 @@ class ControlBottomAppBar extends ConsumerWidget {
} }
: null, : null,
), ),
if (!hasLocal) if (!hasLocal && selectionAssetState.selectedCount > 1)
ControlBoxButton( ControlBoxButton(
iconData: Icons.filter_none_rounded, iconData: Icons.filter_none_rounded,
label: "control_bottom_app_bar_stack".tr(), label: "control_bottom_app_bar_stack".tr(),

View File

@ -7,12 +7,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
import 'package:immich_mobile/modules/album/providers/album.provider.dart'; import 'package:immich_mobile/modules/album/providers/album.provider.dart';
import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart'; import 'package:immich_mobile/modules/album/providers/album_detail.provider.dart';
import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart';
import 'package:immich_mobile/modules/album/services/album.service.dart'; import 'package:immich_mobile/modules/album/services/album.service.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/asset_stack.provider.dart';
import 'package:immich_mobile/modules/asset_viewer/services/asset_stack.service.dart'; import 'package:immich_mobile/modules/asset_viewer/services/asset_stack.service.dart';
import 'package:immich_mobile/modules/backup/providers/manual_upload.provider.dart'; import 'package:immich_mobile/modules/backup/providers/manual_upload.provider.dart';
import 'package:immich_mobile/modules/home/models/selection_state.dart'; import 'package:immich_mobile/modules/home/models/selection_state.dart';
@ -259,46 +257,15 @@ class HomePage extends HookConsumerWidget {
void onStack() async { void onStack() async {
try { try {
processing.value = true; processing.value = true;
if (!selectionEnabledHook.value) { if (!selectionEnabledHook.value || selection.value.length < 2) {
return; return;
} }
final parent = selection.value.elementAt(0);
final selectedAsset = selection.value.elementAt(0); selection.value.remove(parent);
await ref.read(assetStackServiceProvider).updateStack(
if (selection.value.length == 1) { parent,
final stackChildren = childrenToAdd: selection.value.toList(),
(await ref.read(assetStackProvider(selectedAsset).future)) );
.toSet();
AssetSelectionPageResult? returnPayload =
await AutoRouter.of(context).push<AssetSelectionPageResult?>(
AssetSelectionRoute(
existingAssets: stackChildren,
canDeselect: true,
query: getAssetStackSelectionQuery(ref, selectedAsset),
),
);
if (returnPayload != null) {
Set<Asset> selectedAssets = returnPayload.selectedAssets;
// Do not add itself as its stack child
selectedAssets.remove(selectedAsset);
final removedChildren = stackChildren.difference(selectedAssets);
final addedChildren = selectedAssets.difference(stackChildren);
await ref.read(assetStackServiceProvider).updateStack(
selectedAsset,
childrenToAdd: addedChildren.toList(),
childrenToRemove: removedChildren.toList(),
);
}
} else {
// Merge assets
selection.value.remove(selectedAsset);
final selectedAssets = selection.value;
await ref.read(assetStackServiceProvider).updateStack(
selectedAsset,
childrenToAdd: selectedAssets.toList(),
);
}
} finally { } finally {
processing.value = false; processing.value = false;
selectionEnabledHook.value = false; selectionEnabledHook.value = false;

View File

@ -245,31 +245,3 @@ QueryBuilder<Asset, Asset, QAfterSortBy>? getRemoteAssetQuery(WidgetRef ref) {
.stackParentIdIsNull() .stackParentIdIsNull()
.sortByFileCreatedAtDesc(); .sortByFileCreatedAtDesc();
} }
QueryBuilder<Asset, Asset, QAfterSortBy>? getAssetStackSelectionQuery(
WidgetRef ref,
Asset parentAsset,
) {
final userId = ref.watch(currentUserProvider)?.isarId;
if (userId == null || !parentAsset.isRemote) {
return null;
}
return ref
.watch(dbProvider)
.assets
.where()
.remoteIdIsNotNull()
.filter()
.isArchivedEqualTo(false)
.ownerIdEqualTo(userId)
.not()
.remoteIdEqualTo(parentAsset.remoteId)
// Show existing stack children in selection page
.group(
(q) => q
.stackParentIdIsNull()
.or()
.stackParentIdEqualTo(parentAsset.remoteId),
)
.sortByFileCreatedAtDesc();
}