This commit is contained in:
Alex
2025-04-14 15:17:20 -05:00
parent 5b7d8cb3ef
commit c334eba9b7
105 changed files with 50350 additions and 31087 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -35,6 +35,7 @@ import 'package:timezone/data/latest.dart';
void main() async {
ImmichWidgetsBinding();
EasyLocalization.logger.enableBuildModes = [];
final db = await Bootstrap.initIsar();
await Bootstrap.initDomain(db);
await initApp();

View File

@@ -43,7 +43,7 @@ class AlbumControlButton extends ConsumerWidget {
key: const ValueKey('add_users_button'),
iconData: Icons.person_add_alt_rounded,
onPressed: onAddUsersPressed,
labelText: "album_viewer_page_share_add_users".tr(),
labelText: "page_share_add_users".tr(),
),
],
),

View File

@@ -46,7 +46,7 @@ class AlbumViewer extends HookConsumerWidget {
if (!isSuccess) {
ImmichToast.show(
context: context,
msg: "album_viewer_appbar_share_err_remove".tr(),
msg: "appbar_share_err_remove".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);

View File

@@ -85,7 +85,7 @@ class BackupControllerPage extends HookConsumerWidget {
);
Widget buildSelectedAlbumName() {
var text = "backup_controller_page_backup_selected".tr();
var text = "backup_selected".tr();
var albums = ref.watch(backupProvider).selectedBackupAlbums;
if (albums.isNotEmpty) {
@@ -110,7 +110,7 @@ class BackupControllerPage extends HookConsumerWidget {
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"backup_controller_page_none_selected".tr(),
"none_selected".tr(),
style: context.textTheme.labelLarge?.copyWith(
color: context.primaryColor,
),
@@ -120,7 +120,7 @@ class BackupControllerPage extends HookConsumerWidget {
}
Widget buildExcludedAlbumName() {
var text = "backup_controller_page_excluded".tr();
var text = "excluded".tr();
var albums = ref.watch(backupProvider).excludedBackupAlbums;
if (albums.isNotEmpty) {
@@ -309,22 +309,22 @@ class BackupControllerPage extends HookConsumerWidget {
? [
buildFolderSelectionTile(),
BackupInfoCard(
title: "backup_controller_page_total".tr(),
subtitle: "backup_controller_page_total_sub".tr(),
title: "total".tr(),
subtitle: "total_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.allUniqueAssets.length}",
),
BackupInfoCard(
title: "backup_controller_page_backup".tr(),
subtitle: "backup_controller_page_backup_sub".tr(),
title: "backup".tr(),
subtitle: "backup_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${backupState.selectedAlbumsBackupAssetsIds.length}",
),
BackupInfoCard(
title: "backup_controller_page_remainder".tr(),
subtitle: "backup_controller_page_remainder_sub".tr(),
title: "remainder".tr(),
subtitle: "remainder_sub".tr(),
info: ref.watch(backupProvider).availableAlbums.isEmpty
? "..."
: "${max(0, backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length)}",

View File

@@ -309,7 +309,7 @@ class SearchPage extends HookConsumerWidget {
),
helpText: 'search_filter_date_title'.tr(),
cancelText: 'action_common_cancel'.tr(),
confirmText: 'action_common_select'.tr(),
confirmText: "select".tr(),
saveText: 'action_common_save'.tr(),
errorFormatText: 'invalid_date_format'.tr(),
errorInvalidText: 'invalid_date'.tr(),
@@ -804,7 +804,7 @@ class SearchEmptyContent extends StatelessWidget {
const SizedBox(height: 16),
Center(
child: Text(
'search_page_search_photos_videos'.tr(),
"search_photos_videos".tr(),
style: context.textTheme.labelLarge,
),
),

View File

@@ -63,7 +63,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
if (!success) {
ImmichToast.show(
context: context,
msg: "album_viewer_appbar_share_err_delete".tr(),
msg: "appbar_share_err_delete".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
@@ -118,7 +118,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
context.pop();
ImmichToast.show(
context: context,
msg: "album_viewer_appbar_share_err_leave".tr(),
msg: "appbar_share_err_leave".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
@@ -284,7 +284,7 @@ class AlbumViewerAppbar extends HookConsumerWidget
if (!isSuccess) {
ImmichToast.show(
context: context,
msg: "album_viewer_appbar_share_err_title".tr(),
msg: "appbar_share_err_title".tr(),
gravity: ToastGravity.BOTTOM,
toastType: ToastType.error,
);

View File

@@ -1,387 +1,387 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
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/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';
import 'package:immich_mobile/widgets/asset_grid/upload_dialog.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/widgets/common/drag_sheet.dart';
import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/utils/draggable_scroll_controller.dart';
final controlBottomAppBarNotifier = ControlBottomAppBarNotifier();
class ControlBottomAppBarNotifier with ChangeNotifier {
void minimize() {
notifyListeners();
}
}
class ControlBottomAppBar extends HookConsumerWidget {
final void Function(bool shareLocal) onShare;
final void Function()? onFavorite;
final void Function()? onArchive;
final void Function([bool force])? onDelete;
final void Function([bool force])? onDeleteServer;
final void Function(bool onlyBackedUp)? onDeleteLocal;
final Function(Album album) onAddToAlbum;
final void Function() onCreateNewAlbum;
final void Function() onUpload;
final void Function()? onStack;
final void Function()? onEditTime;
final void Function()? onEditLocation;
final void Function()? onRemoveFromAlbum;
final bool enabled;
final bool unfavorite;
final bool unarchive;
final AssetSelectionState selectionAssetState;
const ControlBottomAppBar({
super.key,
required this.onShare,
this.onFavorite,
this.onArchive,
this.onDelete,
this.onDeleteServer,
this.onDeleteLocal,
required this.onAddToAlbum,
required this.onCreateNewAlbum,
required this.onUpload,
this.onStack,
this.onEditTime,
this.onEditLocation,
this.onRemoveFromAlbum,
this.selectionAssetState = const AssetSelectionState(),
this.enabled = true,
this.unarchive = false,
this.unfavorite = false,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final hasRemote =
selectionAssetState.hasRemote || selectionAssetState.hasMerged;
final hasLocal =
selectionAssetState.hasLocal || selectionAssetState.hasMerged;
final trashEnabled =
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
final albums = ref.watch(albumProvider).where((a) => a.isRemote).toList();
final sharedAlbums =
ref.watch(albumProvider).where((a) => a.shared).toList();
const bottomPadding = 0.20;
final scrollController = useDraggableScrollController();
void minimize() {
scrollController.animateTo(
bottomPadding,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
useEffect(
() {
controlBottomAppBarNotifier.addListener(minimize);
return () {
controlBottomAppBarNotifier.removeListener(minimize);
};
},
[],
);
void showForceDeleteDialog(
Function(bool) deleteCb, {
String? alertMsg,
}) {
showDialog(
context: context,
builder: (BuildContext context) {
return DeleteDialog(
alert: alertMsg,
onDelete: () => deleteCb(true),
);
},
);
}
void handleRemoteDelete(
bool force,
Function(bool) deleteCb, {
String? alertMsg,
}) {
if (!force) {
deleteCb(force);
return;
}
return showForceDeleteDialog(deleteCb, alertMsg: alertMsg);
}
List<Widget> renderActionButtons() {
return [
if (hasRemote)
ControlBoxButton(
iconData: Platform.isAndroid
? Icons.share_rounded
: Icons.ios_share_rounded,
label: "control_bottom_app_bar_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 (hasRemote && onArchive != null)
ControlBoxButton(
iconData:
unarchive ? Icons.unarchive_outlined : Icons.archive_outlined,
label: (unarchive
? "control_bottom_app_bar_unarchive"
: "control_bottom_app_bar_archive")
.tr(),
onPressed: enabled ? onArchive : null,
),
if (hasRemote && onFavorite != null)
ControlBoxButton(
iconData: unfavorite
? Icons.favorite_border_rounded
: Icons.favorite_rounded,
label: (unfavorite
? "control_bottom_app_bar_unfavorite"
: "control_bottom_app_bar_favorite")
.tr(),
onPressed: enabled ? onFavorite : null,
),
if (hasLocal && hasRemote && onDelete != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.delete_sweep_outlined,
label: "control_bottom_app_bar_delete".tr(),
onPressed: enabled
? () => handleRemoteDelete(!trashEnabled, onDelete!)
: null,
onLongPressed:
enabled ? () => showForceDeleteDialog(onDelete!) : null,
),
),
if (hasRemote && onDeleteServer != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 85),
child: ControlBoxButton(
iconData: Icons.cloud_off_outlined,
label: trashEnabled
? "control_bottom_app_bar_trash_from_immich".tr()
: "control_bottom_app_bar_delete_from_immich".tr(),
onPressed: enabled
? () => handleRemoteDelete(
!trashEnabled,
onDeleteServer!,
alertMsg: "delete_dialog_alert_remote",
)
: null,
onLongPressed: enabled
? () => showForceDeleteDialog(
onDeleteServer!,
alertMsg: "delete_dialog_alert_remote",
)
: null,
),
),
if (hasLocal && onDeleteLocal != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 85),
child: ControlBoxButton(
iconData: Icons.no_cell_outlined,
label: "control_bottom_app_bar_delete_from_local".tr(),
onPressed: enabled
? () {
if (!selectionAssetState.hasLocal) {
return onDeleteLocal?.call(true);
}
showDialog(
context: context,
builder: (BuildContext context) {
return DeleteLocalOnlyDialog(
onDeleteLocal: onDeleteLocal!,
);
},
);
}
: null,
),
),
if (hasRemote && onEditTime != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 95),
child: ControlBoxButton(
iconData: Icons.edit_calendar_outlined,
label: "control_bottom_app_bar_edit_time".tr(),
onPressed: enabled ? onEditTime : null,
),
),
if (hasRemote && onEditLocation != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.edit_location_alt_outlined,
label: "control_bottom_app_bar_edit_location".tr(),
onPressed: enabled ? onEditLocation : null,
),
),
if (!selectionAssetState.hasLocal &&
selectionAssetState.selectedCount > 1 &&
onStack != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.filter_none_rounded,
label: "control_bottom_app_bar_stack".tr(),
onPressed: enabled ? onStack : null,
),
),
if (onRemoveFromAlbum != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.remove_circle_outline,
label: 'album_viewer_appbar_share_remove'.tr(),
onPressed: enabled ? onRemoveFromAlbum : null,
),
),
if (selectionAssetState.hasLocal)
ControlBoxButton(
iconData: Icons.backup_outlined,
label: "control_bottom_app_bar_upload".tr(),
onPressed: enabled
? () => showDialog(
context: context,
builder: (BuildContext context) {
return UploadDialog(
onUpload: onUpload,
);
},
)
: null,
),
];
}
return DraggableScrollableSheet(
controller: scrollController,
initialChildSize: hasRemote ? 0.35 : bottomPadding,
minChildSize: bottomPadding,
maxChildSize: hasRemote ? 0.65 : bottomPadding,
snap: true,
builder: (
BuildContext context,
ScrollController scrollController,
) {
return Card(
color: context.colorScheme.surfaceContainerLow,
surfaceTintColor: Colors.transparent,
elevation: 18.0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
margin: const EdgeInsets.all(0),
child: CustomScrollView(
controller: scrollController,
slivers: [
SliverToBoxAdapter(
child: Column(
children: <Widget>[
const SizedBox(height: 12),
const CustomDraggingHandle(),
const SizedBox(height: 12),
SizedBox(
height: 100,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: renderActionButtons(),
),
),
if (hasRemote)
const Divider(
indent: 16,
endIndent: 16,
thickness: 1,
),
if (hasRemote)
_AddToAlbumTitleRow(
onCreateNewAlbum: enabled ? onCreateNewAlbum : null,
),
],
),
),
if (hasRemote)
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: AddToAlbumSliverList(
albums: albums,
sharedAlbums: sharedAlbums,
onAddToAlbum: onAddToAlbum,
enabled: enabled,
),
),
],
),
);
},
);
}
}
class _AddToAlbumTitleRow extends StatelessWidget {
const _AddToAlbumTitleRow({
required this.onCreateNewAlbum,
});
final VoidCallback? onCreateNewAlbum;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"common_add_to_album",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
).tr(),
TextButton.icon(
onPressed: onCreateNewAlbum,
icon: Icon(
Icons.add,
color: context.primaryColor,
),
label: Text(
"common_create_new_album",
style: TextStyle(
color: context.primaryColor,
fontWeight: FontWeight.bold,
fontSize: 14,
),
).tr(),
),
],
),
);
}
}
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
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/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';
import 'package:immich_mobile/widgets/asset_grid/upload_dialog.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/widgets/common/drag_sheet.dart';
import 'package:immich_mobile/entities/album.entity.dart';
import 'package:immich_mobile/utils/draggable_scroll_controller.dart';
final controlBottomAppBarNotifier = ControlBottomAppBarNotifier();
class ControlBottomAppBarNotifier with ChangeNotifier {
void minimize() {
notifyListeners();
}
}
class ControlBottomAppBar extends HookConsumerWidget {
final void Function(bool shareLocal) onShare;
final void Function()? onFavorite;
final void Function()? onArchive;
final void Function([bool force])? onDelete;
final void Function([bool force])? onDeleteServer;
final void Function(bool onlyBackedUp)? onDeleteLocal;
final Function(Album album) onAddToAlbum;
final void Function() onCreateNewAlbum;
final void Function() onUpload;
final void Function()? onStack;
final void Function()? onEditTime;
final void Function()? onEditLocation;
final void Function()? onRemoveFromAlbum;
final bool enabled;
final bool unfavorite;
final bool unarchive;
final AssetSelectionState selectionAssetState;
const ControlBottomAppBar({
super.key,
required this.onShare,
this.onFavorite,
this.onArchive,
this.onDelete,
this.onDeleteServer,
this.onDeleteLocal,
required this.onAddToAlbum,
required this.onCreateNewAlbum,
required this.onUpload,
this.onStack,
this.onEditTime,
this.onEditLocation,
this.onRemoveFromAlbum,
this.selectionAssetState = const AssetSelectionState(),
this.enabled = true,
this.unarchive = false,
this.unfavorite = false,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final hasRemote =
selectionAssetState.hasRemote || selectionAssetState.hasMerged;
final hasLocal =
selectionAssetState.hasLocal || selectionAssetState.hasMerged;
final trashEnabled =
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
final albums = ref.watch(albumProvider).where((a) => a.isRemote).toList();
final sharedAlbums =
ref.watch(albumProvider).where((a) => a.shared).toList();
const bottomPadding = 0.20;
final scrollController = useDraggableScrollController();
void minimize() {
scrollController.animateTo(
bottomPadding,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
useEffect(
() {
controlBottomAppBarNotifier.addListener(minimize);
return () {
controlBottomAppBarNotifier.removeListener(minimize);
};
},
[],
);
void showForceDeleteDialog(
Function(bool) deleteCb, {
String? alertMsg,
}) {
showDialog(
context: context,
builder: (BuildContext context) {
return DeleteDialog(
alert: alertMsg,
onDelete: () => deleteCb(true),
);
},
);
}
void handleRemoteDelete(
bool force,
Function(bool) deleteCb, {
String? alertMsg,
}) {
if (!force) {
deleteCb(force);
return;
}
return showForceDeleteDialog(deleteCb, alertMsg: alertMsg);
}
List<Widget> renderActionButtons() {
return [
if (hasRemote)
ControlBoxButton(
iconData: Platform.isAndroid
? Icons.share_rounded
: Icons.ios_share_rounded,
label: "control_bottom_app_bar_share".tr(),
onPressed: enabled ? () => onShare(true) : null,
),
ControlBoxButton(
iconData: Icons.link_rounded,
label: "share_link".tr(),
onPressed: enabled ? () => onShare(false) : null,
),
if (hasRemote && onArchive != null)
ControlBoxButton(
iconData:
unarchive ? Icons.unarchive_outlined : Icons.archive_outlined,
label: (unarchive
? "control_bottom_app_bar_unarchive"
: "control_bottom_app_bar_archive")
.tr(),
onPressed: enabled ? onArchive : null,
),
if (hasRemote && onFavorite != null)
ControlBoxButton(
iconData: unfavorite
? Icons.favorite_border_rounded
: Icons.favorite_rounded,
label: (unfavorite
? "control_bottom_app_bar_unfavorite"
: "control_bottom_app_bar_favorite")
.tr(),
onPressed: enabled ? onFavorite : null,
),
if (hasLocal && hasRemote && onDelete != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.delete_sweep_outlined,
label: "control_bottom_app_bar_delete".tr(),
onPressed: enabled
? () => handleRemoteDelete(!trashEnabled, onDelete!)
: null,
onLongPressed:
enabled ? () => showForceDeleteDialog(onDelete!) : null,
),
),
if (hasRemote && onDeleteServer != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 85),
child: ControlBoxButton(
iconData: Icons.cloud_off_outlined,
label: trashEnabled
? "trash_from_immich".tr()
: "delete_from_immich".tr(),
onPressed: enabled
? () => handleRemoteDelete(
!trashEnabled,
onDeleteServer!,
alertMsg: "delete_dialog_alert_remote",
)
: null,
onLongPressed: enabled
? () => showForceDeleteDialog(
onDeleteServer!,
alertMsg: "delete_dialog_alert_remote",
)
: null,
),
),
if (hasLocal && onDeleteLocal != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 85),
child: ControlBoxButton(
iconData: Icons.no_cell_outlined,
label: "delete_from_local".tr(),
onPressed: enabled
? () {
if (!selectionAssetState.hasLocal) {
return onDeleteLocal?.call(true);
}
showDialog(
context: context,
builder: (BuildContext context) {
return DeleteLocalOnlyDialog(
onDeleteLocal: onDeleteLocal!,
);
},
);
}
: null,
),
),
if (hasRemote && onEditTime != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 95),
child: ControlBoxButton(
iconData: Icons.edit_calendar_outlined,
label: "edit_time".tr(),
onPressed: enabled ? onEditTime : null,
),
),
if (hasRemote && onEditLocation != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.edit_location_alt_outlined,
label: "control_bottom_app_bar_edit_location".tr(),
onPressed: enabled ? onEditLocation : null,
),
),
if (!selectionAssetState.hasLocal &&
selectionAssetState.selectedCount > 1 &&
onStack != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.filter_none_rounded,
label: "control_bottom_app_bar_stack".tr(),
onPressed: enabled ? onStack : null,
),
),
if (onRemoveFromAlbum != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
iconData: Icons.remove_circle_outline,
label: "appbar_share_remove".tr(),
onPressed: enabled ? onRemoveFromAlbum : null,
),
),
if (selectionAssetState.hasLocal)
ControlBoxButton(
iconData: Icons.backup_outlined,
label: "control_bottom_app_bar_upload".tr(),
onPressed: enabled
? () => showDialog(
context: context,
builder: (BuildContext context) {
return UploadDialog(
onUpload: onUpload,
);
},
)
: null,
),
];
}
return DraggableScrollableSheet(
controller: scrollController,
initialChildSize: hasRemote ? 0.35 : bottomPadding,
minChildSize: bottomPadding,
maxChildSize: hasRemote ? 0.65 : bottomPadding,
snap: true,
builder: (
BuildContext context,
ScrollController scrollController,
) {
return Card(
color: context.colorScheme.surfaceContainerLow,
surfaceTintColor: Colors.transparent,
elevation: 18.0,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12),
),
),
margin: const EdgeInsets.all(0),
child: CustomScrollView(
controller: scrollController,
slivers: [
SliverToBoxAdapter(
child: Column(
children: <Widget>[
const SizedBox(height: 12),
const CustomDraggingHandle(),
const SizedBox(height: 12),
SizedBox(
height: 100,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: renderActionButtons(),
),
),
if (hasRemote)
const Divider(
indent: 16,
endIndent: 16,
thickness: 1,
),
if (hasRemote)
_AddToAlbumTitleRow(
onCreateNewAlbum: enabled ? onCreateNewAlbum : null,
),
],
),
),
if (hasRemote)
SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: AddToAlbumSliverList(
albums: albums,
sharedAlbums: sharedAlbums,
onAddToAlbum: onAddToAlbum,
enabled: enabled,
),
),
],
),
);
},
);
}
}
class _AddToAlbumTitleRow extends StatelessWidget {
const _AddToAlbumTitleRow({
required this.onCreateNewAlbum,
});
final VoidCallback? onCreateNewAlbum;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"common_add_to_album",
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
).tr(),
TextButton.icon(
onPressed: onCreateNewAlbum,
icon: Icon(
Icons.add,
color: context.primaryColor,
),
label: Text(
"common_create_new_album",
style: TextStyle(
color: context.primaryColor,
fontWeight: FontWeight.bold,
fontSize: 14,
),
).tr(),
),
],
),
);
}
}

