chore: migrate mobile translations accessor (4)

This commit is contained in:
shenlong-tanwen 2026-08-08 16:52:37 +05:30 committed by shenlong
parent cb313ce773
commit 0ae1213ed0
29 changed files with 305 additions and 344 deletions

View file

@ -2,7 +2,6 @@ import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:collection/collection.dart';
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';
@ -10,6 +9,7 @@ import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/models/folder/recursive_folder.model.dart';
import 'package:immich_mobile/models/folder/root_folder.model.dart';
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
@ -20,6 +20,7 @@ import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/utils/bytes_units.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart';
import 'package:intl/intl.dart';
RecursiveFolder? _findFolderInStructure(RootFolder rootFolder, RecursiveFolder targetFolder) {
for (final folder in rootFolder.subfolders) {
@ -81,7 +82,7 @@ class FolderPage extends HookConsumerWidget {
return Scaffold(
appBar: AppBar(
title: Text(currentFolder.value?.name ?? tr("folders")),
title: Text(currentFolder.value?.name ?? context.t.folders),
elevation: 0,
centerTitle: false,
actions: [IconButton(icon: const Icon(Icons.swap_vert), onPressed: onToggleSortOrder)],
@ -96,8 +97,8 @@ class FolderPage extends HookConsumerWidget {
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) {
ImmichToast.show(context: context, msg: "failed_to_load_folder".tr(), toastType: ToastType.error);
return Center(child: const Text("failed_to_load_folder").tr());
ImmichToast.show(context: context, msg: context.t.failed_to_load_folder, toastType: ToastType.error);
return Center(child: Text(context.t.failed_to_load_folder));
},
),
);
@ -125,16 +126,16 @@ class FolderContent extends HookConsumerWidget {
}, [folder]);
if (folder == null) {
return Center(child: const Text("folder_not_found").tr());
return Center(child: Text(context.t.folder_not_found));
}
String getSubtitle(int subFolderCount) {
if (subFolderCount > 0) {
return "$subFolderCount ${tr("folders")}".toLowerCase();
return "$subFolderCount ${context.t.folders}".toLowerCase();
}
if (subFolderCount == 1) {
return "1 ${tr("folder")}".toLowerCase();
return "1 ${context.t.folder}".toLowerCase();
}
return "";
@ -147,7 +148,7 @@ class FolderContent extends HookConsumerWidget {
child: folderRenderlist.when(
data: (folderAssets) {
if (folder!.subfolders.isEmpty && folderAssets.isEmpty) {
return Center(child: const Text("empty_folder").tr());
return Center(child: Text(context.t.empty_folder));
}
return ListView(
@ -211,8 +212,8 @@ class FolderContent extends HookConsumerWidget {
},
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) {
ImmichToast.show(context: context, msg: "failed_to_load_assets".tr(), toastType: ToastType.error);
return Center(child: const Text("failed_to_load_assets").tr());
ImmichToast.show(context: context, msg: context.t.failed_to_load_assets, toastType: ToastType.error);
return Center(child: Text(context.t.failed_to_load_assets));
},
),
),

View file

@ -1,11 +1,11 @@
import 'dart:async';
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' show useState;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/local_auth.provider.dart';
import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/widgets/forms/pin_registration_form.dart';
@ -31,7 +31,7 @@ class PinAuthPage extends HookConsumerWidget {
context.showSnackBar(
SnackBar(
content: Text('biometric_auth_enabled'.tr(), style: context.textTheme.labelLarge),
content: Text(context.t.biometric_auth_enabled, style: context.textTheme.labelLarge),
duration: const Duration(seconds: 3),
backgroundColor: context.colorScheme.primaryContainer,
),
@ -52,7 +52,7 @@ class PinAuthPage extends HookConsumerWidget {
mainAxisSize: MainAxisSize.min,
children: [
PinVerificationForm(
description: 'enable_biometric_auth_description'.tr(),
description: context.t.enable_biometric_auth_description,
onSuccess: (pinCode) {
Navigator.pop(buildContext);
unawaited(registerBiometric(pinCode));
@ -71,7 +71,7 @@ class PinAuthPage extends HookConsumerWidget {
}
return Scaffold(
appBar: AppBar(title: Text('locked_folder'.tr())),
appBar: AppBar(title: Text(context.t.locked_folder)),
body: ListView(
shrinkWrap: true,
children: [
@ -97,7 +97,7 @@ class PinAuthPage extends HookConsumerWidget {
icon: const Icon(Icons.fingerprint, size: 28),
onPressed: () => unawaited(enableBiometricAuth()),
label: Text(
'use_biometric'.tr(),
context.t.use_biometric,
style: context.textTheme.labelLarge?.copyWith(color: context.primaryColor, fontSize: 18),
),
),

View file

@ -1,11 +1,11 @@
import 'dart:async';
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:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/models/shared_link/shared_link.model.dart';
import 'package:immich_mobile/providers/shared_link.provider.dart';
import 'package:immich_mobile/widgets/shared_link/shared_link_item.dart';
@ -36,7 +36,7 @@ class SharedLinkPage extends HookConsumerWidget {
children: [
Icon(Icons.link_off, size: 100, color: Theme.of(context).colorScheme.onSurface.withAlpha(128)),
const SizedBox(height: 20),
const Text("you_dont_have_any_shared_links", style: TextStyle(fontSize: 14)).tr(),
Text(context.t.you_dont_have_any_shared_links, style: const TextStyle(fontSize: 14)),
],
),
);
@ -68,7 +68,7 @@ class SharedLinkPage extends HookConsumerWidget {
}
return Scaffold(
appBar: AppBar(title: const Text("shared_link_app_bar_title").tr(), elevation: 0, centerTitle: false),
appBar: AppBar(title: Text(context.t.shared_link_app_bar_title), elevation: 0, centerTitle: false),
body: SafeArea(
child: sharedLinks.widgetWhen(
onError: (error, stackTrace) => buildNoShares(),

View file

@ -10,7 +10,7 @@ import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/pages/drift_user_selection.page.dart';
import 'package:immich_mobile/providers/auth.provider.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
@ -37,7 +37,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
ContextHelper(context).pop();
ImmichToast.show(
context: context,
msg: "shared_album_section_people_action_error".t(context: context),
msg: context.t.shared_album_section_people_action_error,
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
@ -87,7 +87,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
ImmichToast.show(
context: context,
msg: "users_added_to_album_count".t(context: context, args: {'count': newUsers.length}),
msg: context.t.users_added_to_album_count(count: newUsers.length),
toastType: ToastType.success,
);
} catch (e) {
@ -106,7 +106,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
actions = [
ListTile(
leading: const Icon(Icons.exit_to_app_rounded),
title: const Text("leave_album").t(context: context),
title: Text(context.t.leave_album),
onTap: leaveAlbum,
),
];
@ -116,7 +116,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
actions = [
ListTile(
leading: const Icon(Icons.person_remove_rounded),
title: const Text("remove_user").t(context: context),
title: Text(context.t.remove_user),
onTap: () => removeUserFromAlbum(user),
),
];
@ -146,7 +146,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
leading: owner != null ? UserCircleAvatar(user: owner) : const SizedBox(),
title: Text(album.ownerName, style: const TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text(owner?.email ?? "", style: TextStyle(color: context.colorScheme.onSurfaceSecondary)),
trailing: Text("owner", style: context.textTheme.labelLarge).t(context: context),
trailing: Text(context.t.owner, style: context.textTheme.labelLarge),
);
} else {
final usersProvider = ref.read(driftUsersProvider);
@ -162,7 +162,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
leading: UserCircleAvatar(user: user),
title: Text(user.name, style: const TextStyle(fontWeight: FontWeight.w500)),
subtitle: Text(user.email, style: TextStyle(color: context.colorScheme.onSurfaceSecondary)),
trailing: Text("owner", style: context.textTheme.labelLarge).t(context: context),
trailing: Text(context.t.owner, style: context.textTheme.labelLarge),
);
},
orElse: () => const SizedBox(),
@ -207,7 +207,7 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
onPressed: () => context.maybePop(null),
),
centerTitle: true,
title: Text("options".t(context: context)),
title: Text(context.t.options),
),
body: ListView(
children: [
@ -222,19 +222,19 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
activeThumbColor: activityEnabled.value ? context.primaryColor : context.themeData.disabledColor,
dense: true,
title: Text(
"comments_and_likes",
context.t.comments_and_likes,
style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500),
).t(context: context),
),
subtitle: Text(
"let_others_respond",
context.t.let_others_respond,
style: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.onSurfaceSecondary),
).t(context: context),
),
),
buildSectionTitle("shared_album_section_people_title".t(context: context)),
buildSectionTitle(context.t.shared_album_section_people_title),
if (isOwner) ...[
ListTile(
leading: const Icon(Icons.person_add_rounded),
title: Text("invite_people".t(context: context)),
title: Text(context.t.invite_people),
onTap: () async => addUsers(),
),
const Divider(indent: 16),

View file

@ -1,7 +1,7 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/archive_bottom_sheet.widget.dart';
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
@ -28,10 +28,7 @@ class DriftArchivePage extends StatelessWidget {
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(
title: 'archive'.t(context: context),
icon: Icons.archive_outlined,
),
appBar: MesmerizingSliverAppBar(title: context.t.archive, icon: Icons.archive_outlined),
bottomSheet: const ArchiveBottomSheet(),
),
);

View file

@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/routing/router.dart';
@ -52,9 +52,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
bool get _canCreateAlbum => albumTitleController.text.trim().isNotEmpty && !isCreatingAlbum;
String _getEffectiveTitle() {
return albumTitleController.text.isNotEmpty
? albumTitleController.text
: 'create_album_page_untitled'.t(context: context);
return albumTitleController.text.isNotEmpty ? albumTitleController.text : context.t.create_album_page_untitled;
}
Widget _buildSliverAppBar() {
@ -93,7 +91,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
Widget _buildEmptyState() {
return Padding(
padding: const EdgeInsets.only(top: 0, left: 18),
child: Text('create_shared_album_page_share_add_assets', style: context.textTheme.labelLarge).t(),
child: Text(context.t.create_shared_album_page_share_add_assets, style: context.textTheme.labelLarge),
);
}
@ -112,9 +110,9 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
label: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
'create_shared_album_page_share_select_photos',
context.t.create_shared_album_page_share_select_photos,
style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
).t(),
),
),
),
);
@ -148,7 +146,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
});
if (albumTitleController.text.isEmpty) {
final untitledText = 'create_album_page_untitled'.t();
final untitledText = context.t.create_album_page_untitled;
albumTitleController.text = untitledText;
}
}
@ -196,7 +194,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
return;
}
ImmichToast.show(context: context, toastType: ToastType.error, msg: 'errors.failed_to_create_album'.t());
ImmichToast.show(context: context, toastType: ToastType.error, msg: context.t.errors.failed_to_create_album);
} finally {
if (mounted) {
setState(() => isCreatingAlbum = false);
@ -241,7 +239,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
AlbumActionFilledButton(
iconData: Icons.add_photo_alternate_outlined,
onPressed: onSelectPhotos,
labelText: "add_photos".t(),
labelText: context.t.add_photos,
),
],
),
@ -257,12 +255,12 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
centerTitle: false,
backgroundColor: context.scaffoldBackgroundColor,
leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.close_rounded)),
title: const Text('create_album').t(),
title: Text(context.t.create_album),
actions: [
TextButton(
onPressed: _canCreateAlbum ? createAlbum : null,
child: Text(
'create'.t(),
context.t.create,
style: TextStyle(
fontWeight: FontWeight.bold,
color: _canCreateAlbum ? context.primaryColor : context.themeData.disabledColor,
@ -320,7 +318,7 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> {
style: TextStyle(fontSize: 28.0, color: context.colorScheme.onSurface, fontWeight: FontWeight.bold),
controller: widget.textController,
onTap: () {
if (widget.textController.text == 'create_album_page_untitled'.t(context: context)) {
if (widget.textController.text == context.t.create_album_page_untitled) {
widget.textController.clear();
}
},
@ -343,7 +341,7 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> {
borderSide: BorderSide(color: context.primaryColor.withValues(alpha: 0.3)),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
),
hintText: 'add_a_title'.t(),
hintText: context.t.add_a_title,
hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith(
fontSize: 28.0,
fontWeight: FontWeight.bold,
@ -430,7 +428,7 @@ class _AlbumViewerEditableDescriptionState extends State<_AlbumViewerEditableDes
focusColor: Colors.grey[300],
fillColor: context.scaffoldBackgroundColor,
filled: widget.focusNode.hasFocus,
hintText: 'add_a_description'.t(),
hintText: context.t.add_a_description,
),
),
);

View file

@ -1,11 +1,10 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/user.model.dart';
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/images/local_album_thumbnail.widget.dart';
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
import 'package:immich_mobile/presentation/widgets/people/partner_user_avatar.widget.dart';
@ -56,13 +55,13 @@ class _ActionButtonGrid extends ConsumerWidget {
_ActionButton(
icon: Icons.favorite_outline_rounded,
onTap: () => context.pushRoute(const DriftFavoriteRoute()),
label: 'favorites'.t(context: context),
label: context.t.favorites,
),
const SizedBox(width: 8),
_ActionButton(
icon: Icons.archive_outlined,
onTap: () => context.pushRoute(const DriftArchiveRoute()),
label: 'archived'.t(context: context),
label: context.t.archived,
),
],
),
@ -72,14 +71,14 @@ class _ActionButtonGrid extends ConsumerWidget {
_ActionButton(
icon: Icons.link_outlined,
onTap: () => context.pushRoute(const SharedLinkRoute()),
label: 'shared_links'.t(context: context),
label: context.t.shared_links,
),
isTrashEnable ? const SizedBox(width: 8) : const SizedBox.shrink(),
isTrashEnable
? _ActionButton(
icon: Icons.delete_outline_rounded,
onTap: () => context.pushRoute(const DriftTrashRoute()),
label: 'trash'.t(context: context),
label: context.t.trash,
)
: const SizedBox.shrink(),
],
@ -193,7 +192,7 @@ class _PeopleCollectionCard extends ConsumerWidget {
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'people'.t(context: context),
context.t.people,
style: context.textTheme.titleSmall?.copyWith(
color: context.colorScheme.onSurface,
fontWeight: FontWeight.w500,
@ -245,7 +244,7 @@ class _PlacesCollectionCard extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'places'.t(),
context.t.places,
style: context.textTheme.titleSmall?.copyWith(
color: context.colorScheme.onSurface,
fontWeight: FontWeight.w500,
@ -303,9 +302,7 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
}).toList();
},
error: (error, _) {
return [
Center(child: Text('error_saving_image'.tr(args: [error.toString()]))),
];
return [Center(child: Text(context.t.error_saving_image(error: error.toString())))];
},
loading: () {
return [const Center(child: CircularProgressIndicator())];
@ -317,7 +314,7 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'on_this_device'.t(context: context),
context.t.on_this_device,
style: context.textTheme.titleSmall?.copyWith(
color: context.colorScheme.onSurface,
fontWeight: FontWeight.w500,
@ -384,7 +381,7 @@ class _QuickAccessButtonList extends ConsumerWidget {
),
leading: const Icon(Icons.folder_outlined, size: 26),
title: Text(
'folders'.t(context: context),
context.t.folders,
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(FolderRoute()),
@ -392,7 +389,7 @@ class _QuickAccessButtonList extends ConsumerWidget {
ListTile(
leading: const Icon(Icons.lock_outline_rounded, size: 26),
title: Text(
'locked_folder'.t(context: context),
context.t.locked_folder,
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(const DriftLockedFolderRoute()),
@ -400,7 +397,7 @@ class _QuickAccessButtonList extends ConsumerWidget {
ListTile(
leading: const Icon(Icons.group_outlined, size: 26),
title: Text(
'partners'.t(context: context),
context.t.partners,
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(const PartnerRoute()),
@ -438,10 +435,10 @@ class _PartnerList extends StatelessWidget {
),
contentPadding: const EdgeInsets.only(left: 12.0, right: 18.0),
leading: PartnerUserAvatar(userId: partner.id, name: partner.name),
title: const Text(
"partner_list_user_photos",
style: TextStyle(fontWeight: FontWeight.w500),
).t(context: context, args: {'user': partner.name}),
title: Text(
context.t.partner_list_user_photos(user: partner.name),
style: const TextStyle(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(DriftPartnerDetailRoute(partner: partner)),
);
},

View file

@ -1,10 +1,9 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
import 'package:immich_mobile/presentation/widgets/images/local_album_thumbnail.widget.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
@ -49,7 +48,7 @@ class _AlbumList extends ConsumerWidget {
if (albums.isEmpty) {
return SliverToBoxAdapter(
child: Center(
child: Padding(padding: const EdgeInsets.all(20.0), child: Text('no_albums_yet'.tr())),
child: Padding(padding: const EdgeInsets.all(20.0), child: Text(context.t.no_albums_yet)),
),
);
}
@ -67,7 +66,7 @@ class _AlbumList extends ConsumerWidget {
leading: SizedBox(width: 80, height: 80, child: LocalAlbumThumbnail(albumId: album.id)),
title: Text(album.name, style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600)),
subtitle: Text(
'items_count'.t(context: context, args: {'count': album.assetCount}),
context.t.items_count(count: album.assetCount),
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
),
onTap: () => context.pushRoute(LocalTimelineRoute(album: album)),

View file

@ -3,7 +3,7 @@ import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/locked_folder_bottom_sheet.widget.dart';
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
import 'package:immich_mobile/providers/auth.provider.dart';
@ -70,7 +70,7 @@ class _DriftLockedFolderPageState extends ConsumerState<DriftLockedFolderPage> w
: PopScope(
onPopInvokedWithResult: (didPop, _) => didPop ? ref.read(authProvider.notifier).lockPinCode() : null,
child: Timeline(
appBar: MesmerizingSliverAppBar(title: 'locked_folder'.t(context: context)),
appBar: MesmerizingSliverAppBar(title: context.t.locked_folder),
bottomSheet: const LockedFolderBottomSheet(),
),
),

View file

@ -1,11 +1,11 @@
import 'dart:async';
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
import 'package:immich_mobile/providers/infrastructure/people.provider.dart';
import 'package:immich_mobile/routing/router.dart';
@ -49,10 +49,10 @@ class _DriftPeopleCollectionPageState extends ConsumerState<DriftPeopleCollectio
onTapOutside: (_) => _formFocus.unfocus(),
onChanged: (value) => setState(() => _search = value),
filled: true,
hintText: 'filter_people'.tr(),
hintText: context.t.filter_people,
autofocus: true,
)
: Text('people'.tr()),
: Text(context.t.people),
actions: [
IconButton(
icon: Icon(_search != null ? Icons.close : Icons.search),
@ -107,7 +107,7 @@ class _DriftPeopleCollectionPageState extends ConsumerState<DriftPeopleCollectio
onTap: () => showNameEditModal(context, person),
child: person.name.isEmpty
? Text(
'add_a_name'.tr(),
context.t.add_a_name,
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
color: context.colorScheme.primary,

View file

@ -7,7 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/album/pending_uploads_banner.widget.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/remote_album_bottom_sheet.widget.dart';
import 'package:immich_mobile/presentation/widgets/remote_album/drift_album_option.widget.dart';
@ -62,7 +62,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
if (added > 0) {
ImmichToast.show(
context: context,
msg: "assets_added_to_album_count".t(context: context, args: {'count': added.toString()}),
msg: context.t.assets_added_to_album_count(count: added),
toastType: ToastType.success,
);
}
@ -88,7 +88,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
ImmichToast.show(
context: context,
msg: "users_added_to_album_count".t(context: context, args: {'count': newUsers.length}),
msg: context.t.users_added_to_album_count(count: newUsers.length),
toastType: ToastType.success,
);
} catch (e) {
@ -111,24 +111,21 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('delete_album'.t(context: context)),
title: Text(context.t.delete_album),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('album_delete_confirmation'.t(context: context, args: {'album': _album.name})),
Text(context.t.album_delete_confirmation(album: _album.name)),
const SizedBox(height: 8),
Text('album_delete_confirmation_description'.t(context: context)),
Text(context.t.album_delete_confirmation_description),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: Text('cancel'.t(context: context)),
),
TextButton(onPressed: () => Navigator.of(context).pop(false), child: Text(context.t.cancel)),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
style: TextButton.styleFrom(foregroundColor: Theme.of(context).colorScheme.error),
child: Text('delete_album'.t(context: context)),
child: Text(context.t.delete_album),
),
],
);
@ -146,11 +143,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
return;
}
ImmichToast.show(
context: context,
msg: 'album_deleted'.t(context: context),
toastType: ToastType.success,
);
ImmichToast.show(context: context, msg: context.t.album_deleted, toastType: ToastType.success);
unawaited(context.pushRoute(const DriftAlbumsRoute()));
} catch (e) {
@ -160,7 +153,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
ImmichToast.show(
context: context,
msg: 'album_viewer_appbar_share_err_delete'.t(context: context),
msg: context.t.album_viewer_appbar_share_err_delete,
toastType: ToastType.error,
);
}
@ -288,11 +281,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
return;
}
ImmichToast.show(
context: context,
msg: 'album_update_error'.t(context: context),
toastType: ToastType.error,
);
ImmichToast.show(context: context, msg: context.t.errors.unable_to_update_album_info, toastType: ToastType.error);
}
}
@ -315,14 +304,14 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
children: [
Icon(Icons.edit_outlined, color: context.colorScheme.primary, size: 24),
const SizedBox(width: 12),
Text('edit_album'.t(context: context), style: context.textTheme.titleMedium),
Text(context.t.edit_album, style: context.textTheme.titleMedium),
],
),
const SizedBox(height: 24),
// Album Name
Text(
'album_name'.t(context: context).toUpperCase(),
context.t.album_name.toUpperCase(),
style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 4),
@ -337,7 +326,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
),
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'album_name_required'.t(context: context);
return context.t.name_required;
}
return null;
@ -347,7 +336,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
// Description
Text(
'description'.t(context: context).toUpperCase(),
context.t.description.toUpperCase(),
style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 4),
@ -367,15 +356,9 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () => Navigator.of(context).pop(null),
child: Text('cancel'.t(context: context)),
),
TextButton(onPressed: () => Navigator.of(context).pop(null), child: Text(context.t.cancel)),
const SizedBox(width: 12),
FilledButton(
onPressed: _handleSave,
child: Text('save'.t(context: context)),
),
FilledButton(onPressed: _handleSave, child: Text(context.t.save)),
],
),
],

