You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-08-08 23:07:06 +02:00
feat: locked view mobile (#18316)
* feat: locked/private view * feat: locked/private view * feat: mobile lock/private view * feat: mobile lock/private view * merge main * pr feedback * pr feedback * bottom sheet sizing * always lock when navigating away
This commit is contained in:
@ -6,6 +6,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/routes.provider.dart';
|
||||
import 'package:immich_mobile/widgets/album/add_to_album_sliverlist.dart';
|
||||
import 'package:immich_mobile/models/asset_selection_state.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/delete_dialog.dart';
|
||||
@ -37,6 +38,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
final void Function()? onEditTime;
|
||||
final void Function()? onEditLocation;
|
||||
final void Function()? onRemoveFromAlbum;
|
||||
final void Function()? onToggleLocked;
|
||||
|
||||
final bool enabled;
|
||||
final bool unfavorite;
|
||||
@ -58,6 +60,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
this.onEditTime,
|
||||
this.onEditLocation,
|
||||
this.onRemoveFromAlbum,
|
||||
this.onToggleLocked,
|
||||
this.selectionAssetState = const AssetSelectionState(),
|
||||
this.enabled = true,
|
||||
this.unarchive = false,
|
||||
@ -77,6 +80,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
ref.watch(albumProvider).where((a) => a.shared).toList();
|
||||
const bottomPadding = 0.20;
|
||||
final scrollController = useDraggableScrollController();
|
||||
final isInLockedView = ref.watch(inLockedViewProvider);
|
||||
|
||||
void minimize() {
|
||||
scrollController.animateTo(
|
||||
@ -133,11 +137,12 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
label: "share".tr(),
|
||||
onPressed: enabled ? () => onShare(true) : null,
|
||||
),
|
||||
ControlBoxButton(
|
||||
iconData: Icons.link_rounded,
|
||||
label: "control_bottom_app_bar_share_link".tr(),
|
||||
onPressed: enabled ? () => onShare(false) : null,
|
||||
),
|
||||
if (!isInLockedView)
|
||||
ControlBoxButton(
|
||||
iconData: Icons.link_rounded,
|
||||
label: "share_link".tr(),
|
||||
onPressed: enabled ? () => onShare(false) : null,
|
||||
),
|
||||
if (hasRemote && onArchive != null)
|
||||
ControlBoxButton(
|
||||
iconData:
|
||||
@ -153,7 +158,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
label: (unfavorite ? "unfavorite" : "favorite").tr(),
|
||||
onPressed: enabled ? onFavorite : null,
|
||||
),
|
||||
if (hasLocal && hasRemote && onDelete != null)
|
||||
if (hasLocal && hasRemote && onDelete != null && !isInLockedView)
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 90),
|
||||
child: ControlBoxButton(
|
||||
@ -166,7 +171,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
enabled ? () => showForceDeleteDialog(onDelete!) : null,
|
||||
),
|
||||
),
|
||||
if (hasRemote && onDeleteServer != null)
|
||||
if (hasRemote && onDeleteServer != null && !isInLockedView)
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 85),
|
||||
child: ControlBoxButton(
|
||||
@ -189,9 +194,23 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
: null,
|
||||
),
|
||||
),
|
||||
if (hasLocal && onDeleteLocal != null)
|
||||
if (isInLockedView)
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 85),
|
||||
constraints: const BoxConstraints(maxWidth: 110),
|
||||
child: ControlBoxButton(
|
||||
iconData: Icons.delete_forever,
|
||||
label: "delete_dialog_title".tr(),
|
||||
onPressed: enabled
|
||||
? () => showForceDeleteDialog(
|
||||
onDeleteServer!,
|
||||
alertMsg: "delete_dialog_alert_remote",
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
if (hasLocal && onDeleteLocal != null && !isInLockedView)
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 95),
|
||||
child: ControlBoxButton(
|
||||
iconData: Icons.no_cell_outlined,
|
||||
label: "control_bottom_app_bar_delete_from_local".tr(),
|
||||
@ -231,6 +250,19 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
onPressed: enabled ? onEditLocation : null,
|
||||
),
|
||||
),
|
||||
if (hasRemote)
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 100),
|
||||
child: ControlBoxButton(
|
||||
iconData: isInLockedView
|
||||
? Icons.lock_open_rounded
|
||||
: Icons.lock_outline_rounded,
|
||||
label: isInLockedView
|
||||
? "remove_from_locked_folder".tr()
|
||||
: "move_to_locked_folder".tr(),
|
||||
onPressed: enabled ? onToggleLocked : null,
|
||||
),
|
||||
),
|
||||
if (!selectionAssetState.hasLocal &&
|
||||
selectionAssetState.selectedCount > 1 &&
|
||||
onStack != null)
|
||||
@ -269,20 +301,40 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
];
|
||||
}
|
||||
|
||||
getInitialSize() {
|
||||
if (isInLockedView) {
|
||||
return 0.20;
|
||||
}
|
||||
if (hasRemote) {
|
||||
return 0.35;
|
||||
}
|
||||
return bottomPadding;
|
||||
}
|
||||
|
||||
getMaxChildSize() {
|
||||
if (isInLockedView) {
|
||||
return 0.20;
|
||||
}
|
||||
if (hasRemote) {
|
||||
return 0.65;
|
||||
}
|
||||
return bottomPadding;
|
||||
}
|
||||
|
||||
return DraggableScrollableSheet(
|
||||
controller: scrollController,
|
||||
initialChildSize: hasRemote ? 0.35 : bottomPadding,
|
||||
initialChildSize: getInitialSize(),
|
||||
minChildSize: bottomPadding,
|
||||
maxChildSize: hasRemote ? 0.65 : bottomPadding,
|
||||
maxChildSize: getMaxChildSize(),
|
||||
snap: true,
|
||||
builder: (
|
||||
BuildContext context,
|
||||
ScrollController scrollController,
|
||||
) {
|
||||
return Card(
|
||||
color: context.colorScheme.surfaceContainerLow,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 18.0,
|
||||
color: context.colorScheme.surfaceContainerHigh,
|
||||
surfaceTintColor: context.colorScheme.surfaceContainerHigh,
|
||||
elevation: 6.0,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(12),
|
||||
@ -300,27 +352,27 @@ class ControlBottomAppBar extends HookConsumerWidget {
|
||||
const CustomDraggingHandle(),
|
||||
const SizedBox(height: 12),
|
||||
SizedBox(
|
||||
height: 100,
|
||||
height: 120,
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
scrollDirection: Axis.horizontal,
|
||||
children: renderActionButtons(),
|
||||
),
|
||||
),
|
||||
if (hasRemote)
|
||||
if (hasRemote && !isInLockedView) ...[
|
||||
const Divider(
|
||||
indent: 16,
|
||||
endIndent: 16,
|
||||
thickness: 1,
|
||||
),
|
||||
if (hasRemote)
|
||||
_AddToAlbumTitleRow(
|
||||
onCreateNewAlbum: enabled ? onCreateNewAlbum : null,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
if (hasRemote)
|
||||
if (hasRemote && !isInLockedView)
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
sliver: AddToAlbumSliverList(
|
||||
@ -352,12 +404,9 @@ class _AddToAlbumTitleRow extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(
|
||||
Text(
|
||||
"add_to_album",
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: context.textTheme.titleSmall,
|
||||
).tr(),
|
||||
TextButton.icon(
|
||||
onPressed: onCreateNewAlbum,
|
||||
|
Reference in New Issue
Block a user