View File

@@ -260,7 +260,7 @@ class BottomGalleryBar extends ConsumerWidget {
} else {
ImmichToast.show(
context: context,
msg: "album_viewer_appbar_share_err_remove".tr(),
msg: "appbar_share_err_remove".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
@@ -327,8 +327,8 @@ class BottomGalleryBar extends ConsumerWidget {
{
BottomNavigationBarItem(
icon: const Icon(Icons.remove_circle_outline),
label: 'album_viewer_appbar_share_remove'.tr(),
tooltip: 'album_viewer_appbar_share_remove'.tr(),
label: "appbar_share_remove".tr(),
tooltip: "appbar_share_remove".tr(),
): (_) => handleRemoveFromAlbum(),
},
];

View File

@@ -82,7 +82,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
strokeWidth: 2,
strokeCap: StrokeCap.round,
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
semanticsLabel: 'backup_controller_page_backup'.tr(),
semanticsLabel: "backup".tr(),
),
);
} else if (backupState.backupProgress !=
@@ -92,7 +92,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
Icons.check_outlined,
size: 9,
color: iconColor,
semanticLabel: 'backup_controller_page_backup'.tr(),
semanticLabel: "backup".tr(),
);
}
}
@@ -102,7 +102,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
Icons.cloud_off_rounded,
size: 9,
color: iconColor,
semanticLabel: 'backup_controller_page_backup'.tr(),
semanticLabel: "backup".tr(),
);
}
}