View file

@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/trash_bottom_sheet.widget.dart';
@ -35,7 +34,7 @@ class DriftTrashPage extends StatelessWidget {
],
child: Timeline(
appBar: SliverAppBar(
title: Text('trash'.t(context: context)),
title: Text(context.t.trash),
floating: true,
snap: true,
pinned: true,

View file

@ -2,14 +2,13 @@ import 'dart:async';
import 'dart:math';
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/models/albums/album_search.model.dart';
import 'package:immich_mobile/presentation/widgets/album/album_tile.dart';
import 'package:immich_mobile/presentation/widgets/album/new_album_name_modal.widget.dart';
@ -326,7 +325,7 @@ class _SortButtonState extends ConsumerState<_SortButton> {
),
),
child: Text(
sortMode.label.t(context: context),
sortMode.label(context.t),
style: context.textTheme.labelLarge?.copyWith(
color: albumSortOption == sortMode
? context.colorScheme.onPrimary
@ -354,7 +353,7 @@ class _SortButtonState extends ConsumerState<_SortButton> {
: Icon(Icons.keyboard_arrow_up_rounded, color: context.colorScheme.onSurface),
),
Text(
albumSortOption.label.t(context: context),
albumSortOption.label(context.t),
style: context.textTheme.labelLarge?.copyWith(color: context.colorScheme.onSurface.withAlpha(225)),
),
isSorting
@ -413,7 +412,7 @@ class _SearchBar extends StatelessWidget {
child: SearchField(
autofocus: false,
contentPadding: const EdgeInsets.all(16),
hintText: 'search_albums'.tr(),
hintText: context.t.search_albums,
prefixIcon: const Icon(Icons.search_rounded),
suffixIcon: searchController.text.isNotEmpty
? IconButton(icon: const Icon(Icons.clear_rounded), onPressed: onClearSearch)
@ -452,7 +451,7 @@ class _QuickFilterButtonRow extends StatelessWidget {
runSpacing: 4,
children: [
_QuickFilterButton(
label: 'all'.tr(),
label: context.t.all,
isSelected: filterMode == QuickFilterMode.all,
onTap: () {
onChangeFilter(QuickFilterMode.all);
@ -460,7 +459,7 @@ class _QuickFilterButtonRow extends StatelessWidget {
},
),
_QuickFilterButton(
label: 'shared_with_me'.tr(),
label: context.t.shared_with_me,
isSelected: filterMode == QuickFilterMode.sharedWithMe,
onTap: () {
onChangeFilter(QuickFilterMode.sharedWithMe);
@ -468,7 +467,7 @@ class _QuickFilterButtonRow extends StatelessWidget {
},
),
_QuickFilterButton(
label: 'my_albums'.tr(),
label: context.t.my_albums,
isSelected: filterMode == QuickFilterMode.myAlbums,
onTap: () {
onChangeFilter(QuickFilterMode.myAlbums);
@ -571,7 +570,7 @@ class _AlbumList extends ConsumerWidget {
if (albums.isEmpty) {
return SliverToBoxAdapter(
child: Center(
child: Padding(padding: const EdgeInsets.all(20.0), child: Text('album_search_not_found'.tr())),
child: Padding(padding: const EdgeInsets.all(20.0), child: Text(context.t.album_search_not_found)),
),
);
}
@ -600,9 +599,9 @@ class _AlbumList extends ConsumerWidget {
context: context,
builder: (context) => ConfirmDialog(
onOk: () => true,
title: "delete_album".t(context: context),
content: "album_delete_confirmation".t(context: context, args: {'album': album.name}),
ok: "delete".t(context: context),
title: context.t.delete_album,
content: context.t.album_delete_confirmation(album: album.name),
ok: context.t.delete,
),
);
},
@ -637,7 +636,7 @@ class _AlbumGrid extends StatelessWidget {
if (albums.isEmpty) {
return SliverToBoxAdapter(
child: Center(
child: Padding(padding: const EdgeInsets.all(20.0), child: Text('album_search_not_found'.tr())),
child: Padding(padding: const EdgeInsets.all(20.0), child: Text(context.t.album_search_not_found)),
),
);
}
@ -723,7 +722,7 @@ class _GridAlbumCard extends ConsumerWidget {
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600),
),
Text(
'${'items_count'.t(context: context, args: {'count': album.assetCount})}${album.ownerId != userId ? 'shared_by_user'.t(context: context, args: {'user': album.ownerName}) : 'owned'.t(context: context)}',
'${context.t.items_count(count: album.assetCount)}${album.ownerId != userId ? context.t.shared_by_user(user: album.ownerName) : context.t.owned}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: context.textTheme.labelMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
@ -760,7 +759,7 @@ class AddToAlbumHeader extends ConsumerWidget {
}
if (newAlbum == null) {
ImmichToast.show(context: context, toastType: ToastType.error, msg: 'errors.failed_to_create_album'.tr());
ImmichToast.show(context: context, toastType: ToastType.error, msg: context.t.errors.failed_to_create_album);
return;
}
@ -774,7 +773,7 @@ class AddToAlbumHeader extends ConsumerWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("add_to_album", style: context.textTheme.titleSmall).tr(),
Text(context.t.add_to_album, style: context.textTheme.titleSmall),
TextButton.icon(
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), // remove internal padding
@ -784,9 +783,9 @@ class AddToAlbumHeader extends ConsumerWidget {
onPressed: onCreateAlbum,
icon: Icon(Icons.add, color: context.primaryColor),
label: Text(
"common_create_new_album",
context.t.common_create_new_album,
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 14),
).tr(),
),
),
],
),
@ -822,13 +821,13 @@ class CreateAlbumButton extends ConsumerWidget {
}
if (album == null) {
ImmichToast.show(context: context, toastType: ToastType.error, msg: 'errors.failed_to_create_album'.tr());
ImmichToast.show(context: context, toastType: ToastType.error, msg: context.t.errors.failed_to_create_album);
return;
}
ImmichToast.show(
context: context,
msg: 'add_to_album_bottom_sheet_added'.tr(namedArgs: {'album': album.name}),
msg: context.t.add_to_album_bottom_sheet_added(album: album.name),
);
// Invalidate using the asset's remote ID to refresh the "Appears in" list
@ -843,7 +842,7 @@ class CreateAlbumButton extends ConsumerWidget {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("add_to_album", style: context.textTheme.titleSmall).tr(),
Text(context.t.add_to_album, style: context.textTheme.titleSmall),
TextButton.icon(
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
@ -853,9 +852,9 @@ class CreateAlbumButton extends ConsumerWidget {
onPressed: onCreateAlbum,
icon: Icon(Icons.add, color: context.primaryColor),
label: Text(
"common_create_new_album",
context.t.common_create_new_album,
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 14),
).tr(),
),
),
],
),

View file

@ -3,7 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
@ -27,7 +27,7 @@ class AlbumTile extends ConsumerWidget {
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600),
),
subtitle: Text(
'${'items_count'.t(context: context, args: {'count': album.assetCount})} • ${isOwner ? 'owned'.t(context: context) : 'shared_by_user'.t(context: context, args: {'user': album.ownerName})}',
'${context.t.items_count(count: album.assetCount)}${isOwner ? context.t.owned : context.t.shared_by_user(user: album.ownerName)}',
overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
),

View file

@ -1,7 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
@ -98,7 +98,7 @@ class _DriftActivityTextFieldState extends ConsumerState<DriftActivityTextField>
color: context.primaryColor,
disabledColor: context.colorScheme.secondaryContainer,
),
hintText: !widget.isEnabled ? 'shared_album_activities_input_disable'.tr() : 'say_something'.tr(),
hintText: !widget.isEnabled ? context.t.shared_album_activities_input_disable : context.t.say_something,
hintStyle: TextStyle(fontWeight: FontWeight.normal, fontSize: 14, color: Colors.grey[600]),
),
onEditingComplete: onEditingComplete,

View file

@ -1,6 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
class NewAlbumNameModal extends StatefulWidget {
const NewAlbumNameModal({super.key});
@ -21,31 +21,31 @@ class _NewAlbumNameModalState extends State<NewAlbumNameModal> {
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("album_name", style: TextStyle(fontWeight: FontWeight.bold)).tr(),
title: Text(context.t.album_name, style: const TextStyle(fontWeight: FontWeight.bold)),
content: SingleChildScrollView(
child: TextFormField(
controller: nameController,
textCapitalization: TextCapitalization.words,
autofocus: true,
decoration: InputDecoration(hintText: 'name'.tr(), border: const OutlineInputBorder()),
decoration: InputDecoration(hintText: context.t.name, border: const OutlineInputBorder()),
),
),
actions: [
TextButton(
onPressed: () => context.pop(null),
child: Text(
"cancel",
context.t.cancel,
style: TextStyle(color: Colors.red[300], fontWeight: FontWeight.bold),
).tr(),
),
),
TextButton(
onPressed: () {
context.pop(nameController.text.trim());
},
child: Text(
"create_album",
context.t.create_album,
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold),
).tr(),
),
),
],
);

View file

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
import 'package:immich_mobile/providers/album/pending_album_uploads.provider.dart';
import 'package:immich_mobile/providers/backup/asset_upload_progress.provider.dart';
@ -115,7 +115,7 @@ class _PendingUploadsBannerContent extends StatelessWidget {
const SizedBox(width: 12),
Expanded(
child: Text(
'${'uploading'.t(context: context)} $count$percentLabel',
'${context.t.uploading} $count$percentLabel',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500),
@ -183,10 +183,7 @@ class _PendingUploadsSheet extends ConsumerWidget {
child: Row(
children: [
Expanded(
child: Text(
'${'uploading'.t(context: context)} (${pending.length})',
style: context.textTheme.titleMedium,
),
child: Text('${context.t.uploading} (${pending.length})', style: context.textTheme.titleMedium),
),
if (canAbort)
TextButton.icon(
@ -199,14 +196,14 @@ class _PendingUploadsSheet extends ConsumerWidget {
ref.read(pendingAlbumUploadsProvider(albumId).notifier).clear();
},
icon: const Icon(Icons.stop_circle_outlined, size: 18),
label: Text('cancel'.t(context: context)),
label: Text(context.t.cancel),
style: TextButton.styleFrom(foregroundColor: context.colorScheme.error),
)
else if (failedCount > 0)
TextButton.icon(
onPressed: () => ref.read(pendingAlbumUploadsProvider(albumId).notifier).clearFailed(),
icon: const Icon(Icons.clear_rounded, size: 18),
label: Text('clear_failed_count'.t(context: context, args: {'count': failedCount})),
label: Text(context.t.clear_failed_count(count: failedCount)),
style: TextButton.styleFrom(foregroundColor: context.colorScheme.error),
),
],

View file

@ -1,8 +1,8 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/actions/action.widget.dart';
import 'package:immich_mobile/presentation/actions/archive.action.dart';
import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
@ -52,15 +52,15 @@ class _ArchiveBottomSheetState extends ConsumerState<ArchiveBottomSheet> {
}
if (!result.success) {
ImmichToast.show(context: context, msg: 'scaffold_body_error_occurred'.tr(), toastType: ToastType.error);
ImmichToast.show(context: context, msg: context.t.scaffold_body_error_occurred, toastType: ToastType.error);
return;
}
ImmichToast.show(
context: context,
msg: result.count == 0
? 'add_to_album_bottom_sheet_already_exists'.tr(namedArgs: {'album': album.name})
: 'add_to_album_bottom_sheet_added'.tr(namedArgs: {'album': album.name}),
? context.t.add_to_album_bottom_sheet_already_exists(album: album.name)
: context.t.add_to_album_bottom_sheet_added(album: album.name),
);
}

View file

@ -1,8 +1,8 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/actions/action.widget.dart';
import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
import 'package:immich_mobile/presentation/actions/delete.action.dart';
@ -45,15 +45,15 @@ class _LocalAlbumBottomSheetState extends ConsumerState<LocalAlbumBottomSheet> {
}
if (!result.success) {
ImmichToast.show(context: context, msg: 'scaffold_body_error_occurred'.tr(), toastType: ToastType.error);
ImmichToast.show(context: context, msg: context.t.scaffold_body_error_occurred, toastType: ToastType.error);
return;
}
ImmichToast.show(
context: context,
msg: result.count == 0
? 'add_to_album_bottom_sheet_already_exists'.tr(namedArgs: {'album': album.name})
: 'add_to_album_bottom_sheet_added'.tr(namedArgs: {'album': album.name}),
? context.t.add_to_album_bottom_sheet_already_exists(album: album.name)
: context.t.add_to_album_bottom_sheet_added(album: album.name),
);
}

View file

@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/domain/models/album/album.model.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/actions/action.widget.dart';
import 'package:immich_mobile/presentation/actions/archive.action.dart';
import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
@ -58,19 +58,15 @@ class _RemoteAlbumBottomSheetState extends ConsumerState<RemoteAlbumBottomSheet>
}
if (!result.success) {
ImmichToast.show(
context: context,
msg: 'scaffold_body_error_occurred'.t(context: context),
toastType: ToastType.error,
);
ImmichToast.show(context: context, msg: context.t.scaffold_body_error_occurred, toastType: ToastType.error);
return;
}
ImmichToast.show(
context: context,
msg: result.count == 0
? 'add_to_album_bottom_sheet_already_exists'.t(context: context, args: {"album": album.name})
: 'add_to_album_bottom_sheet_added'.t(context: context, args: {"album": album.name}),
? context.t.add_to_album_bottom_sheet_already_exists(album: album.name)
: context.t.add_to_album_bottom_sheet_added(album: album.name),
);
}

View file

@ -4,7 +4,7 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/person.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/people.provider.dart';
import 'package:immich_mobile/utils/debug_print.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart';
@ -49,7 +49,7 @@ class _DriftPersonNameEditFormState extends ConsumerState<DriftPersonBirthdayEdi
ImmichToast.show(
context: context,
msg: 'scaffold_body_error_occurred'.t(context: context),
msg: context.t.scaffold_body_error_occurred,
gravity: ToastGravity.BOTTOM,
toastType: ToastType.error,
);
@ -59,10 +59,7 @@ class _DriftPersonNameEditFormState extends ConsumerState<DriftPersonBirthdayEdi
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(
"edit_birthday".t(context: context),
style: const TextStyle(fontWeight: FontWeight.bold),
),
title: Text(context.t.edit_birthday, style: const TextStyle(fontWeight: FontWeight.bold)),
content: SizedBox(
width: double.maxFinite,
height: 300,
@ -108,16 +105,16 @@ class _DriftPersonNameEditFormState extends ConsumerState<DriftPersonBirthdayEdi
TextButton(
onPressed: () => context.pop(null),
child: Text(
"cancel",
context.t.cancel,
style: TextStyle(color: Colors.red[300], fontWeight: FontWeight.bold),
).tr(),
),
),
TextButton(
onPressed: () => saveBirthday(),
child: Text(
"save",
context.t.save,
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold),
).tr(),
),
),
],
);

