mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
chore: migrate mobile translations accessor (1) (#30667)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
235daff561
commit
565fbe4917
30 changed files with 207 additions and 177 deletions
|
|
@ -97,6 +97,15 @@ const _kIntParamNames = [
|
||||||
'quantity',
|
'quantity',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const _kParamTypeOverrides = <String, String>{
|
||||||
|
'advanced_settings_clear_image_cache_success.size': 'String',
|
||||||
|
'backup_controller_page_storage_format.total': 'String',
|
||||||
|
'backup_controller_page_storage_format.used': 'String',
|
||||||
|
'cleanup_found_assets_with_size.size': 'String',
|
||||||
|
};
|
||||||
|
|
||||||
|
final _usedParamTypeOverrides = <String>{};
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
final sourceFile = File('../i18n/en.json');
|
final sourceFile = File('../i18n/en.json');
|
||||||
if (!await sourceFile.exists()) {
|
if (!await sourceFile.exists()) {
|
||||||
|
|
@ -143,6 +152,11 @@ class TranslationParam {
|
||||||
Future<void> _generateTranslations(Map<String, dynamic> translations, File output) async {
|
Future<void> _generateTranslations(Map<String, dynamic> translations, File output) async {
|
||||||
final root = _buildTranslationTree('', translations);
|
final root = _buildTranslationTree('', translations);
|
||||||
|
|
||||||
|
final staleOverrides = _kParamTypeOverrides.keys.toSet().difference(_usedParamTypeOverrides);
|
||||||
|
if (staleOverrides.isNotEmpty) {
|
||||||
|
throw StateError('_kParamTypeOverrides has entries matching no plain {placeholder}: ${staleOverrides.join(', ')}');
|
||||||
|
}
|
||||||
|
|
||||||
final buffer = StringBuffer('''
|
final buffer = StringBuffer('''
|
||||||
// DO NOT EDIT. This is code generated via generate_keys.dart
|
// DO NOT EDIT. This is code generated via generate_keys.dart
|
||||||
|
|
||||||
|
|
@ -194,21 +208,22 @@ class Translations extends _BaseTranslations {
|
||||||
await output.writeAsString(buffer.toString());
|
await output.writeAsString(buffer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
TranslationNode _buildTranslationTree(String key, dynamic value) {
|
TranslationNode _buildTranslationTree(String key, dynamic value, [String parentKey = '']) {
|
||||||
|
final fullKey = parentKey.isEmpty ? key : '$parentKey.$key';
|
||||||
if (value is Map<String, dynamic>) {
|
if (value is Map<String, dynamic>) {
|
||||||
final children = <String, TranslationNode>{};
|
final children = <String, TranslationNode>{};
|
||||||
for (final entry in value.entries) {
|
for (final entry in value.entries) {
|
||||||
children[entry.key] = _buildTranslationTree(entry.key, entry.value);
|
children[entry.key] = _buildTranslationTree(entry.key, entry.value, fullKey);
|
||||||
}
|
}
|
||||||
return TranslationNode(key: key, children: children);
|
return TranslationNode(key: key, children: children);
|
||||||
} else {
|
} else {
|
||||||
final stringValue = value.toString();
|
final stringValue = value.toString();
|
||||||
final params = _extractParams(stringValue);
|
final params = _extractParams(stringValue, fullKey);
|
||||||
return TranslationNode(key: key, value: stringValue, params: params);
|
return TranslationNode(key: key, value: stringValue, params: params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<TranslationParam> _extractParams(String value) {
|
List<TranslationParam> _extractParams(String value, String fullKey) {
|
||||||
final params = <String, TranslationParam>{};
|
final params = <String, TranslationParam>{};
|
||||||
|
|
||||||
final icuRegex = RegExp(r'\{(\w+),\s*(plural|select|number|date|time)([^}]*(?:\{[^}]*\}[^}]*)*)\}');
|
final icuRegex = RegExp(r'\{(\w+),\s*(plural|select|number|date|time)([^}]*(?:\{[^}]*\}[^}]*)*)\}');
|
||||||
|
|
@ -264,8 +279,11 @@ List<TranslationParam> _extractParams(String value) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String type;
|
final String type;
|
||||||
if (_kIntParamNames.contains(name.toLowerCase())) {
|
if (_kParamTypeOverrides['$fullKey.$name'] case final override?) {
|
||||||
|
type = override;
|
||||||
|
_usedParamTypeOverrides.add('$fullKey.$name');
|
||||||
|
} else if (_kIntParamNames.contains(name.toLowerCase())) {
|
||||||
type = 'int';
|
type = 'int';
|
||||||
} else {
|
} else {
|
||||||
type = 'Object';
|
type = 'Object';
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/constants/locales.dart';
|
import 'package:immich_mobile/constants/locales.dart';
|
||||||
import 'package:immich_mobile/domain/services/background_worker.service.dart';
|
import 'package:immich_mobile/domain/services/background_worker.service.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
|
||||||
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
import 'package:immich_mobile/generated/codegen_loader.g.dart';
|
||||||
import 'package:immich_mobile/generated/translations.g.dart';
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/network.repository.dart';
|
||||||
|
|
@ -273,10 +272,7 @@ class ImmichAppState extends ConsumerState<ImmichApp> with WidgetsBindingObserve
|
||||||
darkTheme: getThemeData(colorScheme: immichTheme.dark, locale: context.locale),
|
darkTheme: getThemeData(colorScheme: immichTheme.dark, locale: context.locale),
|
||||||
theme: getThemeData(colorScheme: immichTheme.light, locale: context.locale),
|
theme: getThemeData(colorScheme: immichTheme.light, locale: context.locale),
|
||||||
builder: (context, child) => ImmichTranslationProvider(
|
builder: (context, child) => ImmichTranslationProvider(
|
||||||
translations: ImmichTranslations(
|
translations: ImmichTranslations(submit: context.t.submit, password: context.t.password),
|
||||||
submit: "submit".t(context: context),
|
|
||||||
password: "password".t(context: context),
|
|
||||||
),
|
|
||||||
child: ImmichThemeProvider(colorScheme: context.colorScheme, child: child!),
|
child: ImmichThemeProvider(colorScheme: context.colorScheme, child: child!),
|
||||||
),
|
),
|
||||||
routerConfig: router.config(
|
routerConfig: router.config(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_config.model.dart';
|
import 'package:immich_mobile/models/server_info/server_config.model.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_disk_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_disk_info.model.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_features.model.dart';
|
import 'package:immich_mobile/models/server_info/server_features.model.dart';
|
||||||
|
|
@ -16,9 +16,9 @@ enum VersionStatus {
|
||||||
|
|
||||||
String get message => switch (this) {
|
String get message => switch (this) {
|
||||||
VersionStatus.upToDate => "",
|
VersionStatus.upToDate => "",
|
||||||
VersionStatus.clientOutOfDate => "app_update_available".tr(),
|
VersionStatus.clientOutOfDate => StaticTranslations.instance.app_update_available,
|
||||||
VersionStatus.serverOutOfDate => "server_update_available".tr(),
|
VersionStatus.serverOutOfDate => StaticTranslations.instance.server_update_available,
|
||||||
VersionStatus.error => "unable_to_check_version".tr(),
|
VersionStatus.error => StaticTranslations.instance.unable_to_check_version,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:immich_mobile/services/immich_logger.service.dart';
|
import 'package:immich_mobile/services/immich_logger.service.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class AppLogPage extends HookWidget {
|
class AppLogPage extends HookWidget {
|
||||||
|
|
@ -50,7 +51,7 @@ class AppLogPage extends HookWidget {
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('logs'.tr(), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0)),
|
title: Text(context.t.logs, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0)),
|
||||||
scrolledUnderElevation: 1,
|
scrolledUnderElevation: 1,
|
||||||
elevation: 2,
|
elevation: 2,
|
||||||
actions: [
|
actions: [
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:immich_mobile/domain/models/log.model.dart';
|
import 'package:immich_mobile/domain/models/log.model.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
class AppLogDetailPage extends HookWidget {
|
class AppLogDetailPage extends HookWidget {
|
||||||
|
|
@ -44,7 +44,7 @@ class AppLogDetailPage extends HookWidget {
|
||||||
context.scaffoldMessenger.showSnackBar(
|
context.scaffoldMessenger.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
"copied_to_clipboard".tr(),
|
context.t.copied_to_clipboard,
|
||||||
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
|
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -106,7 +106,7 @@ class AppLogDetailPage extends HookWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text("log_detail_title".tr())),
|
appBar: AppBar(title: Text(context.t.log_detail_title)),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:background_downloader/background_downloader.dart';
|
import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/download.provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/download.provider.dart';
|
||||||
|
|
||||||
class DownloadPanel extends ConsumerWidget {
|
class DownloadPanel extends ConsumerWidget {
|
||||||
|
|
@ -67,14 +67,14 @@ class DownloadTaskTile extends StatelessWidget {
|
||||||
final progressPercent = (progress * 100).round();
|
final progressPercent = (progress * 100).round();
|
||||||
|
|
||||||
String getStatusText() => switch (status) {
|
String getStatusText() => switch (status) {
|
||||||
TaskStatus.running => 'downloading'.tr(),
|
TaskStatus.running => context.t.downloading,
|
||||||
TaskStatus.complete => 'download_complete'.tr(),
|
TaskStatus.complete => context.t.download_complete,
|
||||||
TaskStatus.failed => 'download_failed'.tr(),
|
TaskStatus.failed => context.t.download_failed,
|
||||||
TaskStatus.canceled => 'download_canceled'.tr(),
|
TaskStatus.canceled => context.t.download_canceled,
|
||||||
TaskStatus.paused => 'download_paused'.tr(),
|
TaskStatus.paused => context.t.download_paused,
|
||||||
TaskStatus.enqueued => 'download_enqueue'.tr(),
|
TaskStatus.enqueued => context.t.download_enqueue,
|
||||||
TaskStatus.notFound => 'download_notfound'.tr(),
|
TaskStatus.notFound => context.t.download_notfound,
|
||||||
TaskStatus.waitingToRetry => 'download_waiting_to_retry'.tr(),
|
TaskStatus.waitingToRetry => context.t.download_waiting_to_retry,
|
||||||
};
|
};
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
@ -64,7 +63,7 @@ class HeaderSettingsPage extends HookConsumerWidget {
|
||||||
headers.value = headers.value.toList();
|
headers.value = headers.value.toList();
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.add_outlined),
|
icon: const Icon(Icons.add_outlined),
|
||||||
tooltip: 'header_settings_add_header_tip'.tr(),
|
tooltip: context.t.header_settings_add_header_tip,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -111,7 +110,7 @@ class HeaderKeyValueSettings extends StatelessWidget {
|
||||||
|
|
||||||
String? emptyFieldValidator(String? value) {
|
String? emptyFieldValidator(String? value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'header_settings_field_validator_msg'.tr();
|
return StaticTranslations.instance.header_settings_field_validator_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -129,7 +128,7 @@ class HeaderKeyValueSettings extends StatelessWidget {
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: keyController,
|
controller: keyController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'header_settings_header_name_input'.tr(),
|
labelText: context.t.header_settings_header_name_input,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
|
|
@ -157,7 +156,7 @@ class HeaderKeyValueSettings extends StatelessWidget {
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: valueController,
|
controller: valueController,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: 'header_settings_header_value_input'.tr(),
|
labelText: context.t.header_settings_header_value_input,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
autocorrect: false,
|
autocorrect: false,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||||
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/presentation/pages/search/paginated_search.provider.dart';
|
import 'package:immich_mobile/presentation/pages/search/paginated_search.provider.dart';
|
||||||
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||||
|
|
@ -34,24 +34,24 @@ class _TabShellPageState extends ConsumerState<TabShellPage> {
|
||||||
|
|
||||||
final navigationDestinations = [
|
final navigationDestinations = [
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
label: 'photos'.tr(),
|
label: context.t.photos,
|
||||||
icon: const Icon(Icons.photo_library_outlined),
|
icon: const Icon(Icons.photo_library_outlined),
|
||||||
selectedIcon: Icon(Icons.photo_library, color: context.primaryColor),
|
selectedIcon: Icon(Icons.photo_library, color: context.primaryColor),
|
||||||
),
|
),
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
label: 'search'.tr(),
|
label: context.t.search,
|
||||||
icon: const Icon(Icons.search_rounded),
|
icon: const Icon(Icons.search_rounded),
|
||||||
selectedIcon: Icon(Icons.search, color: context.primaryColor),
|
selectedIcon: Icon(Icons.search, color: context.primaryColor),
|
||||||
enabled: !isReadonlyModeEnabled,
|
enabled: !isReadonlyModeEnabled,
|
||||||
),
|
),
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
label: 'albums'.tr(),
|
label: context.t.albums,
|
||||||
icon: const Icon(Icons.photo_album_outlined),
|
icon: const Icon(Icons.photo_album_outlined),
|
||||||
selectedIcon: Icon(Icons.photo_album_rounded, color: context.primaryColor),
|
selectedIcon: Icon(Icons.photo_album_rounded, color: context.primaryColor),
|
||||||
enabled: !isReadonlyModeEnabled,
|
enabled: !isReadonlyModeEnabled,
|
||||||
),
|
),
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
label: 'library'.tr(),
|
label: context.t.library$,
|
||||||
icon: const Icon(Icons.space_dashboard_outlined),
|
icon: const Icon(Icons.space_dashboard_outlined),
|
||||||
selectedIcon: Icon(Icons.space_dashboard_rounded, color: context.primaryColor),
|
selectedIcon: Icon(Icons.space_dashboard_rounded, color: context.primaryColor),
|
||||||
enabled: !isReadonlyModeEnabled,
|
enabled: !isReadonlyModeEnabled,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
import 'package:immich_mobile/models/upload/share_intent_attachment.model.dart';
|
||||||
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
|
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
|
||||||
import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart';
|
import 'package:immich_mobile/providers/asset_viewer/share_intent_upload.provider.dart';
|
||||||
|
|
@ -58,7 +58,7 @@ class ShareIntentPage extends ConsumerWidget {
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Column(
|
title: Column(
|
||||||
children: [
|
children: [
|
||||||
const Text('upload_to_immich').tr(namedArgs: {'count': candidates.length.toString()}),
|
Text(context.t.upload_to_immich(count: candidates.length)),
|
||||||
Text(
|
Text(
|
||||||
currentEndpoint,
|
currentEndpoint,
|
||||||
style: context.textTheme.labelMedium?.copyWith(color: context.colorScheme.onSurface.withAlpha(200)),
|
style: context.textTheme.labelMedium?.copyWith(color: context.colorScheme.onSurface.withAlpha(200)),
|
||||||
|
|
@ -130,7 +130,7 @@ class ShareIntentPage extends ConsumerWidget {
|
||||||
height: 48,
|
height: 48,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: (isUploading || isUploaded) ? null : upload,
|
onPressed: (isUploading || isUploaded) ? null : upload,
|
||||||
child: (isUploading || isUploaded) ? UploadingText(candidates: candidates) : const Text('upload').tr(),
|
child: (isUploading || isUploaded) ? UploadingText(candidates: candidates) : Text(context.t.upload),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -149,9 +149,7 @@ class UploadingText extends StatelessWidget {
|
||||||
return element.status == UploadStatus.complete;
|
return element.status == UploadStatus.complete;
|
||||||
}).length;
|
}).length;
|
||||||
|
|
||||||
return const Text(
|
return Text(context.t.shared_intent_upload_button_progress_text(current: uploadedCount, total: candidates.length));
|
||||||
"shared_intent_upload_button_progress_text",
|
|
||||||
).tr(namedArgs: {'current': uploadedCount.toString(), 'total': candidates.length.toString()});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -168,7 +166,7 @@ class UploadStatusIcon extends StatelessWidget {
|
||||||
return Icon(
|
return Icon(
|
||||||
Icons.check_circle_outline_rounded,
|
Icons.check_circle_outline_rounded,
|
||||||
color: context.colorScheme.onSurface.withAlpha(100),
|
color: context.colorScheme.onSurface.withAlpha(100),
|
||||||
semanticLabel: 'not_selected'.tr(),
|
semanticLabel: context.t.not_selected,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,7 +174,7 @@ class UploadStatusIcon extends StatelessWidget {
|
||||||
UploadStatus.enqueued => Icon(
|
UploadStatus.enqueued => Icon(
|
||||||
Icons.check_circle_rounded,
|
Icons.check_circle_rounded,
|
||||||
color: context.primaryColor,
|
color: context.primaryColor,
|
||||||
semanticLabel: 'enqueued'.tr(),
|
semanticLabel: context.t.enqueued,
|
||||||
),
|
),
|
||||||
UploadStatus.running => Stack(
|
UploadStatus.running => Stack(
|
||||||
alignment: AlignmentDirectional.center,
|
alignment: AlignmentDirectional.center,
|
||||||
|
|
@ -191,7 +189,7 @@ class UploadStatusIcon extends StatelessWidget {
|
||||||
backgroundColor: context.colorScheme.surfaceContainerLow,
|
backgroundColor: context.colorScheme.surfaceContainerLow,
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
value: value,
|
value: value,
|
||||||
semanticsLabel: 'uploading'.tr(),
|
semanticsLabel: context.t.uploading,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -201,8 +199,12 @@ class UploadStatusIcon extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
UploadStatus.complete => Icon(Icons.check_circle_rounded, color: Colors.green, semanticLabel: 'completed'.tr()),
|
UploadStatus.complete => Icon(
|
||||||
UploadStatus.failed => Icon(Icons.error_rounded, color: Colors.red, semanticLabel: 'failed'.tr()),
|
Icons.check_circle_rounded,
|
||||||
|
color: Colors.green,
|
||||||
|
semanticLabel: context.t.completed,
|
||||||
|
),
|
||||||
|
UploadStatus.failed => Icon(Icons.error_rounded, color: Colors.red, semanticLabel: context.t.failed),
|
||||||
};
|
};
|
||||||
|
|
||||||
return statusIcon;
|
return statusIcon;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/db.provider.dart';
|
||||||
|
|
@ -56,7 +56,7 @@ class LocalMediaSummaryPage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text('local_media_summary'.tr())),
|
appBar: AppBar(title: Text(context.t.local_media_summary)),
|
||||||
body: Consumer(
|
body: Consumer(
|
||||||
builder: (ctx, ref, __) {
|
builder: (ctx, ref, __) {
|
||||||
final db = ref.watch(driftProvider);
|
final db = ref.watch(driftProvider);
|
||||||
|
|
@ -79,7 +79,7 @@ class LocalMediaSummaryPage extends StatelessWidget {
|
||||||
const Divider(),
|
const Divider(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 15),
|
padding: const EdgeInsets.only(left: 15),
|
||||||
child: Text("album_summary".tr(), style: ctx.textTheme.titleMedium),
|
child: Text(ctx.t.album_summary, style: ctx.textTheme.titleMedium),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -136,7 +136,7 @@ class RemoteMediaSummaryPage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text('remote_media_summary'.tr())),
|
appBar: AppBar(title: Text(context.t.remote_media_summary)),
|
||||||
body: Consumer(
|
body: Consumer(
|
||||||
builder: (ctx, ref, __) {
|
builder: (ctx, ref, __) {
|
||||||
final db = ref.watch(driftProvider);
|
final db = ref.watch(driftProvider);
|
||||||
|
|
@ -159,7 +159,7 @@ class RemoteMediaSummaryPage extends StatelessWidget {
|
||||||
const Divider(),
|
const Divider(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 15),
|
padding: const EdgeInsets.only(left: 15),
|
||||||
child: Text("album_summary".tr(), style: ctx.textTheme.titleMedium),
|
child: Text(ctx.t.album_summary, style: ctx.textTheme.titleMedium),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/exif.model.dart';
|
import 'package:immich_mobile/domain/models/exif.model.dart';
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||||
|
|
||||||
@RoutePage()
|
@RoutePage()
|
||||||
|
|
@ -18,7 +18,7 @@ class AssetTroubleshootPage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: Text('asset_troubleshoot'.tr())),
|
appBar: AppBar(title: Text(context.t.asset_troubleshoot)),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
|
@ -42,7 +42,7 @@ class _AssetDetailsView extends StatelessWidget {
|
||||||
_AssetPropertiesSection(asset: asset),
|
_AssetPropertiesSection(asset: asset),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
'matching_assets'.tr(),
|
context.t.matching_assets,
|
||||||
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
if (asset.checksum != null) ...[
|
if (asset.checksum != null) ...[
|
||||||
|
|
@ -52,12 +52,12 @@ class _AssetDetailsView extends StatelessWidget {
|
||||||
] else ...[
|
] else ...[
|
||||||
_PropertySectionCard(
|
_PropertySectionCard(
|
||||||
title: 'Local Assets',
|
title: 'Local Assets',
|
||||||
properties: [_PropertyItem(label: 'Status', value: 'no_checksum_local'.tr())],
|
properties: [_PropertyItem(label: 'Status', value: context.t.no_checksum_local)],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_PropertySectionCard(
|
_PropertySectionCard(
|
||||||
title: 'Remote Assets',
|
title: 'Remote Assets',
|
||||||
properties: [_PropertyItem(label: 'Status', value: 'no_checksum_remote'.tr())],
|
properties: [_PropertyItem(label: 'Status', value: context.t.no_checksum_remote)],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
@ -243,7 +243,7 @@ class _LocalAssetsSection extends ConsumerWidget {
|
||||||
if (localAssets.isEmpty) {
|
if (localAssets.isEmpty) {
|
||||||
return _PropertySectionCard(
|
return _PropertySectionCard(
|
||||||
title: 'Local Assets',
|
title: 'Local Assets',
|
||||||
properties: [_PropertyItem(label: 'Status', value: 'no_local_assets_found'.tr())],
|
properties: [_PropertyItem(label: 'Status', value: context.t.no_local_assets_found)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,7 +302,7 @@ class _RemoteAssetSection extends ConsumerWidget {
|
||||||
if (remoteAsset == null) {
|
if (remoteAsset == null) {
|
||||||
return _PropertySectionCard(
|
return _PropertySectionCard(
|
||||||
title: 'Remote Assets',
|
title: 'Remote Assets',
|
||||||
properties: [_PropertyItem(label: 'Status', value: 'no_remote_assets_found'.tr())],
|
properties: [_PropertyItem(label: 'Status', value: context.t.no_remote_assets_found)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -356,7 +356,7 @@ class _PropertyItem extends StatelessWidget {
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
value ?? 'not_available'.tr(),
|
value ?? context.t.not_available,
|
||||||
style: TextStyle(color: Theme.of(context).colorScheme.secondary),
|
style: TextStyle(color: Theme.of(context).colorScheme.secondary),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/auth/biometric_status.model.dart';
|
import 'package:immich_mobile/models/auth/biometric_status.model.dart';
|
||||||
import 'package:immich_mobile/services/local_auth.service.dart';
|
import 'package:immich_mobile/services/local_auth.service.dart';
|
||||||
import 'package:immich_mobile/services/secure_storage.service.dart';
|
import 'package:immich_mobile/services/secure_storage.service.dart';
|
||||||
|
|
@ -43,6 +43,7 @@ class LocalAuthNotifier extends StateNotifier<BiometricStatus> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> authenticate(BuildContext context, String? message) async {
|
Future<bool> authenticate(BuildContext context, String? message) async {
|
||||||
|
final t = StaticTranslations.instance;
|
||||||
String errorMessage = "";
|
String errorMessage = "";
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -51,20 +52,20 @@ class LocalAuthNotifier extends StateNotifier<BiometricStatus> {
|
||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case "NotEnrolled":
|
case "NotEnrolled":
|
||||||
_log.warning("User is not enrolled in biometrics");
|
_log.warning("User is not enrolled in biometrics");
|
||||||
errorMessage = "biometric_no_options".tr();
|
errorMessage = t.biometric_no_options;
|
||||||
case "NotAvailable":
|
case "NotAvailable":
|
||||||
_log.warning("Biometric authentication is not available");
|
_log.warning("Biometric authentication is not available");
|
||||||
errorMessage = "biometric_not_available".tr();
|
errorMessage = t.biometric_not_available;
|
||||||
case "LockedOut":
|
case "LockedOut":
|
||||||
_log.warning("User is locked out of biometric authentication");
|
_log.warning("User is locked out of biometric authentication");
|
||||||
errorMessage = "biometric_locked_out".tr();
|
errorMessage = t.biometric_locked_out;
|
||||||
default:
|
default:
|
||||||
_log.warning("Failed to authenticate with unknown reason");
|
_log.warning("Failed to authenticate with unknown reason");
|
||||||
errorMessage = 'failed_to_authenticate'.tr();
|
errorMessage = t.failed_to_authenticate;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
_log.warning("Error during authentication: $error");
|
_log.warning("Error during authentication: $error");
|
||||||
errorMessage = 'failed_to_authenticate'.tr();
|
errorMessage = t.failed_to_authenticate;
|
||||||
} finally {
|
} finally {
|
||||||
if (errorMessage.isNotEmpty) {
|
if (errorMessage.isNotEmpty) {
|
||||||
context.showSnackBar(
|
context.showSnackBar(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
|
|
||||||
part 'sync_status.provider.freezed.dart';
|
part 'sync_status.provider.freezed.dart';
|
||||||
|
|
||||||
|
|
@ -12,11 +12,12 @@ enum SyncStatus {
|
||||||
error;
|
error;
|
||||||
|
|
||||||
String localized() {
|
String localized() {
|
||||||
|
final t = StaticTranslations.instance;
|
||||||
return switch (this) {
|
return switch (this) {
|
||||||
SyncStatus.idle => "idle".tr(),
|
SyncStatus.idle => t.idle,
|
||||||
SyncStatus.syncing => "running".tr(),
|
SyncStatus.syncing => t.running,
|
||||||
SyncStatus.success => "success".tr(),
|
SyncStatus.success => t.success,
|
||||||
SyncStatus.error => "error".tr(),
|
SyncStatus.error => t.error,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/auth/biometric_status.model.dart';
|
import 'package:immich_mobile/models/auth/biometric_status.model.dart';
|
||||||
import 'package:local_auth/local_auth.dart';
|
import 'package:local_auth/local_auth.dart';
|
||||||
|
|
||||||
|
|
@ -19,6 +19,6 @@ class BiometricRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> authenticate(String? message) async {
|
Future<bool> authenticate(String? message) async {
|
||||||
return _localAuth.authenticate(localizedReason: message ?? 'please_auth_to_access'.tr());
|
return _localAuth.authenticate(localizedReason: message ?? StaticTranslations.instance.please_auth_to_access);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import 'package:immich_mobile/domain/models/store.model.dart';
|
||||||
import 'package:immich_mobile/entities/store.entity.dart';
|
import 'package:immich_mobile/entities/store.entity.dart';
|
||||||
import 'package:immich_mobile/extensions/network_capability_extensions.dart';
|
import 'package:immich_mobile/extensions/network_capability_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
import 'package:immich_mobile/extensions/platform_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/backup.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/settings.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/settings.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/storage.repository.dart';
|
||||||
|
|
@ -241,16 +241,17 @@ class ForegroundUploadService {
|
||||||
Completer<void>? cancelToken, {
|
Completer<void>? cancelToken, {
|
||||||
required UploadCallbacks callbacks,
|
required UploadCallbacks callbacks,
|
||||||
}) async {
|
}) async {
|
||||||
|
final t = StaticTranslations.instance;
|
||||||
|
final assetNotFoundOnDevice = CurrentPlatform.isAndroid
|
||||||
|
? t.asset_not_found_on_device_android
|
||||||
|
: t.asset_not_found_on_device_ios;
|
||||||
File? file;
|
File? file;
|
||||||
File? livePhotoFile;
|
File? livePhotoFile;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final entity = await _storageRepository.getAssetEntityForAsset(asset);
|
final entity = await _storageRepository.getAssetEntityForAsset(asset);
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
callbacks.onError?.call(
|
callbacks.onError?.call(asset.localId!, assetNotFoundOnDevice);
|
||||||
asset.localId!,
|
|
||||||
CurrentPlatform.isAndroid ? "asset_not_found_on_device_android".t() : "asset_not_found_on_device_ios".t(),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,10 +285,7 @@ class ForegroundUploadService {
|
||||||
file = await _storageRepository.getFileForAsset(asset.id);
|
file = await _storageRepository.getFileForAsset(asset.id);
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
_logger.warning("Failed to get file ${asset.id} - ${asset.name}");
|
_logger.warning("Failed to get file ${asset.id} - ${asset.name}");
|
||||||
callbacks.onError?.call(
|
callbacks.onError?.call(asset.localId!, assetNotFoundOnDevice);
|
||||||
asset.localId!,
|
|
||||||
CurrentPlatform.isAndroid ? "asset_not_found_on_device_android".t() : "asset_not_found_on_device_ios".t(),
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,17 +294,14 @@ class ForegroundUploadService {
|
||||||
livePhotoFile = await _storageRepository.getMotionFileForAsset(asset);
|
livePhotoFile = await _storageRepository.getMotionFileForAsset(asset);
|
||||||
if (livePhotoFile == null) {
|
if (livePhotoFile == null) {
|
||||||
_logger.warning("Failed to obtain motion part of the livePhoto - ${asset.name}");
|
_logger.warning("Failed to obtain motion part of the livePhoto - ${asset.name}");
|
||||||
callbacks.onError?.call(
|
callbacks.onError?.call(asset.localId!, assetNotFoundOnDevice);
|
||||||
asset.localId!,
|
|
||||||
CurrentPlatform.isAndroid ? "asset_not_found_on_device_android".t() : "asset_not_found_on_device_ios".t(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
_logger.warning("Failed to obtain file from iCloud for asset ${asset.id} - ${asset.name}");
|
_logger.warning("Failed to obtain file from iCloud for asset ${asset.id} - ${asset.name}");
|
||||||
callbacks.onError?.call(asset.localId!, "asset_not_found_on_icloud".t());
|
callbacks.onError?.call(asset.localId!, t.asset_not_found_on_icloud);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
import 'package:immich_mobile/domain/models/album/album.model.dart';
|
||||||
|
|
@ -7,6 +6,7 @@ import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/events.model.dart';
|
import 'package:immich_mobile/domain/models/events.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/presentation/actions/action.widget.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/archive.action.dart';
|
||||||
import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
|
import 'package:immich_mobile/presentation/actions/asset_debug.action.dart';
|
||||||
|
|
@ -203,13 +203,13 @@ enum ActionButtonType {
|
||||||
),
|
),
|
||||||
ActionButtonType.setProfilePicture => ActionMenuItem(action: SetProfilePictureAction(asset: context.asset)),
|
ActionButtonType.setProfilePicture => ActionMenuItem(action: SetProfilePictureAction(asset: context.asset)),
|
||||||
ActionButtonType.openInfo => BaseActionButton(
|
ActionButtonType.openInfo => BaseActionButton(
|
||||||
label: 'info'.tr(),
|
label: StaticTranslations.instance.info,
|
||||||
iconData: Icons.info_outline,
|
iconData: Icons.info_outline,
|
||||||
menuItem: true,
|
menuItem: true,
|
||||||
onPressed: () => EventStream.shared.emit(const ViewerShowDetailsEvent()),
|
onPressed: () => EventStream.shared.emit(const ViewerShowDetailsEvent()),
|
||||||
),
|
),
|
||||||
ActionButtonType.viewInTimeline => BaseActionButton(
|
ActionButtonType.viewInTimeline => BaseActionButton(
|
||||||
label: 'view_in_timeline'.tr(),
|
label: StaticTranslations.instance.view_in_timeline,
|
||||||
iconData: Icons.image_search,
|
iconData: Icons.image_search,
|
||||||
iconOnly: iconOnly,
|
iconOnly: iconOnly,
|
||||||
menuItem: menuItem,
|
menuItem: menuItem,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import 'package:background_downloader/background_downloader.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/domain/services/log.service.dart';
|
import 'package:immich_mobile/domain/services/log.service.dart';
|
||||||
import 'package:immich_mobile/domain/services/store.service.dart';
|
import 'package:immich_mobile/domain/services/store.service.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/db.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/log.repository.dart';
|
||||||
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
|
import 'package:immich_mobile/infrastructure/repositories/logger_db.repository.dart';
|
||||||
|
|
@ -15,31 +15,33 @@ import 'package:photo_manager/photo_manager.dart';
|
||||||
import 'package:sqlite3/common.dart';
|
import 'package:sqlite3/common.dart';
|
||||||
|
|
||||||
void configureFileDownloaderNotifications() {
|
void configureFileDownloaderNotifications() {
|
||||||
|
final t = StaticTranslations.instance;
|
||||||
|
|
||||||
FileDownloader().configureNotificationForGroup(
|
FileDownloader().configureNotificationForGroup(
|
||||||
kDownloadGroupImage,
|
kDownloadGroupImage,
|
||||||
running: TaskNotification('downloading_media'.t(), '${'file_name_text'.t()}: {filename}'),
|
running: TaskNotification(t.downloading_media, '${t.file_name_text}: {filename}'),
|
||||||
complete: TaskNotification('download_finished'.t(), '${'file_name_text'.t()}: {filename}'),
|
complete: TaskNotification(t.download_finished, '${t.file_name_text}: {filename}'),
|
||||||
progressBar: true,
|
progressBar: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
FileDownloader().configureNotificationForGroup(
|
FileDownloader().configureNotificationForGroup(
|
||||||
kDownloadGroupVideo,
|
kDownloadGroupVideo,
|
||||||
running: TaskNotification('downloading_media'.t(), '${'file_name_text'.t()}: {filename}'),
|
running: TaskNotification(t.downloading_media, '${t.file_name_text}: {filename}'),
|
||||||
complete: TaskNotification('download_finished'.t(), '${'file_name_text'.t()}: {filename}'),
|
complete: TaskNotification(t.download_finished, '${t.file_name_text}: {filename}'),
|
||||||
progressBar: true,
|
progressBar: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
FileDownloader().configureNotificationForGroup(
|
FileDownloader().configureNotificationForGroup(
|
||||||
kManualUploadGroup,
|
kManualUploadGroup,
|
||||||
running: TaskNotification('uploading_media'.t(), 'backup_background_service_in_progress_notification'.t()),
|
running: TaskNotification(t.uploading_media, t.backup_background_service_in_progress_notification),
|
||||||
complete: TaskNotification('upload_finished'.t(), 'backup_background_service_complete_notification'.t()),
|
complete: TaskNotification(t.upload_finished, t.backup_background_service_complete_notification),
|
||||||
groupNotificationId: kManualUploadGroup,
|
groupNotificationId: kManualUploadGroup,
|
||||||
);
|
);
|
||||||
|
|
||||||
FileDownloader().configureNotificationForGroup(
|
FileDownloader().configureNotificationForGroup(
|
||||||
kBackupGroup,
|
kBackupGroup,
|
||||||
running: TaskNotification('uploading_media'.t(), 'backup_background_service_in_progress_notification'.t()),
|
running: TaskNotification(t.uploading_media, t.backup_background_service_in_progress_notification),
|
||||||
complete: TaskNotification('upload_finished'.t(), 'backup_background_service_complete_notification'.t()),
|
complete: TaskNotification(t.upload_finished, t.backup_background_service_complete_notification),
|
||||||
groupNotificationId: kBackupGroup,
|
groupNotificationId: kBackupGroup,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/domain/models/person.model.dart';
|
import 'package:immich_mobile/domain/models/person.model.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/people/person_edit_birthday_modal.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/people/person_edit_birthday_modal.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/people/person_edit_name_modal.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/people/person_edit_name_modal.widget.dart';
|
||||||
|
|
||||||
|
|
@ -8,12 +8,13 @@ String formatAge(DateTime birthDate, DateTime referenceDate) {
|
||||||
final int ageInYears = _calculateAge(birthDate, referenceDate);
|
final int ageInYears = _calculateAge(birthDate, referenceDate);
|
||||||
final int ageInMonths = _calculateAgeInMonths(birthDate, referenceDate);
|
final int ageInMonths = _calculateAgeInMonths(birthDate, referenceDate);
|
||||||
|
|
||||||
|
final t = StaticTranslations.instance;
|
||||||
if (ageInMonths <= 11) {
|
if (ageInMonths <= 11) {
|
||||||
return "person_age_months".t(args: {'months': ageInMonths.toString()});
|
return t.person_age_months(months: ageInMonths);
|
||||||
} else if (ageInMonths > 12 && ageInMonths <= 23) {
|
} else if (ageInMonths > 12 && ageInMonths <= 23) {
|
||||||
return "person_age_year_months".t(args: {'months': (ageInMonths - 12).toString()});
|
return t.person_age_year_months(months: ageInMonths - 12);
|
||||||
} else {
|
} else {
|
||||||
return "person_age_years".t(args: {'years': ageInYears.toString()});
|
return t.person_age_years(years: ageInYears);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_disk_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_disk_info.model.dart';
|
||||||
import 'package:immich_mobile/pages/common/settings.page.dart';
|
import 'package:immich_mobile/pages/common/settings.page.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
|
|
@ -78,20 +78,24 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
title: Text(
|
title: Text(
|
||||||
text,
|
text,
|
||||||
style: theme.textTheme.labelLarge?.copyWith(color: theme.textTheme.labelLarge?.color?.withAlpha(250)),
|
style: theme.textTheme.labelLarge?.copyWith(color: theme.textTheme.labelLarge?.color?.withAlpha(250)),
|
||||||
).tr(),
|
),
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
trailing: trailing,
|
trailing: trailing,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ListTile buildSettingButton() {
|
ListTile buildSettingButton() {
|
||||||
return buildActionButton(Icons.settings_outlined, "settings", () => context.pushRoute(const SettingsRoute()));
|
return buildActionButton(
|
||||||
|
Icons.settings_outlined,
|
||||||
|
context.t.settings,
|
||||||
|
() => context.pushRoute(const SettingsRoute()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ListTile buildFreeUpSpaceButton() {
|
ListTile buildFreeUpSpaceButton() {
|
||||||
return buildActionButton(
|
return buildActionButton(
|
||||||
Icons.cleaning_services_outlined,
|
Icons.cleaning_services_outlined,
|
||||||
"free_up_space",
|
context.t.free_up_space,
|
||||||
() => context.pushRoute(SettingsSubRoute(section: SettingSection.freeUpSpace)),
|
() => context.pushRoute(SettingsSubRoute(section: SettingSection.freeUpSpace)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -99,7 +103,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
ListTile buildAppLogButton() {
|
ListTile buildAppLogButton() {
|
||||||
return buildActionButton(
|
return buildActionButton(
|
||||||
Icons.assignment_outlined,
|
Icons.assignment_outlined,
|
||||||
"profile_drawer_app_logs",
|
context.t.profile_drawer_app_logs,
|
||||||
() => context.pushRoute(const AppLogRoute()),
|
() => context.pushRoute(const AppLogRoute()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +111,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
ListTile buildSignOutButton() {
|
ListTile buildSignOutButton() {
|
||||||
return buildActionButton(
|
return buildActionButton(
|
||||||
Icons.logout_rounded,
|
Icons.logout_rounded,
|
||||||
"sign_out",
|
context.t.sign_out,
|
||||||
() async {
|
() async {
|
||||||
if (isLoggingOut.value) {
|
if (isLoggingOut.value) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -163,16 +167,16 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
spacing: 12,
|
spacing: 12,
|
||||||
children: [
|
children: [
|
||||||
Text("backup_controller_page_server_storage".tr(), style: context.textTheme.labelLarge),
|
Text(context.t.backup_controller_page_server_storage, style: context.textTheme.labelLarge),
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
minHeight: 10.0,
|
minHeight: 10.0,
|
||||||
value: percentage,
|
value: percentage,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
borderRadius: const BorderRadius.all(Radius.circular(10.0)),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'backup_controller_page_storage_format',
|
context.t.backup_controller_page_storage_format(used: usedDiskSpace, total: totalDiskSpace),
|
||||||
style: context.textTheme.bodySmall,
|
style: context.textTheme.bodySmall,
|
||||||
).tr(namedArgs: {'used': usedDiskSpace, 'total': totalDiskSpace}),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -189,7 +193,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
ContextHelper(context).pop();
|
ContextHelper(context).pop();
|
||||||
unawaited(launchUrl(Uri.parse('https://docs.immich.app'), mode: LaunchMode.externalApplication));
|
unawaited(launchUrl(Uri.parse('https://docs.immich.app'), mode: LaunchMode.externalApplication));
|
||||||
},
|
},
|
||||||
child: Text("documentation", style: context.textTheme.bodySmall).tr(),
|
child: Text(context.t.documentation, style: context.textTheme.bodySmall),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20, child: Text("•", textAlign: TextAlign.center)),
|
const SizedBox(width: 20, child: Text("•", textAlign: TextAlign.center)),
|
||||||
InkWell(
|
InkWell(
|
||||||
|
|
@ -199,7 +203,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
launchUrl(Uri.parse('https://github.com/immich-app/immich'), mode: LaunchMode.externalApplication),
|
launchUrl(Uri.parse('https://github.com/immich-app/immich'), mode: LaunchMode.externalApplication),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Text("profile_drawer_github", style: context.textTheme.bodySmall).tr(),
|
child: Text(context.t.profile_drawer_github, style: context.textTheme.bodySmall),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20, child: Text("•", textAlign: TextAlign.center)),
|
const SizedBox(width: 20, child: Text("•", textAlign: TextAlign.center)),
|
||||||
InkWell(
|
InkWell(
|
||||||
|
|
@ -219,7 +223,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
applicationVersion: packageInfo.version,
|
applicationVersion: packageInfo.version,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Text("licenses", style: context.textTheme.bodySmall).tr(),
|
child: Text(context.t.licenses, style: context.textTheme.bodySmall),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -237,10 +241,10 @@ class ImmichAppBarDialog extends HookConsumerWidget {
|
||||||
minLeadingWidth: 20,
|
minLeadingWidth: 20,
|
||||||
tileColor: theme.primaryColor.withAlpha(80),
|
tileColor: theme.primaryColor.withAlpha(80),
|
||||||
title: Text(
|
title: Text(
|
||||||
"profile_drawer_readonly_mode",
|
context.t.profile_drawer_readonly_mode,
|
||||||
style: theme.textTheme.labelLarge?.copyWith(color: theme.textTheme.labelLarge?.color?.withAlpha(250)),
|
style: theme.textTheme.labelLarge?.copyWith(color: theme.textTheme.labelLarge?.color?.withAlpha(250)),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/providers/auth.provider.dart';
|
import 'package:immich_mobile/providers/auth.provider.dart';
|
||||||
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
||||||
|
|
@ -68,7 +68,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
|
||||||
SnackBar(
|
SnackBar(
|
||||||
duration: const Duration(seconds: 2),
|
duration: const Duration(seconds: 2),
|
||||||
content: Text(
|
content: Text(
|
||||||
(isReadonlyModeEnabled ? "readonly_mode_disabled" : "readonly_mode_enabled").tr(),
|
isReadonlyModeEnabled ? context.t.readonly_mode_disabled : context.t.readonly_mode_enabled,
|
||||||
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
|
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
import 'package:immich_mobile/extensions/theme_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
||||||
import 'package:immich_mobile/providers/locale_provider.dart';
|
import 'package:immich_mobile/providers/locale_provider.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
|
|
@ -46,20 +46,20 @@ class AppBarServerInfo extends HookConsumerWidget {
|
||||||
children: [
|
children: [
|
||||||
if (showVersionWarning) ...[const ServerUpdateNotification(), divider],
|
if (showVersionWarning) ...[const ServerUpdateNotification(), divider],
|
||||||
_ServerInfoItem(
|
_ServerInfoItem(
|
||||||
label: "server_info_box_app_version".tr(),
|
label: context.t.server_info_box_app_version,
|
||||||
text: "${appInfo.value["version"]} build.${appInfo.value["buildNumber"]}",
|
text: "${appInfo.value["version"]} build.${appInfo.value["buildNumber"]}",
|
||||||
),
|
),
|
||||||
divider,
|
divider,
|
||||||
_ServerInfoItem(
|
_ServerInfoItem(
|
||||||
label: "server_version".tr(),
|
label: context.t.server_version,
|
||||||
text: serverInfoState.serverVersion.major > 0 ? "${serverInfoState.serverVersion}" : "--",
|
text: serverInfoState.serverVersion.major > 0 ? "${serverInfoState.serverVersion}" : "--",
|
||||||
),
|
),
|
||||||
divider,
|
divider,
|
||||||
_ServerInfoItem(label: "server_info_box_server_url".tr(), text: getServerUrl() ?? '--', tooltip: true),
|
_ServerInfoItem(label: context.t.server_info_box_server_url, text: getServerUrl() ?? '--', tooltip: true),
|
||||||
if (serverInfoState.latestVersion != null) ...[
|
if (serverInfoState.latestVersion != null) ...[
|
||||||
divider,
|
divider,
|
||||||
_ServerInfoItem(
|
_ServerInfoItem(
|
||||||
label: "latest_version".tr(),
|
label: context.t.latest_version,
|
||||||
text: serverInfoState.latestVersion!.major > 0 ? "${serverInfoState.latestVersion!}" : "--",
|
text: serverInfoState.latestVersion!.major > 0 ? "${serverInfoState.latestVersion!}" : "--",
|
||||||
tooltip: true,
|
tooltip: true,
|
||||||
icon: serverInfoState.versionStatus == VersionStatus.serverOutOfDate
|
icon: serverInfoState.versionStatus == VersionStatus.serverOutOfDate
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/constants.dart';
|
import 'package:immich_mobile/constants/constants.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
||||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
@ -76,8 +76,8 @@ class ServerUpdateNotification extends HookConsumerWidget {
|
||||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
),
|
),
|
||||||
child: serverInfoState.versionStatus == VersionStatus.clientOutOfDate
|
child: serverInfoState.versionStatus == VersionStatus.clientOutOfDate
|
||||||
? Text("action_common_update".tr(context: context))
|
? Text(context.t.action_common_update)
|
||||||
: Text("view".tr()),
|
: Text(context.t.view),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/duration_extensions.dart';
|
import 'package:immich_mobile/extensions/duration_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/widgets/common/dropdown_search_menu.dart';
|
import 'package:immich_mobile/widgets/common/dropdown_search_menu.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:timezone/timezone.dart' as tz;
|
import 'package:timezone/timezone.dart' as tz;
|
||||||
import 'package:timezone/timezone.dart';
|
import 'package:timezone/timezone.dart';
|
||||||
|
|
||||||
|
|
@ -116,26 +117,26 @@ class _DateTimePicker extends HookWidget {
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
child: Text(
|
child: Text(
|
||||||
"cancel",
|
context.t.cancel,
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: context.colorScheme.error,
|
color: context.colorScheme.error,
|
||||||
),
|
),
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: popWithDateTime,
|
onPressed: popWithDateTime,
|
||||||
child: Text(
|
child: Text(
|
||||||
"action_common_update",
|
context.t.action_common_update,
|
||||||
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Text("date_and_time", style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)).tr(),
|
Text(context.t.date_and_time, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
ListTile(
|
ListTile(
|
||||||
tileColor: context.colorScheme.surfaceContainerHighest,
|
tileColor: context.colorScheme.surfaceContainerHighest,
|
||||||
|
|
@ -151,8 +152,8 @@ class _DateTimePicker extends HookWidget {
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
DropdownSearchMenu(
|
DropdownSearchMenu(
|
||||||
trailingIcon: Icon(Icons.arrow_drop_down, color: context.primaryColor),
|
trailingIcon: Icon(Icons.arrow_drop_down, color: context.primaryColor),
|
||||||
hintText: "timezone".tr(),
|
hintText: context.t.timezone,
|
||||||
label: const Text('timezone').tr(),
|
label: Text(context.t.timezone),
|
||||||
textStyle: context.textTheme.bodyMedium,
|
textStyle: context.textTheme.bodyMedium,
|
||||||
onSelected: (value) => tzOffset.value = value,
|
onSelected: (value) => tzOffset.value = value,
|
||||||
initialSelection: tzOffset.value,
|
initialSelection: tzOffset.value,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
|
|
||||||
class DropdownSearchMenu<T> extends HookWidget {
|
class DropdownSearchMenu<T> extends HookWidget {
|
||||||
const DropdownSearchMenu({
|
const DropdownSearchMenu({
|
||||||
|
|
@ -81,7 +81,7 @@ class DropdownSearchMenu<T> extends HookWidget {
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
decoration: inputDecoration.copyWith(hintText: "search_timezone".tr()),
|
decoration: inputDecoration.copyWith(hintText: context.t.search_timezone),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: context.textTheme.bodyMedium,
|
style: context.textTheme.bodyMedium,
|
||||||
expands: false,
|
expands: false,
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@ import 'dart:async';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
import 'package:immich_mobile/models/server_info/server_info.model.dart';
|
||||||
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
import 'package:immich_mobile/providers/backup/drift_backup.provider.dart';
|
||||||
import 'package:immich_mobile/providers/cast.provider.dart';
|
import 'package:immich_mobile/providers/cast.provider.dart';
|
||||||
|
|
@ -120,7 +120,7 @@ class _ProfileIndicator extends ConsumerWidget {
|
||||||
SnackBar(
|
SnackBar(
|
||||||
duration: const Duration(seconds: 2),
|
duration: const Duration(seconds: 2),
|
||||||
content: Text(
|
content: Text(
|
||||||
(isReadonlyModeEnabled ? "readonly_mode_disabled" : "readonly_mode_enabled").tr(),
|
isReadonlyModeEnabled ? context.t.readonly_mode_disabled : context.t.readonly_mode_enabled,
|
||||||
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
|
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -143,7 +143,7 @@ class _ProfileIndicator extends ConsumerWidget {
|
||||||
? context.colorScheme.error
|
? context.colorScheme.error
|
||||||
: context.primaryColor,
|
: context.primaryColor,
|
||||||
size: widgetSize / 2 - 3,
|
size: widgetSize / 2 - 3,
|
||||||
semanticLabel: 'new_version_available'.tr(),
|
semanticLabel: context.t.new_version_available,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
|
@ -153,7 +153,7 @@ class _ProfileIndicator extends ConsumerWidget {
|
||||||
child: user == null
|
child: user == null
|
||||||
? const Icon(Icons.face_outlined, size: widgetSize)
|
? const Icon(Icons.face_outlined, size: widgetSize)
|
||||||
: Semantics(
|
: Semantics(
|
||||||
label: "logged_in_as".tr(namedArgs: {"user": user.name}),
|
label: context.t.logged_in_as(user: user.name),
|
||||||
child: AbsorbPointer(
|
child: AbsorbPointer(
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => UserCircleAvatar(
|
builder: (context) => UserCircleAvatar(
|
||||||
|
|
@ -201,7 +201,12 @@ class _BackupIndicator extends ConsumerWidget {
|
||||||
|
|
||||||
if (!backupEnabled) {
|
if (!backupEnabled) {
|
||||||
return _BadgeLabel(
|
return _BadgeLabel(
|
||||||
Icon(Icons.cloud_off_rounded, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr()),
|
Icon(
|
||||||
|
Icons.cloud_off_rounded,
|
||||||
|
size: 9,
|
||||||
|
color: iconColor,
|
||||||
|
semanticLabel: context.t.backup_controller_page_backup,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,7 +216,7 @@ class _BackupIndicator extends ConsumerWidget {
|
||||||
Icons.warning_rounded,
|
Icons.warning_rounded,
|
||||||
size: 12,
|
size: 12,
|
||||||
color: context.colorScheme.error,
|
color: context.colorScheme.error,
|
||||||
semanticLabel: 'backup_controller_page_backup'.tr(),
|
semanticLabel: context.t.backup_controller_page_backup,
|
||||||
),
|
),
|
||||||
backgroundColor: context.colorScheme.errorContainer,
|
backgroundColor: context.colorScheme.errorContainer,
|
||||||
);
|
);
|
||||||
|
|
@ -229,7 +234,7 @@ class _BackupIndicator extends ConsumerWidget {
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
strokeCap: StrokeCap.round,
|
strokeCap: StrokeCap.round,
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
|
valueColor: AlwaysStoppedAnimation<Color>(iconColor),
|
||||||
semanticsLabel: 'backup_controller_page_backup'.tr(),
|
semanticsLabel: context.t.backup_controller_page_backup,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -237,7 +242,7 @@ class _BackupIndicator extends ConsumerWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return _BadgeLabel(
|
return _BadgeLabel(
|
||||||
Icon(Icons.check_outlined, size: 9, color: iconColor, semanticLabel: 'backup_controller_page_backup'.tr()),
|
Icon(Icons.check_outlined, size: 9, color: iconColor, semanticLabel: context.t.backup_controller_page_backup),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/string_extensions.dart';
|
import 'package:immich_mobile/extensions/string_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
import 'package:immich_mobile/routing/router.dart';
|
||||||
import 'package:maplibre_gl/maplibre_gl.dart';
|
import 'package:maplibre_gl/maplibre_gl.dart';
|
||||||
|
|
||||||
|
|
@ -73,11 +73,11 @@ class _LocationPicker extends HookWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text("edit_location_dialog_title", style: context.textTheme.titleMedium).tr(),
|
Text(context.t.edit_location_dialog_title, style: context.textTheme.titleMedium),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
icon: const Text("location_picker_choose_on_map").tr(),
|
icon: Text(context.t.location_picker_choose_on_map),
|
||||||
label: const Icon(Icons.map_outlined, size: 16),
|
label: const Icon(Icons.map_outlined, size: 16),
|
||||||
onPressed: onMapTap,
|
onPressed: onMapTap,
|
||||||
),
|
),
|
||||||
|
|
@ -85,9 +85,9 @@ class _LocationPicker extends HookWidget {
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
_ManualPickerInput(
|
_ManualPickerInput(
|
||||||
controller: latitudeController,
|
controller: latitudeController,
|
||||||
decorationText: "latitude",
|
decorationText: context.t.latitude,
|
||||||
hintText: "location_picker_latitude_hint",
|
hintText: context.t.location_picker_latitude_hint,
|
||||||
errorText: "location_picker_latitude_error",
|
errorText: context.t.location_picker_latitude_error,
|
||||||
focusNode: latitiudeFocusNode,
|
focusNode: latitiudeFocusNode,
|
||||||
validator: _validateLat,
|
validator: _validateLat,
|
||||||
onUpdated: onLatitudeUpdated,
|
onUpdated: onLatitudeUpdated,
|
||||||
|
|
@ -95,9 +95,9 @@ class _LocationPicker extends HookWidget {
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
_ManualPickerInput(
|
_ManualPickerInput(
|
||||||
controller: longitudeController,
|
controller: longitudeController,
|
||||||
decorationText: "longitude",
|
decorationText: context.t.longitude,
|
||||||
hintText: "location_picker_longitude_hint",
|
hintText: context.t.location_picker_longitude_hint,
|
||||||
errorText: "location_picker_longitude_error",
|
errorText: context.t.location_picker_longitude_error,
|
||||||
focusNode: longitudeFocusNode,
|
focusNode: longitudeFocusNode,
|
||||||
validator: _validateLong,
|
validator: _validateLong,
|
||||||
onUpdated: onLongitudeEditingCompleted,
|
onUpdated: onLongitudeEditingCompleted,
|
||||||
|
|
@ -109,19 +109,19 @@ class _LocationPicker extends HookWidget {
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => ContextHelper(context).pop(),
|
onPressed: () => ContextHelper(context).pop(),
|
||||||
child: Text(
|
child: Text(
|
||||||
"cancel",
|
context.t.cancel,
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: context.colorScheme.error,
|
color: context.colorScheme.error,
|
||||||
),
|
),
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.maybePop(latlng),
|
onPressed: () => context.maybePop(latlng),
|
||||||
child: Text(
|
child: Text(
|
||||||
"action_common_update",
|
context.t.action_common_update,
|
||||||
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
@ -163,13 +163,13 @@ class _ManualPickerInput extends HookWidget {
|
||||||
textInputAction: TextInputAction.done,
|
textInputAction: TextInputAction.done,
|
||||||
autofocus: false,
|
autofocus: false,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: decorationText.tr(),
|
labelText: decorationText,
|
||||||
labelStyle: TextStyle(fontWeight: FontWeight.bold, color: context.primaryColor),
|
labelStyle: TextStyle(fontWeight: FontWeight.bold, color: context.primaryColor),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.auto,
|
floatingLabelBehavior: FloatingLabelBehavior.auto,
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
hintText: hintText.tr(),
|
hintText: hintText,
|
||||||
hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14),
|
hintStyle: const TextStyle(fontWeight: FontWeight.normal, fontSize: 14),
|
||||||
errorText: isValid.value ? null : errorText.tr(),
|
errorText: isValid.value ? null : errorText,
|
||||||
),
|
),
|
||||||
onEditingComplete: onEditingComplete,
|
onEditingComplete: onEditingComplete,
|
||||||
keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true),
|
keyboardType: const TextInputType.numberWithOptions(decimal: true, signed: true),
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import 'package:immich_mobile/domain/models/events.model.dart';
|
||||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_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/image_provider.dart';
|
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
|
@ -237,7 +237,7 @@ class _ItemCountTextState extends ConsumerState<_ItemCountText> {
|
||||||
final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets));
|
final assetCount = ref.watch(timelineServiceProvider.select((s) => s.totalAssets));
|
||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
'items_count'.t(context: context, args: {"count": assetCount}),
|
context.t.items_count(count: assetCount),
|
||||||
style: context.textTheme.labelLarge?.copyWith(
|
style: context.textTheme.labelLarge?.copyWith(
|
||||||
// letterSpacing: 0.2,
|
// letterSpacing: 0.2,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
|
|
||||||
// Error widget to be used in Scaffold when an AsyncError is received
|
// Error widget to be used in Scaffold when an AsyncError is received
|
||||||
class ScaffoldErrorBody extends StatelessWidget {
|
class ScaffoldErrorBody extends StatelessWidget {
|
||||||
|
|
@ -15,7 +15,11 @@ class ScaffoldErrorBody extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text("scaffold_body_error_occurred", style: context.textTheme.displayMedium, textAlign: TextAlign.center).tr(),
|
Text(
|
||||||
|
context.t.scaffold_body_error_occurred,
|
||||||
|
style: context.textTheme.displayMedium,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
if (withIcon)
|
if (withIcon)
|
||||||
Center(
|
Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/asset/base_asset.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/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/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
|
||||||
class SelectionSliverAppBar extends ConsumerStatefulWidget {
|
class SelectionSliverAppBar extends ConsumerStatefulWidget {
|
||||||
|
|
@ -43,12 +43,12 @@ class _SelectionSliverAppBarState extends ConsumerState<SelectionSliverAppBar> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text("Select {count}".t(context: context, args: {'count': filteredAssets.length.toString()})),
|
title: Text(context.t.selected_count(count: filteredAssets.length)),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => onDone(filteredAssets),
|
onPressed: () => onDone(filteredAssets),
|
||||||
child: Text(
|
child: Text(
|
||||||
'done'.t(context: context),
|
context.t.done,
|
||||||
style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.primary),
|
style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.primary),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/domain/models/tag.model.dart';
|
import 'package:immich_mobile/domain/models/tag.model.dart';
|
||||||
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
import 'package:immich_mobile/generated/translations.g.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/tag.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/tag.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/search_field.dart';
|
import 'package:immich_mobile/widgets/common/search_field.dart';
|
||||||
|
|
||||||
|
|
@ -41,19 +41,19 @@ class _TagPickerModal extends HookWidget {
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.pop(),
|
onPressed: () => context.pop(),
|
||||||
child: Text(
|
child: Text(
|
||||||
"cancel",
|
context.t.cancel,
|
||||||
style: context.textTheme.bodyMedium?.copyWith(
|
style: context.textTheme.bodyMedium?.copyWith(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: context.colorScheme.error,
|
color: context.colorScheme.error,
|
||||||
),
|
),
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => context.pop((selectedTagIds.value, newTagValues.value)),
|
onPressed: () => context.pop((selectedTagIds.value, newTagValues.value)),
|
||||||
child: Text(
|
child: Text(
|
||||||
"action_common_update",
|
context.t.action_common_update,
|
||||||
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
||||||
).tr(),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
|
|
@ -98,7 +98,7 @@ class TagPicker extends HookConsumerWidget {
|
||||||
onChanged: (value) => searchQuery.value = value,
|
onChanged: (value) => searchQuery.value = value,
|
||||||
onTapOutside: (_) => formFocus.unfocus(),
|
onTapOutside: (_) => formFocus.unfocus(),
|
||||||
filled: true,
|
filled: true,
|
||||||
hintText: 'filter_tags'.tr(),
|
hintText: context.t.filter_tags,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue