You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-08-10 23:22:22 +02:00
feat(album): album view sort order (#14648)
* feat(mobile): album view sort order * feat: add error message * refactor(mobile): album page (#14659) * refactor album page * update lint rule * const record * fix: updating sort order when pull to refresh --------- Co-authored-by: Alex <alex.tran1502@gmail.com> * Move sort toggle button to bottom sheet menu * chore: revert multiselectgrid loading status * chore: revert multiselectgrid loading status --------- Co-authored-by: Mert <101130780+mertalev@users.noreply.github.com>
This commit is contained in:
@@ -1,22 +1,21 @@
|
||||
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';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/providers/activity_statistics.provider.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/album/album_viewer.provider.dart';
|
||||
import 'package:immich_mobile/utils/immich_loading_overlay.dart';
|
||||
import 'package:immich_mobile/providers/album/current_album.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||
|
||||
class AlbumViewerAppbar extends HookConsumerWidget
|
||||
implements PreferredSizeWidget {
|
||||
const AlbumViewerAppbar({
|
||||
super.key,
|
||||
required this.album,
|
||||
required this.userId,
|
||||
required this.titleFocusNode,
|
||||
this.onAddPhotos,
|
||||
@@ -24,34 +23,48 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
required this.onActivities,
|
||||
});
|
||||
|
||||
final Album album;
|
||||
final String userId;
|
||||
final FocusNode titleFocusNode;
|
||||
final Function(Album album)? onAddPhotos;
|
||||
final Function(Album album)? onAddUsers;
|
||||
final Function(Album album) onActivities;
|
||||
final void Function()? onAddPhotos;
|
||||
final void Function()? onAddUsers;
|
||||
final void Function() onActivities;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final newAlbumTitle = ref.watch(albumViewerProvider).editTitleText;
|
||||
final isEditAlbum = ref.watch(albumViewerProvider).isEditAlbum;
|
||||
final isProcessing = useProcessingOverlay();
|
||||
final albumState = useState(ref.read(currentAlbumProvider));
|
||||
final album = albumState.value;
|
||||
ref.listen(currentAlbumProvider, (_, newAlbum) {
|
||||
final oldAlbum = albumState.value;
|
||||
if (oldAlbum != null && newAlbum != null && oldAlbum.id == newAlbum.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
albumState.value = newAlbum;
|
||||
});
|
||||
|
||||
if (album == null) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
final albumViewer = ref.watch(albumViewerProvider);
|
||||
final newAlbumTitle = albumViewer.editTitleText;
|
||||
final isEditAlbum = albumViewer.isEditAlbum;
|
||||
|
||||
final comments = album.shared
|
||||
? ref.watch(activityStatisticsProvider(album.remoteId!))
|
||||
: 0;
|
||||
|
||||
deleteAlbum() async {
|
||||
isProcessing.value = true;
|
||||
final bool success =
|
||||
await ref.watch(albumProvider.notifier).deleteAlbum(album);
|
||||
|
||||
final bool success;
|
||||
if (album.shared) {
|
||||
success = await ref.watch(albumProvider.notifier).deleteAlbum(album);
|
||||
context.navigateTo(const TabControllerRoute(children: [AlbumsRoute()]));
|
||||
} else {
|
||||
success = await ref.watch(albumProvider.notifier).deleteAlbum(album);
|
||||
context
|
||||
.navigateTo(const TabControllerRoute(children: [LibraryRoute()]));
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
@@ -60,11 +73,9 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
|
||||
isProcessing.value = false;
|
||||
}
|
||||
|
||||
Future<void> showConfirmationDialog() async {
|
||||
Future<void> onDeleteAlbumPressed() {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false, // user must tap button!
|
||||
@@ -102,13 +113,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
);
|
||||
}
|
||||
|
||||
void onDeleteAlbumPressed() async {
|
||||
showConfirmationDialog();
|
||||
}
|
||||
|
||||
void onLeaveAlbumPressed() async {
|
||||
isProcessing.value = true;
|
||||
|
||||
bool isSuccess =
|
||||
await ref.watch(albumProvider.notifier).leaveAlbum(album);
|
||||
|
||||
@@ -123,8 +128,6 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
|
||||
isProcessing.value = false;
|
||||
}
|
||||
|
||||
buildBottomSheetActions() {
|
||||
@@ -136,7 +139,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
'album_viewer_appbar_share_delete',
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
).tr(),
|
||||
onTap: () => onDeleteAlbumPressed(),
|
||||
onTap: onDeleteAlbumPressed,
|
||||
)
|
||||
: ListTile(
|
||||
leading: const Icon(Icons.person_remove_rounded),
|
||||
@@ -144,25 +147,52 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
'album_viewer_appbar_share_leave',
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
).tr(),
|
||||
onTap: () => onLeaveAlbumPressed(),
|
||||
onTap: onLeaveAlbumPressed,
|
||||
),
|
||||
];
|
||||
// }
|
||||
}
|
||||
|
||||
void onSortOrderToggled() async {
|
||||
final updatedAlbum =
|
||||
await ref.read(albumProvider.notifier).toggleSortOrder(album);
|
||||
|
||||
if (updatedAlbum == null) {
|
||||
ImmichToast.show(
|
||||
context: context,
|
||||
msg: "error_change_sort_album".tr(),
|
||||
toastType: ToastType.error,
|
||||
gravity: ToastGravity.BOTTOM,
|
||||
);
|
||||
}
|
||||
|
||||
context.pop();
|
||||
}
|
||||
|
||||
void buildBottomSheet() {
|
||||
final ownerActions = [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.person_add_alt_rounded),
|
||||
onTap: () {
|
||||
context.pop();
|
||||
onAddUsers!(album);
|
||||
final onAddUsers = this.onAddUsers;
|
||||
if (onAddUsers != null) {
|
||||
onAddUsers();
|
||||
}
|
||||
},
|
||||
title: const Text(
|
||||
"album_viewer_page_share_add_users",
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
).tr(),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.swap_vert_rounded),
|
||||
onTap: onSortOrderToggled,
|
||||
title: const Text(
|
||||
"change_display_order",
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
).tr(),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.share_rounded),
|
||||
onTap: () {
|
||||
@@ -176,7 +206,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.settings_rounded),
|
||||
onTap: () => context.navigateTo(AlbumOptionsRoute(album: album)),
|
||||
onTap: () => context.navigateTo(AlbumOptionsRoute()),
|
||||
title: const Text(
|
||||
"translated_text_options",
|
||||
style: TextStyle(fontWeight: FontWeight.w500),
|
||||
@@ -189,7 +219,10 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
leading: const Icon(Icons.add_photo_alternate_outlined),
|
||||
onTap: () {
|
||||
context.pop();
|
||||
onAddPhotos!(album);
|
||||
final onAddPhotos = this.onAddPhotos;
|
||||
if (onAddPhotos != null) {
|
||||
onAddPhotos();
|
||||
}
|
||||
},
|
||||
title: const Text(
|
||||
"share_add_photos",
|
||||
@@ -222,9 +255,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
|
||||
Widget buildActivitiesButton() {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
onActivities(album);
|
||||
},
|
||||
onPressed: onActivities,
|
||||
icon: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@@ -271,7 +302,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
);
|
||||
} else {
|
||||
return IconButton(
|
||||
onPressed: () async => await context.maybePop(),
|
||||
onPressed: context.maybePop,
|
||||
icon: const Icon(Icons.arrow_back_ios_rounded),
|
||||
splashRadius: 25,
|
||||
);
|
||||
@@ -285,12 +316,13 @@ class AlbumViewerAppbar extends HookConsumerWidget
|
||||
actions: [
|
||||
if (album.shared && (album.activityEnabled || comments != 0))
|
||||
buildActivitiesButton(),
|
||||
if (album.isRemote)
|
||||
if (album.isRemote) ...[
|
||||
IconButton(
|
||||
splashRadius: 25,
|
||||
onPressed: buildBottomSheet,
|
||||
icon: const Icon(Icons.more_horiz_rounded),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@@ -4,20 +4,19 @@ 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_viewer.provider.dart';
|
||||
import 'package:immich_mobile/entities/album.entity.dart';
|
||||
|
||||
class AlbumViewerEditableTitle extends HookConsumerWidget {
|
||||
final Album album;
|
||||
final String albumName;
|
||||
final FocusNode titleFocusNode;
|
||||
const AlbumViewerEditableTitle({
|
||||
super.key,
|
||||
required this.album,
|
||||
required this.albumName,
|
||||
required this.titleFocusNode,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final titleTextEditController = useTextEditingController(text: album.name);
|
||||
final titleTextEditController = useTextEditingController(text: albumName);
|
||||
|
||||
void onFocusModeChange() {
|
||||
if (!titleFocusNode.hasFocus && titleTextEditController.text.isEmpty) {
|
||||
@@ -51,7 +50,7 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
|
||||
onTap: () {
|
||||
context.focusScope.requestFocus(titleFocusNode);
|
||||
|
||||
ref.watch(albumViewerProvider.notifier).setEditTitleText(album.name);
|
||||
ref.watch(albumViewerProvider.notifier).setEditTitleText(albumName);
|
||||
ref.watch(albumViewerProvider.notifier).enableEditAlbum();
|
||||
|
||||
if (titleTextEditController.text == 'Untitled') {
|
||||
|
Reference in New Issue
Block a user