View file

@ -1,10 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/person.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/people.provider.dart';
import 'package:immich_mobile/utils/debug_print.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart';
@ -47,7 +46,7 @@ class _DriftPersonNameEditFormState extends ConsumerState<DriftPersonNameEditFor
ImmichToast.show(
context: context,
msg: 'scaffold_body_error_occurred'.t(context: context),
msg: context.t.scaffold_body_error_occurred,
gravity: ToastGravity.BOTTOM,
toastType: ToastType.error,
);
@ -57,29 +56,29 @@ class _DriftPersonNameEditFormState extends ConsumerState<DriftPersonNameEditFor
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text("edit_name", style: TextStyle(fontWeight: FontWeight.bold)).tr(),
title: Text(context.t.edit_name, style: const TextStyle(fontWeight: FontWeight.bold)),
content: SingleChildScrollView(
child: TextFormField(
controller: _formController,
textCapitalization: TextCapitalization.words,
autofocus: true,
decoration: InputDecoration(hintText: 'name'.tr(), border: const OutlineInputBorder()),
decoration: InputDecoration(hintText: context.t.name, border: const OutlineInputBorder()),
),
),
actions: [
TextButton(
onPressed: () => context.pop(null),
child: Text(
"cancel",
context.t.cancel,
style: TextStyle(color: Colors.red[300], fontWeight: FontWeight.bold),
).tr(),
),
),
TextButton(
onPressed: () => onEdit(widget.person.id, _formController.text),
child: Text(
"save",
context.t.save,
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold),
).tr(),
),
),
],
);