View File

@@ -37,7 +37,7 @@ class PersonNameEditForm extends HookConsumerWidget {
controller: controller,
autofocus: true,
decoration: InputDecoration(
hintText: 'search_page_person_add_name_dialog_hint'.tr(),
hintText: "person_add_name_dialog_hint".tr(),
border: const OutlineInputBorder(),
errorText: isError.value ? 'Error occured' : null,
),

View File

@@ -18,7 +18,7 @@ class SearchMapThumbnail extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ThumbnailWithInfoContainer(
label: 'search_page_your_map'.tr(),
label: "your_map".tr(),
onTap: () {
context.pushRoute(const MapRoute());
},

View File

@@ -32,19 +32,19 @@ class GroupSettings extends HookConsumerWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SettingsSubTitle(title: "asset_list_group_by_sub_title".tr()),
SettingsSubTitle(title: "group_by_sub_title".tr()),
SettingsRadioListTile(
groups: [
SettingsRadioGroup(
title: 'asset_list_layout_settings_group_by_month_day'.tr(),
title: "layout_settings_group_by_month_day".tr(),
value: GroupAssetsBy.day,
),
SettingsRadioGroup(
title: 'asset_list_layout_settings_group_by_month'.tr(),
title: "layout_settings_group_by_month".tr(),
value: GroupAssetsBy.month,
),
SettingsRadioGroup(
title: 'asset_list_layout_settings_group_automatically'.tr(),
title: "layout_settings_group_automatically".tr(),
value: GroupAssetsBy.auto,
),
],

View File

@@ -21,10 +21,10 @@ class LayoutSettings extends HookConsumerWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SettingsSubTitle(title: "asset_list_layout_sub_title".tr()),
SettingsSubTitle(title: "layout_sub_title".tr()),
SettingsSwitchListTile(
valueNotifier: useDynamicLayout,
title: "asset_list_layout_settings_dynamic_layout_title".tr(),
title: "layout_settings_dynamic_layout_title".tr(),
onChanged: (_) => ref.invalidate(appSettingsServiceProvider),
),
SettingsSliderListTile(

View File

@@ -22,7 +22,7 @@ class AssetListSettings extends HookConsumerWidget {
final assetListSetting = [
SettingsSwitchListTile(
valueNotifier: showStorageIndicator,
title: 'theme_setting_asset_list_storage_indicator_title'.tr(),
title: "asset_list_storage_indicator_title".tr(),
onChanged: (_) => ref.invalidate(appSettingsServiceProvider),
),
const LayoutSettings(),

View File

@@ -77,9 +77,9 @@ class BackgroundBackupSettings extends ConsumerWidget {
if (!isBackgroundEnabled) {
return SettingsButtonListTile(
icon: Icons.cloud_sync_outlined,
title: 'backup_controller_page_background_is_off'.tr(),
subtileText: 'backup_controller_page_background_description'.tr(),
buttonText: 'backup_controller_page_background_turn_on'.tr(),
title: "background_is_off".tr(),
subtileText: "background_description".tr(),
buttonText: "background_turn_on".tr(),
onButtonTap: () =>
ref.read(backupProvider.notifier).configureBackgroundBackup(
enabled: true,
@@ -111,9 +111,9 @@ class _IOSBackgroundRefreshDisabled extends StatelessWidget {
return SettingsButtonListTile(
icon: Icons.task_outlined,
title:
'backup_controller_page_background_app_refresh_disabled_title'.tr(),
"background_app_refresh_disabled_title".tr(),
subtileText:
'backup_controller_page_background_app_refresh_disabled_content'.tr(),
"background_app_refresh_disabled_content".tr(),
buttonText:
'backup_controller_page_background_app_refresh_enable_button_text'
.tr(),
@@ -185,8 +185,8 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget {
return SettingsButtonListTile(
icon: Icons.cloud_sync_rounded,
iconColor: context.primaryColor,
title: 'backup_controller_page_background_is_on'.tr(),
buttonText: 'backup_controller_page_background_turn_off'.tr(),
title: "background_is_on".tr(),
buttonText: "background_turn_off".tr(),
onButtonTap: () =>
ref.read(backupProvider.notifier).configureBackgroundBackup(
enabled: false,
@@ -197,7 +197,7 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget {
children: [
SettingsSwitchListTile(
valueNotifier: isWifiRequiredNotifier,
title: 'backup_controller_page_background_wifi'.tr(),
title: "background_wifi".tr(),
icon: Icons.wifi,
onChanged: (enabled) =>
ref.read(backupProvider.notifier).configureBackgroundBackup(
@@ -208,7 +208,7 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget {
),
SettingsSwitchListTile(
valueNotifier: isChargingRequiredNotifier,
title: 'backup_controller_page_background_charging'.tr(),
title: "background_charging".tr(),
icon: Icons.charging_station,
onChanged: (enabled) =>
ref.read(backupProvider.notifier).configureBackgroundBackup(

View File

@@ -19,17 +19,17 @@ class ForegroundBackupSettings extends ConsumerWidget {
return SettingsButtonListTile(
icon: Icons.cloud_done_rounded,
iconColor: context.primaryColor,
title: 'backup_controller_page_status_on'.tr(),
buttonText: 'backup_controller_page_turn_off'.tr(),
title: "status_on".tr(),
buttonText: "turn_off".tr(),
onButtonTap: onButtonTap,
);
}
return SettingsButtonListTile(
icon: Icons.cloud_off_rounded,
title: 'backup_controller_page_status_off'.tr(),
subtileText: 'backup_controller_page_desc_backup'.tr(),
buttonText: 'backup_controller_page_turn_on'.tr(),
title: "status_off".tr(),
subtileText: "desc_backup".tr(),
buttonText: "turn_on".tr(),
onButtonTap: onButtonTap,
);
}

View File

@@ -122,7 +122,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
Align(
alignment: Alignment.center,
child: Text(
"theme_setting_primary_color_title".tr(),
"primary_color_title".tr(),
style: context.textTheme.titleLarge,
),
),
@@ -140,7 +140,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
borderRadius: BorderRadius.circular(15),
),
title: Text(
'theme_setting_system_primary_color_title'.tr(),
"system_primary_color_title".tr(),
style: context.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w500,
height: 1.5,
@@ -194,13 +194,13 @@ class PrimaryColorSetting extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"theme_setting_primary_color_title".tr(),
"primary_color_title".tr(),
style: context.textTheme.bodyLarge?.copyWith(
fontWeight: FontWeight.w500,
),
),
Text(
"theme_setting_primary_color_subtitle".tr(),
"primary_color_subtitle".tr(),
style: context.textTheme.bodyMedium
?.copyWith(color: context.colorScheme.onSurfaceSecondary),
),

View File

@@ -81,23 +81,23 @@ class ThemeSetting extends HookConsumerWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SettingsSubTitle(title: "theme_setting_theme_title".tr()),
SettingsSubTitle(title: "theme_title".tr()),
SettingsSwitchListTile(
valueNotifier: isSystemTheme,
title: 'theme_setting_system_theme_switch'.tr(),
title: "system_theme_switch".tr(),
onChanged: onSystemThemeChange,
),
if (currentTheme.value != ThemeMode.system)
SettingsSwitchListTile(
valueNotifier: isDarkTheme,
title: 'theme_setting_dark_mode_switch'.tr(),
title: "dark_mode_switch".tr(),
onChanged: onThemeChange,
),
const PrimaryColorSetting(),
SettingsSwitchListTile(
valueNotifier: applyThemeToBackgroundProvider,
title: "theme_setting_colorful_interface_title".tr(),
subtitle: 'theme_setting_colorful_interface_subtitle'.tr(),
title: "colorful_interface_title".tr(),
subtitle: "colorful_interface_subtitle".tr(),
onChanged: onSurfaceColorSettingChange,
),
],