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:
parent
013da0aa3d
commit
9b418642a6
@ -46,5 +46,6 @@ final assetStackProvider =
|
|||||||
.isArchivedEqualTo(false)
|
.isArchivedEqualTo(false)
|
||||||
.isTrashedEqualTo(false)
|
.isTrashedEqualTo(false)
|
||||||
.stackParentIdEqualTo(asset.remoteId)
|
.stackParentIdEqualTo(asset.remoteId)
|
||||||
|
.sortByFileCreatedAtDesc()
|
||||||
.findAll();
|
.findAll();
|
||||||
});
|
});
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user