View file

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
class PersonOptionSheet extends StatelessWidget {
const PersonOptionSheet({super.key, this.onEditName, this.onEditBirthday, this.birthdayExists = false});
@ -20,12 +20,12 @@ class PersonOptionSheet extends StatelessWidget {
children: [
ListTile(
leading: const Icon(Icons.edit),
title: Text('edit_name'.t(context: context), style: textStyle),
title: Text(context.t.edit_name, style: textStyle),
onTap: onEditName,
),
ListTile(
leading: const Icon(Icons.cake),
title: Text((birthdayExists ? 'edit_birthday' : "add_birthday").t(context: context), style: textStyle),
title: Text(birthdayExists ? context.t.edit_birthday : context.t.add_birthday, style: textStyle),
onTap: onEditBirthday,
),
],

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
class DriftRemoteAlbumOption extends StatelessWidget {
@ -36,19 +36,14 @@ class DriftRemoteAlbumOption extends StatelessWidget {
if (onEditAlbum != null) {
menuChildren.add(
BaseActionButton(
label: 'edit_album'.t(context: context),
iconData: Icons.edit,
onPressed: onEditAlbum,
menuItem: true,
),
BaseActionButton(label: context.t.edit_album, iconData: Icons.edit, onPressed: onEditAlbum, menuItem: true),
);
}
if (onAddPhotos != null) {
menuChildren.add(
BaseActionButton(
label: 'add_photos'.t(context: context),
label: context.t.add_photos,
iconData: Icons.add_a_photo,
onPressed: onAddPhotos,
menuItem: true,
@ -59,7 +54,7 @@ class DriftRemoteAlbumOption extends StatelessWidget {
if (onAddUsers != null) {
menuChildren.add(
BaseActionButton(
label: 'album_viewer_page_share_add_users'.t(context: context),
label: context.t.album_viewer_page_share_add_users,
iconData: Icons.group_add,
onPressed: onAddUsers,
menuItem: true,
@ -70,7 +65,7 @@ class DriftRemoteAlbumOption extends StatelessWidget {
if (onLeaveAlbum != null) {
menuChildren.add(
BaseActionButton(
label: 'leave_album'.t(context: context),
label: context.t.leave_album,
iconData: Icons.person_remove_rounded,
onPressed: onLeaveAlbum,
menuItem: true,
@ -81,7 +76,7 @@ class DriftRemoteAlbumOption extends StatelessWidget {
if (onToggleAlbumOrder != null) {
menuChildren.add(
BaseActionButton(
label: 'change_display_order'.t(context: context),
label: context.t.change_display_order,
iconData: Icons.swap_vert_rounded,
onPressed: onToggleAlbumOrder,
menuItem: true,
@ -92,7 +87,7 @@ class DriftRemoteAlbumOption extends StatelessWidget {
if (onCreateSharedLink != null) {
menuChildren.add(
BaseActionButton(
label: 'create_shared_link'.t(context: context),
label: context.t.create_shared_link,
iconData: Icons.link,
onPressed: onCreateSharedLink,
menuItem: true,
@ -102,12 +97,7 @@ class DriftRemoteAlbumOption extends StatelessWidget {
if (onShowOptions != null) {
menuChildren.add(
BaseActionButton(
label: 'options'.t(context: context),
iconData: Icons.settings,
onPressed: onShowOptions,
menuItem: true,
),
BaseActionButton(label: context.t.options, iconData: Icons.settings, onPressed: onShowOptions, menuItem: true),
);
}
@ -115,7 +105,7 @@ class DriftRemoteAlbumOption extends StatelessWidget {
menuChildren.add(const Divider(height: 1));
menuChildren.add(
BaseActionButton(
label: 'delete_album'.t(context: context),
label: context.t.delete_album,
iconData: Icons.delete,
iconColor: context.isDarkTheme ? Colors.red[400] : Colors.red[800],
onPressed: onDeleteAlbum,

View file

@ -1,19 +1,28 @@
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/generated/translations.g.dart';
// Store index allows us to re-arrange the values without affecting the saved prefs
enum AlbumSortMode {
title(1, "library_page_sort_title", SortOrder.asc),
assetCount(4, "library_page_sort_asset_count", SortOrder.desc),
lastModified(3, "library_page_sort_last_modified", SortOrder.desc),
created(0, "library_page_sort_created", SortOrder.desc),
mostRecent(2, "sort_recent", SortOrder.desc),
mostOldest(5, "sort_oldest", SortOrder.asc);
title(1, SortOrder.asc),
assetCount(4, SortOrder.desc),
lastModified(3, SortOrder.desc),
created(0, SortOrder.desc),
mostRecent(2, SortOrder.desc),
mostOldest(5, SortOrder.asc);
final int storeIndex;
final String label;
final SortOrder defaultOrder;
const AlbumSortMode(this.storeIndex, this.label, this.defaultOrder);
const AlbumSortMode(this.storeIndex, this.defaultOrder);
String label(Translations t) => switch (this) {
AlbumSortMode.title => t.library_page_sort_title,
AlbumSortMode.assetCount => t.library_page_sort_asset_count,
AlbumSortMode.lastModified => t.library_page_sort_last_modified,
AlbumSortMode.created => t.library_page_sort_created,
AlbumSortMode.mostRecent => t.sort_recent,
AlbumSortMode.mostOldest => t.sort_oldest,
};
SortOrder effectiveOrder(bool isReverse) => isReverse ? defaultOrder.reverse() : defaultOrder;
}

View file

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
class LocalAlbumsSliverAppBar extends StatelessWidget {
const LocalAlbumsSliverAppBar({super.key});
@ -15,7 +15,7 @@ class LocalAlbumsSliverAppBar extends StatelessWidget {
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))),
automaticallyImplyLeading: true,
centerTitle: true,
title: Text("on_this_device".t(context: context)),
title: Text(context.t.on_this_device),
);
}
}

View file

@ -11,7 +11,7 @@ import 'package:immich_mobile/domain/models/person.model.dart';
import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
@ -261,7 +261,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> with S
),
)
: Text(
'add_a_name'.tr(),
context.t.add_a_name,
style: context.textTheme.titleLarge?.copyWith(
color: Colors.grey[400],
fontSize: 36,
@ -293,7 +293,7 @@ class _ExpandedBackgroundState extends ConsumerState<_ExpandedBackground> with S
)
else
Text(
'add_birthday'.tr(),
context.t.add_birthday,
style: context.textTheme.labelLarge?.copyWith(
color: Colors.grey[400],
height: 1.2,
@ -344,7 +344,7 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> {
final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets));
return Text(
'items_count'.t(context: context, args: {"count": assetCount}),
context.t.items_count(count: assetCount),
style: context.textTheme.labelLarge?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.white,

View file

@ -12,7 +12,7 @@ import 'package:immich_mobile/domain/services/timeline.service.dart';
import 'package:immich_mobile/domain/utils/event_stream.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/datetime_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
import 'package:immich_mobile/providers/infrastructure/remote_album.provider.dart';
@ -318,7 +318,7 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> {
final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets));
return Text(
'items_count'.t(context: context, args: {"count": assetCount}),
context.t.items_count(count: assetCount),
style: context.textTheme.labelLarge?.copyWith(
color: Colors.white,
shadows: [const Shadow(offset: Offset(0, 2), blurRadius: 12, color: Colors.black87)],

View file

@ -1,112 +1,112 @@
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/domain/models/person.model.dart';
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
import 'package:immich_mobile/providers/search/people.provider.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
import 'package:immich_mobile/widgets/common/search_field.dart';
class PeoplePicker extends HookConsumerWidget {
const PeoplePicker({super.key, required this.onSelect, this.filter});
final Function(Set<PersonDto>) onSelect;
final Set<PersonDto>? filter;
@override
Widget build(BuildContext context, WidgetRef ref) {
final formFocus = useFocusNode();
const imageSize = 60.0;
final searchQuery = useState('');
final people = ref.watch(getAllPeopleProvider);
final selectedPeople = useState<Set<PersonDto>>(filter ?? {});
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8),
child: SearchField(
focusNode: formFocus,
onChanged: (value) => searchQuery.value = value,
onTapOutside: (_) => formFocus.unfocus(),
filled: true,
hintText: 'filter_people'.tr(),
),
),
Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 0),
child: Divider(color: context.colorScheme.surfaceContainerHighest, thickness: 1),
),
Expanded(
child: people.widgetWhen(
onData: (people) {
final filtered = people
.where(
(person) => person.name.toLowerCase().removeDiacritics().contains(
searchQuery.value.toLowerCase().removeDiacritics(),
),
)
.toList();
return ListView.builder(
shrinkWrap: true,
itemCount: filtered.length,
padding: const EdgeInsets.all(8),
itemBuilder: (context, index) {
final person = filtered[index];
final isSelected = selectedPeople.value.contains(person);
return Padding(
key: ValueKey(person.id),
padding: const EdgeInsets.only(bottom: 2.0),
child: LargeLeadingTile(
title: Text(
person.name,
style: context.textTheme.bodyLarge?.copyWith(
fontSize: 20,
fontWeight: FontWeight.w500,
color: isSelected ? context.colorScheme.onPrimary : context.colorScheme.onSurface,
),
),
leading: SizedBox(
height: imageSize,
child: Material(
shape: const CircleBorder(side: BorderSide.none),
elevation: 3,
child: CircleAvatar(
key: ValueKey(person.id),
maxRadius: imageSize / 2,
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(person.id, updatedAt: person.updatedAt),
),
),
),
),
onTap: () {
if (selectedPeople.value.contains(person)) {
selectedPeople.value.remove(person);
} else {
selectedPeople.value.add(person);
}
selectedPeople.value = {...selectedPeople.value};
onSelect(selectedPeople.value);
},
selected: isSelected,
selectedTileColor: context.primaryColor,
tileColor: context.primaryColor.withAlpha(25),
),
);
},
);
},
),
),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/person.model.dart';
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/string_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
import 'package:immich_mobile/presentation/widgets/images/remote_image_provider.dart';
import 'package:immich_mobile/providers/search/people.provider.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
import 'package:immich_mobile/widgets/common/search_field.dart';
class PeoplePicker extends HookConsumerWidget {
const PeoplePicker({super.key, required this.onSelect, this.filter});
final Function(Set<PersonDto>) onSelect;
final Set<PersonDto>? filter;
@override
Widget build(BuildContext context, WidgetRef ref) {
final formFocus = useFocusNode();
const imageSize = 60.0;
final searchQuery = useState('');
final people = ref.watch(getAllPeopleProvider);
final selectedPeople = useState<Set<PersonDto>>(filter ?? {});
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8),
child: SearchField(
focusNode: formFocus,
onChanged: (value) => searchQuery.value = value,
onTapOutside: (_) => formFocus.unfocus(),
filled: true,
hintText: context.t.filter_people,
),
),
Padding(
padding: const EdgeInsets.only(left: 16.0, right: 16.0, bottom: 0),
child: Divider(color: context.colorScheme.surfaceContainerHighest, thickness: 1),
),
Expanded(
child: people.widgetWhen(
onData: (people) {
final filtered = people
.where(
(person) => person.name.toLowerCase().removeDiacritics().contains(
searchQuery.value.toLowerCase().removeDiacritics(),
),
)
.toList();
return ListView.builder(
shrinkWrap: true,
itemCount: filtered.length,
padding: const EdgeInsets.all(8),
itemBuilder: (context, index) {
final person = filtered[index];
final isSelected = selectedPeople.value.contains(person);
return Padding(
key: ValueKey(person.id),
padding: const EdgeInsets.only(bottom: 2.0),
child: LargeLeadingTile(
title: Text(
person.name,
style: context.textTheme.bodyLarge?.copyWith(
fontSize: 20,
fontWeight: FontWeight.w500,
color: isSelected ? context.colorScheme.onPrimary : context.colorScheme.onSurface,
),
),
leading: SizedBox(
height: imageSize,
child: Material(
shape: const CircleBorder(side: BorderSide.none),
elevation: 3,
child: CircleAvatar(
key: ValueKey(person.id),
maxRadius: imageSize / 2,
backgroundImage: RemoteImageProvider(
url: getFaceThumbnailUrl(person.id, updatedAt: person.updatedAt),
),
),
),
),
onTap: () {
if (selectedPeople.value.contains(person)) {
selectedPeople.value.remove(person);
} else {
selectedPeople.value.add(person);
}
selectedPeople.value = {...selectedPeople.value};
onSelect(selectedPeople.value);
},
selected: isSelected,
selectedTileColor: context.primaryColor,
tileColor: context.primaryColor.withAlpha(25),
),
);
},
);
},
),
),
],
);
}
}