From 4a4e499afd2d72333cfb6aca0a15a4c21e397a99 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 13:51:30 +0630 Subject: [PATCH 01/16] feat: Implement loan tracking feature with a new screen, domain entities, and data persistence. --- .../lib/core/providers/data_providers.dart | 6 + .../core/providers/database_providers.dart | 6 + apps/mobile/lib/core/router/app_router.dart | 7 + apps/mobile/lib/core/router/routes.dart | 1 + .../view_models/loan_tracking_view_model.dart | 118 +++ .../views/loan_tracking_screen.dart | 865 ++++++++++++++++++ .../presentation/views/settings_screen.dart | 6 + apps/mobile/lib/l10n/arb/app_en.arb | 4 + apps/mobile/lib/l10n/arb/app_es.arb | 4 + apps/mobile/lib/l10n/arb/app_id.arb | 4 + apps/mobile/lib/l10n/arb/app_ja.arb | 4 + apps/mobile/lib/l10n/arb/app_ko.arb | 4 + apps/mobile/lib/l10n/arb/app_my.arb | 4 + apps/mobile/lib/l10n/arb/app_zh.arb | 4 + .../lib/l10n/gen/app_localizations.dart | 12 + .../lib/l10n/gen/app_localizations_en.dart | 6 + .../lib/l10n/gen/app_localizations_es.dart | 6 + .../lib/l10n/gen/app_localizations_id.dart | 6 + .../lib/l10n/gen/app_localizations_ja.dart | 6 + .../lib/l10n/gen/app_localizations_ko.dart | 6 + .../lib/l10n/gen/app_localizations_my.dart | 6 + .../lib/l10n/gen/app_localizations_zh.dart | 6 + packages/core/data/lib/data.dart | 1 + .../repositories/loan_repository_impl.dart | 218 +++++ packages/core/domain/lib/domain.dart | 2 + .../domain/lib/src/entities/loan_record.dart | 81 ++ .../lib/src/repositories/loan_repository.dart | 24 + .../database/lib/src/app_database.dart | 23 +- .../database/lib/src/daos/daos.dart | 1 + .../database/lib/src/daos/loan_dao.dart | 178 ++++ .../lib/src/tables/item_loans_table.dart | 21 + .../database/lib/src/tables/tables.dart | 1 + 32 files changed, 1639 insertions(+), 2 deletions(-) create mode 100644 apps/mobile/lib/features/loans/presentation/view_models/loan_tracking_view_model.dart create mode 100644 apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart create mode 100644 packages/core/data/lib/src/repositories/loan_repository_impl.dart create mode 100644 packages/core/domain/lib/src/entities/loan_record.dart create mode 100644 packages/core/domain/lib/src/repositories/loan_repository.dart create mode 100644 packages/integrations/database/lib/src/daos/loan_dao.dart create mode 100644 packages/integrations/database/lib/src/tables/item_loans_table.dart diff --git a/apps/mobile/lib/core/providers/data_providers.dart b/apps/mobile/lib/core/providers/data_providers.dart index 1573c1f..2e0faa8 100644 --- a/apps/mobile/lib/core/providers/data_providers.dart +++ b/apps/mobile/lib/core/providers/data_providers.dart @@ -24,3 +24,9 @@ ItemRepository itemRepository(Ref ref) { : null; return ItemRepositoryImpl(dao, syncDao: syncDao); } + +@riverpod +LoanRepository loanRepository(Ref ref) { + final dao = ref.watch(loanDaoProvider); + return LoanRepositoryImpl(dao); +} diff --git a/apps/mobile/lib/core/providers/database_providers.dart b/apps/mobile/lib/core/providers/database_providers.dart index 207730b..75c486b 100644 --- a/apps/mobile/lib/core/providers/database_providers.dart +++ b/apps/mobile/lib/core/providers/database_providers.dart @@ -21,3 +21,9 @@ ItemDao itemDao(Ref ref) { final database = ref.watch(appDatabaseProvider); return database.itemDao; } + +@riverpod +LoanDao loanDao(Ref ref) { + final database = ref.watch(appDatabaseProvider); + return database.loanDao; +} diff --git a/apps/mobile/lib/core/router/app_router.dart b/apps/mobile/lib/core/router/app_router.dart index 52f9743..ef31ce8 100644 --- a/apps/mobile/lib/core/router/app_router.dart +++ b/apps/mobile/lib/core/router/app_router.dart @@ -21,6 +21,7 @@ import '../../features/settings/presentation/views/settings_devtools_screen.dart import '../../features/settings/presentation/views/settings_notifications_screen.dart'; import '../../features/statistics/presentation/views/statistics_screen.dart'; import '../../features/items/presentation/views/tag_management_screen.dart'; +import '../../features/loans/presentation/views/loan_tracking_screen.dart'; import 'app_shell.dart'; import 'package:collection_tracker/core/observers/analytics_observer.dart'; import 'routes.dart'; @@ -163,6 +164,12 @@ GoRouter appRouter(Ref ref) { parentNavigatorKey: _rootNavigatorKey, builder: (_, _) => const SettingsNotificationsScreen(), ), + GoRoute( + path: 'loans', + name: 'settings-loans', + parentNavigatorKey: _rootNavigatorKey, + builder: (_, _) => const LoanTrackingScreen(), + ), GoRoute( path: 'devtools', name: 'settings-devtools', diff --git a/apps/mobile/lib/core/router/routes.dart b/apps/mobile/lib/core/router/routes.dart index 4e74f1b..9b809d7 100644 --- a/apps/mobile/lib/core/router/routes.dart +++ b/apps/mobile/lib/core/router/routes.dart @@ -9,6 +9,7 @@ abstract final class Routes { static const statistics = '/statistics'; static const settings = '/settings'; static const settingsTags = '/settings/tags'; + static const settingsLoans = '/settings/loans'; static const settingsNotifications = '/settings/notifications'; static const settingsDevtools = '/settings/devtools'; static const tagItems = '/tags/items'; diff --git a/apps/mobile/lib/features/loans/presentation/view_models/loan_tracking_view_model.dart b/apps/mobile/lib/features/loans/presentation/view_models/loan_tracking_view_model.dart new file mode 100644 index 0000000..088dccd --- /dev/null +++ b/apps/mobile/lib/features/loans/presentation/view_models/loan_tracking_view_model.dart @@ -0,0 +1,118 @@ +import 'package:app_analytics/app_analytics.dart'; +import 'package:collection_tracker/core/providers/providers.dart'; +import 'package:domain/domain.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'loan_tracking_view_model.g.dart'; + +class LoanCandidateItem { + const LoanCandidateItem({required this.item, required this.collectionName}); + + final Item item; + final String collectionName; + + String get displayLabel => '${item.title} • $collectionName'; +} + +@riverpod +Stream> activeLoans(Ref ref) { + final repository = ref.watch(loanRepositoryProvider); + return repository.watchActiveLoans(); +} + +@riverpod +Stream> loanHistory(Ref ref) { + final repository = ref.watch(loanRepositoryProvider); + return repository.watchLoanHistory(); +} + +@riverpod +Stream activeLoanForItem(Ref ref, String itemId) { + final repository = ref.watch(loanRepositoryProvider); + return repository.watchActiveLoanForItem(itemId); +} + +@riverpod +Future> loanCandidateItems(Ref ref) async { + final collectionRepository = ref.read(collectionRepositoryProvider); + final itemRepository = ref.read(itemRepositoryProvider); + + final collectionsResult = await collectionRepository.getCollections(); + final collections = collectionsResult.fold( + (exception) => throw exception, + (r) => r, + ); + + final candidates = []; + for (final collection in collections) { + final itemsResult = await itemRepository.getItems( + collectionId: collection.id, + ); + final items = itemsResult.fold((exception) => throw exception, (r) => r); + for (final item in items) { + candidates.add( + LoanCandidateItem(item: item, collectionName: collection.name), + ); + } + } + + candidates.sort( + (a, b) => a.item.title.toLowerCase().compareTo(b.item.title.toLowerCase()), + ); + + return candidates; +} + +@riverpod +Future createLoan( + Ref ref, { + required String itemId, + required String borrowerName, + String? borrowerContact, + String? notes, + DateTime? dueAt, +}) async { + final repository = ref.read(loanRepositoryProvider); + final result = await repository.createLoan( + itemId: itemId, + borrowerName: borrowerName, + borrowerContact: borrowerContact, + notes: notes, + dueAt: dueAt, + ); + + result.fold((exception) => throw exception, (loan) async { + await AnalyticsService.instance.track( + AnalyticsEvent.custom( + name: 'loan_created', + properties: { + 'loan_id': loan.id, + 'item_id': loan.itemId, + 'has_due_date': loan.dueAt != null, + }, + ), + ); + }); +} + +@riverpod +Future markLoanReturned(Ref ref, {required String loanId}) async { + final repository = ref.read(loanRepositoryProvider); + final result = await repository.markLoanReturned(loanId: loanId); + + result.fold((exception) => throw exception, (loan) async { + await AnalyticsService.instance.track( + AnalyticsEvent.custom( + name: 'loan_returned', + properties: {'loan_id': loan.id, 'item_id': loan.itemId}, + ), + ); + }); +} + +@riverpod +Future deleteLoan(Ref ref, {required String loanId}) async { + final repository = ref.read(loanRepositoryProvider); + final result = await repository.deleteLoan(loanId); + result.fold((exception) => throw exception, (_) => null); +} diff --git a/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart b/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart new file mode 100644 index 0000000..1d36c7c --- /dev/null +++ b/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart @@ -0,0 +1,865 @@ +import 'package:collection_tracker/features/loans/presentation/view_models/loan_tracking_view_model.dart'; +import 'package:collection_tracker/l10n/l10n.dart'; +import 'package:domain/domain.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:intl/intl.dart'; +import 'package:ui/ui.dart'; + +class LoanTrackingScreen extends ConsumerStatefulWidget { + const LoanTrackingScreen({super.key}); + + @override + ConsumerState createState() => _LoanTrackingScreenState(); +} + +class _LoanTrackingScreenState extends ConsumerState { + bool _showHistory = false; + + @override + Widget build(BuildContext context) { + final activeAsync = ref.watch(activeLoansProvider); + final historyAsync = ref.watch(loanHistoryProvider); + final loansAsync = _showHistory ? historyAsync : activeAsync; + + return Scaffold( + appBar: AppBar(title: const Text('Loan Tracking')), + floatingActionButton: FloatingActionButton.extended( + heroTag: 'loan_tracking_fab', + onPressed: () => _showCreateLoanSheet(context), + icon: const Icon(Icons.handshake_outlined), + label: const Text('New Loan'), + ), + body: ListView( + padding: const EdgeInsets.fromLTRB( + AppSpacing.lg, + AppSpacing.md, + AppSpacing.lg, + AppSpacing.xxl * 2, + ), + children: [ + AppReveal(child: _LoanSummaryCard(activeAsync: activeAsync)), + const SizedBox(height: AppSpacing.md), + AppReveal( + delay: AppMotion.stagger, + child: Wrap( + spacing: AppSpacing.sm, + children: [ + ChoiceChip( + selected: !_showHistory, + label: const Text('Active'), + onSelected: (_) => setState(() => _showHistory = false), + ), + ChoiceChip( + selected: _showHistory, + label: const Text('History'), + onSelected: (_) => setState(() => _showHistory = true), + ), + ], + ), + ), + const SizedBox(height: AppSpacing.md), + AppReveal( + delay: AppMotion.stagger * 2, + child: AppAnimatedSwitcher( + child: loansAsync.when( + data: (loans) { + if (loans.isEmpty) { + return EmptyState( + key: ValueKey( + _showHistory ? 'history-empty' : 'active-empty', + ), + icon: _showHistory + ? Icons.history_toggle_off_rounded + : Icons.inventory_2_outlined, + title: _showHistory + ? 'No returned loans yet' + : 'No active loans', + message: _showHistory + ? 'Returned items will appear here.' + : 'Create a loan to start tracking borrowed items.', + ); + } + + return Column( + key: ValueKey( + _showHistory ? 'history-list' : 'active-list', + ), + children: [ + for (var i = 0; i < loans.length; i++) ...[ + _LoanCard( + loan: loans[i], + showHistoryMeta: _showHistory, + onReturn: loans[i].isActive + ? () => _markReturned(context, loans[i]) + : null, + onDelete: () => _deleteLoan(context, loans[i]), + ), + if (i < loans.length - 1) + const SizedBox(height: AppSpacing.sm), + ], + ], + ); + }, + loading: () => const Padding( + padding: EdgeInsets.only(top: AppSpacing.xxl), + child: LoadingView(message: 'Loading loans...'), + ), + error: (error, _) => ErrorView( + message: 'Failed to load loans: $error', + onRetry: () { + ref.invalidate(activeLoansProvider); + ref.invalidate(loanHistoryProvider); + }, + ), + ), + ), + ), + ], + ), + ); + } + + Future _showCreateLoanSheet(BuildContext context) async { + await showAppSheet( + context: context, + builder: (_) => const _CreateLoanSheet(), + ); + } + + Future _markReturned(BuildContext context, LoanRecord loan) async { + final confirmed = await showAppDialog( + context: context, + title: const Text('Mark as returned?'), + content: Text('Confirm return for "${loan.itemTitle}".'), + actions: [ + AppButton( + label: context.l10n.actionCancel, + variant: AppButtonVariant.ghost, + onPressed: () => closeAppDialog(context, false), + ), + AppButton( + label: 'Mark Returned', + onPressed: () => closeAppDialog(context, true), + ), + ], + ); + + if (confirmed != true || !context.mounted) { + return; + } + + try { + await ref.read(markLoanReturnedProvider(loanId: loan.id).future); + if (!context.mounted) { + return; + } + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Loan marked as returned.'))); + } catch (error) { + if (!context.mounted) { + return; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to mark return: $error'), + backgroundColor: Colors.red, + ), + ); + } + } + + Future _deleteLoan(BuildContext context, LoanRecord loan) async { + final confirmed = await showAppDialog( + context: context, + title: const Text('Delete loan record?'), + content: Text('Delete loan record for "${loan.itemTitle}".'), + actions: [ + AppButton( + label: context.l10n.actionCancel, + variant: AppButtonVariant.ghost, + onPressed: () => closeAppDialog(context, false), + ), + AppButton( + label: context.l10n.actionDelete, + variant: AppButtonVariant.danger, + onPressed: () => closeAppDialog(context, true), + ), + ], + ); + + if (confirmed != true || !context.mounted) { + return; + } + + try { + await ref.read(deleteLoanProvider(loanId: loan.id).future); + if (!context.mounted) { + return; + } + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Loan deleted.'))); + } catch (error) { + if (!context.mounted) { + return; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to delete loan: $error'), + backgroundColor: Colors.red, + ), + ); + } + } +} + +class _LoanSummaryCard extends StatelessWidget { + const _LoanSummaryCard({required this.activeAsync}); + + final AsyncValue> activeAsync; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return AppCard( + child: activeAsync.when( + data: (activeLoans) { + final overdueCount = activeLoans + .where((loan) => loan.isOverdue) + .length; + + return Row( + children: [ + Expanded( + child: _StatPill( + icon: Icons.inventory_2_outlined, + label: 'Active Loans', + value: '${activeLoans.length}', + ), + ), + const SizedBox(width: AppSpacing.sm), + Expanded( + child: _StatPill( + icon: Icons.warning_amber_rounded, + label: 'Overdue', + value: '$overdueCount', + tint: overdueCount > 0 + ? theme.colorScheme.errorContainer + : theme.colorScheme.surfaceContainerHighest, + ), + ), + ], + ); + }, + loading: () => const SizedBox( + height: 74, + child: Center(child: LoadingView(indicatorSize: 30)), + ), + error: (_, _) => const Text('Unable to load loan summary.'), + ), + ); + } +} + +class _StatPill extends StatelessWidget { + const _StatPill({ + required this.icon, + required this.label, + required this.value, + this.tint, + }); + + final IconData icon; + final String label; + final String value; + final Color? tint; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + return Container( + padding: const EdgeInsets.all(AppSpacing.md), + decoration: BoxDecoration( + color: tint ?? colors.surfaceContainerHighest, + borderRadius: BorderRadius.circular(AppRadii.md), + ), + child: Row( + children: [ + Icon(icon, size: 18, color: colors.onSurfaceVariant), + const SizedBox(width: AppSpacing.sm), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + value, + style: Theme.of( + context, + ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w800), + ), + Text( + label, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: colors.onSurfaceVariant, + ), + ), + ], + ), + ), + ], + ), + ); + } +} + +class _LoanCard extends StatelessWidget { + const _LoanCard({ + required this.loan, + required this.showHistoryMeta, + required this.onDelete, + this.onReturn, + }); + + final LoanRecord loan; + final bool showHistoryMeta; + final VoidCallback onDelete; + final VoidCallback? onReturn; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return AppCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + loan.itemTitle, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w800, + ), + ), + ), + const SizedBox(width: AppSpacing.sm), + _LoanStatusBadge(loan: loan), + ], + ), + const SizedBox(height: AppSpacing.xs), + Text( + loan.collectionName, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: AppSpacing.md), + _LoanMetaRow( + icon: Icons.person_outline_rounded, + label: 'Borrower', + value: loan.borrowerName, + ), + if (loan.borrowerContact != null) ...[ + const SizedBox(height: AppSpacing.xs), + _LoanMetaRow( + icon: Icons.call_outlined, + label: 'Contact', + value: loan.borrowerContact!, + ), + ], + const SizedBox(height: AppSpacing.xs), + _LoanMetaRow( + icon: Icons.calendar_today_outlined, + label: 'Loaned', + value: _formatDate(context, loan.loanedAt), + ), + if (loan.dueAt != null) ...[ + const SizedBox(height: AppSpacing.xs), + _LoanMetaRow( + icon: Icons.event_available_outlined, + label: 'Due', + value: _formatDate(context, loan.dueAt!), + valueColor: loan.isOverdue + ? theme.colorScheme.error + : theme.colorScheme.onSurface, + ), + ], + if (showHistoryMeta && loan.returnedAt != null) ...[ + const SizedBox(height: AppSpacing.xs), + _LoanMetaRow( + icon: Icons.assignment_turned_in_outlined, + label: 'Returned', + value: _formatDate(context, loan.returnedAt!), + ), + ], + if (loan.notes != null && loan.notes!.trim().isNotEmpty) ...[ + const SizedBox(height: AppSpacing.sm), + Text( + loan.notes!, + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), + ), + ], + const SizedBox(height: AppSpacing.md), + Wrap( + spacing: AppSpacing.sm, + runSpacing: AppSpacing.sm, + children: [ + if (onReturn != null) + AppButton( + label: 'Mark Returned', + variant: AppButtonVariant.secondary, + onPressed: onReturn, + ), + AppButton( + label: context.l10n.actionDelete, + variant: AppButtonVariant.ghost, + onPressed: onDelete, + ), + ], + ), + ], + ), + ); + } + + String _formatDate(BuildContext context, DateTime date) { + final locale = Localizations.localeOf(context).toLanguageTag(); + return DateFormat.yMMMd(locale).format(date); + } +} + +class _LoanMetaRow extends StatelessWidget { + const _LoanMetaRow({ + required this.icon, + required this.label, + required this.value, + this.valueColor, + }); + + final IconData icon; + final String label; + final String value; + final Color? valueColor; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + + return Row( + children: [ + Icon(icon, size: 15, color: colors.onSurfaceVariant), + const SizedBox(width: AppSpacing.xs), + SizedBox( + width: 84, + child: Text( + label, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: colors.onSurfaceVariant), + ), + ), + Expanded( + child: Text( + value, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: valueColor, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ); + } +} + +class _LoanStatusBadge extends StatelessWidget { + const _LoanStatusBadge({required this.loan}); + + final LoanRecord loan; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final colorScheme = theme.colorScheme; + + late final Color background; + late final Color foreground; + late final String label; + + if (loan.isReturned) { + background = colorScheme.primary.withValues(alpha: 0.14); + foreground = colorScheme.primary; + label = 'Returned'; + } else if (loan.isOverdue) { + background = colorScheme.error.withValues(alpha: 0.14); + foreground = colorScheme.error; + label = 'Overdue'; + } else { + background = colorScheme.tertiary.withValues(alpha: 0.14); + foreground = colorScheme.tertiary; + label = 'Active'; + } + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + decoration: BoxDecoration( + color: background, + borderRadius: BorderRadius.circular(AppRadii.pill), + ), + child: Text( + label, + style: theme.textTheme.labelSmall?.copyWith( + color: foreground, + fontWeight: FontWeight.w700, + ), + ), + ); + } +} + +class _CreateLoanSheet extends ConsumerStatefulWidget { + const _CreateLoanSheet(); + + @override + ConsumerState<_CreateLoanSheet> createState() => _CreateLoanSheetState(); +} + +class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { + final TextEditingController _borrowerController = TextEditingController(); + final TextEditingController _contactController = TextEditingController(); + final TextEditingController _notesController = TextEditingController(); + + String? _selectedItemId; + DateTime? _dueDate; + bool _submitting = false; + + @override + void dispose() { + _borrowerController.dispose(); + _contactController.dispose(); + _notesController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final candidatesAsync = ref.watch(loanCandidateItemsProvider); + final activeLoans = + ref.watch(activeLoansProvider).asData?.value ?? const []; + + return AnimatedPadding( + duration: AppMotion.fast, + curve: AppMotion.emphasized, + padding: EdgeInsets.only(bottom: MediaQuery.viewInsetsOf(context).bottom), + child: SafeArea( + top: false, + child: Padding( + padding: const EdgeInsets.only(bottom: AppSpacing.sm), + child: candidatesAsync.when( + data: (allCandidates) { + final activeItemIds = activeLoans + .map((loan) => loan.itemId) + .toSet(); + final candidates = allCandidates + .where( + (candidate) => !activeItemIds.contains(candidate.item.id), + ) + .toList(growable: false); + + final selectedStillValid = + _selectedItemId != null && + candidates.any( + (candidate) => candidate.item.id == _selectedItemId, + ); + if (!selectedStillValid) { + _selectedItemId = candidates.isEmpty + ? null + : candidates.first.item.id; + } + + return SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Create Loan', + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + const SizedBox(height: AppSpacing.sm), + Text( + 'Track who borrowed an item and when it should be returned.', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: AppSpacing.md), + if (candidates.isEmpty) + EmptyState( + icon: Icons.inventory_2_outlined, + title: 'No available items', + message: + 'All items are currently loaned or there are no items yet.', + ) + else + DropdownButtonFormField( + key: ValueKey(_selectedItemId), + initialValue: _selectedItemId, + isExpanded: true, + decoration: const InputDecoration(labelText: 'Item'), + items: candidates + .map( + (candidate) => DropdownMenuItem( + value: candidate.item.id, + child: Text( + candidate.displayLabel, + overflow: TextOverflow.ellipsis, + ), + ), + ) + .toList(growable: false), + onChanged: _submitting + ? null + : (value) => + setState(() => _selectedItemId = value), + ), + const SizedBox(height: AppSpacing.md), + AppInput( + controller: _borrowerController, + labelText: 'Borrower name', + hintText: 'e.g. John Doe', + enabled: !_submitting && candidates.isNotEmpty, + ), + const SizedBox(height: AppSpacing.md), + AppInput( + controller: _contactController, + labelText: 'Contact (optional)', + hintText: 'Phone, email, or @username', + enabled: !_submitting && candidates.isNotEmpty, + ), + const SizedBox(height: AppSpacing.md), + _DueDateField( + dueDate: _dueDate, + enabled: !_submitting && candidates.isNotEmpty, + onPick: () => _pickDueDate(context), + onClear: _dueDate == null + ? null + : () => setState(() => _dueDate = null), + ), + const SizedBox(height: AppSpacing.md), + AppInput( + controller: _notesController, + labelText: 'Notes (optional)', + hintText: 'Extra details for this loan', + maxLines: 3, + enabled: !_submitting && candidates.isNotEmpty, + ), + const SizedBox(height: AppSpacing.lg), + AppButton( + label: _submitting ? 'Creating...' : 'Create Loan', + onPressed: (_submitting || candidates.isEmpty) + ? null + : () => _submit(context), + ), + const SizedBox(height: AppSpacing.sm), + AppButton( + label: context.l10n.actionCancel, + variant: AppButtonVariant.ghost, + onPressed: _submitting + ? null + : () => Navigator.of(context).pop(), + ), + ], + ), + ); + }, + loading: () => const SizedBox( + height: 180, + child: LoadingView(message: 'Loading items...'), + ), + error: (error, _) => ErrorView( + message: 'Failed to load items: $error', + onRetry: () => ref.invalidate(loanCandidateItemsProvider), + ), + ), + ), + ), + ); + } + + Future _pickDueDate(BuildContext context) async { + final now = DateTime.now(); + final picked = await showDatePicker( + context: context, + initialDate: _dueDate ?? now.add(const Duration(days: 7)), + firstDate: now, + lastDate: now.add(const Duration(days: 3650)), + ); + if (picked != null) { + setState(() { + _dueDate = DateTime(picked.year, picked.month, picked.day, 12); + }); + } + } + + Future _submit(BuildContext context) async { + final itemId = _selectedItemId; + if (itemId == null || itemId.isEmpty) { + return; + } + + final borrowerName = _borrowerController.text.trim(); + if (borrowerName.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Borrower name is required.')), + ); + return; + } + + setState(() => _submitting = true); + + try { + await ref + .read( + createLoanProvider( + itemId: itemId, + borrowerName: borrowerName, + borrowerContact: _contactController.text, + notes: _notesController.text, + dueAt: _dueDate, + ).future, + ) + .then((_) { + ref.invalidate(activeLoansProvider); + ref.invalidate(loanHistoryProvider); + ref.invalidate(loanCandidateItemsProvider); + }); + + if (!context.mounted) { + return; + } + + Navigator.of(context).pop(); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Loan created successfully.')), + ); + } catch (error) { + if (!context.mounted) { + return; + } + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to create loan: $error'), + backgroundColor: Colors.red, + ), + ); + } finally { + if (mounted) { + setState(() => _submitting = false); + } + } + } +} + +class _DueDateField extends StatelessWidget { + const _DueDateField({ + required this.dueDate, + required this.enabled, + required this.onPick, + this.onClear, + }); + + final DateTime? dueDate; + final bool enabled; + final VoidCallback onPick; + final VoidCallback? onClear; + + @override + Widget build(BuildContext context) { + final locale = Localizations.localeOf(context).toLanguageTag(); + final label = dueDate == null + ? 'No due date' + : DateFormat.yMMMd(locale).format(dueDate!); + + final controls = [ + AppButton( + label: 'Pick', + variant: AppButtonVariant.secondary, + onPressed: enabled ? onPick : null, + ), + if (dueDate != null) + AppButton( + label: 'Clear', + variant: AppButtonVariant.ghost, + onPressed: enabled ? onClear : null, + ), + ]; + + return LayoutBuilder( + builder: (context, constraints) { + final isCompact = constraints.maxWidth < 420; + final dateField = Container( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.md, + vertical: AppSpacing.md, + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(AppRadii.md), + border: Border.all( + color: Theme.of(context).colorScheme.outlineVariant, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Due date', style: Theme.of(context).textTheme.labelMedium), + const SizedBox(height: AppSpacing.xs), + Text(label, style: Theme.of(context).textTheme.bodyMedium), + ], + ), + ); + + if (isCompact) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + dateField, + const SizedBox(height: AppSpacing.sm), + Wrap( + spacing: AppSpacing.xs, + runSpacing: AppSpacing.xs, + children: controls, + ), + ], + ); + } + + return Row( + children: [ + Expanded(child: dateField), + const SizedBox(width: AppSpacing.sm), + for (final button in controls) + Padding( + padding: const EdgeInsets.only(left: AppSpacing.xs), + child: button, + ), + ], + ); + }, + ); + } +} diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart index 59bc1cf..cf121db 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart @@ -145,6 +145,12 @@ class SettingsScreen extends ConsumerWidget { subtitle: l10n.settingsManageTagsSubtitle, onTap: () => context.push(Routes.settingsTags), ), + SettingsTile( + icon: Icons.handshake_outlined, + title: l10n.settingsLoanTrackingTitle, + subtitle: l10n.settingsLoanTrackingSubtitle, + onTap: () => context.push(Routes.settingsLoans), + ), ], ), ), diff --git a/apps/mobile/lib/l10n/arb/app_en.arb b/apps/mobile/lib/l10n/arb/app_en.arb index 96b0378..3d28c05 100644 --- a/apps/mobile/lib/l10n/arb/app_en.arb +++ b/apps/mobile/lib/l10n/arb/app_en.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "Rename, merge, and delete tags", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "Loan Tracking", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "Track borrowed items and return dates", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "Version", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "Privacy Policy", diff --git a/apps/mobile/lib/l10n/arb/app_es.arb b/apps/mobile/lib/l10n/arb/app_es.arb index b08f0c6..131aac4 100644 --- a/apps/mobile/lib/l10n/arb/app_es.arb +++ b/apps/mobile/lib/l10n/arb/app_es.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "Renombrar, combinar y eliminar etiquetas", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "Seguimiento de préstamos", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "Controla artículos prestados y fechas de devolución", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "Versión", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "Política de privacidad", diff --git a/apps/mobile/lib/l10n/arb/app_id.arb b/apps/mobile/lib/l10n/arb/app_id.arb index f69c021..d6f80ec 100644 --- a/apps/mobile/lib/l10n/arb/app_id.arb +++ b/apps/mobile/lib/l10n/arb/app_id.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "Ubah nama, gabungkan, dan hapus tag", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "Pelacakan Pinjaman", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "Lacak item yang dipinjam dan tanggal pengembalian", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "Versi", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "Kebijakan Privasi", diff --git a/apps/mobile/lib/l10n/arb/app_ja.arb b/apps/mobile/lib/l10n/arb/app_ja.arb index de08977..a439846 100644 --- a/apps/mobile/lib/l10n/arb/app_ja.arb +++ b/apps/mobile/lib/l10n/arb/app_ja.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "タグの名前変更・統合・削除", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "貸出管理", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "貸し出したアイテムと返却予定日を追跡", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "バージョン", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "プライバシーポリシー", diff --git a/apps/mobile/lib/l10n/arb/app_ko.arb b/apps/mobile/lib/l10n/arb/app_ko.arb index 7543352..1432d47 100644 --- a/apps/mobile/lib/l10n/arb/app_ko.arb +++ b/apps/mobile/lib/l10n/arb/app_ko.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "태그 이름 변경, 병합, 삭제", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "대여 추적", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "대여한 항목과 반납 예정일을 추적합니다", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "버전", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "개인정보 처리방침", diff --git a/apps/mobile/lib/l10n/arb/app_my.arb b/apps/mobile/lib/l10n/arb/app_my.arb index ced5bf2..8f0b418 100644 --- a/apps/mobile/lib/l10n/arb/app_my.arb +++ b/apps/mobile/lib/l10n/arb/app_my.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "Tag အမည်ပြောင်း၊ ပေါင်းစည်း၊ ဖျက်နိုင်သည်", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "ငှားရမ်းမှု ခြေရာခံ", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "ငှားထားသော ပစ္စည်းများနှင့် ပြန်အပ်ရမည့်ရက်ကို ခြေရာခံပါ", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "ဗားရှင်း", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "ကိုယ်ရေးကိုယ်တာ မူဝါဒ", diff --git a/apps/mobile/lib/l10n/arb/app_zh.arb b/apps/mobile/lib/l10n/arb/app_zh.arb index 41eb06c..7adf6a6 100644 --- a/apps/mobile/lib/l10n/arb/app_zh.arb +++ b/apps/mobile/lib/l10n/arb/app_zh.arb @@ -68,6 +68,10 @@ "@settingsManageTagsTitle": {}, "settingsManageTagsSubtitle": "重命名、合并和删除标签", "@settingsManageTagsSubtitle": {}, + "settingsLoanTrackingTitle": "借出追踪", + "@settingsLoanTrackingTitle": {}, + "settingsLoanTrackingSubtitle": "跟踪借出物品和归还日期", + "@settingsLoanTrackingSubtitle": {}, "settingsVersionTitle": "版本", "@settingsVersionTitle": {}, "settingsPrivacyPolicyTitle": "隐私政策", diff --git a/apps/mobile/lib/l10n/gen/app_localizations.dart b/apps/mobile/lib/l10n/gen/app_localizations.dart index d4e4491..a3b1c8c 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations.dart @@ -311,6 +311,18 @@ abstract class AppLocalizations { /// **'Rename, merge, and delete tags'** String get settingsManageTagsSubtitle; + /// No description provided for @settingsLoanTrackingTitle. + /// + /// In en, this message translates to: + /// **'Loan Tracking'** + String get settingsLoanTrackingTitle; + + /// No description provided for @settingsLoanTrackingSubtitle. + /// + /// In en, this message translates to: + /// **'Track borrowed items and return dates'** + String get settingsLoanTrackingSubtitle; + /// No description provided for @settingsVersionTitle. /// /// In en, this message translates to: diff --git a/apps/mobile/lib/l10n/gen/app_localizations_en.dart b/apps/mobile/lib/l10n/gen/app_localizations_en.dart index c8b4487..86bd57d 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_en.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_en.dart @@ -113,6 +113,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settingsManageTagsSubtitle => 'Rename, merge, and delete tags'; + @override + String get settingsLoanTrackingTitle => 'Loan Tracking'; + + @override + String get settingsLoanTrackingSubtitle => 'Track borrowed items and return dates'; + @override String get settingsVersionTitle => 'Version'; diff --git a/apps/mobile/lib/l10n/gen/app_localizations_es.dart b/apps/mobile/lib/l10n/gen/app_localizations_es.dart index 7fb797f..e61f831 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_es.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_es.dart @@ -113,6 +113,12 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settingsManageTagsSubtitle => 'Renombrar, combinar y eliminar etiquetas'; + @override + String get settingsLoanTrackingTitle => 'Seguimiento de préstamos'; + + @override + String get settingsLoanTrackingSubtitle => 'Controla artículos prestados y fechas de devolución'; + @override String get settingsVersionTitle => 'Versión'; diff --git a/apps/mobile/lib/l10n/gen/app_localizations_id.dart b/apps/mobile/lib/l10n/gen/app_localizations_id.dart index fc22d03..3ec4e6f 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_id.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_id.dart @@ -113,6 +113,12 @@ class AppLocalizationsId extends AppLocalizations { @override String get settingsManageTagsSubtitle => 'Ubah nama, gabungkan, dan hapus tag'; + @override + String get settingsLoanTrackingTitle => 'Pelacakan Pinjaman'; + + @override + String get settingsLoanTrackingSubtitle => 'Lacak item yang dipinjam dan tanggal pengembalian'; + @override String get settingsVersionTitle => 'Versi'; diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart index e5d70dc..04c9632 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart @@ -113,6 +113,12 @@ class AppLocalizationsJa extends AppLocalizations { @override String get settingsManageTagsSubtitle => 'タグの名前変更・統合・削除'; + @override + String get settingsLoanTrackingTitle => '貸出管理'; + + @override + String get settingsLoanTrackingSubtitle => '貸し出したアイテムと返却予定日を追跡'; + @override String get settingsVersionTitle => 'バージョン'; diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart index e48c373..13f238f 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart @@ -113,6 +113,12 @@ class AppLocalizationsKo extends AppLocalizations { @override String get settingsManageTagsSubtitle => '태그 이름 변경, 병합, 삭제'; + @override + String get settingsLoanTrackingTitle => '대여 추적'; + + @override + String get settingsLoanTrackingSubtitle => '대여한 항목과 반납 예정일을 추적합니다'; + @override String get settingsVersionTitle => '버전'; diff --git a/apps/mobile/lib/l10n/gen/app_localizations_my.dart b/apps/mobile/lib/l10n/gen/app_localizations_my.dart index 728fdac..f2f6766 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_my.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_my.dart @@ -113,6 +113,12 @@ class AppLocalizationsMy extends AppLocalizations { @override String get settingsManageTagsSubtitle => 'Tag အမည်ပြောင်း၊ ပေါင်းစည်း၊ ဖျက်နိုင်သည်'; + @override + String get settingsLoanTrackingTitle => 'ငှားရမ်းမှု ခြေရာခံ'; + + @override + String get settingsLoanTrackingSubtitle => 'ငှားထားသော ပစ္စည်းများနှင့် ပြန်အပ်ရမည့်ရက်ကို ခြေရာခံပါ'; + @override String get settingsVersionTitle => 'ဗားရှင်း'; diff --git a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart index 76701d8..cd06a73 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart @@ -113,6 +113,12 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settingsManageTagsSubtitle => '重命名、合并和删除标签'; + @override + String get settingsLoanTrackingTitle => '借出追踪'; + + @override + String get settingsLoanTrackingSubtitle => '跟踪借出物品和归还日期'; + @override String get settingsVersionTitle => '版本'; diff --git a/packages/core/data/lib/data.dart b/packages/core/data/lib/data.dart index bc7c481..e8dce24 100644 --- a/packages/core/data/lib/data.dart +++ b/packages/core/data/lib/data.dart @@ -3,3 +3,4 @@ export 'src/models/item_model.dart'; export 'src/repositories/collection_repository_impl.dart'; export 'src/repositories/item_repository_impl.dart'; +export 'src/repositories/loan_repository_impl.dart'; diff --git a/packages/core/data/lib/src/repositories/loan_repository_impl.dart b/packages/core/data/lib/src/repositories/loan_repository_impl.dart new file mode 100644 index 0000000..d346264 --- /dev/null +++ b/packages/core/data/lib/src/repositories/loan_repository_impl.dart @@ -0,0 +1,218 @@ +import 'dart:math'; + +import 'package:database/database.dart'; +import 'package:domain/domain.dart'; +import 'package:fpdart/fpdart.dart'; + +class LoanRepositoryImpl implements LoanRepository { + LoanRepositoryImpl(this._dao); + + final LoanDao _dao; + final Random _random = Random(); + + @override + Stream> watchActiveLoans() { + return _dao.watchActiveLoans().map( + (rows) => rows.map(_mapToEntity).toList(growable: false), + ); + } + + @override + Stream> watchLoanHistory({int limit = 200}) { + return _dao + .watchLoanHistory(limit: limit) + .map((rows) => rows.map(_mapToEntity).toList(growable: false)); + } + + @override + Stream watchActiveLoanForItem(String itemId) { + return _dao + .watchActiveLoanForItem(itemId) + .map((row) => row == null ? null : _mapToEntity(row)); + } + + @override + Future> createLoan({ + required String itemId, + required String borrowerName, + String? borrowerContact, + String? notes, + DateTime? dueAt, + }) async { + final normalizedBorrower = borrowerName.trim(); + if (normalizedBorrower.isEmpty) { + return const Left( + AppException.validation(message: 'Borrower name is required.'), + ); + } + + try { + final existingActive = await _dao.getActiveLoanByItemId(itemId); + if (existingActive != null) { + return const Left( + AppException.business( + message: 'This item is already on loan.', + code: 'item_already_loaned', + ), + ); + } + + final now = DateTime.now(); + if (dueAt != null && dueAt.isBefore(now)) { + return const Left( + AppException.validation( + message: 'Due date must be in the future.', + fieldErrors: {'dueAt': 'Due date must be in the future.'}, + ), + ); + } + + final id = _generateLoanId(itemId); + await _dao.insertLoan( + ItemLoansCompanion.insert( + id: id, + itemId: itemId, + borrowerName: normalizedBorrower, + borrowerContact: Value(_normalizeNullableText(borrowerContact)), + notes: Value(_normalizeNullableText(notes)), + loanedAt: now, + dueAt: Value(dueAt), + createdAt: now, + updatedAt: now, + ), + ); + + final created = await _dao.getLoanWithItemById(id); + if (created == null) { + return const Left( + AppException.notFound( + message: 'Loan was created but could not be loaded.', + resourceType: 'Loan', + ), + ); + } + + return Right(_mapToEntity(created)); + } catch (error, stackTrace) { + return Left( + AppException.database( + message: 'Failed to create loan', + stackTrace: stackTrace, + ), + ); + } + } + + @override + Future> markLoanReturned({ + required String loanId, + DateTime? returnedAt, + }) async { + try { + final existing = await _dao.getLoanWithItemById(loanId); + if (existing == null) { + return const Left( + AppException.notFound( + message: 'Loan not found', + resourceType: 'Loan', + ), + ); + } + + if (existing.loan.returnedAt != null) { + return Right(_mapToEntity(existing)); + } + + final effectiveReturnedAt = returnedAt ?? DateTime.now(); + final rowsAffected = await _dao.markReturned( + loanId: loanId, + returnedAt: effectiveReturnedAt, + ); + if (rowsAffected < 1) { + return const Left( + AppException.notFound( + message: 'Loan not found', + resourceType: 'Loan', + ), + ); + } + + final updated = await _dao.getLoanWithItemById(loanId); + if (updated == null) { + return const Left( + AppException.notFound( + message: 'Loan not found', + resourceType: 'Loan', + ), + ); + } + + return Right(_mapToEntity(updated)); + } catch (error, stackTrace) { + return Left( + AppException.database( + message: 'Failed to update loan status', + stackTrace: stackTrace, + ), + ); + } + } + + @override + Future> deleteLoan(String loanId) async { + try { + final rowsAffected = await _dao.deleteLoan(loanId); + if (rowsAffected < 1) { + return const Left( + AppException.notFound( + message: 'Loan not found', + resourceType: 'Loan', + ), + ); + } + + return const Right(null); + } catch (error, stackTrace) { + return Left( + AppException.database( + message: 'Failed to delete loan', + stackTrace: stackTrace, + ), + ); + } + } + + LoanRecord _mapToEntity(ItemLoanWithItemData row) { + return LoanRecord( + id: row.loan.id, + itemId: row.item.id, + itemTitle: row.item.title, + collectionId: row.item.collectionId, + collectionName: row.collection.name, + itemCoverImageUrl: row.item.coverImageUrl, + itemCoverImagePath: row.item.coverImagePath, + borrowerName: row.loan.borrowerName, + borrowerContact: row.loan.borrowerContact, + notes: row.loan.notes, + loanedAt: row.loan.loanedAt, + dueAt: row.loan.dueAt, + returnedAt: row.loan.returnedAt, + createdAt: row.loan.createdAt, + updatedAt: row.loan.updatedAt, + ); + } + + String _generateLoanId(String itemId) { + final timestamp = DateTime.now().microsecondsSinceEpoch; + final randomPart = _random.nextInt(1 << 32).toRadixString(16); + return 'loan_${itemId}_$timestamp$randomPart'; + } + + String? _normalizeNullableText(String? value) { + final normalized = value?.trim(); + if (normalized == null || normalized.isEmpty) { + return null; + } + return normalized; + } +} diff --git a/packages/core/domain/lib/domain.dart b/packages/core/domain/lib/domain.dart index aa13020..14b56a9 100644 --- a/packages/core/domain/lib/domain.dart +++ b/packages/core/domain/lib/domain.dart @@ -1,10 +1,12 @@ export 'src/entities/collection.dart'; export 'src/entities/item.dart'; +export 'src/entities/loan_record.dart'; export 'src/failures/app_exception.dart'; export 'src/repositories/collection_repository.dart'; export 'src/repositories/item_repository.dart'; +export 'src/repositories/loan_repository.dart'; export 'src/usecases/base_usecase.dart'; export 'src/usecases/collection/create_collection_usecase.dart'; diff --git a/packages/core/domain/lib/src/entities/loan_record.dart b/packages/core/domain/lib/src/entities/loan_record.dart new file mode 100644 index 0000000..5b8f208 --- /dev/null +++ b/packages/core/domain/lib/src/entities/loan_record.dart @@ -0,0 +1,81 @@ +class LoanRecord { + const LoanRecord({ + required this.id, + required this.itemId, + required this.itemTitle, + required this.collectionId, + required this.collectionName, + this.itemCoverImageUrl, + this.itemCoverImagePath, + required this.borrowerName, + this.borrowerContact, + this.notes, + required this.loanedAt, + this.dueAt, + this.returnedAt, + required this.createdAt, + required this.updatedAt, + }); + + final String id; + final String itemId; + final String itemTitle; + final String collectionId; + final String collectionName; + final String? itemCoverImageUrl; + final String? itemCoverImagePath; + final String borrowerName; + final String? borrowerContact; + final String? notes; + final DateTime loanedAt; + final DateTime? dueAt; + final DateTime? returnedAt; + final DateTime createdAt; + final DateTime updatedAt; + + bool get isReturned => returnedAt != null; + bool get isActive => !isReturned; + + bool get isOverdue { + if (isReturned || dueAt == null) { + return false; + } + return dueAt!.isBefore(DateTime.now()); + } + + LoanRecord copyWith({ + String? id, + String? itemId, + String? itemTitle, + String? collectionId, + String? collectionName, + String? itemCoverImageUrl, + String? itemCoverImagePath, + String? borrowerName, + String? borrowerContact, + String? notes, + DateTime? loanedAt, + DateTime? dueAt, + DateTime? returnedAt, + DateTime? createdAt, + DateTime? updatedAt, + }) { + return LoanRecord( + id: id ?? this.id, + itemId: itemId ?? this.itemId, + itemTitle: itemTitle ?? this.itemTitle, + collectionId: collectionId ?? this.collectionId, + collectionName: collectionName ?? this.collectionName, + itemCoverImageUrl: itemCoverImageUrl ?? this.itemCoverImageUrl, + itemCoverImagePath: itemCoverImagePath ?? this.itemCoverImagePath, + borrowerName: borrowerName ?? this.borrowerName, + borrowerContact: borrowerContact ?? this.borrowerContact, + notes: notes ?? this.notes, + loanedAt: loanedAt ?? this.loanedAt, + dueAt: dueAt ?? this.dueAt, + returnedAt: returnedAt ?? this.returnedAt, + createdAt: createdAt ?? this.createdAt, + updatedAt: updatedAt ?? this.updatedAt, + ); + } +} diff --git a/packages/core/domain/lib/src/repositories/loan_repository.dart b/packages/core/domain/lib/src/repositories/loan_repository.dart new file mode 100644 index 0000000..d939819 --- /dev/null +++ b/packages/core/domain/lib/src/repositories/loan_repository.dart @@ -0,0 +1,24 @@ +import 'package:domain/src/entities/loan_record.dart'; +import 'package:domain/src/failures/app_exception.dart'; +import 'package:fpdart/fpdart.dart'; + +abstract class LoanRepository { + Stream> watchActiveLoans(); + Stream> watchLoanHistory({int limit = 200}); + Stream watchActiveLoanForItem(String itemId); + + Future> createLoan({ + required String itemId, + required String borrowerName, + String? borrowerContact, + String? notes, + DateTime? dueAt, + }); + + Future> markLoanReturned({ + required String loanId, + DateTime? returnedAt, + }); + + Future> deleteLoan(String loanId); +} diff --git a/packages/integrations/database/lib/src/app_database.dart b/packages/integrations/database/lib/src/app_database.dart index 13b615e..79e38ec 100644 --- a/packages/integrations/database/lib/src/app_database.dart +++ b/packages/integrations/database/lib/src/app_database.dart @@ -13,16 +13,17 @@ part 'app_database.g.dart'; Tags, ItemTags, ItemPriceHistory, + ItemLoans, SyncOutbox, SyncState, ], - daos: [CollectionDao, ItemDao, SyncDao], + daos: [CollectionDao, ItemDao, LoanDao, SyncDao], ) class AppDatabase extends _$AppDatabase { AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection()); @override - int get schemaVersion => 7; + int get schemaVersion => 8; @override MigrationStrategy get migration { @@ -39,6 +40,13 @@ class AppDatabase extends _$AppDatabase { 'CREATE INDEX idx_item_price_history_item_time ' 'ON item_price_history(item_id, recorded_at DESC);', ); + await customStatement( + 'CREATE INDEX idx_item_loans_item_active ' + 'ON item_loans(item_id, returned_at);', + ); + await customStatement( + 'CREATE INDEX idx_item_loans_due_at ON item_loans(due_at);', + ); await customStatement( 'CREATE INDEX idx_sync_outbox_created_at ON sync_outbox(created_at);', ); @@ -84,6 +92,17 @@ class AppDatabase extends _$AppDatabase { if (from < 7) { await m.addColumn(syncState, syncState.nextRetryAt); } + + if (from < 8) { + await m.createTable(itemLoans); + await customStatement( + 'CREATE INDEX idx_item_loans_item_active ' + 'ON item_loans(item_id, returned_at);', + ); + await customStatement( + 'CREATE INDEX idx_item_loans_due_at ON item_loans(due_at);', + ); + } }, beforeOpen: (details) async { await customStatement('PRAGMA foreign_keys = ON'); diff --git a/packages/integrations/database/lib/src/daos/daos.dart b/packages/integrations/database/lib/src/daos/daos.dart index 57b697c..b99f9f7 100644 --- a/packages/integrations/database/lib/src/daos/daos.dart +++ b/packages/integrations/database/lib/src/daos/daos.dart @@ -1,3 +1,4 @@ export 'collection_dao.dart'; export 'item_dao.dart'; +export 'loan_dao.dart'; export 'sync_dao.dart'; diff --git a/packages/integrations/database/lib/src/daos/loan_dao.dart b/packages/integrations/database/lib/src/daos/loan_dao.dart new file mode 100644 index 0000000..ca1ecc1 --- /dev/null +++ b/packages/integrations/database/lib/src/daos/loan_dao.dart @@ -0,0 +1,178 @@ +import 'package:database/src/app_database.dart'; +import 'package:database/src/tables/tables.dart'; +import 'package:drift/drift.dart'; + +part 'loan_dao.g.dart'; + +class ItemLoanWithItemData { + const ItemLoanWithItemData({ + required this.loan, + required this.item, + required this.collection, + }); + + final ItemLoanData loan; + final ItemData item; + final CollectionData collection; +} + +@DriftAccessor(tables: [ItemLoans, Items, Collections]) +class LoanDao extends DatabaseAccessor with _$LoanDaoMixin { + LoanDao(super.db); + + Stream> watchActiveLoans() { + final query = + select(itemLoans).join([ + innerJoin(items, items.id.equalsExp(itemLoans.itemId)), + innerJoin( + collections, + collections.id.equalsExp(items.collectionId), + ), + ]) + ..where(itemLoans.returnedAt.isNull()) + ..orderBy([ + OrderingTerm.asc(itemLoans.dueAt), + OrderingTerm.desc(itemLoans.loanedAt), + ]); + + return query.watch().map(_mapJoinedRows); + } + + Stream> watchLoanHistory({int limit = 200}) { + final query = + select(itemLoans).join([ + innerJoin(items, items.id.equalsExp(itemLoans.itemId)), + innerJoin( + collections, + collections.id.equalsExp(items.collectionId), + ), + ]) + ..where(itemLoans.returnedAt.isNotNull()) + ..orderBy([ + OrderingTerm.desc(itemLoans.returnedAt), + OrderingTerm.desc(itemLoans.loanedAt), + ]) + ..limit(limit); + + return query.watch().map(_mapJoinedRows); + } + + Stream watchActiveLoanForItem(String itemId) { + final query = + select(itemLoans).join([ + innerJoin(items, items.id.equalsExp(itemLoans.itemId)), + innerJoin( + collections, + collections.id.equalsExp(items.collectionId), + ), + ]) + ..where( + itemLoans.itemId.equals(itemId) & itemLoans.returnedAt.isNull(), + ) + ..orderBy([OrderingTerm.desc(itemLoans.loanedAt)]) + ..limit(1); + + return query.watch().map((rows) { + if (rows.isEmpty) { + return null; + } + return _mapJoinedRow(rows.first); + }); + } + + Future getLoanById(String id) { + return (select( + itemLoans, + )..where((tbl) => tbl.id.equals(id))).getSingleOrNull(); + } + + Future getLoanWithItemById(String loanId) async { + final query = + select(itemLoans).join([ + innerJoin(items, items.id.equalsExp(itemLoans.itemId)), + innerJoin( + collections, + collections.id.equalsExp(items.collectionId), + ), + ]) + ..where(itemLoans.id.equals(loanId)) + ..limit(1); + + final rows = await query.get(); + if (rows.isEmpty) { + return null; + } + + return _mapJoinedRow(rows.first); + } + + Future getActiveLoanByItemId(String itemId) { + return (select(itemLoans) + ..where((tbl) => tbl.itemId.equals(itemId) & tbl.returnedAt.isNull()) + ..orderBy([(tbl) => OrderingTerm.desc(tbl.loanedAt)]) + ..limit(1)) + .getSingleOrNull(); + } + + Future getActiveLoanWithItemByItemId( + String itemId, + ) async { + final query = + select(itemLoans).join([ + innerJoin(items, items.id.equalsExp(itemLoans.itemId)), + innerJoin( + collections, + collections.id.equalsExp(items.collectionId), + ), + ]) + ..where( + itemLoans.itemId.equals(itemId) & itemLoans.returnedAt.isNull(), + ) + ..orderBy([OrderingTerm.desc(itemLoans.loanedAt)]) + ..limit(1); + + final rows = await query.get(); + if (rows.isEmpty) { + return null; + } + return _mapJoinedRow(rows.first); + } + + Future insertLoan(ItemLoansCompanion loan) { + return into(itemLoans).insert(loan, mode: InsertMode.insertOrReplace); + } + + Future updateLoan(ItemLoansCompanion loan) { + return (update( + itemLoans, + )..where((tbl) => tbl.id.equals(loan.id.value))).write(loan); + } + + Future markReturned({ + required String loanId, + required DateTime returnedAt, + }) { + return (update(itemLoans)..where((tbl) => tbl.id.equals(loanId))).write( + ItemLoansCompanion( + returnedAt: Value(returnedAt), + updatedAt: Value(returnedAt), + ), + ); + } + + Future deleteLoan(String loanId) { + return (delete(itemLoans)..where((tbl) => tbl.id.equals(loanId))).go(); + } + + List _mapJoinedRows(List rows) { + return rows.map(_mapJoinedRow).toList(growable: false); + } + + ItemLoanWithItemData _mapJoinedRow(TypedResult row) { + return ItemLoanWithItemData( + loan: row.readTable(itemLoans), + item: row.readTable(items), + collection: row.readTable(collections), + ); + } +} diff --git a/packages/integrations/database/lib/src/tables/item_loans_table.dart b/packages/integrations/database/lib/src/tables/item_loans_table.dart new file mode 100644 index 0000000..02bf551 --- /dev/null +++ b/packages/integrations/database/lib/src/tables/item_loans_table.dart @@ -0,0 +1,21 @@ +import 'package:drift/drift.dart'; + +import 'items_table.dart'; + +@DataClassName('ItemLoanData') +class ItemLoans extends Table { + TextColumn get id => text()(); + TextColumn get itemId => + text().references(Items, #id, onDelete: KeyAction.cascade)(); + TextColumn get borrowerName => text().withLength(min: 1, max: 120)(); + TextColumn get borrowerContact => text().nullable()(); + TextColumn get notes => text().nullable()(); + DateTimeColumn get loanedAt => dateTime()(); + DateTimeColumn get dueAt => dateTime().nullable()(); + DateTimeColumn get returnedAt => dateTime().nullable()(); + DateTimeColumn get createdAt => dateTime()(); + DateTimeColumn get updatedAt => dateTime()(); + + @override + Set get primaryKey => {id}; +} diff --git a/packages/integrations/database/lib/src/tables/tables.dart b/packages/integrations/database/lib/src/tables/tables.dart index e158a85..33a2e1e 100644 --- a/packages/integrations/database/lib/src/tables/tables.dart +++ b/packages/integrations/database/lib/src/tables/tables.dart @@ -3,5 +3,6 @@ export 'items_table.dart'; export 'tags_table.dart'; export 'item_tags_table.dart'; export 'item_price_history_table.dart'; +export 'item_loans_table.dart'; export 'sync_outbox_table.dart'; export 'sync_state_table.dart'; From ea0b624127eeebe15701b79ffd7707ca63b4272a Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 14:28:17 +0630 Subject: [PATCH 02/16] feat: Implement the loan tracking screen and add its multi-language localization strings. --- .../views/loan_tracking_screen.dart | 139 ++++---- apps/mobile/lib/l10n/arb/app_en.arb | 148 ++++++++- apps/mobile/lib/l10n/arb/app_es.arb | 148 ++++++++- apps/mobile/lib/l10n/arb/app_id.arb | 148 ++++++++- apps/mobile/lib/l10n/arb/app_ja.arb | 148 ++++++++- apps/mobile/lib/l10n/arb/app_ko.arb | 148 ++++++++- apps/mobile/lib/l10n/arb/app_my.arb | 148 ++++++++- apps/mobile/lib/l10n/arb/app_zh.arb | 148 ++++++++- .../lib/l10n/gen/app_localizations.dart | 312 ++++++++++++++++++ .../lib/l10n/gen/app_localizations_en.dart | 170 ++++++++++ .../lib/l10n/gen/app_localizations_es.dart | 170 ++++++++++ .../lib/l10n/gen/app_localizations_id.dart | 170 ++++++++++ .../lib/l10n/gen/app_localizations_ja.dart | 170 ++++++++++ .../lib/l10n/gen/app_localizations_ko.dart | 170 ++++++++++ .../lib/l10n/gen/app_localizations_my.dart | 170 ++++++++++ .../lib/l10n/gen/app_localizations_zh.dart | 170 ++++++++++ 16 files changed, 2609 insertions(+), 68 deletions(-) diff --git a/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart b/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart index 1d36c7c..32f1c7a 100644 --- a/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart +++ b/apps/mobile/lib/features/loans/presentation/views/loan_tracking_screen.dart @@ -18,17 +18,18 @@ class _LoanTrackingScreenState extends ConsumerState { @override Widget build(BuildContext context) { + final l10n = context.l10n; final activeAsync = ref.watch(activeLoansProvider); final historyAsync = ref.watch(loanHistoryProvider); final loansAsync = _showHistory ? historyAsync : activeAsync; return Scaffold( - appBar: AppBar(title: const Text('Loan Tracking')), + appBar: AppBar(title: Text(l10n.loanTrackingTitle)), floatingActionButton: FloatingActionButton.extended( heroTag: 'loan_tracking_fab', onPressed: () => _showCreateLoanSheet(context), icon: const Icon(Icons.handshake_outlined), - label: const Text('New Loan'), + label: Text(l10n.loanTrackingNewLoan), ), body: ListView( padding: const EdgeInsets.fromLTRB( @@ -47,12 +48,12 @@ class _LoanTrackingScreenState extends ConsumerState { children: [ ChoiceChip( selected: !_showHistory, - label: const Text('Active'), + label: Text(l10n.loanTrackingFilterActive), onSelected: (_) => setState(() => _showHistory = false), ), ChoiceChip( selected: _showHistory, - label: const Text('History'), + label: Text(l10n.loanTrackingFilterHistory), onSelected: (_) => setState(() => _showHistory = true), ), ], @@ -73,11 +74,11 @@ class _LoanTrackingScreenState extends ConsumerState { ? Icons.history_toggle_off_rounded : Icons.inventory_2_outlined, title: _showHistory - ? 'No returned loans yet' - : 'No active loans', + ? l10n.loanTrackingEmptyHistoryTitle + : l10n.loanTrackingEmptyActiveTitle, message: _showHistory - ? 'Returned items will appear here.' - : 'Create a loan to start tracking borrowed items.', + ? l10n.loanTrackingEmptyHistoryMessage + : l10n.loanTrackingEmptyActiveMessage, ); } @@ -101,12 +102,12 @@ class _LoanTrackingScreenState extends ConsumerState { ], ); }, - loading: () => const Padding( + loading: () => Padding( padding: EdgeInsets.only(top: AppSpacing.xxl), - child: LoadingView(message: 'Loading loans...'), + child: LoadingView(message: l10n.loanTrackingLoadingLoans), ), error: (error, _) => ErrorView( - message: 'Failed to load loans: $error', + message: l10n.loanTrackingLoadFailed('$error'), onRetry: () { ref.invalidate(activeLoansProvider); ref.invalidate(loanHistoryProvider); @@ -128,18 +129,21 @@ class _LoanTrackingScreenState extends ConsumerState { } Future _markReturned(BuildContext context, LoanRecord loan) async { + final l10n = context.l10n; final confirmed = await showAppDialog( context: context, - title: const Text('Mark as returned?'), - content: Text('Confirm return for "${loan.itemTitle}".'), + title: Text(l10n.loanTrackingMarkReturnedConfirmTitle), + content: Text( + l10n.loanTrackingMarkReturnedConfirmMessage(loan.itemTitle), + ), actions: [ AppButton( - label: context.l10n.actionCancel, + label: l10n.actionCancel, variant: AppButtonVariant.ghost, onPressed: () => closeAppDialog(context, false), ), AppButton( - label: 'Mark Returned', + label: l10n.loanTrackingMarkReturnedAction, onPressed: () => closeAppDialog(context, true), ), ], @@ -154,16 +158,16 @@ class _LoanTrackingScreenState extends ConsumerState { if (!context.mounted) { return; } - ScaffoldMessenger.of( - context, - ).showSnackBar(const SnackBar(content: Text('Loan marked as returned.'))); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(l10n.loanTrackingMarkedReturnedSuccess)), + ); } catch (error) { if (!context.mounted) { return; } ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Failed to mark return: $error'), + content: Text(l10n.loanTrackingMarkReturnedFailed('$error')), backgroundColor: Colors.red, ), ); @@ -171,13 +175,14 @@ class _LoanTrackingScreenState extends ConsumerState { } Future _deleteLoan(BuildContext context, LoanRecord loan) async { + final l10n = context.l10n; final confirmed = await showAppDialog( context: context, - title: const Text('Delete loan record?'), - content: Text('Delete loan record for "${loan.itemTitle}".'), + title: Text(l10n.loanTrackingDeleteConfirmTitle), + content: Text(l10n.loanTrackingDeleteConfirmMessage(loan.itemTitle)), actions: [ AppButton( - label: context.l10n.actionCancel, + label: l10n.actionCancel, variant: AppButtonVariant.ghost, onPressed: () => closeAppDialog(context, false), ), @@ -200,14 +205,14 @@ class _LoanTrackingScreenState extends ConsumerState { } ScaffoldMessenger.of( context, - ).showSnackBar(const SnackBar(content: Text('Loan deleted.'))); + ).showSnackBar(SnackBar(content: Text(l10n.loanTrackingDeleteSuccess))); } catch (error) { if (!context.mounted) { return; } ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Failed to delete loan: $error'), + content: Text(l10n.loanTrackingDeleteFailed('$error')), backgroundColor: Colors.red, ), ); @@ -222,6 +227,7 @@ class _LoanSummaryCard extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; final theme = Theme.of(context); return AppCard( @@ -236,7 +242,7 @@ class _LoanSummaryCard extends StatelessWidget { Expanded( child: _StatPill( icon: Icons.inventory_2_outlined, - label: 'Active Loans', + label: l10n.loanTrackingSummaryActiveLabel, value: '${activeLoans.length}', ), ), @@ -244,7 +250,7 @@ class _LoanSummaryCard extends StatelessWidget { Expanded( child: _StatPill( icon: Icons.warning_amber_rounded, - label: 'Overdue', + label: l10n.loanTrackingSummaryOverdueLabel, value: '$overdueCount', tint: overdueCount > 0 ? theme.colorScheme.errorContainer @@ -258,7 +264,7 @@ class _LoanSummaryCard extends StatelessWidget { height: 74, child: Center(child: LoadingView(indicatorSize: 30)), ), - error: (_, _) => const Text('Unable to load loan summary.'), + error: (_, _) => Text(l10n.loanTrackingSummaryLoadFailed), ), ); } @@ -330,6 +336,7 @@ class _LoanCard extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; final theme = Theme.of(context); return AppCard( @@ -362,28 +369,28 @@ class _LoanCard extends StatelessWidget { const SizedBox(height: AppSpacing.md), _LoanMetaRow( icon: Icons.person_outline_rounded, - label: 'Borrower', + label: l10n.loanTrackingFieldBorrower, value: loan.borrowerName, ), if (loan.borrowerContact != null) ...[ const SizedBox(height: AppSpacing.xs), _LoanMetaRow( icon: Icons.call_outlined, - label: 'Contact', + label: l10n.loanTrackingFieldContact, value: loan.borrowerContact!, ), ], const SizedBox(height: AppSpacing.xs), _LoanMetaRow( icon: Icons.calendar_today_outlined, - label: 'Loaned', + label: l10n.loanTrackingFieldLoaned, value: _formatDate(context, loan.loanedAt), ), if (loan.dueAt != null) ...[ const SizedBox(height: AppSpacing.xs), _LoanMetaRow( icon: Icons.event_available_outlined, - label: 'Due', + label: l10n.loanTrackingFieldDue, value: _formatDate(context, loan.dueAt!), valueColor: loan.isOverdue ? theme.colorScheme.error @@ -394,7 +401,7 @@ class _LoanCard extends StatelessWidget { const SizedBox(height: AppSpacing.xs), _LoanMetaRow( icon: Icons.assignment_turned_in_outlined, - label: 'Returned', + label: l10n.loanTrackingFieldReturned, value: _formatDate(context, loan.returnedAt!), ), ], @@ -416,7 +423,7 @@ class _LoanCard extends StatelessWidget { children: [ if (onReturn != null) AppButton( - label: 'Mark Returned', + label: l10n.loanTrackingMarkReturnedAction, variant: AppButtonVariant.secondary, onPressed: onReturn, ), @@ -491,6 +498,7 @@ class _LoanStatusBadge extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; final theme = Theme.of(context); final colorScheme = theme.colorScheme; @@ -501,15 +509,15 @@ class _LoanStatusBadge extends StatelessWidget { if (loan.isReturned) { background = colorScheme.primary.withValues(alpha: 0.14); foreground = colorScheme.primary; - label = 'Returned'; + label = l10n.loanTrackingStatusReturned; } else if (loan.isOverdue) { background = colorScheme.error.withValues(alpha: 0.14); foreground = colorScheme.error; - label = 'Overdue'; + label = l10n.loanTrackingStatusOverdue; } else { background = colorScheme.tertiary.withValues(alpha: 0.14); foreground = colorScheme.tertiary; - label = 'Active'; + label = l10n.loanTrackingStatusActive; } return Container( @@ -555,6 +563,7 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { @override Widget build(BuildContext context) { + final l10n = context.l10n; final candidatesAsync = ref.watch(loanCandidateItemsProvider); final activeLoans = ref.watch(activeLoansProvider).asData?.value ?? const []; @@ -595,14 +604,14 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Create Loan', + l10n.loanTrackingCreateTitle, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w700, ), ), const SizedBox(height: AppSpacing.sm), Text( - 'Track who borrowed an item and when it should be returned.', + l10n.loanTrackingCreateDescription, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onSurfaceVariant, ), @@ -611,16 +620,17 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { if (candidates.isEmpty) EmptyState( icon: Icons.inventory_2_outlined, - title: 'No available items', - message: - 'All items are currently loaned or there are no items yet.', + title: l10n.loanTrackingCreateNoItemsTitle, + message: l10n.loanTrackingCreateNoItemsMessage, ) else DropdownButtonFormField( key: ValueKey(_selectedItemId), initialValue: _selectedItemId, isExpanded: true, - decoration: const InputDecoration(labelText: 'Item'), + decoration: InputDecoration( + labelText: l10n.loanTrackingCreateItemLabel, + ), items: candidates .map( (candidate) => DropdownMenuItem( @@ -640,15 +650,15 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { const SizedBox(height: AppSpacing.md), AppInput( controller: _borrowerController, - labelText: 'Borrower name', - hintText: 'e.g. John Doe', + labelText: l10n.loanTrackingCreateBorrowerLabel, + hintText: l10n.loanTrackingCreateBorrowerHint, enabled: !_submitting && candidates.isNotEmpty, ), const SizedBox(height: AppSpacing.md), AppInput( controller: _contactController, - labelText: 'Contact (optional)', - hintText: 'Phone, email, or @username', + labelText: l10n.loanTrackingCreateContactLabel, + hintText: l10n.loanTrackingCreateContactHint, enabled: !_submitting && candidates.isNotEmpty, ), const SizedBox(height: AppSpacing.md), @@ -663,14 +673,16 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { const SizedBox(height: AppSpacing.md), AppInput( controller: _notesController, - labelText: 'Notes (optional)', - hintText: 'Extra details for this loan', + labelText: l10n.loanTrackingCreateNotesLabel, + hintText: l10n.loanTrackingCreateNotesHint, maxLines: 3, enabled: !_submitting && candidates.isNotEmpty, ), const SizedBox(height: AppSpacing.lg), AppButton( - label: _submitting ? 'Creating...' : 'Create Loan', + label: _submitting + ? l10n.loanTrackingCreateSubmitting + : l10n.loanTrackingCreateAction, onPressed: (_submitting || candidates.isEmpty) ? null : () => _submit(context), @@ -687,12 +699,12 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { ), ); }, - loading: () => const SizedBox( + loading: () => SizedBox( height: 180, - child: LoadingView(message: 'Loading items...'), + child: LoadingView(message: l10n.loanTrackingLoadingItems), ), error: (error, _) => ErrorView( - message: 'Failed to load items: $error', + message: l10n.loanTrackingLoadItemsFailed('$error'), onRetry: () => ref.invalidate(loanCandidateItemsProvider), ), ), @@ -717,6 +729,7 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { } Future _submit(BuildContext context) async { + final l10n = context.l10n; final itemId = _selectedItemId; if (itemId == null || itemId.isEmpty) { return; @@ -725,7 +738,7 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { final borrowerName = _borrowerController.text.trim(); if (borrowerName.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Borrower name is required.')), + SnackBar(content: Text(l10n.loanTrackingBorrowerRequired)), ); return; } @@ -754,16 +767,16 @@ class _CreateLoanSheetState extends ConsumerState<_CreateLoanSheet> { } Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Loan created successfully.')), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.loanTrackingCreateSuccess))); } catch (error) { if (!context.mounted) { return; } ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('Failed to create loan: $error'), + content: Text(l10n.loanTrackingCreateFailed('$error')), backgroundColor: Colors.red, ), ); @@ -790,20 +803,21 @@ class _DueDateField extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; final locale = Localizations.localeOf(context).toLanguageTag(); final label = dueDate == null - ? 'No due date' + ? l10n.loanTrackingNoDueDate : DateFormat.yMMMd(locale).format(dueDate!); final controls = [ AppButton( - label: 'Pick', + label: l10n.loanTrackingPickDateAction, variant: AppButtonVariant.secondary, onPressed: enabled ? onPick : null, ), if (dueDate != null) AppButton( - label: 'Clear', + label: l10n.loanTrackingClearDateAction, variant: AppButtonVariant.ghost, onPressed: enabled ? onClear : null, ), @@ -826,7 +840,10 @@ class _DueDateField extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Due date', style: Theme.of(context).textTheme.labelMedium), + Text( + l10n.loanTrackingDueDateLabel, + style: Theme.of(context).textTheme.labelMedium, + ), const SizedBox(height: AppSpacing.xs), Text(label, style: Theme.of(context).textTheme.bodyMedium), ], diff --git a/apps/mobile/lib/l10n/arb/app_en.arb b/apps/mobile/lib/l10n/arb/app_en.arb index 3d28c05..816820a 100644 --- a/apps/mobile/lib/l10n/arb/app_en.arb +++ b/apps/mobile/lib/l10n/arb/app_en.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "Music", "@collectionTypeMusic": {}, "collectionTypeCustom": "Custom", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "Loan Tracking", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "New Loan", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "Active", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "History", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "No returned loans yet", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "Returned items will appear here.", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "No active loans", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "Create a loan to start tracking borrowed items.", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "Loading loans...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "Failed to load loans: {error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "Mark as returned?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "Confirm return for \"{itemTitle}\".", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "Mark Returned", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "Loan marked as returned.", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "Failed to mark return: {error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "Delete loan record?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "Delete loan record for \"{itemTitle}\".", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "Loan deleted.", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "Failed to delete loan: {error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "Active Loans", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "Overdue", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "Unable to load loan summary.", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "Borrower", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "Contact", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "Loaned", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "Due", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "Returned", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "Returned", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "Overdue", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "Active", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "Create Loan", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "Track who borrowed an item and when it should be returned.", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "No available items", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "All items are currently loaned or there are no items yet.", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "Item", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "Borrower name", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "e.g. John Doe", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "Contact (optional)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "Phone, email, or @username", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "Notes (optional)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "Extra details for this loan", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "Creating...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "Create Loan", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "Loading items...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "Failed to load items: {error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "Borrower name is required.", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "Loan created successfully.", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "Failed to create loan: {error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "No due date", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "Pick", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "Clear", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "Due date", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/arb/app_es.arb b/apps/mobile/lib/l10n/arb/app_es.arb index 131aac4..1f8739a 100644 --- a/apps/mobile/lib/l10n/arb/app_es.arb +++ b/apps/mobile/lib/l10n/arb/app_es.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "Música", "@collectionTypeMusic": {}, "collectionTypeCustom": "Personalizada", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "Seguimiento de préstamos", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "Nuevo préstamo", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "Activos", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "Historial", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "Aún no hay préstamos devueltos", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "Los artículos devueltos aparecerán aquí.", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "No hay préstamos activos", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "Crea un préstamo para empezar a seguir artículos prestados.", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "Cargando préstamos...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "No se pudieron cargar los préstamos: {error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "¿Marcar como devuelto?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "Confirmar devolución de \"{itemTitle}\".", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "Marcar devuelto", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "El préstamo se marcó como devuelto.", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "No se pudo marcar la devolución: {error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "¿Eliminar registro del préstamo?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "Eliminar registro del préstamo de \"{itemTitle}\".", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "Préstamo eliminado.", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "No se pudo eliminar el préstamo: {error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "Préstamos activos", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "Vencidos", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "No se pudo cargar el resumen de préstamos.", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "Prestatario", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "Contacto", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "Prestado", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "Vence", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "Devuelto", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "Devuelto", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "Vencido", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "Activo", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "Crear préstamo", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "Registra quién tomó un artículo prestado y cuándo debe devolverlo.", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "No hay artículos disponibles", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "Todos los artículos están prestados actualmente o aún no hay artículos.", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "Artículo", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "Nombre del prestatario", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "p. ej. Juan Pérez", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "Contacto (opcional)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "Teléfono, correo o @usuario", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "Notas (opcional)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "Detalles adicionales para este préstamo", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "Creando...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "Crear préstamo", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "Cargando artículos...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "No se pudieron cargar los artículos: {error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "El nombre del prestatario es obligatorio.", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "Préstamo creado correctamente.", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "No se pudo crear el préstamo: {error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "Sin fecha de vencimiento", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "Elegir", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "Limpiar", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "Fecha de vencimiento", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/arb/app_id.arb b/apps/mobile/lib/l10n/arb/app_id.arb index d6f80ec..d9c3a15 100644 --- a/apps/mobile/lib/l10n/arb/app_id.arb +++ b/apps/mobile/lib/l10n/arb/app_id.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "Musik", "@collectionTypeMusic": {}, "collectionTypeCustom": "Kustom", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "Pelacakan Pinjaman", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "Pinjaman Baru", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "Aktif", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "Riwayat", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "Belum ada pinjaman yang dikembalikan", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "Item yang sudah dikembalikan akan muncul di sini.", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "Tidak ada pinjaman aktif", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "Buat pinjaman untuk mulai melacak item yang dipinjam.", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "Memuat pinjaman...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "Gagal memuat pinjaman: {error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "Tandai sudah dikembalikan?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "Konfirmasi pengembalian untuk \"{itemTitle}\".", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "Tandai Dikembalikan", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "Pinjaman ditandai sudah dikembalikan.", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "Gagal menandai pengembalian: {error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "Hapus catatan pinjaman?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "Hapus catatan pinjaman untuk \"{itemTitle}\".", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "Pinjaman dihapus.", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "Gagal menghapus pinjaman: {error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "Pinjaman Aktif", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "Terlambat", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "Tidak dapat memuat ringkasan pinjaman.", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "Peminjam", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "Kontak", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "Dipinjamkan", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "Jatuh tempo", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "Dikembalikan", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "Dikembalikan", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "Terlambat", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "Aktif", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "Buat Pinjaman", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "Lacak siapa yang meminjam item dan kapan harus dikembalikan.", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "Tidak ada item yang tersedia", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "Semua item sedang dipinjam atau belum ada item.", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "Item", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "Nama peminjam", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "mis. Budi Santoso", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "Kontak (opsional)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "Telepon, email, atau @username", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "Catatan (opsional)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "Detail tambahan untuk pinjaman ini", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "Membuat...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "Buat Pinjaman", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "Memuat item...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "Gagal memuat item: {error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "Nama peminjam wajib diisi.", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "Pinjaman berhasil dibuat.", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "Gagal membuat pinjaman: {error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "Tanpa tanggal jatuh tempo", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "Pilih", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "Hapus", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "Tanggal jatuh tempo", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/arb/app_ja.arb b/apps/mobile/lib/l10n/arb/app_ja.arb index a439846..f77258c 100644 --- a/apps/mobile/lib/l10n/arb/app_ja.arb +++ b/apps/mobile/lib/l10n/arb/app_ja.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "音楽", "@collectionTypeMusic": {}, "collectionTypeCustom": "カスタム", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "貸出管理", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "新しい貸出", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "アクティブ", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "履歴", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "返却済みの貸出はまだありません", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "返却されたアイテムはここに表示されます。", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "アクティブな貸出はありません", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "貸出を作成して、借りられたアイテムの管理を始めましょう。", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "貸出を読み込み中...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "貸出の読み込みに失敗しました: {error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "返却済みにしますか?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "\"{itemTitle}\" の返却を確認します。", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "返却済みにする", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "貸出を返却済みにしました。", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "返却の更新に失敗しました: {error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "貸出記録を削除しますか?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "\"{itemTitle}\" の貸出記録を削除します。", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "貸出記録を削除しました。", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "貸出の削除に失敗しました: {error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "アクティブな貸出", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "期限超過", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "貸出サマリーを読み込めませんでした。", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "借り手", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "連絡先", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "貸出日", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "返却期限", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "返却日", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "返却済み", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "期限超過", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "アクティブ", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "貸出を作成", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "誰がアイテムを借りたか、いつ返却予定かを記録します。", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "利用可能なアイテムがありません", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "すべて貸出中か、まだアイテムがありません。", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "アイテム", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "借り手の名前", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "例: 山田 太郎", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "連絡先(任意)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "電話、メール、または @username", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "メモ(任意)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "この貸出の追加情報", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "作成中...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "貸出を作成", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "アイテムを読み込み中...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "アイテムの読み込みに失敗しました: {error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "借り手の名前は必須です。", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "貸出を作成しました。", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "貸出の作成に失敗しました: {error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "返却期限なし", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "選択", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "クリア", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "返却期限", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/arb/app_ko.arb b/apps/mobile/lib/l10n/arb/app_ko.arb index 1432d47..f1cc107 100644 --- a/apps/mobile/lib/l10n/arb/app_ko.arb +++ b/apps/mobile/lib/l10n/arb/app_ko.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "음악", "@collectionTypeMusic": {}, "collectionTypeCustom": "사용자 지정", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "대여 추적", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "새 대여", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "활성", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "기록", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "아직 반납된 대여가 없습니다", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "반납된 항목이 여기에 표시됩니다.", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "활성 대여가 없습니다", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "대여를 생성해 빌려준 항목을 추적해 보세요.", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "대여 불러오는 중...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "대여를 불러오지 못했습니다: {error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "반납으로 표시할까요?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "\"{itemTitle}\" 반납을 확인합니다.", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "반납 처리", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "대여가 반납 처리되었습니다.", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "반납 처리에 실패했습니다: {error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "대여 기록을 삭제할까요?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "\"{itemTitle}\" 대여 기록을 삭제합니다.", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "대여가 삭제되었습니다.", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "대여 삭제에 실패했습니다: {error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "활성 대여", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "연체", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "대여 요약을 불러올 수 없습니다.", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "대여자", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "연락처", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "대여일", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "반납 예정일", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "반납일", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "반납됨", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "연체", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "활성", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "대여 생성", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "누가 항목을 빌렸는지와 반납 예정일을 추적합니다.", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "사용 가능한 항목이 없습니다", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "모든 항목이 이미 대여 중이거나 아직 항목이 없습니다.", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "항목", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "대여자 이름", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "예: 홍길동", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "연락처 (선택)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "전화번호, 이메일 또는 @username", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "메모 (선택)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "이 대여에 대한 추가 정보", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "생성 중...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "대여 생성", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "항목 불러오는 중...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "항목을 불러오지 못했습니다: {error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "대여자 이름은 필수입니다.", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "대여가 생성되었습니다.", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "대여 생성에 실패했습니다: {error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "반납 예정일 없음", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "선택", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "지우기", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "반납 예정일", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/arb/app_my.arb b/apps/mobile/lib/l10n/arb/app_my.arb index 8f0b418..bdea14d 100644 --- a/apps/mobile/lib/l10n/arb/app_my.arb +++ b/apps/mobile/lib/l10n/arb/app_my.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "ဂီတ", "@collectionTypeMusic": {}, "collectionTypeCustom": "စိတ်ကြိုက်", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "ငှားရမ်းမှု ခြေရာခံ", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "ငှားရမ်းမှု အသစ်", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "လက်ရှိ", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "မှတ်တမ်း", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "ပြန်အပ်ပြီး ငှားရမ်းမှု မရှိသေးပါ", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "ပြန်အပ်ပြီး ပစ္စည်းများကို ဒီနေရာတွင် ပြပါမည်။", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "လက်ရှိ ငှားရမ်းမှု မရှိပါ", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "ငှားသွားသော ပစ္စည်းများကို ခြေရာခံရန် ငှားရမ်းမှု အသစ် ဖန်တီးပါ။", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "ငှားရမ်းမှုများ တင်နေသည်...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "ငှားရမ်းမှုများ တင်မရပါ: {error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "ပြန်အပ်ပြီးဟု မှတ်မလား?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "\"{itemTitle}\" ကို ပြန်အပ်ပြီးဟု အတည်ပြုမည်။", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "ပြန်အပ်ပြီး မှတ်မည်", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "ငှားရမ်းမှုကို ပြန်အပ်ပြီးအဖြစ် မှတ်သားပြီးပါပြီ။", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "ပြန်အပ်ပြီး မှတ်မရပါ: {error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "ငှားရမ်းမှု မှတ်တမ်း ဖျက်မလား?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "\"{itemTitle}\" အတွက် ငှားရမ်းမှု မှတ်တမ်းကို ဖျက်မည်။", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "ငှားရမ်းမှုကို ဖျက်ပြီးပါပြီ။", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "ငှားရမ်းမှု ဖျက်မရပါ: {error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "လက်ရှိ ငှားရမ်းမှု", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "ကျော်လွန်", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "ငှားရမ်းမှု အနှစ်ချုပ် တင်မရပါ။", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "ငှားယူသူ", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "ဆက်သွယ်ရန်", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "ငှားသည့်နေ့", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "ပြန်အပ်ရမည့်နေ့", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "ပြန်အပ်သည့်နေ့", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "ပြန်အပ်ပြီး", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "ကျော်လွန်", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "လက်ရှိ", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "ငှားရမ်းမှု ဖန်တီး", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "ဘယ်သူငှားယူသွားသည်နှင့် ဘယ်နေ့ ပြန်အပ်ရမည်ကို မှတ်တမ်းတင်ပါ။", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "အသုံးပြုနိုင်သော ပစ္စည်း မရှိပါ", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "ပစ္စည်းအားလုံး ငှားထားပြီး သို့မဟုတ် ပစ္စည်းမရှိသေးပါ။", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "ပစ္စည်း", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "ငှားယူသူ အမည်", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "ဥပမာ - Aung Aung", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "ဆက်သွယ်ရန် (မဖြည့်လည်းရ)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "ဖုန်း၊ အီးမေးလ် သို့မဟုတ် @username", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "မှတ်စု (မဖြည့်လည်းရ)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "ဒီငှားရမ်းမှုအတွက် အသေးစိတ်", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "ဖန်တီးနေသည်...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "ငှားရမ်းမှု ဖန်တီး", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "ပစ္စည်းများ တင်နေသည်...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "ပစ္စည်းများ တင်မရပါ: {error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "ငှားယူသူ အမည် မဖြစ်မနေလိုအပ်သည်။", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "ငှားရမ်းမှု အောင်မြင်စွာ ဖန်တီးပြီးပါပြီ။", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "ငှားရမ်းမှု ဖန်တီးမရပါ: {error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "ပြန်အပ်ရမည့်နေ့ မသတ်မှတ်ထားပါ", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "ရွေးမည်", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "ရှင်းမည်", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "ပြန်အပ်ရမည့်နေ့", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/arb/app_zh.arb b/apps/mobile/lib/l10n/arb/app_zh.arb index 7adf6a6..d8be95c 100644 --- a/apps/mobile/lib/l10n/arb/app_zh.arb +++ b/apps/mobile/lib/l10n/arb/app_zh.arb @@ -980,5 +980,151 @@ "collectionTypeMusic": "音乐", "@collectionTypeMusic": {}, "collectionTypeCustom": "自定义", - "@collectionTypeCustom": {} + "@collectionTypeCustom": {}, + "loanTrackingTitle": "借出追踪", + "@loanTrackingTitle": {}, + "loanTrackingNewLoan": "新建借出", + "@loanTrackingNewLoan": {}, + "loanTrackingFilterActive": "进行中", + "@loanTrackingFilterActive": {}, + "loanTrackingFilterHistory": "历史", + "@loanTrackingFilterHistory": {}, + "loanTrackingEmptyHistoryTitle": "暂无已归还借出", + "@loanTrackingEmptyHistoryTitle": {}, + "loanTrackingEmptyHistoryMessage": "已归还条目会显示在这里。", + "@loanTrackingEmptyHistoryMessage": {}, + "loanTrackingEmptyActiveTitle": "暂无进行中借出", + "@loanTrackingEmptyActiveTitle": {}, + "loanTrackingEmptyActiveMessage": "创建一条借出记录来跟踪借出物品。", + "@loanTrackingEmptyActiveMessage": {}, + "loanTrackingLoadingLoans": "正在加载借出记录...", + "@loanTrackingLoadingLoans": {}, + "loanTrackingLoadFailed": "加载借出记录失败:{error}", + "@loanTrackingLoadFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedConfirmTitle": "标记为已归还?", + "@loanTrackingMarkReturnedConfirmTitle": {}, + "loanTrackingMarkReturnedConfirmMessage": "确认「{itemTitle}」已归还。", + "@loanTrackingMarkReturnedConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingMarkReturnedAction": "标记已归还", + "@loanTrackingMarkReturnedAction": {}, + "loanTrackingMarkedReturnedSuccess": "借出已标记为归还。", + "@loanTrackingMarkedReturnedSuccess": {}, + "loanTrackingMarkReturnedFailed": "标记归还失败:{error}", + "@loanTrackingMarkReturnedFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingDeleteConfirmTitle": "删除借出记录?", + "@loanTrackingDeleteConfirmTitle": {}, + "loanTrackingDeleteConfirmMessage": "删除「{itemTitle}」的借出记录。", + "@loanTrackingDeleteConfirmMessage": { + "placeholders": { + "itemTitle": { + "type": "String" + } + } + }, + "loanTrackingDeleteSuccess": "借出记录已删除。", + "@loanTrackingDeleteSuccess": {}, + "loanTrackingDeleteFailed": "删除借出记录失败:{error}", + "@loanTrackingDeleteFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingSummaryActiveLabel": "进行中借出", + "@loanTrackingSummaryActiveLabel": {}, + "loanTrackingSummaryOverdueLabel": "逾期", + "@loanTrackingSummaryOverdueLabel": {}, + "loanTrackingSummaryLoadFailed": "无法加载借出摘要。", + "@loanTrackingSummaryLoadFailed": {}, + "loanTrackingFieldBorrower": "借用人", + "@loanTrackingFieldBorrower": {}, + "loanTrackingFieldContact": "联系方式", + "@loanTrackingFieldContact": {}, + "loanTrackingFieldLoaned": "借出日期", + "@loanTrackingFieldLoaned": {}, + "loanTrackingFieldDue": "到期日期", + "@loanTrackingFieldDue": {}, + "loanTrackingFieldReturned": "归还日期", + "@loanTrackingFieldReturned": {}, + "loanTrackingStatusReturned": "已归还", + "@loanTrackingStatusReturned": {}, + "loanTrackingStatusOverdue": "逾期", + "@loanTrackingStatusOverdue": {}, + "loanTrackingStatusActive": "进行中", + "@loanTrackingStatusActive": {}, + "loanTrackingCreateTitle": "创建借出", + "@loanTrackingCreateTitle": {}, + "loanTrackingCreateDescription": "记录谁借走了物品以及应归还时间。", + "@loanTrackingCreateDescription": {}, + "loanTrackingCreateNoItemsTitle": "暂无可借出条目", + "@loanTrackingCreateNoItemsTitle": {}, + "loanTrackingCreateNoItemsMessage": "所有条目都在借出中,或还没有条目。", + "@loanTrackingCreateNoItemsMessage": {}, + "loanTrackingCreateItemLabel": "条目", + "@loanTrackingCreateItemLabel": {}, + "loanTrackingCreateBorrowerLabel": "借用人姓名", + "@loanTrackingCreateBorrowerLabel": {}, + "loanTrackingCreateBorrowerHint": "例如:张三", + "@loanTrackingCreateBorrowerHint": {}, + "loanTrackingCreateContactLabel": "联系方式(可选)", + "@loanTrackingCreateContactLabel": {}, + "loanTrackingCreateContactHint": "电话、邮箱或 @username", + "@loanTrackingCreateContactHint": {}, + "loanTrackingCreateNotesLabel": "备注(可选)", + "@loanTrackingCreateNotesLabel": {}, + "loanTrackingCreateNotesHint": "这次借出的额外说明", + "@loanTrackingCreateNotesHint": {}, + "loanTrackingCreateSubmitting": "创建中...", + "@loanTrackingCreateSubmitting": {}, + "loanTrackingCreateAction": "创建借出", + "@loanTrackingCreateAction": {}, + "loanTrackingLoadingItems": "正在加载条目...", + "@loanTrackingLoadingItems": {}, + "loanTrackingLoadItemsFailed": "加载条目失败:{error}", + "@loanTrackingLoadItemsFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingBorrowerRequired": "借用人姓名不能为空。", + "@loanTrackingBorrowerRequired": {}, + "loanTrackingCreateSuccess": "借出创建成功。", + "@loanTrackingCreateSuccess": {}, + "loanTrackingCreateFailed": "创建借出失败:{error}", + "@loanTrackingCreateFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "loanTrackingNoDueDate": "无到期日期", + "@loanTrackingNoDueDate": {}, + "loanTrackingPickDateAction": "选择", + "@loanTrackingPickDateAction": {}, + "loanTrackingClearDateAction": "清除", + "@loanTrackingClearDateAction": {}, + "loanTrackingDueDateLabel": "到期日期", + "@loanTrackingDueDateLabel": {} } diff --git a/apps/mobile/lib/l10n/gen/app_localizations.dart b/apps/mobile/lib/l10n/gen/app_localizations.dart index a3b1c8c..6f884bb 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations.dart @@ -2014,6 +2014,318 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Custom'** String get collectionTypeCustom; + + /// No description provided for @loanTrackingTitle. + /// + /// In en, this message translates to: + /// **'Loan Tracking'** + String get loanTrackingTitle; + + /// No description provided for @loanTrackingNewLoan. + /// + /// In en, this message translates to: + /// **'New Loan'** + String get loanTrackingNewLoan; + + /// No description provided for @loanTrackingFilterActive. + /// + /// In en, this message translates to: + /// **'Active'** + String get loanTrackingFilterActive; + + /// No description provided for @loanTrackingFilterHistory. + /// + /// In en, this message translates to: + /// **'History'** + String get loanTrackingFilterHistory; + + /// No description provided for @loanTrackingEmptyHistoryTitle. + /// + /// In en, this message translates to: + /// **'No returned loans yet'** + String get loanTrackingEmptyHistoryTitle; + + /// No description provided for @loanTrackingEmptyHistoryMessage. + /// + /// In en, this message translates to: + /// **'Returned items will appear here.'** + String get loanTrackingEmptyHistoryMessage; + + /// No description provided for @loanTrackingEmptyActiveTitle. + /// + /// In en, this message translates to: + /// **'No active loans'** + String get loanTrackingEmptyActiveTitle; + + /// No description provided for @loanTrackingEmptyActiveMessage. + /// + /// In en, this message translates to: + /// **'Create a loan to start tracking borrowed items.'** + String get loanTrackingEmptyActiveMessage; + + /// No description provided for @loanTrackingLoadingLoans. + /// + /// In en, this message translates to: + /// **'Loading loans...'** + String get loanTrackingLoadingLoans; + + /// No description provided for @loanTrackingLoadFailed. + /// + /// In en, this message translates to: + /// **'Failed to load loans: {error}'** + String loanTrackingLoadFailed(String error); + + /// No description provided for @loanTrackingMarkReturnedConfirmTitle. + /// + /// In en, this message translates to: + /// **'Mark as returned?'** + String get loanTrackingMarkReturnedConfirmTitle; + + /// No description provided for @loanTrackingMarkReturnedConfirmMessage. + /// + /// In en, this message translates to: + /// **'Confirm return for \"{itemTitle}\".'** + String loanTrackingMarkReturnedConfirmMessage(String itemTitle); + + /// No description provided for @loanTrackingMarkReturnedAction. + /// + /// In en, this message translates to: + /// **'Mark Returned'** + String get loanTrackingMarkReturnedAction; + + /// No description provided for @loanTrackingMarkedReturnedSuccess. + /// + /// In en, this message translates to: + /// **'Loan marked as returned.'** + String get loanTrackingMarkedReturnedSuccess; + + /// No description provided for @loanTrackingMarkReturnedFailed. + /// + /// In en, this message translates to: + /// **'Failed to mark return: {error}'** + String loanTrackingMarkReturnedFailed(String error); + + /// No description provided for @loanTrackingDeleteConfirmTitle. + /// + /// In en, this message translates to: + /// **'Delete loan record?'** + String get loanTrackingDeleteConfirmTitle; + + /// No description provided for @loanTrackingDeleteConfirmMessage. + /// + /// In en, this message translates to: + /// **'Delete loan record for \"{itemTitle}\".'** + String loanTrackingDeleteConfirmMessage(String itemTitle); + + /// No description provided for @loanTrackingDeleteSuccess. + /// + /// In en, this message translates to: + /// **'Loan deleted.'** + String get loanTrackingDeleteSuccess; + + /// No description provided for @loanTrackingDeleteFailed. + /// + /// In en, this message translates to: + /// **'Failed to delete loan: {error}'** + String loanTrackingDeleteFailed(String error); + + /// No description provided for @loanTrackingSummaryActiveLabel. + /// + /// In en, this message translates to: + /// **'Active Loans'** + String get loanTrackingSummaryActiveLabel; + + /// No description provided for @loanTrackingSummaryOverdueLabel. + /// + /// In en, this message translates to: + /// **'Overdue'** + String get loanTrackingSummaryOverdueLabel; + + /// No description provided for @loanTrackingSummaryLoadFailed. + /// + /// In en, this message translates to: + /// **'Unable to load loan summary.'** + String get loanTrackingSummaryLoadFailed; + + /// No description provided for @loanTrackingFieldBorrower. + /// + /// In en, this message translates to: + /// **'Borrower'** + String get loanTrackingFieldBorrower; + + /// No description provided for @loanTrackingFieldContact. + /// + /// In en, this message translates to: + /// **'Contact'** + String get loanTrackingFieldContact; + + /// No description provided for @loanTrackingFieldLoaned. + /// + /// In en, this message translates to: + /// **'Loaned'** + String get loanTrackingFieldLoaned; + + /// No description provided for @loanTrackingFieldDue. + /// + /// In en, this message translates to: + /// **'Due'** + String get loanTrackingFieldDue; + + /// No description provided for @loanTrackingFieldReturned. + /// + /// In en, this message translates to: + /// **'Returned'** + String get loanTrackingFieldReturned; + + /// No description provided for @loanTrackingStatusReturned. + /// + /// In en, this message translates to: + /// **'Returned'** + String get loanTrackingStatusReturned; + + /// No description provided for @loanTrackingStatusOverdue. + /// + /// In en, this message translates to: + /// **'Overdue'** + String get loanTrackingStatusOverdue; + + /// No description provided for @loanTrackingStatusActive. + /// + /// In en, this message translates to: + /// **'Active'** + String get loanTrackingStatusActive; + + /// No description provided for @loanTrackingCreateTitle. + /// + /// In en, this message translates to: + /// **'Create Loan'** + String get loanTrackingCreateTitle; + + /// No description provided for @loanTrackingCreateDescription. + /// + /// In en, this message translates to: + /// **'Track who borrowed an item and when it should be returned.'** + String get loanTrackingCreateDescription; + + /// No description provided for @loanTrackingCreateNoItemsTitle. + /// + /// In en, this message translates to: + /// **'No available items'** + String get loanTrackingCreateNoItemsTitle; + + /// No description provided for @loanTrackingCreateNoItemsMessage. + /// + /// In en, this message translates to: + /// **'All items are currently loaned or there are no items yet.'** + String get loanTrackingCreateNoItemsMessage; + + /// No description provided for @loanTrackingCreateItemLabel. + /// + /// In en, this message translates to: + /// **'Item'** + String get loanTrackingCreateItemLabel; + + /// No description provided for @loanTrackingCreateBorrowerLabel. + /// + /// In en, this message translates to: + /// **'Borrower name'** + String get loanTrackingCreateBorrowerLabel; + + /// No description provided for @loanTrackingCreateBorrowerHint. + /// + /// In en, this message translates to: + /// **'e.g. John Doe'** + String get loanTrackingCreateBorrowerHint; + + /// No description provided for @loanTrackingCreateContactLabel. + /// + /// In en, this message translates to: + /// **'Contact (optional)'** + String get loanTrackingCreateContactLabel; + + /// No description provided for @loanTrackingCreateContactHint. + /// + /// In en, this message translates to: + /// **'Phone, email, or @username'** + String get loanTrackingCreateContactHint; + + /// No description provided for @loanTrackingCreateNotesLabel. + /// + /// In en, this message translates to: + /// **'Notes (optional)'** + String get loanTrackingCreateNotesLabel; + + /// No description provided for @loanTrackingCreateNotesHint. + /// + /// In en, this message translates to: + /// **'Extra details for this loan'** + String get loanTrackingCreateNotesHint; + + /// No description provided for @loanTrackingCreateSubmitting. + /// + /// In en, this message translates to: + /// **'Creating...'** + String get loanTrackingCreateSubmitting; + + /// No description provided for @loanTrackingCreateAction. + /// + /// In en, this message translates to: + /// **'Create Loan'** + String get loanTrackingCreateAction; + + /// No description provided for @loanTrackingLoadingItems. + /// + /// In en, this message translates to: + /// **'Loading items...'** + String get loanTrackingLoadingItems; + + /// No description provided for @loanTrackingLoadItemsFailed. + /// + /// In en, this message translates to: + /// **'Failed to load items: {error}'** + String loanTrackingLoadItemsFailed(String error); + + /// No description provided for @loanTrackingBorrowerRequired. + /// + /// In en, this message translates to: + /// **'Borrower name is required.'** + String get loanTrackingBorrowerRequired; + + /// No description provided for @loanTrackingCreateSuccess. + /// + /// In en, this message translates to: + /// **'Loan created successfully.'** + String get loanTrackingCreateSuccess; + + /// No description provided for @loanTrackingCreateFailed. + /// + /// In en, this message translates to: + /// **'Failed to create loan: {error}'** + String loanTrackingCreateFailed(String error); + + /// No description provided for @loanTrackingNoDueDate. + /// + /// In en, this message translates to: + /// **'No due date'** + String get loanTrackingNoDueDate; + + /// No description provided for @loanTrackingPickDateAction. + /// + /// In en, this message translates to: + /// **'Pick'** + String get loanTrackingPickDateAction; + + /// No description provided for @loanTrackingClearDateAction. + /// + /// In en, this message translates to: + /// **'Clear'** + String get loanTrackingClearDateAction; + + /// No description provided for @loanTrackingDueDateLabel. + /// + /// In en, this message translates to: + /// **'Due date'** + String get loanTrackingDueDateLabel; } class _AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/apps/mobile/lib/l10n/gen/app_localizations_en.dart b/apps/mobile/lib/l10n/gen/app_localizations_en.dart index 86bd57d..0941898 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_en.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_en.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsEn extends AppLocalizations { @override String get collectionTypeCustom => 'Custom'; + + @override + String get loanTrackingTitle => 'Loan Tracking'; + + @override + String get loanTrackingNewLoan => 'New Loan'; + + @override + String get loanTrackingFilterActive => 'Active'; + + @override + String get loanTrackingFilterHistory => 'History'; + + @override + String get loanTrackingEmptyHistoryTitle => 'No returned loans yet'; + + @override + String get loanTrackingEmptyHistoryMessage => 'Returned items will appear here.'; + + @override + String get loanTrackingEmptyActiveTitle => 'No active loans'; + + @override + String get loanTrackingEmptyActiveMessage => 'Create a loan to start tracking borrowed items.'; + + @override + String get loanTrackingLoadingLoans => 'Loading loans...'; + + @override + String loanTrackingLoadFailed(String error) { + return 'Failed to load loans: $error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => 'Mark as returned?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return 'Confirm return for \"$itemTitle\".'; + } + + @override + String get loanTrackingMarkReturnedAction => 'Mark Returned'; + + @override + String get loanTrackingMarkedReturnedSuccess => 'Loan marked as returned.'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return 'Failed to mark return: $error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => 'Delete loan record?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return 'Delete loan record for \"$itemTitle\".'; + } + + @override + String get loanTrackingDeleteSuccess => 'Loan deleted.'; + + @override + String loanTrackingDeleteFailed(String error) { + return 'Failed to delete loan: $error'; + } + + @override + String get loanTrackingSummaryActiveLabel => 'Active Loans'; + + @override + String get loanTrackingSummaryOverdueLabel => 'Overdue'; + + @override + String get loanTrackingSummaryLoadFailed => 'Unable to load loan summary.'; + + @override + String get loanTrackingFieldBorrower => 'Borrower'; + + @override + String get loanTrackingFieldContact => 'Contact'; + + @override + String get loanTrackingFieldLoaned => 'Loaned'; + + @override + String get loanTrackingFieldDue => 'Due'; + + @override + String get loanTrackingFieldReturned => 'Returned'; + + @override + String get loanTrackingStatusReturned => 'Returned'; + + @override + String get loanTrackingStatusOverdue => 'Overdue'; + + @override + String get loanTrackingStatusActive => 'Active'; + + @override + String get loanTrackingCreateTitle => 'Create Loan'; + + @override + String get loanTrackingCreateDescription => 'Track who borrowed an item and when it should be returned.'; + + @override + String get loanTrackingCreateNoItemsTitle => 'No available items'; + + @override + String get loanTrackingCreateNoItemsMessage => 'All items are currently loaned or there are no items yet.'; + + @override + String get loanTrackingCreateItemLabel => 'Item'; + + @override + String get loanTrackingCreateBorrowerLabel => 'Borrower name'; + + @override + String get loanTrackingCreateBorrowerHint => 'e.g. John Doe'; + + @override + String get loanTrackingCreateContactLabel => 'Contact (optional)'; + + @override + String get loanTrackingCreateContactHint => 'Phone, email, or @username'; + + @override + String get loanTrackingCreateNotesLabel => 'Notes (optional)'; + + @override + String get loanTrackingCreateNotesHint => 'Extra details for this loan'; + + @override + String get loanTrackingCreateSubmitting => 'Creating...'; + + @override + String get loanTrackingCreateAction => 'Create Loan'; + + @override + String get loanTrackingLoadingItems => 'Loading items...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return 'Failed to load items: $error'; + } + + @override + String get loanTrackingBorrowerRequired => 'Borrower name is required.'; + + @override + String get loanTrackingCreateSuccess => 'Loan created successfully.'; + + @override + String loanTrackingCreateFailed(String error) { + return 'Failed to create loan: $error'; + } + + @override + String get loanTrackingNoDueDate => 'No due date'; + + @override + String get loanTrackingPickDateAction => 'Pick'; + + @override + String get loanTrackingClearDateAction => 'Clear'; + + @override + String get loanTrackingDueDateLabel => 'Due date'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_es.dart b/apps/mobile/lib/l10n/gen/app_localizations_es.dart index e61f831..7afb738 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_es.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_es.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsEs extends AppLocalizations { @override String get collectionTypeCustom => 'Personalizada'; + + @override + String get loanTrackingTitle => 'Seguimiento de préstamos'; + + @override + String get loanTrackingNewLoan => 'Nuevo préstamo'; + + @override + String get loanTrackingFilterActive => 'Activos'; + + @override + String get loanTrackingFilterHistory => 'Historial'; + + @override + String get loanTrackingEmptyHistoryTitle => 'Aún no hay préstamos devueltos'; + + @override + String get loanTrackingEmptyHistoryMessage => 'Los artículos devueltos aparecerán aquí.'; + + @override + String get loanTrackingEmptyActiveTitle => 'No hay préstamos activos'; + + @override + String get loanTrackingEmptyActiveMessage => 'Crea un préstamo para empezar a seguir artículos prestados.'; + + @override + String get loanTrackingLoadingLoans => 'Cargando préstamos...'; + + @override + String loanTrackingLoadFailed(String error) { + return 'No se pudieron cargar los préstamos: $error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => '¿Marcar como devuelto?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return 'Confirmar devolución de \"$itemTitle\".'; + } + + @override + String get loanTrackingMarkReturnedAction => 'Marcar devuelto'; + + @override + String get loanTrackingMarkedReturnedSuccess => 'El préstamo se marcó como devuelto.'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return 'No se pudo marcar la devolución: $error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => '¿Eliminar registro del préstamo?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return 'Eliminar registro del préstamo de \"$itemTitle\".'; + } + + @override + String get loanTrackingDeleteSuccess => 'Préstamo eliminado.'; + + @override + String loanTrackingDeleteFailed(String error) { + return 'No se pudo eliminar el préstamo: $error'; + } + + @override + String get loanTrackingSummaryActiveLabel => 'Préstamos activos'; + + @override + String get loanTrackingSummaryOverdueLabel => 'Vencidos'; + + @override + String get loanTrackingSummaryLoadFailed => 'No se pudo cargar el resumen de préstamos.'; + + @override + String get loanTrackingFieldBorrower => 'Prestatario'; + + @override + String get loanTrackingFieldContact => 'Contacto'; + + @override + String get loanTrackingFieldLoaned => 'Prestado'; + + @override + String get loanTrackingFieldDue => 'Vence'; + + @override + String get loanTrackingFieldReturned => 'Devuelto'; + + @override + String get loanTrackingStatusReturned => 'Devuelto'; + + @override + String get loanTrackingStatusOverdue => 'Vencido'; + + @override + String get loanTrackingStatusActive => 'Activo'; + + @override + String get loanTrackingCreateTitle => 'Crear préstamo'; + + @override + String get loanTrackingCreateDescription => 'Registra quién tomó un artículo prestado y cuándo debe devolverlo.'; + + @override + String get loanTrackingCreateNoItemsTitle => 'No hay artículos disponibles'; + + @override + String get loanTrackingCreateNoItemsMessage => 'Todos los artículos están prestados actualmente o aún no hay artículos.'; + + @override + String get loanTrackingCreateItemLabel => 'Artículo'; + + @override + String get loanTrackingCreateBorrowerLabel => 'Nombre del prestatario'; + + @override + String get loanTrackingCreateBorrowerHint => 'p. ej. Juan Pérez'; + + @override + String get loanTrackingCreateContactLabel => 'Contacto (opcional)'; + + @override + String get loanTrackingCreateContactHint => 'Teléfono, correo o @usuario'; + + @override + String get loanTrackingCreateNotesLabel => 'Notas (opcional)'; + + @override + String get loanTrackingCreateNotesHint => 'Detalles adicionales para este préstamo'; + + @override + String get loanTrackingCreateSubmitting => 'Creando...'; + + @override + String get loanTrackingCreateAction => 'Crear préstamo'; + + @override + String get loanTrackingLoadingItems => 'Cargando artículos...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return 'No se pudieron cargar los artículos: $error'; + } + + @override + String get loanTrackingBorrowerRequired => 'El nombre del prestatario es obligatorio.'; + + @override + String get loanTrackingCreateSuccess => 'Préstamo creado correctamente.'; + + @override + String loanTrackingCreateFailed(String error) { + return 'No se pudo crear el préstamo: $error'; + } + + @override + String get loanTrackingNoDueDate => 'Sin fecha de vencimiento'; + + @override + String get loanTrackingPickDateAction => 'Elegir'; + + @override + String get loanTrackingClearDateAction => 'Limpiar'; + + @override + String get loanTrackingDueDateLabel => 'Fecha de vencimiento'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_id.dart b/apps/mobile/lib/l10n/gen/app_localizations_id.dart index 3ec4e6f..865af51 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_id.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_id.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsId extends AppLocalizations { @override String get collectionTypeCustom => 'Kustom'; + + @override + String get loanTrackingTitle => 'Pelacakan Pinjaman'; + + @override + String get loanTrackingNewLoan => 'Pinjaman Baru'; + + @override + String get loanTrackingFilterActive => 'Aktif'; + + @override + String get loanTrackingFilterHistory => 'Riwayat'; + + @override + String get loanTrackingEmptyHistoryTitle => 'Belum ada pinjaman yang dikembalikan'; + + @override + String get loanTrackingEmptyHistoryMessage => 'Item yang sudah dikembalikan akan muncul di sini.'; + + @override + String get loanTrackingEmptyActiveTitle => 'Tidak ada pinjaman aktif'; + + @override + String get loanTrackingEmptyActiveMessage => 'Buat pinjaman untuk mulai melacak item yang dipinjam.'; + + @override + String get loanTrackingLoadingLoans => 'Memuat pinjaman...'; + + @override + String loanTrackingLoadFailed(String error) { + return 'Gagal memuat pinjaman: $error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => 'Tandai sudah dikembalikan?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return 'Konfirmasi pengembalian untuk \"$itemTitle\".'; + } + + @override + String get loanTrackingMarkReturnedAction => 'Tandai Dikembalikan'; + + @override + String get loanTrackingMarkedReturnedSuccess => 'Pinjaman ditandai sudah dikembalikan.'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return 'Gagal menandai pengembalian: $error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => 'Hapus catatan pinjaman?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return 'Hapus catatan pinjaman untuk \"$itemTitle\".'; + } + + @override + String get loanTrackingDeleteSuccess => 'Pinjaman dihapus.'; + + @override + String loanTrackingDeleteFailed(String error) { + return 'Gagal menghapus pinjaman: $error'; + } + + @override + String get loanTrackingSummaryActiveLabel => 'Pinjaman Aktif'; + + @override + String get loanTrackingSummaryOverdueLabel => 'Terlambat'; + + @override + String get loanTrackingSummaryLoadFailed => 'Tidak dapat memuat ringkasan pinjaman.'; + + @override + String get loanTrackingFieldBorrower => 'Peminjam'; + + @override + String get loanTrackingFieldContact => 'Kontak'; + + @override + String get loanTrackingFieldLoaned => 'Dipinjamkan'; + + @override + String get loanTrackingFieldDue => 'Jatuh tempo'; + + @override + String get loanTrackingFieldReturned => 'Dikembalikan'; + + @override + String get loanTrackingStatusReturned => 'Dikembalikan'; + + @override + String get loanTrackingStatusOverdue => 'Terlambat'; + + @override + String get loanTrackingStatusActive => 'Aktif'; + + @override + String get loanTrackingCreateTitle => 'Buat Pinjaman'; + + @override + String get loanTrackingCreateDescription => 'Lacak siapa yang meminjam item dan kapan harus dikembalikan.'; + + @override + String get loanTrackingCreateNoItemsTitle => 'Tidak ada item yang tersedia'; + + @override + String get loanTrackingCreateNoItemsMessage => 'Semua item sedang dipinjam atau belum ada item.'; + + @override + String get loanTrackingCreateItemLabel => 'Item'; + + @override + String get loanTrackingCreateBorrowerLabel => 'Nama peminjam'; + + @override + String get loanTrackingCreateBorrowerHint => 'mis. Budi Santoso'; + + @override + String get loanTrackingCreateContactLabel => 'Kontak (opsional)'; + + @override + String get loanTrackingCreateContactHint => 'Telepon, email, atau @username'; + + @override + String get loanTrackingCreateNotesLabel => 'Catatan (opsional)'; + + @override + String get loanTrackingCreateNotesHint => 'Detail tambahan untuk pinjaman ini'; + + @override + String get loanTrackingCreateSubmitting => 'Membuat...'; + + @override + String get loanTrackingCreateAction => 'Buat Pinjaman'; + + @override + String get loanTrackingLoadingItems => 'Memuat item...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return 'Gagal memuat item: $error'; + } + + @override + String get loanTrackingBorrowerRequired => 'Nama peminjam wajib diisi.'; + + @override + String get loanTrackingCreateSuccess => 'Pinjaman berhasil dibuat.'; + + @override + String loanTrackingCreateFailed(String error) { + return 'Gagal membuat pinjaman: $error'; + } + + @override + String get loanTrackingNoDueDate => 'Tanpa tanggal jatuh tempo'; + + @override + String get loanTrackingPickDateAction => 'Pilih'; + + @override + String get loanTrackingClearDateAction => 'Hapus'; + + @override + String get loanTrackingDueDateLabel => 'Tanggal jatuh tempo'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart index 04c9632..2aa7691 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsJa extends AppLocalizations { @override String get collectionTypeCustom => 'カスタム'; + + @override + String get loanTrackingTitle => '貸出管理'; + + @override + String get loanTrackingNewLoan => '新しい貸出'; + + @override + String get loanTrackingFilterActive => 'アクティブ'; + + @override + String get loanTrackingFilterHistory => '履歴'; + + @override + String get loanTrackingEmptyHistoryTitle => '返却済みの貸出はまだありません'; + + @override + String get loanTrackingEmptyHistoryMessage => '返却されたアイテムはここに表示されます。'; + + @override + String get loanTrackingEmptyActiveTitle => 'アクティブな貸出はありません'; + + @override + String get loanTrackingEmptyActiveMessage => '貸出を作成して、借りられたアイテムの管理を始めましょう。'; + + @override + String get loanTrackingLoadingLoans => '貸出を読み込み中...'; + + @override + String loanTrackingLoadFailed(String error) { + return '貸出の読み込みに失敗しました: $error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => '返却済みにしますか?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return '\"$itemTitle\" の返却を確認します。'; + } + + @override + String get loanTrackingMarkReturnedAction => '返却済みにする'; + + @override + String get loanTrackingMarkedReturnedSuccess => '貸出を返却済みにしました。'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return '返却の更新に失敗しました: $error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => '貸出記録を削除しますか?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return '\"$itemTitle\" の貸出記録を削除します。'; + } + + @override + String get loanTrackingDeleteSuccess => '貸出記録を削除しました。'; + + @override + String loanTrackingDeleteFailed(String error) { + return '貸出の削除に失敗しました: $error'; + } + + @override + String get loanTrackingSummaryActiveLabel => 'アクティブな貸出'; + + @override + String get loanTrackingSummaryOverdueLabel => '期限超過'; + + @override + String get loanTrackingSummaryLoadFailed => '貸出サマリーを読み込めませんでした。'; + + @override + String get loanTrackingFieldBorrower => '借り手'; + + @override + String get loanTrackingFieldContact => '連絡先'; + + @override + String get loanTrackingFieldLoaned => '貸出日'; + + @override + String get loanTrackingFieldDue => '返却期限'; + + @override + String get loanTrackingFieldReturned => '返却日'; + + @override + String get loanTrackingStatusReturned => '返却済み'; + + @override + String get loanTrackingStatusOverdue => '期限超過'; + + @override + String get loanTrackingStatusActive => 'アクティブ'; + + @override + String get loanTrackingCreateTitle => '貸出を作成'; + + @override + String get loanTrackingCreateDescription => '誰がアイテムを借りたか、いつ返却予定かを記録します。'; + + @override + String get loanTrackingCreateNoItemsTitle => '利用可能なアイテムがありません'; + + @override + String get loanTrackingCreateNoItemsMessage => 'すべて貸出中か、まだアイテムがありません。'; + + @override + String get loanTrackingCreateItemLabel => 'アイテム'; + + @override + String get loanTrackingCreateBorrowerLabel => '借り手の名前'; + + @override + String get loanTrackingCreateBorrowerHint => '例: 山田 太郎'; + + @override + String get loanTrackingCreateContactLabel => '連絡先(任意)'; + + @override + String get loanTrackingCreateContactHint => '電話、メール、または @username'; + + @override + String get loanTrackingCreateNotesLabel => 'メモ(任意)'; + + @override + String get loanTrackingCreateNotesHint => 'この貸出の追加情報'; + + @override + String get loanTrackingCreateSubmitting => '作成中...'; + + @override + String get loanTrackingCreateAction => '貸出を作成'; + + @override + String get loanTrackingLoadingItems => 'アイテムを読み込み中...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return 'アイテムの読み込みに失敗しました: $error'; + } + + @override + String get loanTrackingBorrowerRequired => '借り手の名前は必須です。'; + + @override + String get loanTrackingCreateSuccess => '貸出を作成しました。'; + + @override + String loanTrackingCreateFailed(String error) { + return '貸出の作成に失敗しました: $error'; + } + + @override + String get loanTrackingNoDueDate => '返却期限なし'; + + @override + String get loanTrackingPickDateAction => '選択'; + + @override + String get loanTrackingClearDateAction => 'クリア'; + + @override + String get loanTrackingDueDateLabel => '返却期限'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart index 13f238f..c3df1b3 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsKo extends AppLocalizations { @override String get collectionTypeCustom => '사용자 지정'; + + @override + String get loanTrackingTitle => '대여 추적'; + + @override + String get loanTrackingNewLoan => '새 대여'; + + @override + String get loanTrackingFilterActive => '활성'; + + @override + String get loanTrackingFilterHistory => '기록'; + + @override + String get loanTrackingEmptyHistoryTitle => '아직 반납된 대여가 없습니다'; + + @override + String get loanTrackingEmptyHistoryMessage => '반납된 항목이 여기에 표시됩니다.'; + + @override + String get loanTrackingEmptyActiveTitle => '활성 대여가 없습니다'; + + @override + String get loanTrackingEmptyActiveMessage => '대여를 생성해 빌려준 항목을 추적해 보세요.'; + + @override + String get loanTrackingLoadingLoans => '대여 불러오는 중...'; + + @override + String loanTrackingLoadFailed(String error) { + return '대여를 불러오지 못했습니다: $error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => '반납으로 표시할까요?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return '\"$itemTitle\" 반납을 확인합니다.'; + } + + @override + String get loanTrackingMarkReturnedAction => '반납 처리'; + + @override + String get loanTrackingMarkedReturnedSuccess => '대여가 반납 처리되었습니다.'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return '반납 처리에 실패했습니다: $error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => '대여 기록을 삭제할까요?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return '\"$itemTitle\" 대여 기록을 삭제합니다.'; + } + + @override + String get loanTrackingDeleteSuccess => '대여가 삭제되었습니다.'; + + @override + String loanTrackingDeleteFailed(String error) { + return '대여 삭제에 실패했습니다: $error'; + } + + @override + String get loanTrackingSummaryActiveLabel => '활성 대여'; + + @override + String get loanTrackingSummaryOverdueLabel => '연체'; + + @override + String get loanTrackingSummaryLoadFailed => '대여 요약을 불러올 수 없습니다.'; + + @override + String get loanTrackingFieldBorrower => '대여자'; + + @override + String get loanTrackingFieldContact => '연락처'; + + @override + String get loanTrackingFieldLoaned => '대여일'; + + @override + String get loanTrackingFieldDue => '반납 예정일'; + + @override + String get loanTrackingFieldReturned => '반납일'; + + @override + String get loanTrackingStatusReturned => '반납됨'; + + @override + String get loanTrackingStatusOverdue => '연체'; + + @override + String get loanTrackingStatusActive => '활성'; + + @override + String get loanTrackingCreateTitle => '대여 생성'; + + @override + String get loanTrackingCreateDescription => '누가 항목을 빌렸는지와 반납 예정일을 추적합니다.'; + + @override + String get loanTrackingCreateNoItemsTitle => '사용 가능한 항목이 없습니다'; + + @override + String get loanTrackingCreateNoItemsMessage => '모든 항목이 이미 대여 중이거나 아직 항목이 없습니다.'; + + @override + String get loanTrackingCreateItemLabel => '항목'; + + @override + String get loanTrackingCreateBorrowerLabel => '대여자 이름'; + + @override + String get loanTrackingCreateBorrowerHint => '예: 홍길동'; + + @override + String get loanTrackingCreateContactLabel => '연락처 (선택)'; + + @override + String get loanTrackingCreateContactHint => '전화번호, 이메일 또는 @username'; + + @override + String get loanTrackingCreateNotesLabel => '메모 (선택)'; + + @override + String get loanTrackingCreateNotesHint => '이 대여에 대한 추가 정보'; + + @override + String get loanTrackingCreateSubmitting => '생성 중...'; + + @override + String get loanTrackingCreateAction => '대여 생성'; + + @override + String get loanTrackingLoadingItems => '항목 불러오는 중...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return '항목을 불러오지 못했습니다: $error'; + } + + @override + String get loanTrackingBorrowerRequired => '대여자 이름은 필수입니다.'; + + @override + String get loanTrackingCreateSuccess => '대여가 생성되었습니다.'; + + @override + String loanTrackingCreateFailed(String error) { + return '대여 생성에 실패했습니다: $error'; + } + + @override + String get loanTrackingNoDueDate => '반납 예정일 없음'; + + @override + String get loanTrackingPickDateAction => '선택'; + + @override + String get loanTrackingClearDateAction => '지우기'; + + @override + String get loanTrackingDueDateLabel => '반납 예정일'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_my.dart b/apps/mobile/lib/l10n/gen/app_localizations_my.dart index f2f6766..4b88bac 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_my.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_my.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsMy extends AppLocalizations { @override String get collectionTypeCustom => 'စိတ်ကြိုက်'; + + @override + String get loanTrackingTitle => 'ငှားရမ်းမှု ခြေရာခံ'; + + @override + String get loanTrackingNewLoan => 'ငှားရမ်းမှု အသစ်'; + + @override + String get loanTrackingFilterActive => 'လက်ရှိ'; + + @override + String get loanTrackingFilterHistory => 'မှတ်တမ်း'; + + @override + String get loanTrackingEmptyHistoryTitle => 'ပြန်အပ်ပြီး ငှားရမ်းမှု မရှိသေးပါ'; + + @override + String get loanTrackingEmptyHistoryMessage => 'ပြန်အပ်ပြီး ပစ္စည်းများကို ဒီနေရာတွင် ပြပါမည်။'; + + @override + String get loanTrackingEmptyActiveTitle => 'လက်ရှိ ငှားရမ်းမှု မရှိပါ'; + + @override + String get loanTrackingEmptyActiveMessage => 'ငှားသွားသော ပစ္စည်းများကို ခြေရာခံရန် ငှားရမ်းမှု အသစ် ဖန်တီးပါ။'; + + @override + String get loanTrackingLoadingLoans => 'ငှားရမ်းမှုများ တင်နေသည်...'; + + @override + String loanTrackingLoadFailed(String error) { + return 'ငှားရမ်းမှုများ တင်မရပါ: $error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => 'ပြန်အပ်ပြီးဟု မှတ်မလား?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return '\"$itemTitle\" ကို ပြန်အပ်ပြီးဟု အတည်ပြုမည်။'; + } + + @override + String get loanTrackingMarkReturnedAction => 'ပြန်အပ်ပြီး မှတ်မည်'; + + @override + String get loanTrackingMarkedReturnedSuccess => 'ငှားရမ်းမှုကို ပြန်အပ်ပြီးအဖြစ် မှတ်သားပြီးပါပြီ။'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return 'ပြန်အပ်ပြီး မှတ်မရပါ: $error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => 'ငှားရမ်းမှု မှတ်တမ်း ဖျက်မလား?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return '\"$itemTitle\" အတွက် ငှားရမ်းမှု မှတ်တမ်းကို ဖျက်မည်။'; + } + + @override + String get loanTrackingDeleteSuccess => 'ငှားရမ်းမှုကို ဖျက်ပြီးပါပြီ။'; + + @override + String loanTrackingDeleteFailed(String error) { + return 'ငှားရမ်းမှု ဖျက်မရပါ: $error'; + } + + @override + String get loanTrackingSummaryActiveLabel => 'လက်ရှိ ငှားရမ်းမှု'; + + @override + String get loanTrackingSummaryOverdueLabel => 'ကျော်လွန်'; + + @override + String get loanTrackingSummaryLoadFailed => 'ငှားရမ်းမှု အနှစ်ချုပ် တင်မရပါ။'; + + @override + String get loanTrackingFieldBorrower => 'ငှားယူသူ'; + + @override + String get loanTrackingFieldContact => 'ဆက်သွယ်ရန်'; + + @override + String get loanTrackingFieldLoaned => 'ငှားသည့်နေ့'; + + @override + String get loanTrackingFieldDue => 'ပြန်အပ်ရမည့်နေ့'; + + @override + String get loanTrackingFieldReturned => 'ပြန်အပ်သည့်နေ့'; + + @override + String get loanTrackingStatusReturned => 'ပြန်အပ်ပြီး'; + + @override + String get loanTrackingStatusOverdue => 'ကျော်လွန်'; + + @override + String get loanTrackingStatusActive => 'လက်ရှိ'; + + @override + String get loanTrackingCreateTitle => 'ငှားရမ်းမှု ဖန်တီး'; + + @override + String get loanTrackingCreateDescription => 'ဘယ်သူငှားယူသွားသည်နှင့် ဘယ်နေ့ ပြန်အပ်ရမည်ကို မှတ်တမ်းတင်ပါ။'; + + @override + String get loanTrackingCreateNoItemsTitle => 'အသုံးပြုနိုင်သော ပစ္စည်း မရှိပါ'; + + @override + String get loanTrackingCreateNoItemsMessage => 'ပစ္စည်းအားလုံး ငှားထားပြီး သို့မဟုတ် ပစ္စည်းမရှိသေးပါ။'; + + @override + String get loanTrackingCreateItemLabel => 'ပစ္စည်း'; + + @override + String get loanTrackingCreateBorrowerLabel => 'ငှားယူသူ အမည်'; + + @override + String get loanTrackingCreateBorrowerHint => 'ဥပမာ - Aung Aung'; + + @override + String get loanTrackingCreateContactLabel => 'ဆက်သွယ်ရန် (မဖြည့်လည်းရ)'; + + @override + String get loanTrackingCreateContactHint => 'ဖုန်း၊ အီးမေးလ် သို့မဟုတ် @username'; + + @override + String get loanTrackingCreateNotesLabel => 'မှတ်စု (မဖြည့်လည်းရ)'; + + @override + String get loanTrackingCreateNotesHint => 'ဒီငှားရမ်းမှုအတွက် အသေးစိတ်'; + + @override + String get loanTrackingCreateSubmitting => 'ဖန်တီးနေသည်...'; + + @override + String get loanTrackingCreateAction => 'ငှားရမ်းမှု ဖန်တီး'; + + @override + String get loanTrackingLoadingItems => 'ပစ္စည်းများ တင်နေသည်...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return 'ပစ္စည်းများ တင်မရပါ: $error'; + } + + @override + String get loanTrackingBorrowerRequired => 'ငှားယူသူ အမည် မဖြစ်မနေလိုအပ်သည်။'; + + @override + String get loanTrackingCreateSuccess => 'ငှားရမ်းမှု အောင်မြင်စွာ ဖန်တီးပြီးပါပြီ။'; + + @override + String loanTrackingCreateFailed(String error) { + return 'ငှားရမ်းမှု ဖန်တီးမရပါ: $error'; + } + + @override + String get loanTrackingNoDueDate => 'ပြန်အပ်ရမည့်နေ့ မသတ်မှတ်ထားပါ'; + + @override + String get loanTrackingPickDateAction => 'ရွေးမည်'; + + @override + String get loanTrackingClearDateAction => 'ရှင်းမည်'; + + @override + String get loanTrackingDueDateLabel => 'ပြန်အပ်ရမည့်နေ့'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart index cd06a73..586b0a4 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart @@ -1070,4 +1070,174 @@ class AppLocalizationsZh extends AppLocalizations { @override String get collectionTypeCustom => '自定义'; + + @override + String get loanTrackingTitle => '借出追踪'; + + @override + String get loanTrackingNewLoan => '新建借出'; + + @override + String get loanTrackingFilterActive => '进行中'; + + @override + String get loanTrackingFilterHistory => '历史'; + + @override + String get loanTrackingEmptyHistoryTitle => '暂无已归还借出'; + + @override + String get loanTrackingEmptyHistoryMessage => '已归还条目会显示在这里。'; + + @override + String get loanTrackingEmptyActiveTitle => '暂无进行中借出'; + + @override + String get loanTrackingEmptyActiveMessage => '创建一条借出记录来跟踪借出物品。'; + + @override + String get loanTrackingLoadingLoans => '正在加载借出记录...'; + + @override + String loanTrackingLoadFailed(String error) { + return '加载借出记录失败:$error'; + } + + @override + String get loanTrackingMarkReturnedConfirmTitle => '标记为已归还?'; + + @override + String loanTrackingMarkReturnedConfirmMessage(String itemTitle) { + return '确认「$itemTitle」已归还。'; + } + + @override + String get loanTrackingMarkReturnedAction => '标记已归还'; + + @override + String get loanTrackingMarkedReturnedSuccess => '借出已标记为归还。'; + + @override + String loanTrackingMarkReturnedFailed(String error) { + return '标记归还失败:$error'; + } + + @override + String get loanTrackingDeleteConfirmTitle => '删除借出记录?'; + + @override + String loanTrackingDeleteConfirmMessage(String itemTitle) { + return '删除「$itemTitle」的借出记录。'; + } + + @override + String get loanTrackingDeleteSuccess => '借出记录已删除。'; + + @override + String loanTrackingDeleteFailed(String error) { + return '删除借出记录失败:$error'; + } + + @override + String get loanTrackingSummaryActiveLabel => '进行中借出'; + + @override + String get loanTrackingSummaryOverdueLabel => '逾期'; + + @override + String get loanTrackingSummaryLoadFailed => '无法加载借出摘要。'; + + @override + String get loanTrackingFieldBorrower => '借用人'; + + @override + String get loanTrackingFieldContact => '联系方式'; + + @override + String get loanTrackingFieldLoaned => '借出日期'; + + @override + String get loanTrackingFieldDue => '到期日期'; + + @override + String get loanTrackingFieldReturned => '归还日期'; + + @override + String get loanTrackingStatusReturned => '已归还'; + + @override + String get loanTrackingStatusOverdue => '逾期'; + + @override + String get loanTrackingStatusActive => '进行中'; + + @override + String get loanTrackingCreateTitle => '创建借出'; + + @override + String get loanTrackingCreateDescription => '记录谁借走了物品以及应归还时间。'; + + @override + String get loanTrackingCreateNoItemsTitle => '暂无可借出条目'; + + @override + String get loanTrackingCreateNoItemsMessage => '所有条目都在借出中,或还没有条目。'; + + @override + String get loanTrackingCreateItemLabel => '条目'; + + @override + String get loanTrackingCreateBorrowerLabel => '借用人姓名'; + + @override + String get loanTrackingCreateBorrowerHint => '例如:张三'; + + @override + String get loanTrackingCreateContactLabel => '联系方式(可选)'; + + @override + String get loanTrackingCreateContactHint => '电话、邮箱或 @username'; + + @override + String get loanTrackingCreateNotesLabel => '备注(可选)'; + + @override + String get loanTrackingCreateNotesHint => '这次借出的额外说明'; + + @override + String get loanTrackingCreateSubmitting => '创建中...'; + + @override + String get loanTrackingCreateAction => '创建借出'; + + @override + String get loanTrackingLoadingItems => '正在加载条目...'; + + @override + String loanTrackingLoadItemsFailed(String error) { + return '加载条目失败:$error'; + } + + @override + String get loanTrackingBorrowerRequired => '借用人姓名不能为空。'; + + @override + String get loanTrackingCreateSuccess => '借出创建成功。'; + + @override + String loanTrackingCreateFailed(String error) { + return '创建借出失败:$error'; + } + + @override + String get loanTrackingNoDueDate => '无到期日期'; + + @override + String get loanTrackingPickDateAction => '选择'; + + @override + String get loanTrackingClearDateAction => '清除'; + + @override + String get loanTrackingDueDateLabel => '到期日期'; } From b1da3db9b01716a3e42898fc2742805c06467f40 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 14:44:24 +0630 Subject: [PATCH 03/16] feat: Implement synchronization for loan entities across the app and data layers. --- .../observability/operational_telemetry.dart | 16 +++- .../lib/core/providers/data_providers.dart | 5 +- .../lib/core/providers/sync_providers.dart | 2 + .../core/sync/sync_auto_retry_on_resume.dart | 3 + .../lib/core/sync/sync_orchestrator.dart | 92 +++++++++++++++--- .../core/sync/sync_outbox_bootstrapper.dart | 40 +++++++- .../sync/sync_server_changes_applier.dart | 94 ++++++++++++++++++- .../presentation/views/settings_screen.dart | 3 + .../test/core/sync/sync_resilience_test.dart | 2 + .../repositories/loan_repository_impl.dart | 83 +++++++++++++++- .../database/lib/src/daos/loan_dao.dart | 6 ++ .../lib/src/models/sync_contract.dart | 22 ++++- 12 files changed, 343 insertions(+), 25 deletions(-) diff --git a/apps/mobile/lib/core/observability/operational_telemetry.dart b/apps/mobile/lib/core/observability/operational_telemetry.dart index dcbaa1c..f543b9d 100644 --- a/apps/mobile/lib/core/observability/operational_telemetry.dart +++ b/apps/mobile/lib/core/observability/operational_telemetry.dart @@ -50,13 +50,16 @@ class OperationalTelemetry { required int syncedCollections, required int syncedItems, required int syncedTags, + int syncedLoans = 0, required int conflictCount, required int appliedServerCollections, required int appliedServerItems, required int appliedServerTags, + int appliedServerLoans = 0, required int skippedServerCollections, required int skippedServerItems, required int skippedServerTags, + int skippedServerLoans = 0, String? message, Object? error, StackTrace? stackTrace, @@ -73,13 +76,16 @@ class OperationalTelemetry { 'synced_collections': syncedCollections, 'synced_items': syncedItems, 'synced_tags': syncedTags, + 'synced_loans': syncedLoans, 'conflicts': conflictCount, 'applied_server_collections': appliedServerCollections, 'applied_server_items': appliedServerItems, 'applied_server_tags': appliedServerTags, + 'applied_server_loans': appliedServerLoans, 'skipped_server_collections': skippedServerCollections, 'skipped_server_items': skippedServerItems, 'skipped_server_tags': skippedServerTags, + 'skipped_server_loans': skippedServerLoans, if (message != null && message.trim().isNotEmpty) 'message': message, }, crashlyticsLog: true, @@ -94,9 +100,15 @@ class OperationalTelemetry { 'sync_pending_ops': pendingOperations, 'sync_processed_ops': processedOperations, 'sync_applied_server': - appliedServerCollections + appliedServerItems + appliedServerTags, + appliedServerCollections + + appliedServerItems + + appliedServerTags + + appliedServerLoans, 'sync_skipped_server': - skippedServerCollections + skippedServerItems + skippedServerTags, + skippedServerCollections + + skippedServerItems + + skippedServerTags + + skippedServerLoans, }, ); } diff --git a/apps/mobile/lib/core/providers/data_providers.dart b/apps/mobile/lib/core/providers/data_providers.dart index 2e0faa8..52bfa05 100644 --- a/apps/mobile/lib/core/providers/data_providers.dart +++ b/apps/mobile/lib/core/providers/data_providers.dart @@ -28,5 +28,8 @@ ItemRepository itemRepository(Ref ref) { @riverpod LoanRepository loanRepository(Ref ref) { final dao = ref.watch(loanDaoProvider); - return LoanRepositoryImpl(dao); + final syncDao = ref.watch(syncOutboxWritesEnabledProvider) + ? ref.watch(syncDaoProvider) + : null; + return LoanRepositoryImpl(dao, syncDao: syncDao); } diff --git a/apps/mobile/lib/core/providers/sync_providers.dart b/apps/mobile/lib/core/providers/sync_providers.dart index dca23c6..3fe1d4a 100644 --- a/apps/mobile/lib/core/providers/sync_providers.dart +++ b/apps/mobile/lib/core/providers/sync_providers.dart @@ -253,10 +253,12 @@ final syncOutboxBootstrapperProvider = Provider((ref) { final syncDao = ref.watch(syncDaoProvider); final collectionDao = ref.watch(collectionDaoProvider); final itemDao = ref.watch(itemDaoProvider); + final loanDao = ref.watch(loanDaoProvider); return SyncOutboxBootstrapper( syncDao: syncDao, collectionDao: collectionDao, itemDao: itemDao, + loanDao: loanDao, ); }); diff --git a/apps/mobile/lib/core/sync/sync_auto_retry_on_resume.dart b/apps/mobile/lib/core/sync/sync_auto_retry_on_resume.dart index 745a3c3..3126fe9 100644 --- a/apps/mobile/lib/core/sync/sync_auto_retry_on_resume.dart +++ b/apps/mobile/lib/core/sync/sync_auto_retry_on_resume.dart @@ -98,13 +98,16 @@ class _SyncAutoRetryOnResumeState extends ConsumerState syncedCollections: result.syncedCollections, syncedItems: result.syncedItems, syncedTags: result.syncedTags, + syncedLoans: result.syncedLoans, conflictCount: result.conflictCount, appliedServerCollections: result.appliedServerCollections, appliedServerItems: result.appliedServerItems, appliedServerTags: result.appliedServerTags, + appliedServerLoans: result.appliedServerLoans, skippedServerCollections: result.skippedServerCollections, skippedServerItems: result.skippedServerItems, skippedServerTags: result.skippedServerTags, + skippedServerLoans: result.skippedServerLoans, message: result.message, error: result.error, stackTrace: result.stackTrace, diff --git a/apps/mobile/lib/core/sync/sync_orchestrator.dart b/apps/mobile/lib/core/sync/sync_orchestrator.dart index dc7701a..64a553b 100644 --- a/apps/mobile/lib/core/sync/sync_orchestrator.dart +++ b/apps/mobile/lib/core/sync/sync_orchestrator.dart @@ -16,7 +16,7 @@ typedef SyncTraceRunner = Map? attributes, }); -enum SyncEntityType { collection, item, tag } +enum SyncEntityType { collection, item, tag, loan } enum SyncOperationType { upsert, delete } @@ -32,14 +32,17 @@ class SyncAttemptResult { this.syncedCollections = 0, this.syncedItems = 0, this.syncedTags = 0, + this.syncedLoans = 0, this.conflictCount = 0, this.partial = false, this.appliedServerCollections = 0, this.appliedServerItems = 0, this.appliedServerTags = 0, + this.appliedServerLoans = 0, this.skippedServerCollections = 0, this.skippedServerItems = 0, this.skippedServerTags = 0, + this.skippedServerLoans = 0, }); final bool executed; @@ -52,14 +55,17 @@ class SyncAttemptResult { final int syncedCollections; final int syncedItems; final int syncedTags; + final int syncedLoans; final int conflictCount; final bool partial; final int appliedServerCollections; final int appliedServerItems; final int appliedServerTags; + final int appliedServerLoans; final int skippedServerCollections; final int skippedServerItems; final int skippedServerTags; + final int skippedServerLoans; } class SyncOrchestrator { @@ -141,6 +147,13 @@ class SyncOrchestrator { bool forceFullSync = false, }) async { final pending = await _syncDao.getPendingOperations(limit: _maxBatchSize); + final capability = await _evaluateCapabilities(); + final operationsToSync = capability.loansSupported + ? pending + : pending + .where((op) => op.entityType != SyncEntityType.loan.name) + .toList(growable: false); + final deferredLoanOperationCount = pending.length - operationsToSync.length; if (_backendClient is NoopSyncBackendClient) { final client = _backendClient; @@ -157,9 +170,10 @@ class SyncOrchestrator { await _syncDao.upsertSyncState(lastAttemptedSyncAt: DateTime.now()); - final changes = _buildChangesPayload(pending); + final changes = _buildChangesPayload(operationsToSync); final requestPayload = SyncRequestPayload( deviceId: deviceId, + schemaVersion: capability.schemaVersion, clientRequestId: _uuid.v4(), lastSyncAt: forceFullSync ? null : state?.lastSuccessfulSyncAt, changes: changes.isEmpty ? null : changes, @@ -168,17 +182,17 @@ class SyncOrchestrator { try { final response = await _syncWithRetry( request: requestPayload, - pendingOperationCount: pending.length, + pendingOperationCount: operationsToSync.length, forceFullSync: forceFullSync, ); final processedOperations = _processedOperationCount(response); - if (processedOperations < pending.length) { + if (processedOperations < operationsToSync.length) { final errorText = 'Sync response did not process all operations ' - '(processed: $processedOperations, pending: ${pending.length}).'; + '(processed: $processedOperations, pending: ${operationsToSync.length}).'; - for (final op in pending) { + for (final op in operationsToSync) { await _syncDao.markOperationFailed(op.id, errorText); } @@ -192,7 +206,7 @@ class SyncOrchestrator { success: false, message: 'Sync partially processed. Local queue kept for retry. ' - 'Processed $processedOperations of ${pending.length} change(s).', + 'Processed $processedOperations of ${operationsToSync.length} change(s).', error: errorText, stackTrace: null, pendingOperations: pending.length, @@ -200,6 +214,7 @@ class SyncOrchestrator { syncedCollections: response.syncedCollections, syncedItems: response.syncedItems, syncedTags: response.syncedTags, + syncedLoans: response.syncedLoans, conflictCount: response.conflicts.length, partial: true, ); @@ -209,7 +224,7 @@ class SyncOrchestrator { response.serverChanges, ); - for (final op in pending) { + for (final op in operationsToSync) { await _syncDao.markOperationSynced(op.id); } @@ -224,21 +239,26 @@ class SyncOrchestrator { success: true, message: 'Sync completed: ${response.syncedCollections} collections, ' - '${response.syncedItems} items, ${response.syncedTags} tags. ' - 'Applied ${applyResult.appliedTotal} remote change(s).', + '${response.syncedItems} items, ${response.syncedTags} tags, ' + '${response.syncedLoans} loans. ' + 'Applied ${applyResult.appliedTotal} remote change(s).' + '${deferredLoanOperationCount > 0 ? ' Deferred $deferredLoanOperationCount loan change(s) until backend loan sync support is enabled.' : ''}', pendingOperations: pending.length, processedOperations: processedOperations, syncedCollections: response.syncedCollections, syncedItems: response.syncedItems, syncedTags: response.syncedTags, + syncedLoans: response.syncedLoans, conflictCount: response.conflicts.length, partial: false, appliedServerCollections: applyResult.appliedCollections, appliedServerItems: applyResult.appliedItems, appliedServerTags: applyResult.appliedTags, + appliedServerLoans: applyResult.appliedLoans, skippedServerCollections: applyResult.skippedCollections, skippedServerItems: applyResult.skippedItems, skippedServerTags: applyResult.skippedTags, + skippedServerLoans: applyResult.skippedLoans, ); } on SyncAuthRequiredException catch (error) { await _syncDao.upsertSyncState(clearNextRetryAt: true); @@ -253,7 +273,7 @@ class SyncOrchestrator { ); } on DioException catch (error, stackTrace) { final errorText = _buildDioErrorMessage(error); - for (final op in pending) { + for (final op in operationsToSync) { await _syncDao.markOperationFailed(op.id, errorText); } @@ -278,7 +298,7 @@ class SyncOrchestrator { ); } catch (error, stackTrace) { final errorText = '$error'; - for (final op in pending) { + for (final op in operationsToSync) { await _syncDao.markOperationFailed(op.id, errorText); } @@ -343,6 +363,7 @@ class SyncOrchestrator { final collections = >[]; final items = >[]; final tags = >[]; + final loans = >[]; for (final op in pending) { final decoded = jsonDecode(op.payload); @@ -357,6 +378,8 @@ class SyncOrchestrator { items.add(payload); } else if (op.entityType == SyncEntityType.tag.name) { tags.add(payload); + } else if (op.entityType == SyncEntityType.loan.name) { + loans.add(payload); } } @@ -364,6 +387,7 @@ class SyncOrchestrator { collections: collections, items: items, tags: tags, + loans: loans, ); } @@ -371,9 +395,43 @@ class SyncOrchestrator { return response.syncedCollections + response.syncedItems + response.syncedTags + + response.syncedLoans + response.conflicts.length; } + Future<_SyncCapabilityEvaluation> _evaluateCapabilities() async { + var schemaVersion = 'v1'; + var loansSupported = false; + + try { + final capabilities = await _backendClient.getCapabilities(); + final acceptedVersions = capabilities.acceptedSchemaVersions + .map((version) => version.trim().toLowerCase()) + .toSet(); + if (acceptedVersions.contains('v2') || + acceptedVersions.contains('v2-loans')) { + schemaVersion = 'v2'; + } + + final supportedEntities = capabilities.supportedEntities + .map((entity) => entity.trim().toLowerCase()) + .toSet(); + if (supportedEntities.contains('loan') || + supportedEntities.contains('loans')) { + loansSupported = true; + } else if (schemaVersion == 'v2') { + loansSupported = true; + } + } catch (_) { + // Treat capabilities as unknown and stay with safest defaults. + } + + return _SyncCapabilityEvaluation( + schemaVersion: schemaVersion, + loansSupported: loansSupported, + ); + } + Future _syncWithRetry({ required SyncRequestPayload request, required int pendingOperationCount, @@ -469,3 +527,13 @@ class SyncOrchestrator { ); } } + +class _SyncCapabilityEvaluation { + const _SyncCapabilityEvaluation({ + required this.schemaVersion, + required this.loansSupported, + }); + + final String schemaVersion; + final bool loansSupported; +} diff --git a/apps/mobile/lib/core/sync/sync_outbox_bootstrapper.dart b/apps/mobile/lib/core/sync/sync_outbox_bootstrapper.dart index 5ed0ee4..24dd471 100644 --- a/apps/mobile/lib/core/sync/sync_outbox_bootstrapper.dart +++ b/apps/mobile/lib/core/sync/sync_outbox_bootstrapper.dart @@ -8,16 +8,18 @@ class SyncOutboxBootstrapResult { required this.collectionOperations, required this.itemOperations, required this.tagOperations, + required this.loanOperations, required this.skipped, }); final int collectionOperations; final int itemOperations; final int tagOperations; + final int loanOperations; final bool skipped; int get totalOperations => - collectionOperations + itemOperations + tagOperations; + collectionOperations + itemOperations + tagOperations + loanOperations; } class SyncOutboxBootstrapper { @@ -29,13 +31,16 @@ class SyncOutboxBootstrapper { required SyncDao syncDao, required CollectionDao collectionDao, required ItemDao itemDao, + required LoanDao loanDao, }) : _syncDao = syncDao, _collectionDao = collectionDao, - _itemDao = itemDao; + _itemDao = itemDao, + _loanDao = loanDao; final SyncDao _syncDao; final CollectionDao _collectionDao; final ItemDao _itemDao; + final LoanDao _loanDao; Future seedFromLocalDataIfNeeded() async { final pending = await _syncDao.getPendingOperations(limit: 1); @@ -44,6 +49,7 @@ class SyncOutboxBootstrapper { collectionOperations: 0, itemOperations: 0, tagOperations: 0, + loanOperations: 0, skipped: true, ); } @@ -60,6 +66,7 @@ class SyncOutboxBootstrapper { collectionOperations: 0, itemOperations: 0, tagOperations: 0, + loanOperations: 0, skipped: true, ); } @@ -94,6 +101,7 @@ class SyncOutboxBootstrapper { var collectionOperations = 0; var itemOperations = 0; var tagOperations = 0; + var loanOperations = 0; for (final tag in tags) { await _queueUpsert( @@ -132,10 +140,21 @@ class SyncOutboxBootstrapper { } } + final loans = await _loanDao.getAllLoans(); + for (final loan in loans) { + await _queueUpsert( + entityType: 'loan', + entityId: loan.id, + payload: _loanPayload(loan), + ); + loanOperations++; + } + return SyncOutboxBootstrapResult( collectionOperations: collectionOperations, itemOperations: itemOperations, tagOperations: tagOperations, + loanOperations: loanOperations, skipped: false, ); } @@ -222,4 +241,21 @@ class SyncOutboxBootstrapper { 'updatedAt': tag.updatedAt.toUtc().toIso8601String(), }; } + + Map _loanPayload(ItemLoanData loan) { + return { + 'id': loan.id, + 'itemId': loan.itemId, + 'borrowerName': loan.borrowerName, + 'borrowerContact': loan.borrowerContact, + 'notes': loan.notes, + 'loanedAt': loan.loanedAt.toUtc().toIso8601String(), + 'dueAt': loan.dueAt?.toUtc().toIso8601String(), + 'returnedAt': loan.returnedAt?.toUtc().toIso8601String(), + 'version': 1, + 'isDeleted': false, + 'createdAt': loan.createdAt.toUtc().toIso8601String(), + 'updatedAt': loan.updatedAt.toUtc().toIso8601String(), + }; + } } diff --git a/apps/mobile/lib/core/sync/sync_server_changes_applier.dart b/apps/mobile/lib/core/sync/sync_server_changes_applier.dart index 601541b..882c820 100644 --- a/apps/mobile/lib/core/sync/sync_server_changes_applier.dart +++ b/apps/mobile/lib/core/sync/sync_server_changes_applier.dart @@ -8,20 +8,26 @@ class SyncServerChangeApplyResult { required this.appliedCollections, required this.appliedItems, required this.appliedTags, + required this.appliedLoans, required this.skippedCollections, required this.skippedItems, required this.skippedTags, + required this.skippedLoans, }); final int appliedCollections; final int appliedItems; final int appliedTags; + final int appliedLoans; final int skippedCollections; final int skippedItems; final int skippedTags; + final int skippedLoans; - int get appliedTotal => appliedCollections + appliedItems + appliedTags; - int get skippedTotal => skippedCollections + skippedItems + skippedTags; + int get appliedTotal => + appliedCollections + appliedItems + appliedTags + appliedLoans; + int get skippedTotal => + skippedCollections + skippedItems + skippedTags + skippedLoans; } class SyncServerChangesApplier { @@ -38,9 +44,11 @@ class SyncServerChangesApplier { var appliedCollections = 0; var appliedItems = 0; var appliedTags = 0; + var appliedLoans = 0; var skippedCollections = 0; var skippedItems = 0; var skippedTags = 0; + var skippedLoans = 0; final affectedCollectionIds = {}; await _database.transaction(() async { @@ -297,6 +305,86 @@ class SyncServerChangesApplier { } } + for (final payload in changes.loans) { + final loanId = _asString(payload['id']); + if (loanId == null || loanId.isEmpty) { + skippedLoans++; + continue; + } + + if (await _hasPendingLocalOperation( + entityType: 'loan', + entityId: loanId, + )) { + skippedLoans++; + continue; + } + + final existingLoan = await (_database.select( + _database.itemLoans, + )..where((tbl) => tbl.id.equals(loanId))).getSingleOrNull(); + final serverUpdatedAt = _asDate(payload['updatedAt']); + if (_isServerPayloadOutdated( + localUpdatedAt: existingLoan?.updatedAt, + serverUpdatedAt: serverUpdatedAt, + )) { + skippedLoans++; + continue; + } + + if (_asBool(payload['isDeleted'])) { + await (_database.delete( + _database.itemLoans, + )..where((tbl) => tbl.id.equals(loanId))).go(); + appliedLoans++; + continue; + } + + final itemId = _asString(payload['itemId']); + final borrowerName = _asString(payload['borrowerName']); + final loanedAt = _asDate(payload['loanedAt']); + if (itemId == null || + itemId.isEmpty || + borrowerName == null || + borrowerName.trim().isEmpty || + loanedAt == null) { + skippedLoans++; + continue; + } + + final existingItem = await (_database.select( + _database.items, + )..where((tbl) => tbl.id.equals(itemId))).getSingleOrNull(); + if (existingItem == null) { + skippedLoans++; + continue; + } + + final now = DateTime.now().toUtc(); + await _database + .into(_database.itemLoans) + .insert( + ItemLoansCompanion( + id: Value(loanId), + itemId: Value(itemId), + borrowerName: Value(borrowerName), + borrowerContact: Value(_asString(payload['borrowerContact'])), + notes: Value(_asString(payload['notes'])), + loanedAt: Value(loanedAt), + dueAt: Value(_asDate(payload['dueAt'])), + returnedAt: Value(_asDate(payload['returnedAt'])), + createdAt: Value( + _asDate(payload['createdAt']) ?? + existingLoan?.createdAt ?? + now, + ), + updatedAt: Value(_asDate(payload['updatedAt']) ?? now), + ), + mode: InsertMode.insertOrReplace, + ); + appliedLoans++; + } + for (final collectionId in affectedCollectionIds) { final countRow = await _database .customSelect( @@ -322,9 +410,11 @@ class SyncServerChangesApplier { appliedCollections: appliedCollections, appliedItems: appliedItems, appliedTags: appliedTags, + appliedLoans: appliedLoans, skippedCollections: skippedCollections, skippedItems: skippedItems, skippedTags: skippedTags, + skippedLoans: skippedLoans, ); } diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart index cf121db..6874203 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart @@ -474,13 +474,16 @@ class SettingsScreen extends ConsumerWidget { syncedCollections: result.syncedCollections, syncedItems: result.syncedItems, syncedTags: result.syncedTags, + syncedLoans: result.syncedLoans, conflictCount: result.conflictCount, appliedServerCollections: result.appliedServerCollections, appliedServerItems: result.appliedServerItems, appliedServerTags: result.appliedServerTags, + appliedServerLoans: result.appliedServerLoans, skippedServerCollections: result.skippedServerCollections, skippedServerItems: result.skippedServerItems, skippedServerTags: result.skippedServerTags, + skippedServerLoans: result.skippedServerLoans, message: result.message, error: result.error, stackTrace: result.stackTrace, diff --git a/apps/mobile/test/core/sync/sync_resilience_test.dart b/apps/mobile/test/core/sync/sync_resilience_test.dart index 18df5bd..a4f77e2 100644 --- a/apps/mobile/test/core/sync/sync_resilience_test.dart +++ b/apps/mobile/test/core/sync/sync_resilience_test.dart @@ -74,6 +74,7 @@ void main() { syncedCollections: 1, syncedItems: 0, syncedTags: 0, + syncedLoans: 0, conflictsResolved: 0, ), ], @@ -225,6 +226,7 @@ class _SequenceBackendClient implements SyncBackendClient { maxBatchSize: 1000, conflictStrategy: 'last_write_wins', acceptedSchemaVersions: ['v1'], + supportedEntities: ['collection', 'item', 'tag'], ); } diff --git a/packages/core/data/lib/src/repositories/loan_repository_impl.dart b/packages/core/data/lib/src/repositories/loan_repository_impl.dart index d346264..4e4d0d8 100644 --- a/packages/core/data/lib/src/repositories/loan_repository_impl.dart +++ b/packages/core/data/lib/src/repositories/loan_repository_impl.dart @@ -4,11 +4,15 @@ import 'package:database/database.dart'; import 'package:domain/domain.dart'; import 'package:fpdart/fpdart.dart'; +import '../sync/outbox_sync_writer.dart'; + class LoanRepositoryImpl implements LoanRepository { - LoanRepositoryImpl(this._dao); + LoanRepositoryImpl(this._dao, {SyncDao? syncDao}) + : _syncOutboxWriter = syncDao != null ? SyncOutboxWriter(syncDao) : null; final LoanDao _dao; final Random _random = Random(); + final SyncOutboxWriter? _syncOutboxWriter; @override Stream> watchActiveLoans() { @@ -92,7 +96,9 @@ class LoanRepositoryImpl implements LoanRepository { ); } - return Right(_mapToEntity(created)); + final createdEntity = _mapToEntity(created); + await _queueLoanUpsert(createdEntity); + return Right(createdEntity); } catch (error, stackTrace) { return Left( AppException.database( @@ -147,7 +153,9 @@ class LoanRepositoryImpl implements LoanRepository { ); } - return Right(_mapToEntity(updated)); + final updatedEntity = _mapToEntity(updated); + await _queueLoanUpsert(updatedEntity); + return Right(updatedEntity); } catch (error, stackTrace) { return Left( AppException.database( @@ -161,6 +169,7 @@ class LoanRepositoryImpl implements LoanRepository { @override Future> deleteLoan(String loanId) async { try { + final existing = await _dao.getLoanWithItemById(loanId); final rowsAffected = await _dao.deleteLoan(loanId); if (rowsAffected < 1) { return const Left( @@ -171,6 +180,10 @@ class LoanRepositoryImpl implements LoanRepository { ); } + if (existing != null) { + await _queueLoanDelete(_mapToEntity(existing)); + } + return const Right(null); } catch (error, stackTrace) { return Left( @@ -215,4 +228,68 @@ class LoanRepositoryImpl implements LoanRepository { } return normalized; } + + Future _queueLoanUpsert(LoanRecord loan) async { + final writer = _syncOutboxWriter; + if (writer == null) { + return; + } + + try { + await writer.queueUpsert( + entityType: 'loan', + entityId: loan.id, + payload: _loanSyncPayload(loan: loan), + ); + } catch (_) { + // Keep local write successful even if sync queue persistence fails. + } + } + + Future _queueLoanDelete(LoanRecord loan) async { + final writer = _syncOutboxWriter; + if (writer == null) { + return; + } + + final deletedAt = DateTime.now(); + try { + await writer.queueDelete( + entityType: 'loan', + entityId: loan.id, + payload: _loanSyncPayload( + loan: loan, + isDeleted: true, + deletedAt: deletedAt, + updatedAt: deletedAt, + ), + ); + } catch (_) { + // Keep local write successful even if sync queue persistence fails. + } + } + + Map _loanSyncPayload({ + required LoanRecord loan, + bool isDeleted = false, + DateTime? deletedAt, + DateTime? updatedAt, + }) { + final effectiveUpdatedAt = updatedAt ?? loan.updatedAt; + return { + 'id': loan.id, + 'itemId': loan.itemId, + 'borrowerName': loan.borrowerName, + 'borrowerContact': loan.borrowerContact, + 'notes': loan.notes, + 'loanedAt': loan.loanedAt.toUtc().toIso8601String(), + 'dueAt': loan.dueAt?.toUtc().toIso8601String(), + 'returnedAt': loan.returnedAt?.toUtc().toIso8601String(), + 'version': 1, + 'isDeleted': isDeleted, + if (deletedAt != null) 'deletedAt': deletedAt.toUtc().toIso8601String(), + 'createdAt': loan.createdAt.toUtc().toIso8601String(), + 'updatedAt': effectiveUpdatedAt.toUtc().toIso8601String(), + }; + } } diff --git a/packages/integrations/database/lib/src/daos/loan_dao.dart b/packages/integrations/database/lib/src/daos/loan_dao.dart index ca1ecc1..e2777fe 100644 --- a/packages/integrations/database/lib/src/daos/loan_dao.dart +++ b/packages/integrations/database/lib/src/daos/loan_dao.dart @@ -20,6 +20,12 @@ class ItemLoanWithItemData { class LoanDao extends DatabaseAccessor with _$LoanDaoMixin { LoanDao(super.db); + Future> getAllLoans() { + return (select( + itemLoans, + )..orderBy([(tbl) => OrderingTerm.desc(tbl.loanedAt)])).get(); + } + Stream> watchActiveLoans() { final query = select(itemLoans).join([ diff --git a/packages/integrations/sync_api/lib/src/models/sync_contract.dart b/packages/integrations/sync_api/lib/src/models/sync_contract.dart index 4a6dfad..2982776 100644 --- a/packages/integrations/sync_api/lib/src/models/sync_contract.dart +++ b/packages/integrations/sync_api/lib/src/models/sync_contract.dart @@ -3,18 +3,27 @@ class SyncChangesPayload { this.collections = const [], this.items = const [], this.tags = const [], + this.loans = const [], }); final List> collections; final List> items; final List> tags; + final List> loans; - bool get isEmpty => collections.isEmpty && items.isEmpty && tags.isEmpty; + bool get isEmpty => + collections.isEmpty && items.isEmpty && tags.isEmpty && loans.isEmpty; - int get totalCount => collections.length + items.length + tags.length; + int get totalCount => + collections.length + items.length + tags.length + loans.length; Map toJson() { - return {'collections': collections, 'items': items, 'tags': tags}; + return { + 'collections': collections, + 'items': items, + 'tags': tags, + 'loans': loans, + }; } } @@ -58,6 +67,7 @@ class SyncCapabilities { required this.maxBatchSize, required this.conflictStrategy, required this.acceptedSchemaVersions, + required this.supportedEntities, }); final String apiVersion; @@ -65,6 +75,7 @@ class SyncCapabilities { final int maxBatchSize; final String conflictStrategy; final List acceptedSchemaVersions; + final List supportedEntities; factory SyncCapabilities.fromJson(Map json) { return SyncCapabilities( @@ -74,6 +85,7 @@ class SyncCapabilities { conflictStrategy: json['conflictStrategy'] as String? ?? 'last_write_wins', acceptedSchemaVersions: _toStringList(json['acceptedSchemaVersions']), + supportedEntities: _toStringList(json['supportedEntities']), ); } @@ -91,6 +103,7 @@ class SyncResponsePayload { required this.syncedCollections, required this.syncedItems, required this.syncedTags, + required this.syncedLoans, required this.conflictsResolved, }); @@ -100,6 +113,7 @@ class SyncResponsePayload { final int syncedCollections; final int syncedItems; final int syncedTags; + final int syncedLoans; final int conflictsResolved; factory SyncResponsePayload.fromJson(Map json) { @@ -114,11 +128,13 @@ class SyncResponsePayload { collections: _toJsonMapList(serverChangesJson['collections']), items: _toJsonMapList(serverChangesJson['items']), tags: _toJsonMapList(serverChangesJson['tags']), + loans: _toJsonMapList(serverChangesJson['loans']), ), conflicts: _toJsonMapList(json['conflicts']), syncedCollections: (json['syncedCollections'] as num?)?.toInt() ?? 0, syncedItems: (json['syncedItems'] as num?)?.toInt() ?? 0, syncedTags: (json['syncedTags'] as num?)?.toInt() ?? 0, + syncedLoans: (json['syncedLoans'] as num?)?.toInt() ?? 0, conflictsResolved: (json['conflictsResolved'] as num?)?.toInt() ?? 0, ); } From 3eee08cf805cebda245b3eed7988cfd5d2bc439f Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 15:47:57 +0630 Subject: [PATCH 04/16] feat: Enhance UI responsiveness and text scaling across various widgets, and conditionalize debug logging and tools for production builds. --- .../push_notification_bridge.dart | 5 ++- .../core/providers/metadata_providers.dart | 33 +++++++------- apps/mobile/lib/core/router/app_router.dart | 28 +++++++++--- .../widgets/collection_grid_tile.dart | 19 ++++---- .../presentation/views/add_item_screen.dart | 5 ++- .../presentation/views/settings_screen.dart | 20 ++++----- .../presentation/views/statistics_screen.dart | 2 +- apps/mobile/lib/main.dart | 3 +- .../common/ui/lib/src/widgets/app_sheet.dart | 2 +- .../glass_segmented_navigation_bar.dart | 44 ++++++++++--------- 10 files changed, 97 insertions(+), 64 deletions(-) diff --git a/apps/mobile/lib/core/notifications/push_notification_bridge.dart b/apps/mobile/lib/core/notifications/push_notification_bridge.dart index a16947a..120661b 100644 --- a/apps/mobile/lib/core/notifications/push_notification_bridge.dart +++ b/apps/mobile/lib/core/notifications/push_notification_bridge.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:app_analytics/app_analytics.dart'; import 'package:app_firebase/app_firebase.dart'; import 'package:collection_tracker/core/observability/operational_telemetry.dart'; +import 'package:collection_tracker/core/providers/backend_api_providers.dart'; import 'package:collection_tracker/core/providers/push_notifications_provider.dart'; import 'package:collection_tracker/core/router/routes.dart'; import 'package:flutter/material.dart'; @@ -171,11 +172,13 @@ class _PushNotificationBridgeState return '/collections/$collectionId'; } + final authFeatureEnabled = ref.read(backendAuthFeatureFlagProvider); return switch (_notificationType(message.data)) { 'sync_needed' => Routes.settings, 'price_alert' => Routes.statistics, 'reminder' => Routes.collections, - 'account_security' => '${Routes.auth}?mode=signin', + 'account_security' => + authFeatureEnabled ? '${Routes.auth}?mode=signin' : Routes.settings, _ => null, }; } diff --git a/apps/mobile/lib/core/providers/metadata_providers.dart b/apps/mobile/lib/core/providers/metadata_providers.dart index 508acb7..6a04a91 100644 --- a/apps/mobile/lib/core/providers/metadata_providers.dart +++ b/apps/mobile/lib/core/providers/metadata_providers.dart @@ -9,25 +9,26 @@ part 'metadata_providers.g.dart'; @riverpod Dio metadataDio(Ref ref) { - return Dio( - BaseOptions( - connectTimeout: const Duration(seconds: 10), - receiveTimeout: const Duration(seconds: 10), - headers: {'Accept': 'application/json'}, - ), - ) - ..interceptors.addAll([ + final dio = Dio( + BaseOptions( + connectTimeout: const Duration(seconds: 10), + receiveTimeout: const Duration(seconds: 10), + headers: {'Accept': 'application/json'}, + ), + ); + + if (kDebugMode) { + dio.interceptors.add( LogInterceptor( requestBody: true, responseBody: true, error: true, - logPrint: (obj) { - // Use your logging package here - // logger.debug(obj.toString()); - debugPrint(obj.toString()); - }, + logPrint: (obj) => debugPrint(obj.toString()), ), - ]); + ); + } + + return dio; } @riverpod @@ -79,7 +80,9 @@ Future igdbAccessToken(Ref ref) async { return result.fold( (exception) { - debugPrint('IGDB Auth Error: $exception'); + if (kDebugMode) { + debugPrint('IGDB Auth Error: $exception'); + } return null; }, (token) async { diff --git a/apps/mobile/lib/core/router/app_router.dart b/apps/mobile/lib/core/router/app_router.dart index ef31ce8..f1e8a81 100644 --- a/apps/mobile/lib/core/router/app_router.dart +++ b/apps/mobile/lib/core/router/app_router.dart @@ -1,5 +1,6 @@ import 'package:collection_tracker/core/providers/providers.dart'; import 'package:collection_tracker/core/analytics/analytics_consent_gate.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -34,12 +35,26 @@ final _rootNavigatorKey = GlobalKey(); @riverpod GoRouter appRouter(Ref ref) { final onboardingComplete = ref.watch(onboardingCompleteProvider); + final authFeatureEnabled = ref.watch(backendAuthFeatureFlagProvider); Widget withAnalyticsConsent(Widget child) => AnalyticsConsentGate(child: child); return GoRouter( navigatorKey: _rootNavigatorKey, observers: [AnalyticsObserver()], + redirect: (context, state) { + final path = state.uri.path; + + if (path == Routes.auth && !authFeatureEnabled) { + return Routes.settings; + } + + if (!kDebugMode && path == Routes.settingsDevtools) { + return Routes.settings; + } + + return null; + }, initialLocation: onboardingComplete ? Routes.collections : Routes.onboarding, @@ -170,12 +185,13 @@ GoRouter appRouter(Ref ref) { parentNavigatorKey: _rootNavigatorKey, builder: (_, _) => const LoanTrackingScreen(), ), - GoRoute( - path: 'devtools', - name: 'settings-devtools', - parentNavigatorKey: _rootNavigatorKey, - builder: (_, _) => const SettingsDevToolsScreen(), - ), + if (kDebugMode) + GoRoute( + path: 'devtools', + name: 'settings-devtools', + parentNavigatorKey: _rootNavigatorKey, + builder: (_, _) => const SettingsDevToolsScreen(), + ), ], ), ], diff --git a/apps/mobile/lib/features/collections/presentation/widgets/collection_grid_tile.dart b/apps/mobile/lib/features/collections/presentation/widgets/collection_grid_tile.dart index 630d942..259bcd8 100644 --- a/apps/mobile/lib/features/collections/presentation/widgets/collection_grid_tile.dart +++ b/apps/mobile/lib/features/collections/presentation/widgets/collection_grid_tile.dart @@ -36,6 +36,8 @@ class CollectionGridTile extends StatelessWidget { final hasDescription = collection.description != null && collection.description!.trim().isNotEmpty; + final showDescription = + hasDescription && (!compact || constraints.maxHeight >= 232); final iconSize = compact ? 36.0 : 40.0; return ClipRRect( @@ -125,15 +127,16 @@ class CollectionGridTile extends StatelessWidget { icon: Icons.category_outlined, label: collectionTypeLabel(context, collection.type), ), - if (hasDescription) ...[ - if (!compact) const Spacer(), + if (showDescription) ...[ const SizedBox(height: AppSpacing.xs), - Text( - collection.description!, - maxLines: compact ? 1 : 2, - overflow: TextOverflow.ellipsis, - style: theme.textTheme.bodySmall?.copyWith( - color: theme.colorScheme.onSurfaceVariant, + Flexible( + child: Text( + collection.description!, + maxLines: compact ? 1 : 2, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurfaceVariant, + ), ), ), ], diff --git a/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart b/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart index fe795cc..5637f0a 100644 --- a/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart +++ b/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:collection_tracker/l10n/l10n.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -334,7 +335,9 @@ class _AddItemScreenState extends ConsumerState { }, ); } catch (e) { - debugPrint('Metadata fetch error: $e'); + if (kDebugMode) { + debugPrint('Metadata fetch error: $e'); + } } finally { if (mounted) { setState(() { diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart index 6874203..cc6a59b 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart @@ -88,15 +88,13 @@ class SettingsScreen extends ConsumerWidget { subtitle: analyticsSummary, onTap: () => _showAnalyticsSettings(context, ref), ), - SettingsTile( - icon: Icons.person_outline_rounded, - title: 'Account', - subtitle: accountSummary, - enabled: accountFeatureEnabled, - onTap: accountFeatureEnabled - ? () => context.push(Routes.auth) - : null, - ), + if (accountFeatureEnabled) + SettingsTile( + icon: Icons.person_outline_rounded, + title: 'Account', + subtitle: accountSummary, + onTap: () => context.push(Routes.auth), + ), SettingsTile( icon: Icons.notifications_outlined, title: 'Push Notifications', @@ -496,7 +494,9 @@ class SettingsScreen extends ConsumerWidget { ? 'Prepared ${bootstrapResult.totalOperations} local change(s). ' : ''; final recoveryHint = bootstrapResult.skipped && !result.executed - ? ' If existing local data is missing on cloud, open Developer Tools and use "Rebuild local sync queue".' + ? kDebugMode + ? ' If existing local data is missing on cloud, open Developer Tools and use "Rebuild local sync queue".' + : '' : ''; ScaffoldMessenger.of(context).showSnackBar( SnackBar( diff --git a/apps/mobile/lib/features/statistics/presentation/views/statistics_screen.dart b/apps/mobile/lib/features/statistics/presentation/views/statistics_screen.dart index 9bc8d59..74776d4 100644 --- a/apps/mobile/lib/features/statistics/presentation/views/statistics_screen.dart +++ b/apps/mobile/lib/features/statistics/presentation/views/statistics_screen.dart @@ -83,7 +83,7 @@ class StatisticsScreen extends ConsumerWidget { final isCompact = width < 900 || textScale > 1.05; final crossAxisCount = isCompact ? 2 : 4; final tileHeight = switch (crossAxisCount) { - 2 => width < 460 || textScale > 1.0 ? 184.0 : 160.0, + 2 => width < 460 || textScale > 1.0 ? 210.0 : 186.0, _ => 136.0, }; final cards = [ diff --git a/apps/mobile/lib/main.dart b/apps/mobile/lib/main.dart index be4b173..b6e7b16 100644 --- a/apps/mobile/lib/main.dart +++ b/apps/mobile/lib/main.dart @@ -1,5 +1,6 @@ import 'package:collection_tracker/app.dart'; import 'package:collection_tracker/core/bootstrap/app_bootstrap.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:collection_tracker/core/observers/riverpod_logger.dart'; @@ -21,7 +22,7 @@ void main() async { (ref) => bootstrapData.firebaseRuntimeConfig, ), ], - observers: [RiverpodLogger()], + observers: [if (kDebugMode) RiverpodLogger()], child: const CollectionTrackerApp(), ), ); diff --git a/packages/common/ui/lib/src/widgets/app_sheet.dart b/packages/common/ui/lib/src/widgets/app_sheet.dart index f5fa622..986f222 100644 --- a/packages/common/ui/lib/src/widgets/app_sheet.dart +++ b/packages/common/ui/lib/src/widgets/app_sheet.dart @@ -8,7 +8,7 @@ import 'glass_surface.dart'; Future showAppSheet({ required BuildContext context, required WidgetBuilder builder, - bool isScrollControlled = false, + bool isScrollControlled = true, bool useSafeArea = true, }) { return showModalBottomSheet( diff --git a/packages/common/ui/lib/src/widgets/glass_segmented_navigation_bar.dart b/packages/common/ui/lib/src/widgets/glass_segmented_navigation_bar.dart index 6c14715..1f83fad 100644 --- a/packages/common/ui/lib/src/widgets/glass_segmented_navigation_bar.dart +++ b/packages/common/ui/lib/src/widgets/glass_segmented_navigation_bar.dart @@ -40,7 +40,7 @@ class GlassSegmentedNavigationBar extends StatelessWidget { final textScale = MediaQuery.textScalerOf(context).scale(1.0); final effectiveHeight = (height ?? tokens.navBarHeight) + - (textScale > 1 ? (textScale - 1) * 18 : 0); + (textScale > 1 ? (textScale - 1) * 24 : 0); return SafeArea( top: false, @@ -120,7 +120,9 @@ class _GlassNavItem extends StatelessWidget { scale: selected ? 1 : 0.97, child: LayoutBuilder( builder: (context, constraints) { - final isTight = constraints.maxHeight < 52; + final isTight = + constraints.maxHeight < 52 || constraints.maxWidth < 76; + final showLabel = !isTight || textScale <= 1.02; return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -139,26 +141,28 @@ class _GlassNavItem extends StatelessWidget { : theme.colorScheme.onSurfaceVariant, ), ), - SizedBox(height: isTight ? 2 : 3), - Flexible( - child: Text( - destination.label, - maxLines: 1, - overflow: TextOverflow.ellipsis, - textAlign: TextAlign.center, - textScaler: TextScaler.linear(maxTextScale), - style: theme.textTheme.labelSmall?.copyWith( - fontSize: labelSize, - height: 1.0, - fontWeight: selected - ? FontWeight.w700 - : FontWeight.w500, - color: selected - ? theme.colorScheme.primary - : theme.colorScheme.onSurfaceVariant, + if (showLabel) ...[ + SizedBox(height: isTight ? 2 : 3), + Flexible( + child: Text( + destination.label, + maxLines: 1, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.center, + textScaler: TextScaler.linear(maxTextScale), + style: theme.textTheme.labelSmall?.copyWith( + fontSize: labelSize, + height: 1.0, + fontWeight: selected + ? FontWeight.w700 + : FontWeight.w500, + color: selected + ? theme.colorScheme.primary + : theme.colorScheme.onSurfaceVariant, + ), ), ), - ), + ], ], ); }, From e7f600cba24cdf9406c3b707a1e964b2a1e70f3f Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 16:21:52 +0630 Subject: [PATCH 05/16] feat: Introduce `MetadataLookupService` for centralized metadata fetching, caching, and improved search suggestions. --- .../metadata/metadata_lookup_service.dart | 559 ++++++++++++++++++ .../core/providers/metadata_providers.dart | 182 +----- .../presentation/views/add_item_screen.dart | 50 +- .../views/metadata_search_delegate.dart | 98 ++- 4 files changed, 684 insertions(+), 205 deletions(-) create mode 100644 apps/mobile/lib/core/metadata/metadata_lookup_service.dart diff --git a/apps/mobile/lib/core/metadata/metadata_lookup_service.dart b/apps/mobile/lib/core/metadata/metadata_lookup_service.dart new file mode 100644 index 0000000..3e1e2c4 --- /dev/null +++ b/apps/mobile/lib/core/metadata/metadata_lookup_service.dart @@ -0,0 +1,559 @@ +import 'dart:collection'; + +import 'package:dio/dio.dart'; +import 'package:domain/domain.dart'; +import 'package:metadata_api/metadata_api.dart'; +import 'package:storage/storage.dart'; + +class MetadataApiConfig { + const MetadataApiConfig({ + required this.googleBooksApiKey, + required this.igdbClientId, + required this.igdbClientSecret, + required this.tmdbReadAccessToken, + }); + + final String googleBooksApiKey; + final String igdbClientId; + final String igdbClientSecret; + final String tmdbReadAccessToken; + + bool get hasIgdbConfig => + igdbClientId.trim().isNotEmpty && igdbClientSecret.trim().isNotEmpty; + + bool get hasTmdbConfig => tmdbReadAccessToken.trim().isNotEmpty; +} + +class MetadataLookupMatch { + const MetadataLookupMatch({ + required this.metadata, + required this.confidence, + required this.source, + }); + + const MetadataLookupMatch.none() + : metadata = null, + confidence = 0, + source = 'none'; + + final MetadataBase? metadata; + final double confidence; + final String source; + + bool get hasMetadata => metadata != null; +} + +class MetadataLookupService { + MetadataLookupService({ + required MetadataApiConfig config, + required SecureStorageService secureStorage, + }) : _config = config, + _secureStorage = secureStorage, + _oauthDio = Dio( + BaseOptions( + connectTimeout: const Duration(seconds: 10), + receiveTimeout: const Duration(seconds: 10), + headers: const {'Accept': 'application/json'}, + ), + ); + + static const _igdbTokenStorageKey = 'metadata_igdb_access_token'; + static const _igdbTokenSkewSeconds = 120; + static const _searchCacheTtl = Duration(minutes: 5); + static const _barcodeCacheTtl = Duration(minutes: 10); + static const _maxSearchCacheEntries = 120; + static const _maxBarcodeCacheEntries = 120; + + final MetadataApiConfig _config; + final SecureStorageService _secureStorage; + final Dio _oauthDio; + + GoogleBooksClient? _booksClient; + TMDBClient? _moviesClient; + IGDBClient? _gamesClient; + String? _gamesClientToken; + Future? _tokenRefreshInFlight; + final LinkedHashMap>> + _searchCache = LinkedHashMap(); + final LinkedHashMap> + _barcodeCache = LinkedHashMap(); + final Map>> _searchInFlight = {}; + final Map> _barcodeInFlight = {}; + + Future> search({ + required String query, + required CollectionType collectionType, + int limit = 10, + }) async { + final normalizedQuery = query.trim(); + if (normalizedQuery.isEmpty) { + return const []; + } + + final key = _searchCacheKey( + collectionType: collectionType, + query: normalizedQuery, + limit: limit, + ); + final cached = _getSearchCache(key); + if (cached != null) { + return cached; + } + + final inFlight = _searchInFlight[key]; + if (inFlight != null) { + return inFlight; + } + + final request = _searchInternal( + query: normalizedQuery, + collectionType: collectionType, + limit: limit, + ); + _searchInFlight[key] = request; + + try { + final results = await request; + _putSearchCache(key, results); + return results; + } finally { + _searchInFlight.remove(key); + } + } + + Future findBestBarcodeMatch({ + required String barcode, + required CollectionType primaryType, + List? fallbackTypes, + }) async { + final normalizedBarcode = barcode.trim(); + if (normalizedBarcode.isEmpty) { + return const MetadataLookupMatch.none(); + } + + final fallbackOrder = _resolveFallbackTypes( + primaryType: primaryType, + providedFallbackTypes: fallbackTypes, + ); + final key = _barcodeCacheKey( + primaryType: primaryType, + barcode: normalizedBarcode, + fallbackTypes: fallbackOrder, + ); + final cached = _getBarcodeCache(key); + if (cached != null) { + return cached; + } + + final inFlight = _barcodeInFlight[key]; + if (inFlight != null) { + return inFlight; + } + + final request = _findBestBarcodeMatchInternal( + barcode: normalizedBarcode, + primaryType: primaryType, + fallbackTypes: fallbackOrder, + ); + _barcodeInFlight[key] = request; + + try { + final result = await request; + _putBarcodeCache(key, result); + return result; + } finally { + _barcodeInFlight.remove(key); + } + } + + Future> _searchInternal({ + required String query, + required CollectionType collectionType, + required int limit, + }) { + switch (collectionType) { + case CollectionType.book: + return _searchBooks(query, limit); + case CollectionType.game: + return _searchGames(query, limit); + case CollectionType.movie: + return _searchMovies(query, limit); + case CollectionType.comic: + case CollectionType.music: + case CollectionType.custom: + return Future.value(const []); + } + } + + Future _findBestBarcodeMatchInternal({ + required String barcode, + required CollectionType primaryType, + required List fallbackTypes, + }) async { + final primary = await _safeFetchByBarcode( + barcode: barcode, + collectionType: primaryType, + ); + + if (primary != null) { + return MetadataLookupMatch( + metadata: primary, + confidence: 1, + source: primaryType.name, + ); + } + + for (final fallbackType in fallbackTypes) { + final fallback = await _safeFetchByBarcode( + barcode: barcode, + collectionType: fallbackType, + ); + if (fallback != null) { + return MetadataLookupMatch( + metadata: fallback, + confidence: 0.7, + source: fallbackType.name, + ); + } + } + + return const MetadataLookupMatch.none(); + } + + Future _safeFetchByBarcode({ + required String barcode, + required CollectionType collectionType, + }) async { + try { + return _fetchByBarcode(barcode: barcode, collectionType: collectionType); + } catch (_) { + return null; + } + } + + Future _fetchByBarcode({ + required String barcode, + required CollectionType collectionType, + }) async { + switch (collectionType) { + case CollectionType.book: + return _fetchBookByBarcode(barcode); + case CollectionType.game: + final games = await _searchGames(barcode, 1); + return games.isEmpty ? null : games.first; + case CollectionType.movie: + final movies = await _searchMovies(barcode, 1); + return movies.isEmpty ? null : movies.first; + case CollectionType.comic: + case CollectionType.music: + case CollectionType.custom: + return null; + } + } + + Future _fetchBookByBarcode(String barcode) async { + final client = _resolveBooksClient(); + if (client == null) { + return null; + } + + if (_isValidIsbn(barcode)) { + return _unwrapOrThrow(await client.getBookByISBN(barcode)); + } + + final response = _unwrapOrThrow>( + await client.searchBooks(query: barcode, pageSize: 1), + ); + if (response.items.isEmpty) { + return null; + } + return response.items.first; + } + + Future> _searchBooks(String query, int limit) async { + final client = _resolveBooksClient(); + if (client == null) { + return const []; + } + + final response = _unwrapOrThrow>( + await client.searchBooks(query: query, pageSize: limit), + ); + return response.items.cast(); + } + + Future> _searchGames(String query, int limit) async { + try { + return await _withGamesClient((client) async { + final response = _unwrapOrThrow>( + await client.searchGames(query: query, pageSize: limit), + ); + return response.items.cast(); + }); + } on AppException catch (error) { + if (!_isInvalidIgdbTokenError(error)) { + rethrow; + } + + _gamesClient = null; + _gamesClientToken = null; + await _secureStorage.delete(_igdbTokenStorageKey); + + return _withGamesClient((client) async { + final response = _unwrapOrThrow>( + await client.searchGames(query: query, pageSize: limit), + ); + return response.items.cast(); + }); + } + } + + Future> _searchMovies(String query, int limit) async { + final client = _resolveMoviesClient(); + if (client == null) { + return const []; + } + + final response = _unwrapOrThrow>( + await client.searchMovies(query: query), + ); + return response.items.take(limit).toList().cast(); + } + + GoogleBooksClient? _resolveBooksClient() { + _booksClient ??= GoogleBooksClient( + apiKey: _config.googleBooksApiKey.trim().isEmpty + ? null + : _config.googleBooksApiKey, + ); + return _booksClient; + } + + TMDBClient? _resolveMoviesClient() { + if (!_config.hasTmdbConfig) { + return null; + } + + _moviesClient ??= TMDBClient(apiKey: _config.tmdbReadAccessToken); + return _moviesClient; + } + + Future _resolveGamesClient() async { + if (!_config.hasIgdbConfig) { + return null; + } + + final token = await _resolveIgdbAccessToken(); + if (token == null || token.trim().isEmpty) { + return null; + } + + if (_gamesClient != null && _gamesClientToken == token) { + return _gamesClient; + } + + _gamesClientToken = token; + _gamesClient = IGDBClient( + clientId: _config.igdbClientId, + accessToken: token, + ); + return _gamesClient; + } + + Future _resolveIgdbAccessToken() async { + final cached = await _secureStorage.get(_igdbTokenStorageKey); + if (cached != null && cached.trim().isNotEmpty) { + return cached; + } + + final inFlight = _tokenRefreshInFlight; + if (inFlight != null) { + return inFlight; + } + + final refreshFuture = _requestIgdbAccessToken(); + _tokenRefreshInFlight = refreshFuture; + + try { + return await refreshFuture; + } finally { + _tokenRefreshInFlight = null; + } + } + + Future _requestIgdbAccessToken() async { + if (!_config.hasIgdbConfig) { + return null; + } + + try { + final response = await _oauthDio.post>( + 'https://id.twitch.tv/oauth2/token', + queryParameters: { + 'client_id': _config.igdbClientId, + 'client_secret': _config.igdbClientSecret, + 'grant_type': 'client_credentials', + }, + ); + + final data = response.data; + if (data == null) { + return null; + } + + final token = (data['access_token'] as String?)?.trim(); + if (token == null || token.isEmpty) { + return null; + } + + final expiresIn = (data['expires_in'] as num?)?.toInt(); + final ttlSeconds = expiresIn == null + ? null + : (expiresIn - _igdbTokenSkewSeconds).clamp( + _igdbTokenSkewSeconds, + expiresIn, + ); + + await _secureStorage.save( + _igdbTokenStorageKey, + token, + ttl: ttlSeconds, + ); + return token; + } on DioException { + return null; + } + } + + Future _withGamesClient( + Future Function(IGDBClient client) run, + ) async { + final client = await _resolveGamesClient(); + if (client == null) { + throw AppException.business( + message: 'IGDB metadata source is unavailable', + ); + } + return run(client); + } + + T _unwrapOrThrow(dynamic eitherResult) { + return eitherResult.fold( + (exception) => throw exception as AppException, + (value) => value as T, + ) + as T; + } + + bool _isInvalidIgdbTokenError(AppException exception) { + return exception.maybeWhen( + business: (_, code) => code == 'INVALID_TOKEN', + orElse: () => false, + ); + } + + bool _isValidIsbn(String value) { + final cleaned = value.replaceAll(RegExp(r'[^0-9X]'), ''); + return cleaned.length == 10 || cleaned.length == 13; + } + + List _resolveFallbackTypes({ + required CollectionType primaryType, + required List? providedFallbackTypes, + }) { + final defaults = switch (primaryType) { + CollectionType.book => const [CollectionType.movie, CollectionType.game], + CollectionType.game => const [CollectionType.movie, CollectionType.book], + CollectionType.movie => const [CollectionType.book, CollectionType.game], + CollectionType.comic || CollectionType.music || CollectionType.custom => + const [CollectionType.book, CollectionType.movie, CollectionType.game], + }; + + final candidates = providedFallbackTypes ?? defaults; + final resolved = []; + for (final type in candidates) { + if (type == primaryType || resolved.contains(type)) { + continue; + } + resolved.add(type); + } + return resolved; + } + + String _searchCacheKey({ + required CollectionType collectionType, + required String query, + required int limit, + }) { + return '${collectionType.name}|${query.toLowerCase()}|$limit'; + } + + String _barcodeCacheKey({ + required CollectionType primaryType, + required String barcode, + required List fallbackTypes, + }) { + final fallback = fallbackTypes.map((type) => type.name).join(','); + return '${primaryType.name}|${barcode.toLowerCase()}|$fallback'; + } + + List? _getSearchCache(String key) { + final entry = _searchCache.remove(key); + if (entry == null) { + return null; + } + if (entry.isExpired) { + return null; + } + _searchCache[key] = entry; + return entry.value; + } + + MetadataLookupMatch? _getBarcodeCache(String key) { + final entry = _barcodeCache.remove(key); + if (entry == null) { + return null; + } + if (entry.isExpired) { + return null; + } + _barcodeCache[key] = entry; + return entry.value; + } + + void _putSearchCache(String key, List value) { + _searchCache.remove(key); + _searchCache[key] = _MetadataCacheEntry( + value: List.unmodifiable(value), + expiresAt: DateTime.now().add(_searchCacheTtl), + ); + _trimCache(_searchCache, _maxSearchCacheEntries); + } + + void _putBarcodeCache(String key, MetadataLookupMatch value) { + _barcodeCache.remove(key); + _barcodeCache[key] = _MetadataCacheEntry( + value: value, + expiresAt: DateTime.now().add(_barcodeCacheTtl), + ); + _trimCache(_barcodeCache, _maxBarcodeCacheEntries); + } + + void _trimCache( + LinkedHashMap> cache, + int maxEntries, + ) { + while (cache.length > maxEntries) { + cache.remove(cache.keys.first); + } + } +} + +class _MetadataCacheEntry { + const _MetadataCacheEntry({required this.value, required this.expiresAt}); + + final T value; + final DateTime expiresAt; + + bool get isExpired => DateTime.now().isAfter(expiresAt); +} diff --git a/apps/mobile/lib/core/providers/metadata_providers.dart b/apps/mobile/lib/core/providers/metadata_providers.dart index 6a04a91..ca00f7f 100644 --- a/apps/mobile/lib/core/providers/metadata_providers.dart +++ b/apps/mobile/lib/core/providers/metadata_providers.dart @@ -1,172 +1,24 @@ import 'package:common_env/common_env.dart'; -import 'package:flutter/foundation.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; -import 'package:dio/dio.dart'; -import 'package:metadata_api/metadata_api.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:storage/storage.dart'; -part 'metadata_providers.g.dart'; +import '../metadata/metadata_lookup_service.dart'; -@riverpod -Dio metadataDio(Ref ref) { - final dio = Dio( - BaseOptions( - connectTimeout: const Duration(seconds: 10), - receiveTimeout: const Duration(seconds: 10), - headers: {'Accept': 'application/json'}, - ), - ); - - if (kDebugMode) { - dio.interceptors.add( - LogInterceptor( - requestBody: true, - responseBody: true, - error: true, - logPrint: (obj) => debugPrint(obj.toString()), - ), - ); - } - - return dio; -} - -@riverpod -SecureStorageService secureStorageService(Ref ref) { +final metadataSecureStorageProvider = Provider((ref) { return SecureStorageService.instance; -} - -// ============================================================ -// API Keys Providers -// These should be loaded from secure storage or environment -// ============================================================ - -@riverpod -String googleBooksApiKey(Ref ref) { - return AppEnv.googleBooksApiKey; -} - -@riverpod -Future igdbClientId(Ref ref) async { - return AppEnv.igdbClientId; -} - -@riverpod -Future igdbAccessToken(Ref ref) async { - final secureStorage = ref.watch(secureStorageServiceProvider); - final clientIdFuture = ref.watch(igdbClientIdProvider.future); - final dio = ref.watch(metadataDioProvider); - - final clientId = await clientIdFuture; - final clientSecret = AppEnv.igdbClientSecret; - - if (clientId.isEmpty || clientSecret.isEmpty) { - return null; - } - - const tokenKey = 'igdb_access_token'; - - // Try to load cached token - final cachedToken = await secureStorage.get(tokenKey); - if (cachedToken != null) { - return cachedToken; - } - - final result = await IGDBAuth.getAccessToken( - clientId: clientId, - clientSecret: clientSecret, - dio: dio, - ); - - return result.fold( - (exception) { - if (kDebugMode) { - debugPrint('IGDB Auth Error: $exception'); - } - return null; - }, - (token) async { - // Cache the new token - await secureStorage.save(tokenKey, token); - return token; - }, - ); -} - -@riverpod -String tmdbApiKey(Ref ref) { - return AppEnv.tmdbReadAccessToken; -} - -// ============================================================ -// Client Providers -// ============================================================ - -@riverpod -GoogleBooksClient googleBooksClient(Ref ref) { - final apiKey = ref.watch(googleBooksApiKeyProvider); - final dio = ref.watch(metadataDioProvider); - - return GoogleBooksClient(apiKey: apiKey.isEmpty ? null : apiKey, dio: dio); -} - -@riverpod -Future igdbClient(Ref ref) async { - final clientIdFuture = ref.watch(igdbClientIdProvider.future); - final accessTokenFuture = ref.watch(igdbAccessTokenProvider.future); - final dio = ref.watch(metadataDioProvider); - - final clientId = await clientIdFuture; - final accessToken = await accessTokenFuture; - - if (clientId.isEmpty || accessToken == null) { - return null; - } - - return IGDBClient(clientId: clientId, accessToken: accessToken, dio: dio); -} - -@riverpod -TMDBClient? tmdbClient(Ref ref) { - final apiKey = ref.watch(tmdbApiKeyProvider); - final dio = ref.watch(metadataDioProvider); - - if (apiKey.isEmpty) { - return null; - } - - return TMDBClient(apiKey: apiKey, dio: dio); -} - -// ============================================================ -// Unified Metadata Service Provider -// ============================================================ - -@riverpod -class MetadataService extends _$MetadataService { - @override - FutureOr build() async { - // Initialize service - } - - GoogleBooksClient get booksClient => ref.read(googleBooksClientProvider); - - Future get gamesClient => ref.read(igdbClientProvider.future); - - TMDBClient? get moviesClient => ref.read(tmdbClientProvider); -} - -@riverpod -Future unifiedMetadataService(Ref ref) async { - return UnifiedMetadataService( - booksClient: () => ref.read(googleBooksClientProvider), - gamesClient: () => ref.read(igdbClientProvider.future), - moviesClient: () => ref.read(tmdbClientProvider), +}); + +final metadataApiConfigProvider = Provider((ref) { + return MetadataApiConfig( + googleBooksApiKey: AppEnv.googleBooksApiKey, + igdbClientId: AppEnv.igdbClientId, + igdbClientSecret: AppEnv.igdbClientSecret, + tmdbReadAccessToken: AppEnv.tmdbReadAccessToken, ); -} +}); -@riverpod -Future smartMetadataMatcher(Ref ref) async { - final service = await ref.watch(unifiedMetadataServiceProvider.future); - return SmartMetadataMatcher(service); -} +final metadataLookupServiceProvider = Provider((ref) { + final config = ref.watch(metadataApiConfigProvider); + final secureStorage = ref.watch(metadataSecureStorageProvider); + return MetadataLookupService(config: config, secureStorage: secureStorage); +}); diff --git a/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart b/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart index 5637f0a..87cc874 100644 --- a/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart +++ b/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:collection_tracker/l10n/l10n.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -259,7 +257,6 @@ class _AddItemScreenState extends ConsumerState { } Future _showMetadataSearch(BuildContext context) async { - log('show metadata search'); final collectionAsync = ref.read( collectionDetailProvider(widget.collectionId), ); @@ -302,38 +299,31 @@ class _AddItemScreenState extends ConsumerState { }); try { - final matcher = await ref.read(smartMetadataMatcherProvider.future); - final result = await matcher.findBestMatch( + final metadataService = ref.read(metadataLookupServiceProvider); + final result = await metadataService.findBestBarcodeMatch( barcode: barcode, primaryType: collection.type, ); - result.fold( - (exception) => null, // Ignore errors for now - (match) { - if (match.metadata != null && mounted) { - final metadata = match.metadata!; - setState(() { - if (_titleController.text.isEmpty) { - _titleController.text = metadata.title; - } - if (_descriptionController.text.isEmpty) { - _descriptionController.text = metadata.description ?? ''; - } - _coverImageUrl = metadata.thumbnailUrl; - }); - - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - context.l10n.addItemMatchedMetadata(match.source), - ), - duration: const Duration(seconds: 2), - ), - ); + if (result.metadata != null && mounted) { + final metadata = result.metadata!; + setState(() { + if (_titleController.text.isEmpty) { + _titleController.text = metadata.title; } - }, - ); + if (_descriptionController.text.isEmpty) { + _descriptionController.text = metadata.description ?? ''; + } + _coverImageUrl = metadata.thumbnailUrl; + }); + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(context.l10n.addItemMatchedMetadata(result.source)), + duration: const Duration(seconds: 2), + ), + ); + } } catch (e) { if (kDebugMode) { debugPrint('Metadata fetch error: $e'); diff --git a/apps/mobile/lib/features/items/presentation/views/metadata_search_delegate.dart b/apps/mobile/lib/features/items/presentation/views/metadata_search_delegate.dart index 81c0f54..f5be060 100644 --- a/apps/mobile/lib/features/items/presentation/views/metadata_search_delegate.dart +++ b/apps/mobile/lib/features/items/presentation/views/metadata_search_delegate.dart @@ -18,6 +18,10 @@ class MetadataSearchDelegate extends SearchDelegate { required this.searchFieldLabelText, }) : super(searchFieldLabel: searchFieldLabelText); + String _lastSearchQuery = ''; + int _lastSearchLimit = 0; + Future>? _lastSearchFuture; + @override List? buildActions(BuildContext context) { return [ @@ -52,7 +56,7 @@ class MetadataSearchDelegate extends SearchDelegate { } return FutureBuilder( - future: _performSearch(), + future: _performSearch(query: query, limit: 12), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return LoadingView(message: l10n.metadataSearchLoading); @@ -116,20 +120,94 @@ class MetadataSearchDelegate extends SearchDelegate { @override Widget buildSuggestions(BuildContext context) { - return EmptyState( - icon: Icons.search, - title: context.l10n.metadataSearchSuggestionTitle, - message: context.l10n.metadataSearchSuggestionMessage, + if (query.trim().length < 2) { + return EmptyState( + icon: Icons.search, + title: context.l10n.metadataSearchSuggestionTitle, + message: context.l10n.metadataSearchSuggestionMessage, + ); + } + + return FutureBuilder>( + future: _performSearch(query: query, limit: 6), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return LoadingView(message: context.l10n.metadataSearchLoading); + } + if (snapshot.hasError) { + return ErrorView( + message: context.l10n.metadataSearchError('${snapshot.error}'), + ); + } + + final results = snapshot.data ?? const []; + if (results.isEmpty) { + return EmptyState( + icon: Icons.search_off, + title: context.l10n.metadataSearchNoResultsTitle, + message: context.l10n.metadataSearchNoResultsMessage, + ); + } + + return ListView.builder( + padding: const EdgeInsets.all(AppSpacing.md), + itemCount: results.length, + itemBuilder: (context, index) { + final item = results[index]; + return ListTile( + leading: item.thumbnailUrl != null + ? CachedNetworkImage( + imageUrl: item.thumbnailUrl!, + width: 42, + fit: BoxFit.cover, + placeholder: (context, url) => const Icon(Icons.image), + errorWidget: (context, url, error) => + const Icon(Icons.image_not_supported), + ) + : const Icon(Icons.image), + title: Text( + item.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + onTap: () { + query = item.title; + showResults(context); + }, + ); + }, + ); + }, ); } - Future> _performSearch() async { - final service = await ref.read(unifiedMetadataServiceProvider.future); - final result = await service.search( + Future> _performSearch({ + required String query, + int limit = 10, + }) { + final normalized = query.trim(); + if (_lastSearchFuture != null && + _lastSearchQuery == normalized && + _lastSearchLimit == limit) { + return _lastSearchFuture!; + } + + _lastSearchQuery = normalized; + _lastSearchLimit = limit; + _lastSearchFuture = _search(normalized, limit); + return _lastSearchFuture!; + } + + Future> _search(String query, int limit) async { + if (query.isEmpty) { + return const []; + } + + final service = ref.read(metadataLookupServiceProvider); + return service.search( query: query, collectionType: collectionType, + limit: limit, ); - - return result.fold((exception) => throw exception, (items) => items); } } From 0bad5f4ce2869d131e7e47c795e85a6db1530918 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 18:15:26 +0630 Subject: [PATCH 06/16] feat: Introduce metadata assistance settings and enhance authentication UI with new localization strings. --- .../lib/core/auth/backend_auth_service.dart | 20 + .../lib/core/bootstrap/app_bootstrap.dart | 1 + .../firebase_services_bootstrap.dart | 9 + .../firebase/firebase_runtime_config.dart | 3 + .../metadata/metadata_lookup_service.dart | 83 +- .../observability/operational_telemetry.dart | 3 + .../core/providers/backend_api_providers.dart | 20 + .../metadata_preferences_provider.dart | 93 ++ apps/mobile/lib/core/providers/providers.dart | 1 + apps/mobile/lib/core/router/app_router.dart | 7 + apps/mobile/lib/core/router/routes.dart | 1 + .../auth/presentation/views/auth_screen.dart | 829 ++++++++++++++---- .../presentation/views/add_item_screen.dart | 175 +++- .../presentation/views/edit_item_screen.dart | 252 +++++- .../views/settings_devtools_screen.dart | 12 + .../views/settings_metadata_screen.dart | 184 ++++ .../presentation/views/settings_screen.dart | 25 + apps/mobile/lib/l10n/arb/app_en.arb | 170 +++- apps/mobile/lib/l10n/arb/app_es.arb | 170 +++- apps/mobile/lib/l10n/arb/app_id.arb | 170 +++- apps/mobile/lib/l10n/arb/app_ja.arb | 170 +++- apps/mobile/lib/l10n/arb/app_ko.arb | 170 +++- apps/mobile/lib/l10n/arb/app_my.arb | 170 +++- apps/mobile/lib/l10n/arb/app_zh.arb | 170 +++- .../lib/l10n/gen/app_localizations.dart | 468 ++++++++++ .../lib/l10n/gen/app_localizations_en.dart | 238 +++++ .../lib/l10n/gen/app_localizations_es.dart | 238 +++++ .../lib/l10n/gen/app_localizations_id.dart | 238 +++++ .../lib/l10n/gen/app_localizations_ja.dart | 238 +++++ .../lib/l10n/gen/app_localizations_ko.dart | 238 +++++ .../lib/l10n/gen/app_localizations_my.dart | 238 +++++ .../lib/l10n/gen/app_localizations_zh.dart | 238 +++++ packages/integrations/backend_api/README.md | 1 + .../lib/src/clients/backend_auth_client.dart | 39 + .../lib/src/models/backend_auth_models.dart | 14 + 35 files changed, 4879 insertions(+), 217 deletions(-) create mode 100644 apps/mobile/lib/core/providers/metadata_preferences_provider.dart create mode 100644 apps/mobile/lib/features/settings/presentation/views/settings_metadata_screen.dart diff --git a/apps/mobile/lib/core/auth/backend_auth_service.dart b/apps/mobile/lib/core/auth/backend_auth_service.dart index 93e2193..bdf11e1 100644 --- a/apps/mobile/lib/core/auth/backend_auth_service.dart +++ b/apps/mobile/lib/core/auth/backend_auth_service.dart @@ -115,6 +115,26 @@ class BackendAuthService { return response.user; } + Future requestAccountDeletion({String? reason}) async { + final existing = await _sessionStore.readSession(); + if (!existing.hasAccessToken || existing.accessToken == null) { + throw const BackendApiException( + message: 'Sign in is required to request account deletion.', + code: 'AUTH_REQUIRED', + ); + } + + await _client.requestAccountDeletion( + accessToken: existing.accessToken!, + request: BackendAccountDeletionRequest( + reason: reason, + source: 'mobile_app', + ), + ); + + await _sessionStore.clearSession(); + } + Future _persistAuthResponse(BackendAuthResponse response) async { final session = AuthSession( status: AuthSessionStatus.signedIn, diff --git a/apps/mobile/lib/core/bootstrap/app_bootstrap.dart b/apps/mobile/lib/core/bootstrap/app_bootstrap.dart index acd0c86..5582bca 100644 --- a/apps/mobile/lib/core/bootstrap/app_bootstrap.dart +++ b/apps/mobile/lib/core/bootstrap/app_bootstrap.dart @@ -40,6 +40,7 @@ abstract final class AppBootstrap { performanceEnabled: firebaseRuntimeConfig.performanceCollectionEnabled, appCheckEnabled: firebaseRuntimeConfig.appCheckEnabled, fcmEnabled: firebaseRuntimeConfig.fcmEnabled, + metadataEnabled: firebaseRuntimeConfig.metadataFeatureEnabled, backendEnabled: firebaseRuntimeConfig.backendIntegrationEnabled, authEnabled: firebaseRuntimeConfig.authFeatureEnabled, syncEnabled: firebaseRuntimeConfig.syncFeatureEnabled, diff --git a/apps/mobile/lib/core/bootstrap/firebase_services_bootstrap.dart b/apps/mobile/lib/core/bootstrap/firebase_services_bootstrap.dart index 20ee3cc..086dd7a 100644 --- a/apps/mobile/lib/core/bootstrap/firebase_services_bootstrap.dart +++ b/apps/mobile/lib/core/bootstrap/firebase_services_bootstrap.dart @@ -27,6 +27,7 @@ abstract final class FirebaseServicesBootstrap { 'app_performance_collection_enabled'; static const _appCheckEnabledKey = 'app_app_check_enabled'; static const _fcmEnabledKey = 'app_fcm_enabled'; + static const _metadataFeatureEnabledKey = 'app_metadata_feature_enabled'; static const _backendIntegrationEnabledKey = 'app_backend_integration_enabled'; static const _authFeatureEnabledKey = 'app_auth_feature_enabled'; @@ -42,6 +43,7 @@ abstract final class FirebaseServicesBootstrap { _performanceCollectionEnabledKey: true, _appCheckEnabledKey: false, _fcmEnabledKey: false, + _metadataFeatureEnabledKey: true, _backendIntegrationEnabledKey: false, _authFeatureEnabledKey: true, _syncFeatureEnabledKey: false, @@ -69,6 +71,7 @@ abstract final class FirebaseServicesBootstrap { 'performance: ${runtimeConfig.performanceCollectionEnabled}, ' 'appCheck: ${runtimeConfig.appCheckEnabled}, ' 'fcm: ${runtimeConfig.fcmEnabled}, ' + 'metadata: ${runtimeConfig.metadataFeatureEnabled}, ' 'backend: ${runtimeConfig.backendIntegrationEnabled}, ' 'auth: ${runtimeConfig.authFeatureEnabled}, ' 'sync: ${runtimeConfig.syncFeatureEnabled}).', @@ -115,6 +118,7 @@ abstract final class FirebaseServicesBootstrap { 'performance: ${runtimeConfig.performanceCollectionEnabled}, ' 'appCheck: ${runtimeConfig.appCheckEnabled}, ' 'fcm: ${runtimeConfig.fcmEnabled}, ' + 'metadata: ${runtimeConfig.metadataFeatureEnabled}, ' 'backend: ${runtimeConfig.backendIntegrationEnabled}, ' 'auth: ${runtimeConfig.authFeatureEnabled}, ' 'sync: ${runtimeConfig.syncFeatureEnabled}).', @@ -126,6 +130,7 @@ abstract final class FirebaseServicesBootstrap { performanceEnabled: runtimeConfig.performanceCollectionEnabled, appCheckEnabled: runtimeConfig.appCheckEnabled, fcmEnabled: runtimeConfig.fcmEnabled, + metadataEnabled: runtimeConfig.metadataFeatureEnabled, backendEnabled: runtimeConfig.backendIntegrationEnabled, authEnabled: runtimeConfig.authFeatureEnabled, syncEnabled: runtimeConfig.syncFeatureEnabled, @@ -160,6 +165,10 @@ abstract final class FirebaseServicesBootstrap { fallback: false, ), fcmEnabled: remoteConfigService.getBool(_fcmEnabledKey, fallback: false), + metadataFeatureEnabled: remoteConfigService.getBool( + _metadataFeatureEnabledKey, + fallback: true, + ), backendIntegrationEnabled: remoteConfigService.getBool( _backendIntegrationEnabledKey, fallback: false, diff --git a/apps/mobile/lib/core/firebase/firebase_runtime_config.dart b/apps/mobile/lib/core/firebase/firebase_runtime_config.dart index ba53a07..9d77ed2 100644 --- a/apps/mobile/lib/core/firebase/firebase_runtime_config.dart +++ b/apps/mobile/lib/core/firebase/firebase_runtime_config.dart @@ -5,6 +5,7 @@ class FirebaseRuntimeConfig { required this.performanceCollectionEnabled, required this.appCheckEnabled, required this.fcmEnabled, + required this.metadataFeatureEnabled, required this.backendIntegrationEnabled, required this.authFeatureEnabled, required this.syncFeatureEnabled, @@ -16,6 +17,7 @@ class FirebaseRuntimeConfig { performanceCollectionEnabled: true, appCheckEnabled: false, fcmEnabled: false, + metadataFeatureEnabled: true, backendIntegrationEnabled: false, authFeatureEnabled: true, syncFeatureEnabled: false, @@ -26,6 +28,7 @@ class FirebaseRuntimeConfig { final bool performanceCollectionEnabled; final bool appCheckEnabled; final bool fcmEnabled; + final bool metadataFeatureEnabled; final bool backendIntegrationEnabled; final bool authFeatureEnabled; final bool syncFeatureEnabled; diff --git a/apps/mobile/lib/core/metadata/metadata_lookup_service.dart b/apps/mobile/lib/core/metadata/metadata_lookup_service.dart index 3e1e2c4..d3c0e31 100644 --- a/apps/mobile/lib/core/metadata/metadata_lookup_service.dart +++ b/apps/mobile/lib/core/metadata/metadata_lookup_service.dart @@ -80,6 +80,32 @@ class MetadataLookupService { final Map>> _searchInFlight = {}; final Map> _barcodeInFlight = {}; + bool supportsSearch(CollectionType collectionType) { + return switch (collectionType) { + CollectionType.book => true, + CollectionType.game => _config.hasIgdbConfig, + CollectionType.movie => _config.hasTmdbConfig, + CollectionType.comic || + CollectionType.music || + CollectionType.custom => false, + }; + } + + bool supportsBarcodeLookup({ + required CollectionType primaryType, + List? fallbackTypes, + }) { + if (supportsSearch(primaryType)) { + return true; + } + + final fallbackOrder = _resolveFallbackTypes( + primaryType: primaryType, + providedFallbackTypes: fallbackTypes, + ); + return fallbackOrder.any(supportsSearch); + } + Future> search({ required String query, required CollectionType collectionType, @@ -170,19 +196,20 @@ class MetadataLookupService { required String query, required CollectionType collectionType, required int limit, - }) { - switch (collectionType) { - case CollectionType.book: - return _searchBooks(query, limit); - case CollectionType.game: - return _searchGames(query, limit); - case CollectionType.movie: - return _searchMovies(query, limit); - case CollectionType.comic: - case CollectionType.music: - case CollectionType.custom: - return Future.value(const []); - } + }) async { + final results = switch (collectionType) { + CollectionType.book => await _searchBooks(query, limit), + CollectionType.game => await _searchGames(query, limit), + CollectionType.movie => await _searchMovies(query, limit), + CollectionType.comic || + CollectionType.music || + CollectionType.custom => const [], + }; + + return _filterSearchResults( + collectionType: collectionType, + results: results, + ); } Future _findBestBarcodeMatchInternal({ @@ -239,10 +266,16 @@ class MetadataLookupService { case CollectionType.book: return _fetchBookByBarcode(barcode); case CollectionType.game: - final games = await _searchGames(barcode, 1); + final games = _filterSearchResults( + collectionType: CollectionType.game, + results: await _searchGames(barcode, 1), + ); return games.isEmpty ? null : games.first; case CollectionType.movie: - final movies = await _searchMovies(barcode, 1); + final movies = _filterSearchResults( + collectionType: CollectionType.movie, + results: await _searchMovies(barcode, 1), + ); return movies.isEmpty ? null : movies.first; case CollectionType.comic: case CollectionType.music: @@ -457,14 +490,28 @@ class MetadataLookupService { return cleaned.length == 10 || cleaned.length == 13; } + List _filterSearchResults({ + required CollectionType collectionType, + required List results, + }) { + return switch (collectionType) { + CollectionType.book => results.whereType().toList(), + CollectionType.game => results.whereType().toList(), + CollectionType.movie => results.whereType().toList(), + CollectionType.comic || + CollectionType.music || + CollectionType.custom => const [], + }; + } + List _resolveFallbackTypes({ required CollectionType primaryType, required List? providedFallbackTypes, }) { final defaults = switch (primaryType) { - CollectionType.book => const [CollectionType.movie, CollectionType.game], - CollectionType.game => const [CollectionType.movie, CollectionType.book], - CollectionType.movie => const [CollectionType.book, CollectionType.game], + CollectionType.book => const [], + CollectionType.game => const [], + CollectionType.movie => const [], CollectionType.comic || CollectionType.music || CollectionType.custom => const [CollectionType.book, CollectionType.movie, CollectionType.game], }; diff --git a/apps/mobile/lib/core/observability/operational_telemetry.dart b/apps/mobile/lib/core/observability/operational_telemetry.dart index f543b9d..bdcfddc 100644 --- a/apps/mobile/lib/core/observability/operational_telemetry.dart +++ b/apps/mobile/lib/core/observability/operational_telemetry.dart @@ -165,6 +165,7 @@ class OperationalTelemetry { required bool performanceEnabled, required bool appCheckEnabled, required bool fcmEnabled, + required bool metadataEnabled, required bool backendEnabled, required bool authEnabled, required bool syncEnabled, @@ -180,6 +181,7 @@ class OperationalTelemetry { 'performance_enabled': performanceEnabled, 'app_check_enabled': appCheckEnabled, 'fcm_enabled': fcmEnabled, + 'metadata_enabled': metadataEnabled, 'backend_enabled': backendEnabled, 'auth_enabled': authEnabled, 'sync_enabled': syncEnabled, @@ -192,6 +194,7 @@ class OperationalTelemetry { 'flag_performance_enabled': performanceEnabled, 'flag_app_check_enabled': appCheckEnabled, 'flag_fcm_enabled': fcmEnabled, + 'flag_metadata_enabled': metadataEnabled, 'flag_backend_enabled': backendEnabled, 'flag_auth_enabled': authEnabled, 'flag_sync_enabled': syncEnabled, diff --git a/apps/mobile/lib/core/providers/backend_api_providers.dart b/apps/mobile/lib/core/providers/backend_api_providers.dart index 1d9876e..9aab51f 100644 --- a/apps/mobile/lib/core/providers/backend_api_providers.dart +++ b/apps/mobile/lib/core/providers/backend_api_providers.dart @@ -282,6 +282,26 @@ final backendAuthServiceProvider = Provider((ref) { ); }); +final backendAuthProfileProvider = FutureProvider(( + ref, +) async { + final service = ref.watch(backendAuthServiceProvider); + if (service == null) { + return null; + } + + final session = ref.watch(authSessionProvider).value; + if (session == null || !session.isAuthenticated) { + return null; + } + + try { + return await service.fetchProfile(); + } on BackendApiException { + return null; + } +}); + final backendSessionStoreProvider = Provider((ref) { return ref.watch(authSessionStoreProvider); }); diff --git a/apps/mobile/lib/core/providers/metadata_preferences_provider.dart b/apps/mobile/lib/core/providers/metadata_preferences_provider.dart new file mode 100644 index 0000000..43be7d0 --- /dev/null +++ b/apps/mobile/lib/core/providers/metadata_preferences_provider.dart @@ -0,0 +1,93 @@ +import 'package:collection_tracker/core/firebase/firebase_runtime_config.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:storage/storage.dart'; + +import 'firebase_runtime_config_provider.dart'; + +class MetadataPreferencesState { + const MetadataPreferencesState({ + required this.preferenceEnabled, + required this.autoFetchBarcodeEnabled, + required this.fillOnlyEmptyFields, + required this.runtimeFeatureEnabled, + }); + + final bool preferenceEnabled; + final bool autoFetchBarcodeEnabled; + final bool fillOnlyEmptyFields; + final bool runtimeFeatureEnabled; + + bool get isEnabled => runtimeFeatureEnabled && preferenceEnabled; + bool get canAutoFetchFromBarcode => isEnabled && autoFetchBarcodeEnabled; + + MetadataPreferencesState copyWith({ + bool? preferenceEnabled, + bool? autoFetchBarcodeEnabled, + bool? fillOnlyEmptyFields, + bool? runtimeFeatureEnabled, + }) { + return MetadataPreferencesState( + preferenceEnabled: preferenceEnabled ?? this.preferenceEnabled, + autoFetchBarcodeEnabled: + autoFetchBarcodeEnabled ?? this.autoFetchBarcodeEnabled, + fillOnlyEmptyFields: fillOnlyEmptyFields ?? this.fillOnlyEmptyFields, + runtimeFeatureEnabled: + runtimeFeatureEnabled ?? this.runtimeFeatureEnabled, + ); + } +} + +final metadataPreferencesProvider = + NotifierProvider( + MetadataPreferencesController.new, + ); + +class MetadataPreferencesController extends Notifier { + static const _enabledKey = 'metadata_feature_enabled'; + static const _autoFetchBarcodeKey = 'metadata_auto_fetch_barcode'; + static const _fillEmptyOnlyKey = 'metadata_fill_empty_only'; + + late final PrefsStorageService _prefs; + + @override + MetadataPreferencesState build() { + _prefs = PrefsStorageService.instance; + + ref.listen(firebaseRuntimeConfigProvider, ( + previous, + next, + ) { + if (previous?.metadataFeatureEnabled == next.metadataFeatureEnabled) { + return; + } + state = state.copyWith( + runtimeFeatureEnabled: next.metadataFeatureEnabled, + ); + }); + + return MetadataPreferencesState( + preferenceEnabled: _prefs.readSync(_enabledKey) ?? true, + autoFetchBarcodeEnabled: + _prefs.readSync(_autoFetchBarcodeKey) ?? true, + fillOnlyEmptyFields: _prefs.readSync(_fillEmptyOnlyKey) ?? true, + runtimeFeatureEnabled: ref + .read(firebaseRuntimeConfigProvider) + .metadataFeatureEnabled, + ); + } + + Future setPreferenceEnabled(bool enabled) async { + await _prefs.save(_enabledKey, enabled); + state = state.copyWith(preferenceEnabled: enabled); + } + + Future setAutoFetchBarcodeEnabled(bool enabled) async { + await _prefs.save(_autoFetchBarcodeKey, enabled); + state = state.copyWith(autoFetchBarcodeEnabled: enabled); + } + + Future setFillOnlyEmptyFields(bool enabled) async { + await _prefs.save(_fillEmptyOnlyKey, enabled); + state = state.copyWith(fillOnlyEmptyFields: enabled); + } +} diff --git a/apps/mobile/lib/core/providers/providers.dart b/apps/mobile/lib/core/providers/providers.dart index b8512ee..48da90a 100644 --- a/apps/mobile/lib/core/providers/providers.dart +++ b/apps/mobile/lib/core/providers/providers.dart @@ -13,5 +13,6 @@ export 'collections_view_mode_provider.dart'; export 'locale_provider.dart'; export 'push_notifications_provider.dart'; export 'sync_providers.dart'; +export 'metadata_preferences_provider.dart'; final onboardingCompleteProvider = Provider((ref) => false); diff --git a/apps/mobile/lib/core/router/app_router.dart b/apps/mobile/lib/core/router/app_router.dart index f1e8a81..6fcb1c2 100644 --- a/apps/mobile/lib/core/router/app_router.dart +++ b/apps/mobile/lib/core/router/app_router.dart @@ -19,6 +19,7 @@ import '../../features/scanner/presentation/views/scanner_screen.dart'; import '../../features/search/presentation/views/search_screen.dart'; import '../../features/settings/presentation/views/settings_screen.dart'; import '../../features/settings/presentation/views/settings_devtools_screen.dart'; +import '../../features/settings/presentation/views/settings_metadata_screen.dart'; import '../../features/settings/presentation/views/settings_notifications_screen.dart'; import '../../features/statistics/presentation/views/statistics_screen.dart'; import '../../features/items/presentation/views/tag_management_screen.dart'; @@ -179,6 +180,12 @@ GoRouter appRouter(Ref ref) { parentNavigatorKey: _rootNavigatorKey, builder: (_, _) => const SettingsNotificationsScreen(), ), + GoRoute( + path: 'metadata', + name: 'settings-metadata', + parentNavigatorKey: _rootNavigatorKey, + builder: (_, _) => const SettingsMetadataScreen(), + ), GoRoute( path: 'loans', name: 'settings-loans', diff --git a/apps/mobile/lib/core/router/routes.dart b/apps/mobile/lib/core/router/routes.dart index 9b809d7..77a021e 100644 --- a/apps/mobile/lib/core/router/routes.dart +++ b/apps/mobile/lib/core/router/routes.dart @@ -10,6 +10,7 @@ abstract final class Routes { static const settings = '/settings'; static const settingsTags = '/settings/tags'; static const settingsLoans = '/settings/loans'; + static const settingsMetadata = '/settings/metadata'; static const settingsNotifications = '/settings/notifications'; static const settingsDevtools = '/settings/devtools'; static const tagItems = '/tags/items'; diff --git a/apps/mobile/lib/features/auth/presentation/views/auth_screen.dart b/apps/mobile/lib/features/auth/presentation/views/auth_screen.dart index 109b5ad..599c075 100644 --- a/apps/mobile/lib/features/auth/presentation/views/auth_screen.dart +++ b/apps/mobile/lib/features/auth/presentation/views/auth_screen.dart @@ -1,6 +1,8 @@ import 'package:auth_session/auth_session.dart'; import 'package:backend_api/backend_api.dart'; import 'package:collection_tracker/core/providers/providers.dart'; +import 'package:collection_tracker/core/router/routes.dart'; +import 'package:collection_tracker/l10n/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -51,15 +53,17 @@ class _AuthScreenState extends ConsumerState { @override Widget build(BuildContext context) { + final l10n = context.l10n; final sessionAsync = ref.watch(authSessionProvider); final session = sessionAsync.value; + final profileAsync = ref.watch(backendAuthProfileProvider); final service = ref.watch(backendAuthServiceProvider); final readiness = ref.watch(backendAuthReadinessProvider); final canAuthenticate = service != null; final isAuthenticated = session?.isAuthenticated ?? false; return Scaffold( - appBar: AppBar(title: const Text('Account')), + appBar: AppBar(title: Text(l10n.authTitleAccount)), body: SafeArea( child: ListView( padding: const EdgeInsets.fromLTRB( @@ -75,142 +79,183 @@ class _AuthScreenState extends ConsumerState { child: Center(child: CircularProgressIndicator()), ) else if (isAuthenticated) - AppReveal( - child: _AuthenticatedCard( - session: session!, - isSubmitting: _isSubmitting, - onSignOut: _handleSignOut, - onDone: () => context.pop(true), - ), + Column( + children: [ + AppReveal( + child: _AuthenticatedCard( + l10n: l10n, + session: session!, + profile: profileAsync.value, + isProfileLoading: profileAsync.isLoading, + isSubmitting: _isSubmitting, + onRequestAccountDeletion: _handleRequestAccountDeletion, + onSignOut: _handleSignOut, + onDone: () => _closeWithResult(true), + ), + ), + ], ) else if (!canAuthenticate) AppReveal( child: _AuthUnavailableCard( + l10n: l10n, message: readiness.message, - onClose: () => context.pop(false), + onClose: () => _closeWithResult(false), ), ) else - AppReveal( - child: AppCard( - child: Form( - key: _formKey, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - _isRegisterMode ? 'Create Account' : 'Sign In', - style: Theme.of(context).textTheme.titleMedium - ?.copyWith(fontWeight: FontWeight.w700), - ), - const SizedBox(height: AppSpacing.sm), - Text( - 'Sign in to enable cloud sync features.', - style: Theme.of(context).textTheme.bodyMedium - ?.copyWith( - color: Theme.of( - context, - ).colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(height: AppSpacing.md), - Wrap( - spacing: AppSpacing.sm, + Column( + children: [ + AppReveal( + child: _AuthHeaderCard( + l10n: l10n, + isRegisterMode: _isRegisterMode, + ), + ), + const SizedBox(height: AppSpacing.md), + AppReveal( + delay: AppMotion.stagger, + child: AppCard( + child: Form( + key: _formKey, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - ChoiceChip( - label: const Text('Sign in'), - selected: !_isRegisterMode, - onSelected: _isSubmitting - ? null - : (selected) { - if (!selected) return; - setState(() => _isRegisterMode = false); - }, + Text( + _isRegisterMode + ? l10n.authCreateAccountHeading + : l10n.authSignInHeading, + style: Theme.of(context).textTheme.titleMedium + ?.copyWith(fontWeight: FontWeight.w700), + ), + const SizedBox(height: AppSpacing.sm), + Text( + _isRegisterMode + ? l10n.authCreateAccountDescription + : l10n.authSignInDescription, + style: Theme.of(context).textTheme.bodyMedium + ?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: AppSpacing.md), + Wrap( + spacing: AppSpacing.sm, + children: [ + ChoiceChip( + label: Text(l10n.authSignInChoice), + selected: !_isRegisterMode, + onSelected: _isSubmitting + ? null + : (selected) { + if (!selected) return; + setState( + () => _isRegisterMode = false, + ); + }, + ), + ChoiceChip( + label: Text(l10n.authRegisterChoice), + selected: _isRegisterMode, + onSelected: _isSubmitting + ? null + : (selected) { + if (!selected) return; + setState( + () => _isRegisterMode = true, + ); + }, + ), + ], ), - ChoiceChip( - label: const Text('Register'), - selected: _isRegisterMode, - onSelected: _isSubmitting + const SizedBox(height: AppSpacing.md), + AppInput( + controller: _emailController, + labelText: l10n.authEmailLabel, + hintText: l10n.authEmailHint, + prefixIcon: const Icon(Icons.email_outlined), + keyboardType: TextInputType.emailAddress, + textInputAction: TextInputAction.next, + validator: (value) { + final text = (value ?? '').trim(); + if (text.isEmpty) { + return l10n.authEmailRequiredError; + } + if (!text.contains('@')) { + return l10n.authEmailInvalidError; + } + return null; + }, + ), + const SizedBox(height: AppSpacing.sm), + AppInput( + controller: _passwordController, + labelText: l10n.authPasswordLabel, + hintText: _isRegisterMode + ? l10n.authPasswordHint + : null, + prefixIcon: const Icon(Icons.lock_outline), + keyboardType: TextInputType.visiblePassword, + obscureText: true, + autocorrect: false, + enableSuggestions: false, + smartDashesType: SmartDashesType.disabled, + smartQuotesType: SmartQuotesType.disabled, + textInputAction: _isRegisterMode + ? TextInputAction.next + : TextInputAction.done, + validator: (value) { + final text = value ?? ''; + if (text.isEmpty) { + return l10n.authPasswordRequiredError; + } + if (text.length < 8) { + return l10n.authPasswordLengthError; + } + if (!_passwordPolicyRegex.hasMatch(text)) { + return l10n.authPasswordPolicyError; + } + return null; + }, + ), + if (_isRegisterMode) ...[ + const SizedBox(height: AppSpacing.sm), + AppInput( + controller: _displayNameController, + labelText: l10n.authDisplayNameLabel, + hintText: l10n.authDisplayNameHint, + prefixIcon: const Icon( + Icons.person_outline_rounded, + ), + textInputAction: TextInputAction.done, + ), + ], + const SizedBox(height: AppSpacing.lg), + AppButton( + label: _isRegisterMode + ? l10n.authCreateAccountAction + : l10n.authSignInChoice, + isLoading: _isSubmitting, + onPressed: _isSubmitting ? null : _handleSubmit, + expand: true, + ), + const SizedBox(height: AppSpacing.sm), + AppButton( + label: l10n.authNotNowAction, + variant: AppButtonVariant.ghost, + onPressed: _isSubmitting ? null - : (selected) { - if (!selected) return; - setState(() => _isRegisterMode = true); - }, + : () => _closeWithResult(false), + expand: true, ), ], ), - const SizedBox(height: AppSpacing.md), - AppInput( - controller: _emailController, - labelText: 'Email', - keyboardType: TextInputType.emailAddress, - textInputAction: TextInputAction.next, - validator: (value) { - final text = (value ?? '').trim(); - if (text.isEmpty) { - return 'Email is required.'; - } - if (!text.contains('@')) { - return 'Enter a valid email.'; - } - return null; - }, - ), - const SizedBox(height: AppSpacing.sm), - AppInput( - controller: _passwordController, - labelText: 'Password', - keyboardType: TextInputType.visiblePassword, - obscureText: true, - autocorrect: false, - enableSuggestions: false, - smartDashesType: SmartDashesType.disabled, - smartQuotesType: SmartQuotesType.disabled, - textInputAction: _isRegisterMode - ? TextInputAction.next - : TextInputAction.done, - validator: (value) { - final text = value ?? ''; - if (text.isEmpty) { - return 'Password is required.'; - } - if (text.length < 8) { - return 'Password must be at least 8 characters.'; - } - if (!_passwordPolicyRegex.hasMatch(text)) { - return 'Password must include uppercase, lowercase, and number.'; - } - return null; - }, - ), - if (_isRegisterMode) ...[ - const SizedBox(height: AppSpacing.sm), - AppInput( - controller: _displayNameController, - labelText: 'Display Name (optional)', - textInputAction: TextInputAction.done, - ), - ], - const SizedBox(height: AppSpacing.lg), - AppButton( - label: _isRegisterMode ? 'Create account' : 'Sign in', - isLoading: _isSubmitting, - onPressed: _isSubmitting ? null : _handleSubmit, - expand: true, - ), - const SizedBox(height: AppSpacing.sm), - AppButton( - label: 'Not now', - variant: AppButtonVariant.ghost, - onPressed: _isSubmitting - ? null - : () => context.pop(false), - expand: true, - ), - ], + ), ), ), - ), + ], ), ], ), @@ -219,14 +264,13 @@ class _AuthScreenState extends ConsumerState { } Future _handleSubmit() async { + final l10n = context.l10n; final service = ref.read(backendAuthServiceProvider); if (service == null) { if (!mounted) return; - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Authentication is currently unavailable.'), - ), - ); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(l10n.authUnavailableMessage))); return; } @@ -254,16 +298,14 @@ class _AuthScreenState extends ConsumerState { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - _isRegisterMode - ? 'Account created and signed in.' - : 'Signed in successfully.', + _isRegisterMode ? l10n.authRegisterSuccess : l10n.authSignInSuccess, ), backgroundColor: Colors.green, ), ); if (widget.popOnSuccess && mounted) { - context.pop(true); + _closeWithResult(true); } } on BackendApiException catch (error) { if (!mounted) return; @@ -274,7 +316,7 @@ class _AuthScreenState extends ConsumerState { if (!mounted) return; ScaffoldMessenger.of( context, - ).showSnackBar(SnackBar(content: Text('Sign-in failed: $error'))); + ).showSnackBar(SnackBar(content: Text(l10n.authSignInFailed('$error')))); } finally { if (mounted) { setState(() => _isSubmitting = false); @@ -283,6 +325,7 @@ class _AuthScreenState extends ConsumerState { } Future _handleSignOut() async { + final l10n = context.l10n; setState(() => _isSubmitting = true); try { final service = ref.read(backendAuthServiceProvider); @@ -295,8 +338,8 @@ class _AuthScreenState extends ConsumerState { if (!mounted) return; ScaffoldMessenger.of( context, - ).showSnackBar(const SnackBar(content: Text('Signed out.'))); - context.pop(true); + ).showSnackBar(SnackBar(content: Text(l10n.authSignedOut))); + _closeWithResult(true); } finally { if (mounted) { setState(() => _isSubmitting = false); @@ -304,10 +347,184 @@ class _AuthScreenState extends ConsumerState { } } + Future _handleRequestAccountDeletion() async { + final l10n = context.l10n; + final acknowledged = await _showDeletionImpactDialog(); + if (acknowledged != true) { + return; + } + if (!mounted) { + return; + } + + final confirmed = await showAppDialog( + context: context, + title: Text(l10n.authFinalConfirmationTitle), + content: Text(l10n.authFinalConfirmationMessage), + actions: [ + AppButton( + label: l10n.authBackAction, + variant: AppButtonVariant.ghost, + onPressed: () => closeAppDialog(context, false), + ), + AppButton( + label: l10n.authSubmitRequestAction, + variant: AppButtonVariant.danger, + onPressed: () => closeAppDialog(context, true), + ), + ], + ); + + if (confirmed != true || !mounted) { + return; + } + + setState(() => _isSubmitting = true); + try { + final service = ref.read(backendAuthServiceProvider); + if (service == null) { + throw BackendApiException( + message: l10n.authUnavailableMessage, + code: 'AUTH_UNAVAILABLE', + ); + } + + await service.requestAccountDeletion( + reason: 'User requested deletion from mobile app', + ); + + if (!mounted) { + return; + } + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(l10n.authDeletionRequestSubmitted), + backgroundColor: Colors.green, + ), + ); + _closeWithResult(true); + } on BackendApiException catch (error) { + if (!mounted) { + return; + } + final message = error.code == 'ACCOUNT_DELETION_ENDPOINT_NOT_FOUND' + ? l10n.authDeletionEndpointMissing + : _friendlyAuthError(error); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(message))); + } finally { + if (mounted) { + setState(() => _isSubmitting = false); + } + } + } + + Future _showDeletionImpactDialog() { + final l10n = context.l10n; + final colorScheme = Theme.of(context).colorScheme; + final warningBackground = colorScheme.errorContainer.withValues( + alpha: colorScheme.brightness == Brightness.light ? 0.78 : 0.9, + ); + final warningBorder = colorScheme.error.withValues( + alpha: colorScheme.brightness == Brightness.light ? 0.35 : 0.48, + ); + final warningTitle = colorScheme.onErrorContainer; + final warningBody = colorScheme.onErrorContainer.withValues(alpha: 0.92); + + return showAppDialog( + context: context, + barrierDismissible: false, + title: Text(l10n.authDeletionImpactDialogTitle), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.authDeletionImpactReviewPrompt, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: AppSpacing.md), + AppCard( + padding: const EdgeInsets.all(AppSpacing.md), + color: warningBackground, + borderColor: warningBorder, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.warning_amber_rounded, + color: warningTitle, + size: 18, + ), + const SizedBox(width: AppSpacing.xs), + Text( + l10n.authIrreversibleRequestTitle, + style: Theme.of(context).textTheme.labelLarge?.copyWith( + color: warningTitle, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + const SizedBox(height: AppSpacing.sm), + _DeletionImpactLine( + color: warningBody, + text: l10n.authImpactLineSessionRevoked, + ), + const SizedBox(height: AppSpacing.xs), + _DeletionImpactLine( + color: warningBody, + text: l10n.authImpactLineCloudDataDeleted, + ), + const SizedBox(height: AppSpacing.xs), + _DeletionImpactLine( + color: warningBody, + text: l10n.authImpactLineCannotRestore, + ), + ], + ), + ), + ], + ), + actions: [ + AppButton( + label: l10n.actionCancel, + variant: AppButtonVariant.ghost, + onPressed: () => closeAppDialog(context, false), + ), + AppButton( + label: l10n.authUnderstandAction, + variant: AppButtonVariant.danger, + onPressed: () => closeAppDialog(context, true), + ), + ], + ); + } + + void _closeWithResult(bool result) { + if (!mounted) { + return; + } + + if (Navigator.of(context).canPop()) { + context.pop(result); + return; + } + + context.go(Routes.settings); + } + String _friendlyAuthError(BackendApiException error) { + final l10n = context.l10n; final message = error.message.trim(); if (message.toLowerCase().contains('password must contain uppercase')) { - return '$message Use English keyboard letters and digits (A-Z, a-z, 0-9).'; + return '$message ${l10n.authPasswordPolicySuffix}'; } return message; } @@ -315,55 +532,274 @@ class _AuthScreenState extends ConsumerState { class _AuthenticatedCard extends StatelessWidget { const _AuthenticatedCard({ + required this.l10n, required this.session, + required this.profile, + required this.isProfileLoading, required this.isSubmitting, + required this.onRequestAccountDeletion, required this.onSignOut, required this.onDone, }); + final AppLocalizations l10n; final AuthSession session; + final BackendAuthUser? profile; + final bool isProfileLoading; final bool isSubmitting; + final Future Function() onRequestAccountDeletion; final Future Function() onSignOut; final VoidCallback onDone; @override Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + final warningBackground = colorScheme.errorContainer.withValues( + alpha: colorScheme.brightness == Brightness.light ? 0.78 : 0.9, + ); + final warningBorder = colorScheme.error.withValues( + alpha: colorScheme.brightness == Brightness.light ? 0.35 : 0.48, + ); + final warningTitle = colorScheme.onErrorContainer; + final warningBody = colorScheme.onErrorContainer.withValues(alpha: 0.92); + final titleText = profile?.displayName?.trim(); + final subtitleText = profile?.email.trim(); + + return Column( + children: [ + AppCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + CircleAvatar( + radius: 24, + backgroundColor: colorScheme.primaryContainer, + foregroundColor: colorScheme.onPrimaryContainer, + child: const Icon(Icons.person_rounded), + ), + const SizedBox(width: AppSpacing.md), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + (titleText == null || titleText.isEmpty) + ? l10n.authAccountConnected + : titleText, + style: Theme.of(context).textTheme.titleMedium + ?.copyWith(fontWeight: FontWeight.w700), + ), + const SizedBox(height: 2), + Text( + (subtitleText == null || subtitleText.isEmpty) + ? l10n.authSignedInReadySubtitle + : subtitleText, + style: Theme.of(context).textTheme.bodySmall + ?.copyWith(color: colorScheme.onSurfaceVariant), + ), + ], + ), + ), + Container( + padding: const EdgeInsets.symmetric( + horizontal: AppSpacing.sm, + vertical: 6, + ), + decoration: BoxDecoration( + color: colorScheme.primary.withValues(alpha: 0.12), + borderRadius: BorderRadius.circular(AppRadii.pill), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.verified_rounded, + size: 14, + color: colorScheme.primary, + ), + const SizedBox(width: 4), + Text( + l10n.authActiveStatus, + style: Theme.of(context).textTheme.labelSmall + ?.copyWith( + color: colorScheme.primary, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + ), + ], + ), + if (isProfileLoading) ...[ + const SizedBox(height: AppSpacing.sm), + LinearProgressIndicator( + minHeight: 2, + borderRadius: BorderRadius.circular(AppRadii.pill), + ), + ], + ], + ), + ), + const SizedBox(height: AppSpacing.md), + AppCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.authSessionDetailsTitle, + style: Theme.of( + context, + ).textTheme.labelLarge?.copyWith(fontWeight: FontWeight.w700), + ), + const SizedBox(height: AppSpacing.sm), + _MetaRow( + icon: Icons.badge_outlined, + label: l10n.authUserIdLabel, + value: session.userId ?? l10n.authUnknownValue, + ), + const SizedBox(height: AppSpacing.xs), + _MetaRow( + icon: Icons.smartphone_outlined, + label: l10n.authDeviceIdLabel, + value: session.deviceId ?? l10n.authUnknownValue, + ), + ], + ), + ), + const SizedBox(height: AppSpacing.md), + AppCard( + color: warningBackground, + borderColor: warningBorder, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.warning_amber_rounded, + color: warningTitle, + size: 18, + ), + const SizedBox(width: AppSpacing.xs), + Text( + l10n.authDeletionNoticeTitle, + style: Theme.of(context).textTheme.labelLarge?.copyWith( + color: warningTitle, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + const SizedBox(height: AppSpacing.sm), + Text( + l10n.authDeletionNoticeSubtitle, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: warningBody), + ), + const SizedBox(height: AppSpacing.xs), + _DeletionImpactLine( + color: warningBody, + text: l10n.authDeletionNoticeLineProfileSessions, + ), + const SizedBox(height: AppSpacing.xs), + _DeletionImpactLine( + color: warningBody, + text: l10n.authDeletionNoticeLineSyncedData, + ), + ], + ), + ), + const SizedBox(height: AppSpacing.md), + AppCard( + child: Column( + children: [ + AppButton( + label: l10n.authRequestDeletionAction, + variant: AppButtonVariant.danger, + isLoading: isSubmitting, + onPressed: isSubmitting + ? null + : () => onRequestAccountDeletion(), + expand: true, + ), + const SizedBox(height: AppSpacing.sm), + AppButton( + label: l10n.authSignOutAction, + variant: AppButtonVariant.secondary, + isLoading: isSubmitting, + onPressed: isSubmitting ? null : () => onSignOut(), + expand: true, + ), + const SizedBox(height: AppSpacing.sm), + AppButton( + label: l10n.authDoneAction, + variant: AppButtonVariant.ghost, + onPressed: isSubmitting ? null : onDone, + expand: true, + ), + ], + ), + ), + ], + ); + } +} + +class _AuthHeaderCard extends StatelessWidget { + const _AuthHeaderCard({required this.l10n, required this.isRegisterMode}); + + final AppLocalizations l10n; + final bool isRegisterMode; + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; return AppCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - 'Signed in', - style: Theme.of( - context, - ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700), + Row( + children: [ + Container( + width: 42, + height: 42, + decoration: BoxDecoration( + color: colorScheme.primary.withValues(alpha: 0.12), + borderRadius: BorderRadius.circular(AppRadii.md), + ), + child: Icon( + isRegisterMode + ? Icons.person_add_alt_1_rounded + : Icons.lock_open_rounded, + color: colorScheme.primary, + ), + ), + const SizedBox(width: AppSpacing.sm), + Expanded( + child: Text( + isRegisterMode + ? l10n.authHeaderCreateTitle + : l10n.authHeaderWelcomeTitle, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + ), + ], ), const SizedBox(height: AppSpacing.sm), Text( - 'You can now use cloud sync features.', + isRegisterMode + ? l10n.authHeaderCreateSubtitle + : l10n.authHeaderSignInSubtitle, style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, + color: colorScheme.onSurfaceVariant, ), ), - const SizedBox(height: AppSpacing.md), - _MetaRow(label: 'User ID', value: session.userId ?? 'Unknown'), - const SizedBox(height: AppSpacing.xs), - _MetaRow(label: 'Device ID', value: session.deviceId ?? 'Unknown'), - const SizedBox(height: AppSpacing.lg), - AppButton( - label: 'Sign out', - variant: AppButtonVariant.danger, - isLoading: isSubmitting, - onPressed: isSubmitting ? null : () => onSignOut(), - expand: true, - ), - const SizedBox(height: AppSpacing.sm), - AppButton( - label: 'Done', - variant: AppButtonVariant.ghost, - onPressed: isSubmitting ? null : onDone, - expand: true, - ), ], ), ); @@ -371,22 +807,37 @@ class _AuthenticatedCard extends StatelessWidget { } class _AuthUnavailableCard extends StatelessWidget { - const _AuthUnavailableCard({required this.message, required this.onClose}); + const _AuthUnavailableCard({ + required this.l10n, + required this.message, + required this.onClose, + }); + final AppLocalizations l10n; final String message; final VoidCallback onClose; @override Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; return AppCard( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - 'Authentication unavailable', - style: Theme.of( - context, - ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700), + Row( + children: [ + Icon( + Icons.lock_person_outlined, + color: colorScheme.onSurfaceVariant, + ), + const SizedBox(width: AppSpacing.sm), + Text( + l10n.authUnavailableTitle, + style: Theme.of( + context, + ).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w700), + ), + ], ), const SizedBox(height: AppSpacing.sm), Text( @@ -397,7 +848,7 @@ class _AuthUnavailableCard extends StatelessWidget { ), const SizedBox(height: AppSpacing.lg), AppButton( - label: 'Back', + label: l10n.authBackAction, variant: AppButtonVariant.ghost, onPressed: onClose, expand: true, @@ -409,15 +860,24 @@ class _AuthUnavailableCard extends StatelessWidget { } class _MetaRow extends StatelessWidget { - const _MetaRow({required this.label, required this.value}); + const _MetaRow({required this.label, required this.value, this.icon}); final String label; final String value; + final IconData? icon; @override Widget build(BuildContext context) { return Row( children: [ + if (icon != null) ...[ + Icon( + icon, + size: 16, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + const SizedBox(width: AppSpacing.xs), + ], SizedBox( width: 88, child: Text( @@ -441,3 +901,36 @@ class _MetaRow extends StatelessWidget { ); } } + +class _DeletionImpactLine extends StatelessWidget { + const _DeletionImpactLine({required this.text, this.color}); + + final String text; + final Color? color; + + @override + Widget build(BuildContext context) { + final resolvedColor = color ?? Theme.of(context).colorScheme.onSurface; + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '\u2022', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: resolvedColor, + fontWeight: FontWeight.w700, + ), + ), + const SizedBox(width: AppSpacing.xs), + Expanded( + child: Text( + text, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: resolvedColor), + ), + ), + ], + ); + } +} diff --git a/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart b/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart index 87cc874..3221da3 100644 --- a/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart +++ b/apps/mobile/lib/features/items/presentation/views/add_item_screen.dart @@ -4,8 +4,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; +import 'package:domain/domain.dart'; import 'package:storage/storage.dart'; import 'package:ui/ui.dart'; +import 'package:collection_tracker/core/providers/metadata_preferences_provider.dart'; import 'package:collection_tracker/core/providers/metadata_providers.dart'; import 'package:collection_tracker/features/collections/presentation/view_models/collections_view_model.dart'; import 'package:metadata_api/metadata_api.dart'; @@ -55,8 +57,16 @@ class _AddItemScreenState extends ConsumerState { @override Widget build(BuildContext context) { final l10n = context.l10n; - // Watch collection details so they are available for search/scan actions - ref.watch(collectionDetailProvider(widget.collectionId)); + final collectionAsync = ref.watch( + collectionDetailProvider(widget.collectionId), + ); + final collection = collectionAsync.asData?.value; + final metadataPreferences = ref.watch(metadataPreferencesProvider); + final metadataService = ref.read(metadataLookupServiceProvider); + final metadataSearchSupported = + collection != null && + metadataPreferences.isEnabled && + metadataService.supportsSearch(collection.type); return Scaffold( appBar: AppBar(title: Text(l10n.addItemTitle)), @@ -110,9 +120,14 @@ class _AddItemScreenState extends ConsumerState { labelText: l10n.itemFormTitleLabel, hintText: l10n.addItemTitleHint, prefixIcon: const Icon(Icons.title), - suffixIcon: IconButton( - icon: const Icon(Icons.search), - onPressed: () => _showMetadataSearch(context), + suffixIcon: Tooltip( + message: metadataSearchSupported + ? l10n.metadataSearchSuggestionTitle + : l10n.metadataSearchDisabledHint, + child: IconButton( + icon: const Icon(Icons.search), + onPressed: () => _showMetadataSearch(context), + ), ), textCapitalization: TextCapitalization.words, validator: (value) { @@ -137,7 +152,9 @@ class _AddItemScreenState extends ConsumerState { if (barcode != null && mounted) { _barcodeController.text = barcode; - _fetchMetadata(barcode); + if (metadataPreferences.canAutoFetchFromBarcode) { + _fetchMetadata(barcode, showNoMatchFeedback: false); + } } }, ), @@ -262,6 +279,21 @@ class _AddItemScreenState extends ConsumerState { ); final collection = collectionAsync.asData?.value; if (collection == null) return; + final metadataPreferences = ref.read(metadataPreferencesProvider); + if (!metadataPreferences.isEnabled) { + _showMetadataMessage(context.l10n.settingsMetadataFeatureDisabledMessage); + return; + } + + final metadataService = ref.read(metadataLookupServiceProvider); + if (!metadataService.supportsSearch(collection.type)) { + _showMetadataMessage( + context.l10n.metadataSearchUnavailableForType( + _collectionTypeLabel(collection.type), + ), + ); + return; + } final result = await showSearch( context: context, @@ -269,7 +301,7 @@ class _AddItemScreenState extends ConsumerState { ref: ref, collectionType: collection.type, searchFieldLabelText: context.l10n.metadataSearchFieldLabel( - collection.type.name, + _collectionTypeLabel(collection.type), ), ), query: _titleController.text, @@ -277,16 +309,32 @@ class _AddItemScreenState extends ConsumerState { if (result != null && mounted) { setState(() { - _titleController.text = result.title; - if (_descriptionController.text.isEmpty) { - _descriptionController.text = result.description ?? ''; - } - _coverImageUrl = result.thumbnailUrl; + _applyMetadata( + result, + fillOnlyEmptyFields: metadataPreferences.fillOnlyEmptyFields, + ); }); } } - Future _fetchMetadata(String barcode) async { + Future _fetchMetadata( + String barcode, { + bool showNoMatchFeedback = true, + }) async { + if (_isFetchingMetadata) { + return; + } + + final metadataPreferences = ref.read(metadataPreferencesProvider); + if (!metadataPreferences.isEnabled) { + if (showNoMatchFeedback) { + _showMetadataMessage( + context.l10n.settingsMetadataFeatureDisabledMessage, + ); + } + return; + } + final collectionAsync = ref.read( collectionDetailProvider(widget.collectionId), ); @@ -294,12 +342,23 @@ class _AddItemScreenState extends ConsumerState { final collection = collectionAsync.value; if (collection == null) return; + final metadataService = ref.read(metadataLookupServiceProvider); + if (!metadataService.supportsBarcodeLookup(primaryType: collection.type)) { + if (showNoMatchFeedback) { + _showMetadataMessage( + context.l10n.metadataSearchUnavailableForType( + _collectionTypeLabel(collection.type), + ), + ); + } + return; + } + setState(() { _isFetchingMetadata = true; }); try { - final metadataService = ref.read(metadataLookupServiceProvider); final result = await metadataService.findBestBarcodeMatch( barcode: barcode, primaryType: collection.type, @@ -308,26 +367,32 @@ class _AddItemScreenState extends ConsumerState { if (result.metadata != null && mounted) { final metadata = result.metadata!; setState(() { - if (_titleController.text.isEmpty) { - _titleController.text = metadata.title; - } - if (_descriptionController.text.isEmpty) { - _descriptionController.text = metadata.description ?? ''; - } - _coverImageUrl = metadata.thumbnailUrl; + _applyMetadata( + metadata, + fillOnlyEmptyFields: metadataPreferences.fillOnlyEmptyFields, + ); }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text(context.l10n.addItemMatchedMetadata(result.source)), + content: Text( + context.l10n.addItemMatchedMetadata( + _metadataSourceLabel(result.source), + ), + ), duration: const Duration(seconds: 2), ), ); + } else if (showNoMatchFeedback && mounted) { + _showMetadataMessage(context.l10n.metadataNoMatchForBarcode); } } catch (e) { if (kDebugMode) { debugPrint('Metadata fetch error: $e'); } + if (showNoMatchFeedback && mounted) { + _showMetadataMessage(context.l10n.metadataNoMatchForBarcode); + } } finally { if (mounted) { setState(() { @@ -428,4 +493,70 @@ class _AddItemScreenState extends ConsumerState { final locale = Localizations.localeOf(context).toLanguageTag(); return NumberFormat.simpleCurrency(locale: locale).currencySymbol; } + + void _applyMetadata( + MetadataBase metadata, { + required bool fillOnlyEmptyFields, + }) { + final title = metadata.title.trim(); + final description = metadata.description?.trim(); + final thumbnail = metadata.thumbnailUrl?.trim(); + + if (fillOnlyEmptyFields) { + if (_titleController.text.trim().isEmpty && title.isNotEmpty) { + _titleController.text = title; + } + if (_descriptionController.text.trim().isEmpty && + description != null && + description.isNotEmpty) { + _descriptionController.text = description; + } + final hasImage = + _imagePath != null || (_coverImageUrl?.trim().isNotEmpty ?? false); + if (!hasImage && thumbnail != null && thumbnail.isNotEmpty) { + _coverImageUrl = thumbnail; + } + return; + } + + if (title.isNotEmpty) { + _titleController.text = title; + } + if (description != null && description.isNotEmpty) { + _descriptionController.text = description; + } + if (_imagePath == null && thumbnail != null && thumbnail.isNotEmpty) { + _coverImageUrl = thumbnail; + } + } + + String _collectionTypeLabel(CollectionType type) { + final l10n = context.l10n; + return switch (type) { + CollectionType.book => l10n.collectionTypeBooks, + CollectionType.game => l10n.collectionTypeGames, + CollectionType.movie => l10n.collectionTypeMovies, + CollectionType.comic => l10n.collectionTypeComics, + CollectionType.music => l10n.collectionTypeMusic, + CollectionType.custom => l10n.collectionTypeCustom, + }; + } + + String _metadataSourceLabel(String source) { + return switch (source.toLowerCase()) { + 'book' => context.l10n.collectionTypeBooks, + 'game' => context.l10n.collectionTypeGames, + 'movie' => context.l10n.collectionTypeMovies, + _ => source, + }; + } + + void _showMetadataMessage(String message) { + if (!mounted) { + return; + } + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(message))); + } } diff --git a/apps/mobile/lib/features/items/presentation/views/edit_item_screen.dart b/apps/mobile/lib/features/items/presentation/views/edit_item_screen.dart index 2748023..9209635 100644 --- a/apps/mobile/lib/features/items/presentation/views/edit_item_screen.dart +++ b/apps/mobile/lib/features/items/presentation/views/edit_item_screen.dart @@ -1,12 +1,17 @@ import 'package:domain/domain.dart'; +import 'package:collection_tracker/core/providers/metadata_preferences_provider.dart'; +import 'package:collection_tracker/core/providers/metadata_providers.dart'; +import 'package:collection_tracker/features/collections/presentation/view_models/collections_view_model.dart'; import 'package:collection_tracker/l10n/l10n.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:intl/intl.dart'; +import 'package:metadata_api/metadata_api.dart'; import 'package:ui/ui.dart'; import '../view_models/items_view_model.dart'; +import 'metadata_search_delegate.dart'; import '../widgets/item_tags_editor.dart'; class EditItemScreen extends ConsumerStatefulWidget { @@ -31,6 +36,7 @@ class _EditItemScreenState extends ConsumerState { final _quantityController = TextEditingController(); bool _isSaving = false; + bool _isFetchingMetadata = false; bool _isInitialized = false; Item? _item; ItemCondition? _selectedCondition; @@ -97,6 +103,17 @@ class _EditItemScreenState extends ConsumerState { _isInitialized = true; } + final collectionAsync = ref.watch( + collectionDetailProvider(item.collectionId), + ); + final collection = collectionAsync.asData?.value; + final metadataPreferences = ref.watch(metadataPreferencesProvider); + final metadataService = ref.read(metadataLookupServiceProvider); + final metadataSearchSupported = + collection != null && + metadataPreferences.isEnabled && + metadataService.supportsSearch(collection.type); + return Scaffold( appBar: AppBar(title: Text(l10n.editItemTitle)), body: Form( @@ -111,6 +128,16 @@ class _EditItemScreenState extends ConsumerState { controller: _titleController, labelText: l10n.itemFormTitleLabel, prefixIcon: const Icon(Icons.title), + suffixIcon: Tooltip( + message: metadataSearchSupported + ? l10n.metadataSearchSuggestionTitle + : l10n.metadataSearchDisabledHint, + child: IconButton( + icon: const Icon(Icons.search), + onPressed: () => + _showMetadataSearch(context, collection?.type), + ), + ), textCapitalization: TextCapitalization.words, validator: (value) { if (value == null || value.trim().isEmpty) { @@ -128,18 +155,57 @@ class _EditItemScreenState extends ConsumerState { icon: const Icon(Icons.camera_alt), onPressed: () async { final barcode = await context.push( - '/scanner', + '/scanner?collectionId=${item.collectionId}', ); if (barcode != null && mounted) { setState(() { _barcodeController.text = barcode; }); + if (metadataPreferences.canAutoFetchFromBarcode) { + _fetchMetadata( + barcode, + collectionType: collection?.type, + showNoMatchFeedback: false, + ); + } } }, ), - keyboardType: TextInputType.number, + keyboardType: TextInputType.text, + onFieldSubmitted: (value) { + if (value.trim().isEmpty) { + return; + } + _fetchMetadata( + value.trim(), + collectionType: collection?.type, + ); + }, ), + if (_isFetchingMetadata) + Padding( + padding: EdgeInsets.only(top: AppSpacing.sm), + child: Center( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 16, + height: 16, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ), + SizedBox(width: 8), + Text( + l10n.addItemFetchingMetadata, + style: TextStyle(fontSize: 12), + ), + ], + ), + ), + ), const SizedBox(height: AppSpacing.md), AppInput( controller: _descriptionController, @@ -348,6 +414,131 @@ class _EditItemScreenState extends ConsumerState { } } + Future _showMetadataSearch( + BuildContext context, + CollectionType? collectionType, + ) async { + if (collectionType == null) { + return; + } + + final metadataPreferences = ref.read(metadataPreferencesProvider); + if (!metadataPreferences.isEnabled) { + _showMetadataMessage(context.l10n.settingsMetadataFeatureDisabledMessage); + return; + } + + final metadataService = ref.read(metadataLookupServiceProvider); + if (!metadataService.supportsSearch(collectionType)) { + _showMetadataMessage( + context.l10n.metadataSearchUnavailableForType( + _collectionTypeLabel(collectionType), + ), + ); + return; + } + + final result = await showSearch( + context: context, + delegate: MetadataSearchDelegate( + ref: ref, + collectionType: collectionType, + searchFieldLabelText: context.l10n.metadataSearchFieldLabel( + _collectionTypeLabel(collectionType), + ), + ), + query: _titleController.text, + ); + + if (result == null || !mounted) { + return; + } + + setState(() { + _applyMetadata( + result, + fillOnlyEmptyFields: metadataPreferences.fillOnlyEmptyFields, + ); + }); + } + + Future _fetchMetadata( + String barcode, { + required CollectionType? collectionType, + bool showNoMatchFeedback = true, + }) async { + if (_isFetchingMetadata || collectionType == null) { + return; + } + + final metadataPreferences = ref.read(metadataPreferencesProvider); + if (!metadataPreferences.isEnabled) { + if (showNoMatchFeedback) { + _showMetadataMessage( + context.l10n.settingsMetadataFeatureDisabledMessage, + ); + } + return; + } + + final metadataService = ref.read(metadataLookupServiceProvider); + if (!metadataService.supportsBarcodeLookup(primaryType: collectionType)) { + if (showNoMatchFeedback) { + _showMetadataMessage( + context.l10n.metadataSearchUnavailableForType( + _collectionTypeLabel(collectionType), + ), + ); + } + return; + } + + setState(() { + _isFetchingMetadata = true; + }); + + try { + final result = await metadataService.findBestBarcodeMatch( + barcode: barcode, + primaryType: collectionType, + ); + + if (!mounted) { + return; + } + + if (result.metadata != null) { + setState(() { + _applyMetadata( + result.metadata!, + fillOnlyEmptyFields: metadataPreferences.fillOnlyEmptyFields, + ); + }); + + _showMetadataMessage( + context.l10n.addItemMatchedMetadata( + _metadataSourceLabel(result.source), + ), + ); + } else if (showNoMatchFeedback) { + _showMetadataMessage(context.l10n.metadataNoMatchForBarcode); + } + } catch (_) { + if (!mounted) { + return; + } + if (showNoMatchFeedback) { + _showMetadataMessage(context.l10n.metadataNoMatchForBarcode); + } + } finally { + if (mounted) { + setState(() { + _isFetchingMetadata = false; + }); + } + } + } + String? _validatePriceInput(String? value) { if (value == null || value.trim().isEmpty) { return null; @@ -402,4 +593,61 @@ class _EditItemScreenState extends ConsumerState { ItemCondition.poor => l10n.itemConditionPoor, }; } + + void _applyMetadata( + MetadataBase metadata, { + required bool fillOnlyEmptyFields, + }) { + final title = metadata.title.trim(); + final description = metadata.description?.trim(); + + if (fillOnlyEmptyFields) { + if (_titleController.text.trim().isEmpty && title.isNotEmpty) { + _titleController.text = title; + } + if (_descriptionController.text.trim().isEmpty && + description != null && + description.isNotEmpty) { + _descriptionController.text = description; + } + return; + } + + if (title.isNotEmpty) { + _titleController.text = title; + } + if (description != null && description.isNotEmpty) { + _descriptionController.text = description; + } + } + + String _collectionTypeLabel(CollectionType type) { + final l10n = context.l10n; + return switch (type) { + CollectionType.book => l10n.collectionTypeBooks, + CollectionType.game => l10n.collectionTypeGames, + CollectionType.movie => l10n.collectionTypeMovies, + CollectionType.comic => l10n.collectionTypeComics, + CollectionType.music => l10n.collectionTypeMusic, + CollectionType.custom => l10n.collectionTypeCustom, + }; + } + + String _metadataSourceLabel(String source) { + return switch (source.toLowerCase()) { + 'book' => context.l10n.collectionTypeBooks, + 'game' => context.l10n.collectionTypeGames, + 'movie' => context.l10n.collectionTypeMovies, + _ => source, + }; + } + + void _showMetadataMessage(String message) { + if (!mounted) { + return; + } + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(message))); + } } diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_devtools_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_devtools_screen.dart index c8a3759..162f242 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_devtools_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_devtools_screen.dart @@ -718,6 +718,18 @@ class SettingsDevToolsScreen extends ConsumerWidget { ), ), ), + ListTile( + contentPadding: EdgeInsets.zero, + leading: const Icon(Icons.auto_awesome_outlined), + title: const Text('Metadata fetching'), + subtitle: const Text('app_metadata_feature_enabled'), + trailing: Text( + _enabledDisabledLabel( + sheetContext, + runtimeConfig.metadataFeatureEnabled, + ), + ), + ), ListTile( contentPadding: EdgeInsets.zero, leading: const Icon(Icons.hub_outlined), diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_metadata_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_metadata_screen.dart new file mode 100644 index 0000000..e549cda --- /dev/null +++ b/apps/mobile/lib/features/settings/presentation/views/settings_metadata_screen.dart @@ -0,0 +1,184 @@ +import 'package:collection_tracker/core/providers/metadata_preferences_provider.dart'; +import 'package:collection_tracker/core/providers/metadata_providers.dart'; +import 'package:collection_tracker/l10n/l10n.dart'; +import 'package:domain/domain.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:ui/ui.dart'; + +import '../widgets/settings_primitives.dart'; + +class SettingsMetadataScreen extends ConsumerWidget { + const SettingsMetadataScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final l10n = context.l10n; + final preferences = ref.watch(metadataPreferencesProvider); + final notifier = ref.read(metadataPreferencesProvider.notifier); + final metadataService = ref.read(metadataLookupServiceProvider); + + final canConfigure = preferences.runtimeFeatureEnabled; + final canTuneAutofill = preferences.isEnabled; + + return Scaffold( + appBar: AppBar(title: Text(l10n.settingsMetadataTitle)), + body: ListView( + padding: const EdgeInsets.fromLTRB( + AppSpacing.lg, + AppSpacing.md, + AppSpacing.lg, + AppSpacing.xxl, + ), + children: [ + AppReveal( + child: AppCard( + child: Text( + _statusMessage(context, preferences), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + ), + const SizedBox(height: AppSpacing.lg), + AppReveal( + delay: AppMotion.stagger, + child: SettingsSection( + title: l10n.settingsSectionGeneral, + children: [ + SwitchListTile( + contentPadding: const EdgeInsets.symmetric( + horizontal: AppSpacing.md, + ), + title: Text(l10n.settingsMetadataEnableToggleTitle), + subtitle: Text(l10n.settingsMetadataEnableToggleSubtitle), + value: preferences.preferenceEnabled, + onChanged: canConfigure + ? notifier.setPreferenceEnabled + : null, + ), + SwitchListTile( + contentPadding: const EdgeInsets.symmetric( + horizontal: AppSpacing.md, + ), + title: Text(l10n.settingsMetadataAutoFetchToggleTitle), + subtitle: Text(l10n.settingsMetadataAutoFetchToggleSubtitle), + value: preferences.autoFetchBarcodeEnabled, + onChanged: canTuneAutofill + ? notifier.setAutoFetchBarcodeEnabled + : null, + ), + SwitchListTile( + contentPadding: const EdgeInsets.symmetric( + horizontal: AppSpacing.md, + ), + title: Text(l10n.settingsMetadataFillEmptyOnlyToggleTitle), + subtitle: Text( + l10n.settingsMetadataFillEmptyOnlyToggleSubtitle, + ), + value: preferences.fillOnlyEmptyFields, + onChanged: canTuneAutofill + ? notifier.setFillOnlyEmptyFields + : null, + ), + ], + ), + ), + const SizedBox(height: AppSpacing.lg), + AppReveal( + delay: AppMotion.stagger * 2, + child: SettingsSection( + title: l10n.settingsMetadataSourcesSectionTitle, + children: [ + _MetadataSourceTile( + icon: Icons.menu_book_rounded, + title: l10n.collectionTypeBooks, + source: 'Google Books', + statusText: l10n.settingsMetadataSourceAvailable, + enabled: true, + ), + _MetadataSourceTile( + icon: Icons.sports_esports_rounded, + title: l10n.collectionTypeGames, + source: 'IGDB', + statusText: + metadataService.supportsSearch(CollectionType.game) + ? l10n.settingsMetadataSourceAvailable + : l10n.settingsMetadataSourceNotConfigured, + enabled: metadataService.supportsSearch(CollectionType.game), + ), + _MetadataSourceTile( + icon: Icons.movie_creation_rounded, + title: l10n.collectionTypeMovies, + source: 'TMDB', + statusText: + metadataService.supportsSearch(CollectionType.movie) + ? l10n.settingsMetadataSourceAvailable + : l10n.settingsMetadataSourceNotConfigured, + enabled: metadataService.supportsSearch(CollectionType.movie), + ), + _MetadataSourceTile( + icon: Icons.category_rounded, + title: l10n.collectionTypeCustom, + source: l10n.settingsMetadataManualCollectionsLabel, + statusText: l10n.settingsMetadataSourceManualOnly, + enabled: false, + ), + ], + ), + ), + ], + ), + ); + } + + String _statusMessage( + BuildContext context, + MetadataPreferencesState preferences, + ) { + final l10n = context.l10n; + if (!preferences.runtimeFeatureEnabled) { + return l10n.settingsMetadataSummaryFeatureDisabled; + } + if (!preferences.preferenceEnabled) { + return l10n.settingsMetadataSummaryDisabled; + } + return l10n.settingsMetadataSummaryEnabled; + } +} + +class _MetadataSourceTile extends StatelessWidget { + const _MetadataSourceTile({ + required this.icon, + required this.title, + required this.source, + required this.statusText, + required this.enabled, + }); + + final IconData icon; + final String title; + final String source; + final String statusText; + final bool enabled; + + @override + Widget build(BuildContext context) { + final colors = Theme.of(context).colorScheme; + final statusColor = enabled ? colors.primary : colors.onSurfaceVariant; + + return ListTile( + leading: Icon(icon, color: colors.primary), + title: Text(title), + subtitle: Text(source), + trailing: Text( + statusText, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: statusColor, + fontWeight: FontWeight.w600, + ), + ), + ); + } +} diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart index cc6a59b..6cff69d 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart @@ -26,6 +26,7 @@ class SettingsScreen extends ConsumerWidget { final currentLanguage = ref.watch(localeSettingsProvider); final analyticsPreferences = ref.watch(analyticsPreferencesProvider); final pushPreferences = ref.watch(pushNotificationPreferencesProvider); + final metadataPreferences = ref.watch(metadataPreferencesProvider); final syncReadiness = ref.watch(syncReadinessProvider); final accountReadiness = ref.watch(backendAuthReadinessProvider); final pendingSyncCount = ref.watch(syncOutboxCountProvider).value ?? 0; @@ -42,6 +43,7 @@ class SettingsScreen extends ConsumerWidget { pendingSyncCount: pendingSyncCount, ); final pushSummary = _pushNotificationSummary(pushPreferences); + final metadataSummary = _metadataSummary(context, metadataPreferences); final cloudSyncFeatureEnabled = syncReadiness.status != SyncReadinessStatus.disabledByFeatureFlag; @@ -101,6 +103,12 @@ class SettingsScreen extends ConsumerWidget { subtitle: pushSummary, onTap: () => context.push(Routes.settingsNotifications), ), + SettingsTile( + icon: Icons.auto_awesome_outlined, + title: l10n.settingsMetadataTitle, + subtitle: metadataSummary, + onTap: () => context.push(Routes.settingsMetadata), + ), ], ), ), @@ -889,4 +897,21 @@ class SettingsScreen extends ConsumerWidget { return 'Enabled ($enabledTopics topics)'; } + + String _metadataSummary( + BuildContext context, + MetadataPreferencesState preferences, + ) { + final l10n = context.l10n; + if (!preferences.runtimeFeatureEnabled) { + return l10n.settingsMetadataSummaryFeatureDisabled; + } + if (!preferences.preferenceEnabled) { + return l10n.settingsMetadataSummaryDisabled; + } + if (!preferences.autoFetchBarcodeEnabled) { + return l10n.settingsMetadataSummaryManual; + } + return l10n.settingsMetadataSummaryEnabled; + } } diff --git a/apps/mobile/lib/l10n/arb/app_en.arb b/apps/mobile/lib/l10n/arb/app_en.arb index 816820a..db6f32d 100644 --- a/apps/mobile/lib/l10n/arb/app_en.arb +++ b/apps/mobile/lib/l10n/arb/app_en.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "Inspect and refresh runtime feature flags", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "Metadata & Autofill", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "Enabled with automatic barcode lookup", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "Enabled with manual lookup", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "Disabled", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "Disabled by runtime feature flag", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "Enable metadata assistance", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "Allow metadata search and barcode-based autofill in item forms.", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "Auto-fetch from barcode scan", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "After scanning a barcode, fetch metadata automatically.", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "Fill empty fields only", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "Do not overwrite existing title or description when metadata is found.", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "Sources", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "Available", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "Not configured", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "Manual only", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "Comics, Music, and Custom", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "Metadata assistance is disabled by runtime configuration.", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Firebase Runtime Config", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "Values are fetched from Firebase Remote Config and applied at runtime.", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "Start typing to look up metadata.", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "Metadata search is unavailable for this collection type or currently disabled.", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "No metadata match found for this barcode.", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "Metadata search is unavailable for {collectionType}.", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "Tag: {tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "Clear", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "Due date", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "Account", + "@authTitleAccount": {}, + "authCreateAccountHeading": "Create Account", + "@authCreateAccountHeading": {}, + "authSignInHeading": "Sign In", + "@authSignInHeading": {}, + "authCreateAccountDescription": "Create an account to sync your collections across devices.", + "@authCreateAccountDescription": {}, + "authSignInDescription": "Sign in to enable cloud sync and account features.", + "@authSignInDescription": {}, + "authSignInChoice": "Sign in", + "@authSignInChoice": {}, + "authRegisterChoice": "Register", + "@authRegisterChoice": {}, + "authEmailLabel": "Email", + "@authEmailLabel": {}, + "authEmailHint": "you@example.com", + "@authEmailHint": {}, + "authEmailRequiredError": "Email is required.", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "Enter a valid email.", + "@authEmailInvalidError": {}, + "authPasswordLabel": "Password", + "@authPasswordLabel": {}, + "authPasswordHint": "Min 8 chars, A-Z, a-z, 0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "Password is required.", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "Password must be at least 8 characters.", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "Password must include uppercase, lowercase, and number.", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "Display Name (optional)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "How should we call you?", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "Create account", + "@authCreateAccountAction": {}, + "authNotNowAction": "Not now", + "@authNotNowAction": {}, + "authUnavailableMessage": "Authentication is currently unavailable.", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "Account created and signed in.", + "@authRegisterSuccess": {}, + "authSignInSuccess": "Signed in successfully.", + "@authSignInSuccess": {}, + "authSignInFailed": "Sign-in failed: {error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "Signed out.", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "Final confirmation", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "Submit account deletion request now? You will be signed out immediately from this device.", + "@authFinalConfirmationMessage": {}, + "authBackAction": "Back", + "@authBackAction": {}, + "authSubmitRequestAction": "Submit Request", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "Account deletion request submitted. You have been signed out.", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "Deletion request endpoint is not configured on backend yet.", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "Before requesting account deletion", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "Please review the impact carefully.", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "Irreversible request", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "Your account session is revoked immediately on request.", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "Synced cloud data linked to this account may be permanently deleted during processing.", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "Deleted account data cannot be restored once processed.", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "I understand", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "Use English keyboard letters and digits (A-Z, a-z, 0-9).", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "Account connected", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "Signed in and ready for cloud sync", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "Active", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "Session details", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "User ID", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "Device ID", + "@authDeviceIdLabel": {}, + "authUnknownValue": "Unknown", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "Account deletion notice", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "Deletion requests are irreversible once processed.", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "Account profile and active sessions will be removed from cloud access.", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "Synced collections, items, tags, and loans may be permanently deleted.", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "Request account deletion", + "@authRequestDeletionAction": {}, + "authSignOutAction": "Sign out", + "@authSignOutAction": {}, + "authDoneAction": "Done", + "@authDoneAction": {}, + "authHeaderCreateTitle": "Create your account", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "Welcome back", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "Accounts are optional, but required for cloud sync and multi-device access.", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "Sign in to access cloud sync and account-based features.", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "Authentication unavailable", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/arb/app_es.arb b/apps/mobile/lib/l10n/arb/app_es.arb index 1f8739a..bc5324c 100644 --- a/apps/mobile/lib/l10n/arb/app_es.arb +++ b/apps/mobile/lib/l10n/arb/app_es.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "Inspecciona y actualiza las banderas de ejecución", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "Metadatos y Autorrelleno", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "Activado con búsqueda automática por código de barras", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "Activado con búsqueda manual", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "Desactivado", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "Desactivado por bandera de ejecución", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "Activar asistencia de metadatos", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "Permite la búsqueda de metadatos y el autorrelleno por código de barras en formularios de artículos.", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "Buscar automáticamente al escanear código", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "Después de escanear un código de barras, obtiene metadatos automáticamente.", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "Rellenar solo campos vacíos", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "No sobrescribe el título ni la descripción existentes cuando se encuentran metadatos.", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "Fuentes", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "Disponible", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "Sin configurar", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "Solo manual", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "Cómics, Música y Personalizado", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "La asistencia de metadatos está desactivada por configuración de ejecución.", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Configuración de ejecución de Firebase", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "Los valores se obtienen de Firebase Remote Config y se aplican en tiempo de ejecución.", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "Empieza a escribir para buscar metadatos.", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "La búsqueda de metadatos no está disponible para este tipo de colección o está desactivada.", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "No se encontraron metadatos para este código de barras.", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "La búsqueda de metadatos no está disponible para {collectionType}.", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "Etiqueta: {tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "Limpiar", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "Fecha de vencimiento", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "Cuenta", + "@authTitleAccount": {}, + "authCreateAccountHeading": "Crear cuenta", + "@authCreateAccountHeading": {}, + "authSignInHeading": "Iniciar sesión", + "@authSignInHeading": {}, + "authCreateAccountDescription": "Crea una cuenta para sincronizar tus colecciones entre dispositivos.", + "@authCreateAccountDescription": {}, + "authSignInDescription": "Inicia sesión para habilitar la sincronización en la nube y funciones de cuenta.", + "@authSignInDescription": {}, + "authSignInChoice": "Iniciar sesión", + "@authSignInChoice": {}, + "authRegisterChoice": "Registrarse", + "@authRegisterChoice": {}, + "authEmailLabel": "Correo electrónico", + "@authEmailLabel": {}, + "authEmailHint": "tu@ejemplo.com", + "@authEmailHint": {}, + "authEmailRequiredError": "El correo electrónico es obligatorio.", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "Introduce un correo electrónico válido.", + "@authEmailInvalidError": {}, + "authPasswordLabel": "Contraseña", + "@authPasswordLabel": {}, + "authPasswordHint": "Mín. 8 caracteres, A-Z, a-z, 0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "La contraseña es obligatoria.", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "La contraseña debe tener al menos 8 caracteres.", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "La contraseña debe incluir mayúsculas, minúsculas y números.", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "Nombre para mostrar (opcional)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "¿Cómo debemos llamarte?", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "Crear cuenta", + "@authCreateAccountAction": {}, + "authNotNowAction": "Ahora no", + "@authNotNowAction": {}, + "authUnavailableMessage": "La autenticación no está disponible en este momento.", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "Cuenta creada e inicio de sesión completado.", + "@authRegisterSuccess": {}, + "authSignInSuccess": "Inicio de sesión exitoso.", + "@authSignInSuccess": {}, + "authSignInFailed": "Error al iniciar sesión: {error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "Sesión cerrada.", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "Confirmación final", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "¿Enviar solicitud de eliminación de cuenta ahora? Se cerrará la sesión de inmediato en este dispositivo.", + "@authFinalConfirmationMessage": {}, + "authBackAction": "Atrás", + "@authBackAction": {}, + "authSubmitRequestAction": "Enviar solicitud", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "Solicitud de eliminación enviada. Se cerró tu sesión.", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "El endpoint de solicitud de eliminación aún no está configurado en el backend.", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "Antes de solicitar la eliminación de la cuenta", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "Revisa cuidadosamente el impacto.", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "Solicitud irreversible", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "La sesión de tu cuenta se revoca inmediatamente al solicitarla.", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "Los datos sincronizados en la nube vinculados a esta cuenta pueden eliminarse permanentemente durante el proceso.", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "Los datos eliminados de la cuenta no se pueden restaurar una vez procesados.", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "Entiendo", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "Usa letras y dígitos del teclado en inglés (A-Z, a-z, 0-9).", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "Cuenta conectada", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "Sesión iniciada y lista para sincronización en la nube", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "Activa", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "Detalles de la sesión", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "ID de usuario", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "ID del dispositivo", + "@authDeviceIdLabel": {}, + "authUnknownValue": "Desconocido", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "Aviso de eliminación de cuenta", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "Las solicitudes de eliminación son irreversibles una vez procesadas.", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "El perfil de la cuenta y las sesiones activas se eliminarán del acceso en la nube.", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "Las colecciones, artículos, etiquetas y préstamos sincronizados pueden eliminarse permanentemente.", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "Solicitar eliminación de cuenta", + "@authRequestDeletionAction": {}, + "authSignOutAction": "Cerrar sesión", + "@authSignOutAction": {}, + "authDoneAction": "Listo", + "@authDoneAction": {}, + "authHeaderCreateTitle": "Crea tu cuenta", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "Bienvenido de nuevo", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "Las cuentas son opcionales, pero necesarias para sincronización en la nube y acceso multidispositivo.", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "Inicia sesión para acceder a sincronización en la nube y funciones de cuenta.", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "Autenticación no disponible", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/arb/app_id.arb b/apps/mobile/lib/l10n/arb/app_id.arb index d9c3a15..a8ffbc0 100644 --- a/apps/mobile/lib/l10n/arb/app_id.arb +++ b/apps/mobile/lib/l10n/arb/app_id.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "Periksa dan segarkan flag fitur runtime", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "Metadata & Isi Otomatis", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "Aktif dengan pencarian barcode otomatis", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "Aktif dengan pencarian manual", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "Nonaktif", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "Dinonaktifkan oleh flag fitur runtime", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "Aktifkan bantuan metadata", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "Izinkan pencarian metadata dan isi otomatis berbasis barcode pada formulir item.", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "Ambil otomatis saat barcode dipindai", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "Setelah barcode dipindai, metadata diambil secara otomatis.", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "Isi hanya kolom kosong", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "Jangan menimpa judul atau deskripsi yang sudah ada saat metadata ditemukan.", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "Sumber", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "Tersedia", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "Belum dikonfigurasi", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "Manual saja", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "Komik, Musik, dan Kustom", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "Bantuan metadata dinonaktifkan oleh konfigurasi runtime.", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Konfigurasi Runtime Firebase", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "Nilai diambil dari Firebase Remote Config dan diterapkan saat runtime.", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "Mulai mengetik untuk mencari metadata.", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "Pencarian metadata tidak tersedia untuk tipe koleksi ini atau sedang dinonaktifkan.", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "Tidak ditemukan metadata yang cocok untuk barcode ini.", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "Pencarian metadata tidak tersedia untuk {collectionType}.", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "Tag: {tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "Hapus", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "Tanggal jatuh tempo", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "Akun", + "@authTitleAccount": {}, + "authCreateAccountHeading": "Buat Akun", + "@authCreateAccountHeading": {}, + "authSignInHeading": "Masuk", + "@authSignInHeading": {}, + "authCreateAccountDescription": "Buat akun untuk menyinkronkan koleksi Anda di berbagai perangkat.", + "@authCreateAccountDescription": {}, + "authSignInDescription": "Masuk untuk mengaktifkan sinkronisasi cloud dan fitur akun.", + "@authSignInDescription": {}, + "authSignInChoice": "Masuk", + "@authSignInChoice": {}, + "authRegisterChoice": "Daftar", + "@authRegisterChoice": {}, + "authEmailLabel": "Email", + "@authEmailLabel": {}, + "authEmailHint": "anda@contoh.com", + "@authEmailHint": {}, + "authEmailRequiredError": "Email wajib diisi.", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "Masukkan email yang valid.", + "@authEmailInvalidError": {}, + "authPasswordLabel": "Kata sandi", + "@authPasswordLabel": {}, + "authPasswordHint": "Min 8 karakter, A-Z, a-z, 0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "Kata sandi wajib diisi.", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "Kata sandi minimal 8 karakter.", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "Kata sandi harus mengandung huruf besar, huruf kecil, dan angka.", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "Nama tampilan (opsional)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "Kami memanggil Anda dengan nama apa?", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "Buat akun", + "@authCreateAccountAction": {}, + "authNotNowAction": "Nanti saja", + "@authNotNowAction": {}, + "authUnavailableMessage": "Autentikasi sedang tidak tersedia.", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "Akun berhasil dibuat dan Anda sudah masuk.", + "@authRegisterSuccess": {}, + "authSignInSuccess": "Berhasil masuk.", + "@authSignInSuccess": {}, + "authSignInFailed": "Gagal masuk: {error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "Berhasil keluar.", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "Konfirmasi akhir", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "Kirim permintaan penghapusan akun sekarang? Anda akan langsung keluar dari perangkat ini.", + "@authFinalConfirmationMessage": {}, + "authBackAction": "Kembali", + "@authBackAction": {}, + "authSubmitRequestAction": "Kirim Permintaan", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "Permintaan penghapusan akun dikirim. Anda telah keluar.", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "Endpoint permintaan penghapusan belum dikonfigurasi di backend.", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "Sebelum meminta penghapusan akun", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "Tinjau dampaknya dengan saksama.", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "Permintaan tidak dapat dibatalkan", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "Sesi akun Anda dicabut segera setelah permintaan dikirim.", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "Data cloud tersinkron yang terkait akun ini dapat dihapus permanen saat diproses.", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "Data akun yang sudah dihapus tidak dapat dipulihkan setelah diproses.", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "Saya mengerti", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "Gunakan huruf dan angka keyboard Inggris (A-Z, a-z, 0-9).", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "Akun terhubung", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "Sudah masuk dan siap untuk sinkronisasi cloud", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "Aktif", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "Detail sesi", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "ID Pengguna", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "ID Perangkat", + "@authDeviceIdLabel": {}, + "authUnknownValue": "Tidak diketahui", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "Pemberitahuan penghapusan akun", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "Permintaan penghapusan bersifat permanen setelah diproses.", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "Profil akun dan sesi aktif akan dihapus dari akses cloud.", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "Koleksi, item, tag, dan pinjaman tersinkron dapat dihapus permanen.", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "Minta penghapusan akun", + "@authRequestDeletionAction": {}, + "authSignOutAction": "Keluar", + "@authSignOutAction": {}, + "authDoneAction": "Selesai", + "@authDoneAction": {}, + "authHeaderCreateTitle": "Buat akun Anda", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "Selamat datang kembali", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "Akun bersifat opsional, tetapi diperlukan untuk sinkronisasi cloud dan akses multi-perangkat.", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "Masuk untuk menggunakan sinkronisasi cloud dan fitur berbasis akun.", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "Autentikasi tidak tersedia", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/arb/app_ja.arb b/apps/mobile/lib/l10n/arb/app_ja.arb index f77258c..c61a606 100644 --- a/apps/mobile/lib/l10n/arb/app_ja.arb +++ b/apps/mobile/lib/l10n/arb/app_ja.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "ランタイム機能フラグを確認して更新", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "メタデータと自動入力", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "バーコード自動検索で有効", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "手動検索で有効", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "無効", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "実行時の機能フラグにより無効", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "メタデータ補助を有効化", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "アイテムフォームでメタデータ検索とバーコード自動入力を利用します。", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "バーコード読み取り時に自動取得", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "バーコードを読み取った後、メタデータを自動取得します。", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "空欄のみ入力", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "メタデータ検出時に既存のタイトルや説明を上書きしません。", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "ソース", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "利用可能", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "未設定", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "手動のみ", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "コミック・音楽・カスタム", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "メタデータ補助は実行時設定で無効化されています。", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Firebase ランタイム設定", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "値は Firebase Remote Config から取得され、実行時に適用されます。", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "入力してメタデータを検索してください。", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "このコレクション種別ではメタデータ検索が利用できないか、現在無効です。", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "このバーコードに一致するメタデータが見つかりません。", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "{collectionType} ではメタデータ検索を利用できません。", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "タグ: {tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "クリア", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "返却期限", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "アカウント", + "@authTitleAccount": {}, + "authCreateAccountHeading": "アカウント作成", + "@authCreateAccountHeading": {}, + "authSignInHeading": "サインイン", + "@authSignInHeading": {}, + "authCreateAccountDescription": "アカウントを作成すると、コレクションを複数端末で同期できます。", + "@authCreateAccountDescription": {}, + "authSignInDescription": "サインインするとクラウド同期とアカウント機能を利用できます。", + "@authSignInDescription": {}, + "authSignInChoice": "サインイン", + "@authSignInChoice": {}, + "authRegisterChoice": "登録", + "@authRegisterChoice": {}, + "authEmailLabel": "メールアドレス", + "@authEmailLabel": {}, + "authEmailHint": "you@example.com", + "@authEmailHint": {}, + "authEmailRequiredError": "メールアドレスは必須です。", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "有効なメールアドレスを入力してください。", + "@authEmailInvalidError": {}, + "authPasswordLabel": "パスワード", + "@authPasswordLabel": {}, + "authPasswordHint": "8文字以上、A-Z、a-z、0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "パスワードは必須です。", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "パスワードは8文字以上で入力してください。", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "パスワードには大文字、小文字、数字を含めてください。", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "表示名(任意)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "呼び名を入力してください", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "アカウントを作成", + "@authCreateAccountAction": {}, + "authNotNowAction": "今はしない", + "@authNotNowAction": {}, + "authUnavailableMessage": "認証は現在利用できません。", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "アカウントを作成してサインインしました。", + "@authRegisterSuccess": {}, + "authSignInSuccess": "サインインしました。", + "@authSignInSuccess": {}, + "authSignInFailed": "サインインに失敗しました: {error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "サインアウトしました。", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "最終確認", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "今すぐアカウント削除リクエストを送信しますか?この端末では直ちにサインアウトされます。", + "@authFinalConfirmationMessage": {}, + "authBackAction": "戻る", + "@authBackAction": {}, + "authSubmitRequestAction": "リクエストを送信", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "アカウント削除リクエストを送信しました。サインアウトされました。", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "削除リクエストのエンドポイントがバックエンドにまだ設定されていません。", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "アカウント削除をリクエストする前に", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "影響をよくご確認ください。", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "取り消し不可のリクエスト", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "リクエスト送信後、アカウントセッションはすぐに無効化されます。", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "このアカウントに紐づく同期済みクラウドデータは、処理中に完全削除される可能性があります。", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "削除されたアカウントデータは処理後に復元できません。", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "理解しました", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "英字キーボードの文字と数字(A-Z、a-z、0-9)を使用してください。", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "アカウント接続済み", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "サインイン済みでクラウド同期の準備ができています", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "有効", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "セッション詳細", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "ユーザーID", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "デバイスID", + "@authDeviceIdLabel": {}, + "authUnknownValue": "不明", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "アカウント削除に関する注意", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "削除リクエストは処理されると元に戻せません。", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "アカウントプロフィールと有効なセッションはクラウドアクセスから削除されます。", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "同期済みのコレクション、アイテム、タグ、貸出データは完全に削除される可能性があります。", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "アカウント削除をリクエスト", + "@authRequestDeletionAction": {}, + "authSignOutAction": "サインアウト", + "@authSignOutAction": {}, + "authDoneAction": "完了", + "@authDoneAction": {}, + "authHeaderCreateTitle": "アカウントを作成", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "おかえりなさい", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "アカウントは任意ですが、クラウド同期と複数端末アクセスには必要です。", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "サインインしてクラウド同期とアカウント機能を利用しましょう。", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "認証を利用できません", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/arb/app_ko.arb b/apps/mobile/lib/l10n/arb/app_ko.arb index f1cc107..942e025 100644 --- a/apps/mobile/lib/l10n/arb/app_ko.arb +++ b/apps/mobile/lib/l10n/arb/app_ko.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "런타임 기능 플래그 확인 및 새로고침", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "메타데이터 및 자동완성", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "자동 바코드 조회로 사용 중", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "수동 조회로 사용 중", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "사용 안 함", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "런타임 기능 플래그로 비활성화됨", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "메타데이터 보조 사용", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "아이템 폼에서 메타데이터 검색과 바코드 자동완성을 허용합니다.", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "바코드 스캔 시 자동 조회", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "바코드를 스캔한 뒤 메타데이터를 자동으로 가져옵니다.", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "빈 필드만 채우기", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "메타데이터를 찾았을 때 기존 제목이나 설명을 덮어쓰지 않습니다.", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "소스", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "사용 가능", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "미설정", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "수동만", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "코믹, 음악 및 사용자 지정", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "메타데이터 보조가 런타임 구성으로 비활성화되었습니다.", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Firebase 런타임 구성", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "값은 Firebase Remote Config에서 가져와 런타임에 적용됩니다.", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "메타데이터를 찾으려면 입력하세요.", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "이 컬렉션 유형에서는 메타데이터 검색을 사용할 수 없거나 현재 비활성화되어 있습니다.", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "이 바코드와 일치하는 메타데이터를 찾지 못했습니다.", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "{collectionType}에는 메타데이터 검색을 사용할 수 없습니다.", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "태그: {tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "지우기", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "반납 예정일", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "계정", + "@authTitleAccount": {}, + "authCreateAccountHeading": "계정 만들기", + "@authCreateAccountHeading": {}, + "authSignInHeading": "로그인", + "@authSignInHeading": {}, + "authCreateAccountDescription": "계정을 만들어 컬렉션을 여러 기기에서 동기화하세요.", + "@authCreateAccountDescription": {}, + "authSignInDescription": "로그인하면 클라우드 동기화와 계정 기능을 사용할 수 있습니다.", + "@authSignInDescription": {}, + "authSignInChoice": "로그인", + "@authSignInChoice": {}, + "authRegisterChoice": "회원가입", + "@authRegisterChoice": {}, + "authEmailLabel": "이메일", + "@authEmailLabel": {}, + "authEmailHint": "you@example.com", + "@authEmailHint": {}, + "authEmailRequiredError": "이메일은 필수입니다.", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "유효한 이메일을 입력하세요.", + "@authEmailInvalidError": {}, + "authPasswordLabel": "비밀번호", + "@authPasswordLabel": {}, + "authPasswordHint": "최소 8자, A-Z, a-z, 0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "비밀번호는 필수입니다.", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "비밀번호는 최소 8자 이상이어야 합니다.", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "비밀번호에는 대문자, 소문자, 숫자가 포함되어야 합니다.", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "표시 이름 (선택)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "어떻게 불러드릴까요?", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "계정 만들기", + "@authCreateAccountAction": {}, + "authNotNowAction": "나중에", + "@authNotNowAction": {}, + "authUnavailableMessage": "현재 인증을 사용할 수 없습니다.", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "계정이 생성되었고 로그인되었습니다.", + "@authRegisterSuccess": {}, + "authSignInSuccess": "로그인되었습니다.", + "@authSignInSuccess": {}, + "authSignInFailed": "로그인 실패: {error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "로그아웃되었습니다.", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "최종 확인", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "지금 계정 삭제 요청을 제출할까요? 이 기기에서 즉시 로그아웃됩니다.", + "@authFinalConfirmationMessage": {}, + "authBackAction": "뒤로", + "@authBackAction": {}, + "authSubmitRequestAction": "요청 제출", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "계정 삭제 요청이 제출되었습니다. 로그아웃되었습니다.", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "계정 삭제 요청 엔드포인트가 아직 백엔드에 구성되지 않았습니다.", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "계정 삭제를 요청하기 전에", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "영향을 신중히 확인해 주세요.", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "되돌릴 수 없는 요청", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "요청 즉시 계정 세션이 취소됩니다.", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "이 계정과 연결된 동기화 클라우드 데이터는 처리 중 영구 삭제될 수 있습니다.", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "삭제된 계정 데이터는 처리 후 복구할 수 없습니다.", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "이해했습니다", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "영문 키보드 문자와 숫자(A-Z, a-z, 0-9)를 사용하세요.", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "계정 연결됨", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "로그인되어 클라우드 동기화 준비 완료", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "활성", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "세션 정보", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "사용자 ID", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "기기 ID", + "@authDeviceIdLabel": {}, + "authUnknownValue": "알 수 없음", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "계정 삭제 안내", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "삭제 요청은 처리되면 되돌릴 수 없습니다.", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "계정 프로필과 활성 세션은 클라우드 접근에서 제거됩니다.", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "동기화된 컬렉션, 항목, 태그, 대여 데이터가 영구 삭제될 수 있습니다.", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "계정 삭제 요청", + "@authRequestDeletionAction": {}, + "authSignOutAction": "로그아웃", + "@authSignOutAction": {}, + "authDoneAction": "완료", + "@authDoneAction": {}, + "authHeaderCreateTitle": "계정을 만들어 보세요", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "다시 오신 것을 환영합니다", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "계정은 선택 사항이지만 클라우드 동기화와 다중 기기 접근에 필요합니다.", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "로그인하여 클라우드 동기화와 계정 기능을 사용하세요.", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "인증을 사용할 수 없음", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/arb/app_my.arb b/apps/mobile/lib/l10n/arb/app_my.arb index bdea14d..89e7754 100644 --- a/apps/mobile/lib/l10n/arb/app_my.arb +++ b/apps/mobile/lib/l10n/arb/app_my.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "runtime feature flags ကို စစ်ဆေးပြီး refresh လုပ်ပါ", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "Metadata နှင့် Auto-fill", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "Barcode အလိုအလျောက်ရှာဖွေမှုဖြင့် ဖွင့်ထားသည်", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "လက်ဖြင့်ရှာဖွေမှုဖြင့် ဖွင့်ထားသည်", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "ပိတ်ထားသည်", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "Runtime feature flag ကြောင့် ပိတ်ထားသည်", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "Metadata အကူအညီ ဖွင့်မည်", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "Item form များတွင် metadata ရှာဖွေမှုနှင့် barcode auto-fill ကို ခွင့်ပြုပါသည်။", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "Barcode scan ပြီးနောက် အလိုအလျောက် ရယူမည်", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "Barcode scan ပြီးနောက် metadata ကို အလိုအလျောက် ရယူပါသည်။", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "လွတ်နေသော fields များကိုသာ ဖြည့်မည်", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "Metadata တွေ့ရှိသောအခါ ရှိပြီးသား title သို့မဟုတ် description ကို မရေးကျော်ပါ။", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "Sources", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "အသုံးပြုနိုင်သည်", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "မသတ်မှတ်ရသေးပါ", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "လက်ဖြင့်သာ", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "Comics, Music နှင့် Custom", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "Metadata အကူအညီကို runtime configuration ဖြင့် ပိတ်ထားသည်။", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Firebase Runtime Config", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "values တွေကို Firebase Remote Config မှ ရယူပြီး runtime တွင် apply လုပ်ပါသည်။", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "Start typing to look up metadata.", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "ဤ collection type အတွက် metadata ရှာဖွေမှု မရနိုင်ပါ သို့မဟုတ် လက်ရှိပိတ်ထားသည်။", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "ဤ barcode အတွက် ကိုက်ညီသော metadata မတွေ့ပါ။", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "{collectionType} အတွက် metadata ရှာဖွေမှု မရနိုင်ပါ။", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "Tag: {tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "ရှင်းမည်", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "ပြန်အပ်ရမည့်နေ့", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "အကောင့်", + "@authTitleAccount": {}, + "authCreateAccountHeading": "အကောင့် ဖန်တီးရန်", + "@authCreateAccountHeading": {}, + "authSignInHeading": "ဝင်မည်", + "@authSignInHeading": {}, + "authCreateAccountDescription": "စက်များအကြား စုစည်းမှုများကို sync လုပ်ရန် အကောင့်တစ်ခု ဖန်တီးပါ။", + "@authCreateAccountDescription": {}, + "authSignInDescription": "Cloud sync နှင့် အကောင့်ဆိုင်ရာ လုပ်ဆောင်ချက်များအသုံးပြုရန် ဝင်ပါ။", + "@authSignInDescription": {}, + "authSignInChoice": "ဝင်မည်", + "@authSignInChoice": {}, + "authRegisterChoice": "မှတ်ပုံတင်မည်", + "@authRegisterChoice": {}, + "authEmailLabel": "အီးမေးလ်", + "@authEmailLabel": {}, + "authEmailHint": "you@example.com", + "@authEmailHint": {}, + "authEmailRequiredError": "အီးမေးလ် မဖြစ်မနေလိုအပ်သည်။", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "မှန်ကန်သော အီးမေးလ် ထည့်ပါ။", + "@authEmailInvalidError": {}, + "authPasswordLabel": "လျှို့ဝှက်နံပါတ်", + "@authPasswordLabel": {}, + "authPasswordHint": "အနည်းဆုံး ၈ လုံး၊ A-Z, a-z, 0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "လျှို့ဝှက်နံပါတ် မဖြစ်မနေလိုအပ်သည်။", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "လျှို့ဝှက်နံပါတ်မှာ အနည်းဆုံး ၈ လုံး ရှိရမည်။", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "လျှို့ဝှက်နံပါတ်တွင် စာလုံးကြီး၊ စာလုံးသေးနှင့် ဂဏန်း ပါဝင်ရမည်။", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "ပြသမည့်အမည် (မဖြည့်လည်းရ)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "သင့်ကို ဘယ်လိုခေါ်မလဲ?", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "အကောင့်ဖန်တီးမည်", + "@authCreateAccountAction": {}, + "authNotNowAction": "အခုမလုပ်တော့", + "@authNotNowAction": {}, + "authUnavailableMessage": "ယခု အတည်ပြုဝင်ရောက်မှု မရနိုင်သေးပါ။", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "အကောင့် ဖန်တီးပြီး ဝင်ရောက်ပြီးပါပြီ။", + "@authRegisterSuccess": {}, + "authSignInSuccess": "ဝင်ရောက်မှု အောင်မြင်သည်။", + "@authSignInSuccess": {}, + "authSignInFailed": "ဝင်ရောက်မှု မအောင်မြင်ပါ: {error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "ထွက်ပြီးပါပြီ။", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "နောက်ဆုံးအတည်ပြုချက်", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "အကောင့်ဖျက်ရန် တောင်းဆိုချက်ကို ယခု ပို့မလား? ဒီစက်တွင် ချက်ချင်း ထွက်သွားပါမည်။", + "@authFinalConfirmationMessage": {}, + "authBackAction": "နောက်သို့", + "@authBackAction": {}, + "authSubmitRequestAction": "တောင်းဆိုချက် ပို့မည်", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "အကောင့်ဖျက်ရန် တောင်းဆိုချက် ပို့ပြီးပါပြီ။ သင့်ကို ထွက်ပေးလိုက်ပါပြီ။", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "ဖျက်ရန် တောင်းဆို endpoint ကို backend တွင် မသတ်မှတ်ရသေးပါ။", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "အကောင့်ဖျက်ရန် တောင်းဆိုမီ", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "သက်ရောက်မှုကို သေချာစွာ စစ်ဆေးပါ။", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "ပြန်မယူနိုင်သော တောင်းဆိုချက်", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "တောင်းဆိုပြီးချင်း သင့်အကောင့် session ကို ပိတ်ပါမည်။", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "ဒီအကောင့်နှင့်ချိတ်ဆက်ထားသော sync cloud ဒေတာများကို လုပ်ဆောင်နေစဉ် အပြီးအပိုင် ဖျက်နိုင်ပါသည်။", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "ဖျက်ပြီးသော အကောင့်ဒေတာကို လုပ်ဆောင်ပြီးနောက် ပြန်မရနိုင်ပါ။", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "နားလည်ပါသည်", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "အင်္ဂလိပ်ကီးဘုတ် စာလုံးများနှင့် ဂဏန်းများ (A-Z, a-z, 0-9) ကို အသုံးပြုပါ။", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "အကောင့် ချိတ်ဆက်ပြီး", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "ဝင်ထားပြီး Cloud sync အတွက် အဆင်သင့်", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "အသုံးပြုနေ", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "Session အသေးစိတ်", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "User ID", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "Device ID", + "@authDeviceIdLabel": {}, + "authUnknownValue": "မသိ", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "အကောင့်ဖျက်ရန် အသိပေးချက်", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "ဖျက်ရန် တောင်းဆိုချက်သည် လုပ်ဆောင်ပြီးပါက ပြန်မရနိုင်ပါ။", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "အကောင့်ပရိုဖိုင်နှင့် active session များကို cloud access မှ ဖယ်ရှားပါမည်။", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "Sync လုပ်ထားသော collections, items, tags နှင့် loans များကို အပြီးအပိုင် ဖျက်နိုင်ပါသည်။", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "အကောင့်ဖျက်ရန် တောင်းဆို", + "@authRequestDeletionAction": {}, + "authSignOutAction": "ထွက်မည်", + "@authSignOutAction": {}, + "authDoneAction": "ပြီးပါပြီ", + "@authDoneAction": {}, + "authHeaderCreateTitle": "သင့်အကောင့် ဖန်တီးပါ", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "ပြန်လည်ကြိုဆိုပါသည်", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "အကောင့်မဖွင့်လည်း ရပါသည်၊ သို့သော် cloud sync နှင့် စက်အများအပြား အသုံးပြုရန် လိုအပ်ပါသည်။", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "Cloud sync နှင့် အကောင့်အခြေပြု လုပ်ဆောင်ချက်များ အသုံးပြုရန် ဝင်ပါ။", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "အတည်ပြုဝင်ရောက်မှု မရနိုင်ပါ", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/arb/app_zh.arb b/apps/mobile/lib/l10n/arb/app_zh.arb index d8be95c..082b69e 100644 --- a/apps/mobile/lib/l10n/arb/app_zh.arb +++ b/apps/mobile/lib/l10n/arb/app_zh.arb @@ -144,6 +144,40 @@ "@settingsFirebaseRuntimeConfigTitle": {}, "settingsFirebaseRuntimeConfigSubtitle": "查看并刷新运行时功能开关", "@settingsFirebaseRuntimeConfigSubtitle": {}, + "settingsMetadataTitle": "元数据与自动填充", + "@settingsMetadataTitle": {}, + "settingsMetadataSummaryEnabled": "已启用(自动条码查询)", + "@settingsMetadataSummaryEnabled": {}, + "settingsMetadataSummaryManual": "已启用(手动查询)", + "@settingsMetadataSummaryManual": {}, + "settingsMetadataSummaryDisabled": "已禁用", + "@settingsMetadataSummaryDisabled": {}, + "settingsMetadataSummaryFeatureDisabled": "已被运行时功能开关禁用", + "@settingsMetadataSummaryFeatureDisabled": {}, + "settingsMetadataEnableToggleTitle": "启用元数据辅助", + "@settingsMetadataEnableToggleTitle": {}, + "settingsMetadataEnableToggleSubtitle": "在条目表单中允许元数据搜索和基于条码的自动填充。", + "@settingsMetadataEnableToggleSubtitle": {}, + "settingsMetadataAutoFetchToggleTitle": "扫描条码后自动获取", + "@settingsMetadataAutoFetchToggleTitle": {}, + "settingsMetadataAutoFetchToggleSubtitle": "扫描条码后自动获取元数据。", + "@settingsMetadataAutoFetchToggleSubtitle": {}, + "settingsMetadataFillEmptyOnlyToggleTitle": "仅填充空字段", + "@settingsMetadataFillEmptyOnlyToggleTitle": {}, + "settingsMetadataFillEmptyOnlyToggleSubtitle": "找到元数据时不覆盖现有标题或描述。", + "@settingsMetadataFillEmptyOnlyToggleSubtitle": {}, + "settingsMetadataSourcesSectionTitle": "数据源", + "@settingsMetadataSourcesSectionTitle": {}, + "settingsMetadataSourceAvailable": "可用", + "@settingsMetadataSourceAvailable": {}, + "settingsMetadataSourceNotConfigured": "未配置", + "@settingsMetadataSourceNotConfigured": {}, + "settingsMetadataSourceManualOnly": "仅手动", + "@settingsMetadataSourceManualOnly": {}, + "settingsMetadataManualCollectionsLabel": "漫画、音乐和自定义", + "@settingsMetadataManualCollectionsLabel": {}, + "settingsMetadataFeatureDisabledMessage": "元数据辅助已被运行时配置禁用。", + "@settingsMetadataFeatureDisabledMessage": {}, "settingsFirebaseRuntimeConfigSheetTitle": "Firebase 运行时配置", "@settingsFirebaseRuntimeConfigSheetTitle": {}, "settingsFirebaseRuntimeConfigDescription": "这些值来自 Firebase Remote Config,并在运行时生效。", @@ -613,6 +647,18 @@ "@metadataSearchSuggestionTitle": {}, "metadataSearchSuggestionMessage": "开始输入以查找元数据。", "@metadataSearchSuggestionMessage": {}, + "metadataSearchDisabledHint": "此集合类型不支持元数据搜索,或当前已禁用。", + "@metadataSearchDisabledHint": {}, + "metadataNoMatchForBarcode": "未找到与此条码匹配的元数据。", + "@metadataNoMatchForBarcode": {}, + "metadataSearchUnavailableForType": "{collectionType} 不支持元数据搜索。", + "@metadataSearchUnavailableForType": { + "placeholders": { + "collectionType": { + "type": "String" + } + } + }, "tagItemsTitle": "标签:{tag}", "@tagItemsTitle": { "placeholders": { @@ -1126,5 +1172,127 @@ "loanTrackingClearDateAction": "清除", "@loanTrackingClearDateAction": {}, "loanTrackingDueDateLabel": "到期日期", - "@loanTrackingDueDateLabel": {} + "@loanTrackingDueDateLabel": {}, + "authTitleAccount": "账户", + "@authTitleAccount": {}, + "authCreateAccountHeading": "创建账户", + "@authCreateAccountHeading": {}, + "authSignInHeading": "登录", + "@authSignInHeading": {}, + "authCreateAccountDescription": "创建账户以在多台设备间同步你的收藏。", + "@authCreateAccountDescription": {}, + "authSignInDescription": "登录以启用云同步和账户功能。", + "@authSignInDescription": {}, + "authSignInChoice": "登录", + "@authSignInChoice": {}, + "authRegisterChoice": "注册", + "@authRegisterChoice": {}, + "authEmailLabel": "邮箱", + "@authEmailLabel": {}, + "authEmailHint": "you@example.com", + "@authEmailHint": {}, + "authEmailRequiredError": "邮箱为必填项。", + "@authEmailRequiredError": {}, + "authEmailInvalidError": "请输入有效的邮箱地址。", + "@authEmailInvalidError": {}, + "authPasswordLabel": "密码", + "@authPasswordLabel": {}, + "authPasswordHint": "至少8位,A-Z、a-z、0-9", + "@authPasswordHint": {}, + "authPasswordRequiredError": "密码为必填项。", + "@authPasswordRequiredError": {}, + "authPasswordLengthError": "密码至少需要8位字符。", + "@authPasswordLengthError": {}, + "authPasswordPolicyError": "密码必须包含大写字母、小写字母和数字。", + "@authPasswordPolicyError": {}, + "authDisplayNameLabel": "显示名称(可选)", + "@authDisplayNameLabel": {}, + "authDisplayNameHint": "我们应该如何称呼你?", + "@authDisplayNameHint": {}, + "authCreateAccountAction": "创建账户", + "@authCreateAccountAction": {}, + "authNotNowAction": "暂不", + "@authNotNowAction": {}, + "authUnavailableMessage": "当前无法使用身份验证。", + "@authUnavailableMessage": {}, + "authRegisterSuccess": "账户已创建并已登录。", + "@authRegisterSuccess": {}, + "authSignInSuccess": "登录成功。", + "@authSignInSuccess": {}, + "authSignInFailed": "登录失败:{error}", + "@authSignInFailed": { + "placeholders": { + "error": { + "type": "String" + } + } + }, + "authSignedOut": "已退出登录。", + "@authSignedOut": {}, + "authFinalConfirmationTitle": "最终确认", + "@authFinalConfirmationTitle": {}, + "authFinalConfirmationMessage": "现在提交账户删除请求吗?你将立即在此设备上退出登录。", + "@authFinalConfirmationMessage": {}, + "authBackAction": "返回", + "@authBackAction": {}, + "authSubmitRequestAction": "提交请求", + "@authSubmitRequestAction": {}, + "authDeletionRequestSubmitted": "账户删除请求已提交。你已退出登录。", + "@authDeletionRequestSubmitted": {}, + "authDeletionEndpointMissing": "后端尚未配置删除请求接口。", + "@authDeletionEndpointMissing": {}, + "authDeletionImpactDialogTitle": "请求删除账户前", + "@authDeletionImpactDialogTitle": {}, + "authDeletionImpactReviewPrompt": "请仔细确认影响。", + "@authDeletionImpactReviewPrompt": {}, + "authIrreversibleRequestTitle": "不可逆请求", + "@authIrreversibleRequestTitle": {}, + "authImpactLineSessionRevoked": "提交请求后,你的账户会话将立即失效。", + "@authImpactLineSessionRevoked": {}, + "authImpactLineCloudDataDeleted": "与该账户关联的云端同步数据在处理过程中可能被永久删除。", + "@authImpactLineCloudDataDeleted": {}, + "authImpactLineCannotRestore": "账户数据一旦删除并处理完成将无法恢复。", + "@authImpactLineCannotRestore": {}, + "authUnderstandAction": "我已了解", + "@authUnderstandAction": {}, + "authPasswordPolicySuffix": "请使用英文键盘字母和数字(A-Z、a-z、0-9)。", + "@authPasswordPolicySuffix": {}, + "authAccountConnected": "账户已连接", + "@authAccountConnected": {}, + "authSignedInReadySubtitle": "已登录并可进行云同步", + "@authSignedInReadySubtitle": {}, + "authActiveStatus": "已激活", + "@authActiveStatus": {}, + "authSessionDetailsTitle": "会话详情", + "@authSessionDetailsTitle": {}, + "authUserIdLabel": "用户 ID", + "@authUserIdLabel": {}, + "authDeviceIdLabel": "设备 ID", + "@authDeviceIdLabel": {}, + "authUnknownValue": "未知", + "@authUnknownValue": {}, + "authDeletionNoticeTitle": "账户删除提示", + "@authDeletionNoticeTitle": {}, + "authDeletionNoticeSubtitle": "删除请求一旦处理即不可撤销。", + "@authDeletionNoticeSubtitle": {}, + "authDeletionNoticeLineProfileSessions": "账户资料和活跃会话将从云端访问中移除。", + "@authDeletionNoticeLineProfileSessions": {}, + "authDeletionNoticeLineSyncedData": "已同步的收藏、条目、标签和借出记录可能被永久删除。", + "@authDeletionNoticeLineSyncedData": {}, + "authRequestDeletionAction": "请求删除账户", + "@authRequestDeletionAction": {}, + "authSignOutAction": "退出登录", + "@authSignOutAction": {}, + "authDoneAction": "完成", + "@authDoneAction": {}, + "authHeaderCreateTitle": "创建你的账户", + "@authHeaderCreateTitle": {}, + "authHeaderWelcomeTitle": "欢迎回来", + "@authHeaderWelcomeTitle": {}, + "authHeaderCreateSubtitle": "账户不是必需的,但云同步和多设备访问需要登录账户。", + "@authHeaderCreateSubtitle": {}, + "authHeaderSignInSubtitle": "登录以使用云同步和账户相关功能。", + "@authHeaderSignInSubtitle": {}, + "authUnavailableTitle": "身份验证不可用", + "@authUnavailableTitle": {} } diff --git a/apps/mobile/lib/l10n/gen/app_localizations.dart b/apps/mobile/lib/l10n/gen/app_localizations.dart index 6f884bb..42662a8 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations.dart @@ -521,6 +521,108 @@ abstract class AppLocalizations { /// **'Inspect and refresh runtime feature flags'** String get settingsFirebaseRuntimeConfigSubtitle; + /// No description provided for @settingsMetadataTitle. + /// + /// In en, this message translates to: + /// **'Metadata & Autofill'** + String get settingsMetadataTitle; + + /// No description provided for @settingsMetadataSummaryEnabled. + /// + /// In en, this message translates to: + /// **'Enabled with automatic barcode lookup'** + String get settingsMetadataSummaryEnabled; + + /// No description provided for @settingsMetadataSummaryManual. + /// + /// In en, this message translates to: + /// **'Enabled with manual lookup'** + String get settingsMetadataSummaryManual; + + /// No description provided for @settingsMetadataSummaryDisabled. + /// + /// In en, this message translates to: + /// **'Disabled'** + String get settingsMetadataSummaryDisabled; + + /// No description provided for @settingsMetadataSummaryFeatureDisabled. + /// + /// In en, this message translates to: + /// **'Disabled by runtime feature flag'** + String get settingsMetadataSummaryFeatureDisabled; + + /// No description provided for @settingsMetadataEnableToggleTitle. + /// + /// In en, this message translates to: + /// **'Enable metadata assistance'** + String get settingsMetadataEnableToggleTitle; + + /// No description provided for @settingsMetadataEnableToggleSubtitle. + /// + /// In en, this message translates to: + /// **'Allow metadata search and barcode-based autofill in item forms.'** + String get settingsMetadataEnableToggleSubtitle; + + /// No description provided for @settingsMetadataAutoFetchToggleTitle. + /// + /// In en, this message translates to: + /// **'Auto-fetch from barcode scan'** + String get settingsMetadataAutoFetchToggleTitle; + + /// No description provided for @settingsMetadataAutoFetchToggleSubtitle. + /// + /// In en, this message translates to: + /// **'After scanning a barcode, fetch metadata automatically.'** + String get settingsMetadataAutoFetchToggleSubtitle; + + /// No description provided for @settingsMetadataFillEmptyOnlyToggleTitle. + /// + /// In en, this message translates to: + /// **'Fill empty fields only'** + String get settingsMetadataFillEmptyOnlyToggleTitle; + + /// No description provided for @settingsMetadataFillEmptyOnlyToggleSubtitle. + /// + /// In en, this message translates to: + /// **'Do not overwrite existing title or description when metadata is found.'** + String get settingsMetadataFillEmptyOnlyToggleSubtitle; + + /// No description provided for @settingsMetadataSourcesSectionTitle. + /// + /// In en, this message translates to: + /// **'Sources'** + String get settingsMetadataSourcesSectionTitle; + + /// No description provided for @settingsMetadataSourceAvailable. + /// + /// In en, this message translates to: + /// **'Available'** + String get settingsMetadataSourceAvailable; + + /// No description provided for @settingsMetadataSourceNotConfigured. + /// + /// In en, this message translates to: + /// **'Not configured'** + String get settingsMetadataSourceNotConfigured; + + /// No description provided for @settingsMetadataSourceManualOnly. + /// + /// In en, this message translates to: + /// **'Manual only'** + String get settingsMetadataSourceManualOnly; + + /// No description provided for @settingsMetadataManualCollectionsLabel. + /// + /// In en, this message translates to: + /// **'Comics, Music, and Custom'** + String get settingsMetadataManualCollectionsLabel; + + /// No description provided for @settingsMetadataFeatureDisabledMessage. + /// + /// In en, this message translates to: + /// **'Metadata assistance is disabled by runtime configuration.'** + String get settingsMetadataFeatureDisabledMessage; + /// No description provided for @settingsFirebaseRuntimeConfigSheetTitle. /// /// In en, this message translates to: @@ -1487,6 +1589,24 @@ abstract class AppLocalizations { /// **'Start typing to look up metadata.'** String get metadataSearchSuggestionMessage; + /// No description provided for @metadataSearchDisabledHint. + /// + /// In en, this message translates to: + /// **'Metadata search is unavailable for this collection type or currently disabled.'** + String get metadataSearchDisabledHint; + + /// No description provided for @metadataNoMatchForBarcode. + /// + /// In en, this message translates to: + /// **'No metadata match found for this barcode.'** + String get metadataNoMatchForBarcode; + + /// No description provided for @metadataSearchUnavailableForType. + /// + /// In en, this message translates to: + /// **'Metadata search is unavailable for {collectionType}.'** + String metadataSearchUnavailableForType(String collectionType); + /// No description provided for @tagItemsTitle. /// /// In en, this message translates to: @@ -2326,6 +2446,354 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Due date'** String get loanTrackingDueDateLabel; + + /// No description provided for @authTitleAccount. + /// + /// In en, this message translates to: + /// **'Account'** + String get authTitleAccount; + + /// No description provided for @authCreateAccountHeading. + /// + /// In en, this message translates to: + /// **'Create Account'** + String get authCreateAccountHeading; + + /// No description provided for @authSignInHeading. + /// + /// In en, this message translates to: + /// **'Sign In'** + String get authSignInHeading; + + /// No description provided for @authCreateAccountDescription. + /// + /// In en, this message translates to: + /// **'Create an account to sync your collections across devices.'** + String get authCreateAccountDescription; + + /// No description provided for @authSignInDescription. + /// + /// In en, this message translates to: + /// **'Sign in to enable cloud sync and account features.'** + String get authSignInDescription; + + /// No description provided for @authSignInChoice. + /// + /// In en, this message translates to: + /// **'Sign in'** + String get authSignInChoice; + + /// No description provided for @authRegisterChoice. + /// + /// In en, this message translates to: + /// **'Register'** + String get authRegisterChoice; + + /// No description provided for @authEmailLabel. + /// + /// In en, this message translates to: + /// **'Email'** + String get authEmailLabel; + + /// No description provided for @authEmailHint. + /// + /// In en, this message translates to: + /// **'you@example.com'** + String get authEmailHint; + + /// No description provided for @authEmailRequiredError. + /// + /// In en, this message translates to: + /// **'Email is required.'** + String get authEmailRequiredError; + + /// No description provided for @authEmailInvalidError. + /// + /// In en, this message translates to: + /// **'Enter a valid email.'** + String get authEmailInvalidError; + + /// No description provided for @authPasswordLabel. + /// + /// In en, this message translates to: + /// **'Password'** + String get authPasswordLabel; + + /// No description provided for @authPasswordHint. + /// + /// In en, this message translates to: + /// **'Min 8 chars, A-Z, a-z, 0-9'** + String get authPasswordHint; + + /// No description provided for @authPasswordRequiredError. + /// + /// In en, this message translates to: + /// **'Password is required.'** + String get authPasswordRequiredError; + + /// No description provided for @authPasswordLengthError. + /// + /// In en, this message translates to: + /// **'Password must be at least 8 characters.'** + String get authPasswordLengthError; + + /// No description provided for @authPasswordPolicyError. + /// + /// In en, this message translates to: + /// **'Password must include uppercase, lowercase, and number.'** + String get authPasswordPolicyError; + + /// No description provided for @authDisplayNameLabel. + /// + /// In en, this message translates to: + /// **'Display Name (optional)'** + String get authDisplayNameLabel; + + /// No description provided for @authDisplayNameHint. + /// + /// In en, this message translates to: + /// **'How should we call you?'** + String get authDisplayNameHint; + + /// No description provided for @authCreateAccountAction. + /// + /// In en, this message translates to: + /// **'Create account'** + String get authCreateAccountAction; + + /// No description provided for @authNotNowAction. + /// + /// In en, this message translates to: + /// **'Not now'** + String get authNotNowAction; + + /// No description provided for @authUnavailableMessage. + /// + /// In en, this message translates to: + /// **'Authentication is currently unavailable.'** + String get authUnavailableMessage; + + /// No description provided for @authRegisterSuccess. + /// + /// In en, this message translates to: + /// **'Account created and signed in.'** + String get authRegisterSuccess; + + /// No description provided for @authSignInSuccess. + /// + /// In en, this message translates to: + /// **'Signed in successfully.'** + String get authSignInSuccess; + + /// No description provided for @authSignInFailed. + /// + /// In en, this message translates to: + /// **'Sign-in failed: {error}'** + String authSignInFailed(String error); + + /// No description provided for @authSignedOut. + /// + /// In en, this message translates to: + /// **'Signed out.'** + String get authSignedOut; + + /// No description provided for @authFinalConfirmationTitle. + /// + /// In en, this message translates to: + /// **'Final confirmation'** + String get authFinalConfirmationTitle; + + /// No description provided for @authFinalConfirmationMessage. + /// + /// In en, this message translates to: + /// **'Submit account deletion request now? You will be signed out immediately from this device.'** + String get authFinalConfirmationMessage; + + /// No description provided for @authBackAction. + /// + /// In en, this message translates to: + /// **'Back'** + String get authBackAction; + + /// No description provided for @authSubmitRequestAction. + /// + /// In en, this message translates to: + /// **'Submit Request'** + String get authSubmitRequestAction; + + /// No description provided for @authDeletionRequestSubmitted. + /// + /// In en, this message translates to: + /// **'Account deletion request submitted. You have been signed out.'** + String get authDeletionRequestSubmitted; + + /// No description provided for @authDeletionEndpointMissing. + /// + /// In en, this message translates to: + /// **'Deletion request endpoint is not configured on backend yet.'** + String get authDeletionEndpointMissing; + + /// No description provided for @authDeletionImpactDialogTitle. + /// + /// In en, this message translates to: + /// **'Before requesting account deletion'** + String get authDeletionImpactDialogTitle; + + /// No description provided for @authDeletionImpactReviewPrompt. + /// + /// In en, this message translates to: + /// **'Please review the impact carefully.'** + String get authDeletionImpactReviewPrompt; + + /// No description provided for @authIrreversibleRequestTitle. + /// + /// In en, this message translates to: + /// **'Irreversible request'** + String get authIrreversibleRequestTitle; + + /// No description provided for @authImpactLineSessionRevoked. + /// + /// In en, this message translates to: + /// **'Your account session is revoked immediately on request.'** + String get authImpactLineSessionRevoked; + + /// No description provided for @authImpactLineCloudDataDeleted. + /// + /// In en, this message translates to: + /// **'Synced cloud data linked to this account may be permanently deleted during processing.'** + String get authImpactLineCloudDataDeleted; + + /// No description provided for @authImpactLineCannotRestore. + /// + /// In en, this message translates to: + /// **'Deleted account data cannot be restored once processed.'** + String get authImpactLineCannotRestore; + + /// No description provided for @authUnderstandAction. + /// + /// In en, this message translates to: + /// **'I understand'** + String get authUnderstandAction; + + /// No description provided for @authPasswordPolicySuffix. + /// + /// In en, this message translates to: + /// **'Use English keyboard letters and digits (A-Z, a-z, 0-9).'** + String get authPasswordPolicySuffix; + + /// No description provided for @authAccountConnected. + /// + /// In en, this message translates to: + /// **'Account connected'** + String get authAccountConnected; + + /// No description provided for @authSignedInReadySubtitle. + /// + /// In en, this message translates to: + /// **'Signed in and ready for cloud sync'** + String get authSignedInReadySubtitle; + + /// No description provided for @authActiveStatus. + /// + /// In en, this message translates to: + /// **'Active'** + String get authActiveStatus; + + /// No description provided for @authSessionDetailsTitle. + /// + /// In en, this message translates to: + /// **'Session details'** + String get authSessionDetailsTitle; + + /// No description provided for @authUserIdLabel. + /// + /// In en, this message translates to: + /// **'User ID'** + String get authUserIdLabel; + + /// No description provided for @authDeviceIdLabel. + /// + /// In en, this message translates to: + /// **'Device ID'** + String get authDeviceIdLabel; + + /// No description provided for @authUnknownValue. + /// + /// In en, this message translates to: + /// **'Unknown'** + String get authUnknownValue; + + /// No description provided for @authDeletionNoticeTitle. + /// + /// In en, this message translates to: + /// **'Account deletion notice'** + String get authDeletionNoticeTitle; + + /// No description provided for @authDeletionNoticeSubtitle. + /// + /// In en, this message translates to: + /// **'Deletion requests are irreversible once processed.'** + String get authDeletionNoticeSubtitle; + + /// No description provided for @authDeletionNoticeLineProfileSessions. + /// + /// In en, this message translates to: + /// **'Account profile and active sessions will be removed from cloud access.'** + String get authDeletionNoticeLineProfileSessions; + + /// No description provided for @authDeletionNoticeLineSyncedData. + /// + /// In en, this message translates to: + /// **'Synced collections, items, tags, and loans may be permanently deleted.'** + String get authDeletionNoticeLineSyncedData; + + /// No description provided for @authRequestDeletionAction. + /// + /// In en, this message translates to: + /// **'Request account deletion'** + String get authRequestDeletionAction; + + /// No description provided for @authSignOutAction. + /// + /// In en, this message translates to: + /// **'Sign out'** + String get authSignOutAction; + + /// No description provided for @authDoneAction. + /// + /// In en, this message translates to: + /// **'Done'** + String get authDoneAction; + + /// No description provided for @authHeaderCreateTitle. + /// + /// In en, this message translates to: + /// **'Create your account'** + String get authHeaderCreateTitle; + + /// No description provided for @authHeaderWelcomeTitle. + /// + /// In en, this message translates to: + /// **'Welcome back'** + String get authHeaderWelcomeTitle; + + /// No description provided for @authHeaderCreateSubtitle. + /// + /// In en, this message translates to: + /// **'Accounts are optional, but required for cloud sync and multi-device access.'** + String get authHeaderCreateSubtitle; + + /// No description provided for @authHeaderSignInSubtitle. + /// + /// In en, this message translates to: + /// **'Sign in to access cloud sync and account-based features.'** + String get authHeaderSignInSubtitle; + + /// No description provided for @authUnavailableTitle. + /// + /// In en, this message translates to: + /// **'Authentication unavailable'** + String get authUnavailableTitle; } class _AppLocalizationsDelegate extends LocalizationsDelegate { diff --git a/apps/mobile/lib/l10n/gen/app_localizations_en.dart b/apps/mobile/lib/l10n/gen/app_localizations_en.dart index 0941898..500bb16 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_en.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_en.dart @@ -220,6 +220,57 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => 'Inspect and refresh runtime feature flags'; + @override + String get settingsMetadataTitle => 'Metadata & Autofill'; + + @override + String get settingsMetadataSummaryEnabled => 'Enabled with automatic barcode lookup'; + + @override + String get settingsMetadataSummaryManual => 'Enabled with manual lookup'; + + @override + String get settingsMetadataSummaryDisabled => 'Disabled'; + + @override + String get settingsMetadataSummaryFeatureDisabled => 'Disabled by runtime feature flag'; + + @override + String get settingsMetadataEnableToggleTitle => 'Enable metadata assistance'; + + @override + String get settingsMetadataEnableToggleSubtitle => 'Allow metadata search and barcode-based autofill in item forms.'; + + @override + String get settingsMetadataAutoFetchToggleTitle => 'Auto-fetch from barcode scan'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => 'After scanning a barcode, fetch metadata automatically.'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => 'Fill empty fields only'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => 'Do not overwrite existing title or description when metadata is found.'; + + @override + String get settingsMetadataSourcesSectionTitle => 'Sources'; + + @override + String get settingsMetadataSourceAvailable => 'Available'; + + @override + String get settingsMetadataSourceNotConfigured => 'Not configured'; + + @override + String get settingsMetadataSourceManualOnly => 'Manual only'; + + @override + String get settingsMetadataManualCollectionsLabel => 'Comics, Music, and Custom'; + + @override + String get settingsMetadataFeatureDisabledMessage => 'Metadata assistance is disabled by runtime configuration.'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Firebase Runtime Config'; @@ -751,6 +802,17 @@ class AppLocalizationsEn extends AppLocalizations { @override String get metadataSearchSuggestionMessage => 'Start typing to look up metadata.'; + @override + String get metadataSearchDisabledHint => 'Metadata search is unavailable for this collection type or currently disabled.'; + + @override + String get metadataNoMatchForBarcode => 'No metadata match found for this barcode.'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return 'Metadata search is unavailable for $collectionType.'; + } + @override String tagItemsTitle(String tag) { return 'Tag: $tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsEn extends AppLocalizations { @override String get loanTrackingDueDateLabel => 'Due date'; + + @override + String get authTitleAccount => 'Account'; + + @override + String get authCreateAccountHeading => 'Create Account'; + + @override + String get authSignInHeading => 'Sign In'; + + @override + String get authCreateAccountDescription => 'Create an account to sync your collections across devices.'; + + @override + String get authSignInDescription => 'Sign in to enable cloud sync and account features.'; + + @override + String get authSignInChoice => 'Sign in'; + + @override + String get authRegisterChoice => 'Register'; + + @override + String get authEmailLabel => 'Email'; + + @override + String get authEmailHint => 'you@example.com'; + + @override + String get authEmailRequiredError => 'Email is required.'; + + @override + String get authEmailInvalidError => 'Enter a valid email.'; + + @override + String get authPasswordLabel => 'Password'; + + @override + String get authPasswordHint => 'Min 8 chars, A-Z, a-z, 0-9'; + + @override + String get authPasswordRequiredError => 'Password is required.'; + + @override + String get authPasswordLengthError => 'Password must be at least 8 characters.'; + + @override + String get authPasswordPolicyError => 'Password must include uppercase, lowercase, and number.'; + + @override + String get authDisplayNameLabel => 'Display Name (optional)'; + + @override + String get authDisplayNameHint => 'How should we call you?'; + + @override + String get authCreateAccountAction => 'Create account'; + + @override + String get authNotNowAction => 'Not now'; + + @override + String get authUnavailableMessage => 'Authentication is currently unavailable.'; + + @override + String get authRegisterSuccess => 'Account created and signed in.'; + + @override + String get authSignInSuccess => 'Signed in successfully.'; + + @override + String authSignInFailed(String error) { + return 'Sign-in failed: $error'; + } + + @override + String get authSignedOut => 'Signed out.'; + + @override + String get authFinalConfirmationTitle => 'Final confirmation'; + + @override + String get authFinalConfirmationMessage => 'Submit account deletion request now? You will be signed out immediately from this device.'; + + @override + String get authBackAction => 'Back'; + + @override + String get authSubmitRequestAction => 'Submit Request'; + + @override + String get authDeletionRequestSubmitted => 'Account deletion request submitted. You have been signed out.'; + + @override + String get authDeletionEndpointMissing => 'Deletion request endpoint is not configured on backend yet.'; + + @override + String get authDeletionImpactDialogTitle => 'Before requesting account deletion'; + + @override + String get authDeletionImpactReviewPrompt => 'Please review the impact carefully.'; + + @override + String get authIrreversibleRequestTitle => 'Irreversible request'; + + @override + String get authImpactLineSessionRevoked => 'Your account session is revoked immediately on request.'; + + @override + String get authImpactLineCloudDataDeleted => 'Synced cloud data linked to this account may be permanently deleted during processing.'; + + @override + String get authImpactLineCannotRestore => 'Deleted account data cannot be restored once processed.'; + + @override + String get authUnderstandAction => 'I understand'; + + @override + String get authPasswordPolicySuffix => 'Use English keyboard letters and digits (A-Z, a-z, 0-9).'; + + @override + String get authAccountConnected => 'Account connected'; + + @override + String get authSignedInReadySubtitle => 'Signed in and ready for cloud sync'; + + @override + String get authActiveStatus => 'Active'; + + @override + String get authSessionDetailsTitle => 'Session details'; + + @override + String get authUserIdLabel => 'User ID'; + + @override + String get authDeviceIdLabel => 'Device ID'; + + @override + String get authUnknownValue => 'Unknown'; + + @override + String get authDeletionNoticeTitle => 'Account deletion notice'; + + @override + String get authDeletionNoticeSubtitle => 'Deletion requests are irreversible once processed.'; + + @override + String get authDeletionNoticeLineProfileSessions => 'Account profile and active sessions will be removed from cloud access.'; + + @override + String get authDeletionNoticeLineSyncedData => 'Synced collections, items, tags, and loans may be permanently deleted.'; + + @override + String get authRequestDeletionAction => 'Request account deletion'; + + @override + String get authSignOutAction => 'Sign out'; + + @override + String get authDoneAction => 'Done'; + + @override + String get authHeaderCreateTitle => 'Create your account'; + + @override + String get authHeaderWelcomeTitle => 'Welcome back'; + + @override + String get authHeaderCreateSubtitle => 'Accounts are optional, but required for cloud sync and multi-device access.'; + + @override + String get authHeaderSignInSubtitle => 'Sign in to access cloud sync and account-based features.'; + + @override + String get authUnavailableTitle => 'Authentication unavailable'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_es.dart b/apps/mobile/lib/l10n/gen/app_localizations_es.dart index 7afb738..238b5d5 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_es.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_es.dart @@ -220,6 +220,57 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => 'Inspecciona y actualiza las banderas de ejecución'; + @override + String get settingsMetadataTitle => 'Metadatos y Autorrelleno'; + + @override + String get settingsMetadataSummaryEnabled => 'Activado con búsqueda automática por código de barras'; + + @override + String get settingsMetadataSummaryManual => 'Activado con búsqueda manual'; + + @override + String get settingsMetadataSummaryDisabled => 'Desactivado'; + + @override + String get settingsMetadataSummaryFeatureDisabled => 'Desactivado por bandera de ejecución'; + + @override + String get settingsMetadataEnableToggleTitle => 'Activar asistencia de metadatos'; + + @override + String get settingsMetadataEnableToggleSubtitle => 'Permite la búsqueda de metadatos y el autorrelleno por código de barras en formularios de artículos.'; + + @override + String get settingsMetadataAutoFetchToggleTitle => 'Buscar automáticamente al escanear código'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => 'Después de escanear un código de barras, obtiene metadatos automáticamente.'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => 'Rellenar solo campos vacíos'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => 'No sobrescribe el título ni la descripción existentes cuando se encuentran metadatos.'; + + @override + String get settingsMetadataSourcesSectionTitle => 'Fuentes'; + + @override + String get settingsMetadataSourceAvailable => 'Disponible'; + + @override + String get settingsMetadataSourceNotConfigured => 'Sin configurar'; + + @override + String get settingsMetadataSourceManualOnly => 'Solo manual'; + + @override + String get settingsMetadataManualCollectionsLabel => 'Cómics, Música y Personalizado'; + + @override + String get settingsMetadataFeatureDisabledMessage => 'La asistencia de metadatos está desactivada por configuración de ejecución.'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Configuración de ejecución de Firebase'; @@ -751,6 +802,17 @@ class AppLocalizationsEs extends AppLocalizations { @override String get metadataSearchSuggestionMessage => 'Empieza a escribir para buscar metadatos.'; + @override + String get metadataSearchDisabledHint => 'La búsqueda de metadatos no está disponible para este tipo de colección o está desactivada.'; + + @override + String get metadataNoMatchForBarcode => 'No se encontraron metadatos para este código de barras.'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return 'La búsqueda de metadatos no está disponible para $collectionType.'; + } + @override String tagItemsTitle(String tag) { return 'Etiqueta: $tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsEs extends AppLocalizations { @override String get loanTrackingDueDateLabel => 'Fecha de vencimiento'; + + @override + String get authTitleAccount => 'Cuenta'; + + @override + String get authCreateAccountHeading => 'Crear cuenta'; + + @override + String get authSignInHeading => 'Iniciar sesión'; + + @override + String get authCreateAccountDescription => 'Crea una cuenta para sincronizar tus colecciones entre dispositivos.'; + + @override + String get authSignInDescription => 'Inicia sesión para habilitar la sincronización en la nube y funciones de cuenta.'; + + @override + String get authSignInChoice => 'Iniciar sesión'; + + @override + String get authRegisterChoice => 'Registrarse'; + + @override + String get authEmailLabel => 'Correo electrónico'; + + @override + String get authEmailHint => 'tu@ejemplo.com'; + + @override + String get authEmailRequiredError => 'El correo electrónico es obligatorio.'; + + @override + String get authEmailInvalidError => 'Introduce un correo electrónico válido.'; + + @override + String get authPasswordLabel => 'Contraseña'; + + @override + String get authPasswordHint => 'Mín. 8 caracteres, A-Z, a-z, 0-9'; + + @override + String get authPasswordRequiredError => 'La contraseña es obligatoria.'; + + @override + String get authPasswordLengthError => 'La contraseña debe tener al menos 8 caracteres.'; + + @override + String get authPasswordPolicyError => 'La contraseña debe incluir mayúsculas, minúsculas y números.'; + + @override + String get authDisplayNameLabel => 'Nombre para mostrar (opcional)'; + + @override + String get authDisplayNameHint => '¿Cómo debemos llamarte?'; + + @override + String get authCreateAccountAction => 'Crear cuenta'; + + @override + String get authNotNowAction => 'Ahora no'; + + @override + String get authUnavailableMessage => 'La autenticación no está disponible en este momento.'; + + @override + String get authRegisterSuccess => 'Cuenta creada e inicio de sesión completado.'; + + @override + String get authSignInSuccess => 'Inicio de sesión exitoso.'; + + @override + String authSignInFailed(String error) { + return 'Error al iniciar sesión: $error'; + } + + @override + String get authSignedOut => 'Sesión cerrada.'; + + @override + String get authFinalConfirmationTitle => 'Confirmación final'; + + @override + String get authFinalConfirmationMessage => '¿Enviar solicitud de eliminación de cuenta ahora? Se cerrará la sesión de inmediato en este dispositivo.'; + + @override + String get authBackAction => 'Atrás'; + + @override + String get authSubmitRequestAction => 'Enviar solicitud'; + + @override + String get authDeletionRequestSubmitted => 'Solicitud de eliminación enviada. Se cerró tu sesión.'; + + @override + String get authDeletionEndpointMissing => 'El endpoint de solicitud de eliminación aún no está configurado en el backend.'; + + @override + String get authDeletionImpactDialogTitle => 'Antes de solicitar la eliminación de la cuenta'; + + @override + String get authDeletionImpactReviewPrompt => 'Revisa cuidadosamente el impacto.'; + + @override + String get authIrreversibleRequestTitle => 'Solicitud irreversible'; + + @override + String get authImpactLineSessionRevoked => 'La sesión de tu cuenta se revoca inmediatamente al solicitarla.'; + + @override + String get authImpactLineCloudDataDeleted => 'Los datos sincronizados en la nube vinculados a esta cuenta pueden eliminarse permanentemente durante el proceso.'; + + @override + String get authImpactLineCannotRestore => 'Los datos eliminados de la cuenta no se pueden restaurar una vez procesados.'; + + @override + String get authUnderstandAction => 'Entiendo'; + + @override + String get authPasswordPolicySuffix => 'Usa letras y dígitos del teclado en inglés (A-Z, a-z, 0-9).'; + + @override + String get authAccountConnected => 'Cuenta conectada'; + + @override + String get authSignedInReadySubtitle => 'Sesión iniciada y lista para sincronización en la nube'; + + @override + String get authActiveStatus => 'Activa'; + + @override + String get authSessionDetailsTitle => 'Detalles de la sesión'; + + @override + String get authUserIdLabel => 'ID de usuario'; + + @override + String get authDeviceIdLabel => 'ID del dispositivo'; + + @override + String get authUnknownValue => 'Desconocido'; + + @override + String get authDeletionNoticeTitle => 'Aviso de eliminación de cuenta'; + + @override + String get authDeletionNoticeSubtitle => 'Las solicitudes de eliminación son irreversibles una vez procesadas.'; + + @override + String get authDeletionNoticeLineProfileSessions => 'El perfil de la cuenta y las sesiones activas se eliminarán del acceso en la nube.'; + + @override + String get authDeletionNoticeLineSyncedData => 'Las colecciones, artículos, etiquetas y préstamos sincronizados pueden eliminarse permanentemente.'; + + @override + String get authRequestDeletionAction => 'Solicitar eliminación de cuenta'; + + @override + String get authSignOutAction => 'Cerrar sesión'; + + @override + String get authDoneAction => 'Listo'; + + @override + String get authHeaderCreateTitle => 'Crea tu cuenta'; + + @override + String get authHeaderWelcomeTitle => 'Bienvenido de nuevo'; + + @override + String get authHeaderCreateSubtitle => 'Las cuentas son opcionales, pero necesarias para sincronización en la nube y acceso multidispositivo.'; + + @override + String get authHeaderSignInSubtitle => 'Inicia sesión para acceder a sincronización en la nube y funciones de cuenta.'; + + @override + String get authUnavailableTitle => 'Autenticación no disponible'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_id.dart b/apps/mobile/lib/l10n/gen/app_localizations_id.dart index 865af51..8377a2b 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_id.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_id.dart @@ -220,6 +220,57 @@ class AppLocalizationsId extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => 'Periksa dan segarkan flag fitur runtime'; + @override + String get settingsMetadataTitle => 'Metadata & Isi Otomatis'; + + @override + String get settingsMetadataSummaryEnabled => 'Aktif dengan pencarian barcode otomatis'; + + @override + String get settingsMetadataSummaryManual => 'Aktif dengan pencarian manual'; + + @override + String get settingsMetadataSummaryDisabled => 'Nonaktif'; + + @override + String get settingsMetadataSummaryFeatureDisabled => 'Dinonaktifkan oleh flag fitur runtime'; + + @override + String get settingsMetadataEnableToggleTitle => 'Aktifkan bantuan metadata'; + + @override + String get settingsMetadataEnableToggleSubtitle => 'Izinkan pencarian metadata dan isi otomatis berbasis barcode pada formulir item.'; + + @override + String get settingsMetadataAutoFetchToggleTitle => 'Ambil otomatis saat barcode dipindai'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => 'Setelah barcode dipindai, metadata diambil secara otomatis.'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => 'Isi hanya kolom kosong'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => 'Jangan menimpa judul atau deskripsi yang sudah ada saat metadata ditemukan.'; + + @override + String get settingsMetadataSourcesSectionTitle => 'Sumber'; + + @override + String get settingsMetadataSourceAvailable => 'Tersedia'; + + @override + String get settingsMetadataSourceNotConfigured => 'Belum dikonfigurasi'; + + @override + String get settingsMetadataSourceManualOnly => 'Manual saja'; + + @override + String get settingsMetadataManualCollectionsLabel => 'Komik, Musik, dan Kustom'; + + @override + String get settingsMetadataFeatureDisabledMessage => 'Bantuan metadata dinonaktifkan oleh konfigurasi runtime.'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Konfigurasi Runtime Firebase'; @@ -751,6 +802,17 @@ class AppLocalizationsId extends AppLocalizations { @override String get metadataSearchSuggestionMessage => 'Mulai mengetik untuk mencari metadata.'; + @override + String get metadataSearchDisabledHint => 'Pencarian metadata tidak tersedia untuk tipe koleksi ini atau sedang dinonaktifkan.'; + + @override + String get metadataNoMatchForBarcode => 'Tidak ditemukan metadata yang cocok untuk barcode ini.'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return 'Pencarian metadata tidak tersedia untuk $collectionType.'; + } + @override String tagItemsTitle(String tag) { return 'Tag: $tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsId extends AppLocalizations { @override String get loanTrackingDueDateLabel => 'Tanggal jatuh tempo'; + + @override + String get authTitleAccount => 'Akun'; + + @override + String get authCreateAccountHeading => 'Buat Akun'; + + @override + String get authSignInHeading => 'Masuk'; + + @override + String get authCreateAccountDescription => 'Buat akun untuk menyinkronkan koleksi Anda di berbagai perangkat.'; + + @override + String get authSignInDescription => 'Masuk untuk mengaktifkan sinkronisasi cloud dan fitur akun.'; + + @override + String get authSignInChoice => 'Masuk'; + + @override + String get authRegisterChoice => 'Daftar'; + + @override + String get authEmailLabel => 'Email'; + + @override + String get authEmailHint => 'anda@contoh.com'; + + @override + String get authEmailRequiredError => 'Email wajib diisi.'; + + @override + String get authEmailInvalidError => 'Masukkan email yang valid.'; + + @override + String get authPasswordLabel => 'Kata sandi'; + + @override + String get authPasswordHint => 'Min 8 karakter, A-Z, a-z, 0-9'; + + @override + String get authPasswordRequiredError => 'Kata sandi wajib diisi.'; + + @override + String get authPasswordLengthError => 'Kata sandi minimal 8 karakter.'; + + @override + String get authPasswordPolicyError => 'Kata sandi harus mengandung huruf besar, huruf kecil, dan angka.'; + + @override + String get authDisplayNameLabel => 'Nama tampilan (opsional)'; + + @override + String get authDisplayNameHint => 'Kami memanggil Anda dengan nama apa?'; + + @override + String get authCreateAccountAction => 'Buat akun'; + + @override + String get authNotNowAction => 'Nanti saja'; + + @override + String get authUnavailableMessage => 'Autentikasi sedang tidak tersedia.'; + + @override + String get authRegisterSuccess => 'Akun berhasil dibuat dan Anda sudah masuk.'; + + @override + String get authSignInSuccess => 'Berhasil masuk.'; + + @override + String authSignInFailed(String error) { + return 'Gagal masuk: $error'; + } + + @override + String get authSignedOut => 'Berhasil keluar.'; + + @override + String get authFinalConfirmationTitle => 'Konfirmasi akhir'; + + @override + String get authFinalConfirmationMessage => 'Kirim permintaan penghapusan akun sekarang? Anda akan langsung keluar dari perangkat ini.'; + + @override + String get authBackAction => 'Kembali'; + + @override + String get authSubmitRequestAction => 'Kirim Permintaan'; + + @override + String get authDeletionRequestSubmitted => 'Permintaan penghapusan akun dikirim. Anda telah keluar.'; + + @override + String get authDeletionEndpointMissing => 'Endpoint permintaan penghapusan belum dikonfigurasi di backend.'; + + @override + String get authDeletionImpactDialogTitle => 'Sebelum meminta penghapusan akun'; + + @override + String get authDeletionImpactReviewPrompt => 'Tinjau dampaknya dengan saksama.'; + + @override + String get authIrreversibleRequestTitle => 'Permintaan tidak dapat dibatalkan'; + + @override + String get authImpactLineSessionRevoked => 'Sesi akun Anda dicabut segera setelah permintaan dikirim.'; + + @override + String get authImpactLineCloudDataDeleted => 'Data cloud tersinkron yang terkait akun ini dapat dihapus permanen saat diproses.'; + + @override + String get authImpactLineCannotRestore => 'Data akun yang sudah dihapus tidak dapat dipulihkan setelah diproses.'; + + @override + String get authUnderstandAction => 'Saya mengerti'; + + @override + String get authPasswordPolicySuffix => 'Gunakan huruf dan angka keyboard Inggris (A-Z, a-z, 0-9).'; + + @override + String get authAccountConnected => 'Akun terhubung'; + + @override + String get authSignedInReadySubtitle => 'Sudah masuk dan siap untuk sinkronisasi cloud'; + + @override + String get authActiveStatus => 'Aktif'; + + @override + String get authSessionDetailsTitle => 'Detail sesi'; + + @override + String get authUserIdLabel => 'ID Pengguna'; + + @override + String get authDeviceIdLabel => 'ID Perangkat'; + + @override + String get authUnknownValue => 'Tidak diketahui'; + + @override + String get authDeletionNoticeTitle => 'Pemberitahuan penghapusan akun'; + + @override + String get authDeletionNoticeSubtitle => 'Permintaan penghapusan bersifat permanen setelah diproses.'; + + @override + String get authDeletionNoticeLineProfileSessions => 'Profil akun dan sesi aktif akan dihapus dari akses cloud.'; + + @override + String get authDeletionNoticeLineSyncedData => 'Koleksi, item, tag, dan pinjaman tersinkron dapat dihapus permanen.'; + + @override + String get authRequestDeletionAction => 'Minta penghapusan akun'; + + @override + String get authSignOutAction => 'Keluar'; + + @override + String get authDoneAction => 'Selesai'; + + @override + String get authHeaderCreateTitle => 'Buat akun Anda'; + + @override + String get authHeaderWelcomeTitle => 'Selamat datang kembali'; + + @override + String get authHeaderCreateSubtitle => 'Akun bersifat opsional, tetapi diperlukan untuk sinkronisasi cloud dan akses multi-perangkat.'; + + @override + String get authHeaderSignInSubtitle => 'Masuk untuk menggunakan sinkronisasi cloud dan fitur berbasis akun.'; + + @override + String get authUnavailableTitle => 'Autentikasi tidak tersedia'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart index 2aa7691..1d6a4b0 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart @@ -220,6 +220,57 @@ class AppLocalizationsJa extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => 'ランタイム機能フラグを確認して更新'; + @override + String get settingsMetadataTitle => 'メタデータと自動入力'; + + @override + String get settingsMetadataSummaryEnabled => 'バーコード自動検索で有効'; + + @override + String get settingsMetadataSummaryManual => '手動検索で有効'; + + @override + String get settingsMetadataSummaryDisabled => '無効'; + + @override + String get settingsMetadataSummaryFeatureDisabled => '実行時の機能フラグにより無効'; + + @override + String get settingsMetadataEnableToggleTitle => 'メタデータ補助を有効化'; + + @override + String get settingsMetadataEnableToggleSubtitle => 'アイテムフォームでメタデータ検索とバーコード自動入力を利用します。'; + + @override + String get settingsMetadataAutoFetchToggleTitle => 'バーコード読み取り時に自動取得'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => 'バーコードを読み取った後、メタデータを自動取得します。'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => '空欄のみ入力'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => 'メタデータ検出時に既存のタイトルや説明を上書きしません。'; + + @override + String get settingsMetadataSourcesSectionTitle => 'ソース'; + + @override + String get settingsMetadataSourceAvailable => '利用可能'; + + @override + String get settingsMetadataSourceNotConfigured => '未設定'; + + @override + String get settingsMetadataSourceManualOnly => '手動のみ'; + + @override + String get settingsMetadataManualCollectionsLabel => 'コミック・音楽・カスタム'; + + @override + String get settingsMetadataFeatureDisabledMessage => 'メタデータ補助は実行時設定で無効化されています。'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Firebase ランタイム設定'; @@ -751,6 +802,17 @@ class AppLocalizationsJa extends AppLocalizations { @override String get metadataSearchSuggestionMessage => '入力してメタデータを検索してください。'; + @override + String get metadataSearchDisabledHint => 'このコレクション種別ではメタデータ検索が利用できないか、現在無効です。'; + + @override + String get metadataNoMatchForBarcode => 'このバーコードに一致するメタデータが見つかりません。'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return '$collectionType ではメタデータ検索を利用できません。'; + } + @override String tagItemsTitle(String tag) { return 'タグ: $tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsJa extends AppLocalizations { @override String get loanTrackingDueDateLabel => '返却期限'; + + @override + String get authTitleAccount => 'アカウント'; + + @override + String get authCreateAccountHeading => 'アカウント作成'; + + @override + String get authSignInHeading => 'サインイン'; + + @override + String get authCreateAccountDescription => 'アカウントを作成すると、コレクションを複数端末で同期できます。'; + + @override + String get authSignInDescription => 'サインインするとクラウド同期とアカウント機能を利用できます。'; + + @override + String get authSignInChoice => 'サインイン'; + + @override + String get authRegisterChoice => '登録'; + + @override + String get authEmailLabel => 'メールアドレス'; + + @override + String get authEmailHint => 'you@example.com'; + + @override + String get authEmailRequiredError => 'メールアドレスは必須です。'; + + @override + String get authEmailInvalidError => '有効なメールアドレスを入力してください。'; + + @override + String get authPasswordLabel => 'パスワード'; + + @override + String get authPasswordHint => '8文字以上、A-Z、a-z、0-9'; + + @override + String get authPasswordRequiredError => 'パスワードは必須です。'; + + @override + String get authPasswordLengthError => 'パスワードは8文字以上で入力してください。'; + + @override + String get authPasswordPolicyError => 'パスワードには大文字、小文字、数字を含めてください。'; + + @override + String get authDisplayNameLabel => '表示名(任意)'; + + @override + String get authDisplayNameHint => '呼び名を入力してください'; + + @override + String get authCreateAccountAction => 'アカウントを作成'; + + @override + String get authNotNowAction => '今はしない'; + + @override + String get authUnavailableMessage => '認証は現在利用できません。'; + + @override + String get authRegisterSuccess => 'アカウントを作成してサインインしました。'; + + @override + String get authSignInSuccess => 'サインインしました。'; + + @override + String authSignInFailed(String error) { + return 'サインインに失敗しました: $error'; + } + + @override + String get authSignedOut => 'サインアウトしました。'; + + @override + String get authFinalConfirmationTitle => '最終確認'; + + @override + String get authFinalConfirmationMessage => '今すぐアカウント削除リクエストを送信しますか?この端末では直ちにサインアウトされます。'; + + @override + String get authBackAction => '戻る'; + + @override + String get authSubmitRequestAction => 'リクエストを送信'; + + @override + String get authDeletionRequestSubmitted => 'アカウント削除リクエストを送信しました。サインアウトされました。'; + + @override + String get authDeletionEndpointMissing => '削除リクエストのエンドポイントがバックエンドにまだ設定されていません。'; + + @override + String get authDeletionImpactDialogTitle => 'アカウント削除をリクエストする前に'; + + @override + String get authDeletionImpactReviewPrompt => '影響をよくご確認ください。'; + + @override + String get authIrreversibleRequestTitle => '取り消し不可のリクエスト'; + + @override + String get authImpactLineSessionRevoked => 'リクエスト送信後、アカウントセッションはすぐに無効化されます。'; + + @override + String get authImpactLineCloudDataDeleted => 'このアカウントに紐づく同期済みクラウドデータは、処理中に完全削除される可能性があります。'; + + @override + String get authImpactLineCannotRestore => '削除されたアカウントデータは処理後に復元できません。'; + + @override + String get authUnderstandAction => '理解しました'; + + @override + String get authPasswordPolicySuffix => '英字キーボードの文字と数字(A-Z、a-z、0-9)を使用してください。'; + + @override + String get authAccountConnected => 'アカウント接続済み'; + + @override + String get authSignedInReadySubtitle => 'サインイン済みでクラウド同期の準備ができています'; + + @override + String get authActiveStatus => '有効'; + + @override + String get authSessionDetailsTitle => 'セッション詳細'; + + @override + String get authUserIdLabel => 'ユーザーID'; + + @override + String get authDeviceIdLabel => 'デバイスID'; + + @override + String get authUnknownValue => '不明'; + + @override + String get authDeletionNoticeTitle => 'アカウント削除に関する注意'; + + @override + String get authDeletionNoticeSubtitle => '削除リクエストは処理されると元に戻せません。'; + + @override + String get authDeletionNoticeLineProfileSessions => 'アカウントプロフィールと有効なセッションはクラウドアクセスから削除されます。'; + + @override + String get authDeletionNoticeLineSyncedData => '同期済みのコレクション、アイテム、タグ、貸出データは完全に削除される可能性があります。'; + + @override + String get authRequestDeletionAction => 'アカウント削除をリクエスト'; + + @override + String get authSignOutAction => 'サインアウト'; + + @override + String get authDoneAction => '完了'; + + @override + String get authHeaderCreateTitle => 'アカウントを作成'; + + @override + String get authHeaderWelcomeTitle => 'おかえりなさい'; + + @override + String get authHeaderCreateSubtitle => 'アカウントは任意ですが、クラウド同期と複数端末アクセスには必要です。'; + + @override + String get authHeaderSignInSubtitle => 'サインインしてクラウド同期とアカウント機能を利用しましょう。'; + + @override + String get authUnavailableTitle => '認証を利用できません'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart index c3df1b3..2bf4f4e 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart @@ -220,6 +220,57 @@ class AppLocalizationsKo extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => '런타임 기능 플래그 확인 및 새로고침'; + @override + String get settingsMetadataTitle => '메타데이터 및 자동완성'; + + @override + String get settingsMetadataSummaryEnabled => '자동 바코드 조회로 사용 중'; + + @override + String get settingsMetadataSummaryManual => '수동 조회로 사용 중'; + + @override + String get settingsMetadataSummaryDisabled => '사용 안 함'; + + @override + String get settingsMetadataSummaryFeatureDisabled => '런타임 기능 플래그로 비활성화됨'; + + @override + String get settingsMetadataEnableToggleTitle => '메타데이터 보조 사용'; + + @override + String get settingsMetadataEnableToggleSubtitle => '아이템 폼에서 메타데이터 검색과 바코드 자동완성을 허용합니다.'; + + @override + String get settingsMetadataAutoFetchToggleTitle => '바코드 스캔 시 자동 조회'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => '바코드를 스캔한 뒤 메타데이터를 자동으로 가져옵니다.'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => '빈 필드만 채우기'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => '메타데이터를 찾았을 때 기존 제목이나 설명을 덮어쓰지 않습니다.'; + + @override + String get settingsMetadataSourcesSectionTitle => '소스'; + + @override + String get settingsMetadataSourceAvailable => '사용 가능'; + + @override + String get settingsMetadataSourceNotConfigured => '미설정'; + + @override + String get settingsMetadataSourceManualOnly => '수동만'; + + @override + String get settingsMetadataManualCollectionsLabel => '코믹, 음악 및 사용자 지정'; + + @override + String get settingsMetadataFeatureDisabledMessage => '메타데이터 보조가 런타임 구성으로 비활성화되었습니다.'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Firebase 런타임 구성'; @@ -751,6 +802,17 @@ class AppLocalizationsKo extends AppLocalizations { @override String get metadataSearchSuggestionMessage => '메타데이터를 찾으려면 입력하세요.'; + @override + String get metadataSearchDisabledHint => '이 컬렉션 유형에서는 메타데이터 검색을 사용할 수 없거나 현재 비활성화되어 있습니다.'; + + @override + String get metadataNoMatchForBarcode => '이 바코드와 일치하는 메타데이터를 찾지 못했습니다.'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return '$collectionType에는 메타데이터 검색을 사용할 수 없습니다.'; + } + @override String tagItemsTitle(String tag) { return '태그: $tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsKo extends AppLocalizations { @override String get loanTrackingDueDateLabel => '반납 예정일'; + + @override + String get authTitleAccount => '계정'; + + @override + String get authCreateAccountHeading => '계정 만들기'; + + @override + String get authSignInHeading => '로그인'; + + @override + String get authCreateAccountDescription => '계정을 만들어 컬렉션을 여러 기기에서 동기화하세요.'; + + @override + String get authSignInDescription => '로그인하면 클라우드 동기화와 계정 기능을 사용할 수 있습니다.'; + + @override + String get authSignInChoice => '로그인'; + + @override + String get authRegisterChoice => '회원가입'; + + @override + String get authEmailLabel => '이메일'; + + @override + String get authEmailHint => 'you@example.com'; + + @override + String get authEmailRequiredError => '이메일은 필수입니다.'; + + @override + String get authEmailInvalidError => '유효한 이메일을 입력하세요.'; + + @override + String get authPasswordLabel => '비밀번호'; + + @override + String get authPasswordHint => '최소 8자, A-Z, a-z, 0-9'; + + @override + String get authPasswordRequiredError => '비밀번호는 필수입니다.'; + + @override + String get authPasswordLengthError => '비밀번호는 최소 8자 이상이어야 합니다.'; + + @override + String get authPasswordPolicyError => '비밀번호에는 대문자, 소문자, 숫자가 포함되어야 합니다.'; + + @override + String get authDisplayNameLabel => '표시 이름 (선택)'; + + @override + String get authDisplayNameHint => '어떻게 불러드릴까요?'; + + @override + String get authCreateAccountAction => '계정 만들기'; + + @override + String get authNotNowAction => '나중에'; + + @override + String get authUnavailableMessage => '현재 인증을 사용할 수 없습니다.'; + + @override + String get authRegisterSuccess => '계정이 생성되었고 로그인되었습니다.'; + + @override + String get authSignInSuccess => '로그인되었습니다.'; + + @override + String authSignInFailed(String error) { + return '로그인 실패: $error'; + } + + @override + String get authSignedOut => '로그아웃되었습니다.'; + + @override + String get authFinalConfirmationTitle => '최종 확인'; + + @override + String get authFinalConfirmationMessage => '지금 계정 삭제 요청을 제출할까요? 이 기기에서 즉시 로그아웃됩니다.'; + + @override + String get authBackAction => '뒤로'; + + @override + String get authSubmitRequestAction => '요청 제출'; + + @override + String get authDeletionRequestSubmitted => '계정 삭제 요청이 제출되었습니다. 로그아웃되었습니다.'; + + @override + String get authDeletionEndpointMissing => '계정 삭제 요청 엔드포인트가 아직 백엔드에 구성되지 않았습니다.'; + + @override + String get authDeletionImpactDialogTitle => '계정 삭제를 요청하기 전에'; + + @override + String get authDeletionImpactReviewPrompt => '영향을 신중히 확인해 주세요.'; + + @override + String get authIrreversibleRequestTitle => '되돌릴 수 없는 요청'; + + @override + String get authImpactLineSessionRevoked => '요청 즉시 계정 세션이 취소됩니다.'; + + @override + String get authImpactLineCloudDataDeleted => '이 계정과 연결된 동기화 클라우드 데이터는 처리 중 영구 삭제될 수 있습니다.'; + + @override + String get authImpactLineCannotRestore => '삭제된 계정 데이터는 처리 후 복구할 수 없습니다.'; + + @override + String get authUnderstandAction => '이해했습니다'; + + @override + String get authPasswordPolicySuffix => '영문 키보드 문자와 숫자(A-Z, a-z, 0-9)를 사용하세요.'; + + @override + String get authAccountConnected => '계정 연결됨'; + + @override + String get authSignedInReadySubtitle => '로그인되어 클라우드 동기화 준비 완료'; + + @override + String get authActiveStatus => '활성'; + + @override + String get authSessionDetailsTitle => '세션 정보'; + + @override + String get authUserIdLabel => '사용자 ID'; + + @override + String get authDeviceIdLabel => '기기 ID'; + + @override + String get authUnknownValue => '알 수 없음'; + + @override + String get authDeletionNoticeTitle => '계정 삭제 안내'; + + @override + String get authDeletionNoticeSubtitle => '삭제 요청은 처리되면 되돌릴 수 없습니다.'; + + @override + String get authDeletionNoticeLineProfileSessions => '계정 프로필과 활성 세션은 클라우드 접근에서 제거됩니다.'; + + @override + String get authDeletionNoticeLineSyncedData => '동기화된 컬렉션, 항목, 태그, 대여 데이터가 영구 삭제될 수 있습니다.'; + + @override + String get authRequestDeletionAction => '계정 삭제 요청'; + + @override + String get authSignOutAction => '로그아웃'; + + @override + String get authDoneAction => '완료'; + + @override + String get authHeaderCreateTitle => '계정을 만들어 보세요'; + + @override + String get authHeaderWelcomeTitle => '다시 오신 것을 환영합니다'; + + @override + String get authHeaderCreateSubtitle => '계정은 선택 사항이지만 클라우드 동기화와 다중 기기 접근에 필요합니다.'; + + @override + String get authHeaderSignInSubtitle => '로그인하여 클라우드 동기화와 계정 기능을 사용하세요.'; + + @override + String get authUnavailableTitle => '인증을 사용할 수 없음'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_my.dart b/apps/mobile/lib/l10n/gen/app_localizations_my.dart index 4b88bac..1e02f16 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_my.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_my.dart @@ -220,6 +220,57 @@ class AppLocalizationsMy extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => 'runtime feature flags ကို စစ်ဆေးပြီး refresh လုပ်ပါ'; + @override + String get settingsMetadataTitle => 'Metadata နှင့် Auto-fill'; + + @override + String get settingsMetadataSummaryEnabled => 'Barcode အလိုအလျောက်ရှာဖွေမှုဖြင့် ဖွင့်ထားသည်'; + + @override + String get settingsMetadataSummaryManual => 'လက်ဖြင့်ရှာဖွေမှုဖြင့် ဖွင့်ထားသည်'; + + @override + String get settingsMetadataSummaryDisabled => 'ပိတ်ထားသည်'; + + @override + String get settingsMetadataSummaryFeatureDisabled => 'Runtime feature flag ကြောင့် ပိတ်ထားသည်'; + + @override + String get settingsMetadataEnableToggleTitle => 'Metadata အကူအညီ ဖွင့်မည်'; + + @override + String get settingsMetadataEnableToggleSubtitle => 'Item form များတွင် metadata ရှာဖွေမှုနှင့် barcode auto-fill ကို ခွင့်ပြုပါသည်။'; + + @override + String get settingsMetadataAutoFetchToggleTitle => 'Barcode scan ပြီးနောက် အလိုအလျောက် ရယူမည်'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => 'Barcode scan ပြီးနောက် metadata ကို အလိုအလျောက် ရယူပါသည်။'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => 'လွတ်နေသော fields များကိုသာ ဖြည့်မည်'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => 'Metadata တွေ့ရှိသောအခါ ရှိပြီးသား title သို့မဟုတ် description ကို မရေးကျော်ပါ။'; + + @override + String get settingsMetadataSourcesSectionTitle => 'Sources'; + + @override + String get settingsMetadataSourceAvailable => 'အသုံးပြုနိုင်သည်'; + + @override + String get settingsMetadataSourceNotConfigured => 'မသတ်မှတ်ရသေးပါ'; + + @override + String get settingsMetadataSourceManualOnly => 'လက်ဖြင့်သာ'; + + @override + String get settingsMetadataManualCollectionsLabel => 'Comics, Music နှင့် Custom'; + + @override + String get settingsMetadataFeatureDisabledMessage => 'Metadata အကူအညီကို runtime configuration ဖြင့် ပိတ်ထားသည်။'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Firebase Runtime Config'; @@ -751,6 +802,17 @@ class AppLocalizationsMy extends AppLocalizations { @override String get metadataSearchSuggestionMessage => 'Start typing to look up metadata.'; + @override + String get metadataSearchDisabledHint => 'ဤ collection type အတွက် metadata ရှာဖွေမှု မရနိုင်ပါ သို့မဟုတ် လက်ရှိပိတ်ထားသည်။'; + + @override + String get metadataNoMatchForBarcode => 'ဤ barcode အတွက် ကိုက်ညီသော metadata မတွေ့ပါ။'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return '$collectionType အတွက် metadata ရှာဖွေမှု မရနိုင်ပါ။'; + } + @override String tagItemsTitle(String tag) { return 'Tag: $tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsMy extends AppLocalizations { @override String get loanTrackingDueDateLabel => 'ပြန်အပ်ရမည့်နေ့'; + + @override + String get authTitleAccount => 'အကောင့်'; + + @override + String get authCreateAccountHeading => 'အကောင့် ဖန်တီးရန်'; + + @override + String get authSignInHeading => 'ဝင်မည်'; + + @override + String get authCreateAccountDescription => 'စက်များအကြား စုစည်းမှုများကို sync လုပ်ရန် အကောင့်တစ်ခု ဖန်တီးပါ။'; + + @override + String get authSignInDescription => 'Cloud sync နှင့် အကောင့်ဆိုင်ရာ လုပ်ဆောင်ချက်များအသုံးပြုရန် ဝင်ပါ။'; + + @override + String get authSignInChoice => 'ဝင်မည်'; + + @override + String get authRegisterChoice => 'မှတ်ပုံတင်မည်'; + + @override + String get authEmailLabel => 'အီးမေးလ်'; + + @override + String get authEmailHint => 'you@example.com'; + + @override + String get authEmailRequiredError => 'အီးမေးလ် မဖြစ်မနေလိုအပ်သည်။'; + + @override + String get authEmailInvalidError => 'မှန်ကန်သော အီးမေးလ် ထည့်ပါ။'; + + @override + String get authPasswordLabel => 'လျှို့ဝှက်နံပါတ်'; + + @override + String get authPasswordHint => 'အနည်းဆုံး ၈ လုံး၊ A-Z, a-z, 0-9'; + + @override + String get authPasswordRequiredError => 'လျှို့ဝှက်နံပါတ် မဖြစ်မနေလိုအပ်သည်။'; + + @override + String get authPasswordLengthError => 'လျှို့ဝှက်နံပါတ်မှာ အနည်းဆုံး ၈ လုံး ရှိရမည်။'; + + @override + String get authPasswordPolicyError => 'လျှို့ဝှက်နံပါတ်တွင် စာလုံးကြီး၊ စာလုံးသေးနှင့် ဂဏန်း ပါဝင်ရမည်။'; + + @override + String get authDisplayNameLabel => 'ပြသမည့်အမည် (မဖြည့်လည်းရ)'; + + @override + String get authDisplayNameHint => 'သင့်ကို ဘယ်လိုခေါ်မလဲ?'; + + @override + String get authCreateAccountAction => 'အကောင့်ဖန်တီးမည်'; + + @override + String get authNotNowAction => 'အခုမလုပ်တော့'; + + @override + String get authUnavailableMessage => 'ယခု အတည်ပြုဝင်ရောက်မှု မရနိုင်သေးပါ။'; + + @override + String get authRegisterSuccess => 'အကောင့် ဖန်တီးပြီး ဝင်ရောက်ပြီးပါပြီ။'; + + @override + String get authSignInSuccess => 'ဝင်ရောက်မှု အောင်မြင်သည်။'; + + @override + String authSignInFailed(String error) { + return 'ဝင်ရောက်မှု မအောင်မြင်ပါ: $error'; + } + + @override + String get authSignedOut => 'ထွက်ပြီးပါပြီ။'; + + @override + String get authFinalConfirmationTitle => 'နောက်ဆုံးအတည်ပြုချက်'; + + @override + String get authFinalConfirmationMessage => 'အကောင့်ဖျက်ရန် တောင်းဆိုချက်ကို ယခု ပို့မလား? ဒီစက်တွင် ချက်ချင်း ထွက်သွားပါမည်။'; + + @override + String get authBackAction => 'နောက်သို့'; + + @override + String get authSubmitRequestAction => 'တောင်းဆိုချက် ပို့မည်'; + + @override + String get authDeletionRequestSubmitted => 'အကောင့်ဖျက်ရန် တောင်းဆိုချက် ပို့ပြီးပါပြီ။ သင့်ကို ထွက်ပေးလိုက်ပါပြီ။'; + + @override + String get authDeletionEndpointMissing => 'ဖျက်ရန် တောင်းဆို endpoint ကို backend တွင် မသတ်မှတ်ရသေးပါ။'; + + @override + String get authDeletionImpactDialogTitle => 'အကောင့်ဖျက်ရန် တောင်းဆိုမီ'; + + @override + String get authDeletionImpactReviewPrompt => 'သက်ရောက်မှုကို သေချာစွာ စစ်ဆေးပါ။'; + + @override + String get authIrreversibleRequestTitle => 'ပြန်မယူနိုင်သော တောင်းဆိုချက်'; + + @override + String get authImpactLineSessionRevoked => 'တောင်းဆိုပြီးချင်း သင့်အကောင့် session ကို ပိတ်ပါမည်။'; + + @override + String get authImpactLineCloudDataDeleted => 'ဒီအကောင့်နှင့်ချိတ်ဆက်ထားသော sync cloud ဒေတာများကို လုပ်ဆောင်နေစဉ် အပြီးအပိုင် ဖျက်နိုင်ပါသည်။'; + + @override + String get authImpactLineCannotRestore => 'ဖျက်ပြီးသော အကောင့်ဒေတာကို လုပ်ဆောင်ပြီးနောက် ပြန်မရနိုင်ပါ။'; + + @override + String get authUnderstandAction => 'နားလည်ပါသည်'; + + @override + String get authPasswordPolicySuffix => 'အင်္ဂလိပ်ကီးဘုတ် စာလုံးများနှင့် ဂဏန်းများ (A-Z, a-z, 0-9) ကို အသုံးပြုပါ။'; + + @override + String get authAccountConnected => 'အကောင့် ချိတ်ဆက်ပြီး'; + + @override + String get authSignedInReadySubtitle => 'ဝင်ထားပြီး Cloud sync အတွက် အဆင်သင့်'; + + @override + String get authActiveStatus => 'အသုံးပြုနေ'; + + @override + String get authSessionDetailsTitle => 'Session အသေးစိတ်'; + + @override + String get authUserIdLabel => 'User ID'; + + @override + String get authDeviceIdLabel => 'Device ID'; + + @override + String get authUnknownValue => 'မသိ'; + + @override + String get authDeletionNoticeTitle => 'အကောင့်ဖျက်ရန် အသိပေးချက်'; + + @override + String get authDeletionNoticeSubtitle => 'ဖျက်ရန် တောင်းဆိုချက်သည် လုပ်ဆောင်ပြီးပါက ပြန်မရနိုင်ပါ။'; + + @override + String get authDeletionNoticeLineProfileSessions => 'အကောင့်ပရိုဖိုင်နှင့် active session များကို cloud access မှ ဖယ်ရှားပါမည်။'; + + @override + String get authDeletionNoticeLineSyncedData => 'Sync လုပ်ထားသော collections, items, tags နှင့် loans များကို အပြီးအပိုင် ဖျက်နိုင်ပါသည်။'; + + @override + String get authRequestDeletionAction => 'အကောင့်ဖျက်ရန် တောင်းဆို'; + + @override + String get authSignOutAction => 'ထွက်မည်'; + + @override + String get authDoneAction => 'ပြီးပါပြီ'; + + @override + String get authHeaderCreateTitle => 'သင့်အကောင့် ဖန်တီးပါ'; + + @override + String get authHeaderWelcomeTitle => 'ပြန်လည်ကြိုဆိုပါသည်'; + + @override + String get authHeaderCreateSubtitle => 'အကောင့်မဖွင့်လည်း ရပါသည်၊ သို့သော် cloud sync နှင့် စက်အများအပြား အသုံးပြုရန် လိုအပ်ပါသည်။'; + + @override + String get authHeaderSignInSubtitle => 'Cloud sync နှင့် အကောင့်အခြေပြု လုပ်ဆောင်ချက်များ အသုံးပြုရန် ဝင်ပါ။'; + + @override + String get authUnavailableTitle => 'အတည်ပြုဝင်ရောက်မှု မရနိုင်ပါ'; } diff --git a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart index 586b0a4..da36aef 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart @@ -220,6 +220,57 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settingsFirebaseRuntimeConfigSubtitle => '查看并刷新运行时功能开关'; + @override + String get settingsMetadataTitle => '元数据与自动填充'; + + @override + String get settingsMetadataSummaryEnabled => '已启用(自动条码查询)'; + + @override + String get settingsMetadataSummaryManual => '已启用(手动查询)'; + + @override + String get settingsMetadataSummaryDisabled => '已禁用'; + + @override + String get settingsMetadataSummaryFeatureDisabled => '已被运行时功能开关禁用'; + + @override + String get settingsMetadataEnableToggleTitle => '启用元数据辅助'; + + @override + String get settingsMetadataEnableToggleSubtitle => '在条目表单中允许元数据搜索和基于条码的自动填充。'; + + @override + String get settingsMetadataAutoFetchToggleTitle => '扫描条码后自动获取'; + + @override + String get settingsMetadataAutoFetchToggleSubtitle => '扫描条码后自动获取元数据。'; + + @override + String get settingsMetadataFillEmptyOnlyToggleTitle => '仅填充空字段'; + + @override + String get settingsMetadataFillEmptyOnlyToggleSubtitle => '找到元数据时不覆盖现有标题或描述。'; + + @override + String get settingsMetadataSourcesSectionTitle => '数据源'; + + @override + String get settingsMetadataSourceAvailable => '可用'; + + @override + String get settingsMetadataSourceNotConfigured => '未配置'; + + @override + String get settingsMetadataSourceManualOnly => '仅手动'; + + @override + String get settingsMetadataManualCollectionsLabel => '漫画、音乐和自定义'; + + @override + String get settingsMetadataFeatureDisabledMessage => '元数据辅助已被运行时配置禁用。'; + @override String get settingsFirebaseRuntimeConfigSheetTitle => 'Firebase 运行时配置'; @@ -751,6 +802,17 @@ class AppLocalizationsZh extends AppLocalizations { @override String get metadataSearchSuggestionMessage => '开始输入以查找元数据。'; + @override + String get metadataSearchDisabledHint => '此集合类型不支持元数据搜索,或当前已禁用。'; + + @override + String get metadataNoMatchForBarcode => '未找到与此条码匹配的元数据。'; + + @override + String metadataSearchUnavailableForType(String collectionType) { + return '$collectionType 不支持元数据搜索。'; + } + @override String tagItemsTitle(String tag) { return '标签:$tag'; @@ -1240,4 +1302,180 @@ class AppLocalizationsZh extends AppLocalizations { @override String get loanTrackingDueDateLabel => '到期日期'; + + @override + String get authTitleAccount => '账户'; + + @override + String get authCreateAccountHeading => '创建账户'; + + @override + String get authSignInHeading => '登录'; + + @override + String get authCreateAccountDescription => '创建账户以在多台设备间同步你的收藏。'; + + @override + String get authSignInDescription => '登录以启用云同步和账户功能。'; + + @override + String get authSignInChoice => '登录'; + + @override + String get authRegisterChoice => '注册'; + + @override + String get authEmailLabel => '邮箱'; + + @override + String get authEmailHint => 'you@example.com'; + + @override + String get authEmailRequiredError => '邮箱为必填项。'; + + @override + String get authEmailInvalidError => '请输入有效的邮箱地址。'; + + @override + String get authPasswordLabel => '密码'; + + @override + String get authPasswordHint => '至少8位,A-Z、a-z、0-9'; + + @override + String get authPasswordRequiredError => '密码为必填项。'; + + @override + String get authPasswordLengthError => '密码至少需要8位字符。'; + + @override + String get authPasswordPolicyError => '密码必须包含大写字母、小写字母和数字。'; + + @override + String get authDisplayNameLabel => '显示名称(可选)'; + + @override + String get authDisplayNameHint => '我们应该如何称呼你?'; + + @override + String get authCreateAccountAction => '创建账户'; + + @override + String get authNotNowAction => '暂不'; + + @override + String get authUnavailableMessage => '当前无法使用身份验证。'; + + @override + String get authRegisterSuccess => '账户已创建并已登录。'; + + @override + String get authSignInSuccess => '登录成功。'; + + @override + String authSignInFailed(String error) { + return '登录失败:$error'; + } + + @override + String get authSignedOut => '已退出登录。'; + + @override + String get authFinalConfirmationTitle => '最终确认'; + + @override + String get authFinalConfirmationMessage => '现在提交账户删除请求吗?你将立即在此设备上退出登录。'; + + @override + String get authBackAction => '返回'; + + @override + String get authSubmitRequestAction => '提交请求'; + + @override + String get authDeletionRequestSubmitted => '账户删除请求已提交。你已退出登录。'; + + @override + String get authDeletionEndpointMissing => '后端尚未配置删除请求接口。'; + + @override + String get authDeletionImpactDialogTitle => '请求删除账户前'; + + @override + String get authDeletionImpactReviewPrompt => '请仔细确认影响。'; + + @override + String get authIrreversibleRequestTitle => '不可逆请求'; + + @override + String get authImpactLineSessionRevoked => '提交请求后,你的账户会话将立即失效。'; + + @override + String get authImpactLineCloudDataDeleted => '与该账户关联的云端同步数据在处理过程中可能被永久删除。'; + + @override + String get authImpactLineCannotRestore => '账户数据一旦删除并处理完成将无法恢复。'; + + @override + String get authUnderstandAction => '我已了解'; + + @override + String get authPasswordPolicySuffix => '请使用英文键盘字母和数字(A-Z、a-z、0-9)。'; + + @override + String get authAccountConnected => '账户已连接'; + + @override + String get authSignedInReadySubtitle => '已登录并可进行云同步'; + + @override + String get authActiveStatus => '已激活'; + + @override + String get authSessionDetailsTitle => '会话详情'; + + @override + String get authUserIdLabel => '用户 ID'; + + @override + String get authDeviceIdLabel => '设备 ID'; + + @override + String get authUnknownValue => '未知'; + + @override + String get authDeletionNoticeTitle => '账户删除提示'; + + @override + String get authDeletionNoticeSubtitle => '删除请求一旦处理即不可撤销。'; + + @override + String get authDeletionNoticeLineProfileSessions => '账户资料和活跃会话将从云端访问中移除。'; + + @override + String get authDeletionNoticeLineSyncedData => '已同步的收藏、条目、标签和借出记录可能被永久删除。'; + + @override + String get authRequestDeletionAction => '请求删除账户'; + + @override + String get authSignOutAction => '退出登录'; + + @override + String get authDoneAction => '完成'; + + @override + String get authHeaderCreateTitle => '创建你的账户'; + + @override + String get authHeaderWelcomeTitle => '欢迎回来'; + + @override + String get authHeaderCreateSubtitle => '账户不是必需的,但云同步和多设备访问需要登录账户。'; + + @override + String get authHeaderSignInSubtitle => '登录以使用云同步和账户相关功能。'; + + @override + String get authUnavailableTitle => '身份验证不可用'; } diff --git a/packages/integrations/backend_api/README.md b/packages/integrations/backend_api/README.md index b02581d..5a9b9f0 100644 --- a/packages/integrations/backend_api/README.md +++ b/packages/integrations/backend_api/README.md @@ -4,5 +4,6 @@ Backend API integration package for Collection Tracker. Provides: - auth REST client (register/login/refresh/logout/profile) +- account deletion request client helper - request/response models - backend exception model diff --git a/packages/integrations/backend_api/lib/src/clients/backend_auth_client.dart b/packages/integrations/backend_api/lib/src/clients/backend_auth_client.dart index 2b3963e..dc714f8 100644 --- a/packages/integrations/backend_api/lib/src/clients/backend_auth_client.dart +++ b/packages/integrations/backend_api/lib/src/clients/backend_auth_client.dart @@ -64,6 +64,45 @@ class BackendAuthClient { return BackendProfileResponse.fromJson(map); } + Future requestAccountDeletion({ + required String accessToken, + BackendAccountDeletionRequest request = + const BackendAccountDeletionRequest(), + }) async { + final candidatePaths = [ + '$_authPathPrefix/account-deletion-request', + '$_authPathPrefix/request-account-deletion', + '$_authPathPrefix/delete-account-request', + '$_authPathPrefix/request-deletion', + ]; + + BackendApiException? lastException; + for (final path in candidatePaths) { + try { + await _post( + path: path, + data: request.toJson(), + accessToken: accessToken, + ); + return; + } on BackendApiException catch (error) { + if (error.statusCode == 404) { + lastException = error; + continue; + } + rethrow; + } + } + + throw BackendApiException( + message: + 'Account deletion request endpoint is not available on the backend.', + statusCode: lastException?.statusCode ?? 404, + code: 'ACCOUNT_DELETION_ENDPOINT_NOT_FOUND', + raw: lastException?.raw, + ); + } + Future> _post({ required String path, required Map data, diff --git a/packages/integrations/backend_api/lib/src/models/backend_auth_models.dart b/packages/integrations/backend_api/lib/src/models/backend_auth_models.dart index 58c80f7..de98da6 100644 --- a/packages/integrations/backend_api/lib/src/models/backend_auth_models.dart +++ b/packages/integrations/backend_api/lib/src/models/backend_auth_models.dart @@ -181,3 +181,17 @@ class BackendRefreshTokenRequest { return {'refreshToken': refreshToken, 'deviceId': deviceId}; } } + +class BackendAccountDeletionRequest { + const BackendAccountDeletionRequest({ + this.reason, + this.source = 'mobile_app', + }); + + final String? reason; + final String source; + + Map toJson() { + return {'reason': reason, 'source': source}; + } +} From be644c1ec0169b2b12711ed306e6c434de1c5652 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 18:23:06 +0630 Subject: [PATCH 07/16] feat: Implement native device ID generation using the `native_id` package and refactor the device ID retrieval logic to prioritize native IDs. --- .../core/providers/backend_api_providers.dart | 38 +++++++++++++++---- .../Flutter/GeneratedPluginRegistrant.swift | 2 + apps/mobile/pubspec.yaml | 1 + 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/apps/mobile/lib/core/providers/backend_api_providers.dart b/apps/mobile/lib/core/providers/backend_api_providers.dart index 9aab51f..032b25f 100644 --- a/apps/mobile/lib/core/providers/backend_api_providers.dart +++ b/apps/mobile/lib/core/providers/backend_api_providers.dart @@ -4,6 +4,7 @@ import 'package:collection_tracker/core/auth/backend_auth_service.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:native_id/native_id.dart'; import 'package:storage/storage.dart'; import 'package:uuid/uuid.dart'; @@ -248,19 +249,40 @@ final backendDeviceIdProvider = FutureProvider((ref) async { const currentKey = 'backend_device_id'; const legacyKey = 'sync_device_id'; - String? deviceId = await storage.get(currentKey); - if (deviceId == null || deviceId.trim().isEmpty) { - deviceId = await storage.get(legacyKey); + Future persistDeviceId(String value) async { + await storage.save(currentKey, value); + await storage.save(legacyKey, value); } - if (deviceId == null || deviceId.trim().isEmpty) { - deviceId = const Uuid().v4(); + String? normalize(String? value) { + final normalized = value?.trim(); + if (normalized == null || normalized.isEmpty) { + return null; + } + return normalized; } - await storage.save(currentKey, deviceId); - await storage.save(legacyKey, deviceId); + final nativeId = normalize(await NativeIdService.getDeviceId()); + if (nativeId != null) { + await persistDeviceId(nativeId); + return nativeId; + } + + final storedCurrent = normalize(await storage.get(currentKey)); + if (storedCurrent != null) { + await persistDeviceId(storedCurrent); + return storedCurrent; + } + + final storedLegacy = normalize(await storage.get(legacyKey)); + if (storedLegacy != null) { + await persistDeviceId(storedLegacy); + return storedLegacy; + } - return deviceId; + final fallbackId = const Uuid().v4(); + await persistDeviceId(fallbackId); + return fallbackId; }); final backendAuthServiceProvider = Provider((ref) { diff --git a/apps/mobile/macos/Flutter/GeneratedPluginRegistrant.swift b/apps/mobile/macos/Flutter/GeneratedPluginRegistrant.swift index 1c09eb2..d4398d4 100644 --- a/apps/mobile/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/apps/mobile/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,6 +7,7 @@ import Foundation import amplitude_flutter import connectivity_plus +import device_info_plus import file_picker import file_selector_macos import firebase_analytics @@ -28,6 +29,7 @@ import sqlite3_flutter_libs func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AmplitudeFlutterPlugin.register(with: registry.registrar(forPlugin: "AmplitudeFlutterPlugin")) ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FirebaseAnalyticsPlugin")) diff --git a/apps/mobile/pubspec.yaml b/apps/mobile/pubspec.yaml index d652bb1..fbc6fe6 100644 --- a/apps/mobile/pubspec.yaml +++ b/apps/mobile/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: # Utilities intl: ^0.20.2 + native_id: ^1.0.0 uuid: ^4.5.2 # Firebase From 29280f9acb4801c1e62cdb85cb85123ec17568c5 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 18:39:46 +0630 Subject: [PATCH 08/16] feat: Implement data export/import functionality with file picker integration and a dedicated settings screen. --- apps/mobile/lib/core/router/app_router.dart | 7 + apps/mobile/lib/core/router/routes.dart | 1 + .../view_models/export_import_view_model.dart | 693 ++++++++++++++---- .../views/settings_data_transfer_screen.dart | 257 +++++++ .../presentation/views/settings_screen.dart | 151 +--- .../lib/src/exceptions/storage_exception.dart | 5 + .../lib/src/export_import_service.dart | 228 +++--- 7 files changed, 955 insertions(+), 387 deletions(-) create mode 100644 apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart diff --git a/apps/mobile/lib/core/router/app_router.dart b/apps/mobile/lib/core/router/app_router.dart index 6fcb1c2..b29d36d 100644 --- a/apps/mobile/lib/core/router/app_router.dart +++ b/apps/mobile/lib/core/router/app_router.dart @@ -19,6 +19,7 @@ import '../../features/scanner/presentation/views/scanner_screen.dart'; import '../../features/search/presentation/views/search_screen.dart'; import '../../features/settings/presentation/views/settings_screen.dart'; import '../../features/settings/presentation/views/settings_devtools_screen.dart'; +import '../../features/settings/presentation/views/settings_data_transfer_screen.dart'; import '../../features/settings/presentation/views/settings_metadata_screen.dart'; import '../../features/settings/presentation/views/settings_notifications_screen.dart'; import '../../features/statistics/presentation/views/statistics_screen.dart'; @@ -174,6 +175,12 @@ GoRouter appRouter(Ref ref) { parentNavigatorKey: _rootNavigatorKey, builder: (_, _) => const TagManagementScreen(), ), + GoRoute( + path: 'data-transfer', + name: 'settings-data-transfer', + parentNavigatorKey: _rootNavigatorKey, + builder: (_, _) => const SettingsDataTransferScreen(), + ), GoRoute( path: 'notifications', name: 'settings-notifications', diff --git a/apps/mobile/lib/core/router/routes.dart b/apps/mobile/lib/core/router/routes.dart index 77a021e..411de91 100644 --- a/apps/mobile/lib/core/router/routes.dart +++ b/apps/mobile/lib/core/router/routes.dart @@ -8,6 +8,7 @@ abstract final class Routes { static const scanner = '/scanner'; static const statistics = '/statistics'; static const settings = '/settings'; + static const settingsDataTransfer = '/settings/data-transfer'; static const settingsTags = '/settings/tags'; static const settingsLoans = '/settings/loans'; static const settingsMetadata = '/settings/metadata'; diff --git a/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart b/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart index 81f5390..861f603 100644 --- a/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart +++ b/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart @@ -1,8 +1,9 @@ +import 'dart:convert'; + import 'package:app_firebase/app_firebase.dart'; import 'package:collection_tracker/core/observability/operational_telemetry.dart'; import 'package:collection_tracker/core/providers/providers.dart'; import 'package:database/database.dart'; -import 'package:domain/domain.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:storage/storage.dart'; @@ -19,6 +20,8 @@ class ExportImportViewModel extends _$ExportImportViewModel { state = const AsyncValue.loading(); final performanceService = FirebasePerformanceService.instance; final stopwatch = Stopwatch()..start(); + final db = ref.read(appDatabaseProvider); + final exportService = ExportImportService(); var collectionCount = 0; var itemCount = 0; @@ -26,65 +29,106 @@ class ExportImportViewModel extends _$ExportImportViewModel { () => performanceService.traceAsync( 'settings_export_all_data_json', () async { - final collectionRepo = ref.read(collectionRepositoryProvider); - final itemRepo = ref.read(itemRepositoryProvider); - final exportService = ExportImportService(); - - final collectionsResult = await collectionRepo.getCollections(); - final collections = collectionsResult.fold( - (exception) => throw exception, - (data) => data, - ); - collectionCount = collections.length; + final collections = await db.select(db.collections).get(); + final items = await db.select(db.items).get(); + final tags = await db.select(db.tags).get(); + final itemTags = await db.select(db.itemTags).get(); + final priceHistory = await db.select(db.itemPriceHistory).get(); + final loans = await db.select(db.itemLoans).get(); - final allItems = []; - for (final collection in collections) { - final itemsResult = await itemRepo.getItems( - collectionId: collection.id, - ); - itemsResult.fold( - (exception) => null, - (items) => allItems.addAll(items), - ); - } - itemCount = allItems.length; + collectionCount = collections.length; + itemCount = items.length; - final exportData = { - 'version': '1.0.0', + final exportData = { + 'version': '2.0.0', + 'schema': 'collection_tracker_backup', 'exportDate': DateTime.now().toIso8601String(), 'collections': collections .map( - (c) => { - 'id': c.id, - 'name': c.name, - 'type': c.type.name, - 'description': c.description, - 'itemCount': c.itemCount, - 'createdAt': c.createdAt.toIso8601String(), - 'updatedAt': c.updatedAt.toIso8601String(), + (collection) => { + 'id': collection.id, + 'name': collection.name, + 'type': collection.type, + 'description': collection.description, + 'coverImagePath': collection.coverImagePath, + 'itemCount': collection.itemCount, + 'createdAt': collection.createdAt.toIso8601String(), + 'updatedAt': collection.updatedAt.toIso8601String(), + }, + ) + .toList(growable: false), + 'items': items + .map( + (item) => { + 'id': item.id, + 'collectionId': item.collectionId, + 'title': item.title, + 'barcode': item.barcode, + 'coverImageUrl': item.coverImageUrl, + 'coverImagePath': item.coverImagePath, + 'description': item.description, + 'notes': item.notes, + 'metadata': item.metadata, + 'condition': item.condition, + 'purchasePrice': item.purchasePrice, + 'purchaseDate': item.purchaseDate?.toIso8601String(), + 'currentValue': item.currentValue, + 'location': item.location, + 'isFavorite': item.isFavorite, + 'isWishlist': item.isWishlist, + 'sortOrder': item.sortOrder, + 'quantity': item.quantity, + 'createdAt': item.createdAt.toIso8601String(), + 'updatedAt': item.updatedAt.toIso8601String(), + }, + ) + .toList(growable: false), + 'tags': tags + .map( + (tag) => { + 'id': tag.id, + 'name': tag.name, + 'color': tag.color, + 'createdAt': tag.createdAt.toIso8601String(), + 'updatedAt': tag.updatedAt.toIso8601String(), }, ) - .toList(), - 'items': allItems + .toList(growable: false), + 'itemTags': itemTags .map( - (i) => { - 'id': i.id, - 'collectionId': i.collectionId, - 'title': i.title, - 'barcode': i.barcode, - 'description': i.description, - 'condition': i.condition?.name, - 'quantity': i.quantity, - 'location': i.location, - 'notes': i.notes, - 'isFavorite': i.isFavorite, - 'purchasePrice': i.purchasePrice, - 'purchaseDate': i.purchaseDate?.toIso8601String(), - 'createdAt': i.createdAt.toIso8601String(), - 'updatedAt': i.updatedAt.toIso8601String(), + (relation) => { + 'itemId': relation.itemId, + 'tagId': relation.tagId, }, ) - .toList(), + .toList(growable: false), + 'priceHistory': priceHistory + .map( + (history) => { + 'id': history.id, + 'itemId': history.itemId, + 'value': history.value, + 'recordedAt': history.recordedAt.toIso8601String(), + 'source': history.source, + }, + ) + .toList(growable: false), + 'loans': loans + .map( + (loan) => { + 'id': loan.id, + 'itemId': loan.itemId, + 'borrowerName': loan.borrowerName, + 'borrowerContact': loan.borrowerContact, + 'notes': loan.notes, + 'loanedAt': loan.loanedAt.toIso8601String(), + 'dueAt': loan.dueAt?.toIso8601String(), + 'returnedAt': loan.returnedAt?.toIso8601String(), + 'createdAt': loan.createdAt.toIso8601String(), + 'updatedAt': loan.updatedAt.toIso8601String(), + }, + ) + .toList(growable: false), }; return exportService.exportToJson(exportData); @@ -96,16 +140,20 @@ class ExportImportViewModel extends _$ExportImportViewModel { stopwatch.stop(); if (result.hasError) { + final error = result.error; + if (error is UserCancelledStorageOperationException) { + throw error; + } await OperationalTelemetry.trackDataTransfer( operation: 'export_json', success: false, durationMs: stopwatch.elapsedMilliseconds, collectionCount: collectionCount, itemCount: itemCount, - error: result.error, + error: error, stackTrace: result.stackTrace, ); - throw result.error!; + throw error!; } await OperationalTelemetry.trackDataTransfer( @@ -123,49 +171,68 @@ class ExportImportViewModel extends _$ExportImportViewModel { state = const AsyncValue.loading(); final performanceService = FirebasePerformanceService.instance; final stopwatch = Stopwatch()..start(); + final db = ref.read(appDatabaseProvider); + final exportService = ExportImportService(); var collectionCount = 0; var itemCount = 0; final result = await AsyncValue.guard( () => performanceService.traceAsync('settings_export_items_csv', () async { - final collectionRepo = ref.read(collectionRepositoryProvider); - final itemRepo = ref.read(itemRepositoryProvider); - final exportService = ExportImportService(); - - final collectionsResult = await collectionRepo.getCollections(); - final collections = collectionsResult.fold( - (exception) => throw exception, - (data) => data, - ); + final collections = await db.select(db.collections).get(); + final items = await db.select(db.items).get(); + final tags = await db.select(db.tags).get(); + final itemTags = await db.select(db.itemTags).get(); + collectionCount = collections.length; + itemCount = items.length; - final allItems = >[]; - for (final collection in collections) { - final itemsResult = await itemRepo.getItems( - collectionId: collection.id, - ); - itemsResult.fold((exception) => null, (items) { - for (final item in items) { - allItems.add({ - 'Collection': collection.name, + final collectionById = { + for (final collection in collections) collection.id: collection, + }; + final tagNameById = { + for (final tag in tags) tag.id: tag.name, + }; + final tagsByItemId = >{}; + for (final relation in itemTags) { + final tagName = tagNameById[relation.tagId]; + if (tagName == null) { + continue; + } + tagsByItemId + .putIfAbsent(relation.itemId, () => []) + .add(tagName); + } + + final rows = items + .map((item) { + final collectionName = + collectionById[item.collectionId]?.name ?? + item.collectionId; + final itemTags = (tagsByItemId[item.id] ?? const []) + .join(', '); + + return { + 'Collection': collectionName, 'Title': item.title, + 'Quantity': item.quantity.toString(), + 'Current Value': item.currentValue?.toString() ?? '', + 'Purchase Price': item.purchasePrice?.toString() ?? '', 'Barcode': item.barcode ?? '', + 'Tags': itemTags, 'Description': item.description ?? '', - 'Condition': item.condition?.name ?? '', - 'Quantity': item.quantity.toString(), + 'Condition': item.condition ?? '', 'Location': item.location ?? '', 'Notes': item.notes ?? '', 'Favorite': item.isFavorite ? 'Yes' : 'No', - 'Purchase Price': item.purchasePrice?.toString() ?? '', - 'Created': item.createdAt.toString(), - }); - } - }); - } - itemCount = allItems.length; + 'Wishlist': item.isWishlist ? 'Yes' : 'No', + 'Created': item.createdAt.toIso8601String(), + 'Updated': item.updatedAt.toIso8601String(), + }; + }) + .toList(growable: false); - return exportService.exportToCsv(allItems); + return exportService.exportToCsv(rows); }), ); @@ -173,16 +240,20 @@ class ExportImportViewModel extends _$ExportImportViewModel { stopwatch.stop(); if (result.hasError) { + final error = result.error; + if (error is UserCancelledStorageOperationException) { + throw error; + } await OperationalTelemetry.trackDataTransfer( operation: 'export_csv', success: false, durationMs: stopwatch.elapsedMilliseconds, collectionCount: collectionCount, itemCount: itemCount, - error: result.error, + error: error, stackTrace: result.stackTrace, ); - throw result.error!; + throw error!; } await OperationalTelemetry.trackDataTransfer( @@ -200,85 +271,62 @@ class ExportImportViewModel extends _$ExportImportViewModel { state = const AsyncValue.loading(); final performanceService = FirebasePerformanceService.instance; final stopwatch = Stopwatch()..start(); + final db = ref.read(appDatabaseProvider); + final exportService = ExportImportService(); var collectionCount = 0; var itemCount = 0; final result = await AsyncValue.guard( - () => performanceService.traceAsync( - 'settings_import_data_json', - () async { - final collectionDao = ref.read(collectionDaoProvider); - final itemDao = ref.read(itemDaoProvider); - final exportService = ExportImportService(); + () => + performanceService.traceAsync('settings_import_data_json', () async { + final data = await exportService.importFromJson(); - final data = await exportService.importFromJson(); + final collections = _readMapList(data, 'collections'); + final items = _readMapList(data, 'items'); + final tags = _readMapList(data, 'tags'); + final itemTags = _readMapList(data, 'itemTags'); + final priceHistory = _readMapList(data, 'priceHistory'); + final loans = _readMapList(data, 'loans'); - final collections = data['collections'] as List; - collectionCount = collections.length; - for (final collectionData in collections) { - final companion = CollectionsCompanion( - id: Value(collectionData['id'] as String), - name: Value(collectionData['name'] as String), - type: Value(collectionData['type'] as String), - description: Value(collectionData['description'] as String?), - itemCount: Value(collectionData['itemCount'] as int), - createdAt: Value( - DateTime.parse(collectionData['createdAt'] as String), - ), - updatedAt: Value( - DateTime.parse(collectionData['updatedAt'] as String), - ), - ); - await collectionDao.insertCollection(companion); - } + if (collections.isEmpty && items.isEmpty) { + throw const FormatException( + 'Invalid backup format: collections/items are missing.', + ); + } - final items = data['items'] as List; - itemCount = items.length; - for (final itemData in items) { - final companion = ItemsCompanion( - id: Value(itemData['id'] as String), - collectionId: Value(itemData['collectionId'] as String), - title: Value(itemData['title'] as String), - barcode: Value(itemData['barcode'] as String?), - description: Value(itemData['description'] as String?), - condition: Value(itemData['condition'] as String?), - quantity: Value(itemData['quantity'] as int), - location: Value(itemData['location'] as String?), - notes: Value(itemData['notes'] as String?), - isFavorite: Value(itemData['isFavorite'] as bool), - purchasePrice: Value( - itemData['purchasePrice'] != null - ? (itemData['purchasePrice'] as num).toDouble() - : null, - ), - purchaseDate: Value( - itemData['purchaseDate'] != null - ? DateTime.parse(itemData['purchaseDate'] as String) - : null, - ), - createdAt: Value(DateTime.parse(itemData['createdAt'] as String)), - updatedAt: Value(DateTime.parse(itemData['updatedAt'] as String)), - ); - await itemDao.insertItem(companion); - } - }, - ), + collectionCount = collections.length; + itemCount = items.length; + + await db.transaction(() async { + await _importCollections(db, collections); + await _importItems(db, items); + final tagIdRemap = await _importTags(db, tags); + await _importItemTags(db, itemTags, tagIdRemap); + await _importPriceHistory(db, priceHistory); + await _importLoans(db, loans); + await _recalculateCollectionItemCounts(db); + }); + }), ); _setStateSafely(result); stopwatch.stop(); if (result.hasError) { + final error = result.error; + if (error is UserCancelledStorageOperationException) { + throw error; + } await OperationalTelemetry.trackDataTransfer( operation: 'import_json', success: false, durationMs: stopwatch.elapsedMilliseconds, collectionCount: collectionCount, itemCount: itemCount, - error: result.error, + error: error, stackTrace: result.stackTrace, ); - throw result.error!; + throw error!; } await OperationalTelemetry.trackDataTransfer( @@ -290,11 +338,370 @@ class ExportImportViewModel extends _$ExportImportViewModel { ); } - void _setStateSafely(AsyncValue value) { + Future _importCollections( + AppDatabase db, + List> collections, + ) async { + for (final raw in collections) { + final id = _requiredString(raw, 'id'); + final name = _requiredString(raw, 'name'); + final type = _nullableString(raw['type']) ?? 'custom'; + final now = DateTime.now(); + + await db + .into(db.collections) + .insert( + CollectionsCompanion( + id: Value(id), + name: Value(name), + type: Value(type), + description: Value(_nullableString(raw['description'])), + coverImagePath: Value(_nullableString(raw['coverImagePath'])), + itemCount: Value(_nullableInt(raw['itemCount']) ?? 0), + createdAt: Value(_dateTimeOr(raw['createdAt'], now)), + updatedAt: Value(_dateTimeOr(raw['updatedAt'], now)), + ), + mode: InsertMode.insertOrReplace, + ); + } + } + + Future _importItems( + AppDatabase db, + List> items, + ) async { + final collections = await db.select(db.collections).get(); + final validCollectionIds = collections.map((e) => e.id).toSet(); + + for (final raw in items) { + final collectionId = _requiredString(raw, 'collectionId'); + if (!validCollectionIds.contains(collectionId)) { + continue; + } + + final id = _requiredString(raw, 'id'); + final title = _requiredString(raw, 'title'); + final now = DateTime.now(); + + await db + .into(db.items) + .insert( + ItemsCompanion( + id: Value(id), + collectionId: Value(collectionId), + title: Value(title), + barcode: Value(_nullableString(raw['barcode'])), + coverImageUrl: Value(_nullableString(raw['coverImageUrl'])), + coverImagePath: Value(_nullableString(raw['coverImagePath'])), + description: Value(_nullableString(raw['description'])), + notes: Value(_nullableString(raw['notes'])), + metadata: Value(_stringOrJson(raw['metadata'])), + condition: Value(_nullableString(raw['condition'])), + purchasePrice: Value(_nullableDouble(raw['purchasePrice'])), + purchaseDate: Value(_nullableDateTime(raw['purchaseDate'])), + currentValue: Value(_nullableDouble(raw['currentValue'])), + location: Value(_nullableString(raw['location'])), + isFavorite: Value(_boolOr(raw['isFavorite'], false)), + isWishlist: Value(_boolOr(raw['isWishlist'], false)), + sortOrder: Value(_nullableInt(raw['sortOrder']) ?? 0), + quantity: Value(_nullableInt(raw['quantity']) ?? 1), + createdAt: Value(_dateTimeOr(raw['createdAt'], now)), + updatedAt: Value(_dateTimeOr(raw['updatedAt'], now)), + ), + mode: InsertMode.insertOrReplace, + ); + } + } + + Future> _importTags( + AppDatabase db, + List> tags, + ) async { + final existingTags = await db.select(db.tags).get(); + final knownTagIds = {for (final tag in existingTags) tag.id}; + final knownTagNameToId = { + for (final tag in existingTags) tag.name.trim().toLowerCase(): tag.id, + }; + final importedToResolvedTagId = {}; + + for (final raw in tags) { + final importedId = _requiredString(raw, 'id'); + final name = _requiredString(raw, 'name'); + final normalizedName = name.trim().toLowerCase(); + final now = DateTime.now(); + + final targetId = knownTagIds.contains(importedId) + ? importedId + : (knownTagNameToId[normalizedName] ?? importedId); + + importedToResolvedTagId[importedId] = targetId; + + await db + .into(db.tags) + .insert( + TagsCompanion( + id: Value(targetId), + name: Value(name), + color: Value(_nullableString(raw['color'])), + createdAt: Value(_dateTimeOr(raw['createdAt'], now)), + updatedAt: Value(_dateTimeOr(raw['updatedAt'], now)), + ), + mode: InsertMode.insertOrReplace, + ); + + knownTagIds.add(targetId); + knownTagNameToId[normalizedName] = targetId; + } + + return importedToResolvedTagId; + } + + Future _importItemTags( + AppDatabase db, + List> itemTags, + Map tagIdRemap, + ) async { + final itemIds = (await db.select(db.items).get()).map((e) => e.id).toSet(); + final tagIds = (await db.select(db.tags).get()).map((e) => e.id).toSet(); + + for (final raw in itemTags) { + final itemId = _requiredString(raw, 'itemId'); + final importedTagId = _requiredString(raw, 'tagId'); + final resolvedTagId = tagIdRemap[importedTagId] ?? importedTagId; + + if (!itemIds.contains(itemId) || !tagIds.contains(resolvedTagId)) { + continue; + } + + await db + .into(db.itemTags) + .insert( + ItemTagsCompanion.insert(itemId: itemId, tagId: resolvedTagId), + mode: InsertMode.insertOrIgnore, + ); + } + } + + Future _importPriceHistory( + AppDatabase db, + List> priceHistory, + ) async { + final itemIds = (await db.select(db.items).get()).map((e) => e.id).toSet(); + + for (final raw in priceHistory) { + final id = _requiredString(raw, 'id'); + final itemId = _requiredString(raw, 'itemId'); + if (!itemIds.contains(itemId)) { + continue; + } + + final value = _nullableDouble(raw['value']); + if (value == null) { + continue; + } + + final now = DateTime.now(); + await db + .into(db.itemPriceHistory) + .insert( + ItemPriceHistoryCompanion( + id: Value(id), + itemId: Value(itemId), + value: Value(value), + recordedAt: Value(_dateTimeOr(raw['recordedAt'], now)), + source: Value(_nullableString(raw['source']) ?? 'manual'), + ), + mode: InsertMode.insertOrReplace, + ); + } + } + + Future _importLoans( + AppDatabase db, + List> loans, + ) async { + final itemIds = (await db.select(db.items).get()).map((e) => e.id).toSet(); + + for (final raw in loans) { + final id = _requiredString(raw, 'id'); + final itemId = _requiredString(raw, 'itemId'); + if (!itemIds.contains(itemId)) { + continue; + } + + final borrowerName = _requiredString(raw, 'borrowerName'); + final now = DateTime.now(); + + await db + .into(db.itemLoans) + .insert( + ItemLoansCompanion( + id: Value(id), + itemId: Value(itemId), + borrowerName: Value(borrowerName), + borrowerContact: Value(_nullableString(raw['borrowerContact'])), + notes: Value(_nullableString(raw['notes'])), + loanedAt: Value(_dateTimeOr(raw['loanedAt'], now)), + dueAt: Value(_nullableDateTime(raw['dueAt'])), + returnedAt: Value(_nullableDateTime(raw['returnedAt'])), + createdAt: Value(_dateTimeOr(raw['createdAt'], now)), + updatedAt: Value(_dateTimeOr(raw['updatedAt'], now)), + ), + mode: InsertMode.insertOrReplace, + ); + } + } + + Future _recalculateCollectionItemCounts(AppDatabase db) async { + final allCollections = await db.select(db.collections).get(); + final now = DateTime.now(); + + for (final collection in allCollections) { + final row = await db + .customSelect( + ''' + SELECT COUNT(*) AS count + FROM items + WHERE collection_id = ? + ''', + variables: [Variable(collection.id)], + readsFrom: {db.items}, + ) + .getSingle(); + final count = row.read('count'); + + await (db.update( + db.collections, + )..where((tbl) => tbl.id.equals(collection.id))).write( + CollectionsCompanion(itemCount: Value(count), updatedAt: Value(now)), + ); + } + } + + List> _readMapList( + Map source, + String key, + ) { + final value = source[key]; + if (value == null) { + return const >[]; + } + if (value is! List) { + throw FormatException('Invalid backup format: "$key" must be a list.'); + } + + return value + .map>((entry) { + if (entry is Map) { + return entry; + } + if (entry is Map) { + return entry.map( + (mapKey, mapValue) => MapEntry(mapKey.toString(), mapValue), + ); + } + throw FormatException( + 'Invalid backup format: "$key" contains a non-object element.', + ); + }) + .toList(growable: false); + } + + String _requiredString(Map source, String key) { + final value = _nullableString(source[key]); + if (value == null) { + throw FormatException('Invalid backup data: "$key" is required.'); + } + return value; + } + + String? _nullableString(dynamic value) { + if (value == null) { + return null; + } + final normalized = value.toString().trim(); + return normalized.isEmpty ? null : normalized; + } + + String? _stringOrJson(dynamic value) { + if (value == null) { + return null; + } + if (value is String) { + final normalized = value.trim(); + return normalized.isEmpty ? null : normalized; + } + return jsonEncode(value); + } + + int? _nullableInt(dynamic value) { + if (value == null) { + return null; + } + if (value is int) { + return value; + } + if (value is num) { + return value.toInt(); + } + return int.tryParse(value.toString()); + } + + double? _nullableDouble(dynamic value) { + if (value == null) { + return null; + } + if (value is double) { + return value; + } + if (value is num) { + return value.toDouble(); + } + return double.tryParse(value.toString()); + } + + bool _boolOr(dynamic value, bool fallback) { + if (value is bool) { + return value; + } + if (value is num) { + return value != 0; + } + if (value is String) { + final normalized = value.trim().toLowerCase(); + if (normalized == 'true' || normalized == 'yes' || normalized == '1') { + return true; + } + if (normalized == 'false' || normalized == 'no' || normalized == '0') { + return false; + } + } + return fallback; + } + + DateTime _dateTimeOr(dynamic value, DateTime fallback) { + return _nullableDateTime(value) ?? fallback; + } + + DateTime? _nullableDateTime(dynamic value) { + if (value == null) { + return null; + } + if (value is DateTime) { + return value; + } + final text = value.toString().trim(); + if (text.isEmpty) { + return null; + } + return DateTime.tryParse(text); + } + + void _setStateSafely(AsyncValue value) { try { - state = value; + state = value.whenData((_) {}); } catch (_) { - // Ignore if provider was auto-disposed while async work was running. + // Ignore if provider was disposed while async work was running. } } } diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart new file mode 100644 index 0000000..c3dda54 --- /dev/null +++ b/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart @@ -0,0 +1,257 @@ +import 'package:collection_tracker/l10n/l10n.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:storage/storage.dart'; +import 'package:ui/ui.dart'; + +import '../view_models/export_import_view_model.dart'; +import '../widgets/settings_primitives.dart'; + +class SettingsDataTransferScreen extends ConsumerStatefulWidget { + const SettingsDataTransferScreen({super.key}); + + @override + ConsumerState createState() => + _SettingsDataTransferScreenState(); +} + +class _SettingsDataTransferScreenState + extends ConsumerState { + bool _isBusy = false; + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return Scaffold( + appBar: AppBar( + title: Text( + '${l10n.settingsExportJsonTitle} / ${l10n.settingsImportJsonTitle}', + ), + ), + body: ListView( + padding: const EdgeInsets.fromLTRB( + AppSpacing.lg, + AppSpacing.md, + AppSpacing.lg, + AppSpacing.xxl, + ), + children: [ + AppReveal( + child: AppCard( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.settingsSectionData, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + ), + ), + const SizedBox(height: AppSpacing.sm), + Text( + l10n.settingsExportJsonSubtitle, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: AppSpacing.xs), + Text( + l10n.settingsImportJsonSubtitle, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ], + ), + ), + ), + const SizedBox(height: AppSpacing.lg), + AppReveal( + delay: AppMotion.stagger, + child: SettingsSection( + title: l10n.settingsExportJsonTitle, + children: [ + SettingsTile( + icon: Icons.file_download_outlined, + title: l10n.settingsExportJsonTitle, + subtitle: l10n.settingsExportJsonSubtitle, + enabled: !_isBusy, + onTap: _isBusy ? null : _handleExportJson, + ), + SettingsTile( + icon: Icons.table_chart_outlined, + title: l10n.settingsExportCsvTitle, + subtitle: l10n.settingsExportCsvSubtitle, + enabled: !_isBusy, + onTap: _isBusy ? null : _handleExportCsv, + ), + ], + ), + ), + const SizedBox(height: AppSpacing.lg), + AppReveal( + delay: AppMotion.stagger * 2, + child: SettingsSection( + title: l10n.settingsImportJsonTitle, + children: [ + SettingsTile( + icon: Icons.file_upload_outlined, + title: l10n.settingsImportJsonTitle, + subtitle: l10n.settingsImportJsonSubtitle, + enabled: !_isBusy, + onTap: _isBusy ? null : _handleImportJson, + ), + ], + ), + ), + ], + ), + ); + } + + Future _handleExportJson() async { + final l10n = context.l10n; + final messenger = ScaffoldMessenger.of(context); + if (_isBusy) { + return; + } + + setState(() => _isBusy = true); + try { + messenger.showSnackBar( + SnackBar(content: Text(l10n.settingsExportingData)), + ); + await ref + .read(exportImportViewModelProvider.notifier) + .exportAllDataToJson(); + if (!mounted) { + return; + } + messenger.showSnackBar( + SnackBar( + content: Text(l10n.settingsDataExportSuccess), + backgroundColor: Colors.green, + ), + ); + } on UserCancelledStorageOperationException { + // User canceled picker/save dialog. Keep silent. + } catch (error) { + if (!mounted) { + return; + } + messenger.showSnackBar( + SnackBar( + content: Text(l10n.settingsExportFailed('$error')), + backgroundColor: Colors.red, + ), + ); + } finally { + if (mounted) { + setState(() => _isBusy = false); + } + } + } + + Future _handleExportCsv() async { + final l10n = context.l10n; + final messenger = ScaffoldMessenger.of(context); + if (_isBusy) { + return; + } + + setState(() => _isBusy = true); + try { + messenger.showSnackBar( + SnackBar(content: Text(l10n.settingsExportingData)), + ); + await ref.read(exportImportViewModelProvider.notifier).exportItemsToCsv(); + if (!mounted) { + return; + } + messenger.showSnackBar( + SnackBar( + content: Text(l10n.settingsDataExportSuccess), + backgroundColor: Colors.green, + ), + ); + } on UserCancelledStorageOperationException { + // User canceled picker/save dialog. Keep silent. + } catch (error) { + if (!mounted) { + return; + } + messenger.showSnackBar( + SnackBar( + content: Text(l10n.settingsExportFailed('$error')), + backgroundColor: Colors.red, + ), + ); + } finally { + if (mounted) { + setState(() => _isBusy = false); + } + } + } + + Future _handleImportJson() async { + final l10n = context.l10n; + final messenger = ScaffoldMessenger.of(context); + if (_isBusy) { + return; + } + + final confirmed = await showAppDialog( + context: context, + title: Text(l10n.settingsImportDataTitle), + content: Text(l10n.settingsImportDataMessage), + actions: [ + AppButton( + label: l10n.actionCancel, + variant: AppButtonVariant.ghost, + onPressed: () => closeAppDialog(context, false), + ), + AppButton( + label: l10n.actionImport, + onPressed: () => closeAppDialog(context, true), + ), + ], + ); + + if (confirmed != true || !mounted) { + return; + } + + setState(() => _isBusy = true); + try { + messenger.showSnackBar( + SnackBar(content: Text(l10n.settingsImportingData)), + ); + await ref.read(exportImportViewModelProvider.notifier).importFromJson(); + if (!mounted) { + return; + } + messenger.showSnackBar( + SnackBar( + content: Text(l10n.settingsDataImportSuccess), + backgroundColor: Colors.green, + ), + ); + } on UserCancelledStorageOperationException { + // User canceled picker/save dialog. Keep silent. + } catch (error) { + if (!mounted) { + return; + } + messenger.showSnackBar( + SnackBar( + content: Text(l10n.settingsImportFailed('$error')), + backgroundColor: Colors.red, + ), + ); + } finally { + if (mounted) { + setState(() => _isBusy = false); + } + } + } +} diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart index 6cff69d..128005b 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_screen.dart @@ -10,10 +10,8 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; -import 'package:storage/storage.dart'; import 'package:ui/ui.dart'; -import '../view_models/export_import_view_model.dart'; import '../widgets/settings_primitives.dart'; class SettingsScreen extends ConsumerWidget { @@ -119,22 +117,12 @@ class SettingsScreen extends ConsumerWidget { title: l10n.settingsSectionData, children: [ SettingsTile( - icon: Icons.file_download, - title: l10n.settingsExportJsonTitle, - subtitle: l10n.settingsExportJsonSubtitle, - onTap: () => _handleExportJson(context, ref), - ), - SettingsTile( - icon: Icons.table_chart, - title: l10n.settingsExportCsvTitle, - subtitle: l10n.settingsExportCsvSubtitle, - onTap: () => _handleExportCsv(context, ref), - ), - SettingsTile( - icon: Icons.file_upload, - title: l10n.settingsImportJsonTitle, - subtitle: l10n.settingsImportJsonSubtitle, - onTap: () => _handleImportJson(context, ref), + icon: Icons.folder_shared_outlined, + title: + '${l10n.settingsExportJsonTitle} / ${l10n.settingsImportJsonTitle}', + subtitle: + '${l10n.settingsExportJsonSubtitle}. ${l10n.settingsImportJsonSubtitle}.', + onTap: () => context.push(Routes.settingsDataTransfer), ), SettingsTile( icon: Icons.cloud_upload, @@ -196,133 +184,6 @@ class SettingsScreen extends ConsumerWidget { ); } - Future _handleExportJson(BuildContext context, WidgetRef ref) async { - final l10n = context.l10n; - try { - final messenger = ScaffoldMessenger.of(context); - messenger.showSnackBar( - SnackBar(content: Text(l10n.settingsExportingData)), - ); - - final filePath = await ref - .read(exportImportViewModelProvider.notifier) - .exportAllDataToJson(); - - final exportService = ExportImportService(); - await exportService.shareFile(filePath, 'collection_tracker_export.json'); - - if (!context.mounted) { - return; - } - messenger.showSnackBar( - SnackBar( - content: Text(l10n.settingsDataExportSuccess), - backgroundColor: Colors.green, - ), - ); - } catch (error) { - if (!context.mounted) { - return; - } - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(l10n.settingsExportFailed('$error')), - backgroundColor: Colors.red, - ), - ); - } - } - - Future _handleExportCsv(BuildContext context, WidgetRef ref) async { - final l10n = context.l10n; - try { - final messenger = ScaffoldMessenger.of(context); - messenger.showSnackBar( - SnackBar(content: Text(l10n.settingsExportingData)), - ); - - final filePath = await ref - .read(exportImportViewModelProvider.notifier) - .exportItemsToCsv(); - - final exportService = ExportImportService(); - await exportService.shareFile(filePath, 'collection_tracker_export.csv'); - - if (!context.mounted) { - return; - } - messenger.showSnackBar( - SnackBar( - content: Text(l10n.settingsDataExportSuccess), - backgroundColor: Colors.green, - ), - ); - } catch (error) { - if (!context.mounted) { - return; - } - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(l10n.settingsExportFailed('$error')), - backgroundColor: Colors.red, - ), - ); - } - } - - Future _handleImportJson(BuildContext context, WidgetRef ref) async { - final l10n = context.l10n; - final confirmed = await showAppDialog( - context: context, - title: Text(l10n.settingsImportDataTitle), - content: Text(l10n.settingsImportDataMessage), - actions: [ - AppButton( - label: l10n.actionCancel, - variant: AppButtonVariant.ghost, - onPressed: () => closeAppDialog(context, false), - ), - AppButton( - label: l10n.actionImport, - onPressed: () => closeAppDialog(context, true), - ), - ], - ); - - if (confirmed != true || !context.mounted) { - return; - } - - try { - final messenger = ScaffoldMessenger.of(context); - messenger.showSnackBar( - SnackBar(content: Text(l10n.settingsImportingData)), - ); - - await ref.read(exportImportViewModelProvider.notifier).importFromJson(); - - if (!context.mounted) { - return; - } - messenger.showSnackBar( - SnackBar( - content: Text(l10n.settingsDataImportSuccess), - backgroundColor: Colors.green, - ), - ); - } catch (error) { - if (!context.mounted) { - return; - } - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(l10n.settingsImportFailed('$error')), - backgroundColor: Colors.red, - ), - ); - } - } - Future _showCloudSyncStatusSheet( BuildContext context, WidgetRef ref, diff --git a/packages/integrations/storage/lib/src/exceptions/storage_exception.dart b/packages/integrations/storage/lib/src/exceptions/storage_exception.dart index 869d359..1a18383 100644 --- a/packages/integrations/storage/lib/src/exceptions/storage_exception.dart +++ b/packages/integrations/storage/lib/src/exceptions/storage_exception.dart @@ -35,3 +35,8 @@ class TypeMismatchException extends StorageException { class SerializationException extends StorageException { SerializationException(super.message, {super.key, super.originalError}); } + +/// Exception for user-cancelled storage operations, such as picker dialogs. +class UserCancelledStorageOperationException extends StorageException { + UserCancelledStorageOperationException(super.message); +} diff --git a/packages/integrations/storage/lib/src/export_import_service.dart b/packages/integrations/storage/lib/src/export_import_service.dart index 8b7bd94..0c08f78 100644 --- a/packages/integrations/storage/lib/src/export_import_service.dart +++ b/packages/integrations/storage/lib/src/export_import_service.dart @@ -1,89 +1,83 @@ import 'dart:convert'; -import 'dart:io'; +import 'dart:typed_data'; import 'package:file_picker/file_picker.dart' as fp; -import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; +import 'package:storage/src/exceptions/storage_exception.dart'; class ExportImportService { - // Export data to JSON Future exportToJson(Map data) async { - try { - final jsonString = const JsonEncoder.withIndent(' ').convert(data); - - final timestamp = DateTime.now().millisecondsSinceEpoch; - final file = await _getExportFile( - 'collection_tracker_export_$timestamp.json', - ); - await file.writeAsString(jsonString); - - return file.path; - } catch (e) { - throw Exception('Failed to export to JSON: $e'); - } + final jsonString = const JsonEncoder.withIndent(' ').convert(data); + final bytes = Uint8List.fromList(utf8.encode(jsonString)); + final timestamp = DateTime.now().millisecondsSinceEpoch; + final fileName = 'collection_tracker_export_$timestamp.json'; + return _saveToUserSelectedLocation( + bytes: bytes, + fileName: fileName, + allowedExtensions: const ['json'], + dialogTitle: 'Save JSON export', + ); } - // Export data to CSV Future exportToCsv(List> items) async { - try { - if (items.isEmpty) { - throw Exception('No data to export'); - } - - final headers = items.first.keys.toList(); - final csvLines = []; - - // Add header row - csvLines.add(headers.map((h) => _escapeCsvValue(h)).join(',')); - - // Add data rows - for (final item in items) { - final row = headers - .map((header) { - final value = item[header]?.toString() ?? ''; - return _escapeCsvValue(value); - }) - .join(','); - csvLines.add(row); - } - - final csvString = csvLines.join('\n'); + if (items.isEmpty) { + throw StorageException('No data to export as CSV.'); + } - final timestamp = DateTime.now().millisecondsSinceEpoch; - final file = await _getExportFile( - 'collection_tracker_export_$timestamp.csv', - ); - await file.writeAsString(csvString); + final headers = items.first.keys.toList(); + final csvLines = []; - return file.path; - } catch (e) { - throw Exception('Failed to export to CSV: $e'); + csvLines.add(headers.map((h) => _escapeCsvValue(h)).join(',')); + for (final item in items) { + final row = headers + .map((header) => _escapeCsvValue(item[header]?.toString() ?? '')) + .join(','); + csvLines.add(row); } + + final csvString = csvLines.join('\n'); + final bytes = Uint8List.fromList(utf8.encode(csvString)); + final timestamp = DateTime.now().millisecondsSinceEpoch; + final fileName = 'collection_tracker_export_$timestamp.csv'; + + return _saveToUserSelectedLocation( + bytes: bytes, + fileName: fileName, + allowedExtensions: const ['csv'], + dialogTitle: 'Save CSV export', + ); } - Future _getExportFile(String fileName) async { - Directory? directory; - if (Platform.isMacOS || Platform.isWindows || Platform.isLinux) { - directory = await getDownloadsDirectory(); - } else if (Platform.isAndroid) { - // Try to get the public downloads directory on Android - final externalDirs = await getExternalStorageDirectories( - type: StorageDirectory.downloads, + Future _saveToUserSelectedLocation({ + required Uint8List bytes, + required String fileName, + required List allowedExtensions, + required String dialogTitle, + }) async { + try { + final savedPath = await fp.FilePicker.platform.saveFile( + dialogTitle: dialogTitle, + fileName: fileName, + type: fp.FileType.custom, + allowedExtensions: allowedExtensions, + bytes: bytes, ); - if (externalDirs != null && externalDirs.isNotEmpty) { - directory = externalDirs.first; - } else { - directory = await getExternalStorageDirectory(); - } - } else if (Platform.isIOS) { - // getApplicationDocumentsDirectory is public if UIFileSharingEnabled is set in Info.plist - directory = await getApplicationDocumentsDirectory(); - } - directory ??= await getApplicationDocumentsDirectory(); + if (savedPath == null || savedPath.trim().isEmpty) { + throw UserCancelledStorageOperationException( + 'File save was cancelled by user.', + ); + } - final filePath = '${directory.path}/$fileName'; - return File(filePath); + return savedPath; + } on UserCancelledStorageOperationException { + rethrow; + } catch (error) { + throw StorageException( + 'Failed to save export file.', + originalError: error, + ); + } } String _escapeCsvValue(String value) { @@ -93,7 +87,6 @@ class ExportImportService { return value; } - // Share exported file Future shareFile(String filePath, String fileName) async { try { final file = XFile(filePath); @@ -104,83 +97,120 @@ class ExportImportService { text: 'My collection data from Collection Tracker', ), ); - } catch (e) { - throw Exception('Failed to share file: $e'); + } catch (error) { + throw StorageException('Failed to share file.', originalError: error); } } - // Import from JSON Future> importFromJson() async { try { final result = await fp.FilePicker.platform.pickFiles( type: fp.FileType.custom, - allowedExtensions: ['json'], + allowedExtensions: const ['json'], + withData: true, ); if (result == null || result.files.isEmpty) { - throw Exception('No file selected'); + throw UserCancelledStorageOperationException( + 'Import cancelled by user.', + ); } - final file = File(result.files.first.path!); - final jsonString = await file.readAsString(); - final data = jsonDecode(jsonString) as Map; + final selected = result.files.first; + final bytes = selected.bytes; + final path = selected.path; - return data; - } catch (e) { - throw Exception('Failed to import from JSON: $e'); + String jsonString; + if (bytes != null) { + jsonString = utf8.decode(bytes); + } else if (path != null && path.trim().isNotEmpty) { + jsonString = await XFile(path).readAsString(); + } else { + throw StorageException('Unable to read selected file.'); + } + + final decoded = jsonDecode(jsonString); + if (decoded is! Map) { + throw StorageException('Invalid JSON format: expected an object root.'); + } + return decoded; + } on UserCancelledStorageOperationException { + rethrow; + } catch (error) { + throw StorageException( + 'Failed to import JSON file.', + originalError: error, + ); } } - // Import from CSV Future>> importFromCsv() async { try { final result = await fp.FilePicker.platform.pickFiles( type: fp.FileType.custom, - allowedExtensions: ['csv'], + allowedExtensions: const ['csv'], + withData: true, ); if (result == null || result.files.isEmpty) { - throw Exception('No file selected'); + throw UserCancelledStorageOperationException( + 'Import cancelled by user.', + ); } - final file = File(result.files.first.path!); - final csvString = await file.readAsString(); + final selected = result.files.first; + final bytes = selected.bytes; + final path = selected.path; + + String csvString; + if (bytes != null) { + csvString = utf8.decode(bytes); + } else if (path != null && path.trim().isNotEmpty) { + csvString = await XFile(path).readAsString(); + } else { + throw StorageException('Unable to read selected file.'); + } final lines = csvString.split('\n'); if (lines.isEmpty) { - throw Exception('Empty CSV file'); + throw StorageException('CSV file is empty.'); } - final headers = _parseCsvLine(lines[0]); + final headers = _parseCsvLine(lines.first); final data = >[]; - for (int i = 1; i < lines.length; i++) { - if (lines[i].trim().isEmpty) continue; + for (var index = 1; index < lines.length; index++) { + final line = lines[index].trimRight(); + if (line.isEmpty) { + continue; + } - final values = _parseCsvLine(lines[i]); + final values = _parseCsvLine(line); final row = {}; - - for (int j = 0; j < headers.length && j < values.length; j++) { - row[headers[j]] = values[j]; + for (var i = 0; i < headers.length && i < values.length; i++) { + row[headers[i]] = values[i]; } - data.add(row); } return data; - } catch (e) { - throw Exception('Failed to import from CSV: $e'); + } on UserCancelledStorageOperationException { + rethrow; + } catch (error) { + throw StorageException( + 'Failed to import CSV file.', + originalError: error, + ); } } List _parseCsvLine(String line) { final values = []; final buffer = StringBuffer(); - bool inQuotes = false; + var inQuotes = false; - for (int i = 0; i < line.length; i++) { + for (var i = 0; i < line.length; i++) { final char = line[i]; - if (char == '"') { if (inQuotes && i + 1 < line.length && line[i + 1] == '"') { buffer.write('"'); From 02b0c2173173da60f2f82dd35e2ef93fc7acd8d1 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 18:55:28 +0630 Subject: [PATCH 09/16] feat: Implement a data import preview dialog and correct newline characters in localization strings. --- .../view_models/export_import_view_model.dart | 96 ++++++++++- .../views/settings_data_transfer_screen.dart | 155 +++++++++++++++--- apps/mobile/lib/l10n/arb/app_en.arb | 6 +- apps/mobile/lib/l10n/arb/app_es.arb | 6 +- apps/mobile/lib/l10n/arb/app_id.arb | 6 +- apps/mobile/lib/l10n/arb/app_ja.arb | 6 +- apps/mobile/lib/l10n/arb/app_ko.arb | 6 +- apps/mobile/lib/l10n/arb/app_my.arb | 6 +- apps/mobile/lib/l10n/arb/app_zh.arb | 6 +- .../lib/l10n/gen/app_localizations.dart | 6 +- .../lib/l10n/gen/app_localizations_en.dart | 6 +- .../lib/l10n/gen/app_localizations_es.dart | 6 +- .../lib/l10n/gen/app_localizations_id.dart | 6 +- .../lib/l10n/gen/app_localizations_ja.dart | 6 +- .../lib/l10n/gen/app_localizations_ko.dart | 6 +- .../lib/l10n/gen/app_localizations_my.dart | 6 +- .../lib/l10n/gen/app_localizations_zh.dart | 6 +- .../lib/src/export_import_service.dart | 19 ++- 18 files changed, 288 insertions(+), 72 deletions(-) diff --git a/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart b/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart index 861f603..1c6af0b 100644 --- a/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart +++ b/apps/mobile/lib/features/settings/presentation/view_models/export_import_view_model.dart @@ -9,6 +9,34 @@ import 'package:storage/storage.dart'; part 'export_import_view_model.g.dart'; +class JsonImportPreview { + const JsonImportPreview({ + required this.fileName, + required this.version, + required this.schema, + required this.collectionCount, + required this.itemCount, + required this.tagCount, + required this.itemTagCount, + required this.priceHistoryCount, + required this.loanCount, + required this.warnings, + required this.payload, + }); + + final String fileName; + final String? version; + final String? schema; + final int collectionCount; + final int itemCount; + final int tagCount; + final int itemTagCount; + final int priceHistoryCount; + final int loanCount; + final List warnings; + final Map payload; +} + @riverpod class ExportImportViewModel extends _$ExportImportViewModel { @override @@ -267,20 +295,66 @@ class ExportImportViewModel extends _$ExportImportViewModel { return result.value!; } + Future prepareJsonImportPreview() async { + final exportService = ExportImportService(); + final picked = await exportService.pickJsonImportFile(); + final payload = picked.data; + + final warnings = []; + final version = _nullableString(payload['version']); + final schema = _nullableString(payload['schema']); + + if (schema != null && schema != 'collection_tracker_backup') { + warnings.add('Backup schema "$schema" is not recognized.'); + } + + final collectionCount = _countListSection(payload, 'collections', warnings); + final itemCount = _countListSection(payload, 'items', warnings); + final tagCount = _countListSection(payload, 'tags', warnings); + final itemTagCount = _countListSection(payload, 'itemTags', warnings); + final priceHistoryCount = _countListSection( + payload, + 'priceHistory', + warnings, + ); + final loanCount = _countListSection(payload, 'loans', warnings); + + if (collectionCount == 0 && itemCount == 0) { + warnings.add('No collections or items found in this backup.'); + } + + return JsonImportPreview( + fileName: picked.fileName, + version: version, + schema: schema, + collectionCount: collectionCount, + itemCount: itemCount, + tagCount: tagCount, + itemTagCount: itemTagCount, + priceHistoryCount: priceHistoryCount, + loanCount: loanCount, + warnings: warnings, + payload: payload, + ); + } + Future importFromJson() async { + final exportService = ExportImportService(); + final picked = await exportService.pickJsonImportFile(); + await importFromJsonPayload(picked.data); + } + + Future importFromJsonPayload(Map data) async { state = const AsyncValue.loading(); final performanceService = FirebasePerformanceService.instance; final stopwatch = Stopwatch()..start(); final db = ref.read(appDatabaseProvider); - final exportService = ExportImportService(); var collectionCount = 0; var itemCount = 0; final result = await AsyncValue.guard( () => performanceService.traceAsync('settings_import_data_json', () async { - final data = await exportService.importFromJson(); - final collections = _readMapList(data, 'collections'); final items = _readMapList(data, 'items'); final tags = _readMapList(data, 'tags'); @@ -578,6 +652,22 @@ class ExportImportViewModel extends _$ExportImportViewModel { } } + int _countListSection( + Map source, + String key, + List warnings, + ) { + final value = source[key]; + if (value == null) { + return 0; + } + if (value is! List) { + warnings.add('Section "$key" has invalid format and will be skipped.'); + return 0; + } + return value.length; + } + List> _readMapList( Map source, String key, diff --git a/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart b/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart index c3dda54..536367e 100644 --- a/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart +++ b/apps/mobile/lib/features/settings/presentation/views/settings_data_transfer_screen.dart @@ -200,33 +200,26 @@ class _SettingsDataTransferScreenState return; } - final confirmed = await showAppDialog( - context: context, - title: Text(l10n.settingsImportDataTitle), - content: Text(l10n.settingsImportDataMessage), - actions: [ - AppButton( - label: l10n.actionCancel, - variant: AppButtonVariant.ghost, - onPressed: () => closeAppDialog(context, false), - ), - AppButton( - label: l10n.actionImport, - onPressed: () => closeAppDialog(context, true), - ), - ], - ); - - if (confirmed != true || !mounted) { - return; - } - setState(() => _isBusy = true); try { + final preview = await ref + .read(exportImportViewModelProvider.notifier) + .prepareJsonImportPreview(); + if (!mounted) { + return; + } + + final confirmed = await _showImportPreviewDialog(preview); + if (confirmed != true || !mounted) { + return; + } + messenger.showSnackBar( SnackBar(content: Text(l10n.settingsImportingData)), ); - await ref.read(exportImportViewModelProvider.notifier).importFromJson(); + await ref + .read(exportImportViewModelProvider.notifier) + .importFromJsonPayload(preview.payload); if (!mounted) { return; } @@ -254,4 +247,122 @@ class _SettingsDataTransferScreenState } } } + + Future _showImportPreviewDialog(JsonImportPreview preview) { + final l10n = context.l10n; + final colorScheme = Theme.of(context).colorScheme; + final warningText = preview.warnings.join('\n'); + + return showAppDialog( + context: context, + title: Text(l10n.settingsImportDataTitle), + content: ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 420), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.settingsImportDataMessage, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: colorScheme.onSurfaceVariant, + ), + ), + const SizedBox(height: AppSpacing.md), + _PreviewRow(label: 'File', value: preview.fileName), + if (preview.version != null) + _PreviewRow(label: 'Version', value: preview.version!), + if (preview.schema != null) + _PreviewRow(label: 'Schema', value: preview.schema!), + const SizedBox(height: AppSpacing.sm), + _PreviewRow( + label: 'Collections', + value: preview.collectionCount.toString(), + ), + _PreviewRow(label: 'Items', value: preview.itemCount.toString()), + _PreviewRow(label: 'Tags', value: preview.tagCount.toString()), + _PreviewRow( + label: 'Item-Tag Links', + value: preview.itemTagCount.toString(), + ), + _PreviewRow( + label: 'Price History', + value: preview.priceHistoryCount.toString(), + ), + _PreviewRow(label: 'Loans', value: preview.loanCount.toString()), + if (warningText.isNotEmpty) ...[ + const SizedBox(height: AppSpacing.md), + Container( + width: double.infinity, + padding: const EdgeInsets.all(AppSpacing.sm), + decoration: BoxDecoration( + color: colorScheme.errorContainer.withValues(alpha: 0.85), + borderRadius: BorderRadius.circular(AppRadii.sm), + border: Border.all( + color: colorScheme.error.withValues(alpha: 0.35), + ), + ), + child: Text( + warningText, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: colorScheme.onErrorContainer, + fontWeight: FontWeight.w600, + ), + ), + ), + ], + ], + ), + ), + ), + actions: [ + AppButton( + label: l10n.actionCancel, + variant: AppButtonVariant.ghost, + onPressed: () => closeAppDialog(context, false), + ), + AppButton( + label: l10n.actionImport, + onPressed: () => closeAppDialog(context, true), + ), + ], + ); + } +} + +class _PreviewRow extends StatelessWidget { + const _PreviewRow({required this.label, required this.value}); + + final String label; + final String value; + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(bottom: AppSpacing.xs), + child: Row( + children: [ + Expanded( + child: Text( + label, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context).colorScheme.onSurfaceVariant, + fontWeight: FontWeight.w600, + ), + ), + ), + const SizedBox(width: AppSpacing.sm), + Flexible( + child: Text( + value, + textAlign: TextAlign.end, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(fontWeight: FontWeight.w700), + ), + ), + ], + ), + ); + } } diff --git a/apps/mobile/lib/l10n/arb/app_en.arb b/apps/mobile/lib/l10n/arb/app_en.arb index db6f32d..0a90104 100644 --- a/apps/mobile/lib/l10n/arb/app_en.arb +++ b/apps/mobile/lib/l10n/arb/app_en.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "Import Data", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "This will import collections and items from a JSON file. Existing data will not be deleted.\\n\\nContinue?", + "settingsImportDataMessage": "This will import collections and items from a JSON file. Existing data will not be deleted.\n\nContinue?", "@settingsImportDataMessage": {}, "settingsImportingData": "Importing data...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "Delete Selected Tags", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "Delete {count} selected tags from all items?\\n\\nThis cannot be undone.", + "tagManagementDeleteSelectedMessage": "Delete {count} selected tags from all items?\n\nThis cannot be undone.", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "Delete Tag", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "Delete \"{tagName}\" from all items?\\n\\nThis cannot be undone.", + "tagManagementDeleteMessage": "Delete \"{tagName}\" from all items?\n\nThis cannot be undone.", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/arb/app_es.arb b/apps/mobile/lib/l10n/arb/app_es.arb index bc5324c..03600f7 100644 --- a/apps/mobile/lib/l10n/arb/app_es.arb +++ b/apps/mobile/lib/l10n/arb/app_es.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "Importar datos", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "Esto importará colecciones y artículos desde un archivo JSON. Los datos existentes no se eliminarán.\\n\\n¿Continuar?", + "settingsImportDataMessage": "Esto importará colecciones y artículos desde un archivo JSON. Los datos existentes no se eliminarán.\n\n¿Continuar?", "@settingsImportDataMessage": {}, "settingsImportingData": "Importando datos...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "Eliminar etiquetas seleccionadas", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "¿Eliminar {count} etiquetas seleccionadas de todos los artículos?\\n\\nEsto no se puede deshacer.", + "tagManagementDeleteSelectedMessage": "¿Eliminar {count} etiquetas seleccionadas de todos los artículos?\n\nEsto no se puede deshacer.", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "Eliminar etiqueta", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "¿Eliminar \"{tagName}\" de todos los artículos?\\n\\nEsto no se puede deshacer.", + "tagManagementDeleteMessage": "¿Eliminar \"{tagName}\" de todos los artículos?\n\nEsto no se puede deshacer.", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/arb/app_id.arb b/apps/mobile/lib/l10n/arb/app_id.arb index a8ffbc0..944d184 100644 --- a/apps/mobile/lib/l10n/arb/app_id.arb +++ b/apps/mobile/lib/l10n/arb/app_id.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "Impor Data", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "Ini akan mengimpor koleksi dan item dari file JSON. Data yang sudah ada tidak akan dihapus.\\n\\nLanjutkan?", + "settingsImportDataMessage": "Ini akan mengimpor koleksi dan item dari file JSON. Data yang sudah ada tidak akan dihapus.\n\nLanjutkan?", "@settingsImportDataMessage": {}, "settingsImportingData": "Mengimpor data...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "Hapus Tag Terpilih", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "Hapus {count} tag terpilih dari semua item?\\n\\nTindakan ini tidak dapat dibatalkan.", + "tagManagementDeleteSelectedMessage": "Hapus {count} tag terpilih dari semua item?\n\nTindakan ini tidak dapat dibatalkan.", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "Hapus Tag", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "Hapus \"{tagName}\" dari semua item?\\n\\nTindakan ini tidak dapat dibatalkan.", + "tagManagementDeleteMessage": "Hapus \"{tagName}\" dari semua item?\n\nTindakan ini tidak dapat dibatalkan.", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/arb/app_ja.arb b/apps/mobile/lib/l10n/arb/app_ja.arb index c61a606..bbfe2a8 100644 --- a/apps/mobile/lib/l10n/arb/app_ja.arb +++ b/apps/mobile/lib/l10n/arb/app_ja.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "データをインポート", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "JSONファイルからコレクションとアイテムをインポートします。既存データは削除されません。\\n\\n続行しますか?", + "settingsImportDataMessage": "JSONファイルからコレクションとアイテムをインポートします。既存データは削除されません。\n\n続行しますか?", "@settingsImportDataMessage": {}, "settingsImportingData": "データをインポート中...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "選択したタグを削除", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "すべてのアイテムから選択した {count} 件のタグを削除しますか?\\n\\nこの操作は元に戻せません。", + "tagManagementDeleteSelectedMessage": "すべてのアイテムから選択した {count} 件のタグを削除しますか?\n\nこの操作は元に戻せません。", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "タグを削除", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "すべてのアイテムから \"{tagName}\" を削除しますか?\\n\\nこの操作は元に戻せません。", + "tagManagementDeleteMessage": "すべてのアイテムから \"{tagName}\" を削除しますか?\n\nこの操作は元に戻せません。", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/arb/app_ko.arb b/apps/mobile/lib/l10n/arb/app_ko.arb index 942e025..30d8a98 100644 --- a/apps/mobile/lib/l10n/arb/app_ko.arb +++ b/apps/mobile/lib/l10n/arb/app_ko.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "데이터 가져오기", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "JSON 파일에서 컬렉션과 항목을 가져옵니다. 기존 데이터는 삭제되지 않습니다.\\n\\n계속할까요?", + "settingsImportDataMessage": "JSON 파일에서 컬렉션과 항목을 가져옵니다. 기존 데이터는 삭제되지 않습니다.\n\n계속할까요?", "@settingsImportDataMessage": {}, "settingsImportingData": "데이터 가져오는 중...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "선택한 태그 삭제", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "모든 항목에서 선택한 태그 {count}개를 삭제할까요?\\n\\n이 작업은 되돌릴 수 없습니다.", + "tagManagementDeleteSelectedMessage": "모든 항목에서 선택한 태그 {count}개를 삭제할까요?\n\n이 작업은 되돌릴 수 없습니다.", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "태그 삭제", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "모든 항목에서 \"{tagName}\"을(를) 삭제할까요?\\n\\n이 작업은 되돌릴 수 없습니다.", + "tagManagementDeleteMessage": "모든 항목에서 \"{tagName}\"을(를) 삭제할까요?\n\n이 작업은 되돌릴 수 없습니다.", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/arb/app_my.arb b/apps/mobile/lib/l10n/arb/app_my.arb index 89e7754..50aa8c1 100644 --- a/apps/mobile/lib/l10n/arb/app_my.arb +++ b/apps/mobile/lib/l10n/arb/app_my.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "ဒေတာ ထည့်သွင်းရန်", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "ဤလုပ်ဆောင်မှုသည် JSON ဖိုင်မှ collection များနှင့် item များကို ထည့်သွင်းမည်ဖြစ်သည်။ ရှိပြီးသားဒေတာ မဖျက်ပါ။\\n\\nဆက်လုပ်မလား?", + "settingsImportDataMessage": "ဤလုပ်ဆောင်မှုသည် JSON ဖိုင်မှ collection များနှင့် item များကို ထည့်သွင်းမည်ဖြစ်သည်။ ရှိပြီးသားဒေတာ မဖျက်ပါ။\n\nဆက်လုပ်မလား?", "@settingsImportDataMessage": {}, "settingsImportingData": "ဒေတာ ထည့်သွင်းနေသည်...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "Delete Selected Tags", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "Delete {count} selected tags from all items?\\n\\nThis cannot be undone.", + "tagManagementDeleteSelectedMessage": "Delete {count} selected tags from all items?\n\nThis cannot be undone.", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "Delete Tag", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "Delete \"{tagName}\" from all items?\\n\\nThis cannot be undone.", + "tagManagementDeleteMessage": "Delete \"{tagName}\" from all items?\n\nThis cannot be undone.", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/arb/app_zh.arb b/apps/mobile/lib/l10n/arb/app_zh.arb index 082b69e..9975c3d 100644 --- a/apps/mobile/lib/l10n/arb/app_zh.arb +++ b/apps/mobile/lib/l10n/arb/app_zh.arb @@ -242,7 +242,7 @@ }, "settingsImportDataTitle": "导入数据", "@settingsImportDataTitle": {}, - "settingsImportDataMessage": "这将从 JSON 文件导入集合和条目。现有数据不会被删除。\\n\\n是否继续?", + "settingsImportDataMessage": "这将从 JSON 文件导入集合和条目。现有数据不会被删除。\n\n是否继续?", "@settingsImportDataMessage": {}, "settingsImportingData": "正在导入数据...", "@settingsImportingData": {}, @@ -799,7 +799,7 @@ }, "tagManagementDeleteSelectedTitle": "删除所选标签", "@tagManagementDeleteSelectedTitle": {}, - "tagManagementDeleteSelectedMessage": "要从所有条目中删除所选的 {count} 个标签吗?\\n\\n此操作无法撤销。", + "tagManagementDeleteSelectedMessage": "要从所有条目中删除所选的 {count} 个标签吗?\n\n此操作无法撤销。", "@tagManagementDeleteSelectedMessage": { "placeholders": { "count": { @@ -830,7 +830,7 @@ }, "tagManagementDeleteTitle": "删除标签", "@tagManagementDeleteTitle": {}, - "tagManagementDeleteMessage": "要从所有条目中删除“{tagName}”吗?\\n\\n此操作无法撤销。", + "tagManagementDeleteMessage": "要从所有条目中删除“{tagName}”吗?\n\n此操作无法撤销。", "@tagManagementDeleteMessage": { "placeholders": { "tagName": { diff --git a/apps/mobile/lib/l10n/gen/app_localizations.dart b/apps/mobile/lib/l10n/gen/app_localizations.dart index 42662a8..8f8f29c 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations.dart @@ -764,7 +764,7 @@ abstract class AppLocalizations { /// No description provided for @settingsImportDataMessage. /// /// In en, this message translates to: - /// **'This will import collections and items from a JSON file. Existing data will not be deleted.\\n\\nContinue?'** + /// **'This will import collections and items from a JSON file. Existing data will not be deleted.\n\nContinue?'** String get settingsImportDataMessage; /// No description provided for @settingsImportingData. @@ -1832,7 +1832,7 @@ abstract class AppLocalizations { /// No description provided for @tagManagementDeleteSelectedMessage. /// /// In en, this message translates to: - /// **'Delete {count} selected tags from all items?\\n\\nThis cannot be undone.'** + /// **'Delete {count} selected tags from all items?\n\nThis cannot be undone.'** String tagManagementDeleteSelectedMessage(int count); /// No description provided for @tagManagementDeleteSelectedSuccess. @@ -1862,7 +1862,7 @@ abstract class AppLocalizations { /// No description provided for @tagManagementDeleteMessage. /// /// In en, this message translates to: - /// **'Delete \"{tagName}\" from all items?\\n\\nThis cannot be undone.'** + /// **'Delete \"{tagName}\" from all items?\n\nThis cannot be undone.'** String tagManagementDeleteMessage(String tagName); /// No description provided for @tagManagementDeleteSuccess. diff --git a/apps/mobile/lib/l10n/gen/app_localizations_en.dart b/apps/mobile/lib/l10n/gen/app_localizations_en.dart index 500bb16..e421c17 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_en.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_en.dart @@ -347,7 +347,7 @@ class AppLocalizationsEn extends AppLocalizations { String get settingsImportDataTitle => 'Import Data'; @override - String get settingsImportDataMessage => 'This will import collections and items from a JSON file. Existing data will not be deleted.\\n\\nContinue?'; + String get settingsImportDataMessage => 'This will import collections and items from a JSON file. Existing data will not be deleted.\n\nContinue?'; @override String get settingsImportingData => 'Importing data...'; @@ -946,7 +946,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return 'Delete $count selected tags from all items?\\n\\nThis cannot be undone.'; + return 'Delete $count selected tags from all items?\n\nThis cannot be undone.'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsEn extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return 'Delete \"$tagName\" from all items?\\n\\nThis cannot be undone.'; + return 'Delete \"$tagName\" from all items?\n\nThis cannot be undone.'; } @override diff --git a/apps/mobile/lib/l10n/gen/app_localizations_es.dart b/apps/mobile/lib/l10n/gen/app_localizations_es.dart index 238b5d5..ed225f8 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_es.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_es.dart @@ -347,7 +347,7 @@ class AppLocalizationsEs extends AppLocalizations { String get settingsImportDataTitle => 'Importar datos'; @override - String get settingsImportDataMessage => 'Esto importará colecciones y artículos desde un archivo JSON. Los datos existentes no se eliminarán.\\n\\n¿Continuar?'; + String get settingsImportDataMessage => 'Esto importará colecciones y artículos desde un archivo JSON. Los datos existentes no se eliminarán.\n\n¿Continuar?'; @override String get settingsImportingData => 'Importando datos...'; @@ -946,7 +946,7 @@ class AppLocalizationsEs extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return '¿Eliminar $count etiquetas seleccionadas de todos los artículos?\\n\\nEsto no se puede deshacer.'; + return '¿Eliminar $count etiquetas seleccionadas de todos los artículos?\n\nEsto no se puede deshacer.'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsEs extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return '¿Eliminar \"$tagName\" de todos los artículos?\\n\\nEsto no se puede deshacer.'; + return '¿Eliminar \"$tagName\" de todos los artículos?\n\nEsto no se puede deshacer.'; } @override diff --git a/apps/mobile/lib/l10n/gen/app_localizations_id.dart b/apps/mobile/lib/l10n/gen/app_localizations_id.dart index 8377a2b..a31fae6 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_id.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_id.dart @@ -347,7 +347,7 @@ class AppLocalizationsId extends AppLocalizations { String get settingsImportDataTitle => 'Impor Data'; @override - String get settingsImportDataMessage => 'Ini akan mengimpor koleksi dan item dari file JSON. Data yang sudah ada tidak akan dihapus.\\n\\nLanjutkan?'; + String get settingsImportDataMessage => 'Ini akan mengimpor koleksi dan item dari file JSON. Data yang sudah ada tidak akan dihapus.\n\nLanjutkan?'; @override String get settingsImportingData => 'Mengimpor data...'; @@ -946,7 +946,7 @@ class AppLocalizationsId extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return 'Hapus $count tag terpilih dari semua item?\\n\\nTindakan ini tidak dapat dibatalkan.'; + return 'Hapus $count tag terpilih dari semua item?\n\nTindakan ini tidak dapat dibatalkan.'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsId extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return 'Hapus \"$tagName\" dari semua item?\\n\\nTindakan ini tidak dapat dibatalkan.'; + return 'Hapus \"$tagName\" dari semua item?\n\nTindakan ini tidak dapat dibatalkan.'; } @override diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart index 1d6a4b0..ebb702b 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ja.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ja.dart @@ -347,7 +347,7 @@ class AppLocalizationsJa extends AppLocalizations { String get settingsImportDataTitle => 'データをインポート'; @override - String get settingsImportDataMessage => 'JSONファイルからコレクションとアイテムをインポートします。既存データは削除されません。\\n\\n続行しますか?'; + String get settingsImportDataMessage => 'JSONファイルからコレクションとアイテムをインポートします。既存データは削除されません。\n\n続行しますか?'; @override String get settingsImportingData => 'データをインポート中...'; @@ -946,7 +946,7 @@ class AppLocalizationsJa extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return 'すべてのアイテムから選択した $count 件のタグを削除しますか?\\n\\nこの操作は元に戻せません。'; + return 'すべてのアイテムから選択した $count 件のタグを削除しますか?\n\nこの操作は元に戻せません。'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsJa extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return 'すべてのアイテムから \"$tagName\" を削除しますか?\\n\\nこの操作は元に戻せません。'; + return 'すべてのアイテムから \"$tagName\" を削除しますか?\n\nこの操作は元に戻せません。'; } @override diff --git a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart index 2bf4f4e..dd04f41 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_ko.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_ko.dart @@ -347,7 +347,7 @@ class AppLocalizationsKo extends AppLocalizations { String get settingsImportDataTitle => '데이터 가져오기'; @override - String get settingsImportDataMessage => 'JSON 파일에서 컬렉션과 항목을 가져옵니다. 기존 데이터는 삭제되지 않습니다.\\n\\n계속할까요?'; + String get settingsImportDataMessage => 'JSON 파일에서 컬렉션과 항목을 가져옵니다. 기존 데이터는 삭제되지 않습니다.\n\n계속할까요?'; @override String get settingsImportingData => '데이터 가져오는 중...'; @@ -946,7 +946,7 @@ class AppLocalizationsKo extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return '모든 항목에서 선택한 태그 $count개를 삭제할까요?\\n\\n이 작업은 되돌릴 수 없습니다.'; + return '모든 항목에서 선택한 태그 $count개를 삭제할까요?\n\n이 작업은 되돌릴 수 없습니다.'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsKo extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return '모든 항목에서 \"$tagName\"을(를) 삭제할까요?\\n\\n이 작업은 되돌릴 수 없습니다.'; + return '모든 항목에서 \"$tagName\"을(를) 삭제할까요?\n\n이 작업은 되돌릴 수 없습니다.'; } @override diff --git a/apps/mobile/lib/l10n/gen/app_localizations_my.dart b/apps/mobile/lib/l10n/gen/app_localizations_my.dart index 1e02f16..d0ae977 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_my.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_my.dart @@ -347,7 +347,7 @@ class AppLocalizationsMy extends AppLocalizations { String get settingsImportDataTitle => 'ဒေတာ ထည့်သွင်းရန်'; @override - String get settingsImportDataMessage => 'ဤလုပ်ဆောင်မှုသည် JSON ဖိုင်မှ collection များနှင့် item များကို ထည့်သွင်းမည်ဖြစ်သည်။ ရှိပြီးသားဒေတာ မဖျက်ပါ။\\n\\nဆက်လုပ်မလား?'; + String get settingsImportDataMessage => 'ဤလုပ်ဆောင်မှုသည် JSON ဖိုင်မှ collection များနှင့် item များကို ထည့်သွင်းမည်ဖြစ်သည်။ ရှိပြီးသားဒေတာ မဖျက်ပါ။\n\nဆက်လုပ်မလား?'; @override String get settingsImportingData => 'ဒေတာ ထည့်သွင်းနေသည်...'; @@ -946,7 +946,7 @@ class AppLocalizationsMy extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return 'Delete $count selected tags from all items?\\n\\nThis cannot be undone.'; + return 'Delete $count selected tags from all items?\n\nThis cannot be undone.'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsMy extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return 'Delete \"$tagName\" from all items?\\n\\nThis cannot be undone.'; + return 'Delete \"$tagName\" from all items?\n\nThis cannot be undone.'; } @override diff --git a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart index da36aef..2e0fd04 100644 --- a/apps/mobile/lib/l10n/gen/app_localizations_zh.dart +++ b/apps/mobile/lib/l10n/gen/app_localizations_zh.dart @@ -347,7 +347,7 @@ class AppLocalizationsZh extends AppLocalizations { String get settingsImportDataTitle => '导入数据'; @override - String get settingsImportDataMessage => '这将从 JSON 文件导入集合和条目。现有数据不会被删除。\\n\\n是否继续?'; + String get settingsImportDataMessage => '这将从 JSON 文件导入集合和条目。现有数据不会被删除。\n\n是否继续?'; @override String get settingsImportingData => '正在导入数据...'; @@ -946,7 +946,7 @@ class AppLocalizationsZh extends AppLocalizations { @override String tagManagementDeleteSelectedMessage(int count) { - return '要从所有条目中删除所选的 $count 个标签吗?\\n\\n此操作无法撤销。'; + return '要从所有条目中删除所选的 $count 个标签吗?\n\n此操作无法撤销。'; } @override @@ -967,7 +967,7 @@ class AppLocalizationsZh extends AppLocalizations { @override String tagManagementDeleteMessage(String tagName) { - return '要从所有条目中删除“$tagName”吗?\\n\\n此操作无法撤销。'; + return '要从所有条目中删除“$tagName”吗?\n\n此操作无法撤销。'; } @override diff --git a/packages/integrations/storage/lib/src/export_import_service.dart b/packages/integrations/storage/lib/src/export_import_service.dart index 0c08f78..eb45a4d 100644 --- a/packages/integrations/storage/lib/src/export_import_service.dart +++ b/packages/integrations/storage/lib/src/export_import_service.dart @@ -5,6 +5,13 @@ import 'package:file_picker/file_picker.dart' as fp; import 'package:share_plus/share_plus.dart'; import 'package:storage/src/exceptions/storage_exception.dart'; +class PickedJsonImport { + const PickedJsonImport({required this.fileName, required this.data}); + + final String fileName; + final Map data; +} + class ExportImportService { Future exportToJson(Map data) async { final jsonString = const JsonEncoder.withIndent(' ').convert(data); @@ -102,7 +109,7 @@ class ExportImportService { } } - Future> importFromJson() async { + Future pickJsonImportFile() async { try { final result = await fp.FilePicker.platform.pickFiles( type: fp.FileType.custom, @@ -133,7 +140,10 @@ class ExportImportService { if (decoded is! Map) { throw StorageException('Invalid JSON format: expected an object root.'); } - return decoded; + final fileName = selected.name.trim().isEmpty + ? 'backup.json' + : selected.name; + return PickedJsonImport(fileName: fileName, data: decoded); } on UserCancelledStorageOperationException { rethrow; } catch (error) { @@ -144,6 +154,11 @@ class ExportImportService { } } + Future> importFromJson() async { + final picked = await pickJsonImportFile(); + return picked.data; + } + Future>> importFromCsv() async { try { final result = await fp.FilePicker.platform.pickFiles( From d81adf9b9f6dc5e79b8520bc2412664e8df2b7c5 Mon Sep 17 00:00:00 2001 From: Kyaw Zayar Tun Date: Mon, 23 Feb 2026 19:41:59 +0630 Subject: [PATCH 10/16] feat: Update app branding and icons, introducing a new asset generation script for consistency. --- .../drawable-hdpi/ic_launcher_foreground.png | Bin 3057 -> 10861 bytes .../drawable-mdpi/ic_launcher_foreground.png | Bin 1787 -> 6109 bytes .../drawable-xhdpi/ic_launcher_foreground.png | Bin 3707 -> 14077 bytes .../ic_launcher_foreground.png | Bin 7284 -> 22543 bytes .../ic_launcher_foreground.png | Bin 10492 -> 28511 bytes .../main/res/mipmap-hdpi/launcher_icon.png | Bin 4007 -> 7117 bytes .../main/res/mipmap-mdpi/launcher_icon.png | Bin 2157 -> 3884 bytes .../main/res/mipmap-xhdpi/launcher_icon.png | Bin 4599 -> 9883 bytes .../main/res/mipmap-xxhdpi/launcher_icon.png | Bin 8999 -> 18428 bytes .../main/res/mipmap-xxxhdpi/launcher_icon.png | Bin 10008 -> 23850 bytes .../app/src/main/res/values/colors.xml | 2 +- .../branding/play_store_feature_graphic.png | Bin 0 -> 394396 bytes apps/mobile/assets/icons/logo_dark.png | Bin 193934 -> 534973 bytes apps/mobile/assets/icons/logo_foreground.png | Bin 32290 -> 31372 bytes apps/mobile/assets/icons/logo_light.png | Bin 582887 -> 569556 bytes apps/mobile/flutter_launcher_icons.yaml | 2 +- .../Icon-App-1024x1024@1x.png | Bin 145981 -> 355563 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 760 -> 970 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1585 -> 2488 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 2556 -> 4384 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1120 -> 1669 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 2440 -> 4268 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 3737 -> 7728 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1585 -> 2488 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 3291 -> 6697 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 5655 -> 11820 bytes .../AppIcon.appiconset/Icon-App-50x50@1x.png | Bin 2048 -> 3450 bytes .../AppIcon.appiconset/Icon-App-50x50@2x.png | Bin 4551 -> 9214 bytes .../AppIcon.appiconset/Icon-App-57x57@1x.png | Bin 2307 -> 4077 bytes .../AppIcon.appiconset/Icon-App-57x57@2x.png | Bin 5362 -> 11075 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 5655 -> 11820 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 9437 -> 20280 bytes .../AppIcon.appiconset/Icon-App-72x72@1x.png | Bin 3402 -> 6218 bytes .../AppIcon.appiconset/Icon-App-72x72@2x.png | Bin 7494 -> 16222 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 3337 -> 6868 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 8534 -> 18238 bytes .../Icon-App-83.5x83.5@2x.png | Bin 9067 -> 19637 bytes apps/mobile/tool/generate_brand_assets.swift | 374 ++++++++++++++++++ scripts/generate_brand_assets.sh | 19 + 39 files changed, 395 insertions(+), 2 deletions(-) create mode 100644 apps/mobile/assets/branding/play_store_feature_graphic.png create mode 100644 apps/mobile/tool/generate_brand_assets.swift create mode 100755 scripts/generate_brand_assets.sh diff --git a/apps/mobile/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/apps/mobile/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png index a4a617bd09ae4572ad4ba5ddf4635b28b281c2e7..299fbe76af5420fceb45190f7ac54106a163f254 100644 GIT binary patch literal 10861 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 literal 3057 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 diff --git a/apps/mobile/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/apps/mobile/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png index e54c4ac6814b70ce9df866d368579894f1a5712c..260ea6dc0c9a474feb8c6a4e293da10a45afa602 100644 GIT binary patch literal 6109 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 literal 1787 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%0DDNm_Rlo=|zr!K8oqw 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 diff --git a/apps/mobile/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/apps/mobile/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png index b26f1a9a5781de60cab4e4ab5d80934f1bb16daf..24cac6d33fa3d8aa3454de2bcaee4765e8d157cf 100644 GIT binary patch literal 22543 zcmced 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 literal 7284 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%0DRz3&D9X!Vj^T{OKMZeGcAEH0< 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 U$D=UdHj(Rwxvg34wfm3%18CUYiU0rr diff --git a/apps/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/apps/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png index b8626c419727e02b1557f3584d82b556d5f214cd..ba4bf419982715d7d2e7b550b2882dadbe0840de 100644 GIT binary patch literal 28511 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 K0My8uhyEYk0i+xN literal 10492 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 ZpNEyB&RWif1GgGQZW^0iFTUy&_g}yfQz`%e diff --git a/apps/mobile/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/apps/mobile/android/app/src/main/res/mipmap-hdpi/launcher_icon.png index e403f5e59e3fea828c9b44a3d22d91bde915250e..4fb101d42bd32794a87e520c55919825210e9682 100644 GIT binary patch literal 7117 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 D#G})G literal 4007 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 XS*B>>B_LUH00000NkvXXu0mjfMgBg< diff --git a/apps/mobile/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/apps/mobile/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png index 05f629772b983947635bffa57aba777a80244095..48ab9376024b68fcc040f1bd173287163870b912 100644 GIT binary patch literal 9883 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 N002ovPDHLkV1g-IKlA_q literal 4599 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 diff --git a/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/apps/mobile/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png index 1783d0851502756d04c536876822f98ff89a1d26..13af7f61ffc072b64d43f817d87b6014adf331be 100644 GIT binary patch literal 18428 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 literal 8999 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 JuabT9?tdrrY)1e9 diff --git a/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/apps/mobile/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png index 23cbc2d772df113b960441ef914d145c5fdaa4c5..8542eda8dfe350d55afaa91164156c1df86f7d7b 100644 GIT binary patch literal 23850 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 a0){pw8}s)23w7pHG~4C zqtdE&g{{aeXhBQ6j8V@6y^AfTjC8||SL+ex*SDF~SH^$R1)B}j(ZKNj zuXyC44cK69Yy)yjSU9x5c@>mO{gLZw;$2I5H4%Xhb_x83h)B8zo zC^xxH>RJZyreakeRB&>MS)@J)}Z8-e>wP0w>j4>TajSjtj9?g-WdUFCc z6)7N&^%fjLuX{%4)i@4waSrf zp%=;}L!Gakz^mcx@G=om0T4R>93EU>RsYPXPiu~BtK3lM-pew!4?A8r*H7q0#=i?R zNhr`H;*IJen9Md@?j1+hUlZuPp@U(TTkEh?C}b<}_#-MjxmJbJ0u@r?WB;3}2OLrs z5V-C`ZY99_p11X);q3;z7p|esKtx;s1hdtS?R!suub3oT zW-BP}!cr+DsCYUT6&rKNcne0yXVKfQ!@$T4`UdqF*WG1tmhh97C_#R<9EBPsHsmRx z$&^9lS!~eXJV;^nD}GuD#!)X;55i^-ou%G7{0;vnylhz#0eCom>ZkVR)+>c|dn#(* zso8iC6iKBH1UJv&b6CjuFPHQgax>M)%^-by4ZY87v13eYq?bOO(3&u1us}Csf&PvS zcZ@d7ndV`4aQjgrQ4HN*Sg95xNi9Zlf*7fZ5@aMxk)A9;cAAVH#R>f6ndN2P`@Gm_ zgBf-hl|)g-#-ClEA8nyN>l^2n+ryP56#!vUXSBTgaZCLdO`TuX?b)(_=L^LLKvC*& zdhGk~X(hmD*nG+*$!qyJ3CPchXEYd!a=~JCz+|!0Vj)R+q|-}J0ZCEx%Q2)wES1DS zE)^k8A)>>X7%oQW_vePoVvh;DAz`^|@s zpXoZWZ^sk0J6|l@4Qk%KVs=RPf@262w$N))*?tT)h8Bt2sIgKK#Gtu&SU=b46M}>_ z?g?H#lc??&tMU6D*U4k&97jWalPg>-n*cm?U%NTI>)_1~_kQx-q3X)Q=U%B=|5Ev5 znyqp%@_al8p9!Zp*#H->$-}sO4vlcRLF*>Km_6TA6%lp&Vvn<}<#*?~Z+~_E5XuYe zkzm;c;K49wb)G!i-9|R@|MOecu6}A=dgZ3l?DDe0^fI|rv}REbS%`SNe=yGpeum9h zZXiPn-;^!PWrMj)zXl!T2LyLAB<>sT9(G*)vDewrHRNb-|HIX9W}Zo9S$SXt;LZ69 zeM9Fj^fdq=8%owC$&=ObYjQH;v$E4vnJI}%l4cw~fvDzRgxK_O!pt*<00000NkvXXu0mjf-~~hV literal 10008 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 diff --git a/apps/mobile/android/app/src/main/res/values/colors.xml b/apps/mobile/android/app/src/main/res/values/colors.xml index 093bed2..5dc7c0f 100644 --- a/apps/mobile/android/app/src/main/res/values/colors.xml +++ b/apps/mobile/android/app/src/main/res/values/colors.xml @@ -1,4 +1,4 @@ - #667eea + #FF9800 \ No newline at end of file diff --git a/apps/mobile/assets/branding/play_store_feature_graphic.png b/apps/mobile/assets/branding/play_store_feature_graphic.png new file mode 100644 index 0000000000000000000000000000000000000000..a6fac49b0290324554709dd1b25a69ea0c7b864a GIT binary patch literal 394396 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
N|a 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%0D~W0AbO@8rD70;(k=y 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

6$TC4ct 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%0Aw;~)E=;C zMD?N;jmz4ySNrThy)Rt=5gUy&PW$%o+F$>l+kWtWySvgy$M21~6gF2lwH0^1uVfC`*g3Oc41KuJ}B~C@}Gf)&7;d^pNOvtg+IXXgeti zcAXb7!)e2R_OXu|o_pM5hJ*RGgl_OXus6jw7QFt|zdGFYsO|&gd`+pta^5TXm@6KA z7;F8DzuT^{=e1qwFaUutO)J2PMe|o&+Wv*tIT{V1z`ss?MC zPn$i2Q?b3~!dzmAy4V6>F_-m_n)sMdhV^TI6KPIdv*(i=2TTs}agvRw^|Jvc-Ao0h zN^y*1sPs}0Q@7N18Pa;658Qc=X#Z;ss<|gv^&a_J-fOxN8W-@11Ps?nehZIlbsaau zylWY|X!-dD{8oYAd-eao*YL&LfGlOWWDw+fddZ4S-wwg{Ct{dbsLvZWXIbAo{Ku@ zBC9tKG+9JLqj}KOq9#2k6{m%_01#fZDt6u{cw^Fxly#W0U+oNK5;B%__-@J8Sj_pp zs<*uS_~DD6{-~oH*=rth=CteD+KoNx_f%XC3KQtru<4 zJ#+4Bt+D=hi}r*m#hzy4Xl zT?*>wi~VERmu;c3C(Lu1+gN|d_2xVO`8B-k|2e}sXP?=p)|wxA`=f>@Jo`8G9=x>( z3m|Vg6ZXBn1#kqM$A);%$gT9)(uJ6*v(i;y7BC6A#3aZ`B-#u6o2EjA;CZwCTLAcS ze!ld-N%_6}`domBsZ6{ApnWh|{B@#WtWh86#Qo9m+Bk76Ts1)-@%l4ws5DEC@f^J_ zz?1v8@T{F&Iz7LO^*s^p{;gNm+M%w{YGUde#;E(N{zmJc zN^7>2rdo4TBQlaQM>can_B78s|9w1moI!s~!>2EG~LKfiU_aPGMm=#%TOcl{q8 z_TP8>urPsm%KZT^*9sliV2l?s^~q_W;SzlC-+BLD0!(ycK_7Y7k#@zS$klI*H|Uo4 zF}oIFmFN4-^z09g+Q6yD7~5+yZmjkX0Ati6G_7xql{N(eDS`0&+>BU-kjk;u`Wpb} z1S^v3;H=l=ylvKW{k|@_=1!Bem7^Bxz+MMys|Vy&D=gua&JT$^7cZ;lV~Tp6+$ZrI zy{`M$H7$8+AAECszb8H~WT63sCc}*|=w>GXP0qp3+4s-AP#=VM_@Vqf1ctq+z+0;C zvqHr~AhE%fsliTrAzyi0`Cb$B)K_4$6dd(b@|jzuTR4PP9yK|i4Avrt!3s90#%2W! zOxv!@Mf#w`!>@gH$m5l0lXa?CxvzrCFuywTtW)4%;`>hN(uZBfCw}3uRSsYGYFj4G zqrmtffLbRL{TRVx<-pYxX)MU$Jxk5(tmX4;fv_|D@k0PX0?ZHA8??QzpK^R4uKz^~ z?EydH{xCr1`5}OZ<1+xFPMDmxwy4=W>rOAqn2T;`#x>XUO1~1lX)8%v0NnU?wahOi z+#*BvVK2S(lHtuSdDif+U-)zZukT*vpsNi}eBN&lH#ze5A-p~}k?zL2COy}$qBui`@h`9H>efBxAZp&IEpP;9RkDe*(Q*K`i+Dn)|m zS|#TaMEK{$n!y?kYvLuhSHBV732Ud=JU`3A%Nm}mNyYb^Q;KaGP{i=?II($DhhjIJX%sF!Iujg+$w}3&M z_hT*=m}PV?ZLX(`8C2@^dQ8=r)(xKaukg~{qSwS!r;0N^$DfOZMy2zE*UtVtBzT|I zF~<+0ucP5!SN)mbTL2EhD`ECI2q+hv)1=6NvHf z?KC|#C-)Bl=V+IX3M%)N*JMk+eOqZ(eqUs(T#xm9rdjPji*j_DoL-Lq4m&8)A zs6OeOm;Kvs|NVz29si2qhBv!4vm1|#EaD&+n#NxNdFXY6A>xx_;wlnsjQeALg{)E~(!!Ncwk8m)`ZM z>rpuOe@PXur!F=7tidJxF8qm)ynlH8OP;&!2md$xiCYd&dd`b>;lY2`*jm%rjJkeb zPo}(ARm-uZTeV7{immcd%=HAFOd7fNVSfSUMAY+C>&B$6pAhqH88e4|jsPSd3IB&G zV>O-}J5{h2LVm(SZUPM~W2PBjaV{fFB#h4-0`8Zw{JTt`54!PQ%C-JO-i;MLwYM7X zpBT}>O*)-A`Z;nnRLh&D!2wCSO&+w~lyZ4uPtveMhY7)H-u~ z$84!r`I;c0sTTBs|CqiCi3?m{K^-J zK!dBGV*_P za;Tg5$g4bjafpq0m|)MF`y(p&u=hy{e@qkp;0ec z?Vo9Jc_PR_%+rk=4eufH>2oO7T%FCy5CZ`=r`D&QjvzQ^>|{L-hNh>asxMge7MhHg z^4Y9wFz-P=!Qwl}Iecl;p^qamoVXT!j4SXpap(OT?8R+9ZJ@-$UD!a!VWVV5)Fb0+ zs)eHk^~i{G#x~T5?dQ?rtCY%HThc9^*P^F zsV%F2;c(I(1(-1%O19kPxORLwHmwG8XeJ;LY`v%tBm&a*3kYL%uXqwn#xDOsdvL~A z8E_bq_y}l@y!HaIx%E%@oOB~Oh*#e*mC6PjUBi;&V;P){hjw40QninOdi^;c>0_r>_FXb3+*MmuIAS`^=&|thC5ngG`C(!&El3+M_EryzYIsWDU`+N|F`^*^i2B7Cv zRx#wHDWv!7+})FK+F{;mPh2-gXR%Px&hYdEIF(tK68~{e8&}vcuKL@hJzAS zW~BtdD?!_Ag1XkOO)Zl%26kcpfa;s5AE!>N5#or`XYi+_?2TSdl{_9d|`HUkdDlHDi zonw4ghXrjn5huqy+a-MV-$UxW`Ub9buPmvzb~p-qpUHDCv^dB7S`zUQAW```J4|GHQf_I!;dh!q^`ulr{zb3B&qpK%M;M2RnCHwvW0 zX4gnHbbaR*5TeY>jrG^Y7!Q~>fWHGLBl2pJ zEpj;!69)pUUm?^~4z}im31F>9O+5+lA9%0Yc_iVef&?(;!Caq@+yqu?)i|M&z=`qP zza^R>En^7#=RvO5=p2Dw|D^9K)ccjprs|x2T>$4LUsIM9Brw^FlT-RcI<>$R9RaP= z+@k6AUv@4Yn187~KsPM=OTm_LFSL|mnuq5?MNRoU83^|>JPE*m{k`P-EzGp`pBNq( z(xZd9wPQ-NFo@}g`=mhn1Vs(S=p(QDrx#c@559F0<~RdtIx~X0N5g1&Fz)r&K834b z%3)qZ_PcVed?d9t14DyGLX4{cMYcY90Ys5kH65dk!L=AdOFG~4&zJr40Xk!jyT`hI z%6Lxe^5k$xpK&C_XH1!Px(rV;u@-AihC#GEC~WZwu$xqjxdCB)_iC2QkY?YO82Jtu z0;!6d+-6GM_o7DmUi{idK^nixcAn2n4$f z7jPM4XnTIaWq;7V81MP#%l`GmBRHb+6l0-B1_DP2wS13>!d&DDRW4%6`-GT=E#8^( zo6mW|Z?^S{iS(FkV09C2G~y78lI(e;1v8_M=L~Op+3~}vpTjfF+Z_C~|HmEo>%+ct zAMCZUX6?E9>j;(gi;7dfSB&?uEu}XCOG%~YG?~D`_w2XP-q&BDzI;MpLVMZSU&8zN z=@ZYReXw6*6>GN!uRrq~lg|QhNyU{ery_u%RS6DlHVP1aTOonQN>pZgcM zNo;9Tqo~$bxaN~;dS5dy&?qzSr2x|XI-Tp|GfIXs)%Vh`e}+DWAhf`jXsnfmaGm%y zeHVNKG58vj1`u)2bm1#aZOnN%?OL)Cbj+KZeDE$gtC9D;Ds=Rr8%?X%oalQ3>asz; z2Ar&q0DaLJCx9m&YiJU#VXOok3~Mc0h686f>Go-Pq+}$VM{3eP!OQsM@Nm9rPVN~4 zBwk3IuQO731{@7|&)pM|d`roN-^8ngzKjX(Gv;!*r%AA7tCrW#jI?pmHI1HzzkAOT#Om;&*EwQ%;&Xp{IO6*FASVwmi}ULD zdG(J*X+75HdlW4^^LO2P0lQgig{IS7i+x+gFxl$oe^>Xwg=yCvYjP^g_byA+cwbWY z2LO9={jRTGSgUKo`DzVuf0G|fCzsoAef`VB@4w=O!p{UfPkzBkwa#RXZC3)^tmUA}HVxAg7{yzKS>FI zT91C&#yU@1c|Bh9qE~rq`;|Z2KvQzc*7}~))^&60er*}+hu250wJL`HVf=$L+Jk?- zA9i7=aEs3J5%hi6@0a7LIV%v_$nAp#Wyb?+fSL??N2| z*0C-~%VA3&1yr9thM{fN&W_FXxzJbD4w2+zuJsgguWunyFxk|Mc7-kVYXbyTow9ze z?;`v?ya*5eFUQ-2*c(UE(`j*^y)OhB;vB7G#?g8#TmRm;&kp+0VYmwJH4OpH+QPb6 zg+#qt-)pPazqD1^qi^jVxGX+0xAffC(*1+J@3Vdz`gv}4sVIHS=h~d*7w*KJ6PN&& zOjhvlxM;W-UwwYwSMl6W+;^mKs6R}+{uZ5{y*@^BFAKzZ=V(28U1K9ZehYwh57D0B z_~fSrI2WVPq#)-wa^p)g#O9cQMo#AG;NdksxnF~N7@oHW?d|LT6zA9cp=gW81AoT! zL<@7^qR#^l#kT-x)=JWyJ^?VD_c_*TqxHX#&vhHO%r<^>u?)09+2P$9 zIH>G@!6_Qh9>*rTM^^W~+o~fs%}E6-xp4aANgo{kWyq0PgKwZFChGYFRA(6aqww=;AT_!Lh=Del55sCKjy)pZ(^V}NKCjju* z3lB_*VZQBqd%&+)JPCupa02KFfWX#1r(XleOzc+$DNG$!f~}AU<$X9wRuPg6ZZeuy zNYy5kL%(YZuSJ;%ugm#&lQ*yaZc3=Rl*nMyOTOj#0Pos(Dd08mV2`gftK7hBWmF$E zZ0j1yb9vbfw6jkOL=%ovcvDSDEbD>su2z(s7}E*m@VcvQnRcF)bghoh_g!C#mqcHT z2mgMrKd-a2iKXO10}PIRw8<3aaudFQ@ngVwtN4MN}cEa8CH=l@9C1>Ss`YF%r_`u?r!H_Wvr{b$gqC3b`Qe5p0R zYVG3F+ROdDHuVG@N_kAm*MtF4*Y_yHf(6$1MCw?B0S?dGOuvH;o>4kl02`z z$-U^@+}N_Im*IW>e8tCwc<}Gfqw#&?^^0aMbPK&zDY;tKeD+--=F8TE$&8Jly{J6^ctLt8Z~ko7`8dqAEsH&54NQlBLPt9W~0PiTY169kfP59|H4 zft~jsM<}6l(lU|tMXhEhpAp;U4OfA8g5UX z{j*jr>$ykz?vuWUd!9`ig#Wg=^wQzPx4mKb#}94)6*yG8&x0Q^JmBGvABA_#s~2V) zqS`m`dYQHN&oz4i$5-20YJ!eL&Fjg45|E42X!#0&zre4rc;JtpL%jt6|GMA)WgmZi z@W7uxo_az6>u+(-Y0(9bSdz3oNy|uWg7V!OBHHqU8uDN-( zzWK6|O|3FdV)V&*uPaUV#E}Ks)S9-60!z4g+EhFl!0&?R69IeSZ_M62@Ja!GmEhd4 zUbV!zytU`JHRe7TvzGIm=Lq1sx;-!V*$o=t25K$mU~8IG5BFNFb8|Lz@RDo(%a;!P z3qRiveHq?!&-Y%lnD0f~)Cz%q{njN{epw&qlLcV9OgH&i5L5}20Nj0Xf9!WiyHEDU z69c+WaPR1caSGK;J;AdzMEh3a3%!T-jaL`lfvOxo6WC3@wp#xt+EQ@YaIvj0 zm1{g>@I6gS2gBFGJ-6t1UWli_sA+UadMcaz!fO|00&9~wff-nafWLyj-*DgQ-s6*+ zyzlV9pEmCe;1=nObn1Uu*!cB&<&WRMNz+qN&yp^@n1@ z!DLxOiGwbs69>nBY@8p^Hwqt+V~`d%bXvU3g0G5fVLqt$ff!yzp#SkL0Ego(0Lg7) zF>NJ?RFO7q^-3U6Hquhhj%;F=>u#dbu-nxlFE)U7n=5MgpfB2gdhZFzsHQ0Z= z3}c()$8L19;R(-q*>J7Ht~0NYz3p)QTHJhz-H$Hs_5XhU)5FI;^w+yma(}#%;uoI$ zY<#8y{)k|l^}X*7|LgyM0mLmv0^jJLXP%K3Jjd*Q+BkKOPlQ)=EL2rt~fNY-DbQ|2zuY9k@thuoik z7Mah{gEKLlb^2+;TVDO5;TvE6*D<)E#|N7~|G1|Ocfaq0He{{~U*7+E3N!pZ zz(>G+5-y)0j+$tZ@mz%>+OK~E7th)yWVh$LJS_+FOGn8G2axhrZ zEHrv`eRI;16eIcMAm)_UESM8sh(S!IfRH+6C~&j%1c72eNYuSy$muLUqZ^^75Zd0O zkR1*30U7N?AfS%9fl*yM~f)Om32Cwv}FEbr}^i%a?d#J+r#HR z{*h^L2ebP>{0Z&BJ<4Bn;rX-Lcf7}ahHD*;Cjg?wi!Qui_}s}S%~m}GPZT`(F;AP# z%?0_n5byibw+?5Y@x6ug4;^tmJOMC&$v>w9icIRcF6JzcB#e{9x zdT-X>RqoB!(xtr?av&FAx1j1T*}#cl7nO@&po z+IPR$Wn8ZrcX$z-HmvCPH8cW~W3{*b>n>k(*tp+stjC9T&UuF%o1H37A{3~|(Zn)Awa4aG}u{+S@yd|P5IQe%_r zU$lhxDdOHg^WBH%2`8RonI2QfnP)4GX%L_E=A`XRjaf}K8A}gNt>-mKwrB>e-5ZWa z?VexfZZB^tt^+}SV3}p4tzfK?7$jqMA>g3)4ob_ikGe^2>L_L=9aDA1fCK86z zNgweA%>WZ)&BP!eZV?bXz*+|}CC{G7chP_*CbbDcGUr7z7f^Jp$DDXkLXc9w_R{A- z(WrH^J~A$sF$OTIW((k)U;^}ig_y7Wu^=hvZZSq+wbeQAFdTrW3 zjN>4dqiWWEl;bJ-$abQ4rZ}>1_79M28lSNUh;9voBqTYV+!GtE5YF`(FTqdk=wk|I zaO6v;%vs1WI}MN;7(8 zo-Rk$t@T@~(F3e?2S3s>=Fg-?K9K6)HQd0Q4J^ec+Q6y?IWg2z_YK;hmV#Zc!kcWXMPh>FY~HwP4WxAq$0}~SzI(FvRyu*v{t$;gOpj^q zVJ}nLH@3%=`7LgDm*JT&`~89c+PmFx!FlHnZ+giyhxfhv4~EOHxNPi|z4-7Cku8fc zH#@vX2H4JmcPZ!^w0-?uDzR-D^yHRomuP+Jr1$Hk=1bBG;V+%?so4kr3&7nB)UCEp zefm7=@1Oh`AYcy;_rZGlU4>d1gYSK(t?}8G8u;?dFUONBZ`UXN@8rS%!Ph!;c;<_L zXAeI3uZ!T~yx1C_^NIClMBa3#Y%RI={+UR-3nS~Mv(Wl%l`LNu5J=uD{ryS2p~`ov z%30Lb1YpI-Jhc&Uj8cTECgV(a*oXD+*qYZp9XZEM$?^>Fh=6g7`DcPT!!qw4Ot&C_ z#I{ohV%T}(Bc}eDi$hFeBsOCOXeV;qE8#w@X-l-_8gm2-!)XAjrnSj&zO>J9?q3#< zkn54>V}i%TwUTR6S-CkkOOPPgWjh?x0~(JDp~YK2VG@dPPp5)!Y7be&uPa{k$%n?jnj zlS;4#oIFZiOLZaI7+wpl){1z>;CubHq!l`+Z3Lf_nzyFc&z$rts43+BrvNpJUiO8! z=vq`GbIw{!5NB-5#+jf##~8z~;)fs5Y{1$Amy_r?nV&rB;IJmGu#8tw(K0rB2hQu4 z#avXLFpSrPF@ptCRG5J0o}_+*G&(@mW8R$9v^LPpWu9!}arAuEArHejO(tYTq(=-> z;#sq$TN_G7p7GEY1Uc0Ro*R@Va{zf=((mZ40Vz#R=2IZbTYAJrP1Q%#btamn*UXO! z4XP%C&theW-Z#)`x>xD5C-Bu197!{P;q|v!oQVlNxO=y~bs&g>Mob1Li*Zh$Rzh&- zbCAv><4!Q?fta+Ii-X4c<}1Zh4Cg(cSl}}6-V8vF{WxDFjhMFqr16Fc$N-zoj4En}<~>;tV^*KIr!p#yKjkMHbH2y}^x#XTRdD!*y@ay)=6P zxjewPTKw&wy>)oa^PW6>?>qn5>bkbC53jNNq?GduvIZGo>-Yj;7Xz&2I}sHzQgyU&uOj|^SWtya9!!gB6;8V-dRg@8z9!y zC^h@vMaB@~KFLv>Cmz9P9OHZ6`R4GN7aTkM?TLScC0L;4HaTAx-?s7W6J9@D_xeA+ z32g(cd-K9PUsFPB1E=npx584kjJpiw9iNn9&>;G=pb2BGiF-b!xsjRg+i^;GB0M zQaPj*`H)Mj>$ned&6ACj^~s@cU9X=ou3h`!La=n}FrP8{vOI}6YG>R6%+tpaP(n1M zNiPxsYqc?{HAS!hfgIMX{K(PpNQx)0)b$!Dlf!Y^2v&aGOXh_EfEeXWV$MF3@U<4W z98MWSZonGWAOe|);rbRx&BABQ`lKb@TC_fxPXNM*Gi3q#&a2nJPH^Vanon0k!Dk$Y zp-k!E3BxrsiI@yd&T*bTCpfYOa}0HHgvNoK_Dy_hb`5>(!|xex zdzYhYXx2aX>@$Zi{?o^2bDIPYyvjlN7O(gq$Q8tW_6eNVTYof``P;dnSM-r-_2GLA zQTJtlQ?%ZH_bKbi2>j>=|9be#cf1*&@{bRm*}=Fa-cs|pq-q+6oPW+LY?<%PQ2nY0KYL-a2-szB z#%Mo`BY-1;f86LP`a{_NBNf zCeY&Wey|6Q?1g!bE8G{gr&AoF+%31dL;d!@X%MQ7}sw>oyYw% zwuSSodJrR55CxEi^*;3L6gfEbvn>gfo+H6H$qdGh8eP&O-h)WpO%^_uK?*=(O8n21lE!pjX!@Vr)~ z$PdjFEBpoQIsx)MwxeZEEY5Out+i#xZC!dzdjQ^N{G{i-V)%=9r2_x<^rtVI|f z`26Yby>j^Cr~h$yxTh`8(b>n>_jN z-Z#AS4JRz*p8vW(8m@_#ad$Uq!_|^YuNxBHiUsw>z`uUsGXp=X;LsoXk;P<*eBvX2 zJ6yp}NZsLh>~X&_-12t#{D*ai*XcFcny=pj2!FTGG5>qS?c-sH-Bf=-^FaZ?pgIMwzQ0U znj@LK4NEzVTG+LaC~m`%U{Y958=$ROp8*g7KUcsh?_UqPDw_@h@V#fmxxV)_@BapE z|FLf%@e*X94f9%|v2|vxRm+Q>MMDH8bt@RY|6`|?bxm5wZCx`H(Ffp^u5{ z+b33oKn@3B>1G%ca~R`csN)DthXr7@7GxbF#{%YOi1?gLB|S?%1u+Qc$?M~^)>ORa zdwt9qVo&Z-{K65X)C+gI8Ptd|;R7r_aiVr)*Pp#vqSH)% z%oiXzxFFp9q z`@z3qJ>PNBV?t90Ik~pz(=9p9x&7oSh*`149ruqx9N9}cjViuHs{mqJFJts^EZo1L zZSjES{)p%k1p2=}(gewC^S)ZgaY;nq>WRG+UZh4C1y~OUal(>ALypqYq+q>YHYKs=>b!@Ch}LZq!JeiB2k z%&W9G(SZA4DPt6i+NFie7uhjZffYdC;x2$taeMSQ?={yVjr64+b$ImpO9_CR6I4Sj z<0Ufgm@(V7dkuTd_x-pE!N_awDw2h=uu*W@$nD8cS|&1mc9zJrNBaRi{@+Z^yk)Ux-3rs z`ghGjtvwMyP1la{`E$jd-M32%>&Y;j^2vW3Uiz$G-tmL~{r2AFv0-Ej`nyW1rT0MzVe98LK|$lhF%IlDjuyUt2d4waNm-DJ^&%{M}|>X#nf} zn>;!M@_=7C_LVAp>X>Gy{w`HLN?M>vJFGsa!8~<15*kkBGM~MZLsAfFNa0~EYa=x3 zBAFUY#83=m)w2L{)EmhSocw~zq9RNw5z5|7qYjU{Mq{%k0*=vUZA_BScx!E<#ZcAe zT>Jo=<2bQAT!VSmJVR`&_%M85;XZH0-trs<-uVa z0@fklzIv+sLTk;IekIyY?twZkDL=IA6J2X*?m$?#$y~pFLU)LSJU@!p2F`@kj zS@@EOvW+WX)Ey(uBgYMd%Y;ImNXo;}8oE4rxe>@YO-sB>$;ZU`N~5n)lL)9D1?a~i zKSa5HVHm^^z0=733mxLfA*|nT^Q%PC=>x80SHMe1fw*b0AP_?rF5eLCIA;C6(+|#Tju2#Eaf<)6#|K4 z9EUl?SkLhRl-w$L(%gU+0qs3ct7$NH_T; z{&oNI%khDXOUA$b^Jn!cfhFk;!z=cVJ$r`tpU40JKmbWZK~!zkXUucwRT-21{@<{p zwcxd;fB&#i#@Uy9qvdeC%@jEAoO6bE{O-$!x4i0w13wINCxhR}@vN7=ez?;;?hP3? zKt(sO6ZJW+H-NVKbJ&@f_AEAuewCPOpLs9E*p#h-3QWMxoRoJ1l*{0vcEV~e@EJF4 z+4`x*`&aiceFi*=fOI0cuz%zSM>+r#pT3(2jCzS!;*hI8q3%gEBvk`edFUXRtN~jIpU7N)vzun@`IC_m^(xa`I?8#@|atTnDj;B34=Q%`(>n{Nu^6&sKi1IV~sr+bNn_-rJw*hsZrYTOCHwC2dkR}mJ99_gBEOAH4w z(Z|GR$~oBN7mlw1`8nuE4RIpJ4-Sm59CFOFrG|XgOTp$y%esMcDf5}OFBSqS51akd zCr*GCCx}$h#gR z#+pYR58~89$5B3j;zytK&8IJZ^y-?-%P&~hOELn9t3HDm)-pcIPu3!w&^Uodj_B2A ziu15qOM^!Pm~fEjBH<>s=s8A;Yr0ok#4cw#TqIJoXd)jpyQ+%8}yb`B5*Cy zUIDNGjwZA*RK;LuQV?_UT--Tn1)n^Rx=3N&Z~$COnutZ&aUm{XLEDInPab;;zBLJT z{RNqY0MQt106FU^R!_`FlVNIh(eLZ5MOu`ZM5tk1+jVp+mOeOPyzGf(O;cZHqXT5Xqa`b=s%*nGk26z9%|F&Gfc>l7vpWue4RCUo*Gzdy7Twyv%i1Q^ec1wF zmwexwj#a*MrDRJJjNpWi*hB+)@&cNF$E7&|hGdD!Eqo$ei~OpYdgj}bc`kD;&83lYk@i9U@13IXtx?C_uK1x?drRK=P3Y`PN%Zn5T}l zXbGI?F~*Ss;RDQ&`1FJ4m?*&s)4)u47#vy*J4BoPhX8A7U@kx6Z4xQw0+@WJtif7= znb0{Q&vvB18+-A!C02Y`#V~PQ%4i7S2`sT?>OQQ=oMVCof3gmNnn=bGb1CyV&phD> zsCMw(Yg1}@t%*1RJ3fJkXRq*8Gh&(q&ziM%A1e5=&nzKNX^<+{g`O2pkvE+42<3$!$1(FKfj-&K zt3Vb?rL7%mkz>tG`E%;lqo#G|a3z-e6*2F>A+;?_x(qQjX3koc#46MZUFE7*8=iFh zD~1O?@_!6_?Ty=U2jjx?&(nM4U-#=z8@~I^uPsqxA6^6@)n7u{mGJ!fcSTxjfd1T4 zd_7%$S;0AO!CvEFe9l5QKK7ycw*j1wS7m(ulhbbsxaJ{?{7!C*X}xbc*s{L+xaYqA zy)Uzy*45b2GzzIMgzC?mm&M-PAKdSL>+8eoUU=N_&Nsbk;61&Q!JnxIKH>?(lb-Y9 zfj?_wq1=F-$gjb59WT&!6}94^k^9#zfiNGIbV<)A*1B7QCXCG|RlE8{NnxJcJgi$I z%BuiKy&6IpS3ZM zQ2YBGTE>n! zHEkVFjc}w50a{_`R>QMN$4EsY2B9f6myW;WNSNz~!7Vj6!dL zhzWx!S(Yq}1M910hs$!sV&uDerz+%XOk`1M%!cL_AepOkCeM&#R8_ZAqj+ z6EvPPq}qo7YC`dbX-*JHpc~W44~{p+Ie%zP>M+6YJhcF|0&HF8A|!`#H_5nsI+_$L zLLB1i1Rq>|#j5L23mDY`#=0WTouYcQyzMo=F`R$S*;^{EN`Cp& zQ-%|s`RL(Z$2@Ad4|J!WHBcAU_q0lRJNeb?-;U}c2W#=QbV-8juUhJg{B^E-z2UGQ zK4SRtm%fmtPd(+6!`WwkZ{Rl<)bXj4J}_K%*`+l!+~r;m9RB9d-ZqJ?JNc_Wdh_t< z|MQ`h@ay0BCx(0e+(XATo8dj6)lCkQzgHAAa`&x&_vq&iwYbk5?umZHF1_TE;RAp1 z&f!D<``yFkmo0yL1u5%{t6k&Z;c?G+!En50NChNUMBXaS4FNjLzTKxDs&=JTGJd^jWKynoCg&i9p-6-xm`!xwIx zF8uwaCP(rSAScJ9Xv((w1cB(XoRVw0G!<+(CK4OEIfujFU*ZxM3C_I+ILd+@BVy#F7Y!Vzgh+CHs@k4}A z<``s1KCDMwmoUV}U`|tIs z;WN*X{c*ye`NT06Lpt!yCpPnN7$=>Ban9vvQm_HCp76o1n$kmD{aKjc7?gDb`S%yN zs;gcB6J3PTSLjHl^>c{BUrZD?~6Xmm6^_amX;5Fvj7!ERXHE!QO|0z}aNjhTICQfn3Fi|W7 zNOx~@n*AF4^)K)dU`+k9a5lh6^wr$#(Q8wfd~m$}fJ#%o^)Qj^dIr)WmV9b4!$Oa;2oY!ruI5lhCC^FGxQN|-j!x7=}34jSHzzy2Y zY96QD2&;scP@yV1{g^xFshfA4&AGlBj5+Z+CXbL9t{Qr*k zknd#h0o42d{B6T${_#Wl(7~JErhbaN7rm1Tn{v0kfom2j`rcx1JrzoNR&Z4wq`Thx zfs-cyuEfvS$$$4Z!~Gui*ooxFKJ=c+eE$Ou9PaSbKfCQG0KWU5UmJL=8kb*sX?p^o zU%%(vgt^~etAuwWUw=Pwue)n=>M5Td{`?PrcR2mK-`b68!;Nq8lfz?v<$1%w*FLQ1 zxv(#`ZGr4DcavJaU}cj`pGhs;+r})cg(5X+(FNe<0ZXanT4NolAp4KG?@|A;r$p74 zj~cY9=ez?m^~J%-+SIJW_a_BK7oi|9XUKflbra@0PHaj@aH{3TrAcgn#mC8WvXY+Q z(8>aBP7eF)d#rrt$e7SQA%7t`_LEwzq(n@0NEiks6c%%b+^6xhUau%PaZdbXq(DRi zqk0Ts&h@db^#VE06YNY_YauTPwIby?r}9Ti^MI{GJuqegxb7#lN{(FT>DOyiVZ=D6 zc&RHl^43$#0>)x49fB~bCg*|&hI5bFpJQo5n}+=CQDQAt%D1&fE;ZuiQ;}WzQaJ*-!#hCN3&Ko~TGS37~bJs6* z=s?$)i6(MNM=$K74r9sX;GFmzlSxLKX2DvQd}}dgeKDzJprt~CVfSAlr1a~bXhuGD zMW7fHV|{D4C=>WUF$J%w=LQl7-_Ve4uetU@g*7n{VMMGrH4@^+SX~RtpgU+AlZ_(W z<49q7#*^+KWirS~!6DAn1d54tXoX&&N3<9Uc!Xa=PRW);aVL<434v~AA-Ro!wbpK6 zS|j%vd`h@I%39Kv%<6N#@o<6V#Dnp#$;bZI>xW|=d+f09n&17tTx}Rm|IRmuH@^6p z!y8_F-0aQF=sIM}a@F5P`JcSg-G_s&cJ&GKdJUcz3-ZSQjQaNt3F`S~6mT%RwgeOs2E{LW(HzhLNhCYoZo`umfm5&rf! zzB;_&rOzGSh+{V%{PSn#m`6WlIQE6F>K^>FU|nc)%Af=1h@8P3>!7!w4l!H5a7nlg}_?IOx-r zCM?IqXTbbggmI1#P|X(cGRJiAD~6g1&uC6?$h&;Vt7gCc%+YaA5$yLV(ry0&qndMl zB2T_X^ctpxFtL7xRX-PCB5ha8DT>zh)1PPw(D>@B5}CuOYvJ6u3Z-VQiy$VK^prSY z2s4!Mti@oA;wnPEVv*3AN-gOC8KLR@*Nbt^gJ2v^+afylM4zw_t{CF#@H&W*&twpi zUj(9jVvH3naE6=D9EaDheKDw|GM`iAS<5hT&G-714;*>Qhk$so{uGIvusk78jtaqu z!#JGE7l!dV0&EU##VzzgEo7_}FMCi@4xG=rb?bU>(n@D;*|mPc+0CcX|C zLw+*41o;;5S``bDW1LR>$Y%r84dMbnYBKJ9s+iorUXzlYCivZl0J<=36k;RZXoYdg z;uIw`V&X)Rn*qd-sGbY9mv*@KwK*q;D4 zt+W|FOTnR!tvL7Wvxay5-m8Zbe)WmNm+-IuyD^Tq-VKN6y!=hW&phCv_+4N3I~zb5 z`?kALd0mZlYZ6zm#r6KBTeiwgBrgPg!fR|K!tIHG*%L_~5x0YpV_?7*$pwgJ7LYK4YQhm_$Tu zy=wso&gMfq;G*(GZ0bf-7}Rn+n-PJe09F?}Yt=>rE2-U2X*1iLihMKMzglgFaYdqIf_DdFrR>G!;_ zEU_Ba;UomYSolJ{xh#(ASeC$Jr9hhjTmS1Z70cYQU%t*cl4!G z>QZmRVT$O{&s& z_^*e5!rKDweas_=qaXN)VgCd6-&|-TM(x>~x{<*8;BNm!?8`4xGtL@IaCf=)1BQ>h z@6RV$zU2Srx4GkR(FNxZpZ)kpCb=VU4X=Nbn-BatyX}r2z2Qv;zMp;7_=%sqLxa>c zXk7?6=K19J*DB>5prvhLV_l~v zHbBN&k8=xn{fZ&1d5F~YGhvJ^VYR;T%u~mfxT&xrEnEwZ;RON1q&aC|?2B}#RKGMJ zzLUhkXYZ4E!Pi!dHQkmNuU|2oJZFwE>2m_dJnDHY;E^-Wb&VYbBEtT&K%z#+LWl@f zw6h3u*$?xfM?<;>oUFqjl3~U;fez9y0tyF5Fa}~+*CD;!-pQ(mnESM44VH1EhI`*^ zB`2V~$w~EH+ya59)9e#L`_>g*C$tiEh(Uck0niU5h_QI^gbI=hWb;j^y$=DXzPK0f z&8WJp!??8IDyLxU!Hv{7DUM4s__?sivk&*;UOg8-%Ho3V1#Xv86`j2PXluGL865Ew zkNE|G31WK_>$<)+Xbq|0ak1PJ?H>%?zD-M0)$%pQ_{tIWgxi2@8tlIN?>GGS$2@Jg zU#Eo?nCo2k`ooXk>{gS{0{G%TeGIRvIBPiN6aO$=ddUx5P4+JM z+<@^0nxxjA-2WFJKiu+m^)nm_b)7Z({?#?`1U7%@i{5Uy?kRuHhT-zdFB?8}(g%n4 z{ps6=@1J$XZd8%RA%`B0_xc|{-00@FT0=7%1J?Vn25nth9j>Z1$ZD~-Kt3} zM{0#Y@|A3T8b_-UH501>PKG9?Q9c*oTGfuM=A~xk2dMIL|J+MiC*fLaHqZi|+6spW zwer6onZ%LzZ>LL6E{r%#eJ?xJigVUR?KLkZbn9A;Rc%a=&N9rg4o}vyO%Mqj0)`uS z$C;|Sf(Ax=YkCEe9Ha~vj?xw_d}2KodQG8mjoH45wh&4A5~DVI_B|nxf}>{U0?V|u zY;*sLwt2FJM2L8Ba!roe79CRSnCL=?a}H{HIA+WEq*nvOT9f^7RG!x+{!CxQGAwS% zTT_;z5U{Sb>iP-EVNC?2or$Jlo-IN01Lry-7cO1*V_jPFy@}>K$GCeYT%!ocB}RnS zb6>mm+QgtD(T1n%;rfvljJev6)&YR9?!_XQJ7k=+Ya9XVd;P{rQ-mnGg)Xq=d)HVs zDw|_#y<80g#Bvx^_$|@pfD_cVq>ZbBMQBoB{)V;qyIa@FI&1RR zf?0Fz#jFQp?Y_R(v6X__!O7hGyM>te)J4)b*@#Va-2i!!u(h_r4o=9Jm|x?@G6&z& z-kOqi0^s%M-`@awUFK2P<;|fruIjqBH_UU@08l*F37h+e`GTgKa0A3dEV0ZvXgqDi z7E%t_#sWO;t#t%rvL2WQeOk}K5aSxP&X`N0P|z5wGjFFFa1!t5l{Z zVSzD6*M<<0r`QZrkVnB3S0w8x4y>#}n5&NGDLm>LUm+3>NR|hH7}v}G4Yokw7$%p) zJaTm)rt1<(Q#qXs3Pc0O*k)gaP$p9QvA?o@Wumt_u>x9H)jO1f(uIp)UqFAj-py#!QdA8a=7or7e4lf8bDQc@= zoEZ18fMcBV@Z31sz$%54A+~}5)Aw2XPZGf<+D3^ik2tv#e((x~k(AONLqI%Z13b|c ztMw|^f&>N7p-KG=hQN$b4>fKMbum1(E^PT{Pi6xsbeSrJ9EsZGuoGPH!#LHfdDNs1 zEi*hhXX~8vf$4kWJX3H&lP`z8@=AOt8S8jMvYxeTfOROLQA@@j((M^UUhiHQ;#2h>Yo2? z_>(uieE9A+zqW?hYRDO}cV zX7{hd?4amvj=KAB;#+@b@*VZ>eb-y?VStxURBwk5|Kl}VytyW@?N7W;D%4x7U#fBe z_RoQTH*CN9mP~#N#V0=U{^5iF>z%`y-`n}CR%$VRCF3tX=^4X~@JfvJhc~O*_1W7) z`a;x;vz1cUTTi!)t)-0Pyw4d^fA1{^C3<6LuCDGiDlxg$zyidlg%kItKF5J;c|TDEe5 zSK6EAN- z8mTKyuW?QkIi{JSBM5EOV%Ve7Yfa~63&^^(9M+~Y;Rleh1}YY=u&~K1F=-dR%iEHc zd*!+cwv%eY6&^aa?nC+opPLmmIk!t#-M5~b+Q7}NpF-xR4eXq@^q7c3UJFASj>mMO ziCFE2kmQ#>f|{oGZ9OL4ON}ueEzoVl0b4|^S=Ud&+7HQ9JL&0AsPqxK?dk<0$zOdyd9_9Q3G2{=mB z9vPx|48fz=vR)@ef@cZumvypy(KJ7E)JOri@SU>`5c`fdM~LOFkYGkMMB`@UM_hGu zYK0;^Yb;5tj>7t4P1*oR@zA!QV#uWy^86t3oRjA{oQ^&d05}P*Vu3QZTLfLxsflHB zPYm~J?b44!z16j3kb46>TdVC^a?Y+H-LH_YkXbcJBAPc z)jNmxpZNCSvP&ULDqFYR+#(y>6|PHK_Z_o_vau_DV+LymGQd9oV$UNWUe2=2gZLB z^5xC|PwLGGm@jV0o2NDq|9|YgX|TN8b=LRZS<}^gHQBNy8A~#rWNc#@gDeOJo1siF zq^JxPQWa8_RHc$He9xDBNb)5`rASe!6e&omD2TC{492sN=K;xsWXm>^C0nzurmHL6 zIqP}$`mJ7j_uJ?68UDruZ>irkJHVJ z)@Zhs>~=iTHD?sXU)$2lvot|t16-QHwPq&J6@|Hq9+;zC;>^<=(rFg19+9=;@%F!Rb>V`xSYscWx+*;xKYyw2As$n9A!~QcIdIGgY zt@?Lf*H%7wx=jm#mZYyzr5iqb1Lcl+@Hk_r|(~RNvLoS{qC;GNBAIPs;`b(N2sE|YGfuiC$;HUXvqj%3bHsNoH?`UAB~Nm8pz_r3M} zK%RL;m^ZfiWc$DOxBeHu z5b)MN`DanReU17KK!q~ zhIYTcR@RyEslAF`j}x@|{^j49_2?s?-F_n8>i?tv?7MIEZT?LAhOhoZ+h6%>|NZvR zE5C@;nU=@l(ZQU_zb#Ot+E@NXm9sjHrdji+p(*-=uv@U-3DZf|uCUd@C=jRqV zLG_~D=js+4R zWBs)73lqY9ex$mEuT8`EJRz?Cj)0#ni|Ux92jxljze%me(K4GxSM^iawqt1SMUbSiE91No#p3MVgpPb7zu>Pm=;*OaUV+oy3ddcuzN*38FRWs;0H@l|sAYtG#+7D0=wdm_-^|*?t6y>6sbo zPESEmtnaAz39PjuH}zMKyqRO+#3&(N7>zH!EHgW=9$DjDBD5>38XCqc&SgCd4_vyG ztEUpyp(3DGB$;I-QYY(upWr2Wl!q)UO<7&Sci-&8ebM>$1r;zk;T=|LP?FV6i~Y-@ zJt|E~x>|`*KLp@2Cp}bmkGP;~8C_J+Ep?5HkY!B;QQ*ZGV>>5&bh{QBT@xHRMv!$a zb-`H!Fg1-61YxxQ>HMXWH**yTqg?WxSKRph%v4WW?aSvJN#%`|7OUxkqlAuP!z@5` z*rEfLZ8&QR8bHoP`)3aJ-zY-YtZwYgND9|yfiDQNxDSEyt+$00C*Jc#;P`-B-scP; zNnwU)6QOB;pwU?3>!NW@k|5^h4wkjH>MH7{RlpI}HS*>pgx3Sqhk58NN!>180a|gi zpSZip32_L(N*Mo8y}Bn2t!rvQhrc%#(qM&I&&4yGb3yD(0p_7MbhWadg}jd+dgT{y z|LyCw>}rbbc`htr_Vw`|QdqU;Ucxb#MIY?ce_8h{~o;TI;~_AkD7 z`{keisbdV1>?`88eEWB9dhx;SoR16b`}YNZuQ`^yYUabg^L{_+|LGt7{-X~-ysFk7 zUVr`IyZ-b4di%z={K>uY89B~hw)-6384_25NS9s^xdVtVu)1G#Klz7e+Ab+yi>-8@ zngLt@%65Mj4C(3?IkjN<=T8QzQ^SJ8@|e8K@A)5Duq&T_aBU+A4qkuE<7*K9<4ipA z^tVf7nqej%wB09aHSeNDZ{woIoa|rqPFZJGU0n1PYZ)i&AT9|&mws>sn-)zQuh)XJQ1Y{=!5eO$7T3StQ}Zb3QK0pY!$G`87ZMQ}bvD8ip$k z?NKQ$my%lv<)hI1Nrt%V)p?nG(9N*=i7O2)_r&&~`@$!oW+4u)&nv~O9kq#0AWSaP zg`*a>zRm*Uv~uC|bph8lxY7{ckGJ%l!_NR+KTZPQ_iwGd)GUhKxK&#}_E=TT5JAnU zzI|m+r6$?Hah~)Rb*0awA>8i|2-Zq|*9AKc?9f1cG>>jtaQZnp9~aLAA*?ltQviP5 zA0o%f{PF@okj#^qKyi~OA|__8`~Vp%D`#2o1+pJ?$(GS6t99XXC5DU8IW>JtQY!|qo?+Nyt?pmrG4K~B4D7dBvhxu>4q$L#git=~KUk)t{q$*T4Q5KkEiSe>N1DMVX!>&N5X9Z#(Nh))`Ce!# zPT!glcAn;hV_4#k@)AuQxzm|t3`a10m5Nr5vTa3Aw{3N~>>sUG9{X*3s{=?`ahzj6 zvY8sq#=Z-dIG=@*6wDeIG!2bQQby|tm{aKPBLSbd-w)=*#ksI<9~bwKm9wrk06bFF zD-z6ND~-t2lLs^*%El`G2*+K~=a7bQag+6Yy-p$dGH4br9A8W{c%kDgrpl;TJ|pt;QdTkuxqZ-czKkn;f)+hi+?9OE!RKRUFHH5=+_7at`Hawa2lpGy>Q6Z>_wD$KLEW&Eh169;QaF zzJA#N!ftrbRT@ZXMsCs*D0y`UK~gQ2!s+}XWPVxEwa_))q)4U~p@E65nL;38E>HO= zSQmku)%{bO2p#69+BUs|6TvZf49BmJHBiCM}PN!-`??) zKa!Q(Gw*)K&uqHA>{VY9zis}D+c$jcpW2@H;0tyd^bN2<*_*7cc|wO)E7V`lCpgzk zf88H>>-G=g!vH`3xko02@!@}Z(#n3Z6YS0e>|g3`8wcT>?9JwQZUUdsScp%7fI5#_oi-)2I{VqlyRdpYE|NLrV#B4*Q;<5QC(sS*% z{yY@fv=l_5TBd-Fis97H@9@=!g)6M{!r}u8+rI}{GKqVfbzb(5ocS5BXEiN9YRqM9 zt2s}Re8%QS&a;9E8>!MGpsX>K?LP|kg>Sz265#w576)ID#tHW@ z(^8A@a8AiVoBgXFv#_Q5`MZcy@4D0ZslR&a(iZw2RJE>~zI9ZhmX`fnE(XY>EOp@2 z`}w(+gu+E!`EdGKO2ai>w8HwFQbUH4^9>`H`nrFHHb(;J%2f<8&k&_ zqF#E5vsU9&EUh4|`xn$2X^od|#I(1c!4cnsNM)>SEpfv&IJI6i= zbx=KGa6Y%lNn%~bz-_v#rnya^+;r$y`XPXJwAy%KOfRUg28+p(X&YE33F)8cDe2+4WAtLY`5m!E(sUO(X z-#r9In0Cgp3!T4yAk7gm9L?1iwLYv{B}Z5=vXVwCzq#ENZ-*S8>aUszvEY=S zIRW6SrsaNN#qk_^;lRIAQFSb4QUpFrM=|-ctTz|1o|${fpao|LwoA{noF) z3-w#GAN}C_d*M;xBWjIpXmQfKmQZA`p%NIVpW&`C_l4 za}_Le)0g-%jhvOQYiP(YHZeA7wY{m$UJ;=Qcn5!MG6jdYBBbg~f|4x=uHl)I6=b~rE@AD1@jXlnwMf~w*_vjmV@X$r)w>4TAE`O;}IGw^*KoFwW_4i5QCpFf(o z%&&%RaUSYTNi#B+pkQRl+ZRv^!iao@qriSzVVU2&$U_&-D|LlqC^)j^3m-SfA|@Z5 zDc`jc>JRS0421Nq(4=5&+-C5ue-k! zcLe;+?ctBz?w?~*5B*bvcl^|k`u5-pU+hoE*Iy5K<*Q#CRSkY(IFYZkq@~-u^v@9V zM0_d%<7>kAJ;|AWZgl?x(PL+QOMF0L|1dzk{r;iP`$E|&bz2j1sT^Z%K*{lNCwPu`jB4p9TW~)15=z%?_NyGZ_8jl-NviL~xWwqw1+ftO(f;6IAy{@e! z&OYk#w{+wM0I+;d<1y+F{?j>xI63+pZKW0Dc1_O_3G`JnUzY$o4`0O;=snR?nI)cS z*eF;REo|hOL0oGEP+0p}XTG9^Q?rr8N~j4it8zdp7YXNDP4wcUBO8lZ;ft%4<%6FI z8=9(`e(#Bv$+`qdJZRKYa=@yXGbMp1!9IUsVs$<=iF2j{HD8M#y6{V@X*w5|KCg29 zK*T4;CndYi()Vc}u&}w9Nfy5jEHKRPxdNlO>vpVXXu5LYi$r_#Q)`_$>1BjPx8_qW z`Dlu;ms6fq^_)fd%4HMH%d(pTINzHksQ3|2<)+s$lCy4tRpUVIqbnQ0Z0{^O=Bu0z zaUUSt@A8$TEt+-6t>&f@Z?pRTJf!OUghf-nmgh=7vyMt!_cSACPJ-Z|TeFr($W*cU zDKD7k6($yZblt1*4axzMa^OcEerYvLbN4Q6Nc^bN8!d9~7Z<^uYuJ*dkQn7lM>X-A zfLp7t@&?Dnj)Jj@AE6}HRp*CJ*wPYMq(zgotod?c(QEaKzG_v$^qC(il}j_Y_*l~o z8vH&hdj(5eEhEwS+;6E=`|f-+3KLFf-1W@I-d?g}=tL+h5{JxTfp$$;67u&}3Kc(N zv?t1bP52Ka~D4}Q=8y?yo;KPd22<1dNd=ISpLyy?x~y1nFOdMkI% zeTr~tz78OfJ7)?+2>i0)^fTL`Upm620GcttrGy1=2ERjko4%j!>mX|1Q(@`7ZJ+q) zhqrh9^xNVEqaWVh|C_&dRKM-SgD-ed{7JvR;twvo@4ov(zHd(cZ7eizOYfqY=q1cG z`qlTQxS#Nm>{jv@-<3k-T8ZSZXVvzirH2~JZeH-K9L_V3e`b6913wrqjNRpjsA_t1 z+FkLF{`FIg&lnjwsUC3bf4^TqYun-Q_*VnvwaOnpS5DYggHwD4XxMNM zD+RiqiZxT?A4tus0Y=XKgX}S*HqjHyyiKKC=3oH$aI6~__9-GYIL;-e^dgzJ8X<%;ASEzIdrK@l$xp!Ova}6DLzT(z}3PLqkYi8Sgvt#m^dXgH}K1`T)|2o8(#W zdrSK{r*OTt&e-*sQ5^fS@XJv(G(*(A>65W~^@c?Yr#Kw~U%b7Q0yR&@-qXsxsFvF3 zFyka~f?vJtq)_^$7wM!MP`csteJ7jtgOtgYPha@NBA1V#>?+V|lzg8>J~iV7fFD<> ztq1`tTN{jyMOHp;HG~{3q$nyCzRLz1<%{!?t9qlCxR81hj_!cN_f!6SK>&aG|6&s5{%MapZEBP!^^^ zs&4L8E{Ly!XKL)xnNQ-Rt9p zfVXa68!rZ&|5pU|T5B&_br>UDuhW(@FeUlWu`B<^@if2{)pAC&E*P-4=pCSosx`jA z509CVt*bu8|D8Yews;4}+qMt9_tz_bC!OcVJ4L=Np7`sZO5Cq^Z)nw4*}zEO{EA*R zxVhw|3jNNZ|D~h^1b(I0eVGupf>pZv2^)s~Cjk@svOp@kD++6EJb@pZ;ahNF!g=Nk z4{wiu@JHj@Sw6A1jVJ!`HcLP0SDelCB7q*u#X{U?~#s>}VL8d7LDA&#^JSQh!NDM+8unjIiN zS5K2u?*;z_NpPXGS4nS5bvFy#M$hjOBW;0FsHD{63F==qp zrD~h|&vyV=F$Z6W3^O(FQaN-_jSg`Qt!y;*who>3mFsa1x;(j;R{SSWX*wS;WqE7y zGjS+>vS0527*Fo~Zh_$6_ku6m?!Nzd)e&v13T#!%j_cwuE{EA%n!^Ms>5XK3Q$v%h zYPLD-9?s7bwX$Q$Yte2**SN02XGlO16u+#TSp7jiGM8LSAaUdT^vV7|{saGb`+;~z zz^5Pn_$3;*SANA8zs4^F=$!#y{MvXiO8Yr$<^I>l6x)-=p6{=}yw8Oh+n0BT7xSLm z20Z6Myu;t!XX1|NfQO#G&VT#8zv18Xzw@X6)%M}v{;iz`cP90M7r%7-w!aWh{QrYL z7yoP{e&avg7wq?F12-II-v157E}_#)F!pl^rOM!Q|9;%2Oh2dY7kAHLmTvcO=jXU* zju<)9`lW1qUi2G%eeWubaGrkjBij=ndb|H=48QUBy8!~_Snmu_v$)9mdxd+)I9ZgI^yr> zo|@CpHYcr=x2|m5ydNj${VP=qot&R}i=XvAi**Z-N|CI*Qmx+Hac8R>N#hT6d&*a# z15~9Z_aeTqeZiAmSL9q)uUMrU$!X6~_iO`}BoQ)^d}8Y~j>;W6X*CJwJ6OCni`z8a zq)z8buB;lbnxt|l?NzJhS~)8}XVRvC!spzu$}jZ8VW`;Fx>sqd!K4*pHD}fj2Qb8# z2^{>~X5AM!s$0qp!z+Q2m%eAqu+OPf>2{uy=m|tkZuq_2`F&Q?g$)3EnTQwYTHgW- zzjLyF*no;TU+YQ#K4+g}H}3%s+vdzlUwstBn)oAixC)e7B&Spa{r&@Ln+=#Be%%*Q zw^j~N_e*MW=4ej*3YufFo%0KbwL+-R)tD#qoEx)=lWpoT(f4o70%V6}16@;y&S$=( zGfOEO>F1)A!me8_12Ab-0flB$7fpu?Kj`fp07+;PlgmIlF+tg!K+{m2RloyBWwd0q zrhR0tC6Aw+58Zmw9|Q4E1BCT0b80biJuM5MZP2X=e^*C+Z(^;8@D%p?YO=0B@dn1C-f;~Ve)SiBZrtAa^V=hz`BZ1zabNfApZW{`@%GJs@;f%a z)t|Z7Sv?8K+Z+o`4&^qrSFM}&g1_i0t?{++fnK_;vw=hZ#Fh3(g5`2?1m*ggvcLkmbYZRXh@ zx~it+NJY?REB};k7f7wn>2pr=Ej)$ms`HE9)m~1lt~)Y$E#Q=``{Kg$ufb=oqtvbQ zYmim5WP-EKS$h&c_rl1e>YO6c`8_|~Ng}ck3yZ4~eb-q{6Hu!LA7Q_q#qR|941m5; z;j2yWMVa<}pMC$Lo#I=w)mKf;vT8}s>j->EPr4CYcz!8YM!MciJBsXe;Vj9qPWK~G z{d1OHw$EO2h^pr-b$(fw>A5zt5uJbG%uNs1x+ze)Ip2j^)fA;Gp5K9X@Y?>Bq=hXr zMLylZOHNPLo`gs+Fj8pmKIUjppwWtJ=?8Aoji8^|M88DSa~=5k0zj&B=XZ@FgyVc- z8Pb*~kW-=`Q? zk6o?n$_{o4RB&yFadriw*z4t|r)@h*e5-RwPn=91?y`z|0`DrCLSp|pDM?O*BLm744W%&JRXmi-;g*+5;dj}4^jqepGk1pt6LmQ^<^f~f2t3wOWWGt?z+?vizA}Brz9n>~2X{&w4(M=J zl=d{2_T%yA2Ay^A*O_+tz?c0yorG1#wYGo5;3tQ%F4{l3I)_ddM~k}b-f}$)@H?*a znTLAKMPf$){jLLidR!=ZVn&yu2A;jGdBuIzeCyy1#C%FIKGwO`*EAJbp*!&tOIeos zb@$IKyZqGO{kmX?6sS2e&l#?HXk}}F%qV7^*uONjICk4rCjsj9nXT_leJk%~aao(7x#(27&8J+Ww-*3Fx2jS#Oy;x47%Fnq zp|6&@=vtTYr}hG?#jp-S;2HfXipbT|cK@dCOt#pI%ny-Rn6u8Wi(S>f%Gvb|;9tN`i0+?{{Pz2|_rB*> zw)ef~UE6!(Pd@4s{QaWgRmZ&ryq>gu)i?Z+?T`Q2zqGyntG+fLzah+h)3-LAKYN{$ zw=fa9w;*+8iL3MmyX?QG)n73X?1gh7a3ScdqS{@w_!1LFkAr^an;VzX2z2!f6!ieq{03;TR4+`|RLTBdR{u@)`28;_|@6_u2!ci0IjdE}U!|@fr@g}~2 z0TRxdc2X*9j#6++WlnW8i%v}mE#gUFq=5|Jxc2>(COT81v(k?qv_o5ZHDe@8f0<_- zMDmm4w(`RPE?Z5)MO$ev1HwyE@xl>St7ZuQB5i~7!anG|v>7@iCt_=|mshUwnC+rj zJH9rM+Qlah>pkZFsb_hmPqPT4(K=s=Hg563pj$Qte14fUKSj9zxF1Sf39a62WaeBE zN0I#<(L;w`$Q;?g(60E6H}M4w(9|As6ZXCXbkqH#BWd<1pZ?g|fQo(PywnLhL^ZY` zJuUZ2@xA>IP+SvZeq4mrV&BRq#QCWaO&i|e7GJjiAu2+7lT-YtcL+1t_5y6>CeSF9 zp2CK)L|pp*2cumL${6horK{EX%;xh~vGWzTRs75e+WF#k`qaJ`&`g2aFZ|4xcHm9- zC7VivSUxLqN{d@(o3*|9U4pQumt2`We$5yT^+q|kIhPWiEiC)Cjr21gjlTlmJ0}OS zVEDds(n?@z)at5DD{AroI){EJQ}Z^wFvXEGuX+-e{Cc~8Ji!;ySNWFY3BT-kyTGVF zy*(Z81c(m+*dBPvS5yPEu`UEboas6e&XNZ*m6DmjG;DCrUOiH$t7w5&r|=28RS8L~ za@SrGU)Ke~%mQVli>l@PS{$X**Diil?zVmWBOly;?EC)T?I(ZepKf1x^mC`%{4Q0V z^_=H!ule$LF(6(Pc=eaPVbh=7d&$dQ=_dy@LY)(59@g&F_g|VoVPertXQYd^*qgUQCIB4&jjT8In&QcwN;inyved}NEd=9=0!ojmnK}w^WQkC z8C!($q+ZFE+8%rV_ix)1k8F3xpQZJaeHCN>LQ8Ah21%vyqQXJL{k&BZjjzX)iay(% zhI3UY5Ov4>5;bcM*kNGBjo103eTs;DVlhwG@3WL<2ZXrw_jDs?XdA#VCu0Z)J9}+) zTt=SGDUy=bvJ~L3)sozR8Au9SrN%qr1C~vn^EN+n1qr9lDvD^?3bd@krazqoSt_z7U&=*kN3vkceUa1uf$ z6-Hhqw%W1YWAbb|P@Djt+CNaW(3)@~RXvXfNI*9sh$dEL`MON=Q&^Hdr<|GlPh9lM z%8AAPkePr6#HI7YheKIb>#F-_mcc%Q4=^ozWoGwp^RfSFu2x^<9HMEfOdiaX&+~2N z0n>&~tcf2OLzyLFx9NQOk<9iz+I1qg%$ zS^W!WlsbhRmYN?oG5^H}4y#!STz@_G`A6e#!hZmvKwiI}|BT>Ae&@HYFLVc(_r<5k z>w^Vf`RdpB1%X$7$!q=2ffvQ!mgfnB&x^Yqd+W1sCrNnq&uMnJkM#BX$&Y=+zsdj5 z2j1%^{Q9lFKCn+8-uQcIz5I*5B>s%wU)bLKt$%uZ;5pBZ(KujPt=JdG(d{UXt0{;5 z_tMS%JEgl$Mj!US)-Q?uwS5B9&+W?c%ymNh3Tf`qBTCN1f9t4jY+i~NPUYig(PQuZ zM-j&p{`{~%@$0w#%^$ksMF9!$A%NrSI}az$uRac78Zhc7&##{iAdwfJ(DzXczXNIg4O_)IdahM(6i4^q;<7i zX_719l@xJ-54B1qAG)lT(*=qI09O+bIqgvk-iYEF`IGeI9BCH$1Rq}FJQBHezC}yD zxIa|dy-z#GptzumP0Y%tEUU%2jA*&W%o^LAbj%~U!!PVA6&!O7n2X4*vl=B{a4wru z*wP8V+FZsL>C}o^X{KY{@K1gH9vTnPi61HEl4S|wmAcbjQ^02fZn4y=SFi6T8zAZ( z(&u9i_B`&u;6jj$d=~kZt5nMYr&s9}7(~cNuHXM~WVI~Yw5gA30wT#7RURj}qQkRo zdcbO*0ISgW!DH5h&Hn_T8kI9tAfb732mm=?nlXF?=wN}DZJ5gGY$DGA$(3Nl^&5Wu zrav_O*8jAkk0<=XMa@tC{>xsmJ^zI-+3tTJ{{-Ew z4SwnloEzv*G3rk+KK!u{$L%BA!yk{EY{Z}Z_(%QZ|H&txm`T5fqG!iDG5*lE{E6+G z|M<82pJ&u)`X<0*vp?jzFYp>41THET>T+kjA5J#BTsWaZ*)c#Kjn+wTwQWC2Zh*y7peN8cIM_0~HRInWs{)Laf)@+)wYb2)jsyG&S+G3{-3}|5;CSUWGru5>bxGyyK zYQnL%-ZRHNq$0trN7_f=&+W_npP4k0NnrO?y3*QTnf)Y5m12lM3|16l^c-0hQTF;n!>n)3qUSj$z zrP+w=SvC9`W8EX#VUPB&T-=zW?~!(UwUivD1Q0rCg6sQtE@$lhz*fBt(D}?G+{*8@ zNsl1=ra9X8ss~MnbgDMZ76Wj`ZTxW`wVDrI;()5raL@#&c?~UR;C5$Xb4{~oOKsKM z)ss#M3{hm@vyI}%e?vU;u^%5WZ>9}{OMVseP6LE^HHU~zqKvRwb@(}vApp7s9=ST~ zaNFDchuo;^iM-h46par6oL>OA_qngy?s?AP6W2YCxv&o-hL?IncU%uRvg1VrHmIyH zxj#TRvgk?Vxc_PC?SW@K zd%O4E`?q`VyLY=MUQD>>-g_gKy)W#&p5e(SpWL2`C+d2#F8fr(`Y=VskA30u+oPZT z%=S6m9{J4n=p&yE|I^`rHZYIh+8%zlg!JU=4PW#1+ne9|?c3LW(;pju#;-T`*B4(f z*aqO?(M$5RTmvvtw|Bi$y6c4M!{)Fn=7P9?f9kLy%|)EVdVELO{IJCrWx*@e7jr1rwZNdM*fU~xbdUIf>98X{O|SxM0Svb^ z7a`}fF1#u5yF}+jeqHD&FCQ((b&<2I?1j9lH7n34CX9^jIxEGRWoQ3rgDKrM05$Yv z_j1n1rO#2moVHH!*;s3Te10l+fOLsvTWCLWZtr1SF3rws<%6EI;18;=*E0mUp8KP(^ zaykTk9tg|kz{MX_U!9BkT7y2#(X^0Qc~d@hm18zJ^0mZ0xw6(AHWHc`)) z4fke6QxwnGtYvZz`CZF3aBj)KqLaQr>QctB4h0q=fp5z}=5et@Y_dnRo#ft}b z-~asWzUhMitr(nP587Rop2F0i0(e2qD6_X==qIh5?=0Em`TRu4nUO=PZ$-WqwGmz8 zdP9MUp24Zd%*pA*TQ@fepJZOOpx;{m%#Z%_?Pq@MU;JD9#QCev{QLOxPC#$*|HE(j zw(SqU^-pgvI`_{s^3CAvhaZp2PB?GA)2Q|Fe;Rr73cXNbKg5?=@VWmbH2X?NgTQ5d z&#$Zf?#j9J?TJ-xIyM35`6oW~6Wi0D|4{rW%-{U$p8+IBIO*{O-`cHKeM)fP$@>SO z0@XQ+@|CDSsGSv<4x^8?;&Mb!aODjgx)=WZkyeoE>m>zDPtD^Ew0W}+P%7vV%TBXZ z&=Ch8zF{d|{sDIIjs|GwmorZL45riYb}-xlN9PyVU9Hg6j9Sb;qWNmQ+<$Km_lTdM zOZP8g(`A0{zdmzK)CXvMxy;F4QrZW%s}-D%>C(!xR$cP4;OOZZLJGoP!qGF5=H>vx z6wpD$SyQQ2)@10dTJ>+7asi`TV$F%#3hVr%^8<`T=ZEjvQUIuItqi2g88Lv*TfkPc zo}j6XR?myFy97=x>ZB@0kVL2K)R+}G=kGR&KRPpkX^du@%X^EMJu>q|ftQVo-tyr4 zZ2g>z69D;I%s+y-R>7I03$s!<;!7elro6xm$Gka=!?<)#mX0|z?KZg5fFrB5r#mX+ z3Vr}bZraw`V={)yR!8gzp1|$U$w4T?FG-s6C_6;@^@@TWzBf#ZZ2P)5f2)7fug_LEZ{=gm4?jKr+GEbSRGEA*3;w)@Cr~uN z3Pzt3lv_z(rw5$ee-HaiJum;lALq*%sEnP+EUa1Duoy7IL$=vZp*sUS8~euOnw=8fMK zaOLQ7itqh}4t63o{o)5eY0d+l&R@&82o%ew?jo1STO(q4RmuW9>!{cX>7x(Vu&ALa zSoz68*Bk)dPGSdvQ~Mtq9evyaE$QHgEq)AyF9`cPH7E6T|Mb#+`a&BXw)lWGQ~2iF ziGW;Uq=o*fTYA+1l0+9@y6O>YI{%Rx`M4UAxK^^e%MYye0#Pj&evP-}S3S-Fn0e@v zWT=c~=v$@aC{~Zs^*;fKzXGtXqd`RMAO+EdfqKb))DtpU1^uwiPx2|P99X}}M@uf7 z?Ef5qKmDcFhbRB~;J^GQ0P)*@|1SXdzv#=iyYCx+XWcI%BqyhFFX@b?(yL14rpzVv zj=h>M;eJr(vXkfY3l8%kC98!zzLPh-(CnHz(0NSs$IRK1Yz(opiMIe8JwN{8-`U>r zQ$H3j2>h7;Ox-OA|GvZ>I)T^5pIZFdZ+gr2rZ@kw?WHe&)it~1V~vMg|5_v0m8n;5 z4^+h~IOrTTxPr!Yp!B^8R~*f$m3(9vA3H#Y>#00C*ZRJBknbK7_FVZ<>~;Hfi6646 zj{lqT^kWZikN?h(`bVL@wfRMWaP&ff{XmfyVe+jo&de_g^)N4`$b*8^vn1@Ow-9jWcPc0QaA2tEO|(Phv@xlLhL+2Doc>1o?@spby;%tDi*p z?2n!++%e!@jGWT&s(mEMX(seLb=9;^BxQAhFRqsJVK3BjF=t9n@l(@U@|&h|Vd6S8lz@6`SRe(hO~7DW8WuU}K0Q-0v>i>K9e$9|RNVMg&Kz`X-;1!7FCtFcc4%F2X5$?I(>zI# z6dO?^EpX&VwiV+qZYW<7c+_{PHjS zp7_&sCpPo%MOuGS@%3N%rtK@<^o`qBf8)1oFMRP!ufK17;p^_!rTmmz9~$+rSPR#0 zKQr%??%ZXL)KjZAH^K|AZO(pXEj@iJkrp-D?dk)9unW3U(s%784E>B{+06@nmBV@R zlfSw>_3*F6Z}{~AfaBC`;{vX~D?qx6wg0L+nH`nScMFWiU!ukjqybWjqv?59DF{Q8 zB(zd#@A4%?6N~0$5;zo&G!}YEiLX_O5!Rd$PLS+pIE9rS`Gi@lw1Twyqg%EQlJ2OZ z+3C~yNwl7ZiG{Y|a7O8HRX*{xu|u`IqZyLseDEc)hp|BPpnb>ny*Xdqj`h43fnwR0 z6LI;?k3AGNrm;{=x#q1ZP8_whj>y{So64^HmIW)eO?@JcE<>;1vr3KvBC zsat*ucHGh9A~@QYmd`>?#PrB;#FLOJ$DEWp)D~@TDd!v@U(4-$KY&$feT#pf9lR5| z2S9j%u|~L-O-}jBN6`0gKHA9_UJG33Sj)w@MBtdF}hn$l{uk!A1L@`iLK#b&XCG$>W*w}ESrHG$% zRQ&z=cWuA=&Y$(|eew6~pMLtO(}drz-1r3UzWbi-HDCS}+Z(_3>$f+4%{SP;`<{Dl ztXl&0wH6usvT-~0^;G$bK&5^~r)yTDD{7nz@4dviYQN-jW|HWVr{qrM#h(P6xY0$e zc2~~eA5jVLZ{^!w*5Cf?cpiKI55%hgpN(&A`CEUz5D+svj=KA~7XHb<08r2Pqw~-i z#0YsTGKbF7XCj+JmsL)SLzf%=5zHd{`RRK!M07Gv`p}iW@(rV&T87It4>%slVz9uZ2$eEyrxC9j!jAiZP_M!bP+5y`A9r%!J2hzRZ;l`_Dd|FK(vYOC0LM zk=R(wbfg<)IMaO+`Mvp5?qG6&(ibmoU9<1sL;wo#Wpnku_1H?>o-R2zl}2hI?NsKB zjfAWg7|$5V(wd3~Tu<8%ftoQA@X29?WwAfS__hg{av`X=1~n-zZj=O-a}Jl~D;GB` zXF`lsewwigO*1gk(xNP@MPJVtvFq8Gn#h@&I2ZA!nG7`54fb>^7cl#>abw=vK+2Tq zvnm;c;z#Xh4q?cre`uma^3llw)JDr;@)a|;tQPe?hw@e5(e0e_O+rw?VX2jHTD`w> zadB>`8O&u8h-BjkGHGV5?hFHhLSAwB{r;Kws>f1J3!bbvjN-a-T8TvmoJzDRXkgLo zb@>NzM|CM(K^lKgv$PphD)_Rw&{1e#Hg3%8K*dayu5wy{<%VyVY&eQp=pi%y3P1wD z?U5%UKvc2h0Y_dbg<5Q~4>T%yh2N6N8BfepEOJJcRh!5t7Cx4)@(=F-ARZXO9?+iy zyl?zDK=UMFrX?)Wi zIQsVHzW^Ycp9vs>^1}`%!^q1!?6pGW6!2K&7z}TgP-QOmPrfXKSVqE{vgo1HYp3=(b~%;sQ8Joi3^Y4>8!+QwWB^+cfJv&S>vC}Z{nPl zMDV5Q)%03Rs)d;ohv?M)`~7!7hsS1e075X*(_$9e4ho;M9mx60{(81@C-z^>I!S)^ zE&d_pa|C`gs|q9mVcCmpEW#0u`v<>l2jRmHtMg!;JU;>UW?J=9$k5cjP?N^koU8Yu zg&;o55JywFX)O3Et|HbD5-1F?0Z1+9*#TN4ueF4>Ls2}p4LmKJ0p2LuapU)xa_vr6=?ft*;?)cn*cWv)`&o9UAUE8NW`H8dn|2_g=@S>OaxB9Pn{a0@K_xxY-Wv}1v zf8ben{wVx4mu=RE0uKXhpQdsm-PT$MxGmj_bgnvopD}cAe13hlu6@6jw`K%V&cJGZAk^PB#bR__2%JpjTux4Zx_p6ri0-(&UH1MKIPJwyNg z&$)6Wiu?Cv5u770x$r$`*5p&BrdW$wea|21!?lP5T>Q-M@_UU&2St16Fu(-6h@Z8Z zHwUnu{8(LEKFiP+E5A2CEmTK$vYA)C&R+p*5+FG&CFZ&+pF6Vil_T!mYHvNM0b()7 zhz@)>vRc;7@L8XV`HOuZbYYvWh@)b{)#ko4)Cz|vRNIsq=d1nu#s2ZwNN zppbMmCrHb_Ipax>4JCFuznoDe^1x-i(wQ_Vi7!7c zM|{;XZwP(~r%3YIFWIg)L3a3>L3s9GHuI{Jo9M|YzHqS|4>yF<$s}!*WkwO)ze52g zzckSkKW@rv;afBH%*jIX^Pd0=P7%e{VQVo+5=PR6gFAV_rMY1jXm!o*Q}~Egizoc!JcSc{;GMtwzU_gR{K49*b%gN-MkD8zakA2~ z2Y1CED%bTmk2;{sg|yLr|B1RT$#%)^uh=Wa%zGu$0c`p*zpDL<|A0Q>u{o7*IM0a= zr_;C5?|6RwsloTY=U285{N}H1AA0|L{nrLQ@zD>R9^?PVm6yEi727Lc{o1&_W_$JP z-mty)4S#TZ(Mw-8cI@NN^Ydf+HtvtB9A@;(_GZ!k=<5s6Nx)T_E?BgcMt_0avGCk} z%m}_65T!nTD_=hPp1|d-J%rkxTv1%>j`PB|-~;BF?XlnbzHNK@G4uFMzn;tA6@QsV z_m!~X`ANU5V_k=DN4`_K1ZR{-N#Fam$T^N+Ku672&b_6`PsbMl4Z1cM^x>Ax0aUlU z4B&j^dfi$QKpfwq^W})2<AD2oltpi_U0lWOqKI=>QYP6!}vy$nvy z(!nMi^TpL>YOfJ;uCiLwW4UQ|&OnZ9=UYFE=qa2uvyQn)*W3hJFB+&v*G6YPtdX^L z4h83E7WSC?9}V{T><@}i^eBDhT+rpPz&S&&2++d9Ku>Y)xet)Q;*}GH@D(Cn{7BhX zjRnsHlEe0yndfYN&QK#qeClhVYnH#v<5@IT0dhuCO@H0Lk&E77#}Os3^s`{NF44~| zPw>Ye6t|kpff8*+PU$0l zB&X&f#!zOP6rL=r8V+po{p8xE!7(GWc+y=qw93!A;`)HVdKWm z{NZ|EC~TH#V#<_UZeZn#OR> zhr8a5erS*sR{m|RJEeQkeDu7^KH!9IKPR>6_p8q;bI6ku_GmTTTR2xnIch^903Bn$ zCH#B;hI#tY4{wiu_$PuBPulwj0O|#Rct@HZM*cVdp)VO8%7=FVjQx@K7?I-50Dde{ z?B^;m#a<55m*LF9+ErcY2;fN*{z^Z2&Z%2EL$);Kpr56hp zDXM+(dU6e0z1-B4M)gq;E88E=Z=}aH1>h)Ini=%{4^q2M;E^XKA^SN1J!~T%( zkVa{`c3$V$&!**1%yzDkPpGXfM~}bG&AL*|Tji)(E1G(?EI8NjN9R|7QkopJ1k=)< zw9eW80Qx#E^nx!NH=mOb5wL%SM+>kD^3(KlhTrErG#DH(v%ow{=hu8e==oK5sK>R< zIh|kbPq>~heR#RI(!-&?$4}0*H}T+f&1#r)M67wVTuM&)qg2<*+o|-SRq!>3R^O)p zJwFibntd&l=}O6ob;M82nm_vDn@|Fg7vIT)@A(=>b@K=C@F9Q<1wlIYWfjCSSq_~j zD936!U@DbvB*}Y_s2$y@XkmxufFJmLFrceZKKFg*4o$iIc?9QUxOYz`*Dn4ZJ(+_`qd-!7?-X8w=N4AGQ z8a8~ri$L}>pL}@x{G*R_*6+Ii?B_ghd;W`FyuJ9Lm&b4KUv4Y^#Sgt=dvW|W{{=63 z>2}XO_wLWdzB!iZaY0d30Q)jG&gvV1diO7&wSAxM$Y;J@xam}PLi5y2H|%xe^V^&2 zhBKw4@76teasgN|j`K2VF-v^^0{7U5{?+!(=RX#4z5pPry590HsNV@7N-)O%-RvgE5Qi2|fHEP=a%-Vk<{YWjDeXB{|CDH~K-Kaa8x*jWhAx zC{?b4;3%KL8Yr#T<^Z7cH$7g-bO>25h0jrSwCT`BWvpJL?2&TH&gV z))8MhSGq$YExKXLO{eb>*0d$zw5DXvvE(Oc1pR&}diM1`EZiB6kr*zF*u zY@L}lPmA62@3aDDGB;3ZIkEa4M<$P|fMnBVp8fUeI#WNhsZSJ6@x{@a+DFj&))hdj znvAfnO#oLl_s#x_yRPC|=vQJmNBl?^6la}@0jP_UIrh>i_*gYq=dAN9(BaH9>B%`) zt;VlIw}38V<){u$>Z&TBR@YRFK-hBAF;xDkMQzda`2~k_>E+UF$#S#r?)gPcdRo+v z+9$vEI^g39Sp2x9RNWU!lK1=p@LY}8oC0%@I!dGj&9% z%lULj&rR(kpikii&~mfk_AC54v&4~)UgN*8X=)oF*=Z%iX=+#jsfX=Ds-M=LuIUMI zzZ|aPO%^|HF3V{>)Jvt{$1hLj0Kb}m-pSkpT9+dI)mk1vH z+-JAXJrcLietLWKk7-Ri1cPR(Y%P;=f7yA3&ad?BV&zfBaDKlYe3Q*!t9eB*OJO0z$Wxd{)8)3Gw19 z7fH{dBr5?mANfVV+EIhLl!tC|jY+_&iwDSr5&Q#e&kXU zJ!=Ji)$OwgtA#$=!sxaxG%H^Nj11ZSi;F?-y`8t zU8t+KXlU>4-z4D@WPOw_;s*w8^^?CY=L&R~qf+72J~}x8G6=JO!>Bhtdo-oxjYlRx z-rri6URw&S7Y=7>D@+vdizZy-cNe|@){LUC>m0(>O2C>czO?q{KwyV&`4R|V=SvT6 z*rbm=En4(7d;%T>YR}S=cIzcn(aOoBim~7b2t;}5Xi>LSoHy0Hl!&EzUnlts4vy2h zm3NQ;>R~%yy|wmqO;3RP$?uwGj!VkBj&Ixe6MfNvBQ<7G zucVJ$s|kaIbti!_(-A*_XnQ{ivq}C@z6J;s{BXg!to$gCJX#XID_;N*(0Ma*W0_Q5 z;#sPVDP1eEV6dt)jC}6ggj>`42I?{v4@^akum2d*^Y&>`M<=xP?^)7YzAq|55U97#;t2Ev{CUrRp>NyvYAM`cooI5Q;<|wo;4@)kpX^&&K7bRVx18pzWwo&K zIT~`rzF#BRAK${?XwgI>@~hd6RL>)y+iPb=Mx}&RV`Rw@s|HWL7a#>k#Q{0v+Evbg z4~XtZ6ZhFqe)3lbj_=LdhkZMP+M4mif9$_$R*&TQ)q@~bf9Wjj=BFsC@BPP{hJfw+=nRdZl>Rb18Z4{7NU8-mmEBJ1_mzl%b7m;TlF9 z^2|W&jUymnEJCo#6+Y|PUZrXOBjIb^SL$JW3d?xzaHOj~*2hXSF+*tt%6YY-b;yTh zPDA1Xlsr)7wdgM&tbDCg`ybVIO(L4`9A}OFgK?Y^38?|VU*b6)VU9p~I6Fyyo4 z95eyuf^VxNg%m(qY410jlA)M2&2BpR0;U+6k@x+fID8)C3faFU5~sX`eI5=nPM`Zh zA$`NIYYtm( zRK`GVm;%KYAn**+^OEr}i8%yH95ltTY=Vn7bp4xu;Y%yI%0=%%ZBN8KLuBrnU<1Tt+0z5s7tOA>Fn-bLe&7B z&Rn9cdByA6%dMCxMwCWp2tbhz{zQ*tm(hKt`>yAv8G3LQs1t7Js~^Kl>NfhX8q$v( zt+2G4+9x-SAk#z1iQBv|OmBFZ{>sVytu$cdiMv$|x~+;@*b&{atG`D@GYjwS z>aygi32Q(3_4O-G@`gz2E5~YeyKX#+hBd7F#Krq+yqX_PY+ww-k`L?sFScgQ4Nd1q zKWQ{Q(z41kOKn5g3Ifx8QIgX&v;EkoblXC|W>w?V#06gSs}QSn6=Y7XmO}&@kW|f? z;L1mw?T1JOv!?mtX1(~~)SeFI0TU=zni1rcdAb!)T56%CTDS6Ryd6=rq@e|W1aVF6 zy?o`Wfm!4JmDZrw0L1hx{-7oKzynXY^XmKpWPh2{+Fc-gLacPr>^+?4vgjIz0Gh%m z7t1F7k;(a#(~YwVtKOu*DnSmbntWZ@H@3ji)d~!}X>UCrFvgfPMHjgQ!q-Z0rNgQI zDwo)xGK0BUKhj+^6>1qb+`5*$2GGhugw@UcQvkj>)I<>{m)uFSf&oC&R;jEL_j)Uv z>^7~Jlbs*_DZXLJ6^51cvF}K#q?{I7K7)*1a4{|c?7CG;2fjrk=eBX-{&k!C||GT722FHD|k-m&h zn~P*Gt*OanjZ$QQW1yLBxtZVzxeiQp?Ax6U`@6kf$M?my_ZIjeP( zKb>FXrv8nLTikG__5l!veRN%On*grQL!9J^+xr`*T-3F|k0=vLHq0)TWD!%74Yd5! z3|;JK)zOEU=pn1yGA#Qla$soBnXUUb7F`9YNva-ykx-5sP;f`R1<+!Ea96CgNg7=3 z9WA92U@z;e%uu{^ye0Ylmi=TVUVu%58?ol>m@Liz{Yx@+3B@&EeYk}qf7Kn06BI@( z=(X54vxvX0o?-@L)Kdv;Bcf+~2-x}(poravSUh|+3*RAD^|r+IJ~JmQ{Z8sOEw#ut z=85Z@@+xRG{7B?X5g3yK>aB%EcVx%)NK>Hf1CRM@Fi|NEndzGJ14dZgPUvgZu7~PmzI_PJ6)2OdAxrg|T2X@j;(XP491J5?_*6tt%BexeTM?RaCZt^HQ z42=7#kg4dURgjKRDaCB>wIihGyB{fG+BUh)SY{A69(h z)5@<+!Bei$2O*PTYMI>lQGmxGd5$EMA0UsW-;}5(l17XFn6eiaV>OTbOon~xu}^PL zJ^oqqjqM!6@*M?98Abx7Jh?-Ek249J2pEn5Pr#1SiT57EmsLt5?pgS%U2CnP7l`cj zI7yF!XHQZ);?o_@0-dH`t8#J!*HRmIlBm+3uag zYjQN2dJ)K`dUNYP7MM*nDE?uXLCq>40%3&#FY8-egkNjSHxbaoCRaMbmqkyBTy}F$ zX(*NL=O#gMDi^-@*sO@I3&;RY>M|C4li1p~^i^v`<-Nk`zFTBMx^)ZiTC-k}Q?K>N z%-Cb&`+f+Xtw7QUp7#kKOTA-6$-Xk>M*s~g`ZRzO?GhYm2rnJ;l+aQwZwl8M&43#d zAY$2mqla+rWx)iw7(ThMr4tT#SuGhu<&aCOx>wfB0Yiy6Y`W9_Cv5=1r9T6xq?_=z zCPt8px8B zbZb`SV%g9HOJ0D;nWvoi)I`i$cwUV@gu!Ipy~6kY!dfde#~>j0KSbjPku)Kq1HZR02y&TCnCf0u7l$t6PKJWGb@~m#Nc)cv*x*Hb^h5=Hr+xi z?swl>FW@;2kGd3?%{j&nm&!!X4jOvkVX$Sd6hi`mi^cHMYBHsDoeXdXA3gp5OCMfX<&N|s@0|D&%B4`ZzB=E1RP4OQcYYBtG%&K}hhxob zGST7oWZ;-pJPFANf==a=KhXgXYFx*Xrg^fF;zqsOI=|ExxN^xCUV7F{GMasUX6^bk z?_BE2dDf;cT{N-AtB|YQ&Tlnqwwg-CNgRgrtoa&GHSv5y0744Xj0GI`ANrh$EE1|2 z9vAZ!s}6w1*sP1!m+-}pg6NjW8L4%SeA>v;g5F(|nmLeCTRAQEZ+>Fn*+xz^^am@i zk*^uW)h(8C#$zLA4Ob5r<={_sHP*t0o6=5mQEuhCZvqnY>F?PAXT2NmQ3?8mTl{cbSArG3p~`Wi zmR20^u|Wj&Osyuk@_UQ>YO9D61{^FYLD^U7E163)`iI7N0l;KcVu?gU z+YI)^1|zP4F+DXzsU{J4Q>`|@gJ*ePO3ixai<@cDDDz0*o2 z)0PCPylyP=#AjPX&JbW0X+!HdS*>b{NeQfUAdka{c{jOg~S=wolIgY@#YN-Jio z)NC`U#~J5_y{)lIXLo?AUhJ>|S#CQF?#e{k=JN8`pz)$BFu_PFKl}462@nlzlsd#B{p|scnFjrGE zufE3e=T0P@58M-<`t|MU$38O{B>h+!f!^AGmo6G#ETwe|3@--w^8{2L1r>+uTwY33 z8gaAUfQ~>M39qXGT~3VBwJ-T`gKvs(2F{? zym1M(21TnL=0Lx+#7!PnRMVA@8~K#7QO;V_W#OeYk9v~nKY_C*Q}q}?dfep5ue!kN z3V`SKWfYlRmYJo~wOkWi=d-L3002M$Nkly5qP2QCh3_P|f+cP&Wut1k5s;4;*Fl#m$?z(xE;DD(DuA zGZD~SB~!zE3y+#gT18I{H_1k%*uV6_(~CaFgkDmu4HzAY!m@v~!HBP0Vi;H!FgX)P-d*=I^mh*rG_ZV6+ayIZvp}a2t3ITu4-AADasV+!#rVmUZLEsZODWG3k(JX!BD9Y;E!YmtqY$f-!>+!p%p2_YT0Gu6WtX^Vfz%jY8bU ze`uwi`zSx^&hnW6QG4={55=1R9yjXf!d@uET;g*jU2|G|AT(Qg1>1MDS&-O$;Orb6zbinYd>6B3lYY;0DC)=KkH@}agNGPHD-SQr z!?Zjay>I6;O0Q2^5zq$=9N{Lv2PtB%=4ng)omUP{Si6B$t1g#fKRJ(}O99;{ zf;|HQGzw01Fjxryb6poLX=GVW7XkASe?VFUUEq???0tSp)B?AH(8nO07hJ~%5A3NM zJ{)>DR!{NkB0FoLbzQKzv={de7Y$+NKFvYQK`vuX%IYt!S0^*0l2!DKa2p&79OcU= zbTyp0N6qgA76SQ{C8U%dg5a}%!K6Fs__hQBX8HU}NF~a>H|3I?x;=n2ip%_yuh~?C zuaNr8gHxR$n&aZoh=9^)$#?%Gnk&6?6~_3=3l7)k7p(HusG{mLYTYSN<)`PD8oZ1r z#U(rv%x`SvW!<}=h6Rh3B$8Tt7nsEE3fd(g6VChwf)#KZfWp{sVFWRsa^*y2PVcMY zx!^Dqu{h>oi=>+Lbir0M{sw@GwNw;X3&BpN(8CC9wPgtn8`$22L~Fq(zq0GUi`B4PXNCC&A-1=g)vMSYgG?d z>mo;WCpx>T{A9=bxN4V&$Z3U8BQ5NT-o6&M&o5~9FMH>|E&2+A-5~r5R3*XY5*>-Q z<@n61hMk-@eT3cwegOcz-nsvGb(AItg$kjL zqtCBGN$~)tq3-;dTQ?wN5#GPvJ$(UBtiKAZPyB9Zci_JLoBz4~D>L67^RGSopP&_M z{l;46?FQ?O0%i3j1Oe;w{Ha5s-*N4YpNuXnd>0lr z(neUX63r=`p!9H_dKVC1mVKzKC5~q*Yd<;DC2a9w%k_#t^D8;|!gMe7FiFWc;d=w5 zhNkk~Z)&F1g;|wG!Vm>|2$+Ig^U7)wPagA&BVP;K1SKPc9vJwd>Y=)F_5oLpMk4e&Sk67r;u+6)n}Jqh+`*@?+(vysQFhTVZir3P!#jh6U@H!*4oH@GfAzV#C%nM5b!tkPXYd_ve!D>Z<9#pg2t=N`VOw*9q@>q zWDO?7>!`_C=bsE`a(jLoYn<7Ue^;nEnN+f`=%V1O{*n2+9lb4(>}=M+FX+sn zCCdz-+X9`N`AM-&pgJ@8{+LVhJ@@~!Mpd8mvd;9M3C|4(^A66W;3MDka{RpEU;zBS zZ1r)!3?RcS*g1-Fp52!*6yTBiBv(4!k*1OZ2hGP-_?twP-Xb+*?bkU=_M;j7b90Ulfa4@*)tJTNwD631&Y1mZ2eRyE;-4VZ^F`% z7WKeWU1rvl={=X2Tc)pdsxJJTPd$4b1BB`_bDaImuglayzc*jS&IO2$?8)uE<(M}B z!(C$!zG}kjVL!1s5q01AOQ5a>EbD%$%K&v=kivEjD*TGQ-~$w=e8Jc^J&Carhh`^1 z=hDJ0D=D7+taRL8x`S^woYq4lIBA=c zSVjIP|cwSb@gbT8$KrH?9DG2 znp11;-*P2xe!y^4V-E4j%X*%=*jmKc{1X7Og}iNC`8lxo#)%h>nrJyiFlz8!O1`I| zzxd@(EE{nS-Qd(ut1$kzlq>MnbD<-M{AjFi%+@z&i<175x7JrL-~HWR)DLj}p(d=_ z7;lNMM5o(X)$OYJwZ`ZQA1MG-!M{f;yDj$!N50*<$Rd|=^X354Z@^oQNQl2fVD@LO zjb2IT4=uvUe;5rR72ZX7Q21Elb^{-ictEp3=05J-7c<_45mT&NYCy!XRTNx=_mJ9@5wFSLV~b zZc-BXpRV>cllw<6>}yPMas%g?AqDl6A`TVUWv9SX&;>6K$t`&X0!``E{m;r&@bfH6 zGWC%8;UE9@<-1@0ujN-X$I<<-hiG5be`DP*_C=`GZ&JHolIAXf?rF4iL;_ae0a>G`Qlg_T{DdOydKG33IeMr#`Qo6BJ_08Pt!d540P?$c z`k;Xo*Z#x~J_4Sr@}5l`5yP2UN{9aD{r7B{%YHO_o=&PzOTrmI7|Kp1U`~ZT3-Pon zVO@c1Z8JwxdCLUj^NTK=l={rbo9m|X)^h*kWW;r=3h2+gp-a{zJb0cY|JlOA=Nh$B*#{nR>NF`9zOH)P-}QSsy;E13C8RM7ktnj@ZY@Y|P@ zMU7ZiTI9`fav{jCsBm#S%h07RD~{{4dNM2a z6fhos72$g>@sl&8imIap)|$E~k)&}c*iR4D;e&7OaM8F9c5x^(ljWnQ8s}zQ@~uJt z!m0nnIu4)wHm5lCc$jOXT&|w*HG?>`WzVX&Z&E;m+v$)eN40I1si&qa^3hPdvBYalX;zZl?epv;#{ehWY zCCFfR()$SJFqY|@qBZ}Tf-}K3@QE|{a+HqzmRYx%GNY#updP&sHugCqP7Q=-?sK%?!=)GYHBR;~h(|4s zXpAkZnB26LzF&Y;Md%(0;%(HBD)23SBzY<*_2c*7ynOvv|Dv3=k^b5uo%-#w`K3o2 zU0+v3RNV^QZ?#xC&3;XyuT?AKK0QETSK9@ZFEu_NgtE+1Uxf6CS?3>~wBf6+g>~R2 z_O7Pdj6kx>*fM9(?z8y_56!JVbx6`qFHz7R^lJds2d}Z=&sov(zKg{EHvwrCaQ0%> zo=MsZ=Faq-bGX2TLU>A}DGMLCd+Sm)W~GLOuNZmP5}dQDW?j{z%_iMHJe#Tm5zlqy zl&p2yeSn3TSI-(=w=ajiS-^Ou0;u$ zV4+&G!sd?wm|tzF%V#;4glJH)@I7-#h8Lji6bz>MQ&XJ6qG?<8rbCLxY1r%JkrS5v zVXdnRy4ab@Oy=vtQoj5-DcMP7SC@4gfHK31~@M5&Q}}PO5^)) zU%vUx|FcHPArEEGv&A*XOxzGPe8}>7|+V^QDpYY#Ib0BI&vo}ef3Ha1L z;m!Te@$aUh)zhPz0)X#?)~&j)99epm94-id{TSyw>+1f^FaBkH&G=pM^tGk>eag`T#a_(Y5z!cg1gEm^V9DPK9zn%mkX8@${ zT8l?N)!k<%sy_J+!g1el+$ElH5k6qB2o?n`@7j05|Z=!h60LrJIN?MBNOu$_; zB7M?;KE~-nLOQ{ltAK?1R%m!~<`29%N8J3%YsSfEU$nqlVv6GnP`>w@K72g%8IX@{ zyx; zHc8VLvEs%luGRPyMB!mTUEmPg3RH#37f!KrsvnD#^#~?r>ZNY1Fcs6w&ztb*HE~FS z58WDFD@PnK^FD)V+v3HEZ(jMbb1RO=tkM|tmV`99-dFUPs|f-Eo`U28+;~;npus8! z4Se=hKTD{p0zVLqMa(3E)KGL=)Ddbc&7k8k)QOLQ{M9zVcusjPpyd}=kXNyg$i>6 z_+Lo6@Ao*g;kpak?0hA3Zaf5{_NB+`0ci3m4aCudAuYNt$la8hGU>)A!E=Ae{a#%6 zsh)iPVjeZ~JY|`G#`b3c|8u8g0GfTS-dlY7Y5tG&6t*~~)P;|6wL=EW(VVfc4@)2( z55-YI>=Dx$AR3eVoT6jTwR#yEyv(ya?- zSuXVSUQZ|yt2Tf7PhC7elHhC?rIHdPz$Qm1sx*`qA5G;aeNDbFs?8;iz~)m>T)wsC z$gf9Z6x739`NuM)F0NNC@QW`ze7J770{E2B@foEbnrDp|uB>w+SooTUn$qme@|94| zyl{kde>vTJxvnKGU(0%hgYNbfSYLo>5cl3HVa~v64n5EmUCUfuL@;S3aVv73{rCI} zwnnhX(iYqy0?`gcWiRFtI1sm&5B8i@#M$4#@ToCp$Kogut{!)q<`k&489+2Rhc8Jj zL&3A>%5Peg7etSSR3L3XDz8ONI4>mgnq^cCL=v+r0L-peu`U7Iq{dVWB<@pj`LUpuUNBaxh`9d9-hgS zRa2cA>2J;y$Q+`9k+6AK)dZ+zep&Y-a7D@GIIT-PfPkO#P&23k_wQu16ql~~N{xC- zt4{@uS=0pu&juvNoDqLF~cIf&!BfK%K+2iHX!>Seyt5p;X} z3XG$iys`Ny|Jr~Ayw*2wg&R=i);C zy#e;}_0!87m%IRY@+hy3F9`2{LDVACgeD83!0&)dNLyy$mF*X(*|b`IbBd8^43 zMOd5seXQB*OY2MfX8yUA*}n6YG*z}9%2QMRi!KDQ9}yP^9`*@e^Pi9zPaojBo-0rK zy*r)8oU?e$BCE%<^Y8iYHYcG^U2}j>)p#%Ob9xom^xFSCKU%A%$FuVT_h2DfysJw_ zS1sAS?)1D2NPk@j$FXO7)DZ34U;gWt?|<`urAK}C*5`je)*H@lqdnLEou7T>D?fAj z{O7*TXE@r+@;TD=N<@F1-+>3yXMj)@aAoxnRoZ^OrWm;$T)1r&)|>*HKZ@p~CGFH~ z6Ldd;^_WYX!fm{XQH^5pd^U+USaQP7yjrP59{$u6W*@+rD^&vKmoWQJyG13qYaHzf znZ2!-qUf%b1AYy^=Fye;ugt=ti9PGq$^5QWgC4hh`iVdD!Yb$d;DblYwuz3`Uf`Ei zSr6-#^{Ry8Uh<>kv@Z3quM+qqtS55C_LB#%l9v(%@cAh*0No#L6E2MFCm)PpRYNYY zRZWt*=F>x9@N4J=cc}`@2u4;9^D|@5oLUPGQoH3CUtFJ`8|kt%(Q;o%D&ouPG5M-% zWu6s;Qn_BmLx1MlFGqFBYsqK-j+M(pvdnmD5}Pk#t*MDF+QtU}*9W|)i$Chd-0WX^ z@O#_sWC#YSaN=p@a$Q72Yf#ocNEj5|2&mM&=%lpHu5zlYckds7tm?8=msJZdCl}ZJ zO1cJKAaQ~-Cpj6Xg&p{F|I!18wz%hVj{=ylqDc$oTE*5%9!*0P=plfcD0{7*uWF&M zVg;s-r0FAGO)s9bIAe=cjK16JqTJQKdx56}Mi$+3|CR$7?eO(d7pdi1s8T)PB!G=| zL(wZ%N{{Xn%w0~D4eUgv0G9}xh>Y<)ljs!6+SNr5HXw*BCFnh`Wl6|Cy<`do7 zUK`O_i8J#`J)w*8d22S3|B*(*pZr&*0g4s$^zZinisa{)GJs88+&`+y>B0FMGdosd zev;WXGjSjBKXU#b(S3%Un_{!iuxEbk-!gSM$463mV@{1TMqq*W&zXo}5AM{@eOWKg zDJqYQnHpi%;(k0 zr08lum1^9`>qvZl%AE%poYl$~pOmZ~$~mt(ITNZ5Sn>1|yDn06%^$d~Lr;SNSxuGC z+BgF!m;G;ZDKD-8v5ISLxT?cn)m5MSC*OATmwv`~S=xG7vkE|GPy1tUn?R|+k)XA( z;gA#1ShOZlWG&@1$Eck?`)^1%&Ueyk)|-6kyFEBrC3rhisFU~-I~&+m#rIJ zIW)UZnsv|cty6yJeWvO^brpL_KwyaFwq`lZB&>YvD(^(VmGt>3R|}3X_%76C;yS0i z0uh+QiR5J5aPjGF{ZLE`CZ;MEZv~e;HSbB}dWdJ8STM}Y41GYy0Q7BK32eS})u7hQ zuZ)uQ&>Rs$zUwN(A4#R0W`I$fTG9{Q2-WnErXEdiC$kKaajDDb;hDl0)SB*a_{yO* zdIY-mEuB$&@WXG22Z(Nx)MO`r?%x;#uKhE|br9ierWCzb0_oR7Bk9q-NLH?i@@w@u z7e=rRS^?*qZCVq516wUUGl2Sgj?{$jnbb?ow3Lr+&2DnxgfS;I#oqstkU}p*ELtf8 zS84WC2L2l0f_m=3TkN``sYLmGekn=cnk8UAdFJW<;g_lJSn6sakwZ}3q!BCUBn8z( zrm4zRL(hX$&I#FCrozXr(yA+$InYu8Ul!e1e*;A>LvQ;G-`{){&M(V7V|C(3{mT2F z04SGY_Ntiwee;`tTWbFUYrB%r?&jS z%zWlg*;`-4*Til}XD{ZGMasDXa`WJTy^&pH6`1K3^o5i3V!$sUj~4dOoN4)eX64wg zBt< z@Bc&nyZ=A8?@9c-`$m}LuN}fl&L5xW*PkV1#zkwc9bIx}{x97yqVm$zLv>r_RH&G9 zK6F=JNpXa&g(f=AksJVPlEbmIa1I~g= z#Hr-Fe(GlqG*uQ>GE)~mdAFhG(1h<))dev}wj4dIZvmqgXlS)7K0#S1FhyY0S@@NU5&^MWRCo40Ec4mTLI2#w4ej z7P&jkSvS8D-M$>{L3y4F!k?>0O@HyVe17mNwvGy8&Qo{JiVphBp}29;vvEOQtwqw$ zA=cUmm1=R+0d@i6!V1Q)Y)nvenZ&`)yokXCTz>wn+qCqBRZMR}{gt^Ac~%{Y}`8@O--D_4smc4cp_nqa|qt7y&H zebHL&mlipc&zStHc9N$53h53u=Mt6Y2{PQP6G#2Q0=#SX0RD``)Sv!mNcyfmnP2Jm zwBh_XxA$;9XJm8V+XUQcj{)w=9E+e^y$Xt{v;RZ#i-h!*nEkrA?P?{`y}QZoYZ2c$W9qj{@>_MJ@Hkr4}EeZqL5Uu918-Ze1uOMY*5v5$ISrH(Peg zD}_LC7|Bpu8(0HbUV5XxCKYq6F{iO9&Hk;Q+8m{yzv+eY##a(j`ca>Au3@7v=0Z~z zJh?5_4C(Wb7l9c<7M3|wQ<=w>SCVC6g0dA;hAZ3r@?8f6e&{f>ZEz2K>7?elE7mfu z^2lG#O|C$rtpW6D?In8wB|P-O3#QVHjZ^Z>E0KH;Fb3(~>Z8Zt%h$sz4tVEup5&E? zKjim%Ak=&QZemsM-zi;Y4I;3_U_Fb1%1;_I8a@hJT=~XDH*J=I7i*(FBbKj_eaWYe zR^TfXUtV2|4G4Zp&Kegyb!-D7qP+3Z+k#OjSohurP#RoWyLB-h&9YnnCFSatM`!Tl zD&2EdpqK}I;x&K>nT0`!#cl9Dm(t?ff>Vywg-XP?{LBkWJa|3lSsQcB-r$kwIDBL} z53mbKL|=1qpJe^09DLEBhPfxC6M(Vtr3cnNg`th&-d3^^{NDEZPgXl8Y)FF1W!U3H% zd~EXp4~q+ygQ2~wmT(-FTgbE{Ii!o_>=!iG_RP_ZZG*0kQo-uvv@Bv#(%K8_CvW7!f`;`0XE`Q=Z-Ey=gaAP z`l`}r7HOE~gxI7X&ksPXk3#YCG*>C>#U%hI`6h>SzI1 z+$#e=)0Lhf3{XVV!&9J=E~oC?fA^D9oI!8C^U{kJcH@Rm4xNt0uYkO)0<^H;0h(j* zs=)V5l@iZb41jQ+={A4K`nsJ{@-07gJ2}X53va-$^CH}}it$@>HpkBfz+gvzezLRd5+x^<^-WwiORR6oDyRRK)i-tD z{lkBJ`T95iZq4PAzVWkwuDuGqe3^FRs50EXzvO34Ij`F!#RCI2=W?K)hS0FL^pOPj zRPa*^2&-554zY)(Ab~aZ=KgQzeMr0=GLMjB|8EmN4Z-|u?A-qxXB&xvEC=&xBkU}6 zw`M!!lcO&!KOwL#Wy6tvy&35OxX}@C7cPpy_ey z!dO^MBRM^04*w&q%&CiP-~ad>_h;oQu=2v&JaS6{NoBvTzxMy#FM095z>-~$4BBzN zyw=yB>uZd@epqoE&mH^g)T*ydsB-BV$3CzenqlJRLH*RV{Bfwl=mEzP26p?^+t=#? z-aW*>+PBuGJ2m6CT4qAiHgh#b4!qM+Q=W%%r*3l46$;}$Y)Mz3ub{3s5OclHpxi#d zsmtCBt2$a4agCik*i%;^@I4d>G-d0d<^FOK%bfyFi?7GP3|EX*sw8==i*@NfBmy|| z&1+}1?)H^e>0$muS0NJWVgBHXuX^ha{M^5E90!OdR_R_OJ8{i`CUavu9}ameQr(9h z*c1p)p7?YBiiH8!x+)y2F$I!_dYljPqJlqUR>+(g6zt?1Sam}W95wT*2A}imn=N2^ znUi>G_9hyz_N6dwmrdaFD}h;~ziL}yXyOXe`_$~B#CBde5qw#e*t07oj*{4No3C8O zTApdS>*@i@9hk;W-02U{gXXBU?$oCqP4>W$+xgAD2TvvS7N7lNUDHKt^ydB}<=IQX zyoF|rrAsb^o;7)cl0=jFcL4}x0gjYi^4KT3l+7uOVI*bahrV|?l0Lu6G4r4=-LR=A zT;HLHJo|DOK2#wo%BOKzxs)tSO)%9H8xyc|kffI-K6F_>>LR@0XgP*2kc+i%-pin- z3VeOTSNR1UdU?@an(KxA;%XHCBxi-IR$BhX4Qxq&U;h-~>tEJifBxZn5j?ah;Z?$G z`*ssePxJtUlKr>9;T*h+b$B`-&gdw;7K)-Z={|SmDmm{JIN2}0#sKQ;g{?rYjsokt zE|pNuoTI4llNQ87?~}CNOH!}&WB+YalGGf@PYorsuhH^Fp7qoJ5)^ffv-(V5|4G0us=(JBLr1A<+N0sI zf_SXO>oYJ_IW1X(Hurk|8MJDBhVVq6d^9Clnhs;-3+ow`3)Zppw3O2Y=t+<-Jm~ekC3> z1ro;KbulIh8T94T!*f(((?dg`tjM%R^Q-PzD`8B;Jtusuv{VP9xR!ac<(L;=H7(QO z0j~UsH9vU4=Kd?(^c6El+oW8pOP@*h<`L?mKB~?By+t>^gcNE`Z1Y#?YAqt;$tz&DC{>?W)pa6*7xPpLG?o<;OM>Xg!B~V}Z1^DX6U;K}iS^rR`9%fO#l5@{KOC?!VRE|#&6Yo5@So7rrEEmnqDleSY(7%$a zAliVJ+}Eog#f>7?#0@xFx|Z16QBGjUwV?3miS|l zdytt4@Z?5(rn*#xIfwldtoSZBh@LM)d#^=FxNawW*_(Cp;Q~dISk~=tbf=c_g_$t( zCf}gzV!lF#5WgPWUn3(3R#y0)$)M}feBo{uIx0;q$9<7=tYZ#UyBE;HJZXDd=vg?Z zp@}w_*3BHKpPJ0X z-|ZiOaD5(V4}m$0T4+tY`IW;ifUoOvY1JD5^)~?MF$Wy*-GvOPs-ysFm~-_ofG37r zNbt=GP6tN5wc(*v-)8x50Tf^yh-u;b#e8M~>zpWRp}!kY8{);k_U24_>&1V4OIA4j z%>g5g)oK6ypZ>F#pZ)QFxd_rQ!k~DaSv7^dM>%T^CaKF_5|wL#)U&Y*edC>+8^~v; z#*nl_lNiVxnIoVE=c#>7>>26g6pj>>yZ&=da8K=>z*F#(0z;wop#h#~R+^6sZF;ug z?8T(zbCsil5b2K!fd4{!WQ<$Otn|DET}j|%W{kf+!R(*l!M|!-AgC|2f5~c1x%SVV z3;KCiG*Mvy;%62f_#W~Z;X`?;JzLw?-veY`$lv|ye}DP5{>^{=nwLK7*JBmLUqAU5 zdA)e|i~3;J3;u;(znliMc=~0vYaNPVHht*Ig>U-MRcuZ` z;I=uZfc%@~GgUqV7zQt#+nHa{JKIEhommGbDskx^?HSF5hgkw{*)iAM-X?Bp$ya03 zquKX()Z}WR4RmE!9v?e*te+a-gC&O)fyW=a@ zO|rL&*(3LPgGC#;rjPtF+Qaj=IcYB~=0|t4Lz}#3lu*{j5B_%l^?l3sM*z)d;<6?w zIh#^fI{DrNaV0#I1%qQi_`wF^9;AR$>pnx**hz?AShCPHOXtezNcm_lyDBTCnnuqH zefz#x%e99$0rblNfBNzVfA-(iH+g?h?F--6>0DX&(tZtHcvV@C87i_=BS1JIulgS* zysGvv4`{XFo}Ruiy?+SrwaovC0_#Tav(0(t%x9j~J?cZEE1&OtNo{FmV{`wr1;>ef z*9NA*y9fn>^PxuX6@P*o`|tiwpl_wO@d=8=cCb%%;JgWZs<0KN+$_wz?)mNK^+|ZI zzX`vWG;p8GA5w93l22C^U#oYm&gaMPep~;EzyIashu{5GJx#|8eEIcj`oj7T^V#ax z{?}f`gI4V6DFoknu`n9a;t{BmQWA`DuvmgWi~{`9nYSH4niWW4}`C zMyuTWsyx0bz-G@~@R6_C-KH*_ug{^NXj_-MBurRZzE-T%c7Egn^I2xVjlKm#vs`nO zDqj1^JDt4zHGsYA@39mSMTfPFtoxiW4@gV$SuUBpS;q{yEZ!$kdjk4b>-LMyjFBwA9SyhJxwk_V?a1;7aa5W z{0a}ptwCkv8GQ5Y~N%fOCmO(HvT*?n>5`4Pjkam#N?UDtVNfdCc0H zRwlX|oZu=y%n8q$y7U_W$+QN}xdG*8Zu-_s8Gdwa?sBs(KNz5vui*BE7o7UFQw#dV zJO^#NqbF5{^$P}$)ni{Q{O1|KL-fL=&$O(5b)ou-v;nR z*_p{ntVugqx)pjpr60gM_DSS4RJ5?odCNiIE!=zR()#cK_rg<3l3ruhS*QF-c4&SQ zzeqhxIrI5Dk7D|t+UJ$$$)jWsmC_d(;J%HrmOu9Yh<=heXMFFl`` z?*mbEU+44Y9{IuSImJKVk}os?Dq=B!uHYLAXYk0l)~_V-k?3k%=Z;!DEia?nwIQl@Wi`r6NB zo|#f`WVNW{JL#YA6ESI-adCUiY7m=zeBI#g>@%b*xd6DUnKZ%6*PgZJtWKO-4CCT;X?~?P$`)LEX=eI% zEPmzY9J8hUXtqDe@<-3%`W#)BemJUo;ml?#OaaA5z02_5!4afac+lC?+<#-sq5imm z{oLl5lhZz0h>rny{;M?ag}Caw)s@qNkMBk+ZJt4o7qlk*;mmj1`V9bb?jv?N?Ngk# zFo8L%#wX`I^wzWU$XELIKo0HD_e1g&>k>FW*}o20FV?F#_+WOc7x^BhsQmO_FZLx| zUCTIctGu(WFIW6pCGpiy{>jVF|Mb6o`Dy)D0Q0)GD7t2KHhPsFbB+MQQ|md`__SPD z^svtrs&Xgrl<|NLQ0v(-tuMkUtxNl@2=qt=@Ab+E?Dix>VjYnv$2TrSzuN!BGoNJ)W*j z>>l;NN6$mvbDRZNfi((mO7fH5{*!qg&Z#t8tDN>TPU|Tib2zN{?)fX++5XhEJbG1} zbGbGz!P%U`6F2>#J?G{g%zgE2<+MMw@Jn-RpI~z4b6K>m*?HtEEzr6Dvrp)UfXHi2 zyfUpfw1t^xp|IB!Ft96^Q~9kFj%Q2Z+`q}eiHxg!-;2zs+_}%G4X1iM{u6)(wu0cR ziBf&YsWXTV%76>oH4Er+vjVz3=&HSX5R%)PEd9)~emY+>aX>+@o2tA@^&-D|@S6bZ zg?`=yC|+L9yKWiL{96I5cl*M!75|-p)GPPXfAXKc{QQsq>-r;s|H+z2kH+^KqnsB(FtZSuNUb^_hgQ;C=Pys=^ss zn0%}v+qeg3>8%&ttIrQ#|LW!2`icMd^`CZizO?k3-9PoOKK?C$(z#ynm!E$IpaH&m z8UF+z&&&0be(9`#@XuW6^SRdfHBwKy-YBT#c78b%W6R(6UsPdrxYS!MPR_@GO?T0* zUKN7{C;N1zFC5{LYRv~efDL?gn0i%B=G#Yium}O{)MsFLRc~ zHRlOm+FG~suhP2Sh?x`2#+RP*zLcFCAV)m|phcU>f1p=!?!WcbGBx$K2JOiYjIdhP zmwz-OB~0rM|Ku|hGW!5SUxKwBG?lBz17F~|0y1CuBH*Jb%d%d@o=-{qfuS*c#nveD zi2W9W2!3oo8bx^A~(#yT>_GaH^x{y%sJ|>u7fLTMI|PEI0~h ze{tWn|4ZQduK-w#i>FXo*CUOO4+w@S6eI1Go~*Eqq`r`x#dRk@#Z5?;G}^efr-$*EkX^BY&2C7~oND zLhxU+pLLTYto0=~`2kJ#wT4*NnZrl&v-Uch;I}Y|FJRI9=$Srj_U&1qOytbr%igZ1 zgd`FYucHspQ&X{)ei~2hs~7!s|8IY#7yf^_^7YBp<$~zn^6SGu zFaG@#e0=_seyd!X^#(!tT9390($sqZTAo+A71E1%Wzi96@nyE9F9OO1a@h!Xabq2X z5d!0j%ce~ef$-@=9D%3&s&AUXKj#ct3F z@2==kQ>?{3TG6;3nuH*lUkPf?^#L5(fLZ|OvOVLmeaDoowTQO7KnYp8>6nVhxXKLKXY^(P3cI0dFi9)gL^@^ z;qzPrGA(*wOxI-&z7h5sP$0~8w|`?GxDl+&HosC04fa;EL6^qqd5=jxz$>wBHN9pM zjwKSHNv*A%b5T?tKR7}t=l-1!cFqL8^nTV)x(3&dwoQRfH-;BTKO%8c5$2i#)G|o( zgFj>7z1hNX^F*PaTg*PG39D7@CavX)@4V)>zh0b+vheF0I=x`0g?|QAKh@Vag8EH? z)nf77Z6(%u_*^QhzYU<3Z7cnK{iNypfBaRw5%8z}`v7`F!2E?QXd)T!Qw0!9$Pp=( zhkjF(f4T;t$$+PD{7x0m`;--47qr4x*!biy)S#GtqXGW2ErVch2H+p|(u@137$3U! zdbfXM#kupz$&CipBy=-%ZE29@c+j_Q<4RjMs9Sav` z=EeXsjnd57*FIFFF!+oJSC-tg%8NdzN?n>O+OH4bz5Fy{P622-bI)|aU}*pzE%K2c zq1{Qx#~L8LB-&M+KIEnqZ$K12U$YscnMFw+HO>^ z;8dVr&aV;+PHi37N{4QM`wX4d6n_FQIeU~&J}~APV^F%RL;^rZ#hwA=oMj50e3KW+ zdV|mYl|sVwXftp39zBO^E_=6D6o{+*Dh!iB zx3=W9FF5Lbu6dt*e(GHye|;Kyo-G1BXT&o8b^e7@ZqOGp{LtJ-KHBcDga=r8`BP`k zdkKgXo#ifxNlgC1q?hx;Gh=<9v;HdpVOVPl3YaHMAZ<9HsqCej4gdf^07*naRHtHZ zuzdHOfT@krQ8%P6Is`5BwnK5DE^eTp*6=;s#rIF+N13_&f;;;B#9ns--!@trYyM3D z-7rQKu74w-|89WrX7v`rLTVa^LjJjKdUzb{)?BN{OtPY0oskJp4nZLI+pTt zQz-+__Sca2&_nPLxUasQWq`Ml&k^jc5I+AKBoHi++5YBufIYWU;5q7f<#YL^>^CU;p~$yTALlFW>+D zzkm7h`>#C-FSfzzjb7n(^$T>_>{-9c-@Xx5b5Fe?pnn1&$+ZEym2fWmvv&5k-cYbO z6hBwYlZJ^O%E_P7 zZ}6=pOvV^g&xN$|J|_XSRLBB@Rodl&F_iddhOVuEskcVOPQka>xF~;UstW&I=Qrfq zEdivhmtf99+s?@`IHowWzsryoq|cS-hw%7wfIgq_FwTc#{h49ejL^+GMl2Qr%`$_7s)Zx$?sW;+X} zuA}~pf3#nlL~Pm;kcRMDnoq%Nvlz(bhHtI9SZm4k{GA*1IY6He`mxT3V}0_nnz`0| zey_}RMR)F1RpyZ|UB@(tu4=s=1XlZ|Jevg`nr^mK*_$Hfw7<$d*X{n$3wCNHWrHqb zC~4}!pZ9`u1z7~I-#U=RugC z($w`vF3Q?v4{#OWC^K~nx_<4yW?=rX1Y_|l{)+p>e*fXXynHXdeha`a?ps&C4X}RV zzupY6fJe}*tB34rW|Q&P-zliE>JJ9~?2rEQ`g;L?ntvj|{xr)Nl40AvR%_7v97)j@ zzis*)=l8a73%m_|3(->L%;%YA&UoAWZ|QCIPZj8)hT0rxq(9re>-7QANuT%G650Pe z*LO*W_b%)Wh?!K{{0cZmtT5A8{O-k^pDggC6S_~zGtK_6s^MFvE+0Psy9Nl)+V9Kv z;LpXk{S}Pkm(|+n0UNUw7It1IKbjn!Vf8ulhp&HGKkfg;%XfeOA6|a^_Sa6YKghSV zjW3*YwgoAzj`eo{#46z3i~scog7}v9UbZ(5RIsk>!t{&(P%uj)`*$(~QV#19O+(Z- zu*<2W^AuzQv|E17v^FNb{NyAmsFtu^CY9HT_yM9tx%ngtuAD<%Iw=2G%%b$vZA$Uy ztQ(zvJ;17>DXZ05`0!j^mx=MLzOeK8+j$E`tCG%7-DoQXUl=X#dk8sS7tW(M zRb=zUsmJ6G`j&rsZbN{5GRxh^Me7%j`Gwz>G_^7qy0l_HlW*MyEc$u1P63-=0CK{T zhnMybd9d`q+ouk8=Fx0>Gi#^h)S7(uM^D%55~#uz7`Q^NQ}=;S5k918(*&r)x;$u| zoSKEXXGud_tBOAV6rC%d`!M%!NCP&t4$u-zOTD$6AH8PXy&Aai=G3LrMUcO>S1y_t zYj}W_k{@H8#FO878i`PT=Qn|U7GYf0Oyxx0KKZR+bS?rff$KK_5ZIJDSp-OB+l|A( z=O8M3;Y>gkxOsC>w8fh@QE}4&-RV+;FJi4q`z5?7bs0B;lwo-xuV%cccV55JUmP@+ z)rs};;M>$9AMPw{C?vv+9dV@|W^KA!YXo{RpUEbxxO?;zQL z_jJ_Ro6`6mvo2r!URbyqeaZbZG#ilJm%5!j^||`TZ~m@+t^XH((f`BOe^bA__FWTw z>+8Y`c`LY87IRrB{C4pMJw(=Lw^HLlUM&PdCBs#zTRG==$0>})%fWwq(a zpZlNpugT$1L(Az?tHhYQ4;TI>xB~BcaOSz0U$8l=SqvbXg^t7IDWhqd!0;=PI0`qnBE5i`t>t`x^NT+KrZ4!;<&; zsMLk^JkZ%_QQtIOIL^=LTma8p`PNFG9xIO1Pk5H0cE>Nkb}wh&ZZwnSC*S9HrPjwm z^|_lV?Ki%1b8%+MZS5!>DX6t zKyAY(*S!ayT%Xkd0~6-yoPg46K7aerEkLJh=2vwmXUsG?((m?h=Dx3v!@HZa%6@m3UMeql8Sv05QJm`~tZth)tfwCT+oCts!4d)!9 ztE82D{}#Z?j;mgjqmvio;rc~3e7!kPZGpO0xb;(f@zzYdFmLNO57rpw`w&ZgBL|4iVI>alFSGf>|+{w=529i%BRR3Gki;PGl|O6@A|IZphD5 ze49Ob;!YB|wsNu_K7J{D#3C#X{^)_!EOGRvRN>hiJpa)6Bs&{_lE51z^aYcDEXvaY z`K0GBHK6$4xpQ0RA;5P?cUI5n>XM2s0bH$myaDMYZpYQ0eW)-h| zaEC$X>2o_@e@vU7OV^mzzn_yx2av82nt23`uyi?(8xuruxf z1_mtJ;F4?1iYubHPV?b+WpCq-#w{&SW-<59nxbJHz3FwIwPwdopjR{A=B z530<~ih#ANe2l-J{|%i1nqLC!ckbW1=|vOv=kbmjt$NRzE!seZp*}6#Q+M*fOx}4+ z%?EsA&zTgn*dH-x#s1d~TGew7IGtBwXe(sC?sINHl;Wr^uINBywW!P9u91g7apqTo z+SKW}AT)@?&O7m*6^Cb{Y-eZV~ci`0h<;k4z=l-|$6+Fy2I+&lB7NgwH zPin%mPTe_6Vd{?n1_^1L$Ep-SB3@fymGHu^N3hc{ep zw8r%sBm{|?d|HGkL3BezM6@KL*F>U59o;ZQ5YZAfMj6pX@7?Hv(OaU8KKfvk8Pl$N z*SdefIcvY`oW0*?@8`FLpt4h6?k7kAFWTh_E}KrTbYg7_fDit%&hZ1^zujQ1W|EtX zbq&#c=}y=jh?I+9n6e^q*=@;&h4xVD;^yUl6<%*kC{3ni*V9Ej8ooU6t=X18kFVr& z!0MADIUksL^)p5@84v5a5rnDN&5W1J58$HN?G6+Fr6FE5zvN>C?YK@yzFt8};#Zr5 zmGT`Pw3~T}^x?xbirl&$1BLfCzh;m)mhNR~Gx9IzoHyM4A$kL|&60CH6spkEQq21$ zO7+k#fEJT~cWN2+Iec8w^T{)zU%G~_M{bKGs{by&jDPwobg+L1)W1@^ zbVFU`5|weZJ5TdwP!KENnf_YN8!n2?Y3f#H`$_}_!jgJgs*i`SfVDOSRZr*pOR>D^ zZ7WvRG8smZg_%6Cf>|tUbX8gsr;l07Jmj@{S`L;mB+wX&Y#-2R`COFVJ8!$KPSt6@ zHhjxr#1y^;j}J?obd zVW?7Z;Q{*d*xfQ=dk?KEe$)~t5JPrSeSjukCub=6toQz^>eII1197FDHw&NC?E+UG zJnuSuxMo!tvjrz8Cn%Uj)&T-$3nSRw=@;7|qK8pKhCn*9y6q=j!cB+0IHpO5!pRw6xj5RL9(wBarnycitasg+lbB(L%m`#s6)O4vMYRa<)-4kMq$p)b)Gg`YpO??L68P;`t~v z;MK@1NKZ|b)3q@NYGwEOkx^jk47c^Si2q&@*uqHfLZUY`B3(q(;)ctUJv_}Tae;L#lh*hM#&~aMLfne< z3}(C8WQHC?+?gPn7*Jf1E|{P84-$hVBIZ@iH(bfuM=nlmJiL8gV-90vvH5;`%%l4{ zw~S@oQW?#r{PKfcAZk|;9>mpif+m|XW-c>*#-hmu&hRNyRNa9_#tj|qm&4YXv3@~_ z_(Qh#ePFB>D>~u2a3nXhI-+(gCV$S35s&Ctgl#d%2cq@x_}4XQ`uNlsB7CTc?CU!b z_ku$MK9IMam~g*hXlbs{}mE7XDTwk{Fsevz`=GIkK=;_7h1?Agph?61q0XG^FSMIk| zQ_=kLmK0`0KXsX_37w(u6+f8*dSpflOjyi)y3#OjC!A5(})6KD% z12?#0zy7c3tuC*Y7=8o*GBw#6Y*63cHMlOWWPL~0k;%HgnzNbxO7UIi6gjlD2_i3( z2UnT?4C>t>QvJIEGp=0zQ;SvPrTqi93#$Ij{l4q>L%-VYjPXc8eG3Jv)idp+NelT%H5hHUSE%uR zM=Fbth0tWrV_mkCpZMrXz z$31{cmVg=Gw|9TXb4giDoxOaGtb!&C1sOt0IhNS1P5Hm?MX<~@N|@DbYJ0QEMSWH< zu(~1_yuM)uPA>MkrcWtTMZY2H?mFx4sm?)jSTTI z5@sHB*)JC=$eUqjXXwV$9IafZsfZ8-0~YL$BXR@leaAc1ja00!dG$_HJ{s3D6#>Q` zR;8ZFjlA@r_Ib++GX-5p*0@zs%N9t$HN@isL($j~sUL|i{M~Z)ft0CXMhk!Z-7nf_ zB*v{y@?z3%U0Id)rM9bmIDfigs5ifc8;vgM^{!M?V`|EKSO!H_cy=h>d%yeAM0Gz7 zHyQ`8cIiLIa(51t%|PUE-=78D@jNn=qN$e&6lPJY5ig+2YJF%}deJ)_m5LsWKdZeO z@Llie+MN@U@@;cWViQ3uIO=1A9=H*_DN6O`UgQpCse!4wMuab4xrFz;kYC77m~K~y zB2Vfx5z@3JJp4#Ew5n)-f%LJa0zOi3NUP^?MtSws{ULT^qS?M@^nUSOTPnBq4OsqU zXGz2RV_k;(*l7Nh`rh>WcX5y)95z-<_TrO=i*?F8e$l(;v8L|LLhC$n-n)O0&CwlnMxyo42>@r=WvWdDRtG!^xATv9% zVdI$kpeCEsr@(bRHXW?@!FSlz8s%X9wc-j#Zps2qt$f6NT zpK>t16ALj)mX-2W+*$G5+h(zG=m4|jcJ*IU?c5F}(T5mw-g9iLA7xbqGpgs#YT|o7 z@DG&IUU6A})^#|Z#}Ck#wUEcGSzSC}>pXl>)miuFo^Bm7S9@H@;L*|Hw;=wq`$OEZ z%y>7vlSjSchDnKu>)fcp*9KaLxr6c00~o`ioa_W5SOkzOfEDd-~jw zKNT78prb%F@;**2SC{7w%K(b{NI822;|N4y81vO3aqaKpx8_!RM?Y*fKP*#v{&U3f ze?Nq0^1pUCA{X|OJyLZP4k%v9wW=HYfL&hyNtyvQHtFW}-Q!h#0=GVth&D05Pc(aedP%lc;uwNwuY%U&Yk2Y|FM$ zo<_f=+olk(jX~gNKzR-LP2(Jm%3+iR&;wn(g1blu)8RiuHRPzGf(f5p7EsuM+Hb)KsnTRrg#~J6TQS!eDBp*l>1AdJ zJGyk+n`|h2eRMbSx3mPrC^75cxg=|c@IWY4hVd_sV9gTj4Nu3|=!5_a+X8oqpv?Pa zGrNjz+nB=isq4DOuDc;Se)`MppQhu9<_t@!H@{|sn&^s8oKr6LX{JC6$KS8r&c!w? zW!{dGQj4E9;(kU3LQkq#hTq(v*LNrL8c)0HA?LAe`c3htW!l~B;E##$?(&@&dB?Ww z!Cd(T~e(e@a?uMc8G3zsQ_d_oU zZr7-uzNI1{*m0US z%=uo$gH0Y~zB(s&FyBXETPb>%k_iOi@grlVD zY9+T&LBAA{DWM(>*{S*RArl|QoZ~a_r|0yp5*Qf~C_dL#^Ve&wjXRk79V*H4xm?@K z1+GU~mGE~k2~T#{UoClF9h3X!BITaQzX>Qzf7?F7mMZGixDf9Pf5Vd$rs#zJ>$xB!Jmt{aXvh5KO4kHs&EHGuQ%zD2oMk>VUmZ)=P*i|kWZoYo zJ7*`kG>1mm^-)-DxOH4vrNcL3!9&ea>S0q^t}Fca;wJDq3ix>2FE#uENYxL*mJp_n zIW9^CQ|UBHXY1V?`0x9~oZTH-Cf;$`KfL_yQG$sHr*jY2pN!FBx0%Uh|236g^e$x^ zf=l3{JOQ&mn+9EI2i!*yMhSm3o1Uz%im4f;Se4k#{bL)yKS*{|j!A`L+6eyR%G#~w z_4m@Uao4Ew@>f#_7V6pd8#i8wLs`_ z?z3j~?23)PYnJtTIkVufZ#O&UI&MUbiGX%;cD487NRyS3XXLVa30{@nP}vvbNU{wQs9!#zNbQ@*5bjEUOul0#u&>UI?>o;E- zdM{eiO8Jf8qvAW!RUbRxhWaMD&X2aOCcRX3 zdgduBC%6IqYK-J#=TcpAA{J=kM|_zy$VbdzvC;Z>&&+?4ZM#JiNZ$c%7ECSt6GKGv zD!jK}HD#16?`)OX-NAq_;eq(oW$5n-HFQ_BtlKP?Ny3=!zJWjcp2g3KXvWxUOyAD$ zI7I8MSHy=8OJ>)_d_tNZ)=dbcxdq8*&n`!M7#ts>CfI-JRJ?yvVN7wzX>e{s--!H3 z)%V)t$@jC0G%xBx!+n;)pp`hsJ76j)%^L?>Z$^a2p8H4GZl11s47pCg>wZUSjT>ft zlW+aZXUF+rV@FP$2RWh*i{$K<>?u~+D=e$WU6IKJecUlcTfxY?GAUv|tqf>vuS>=q zU;HNqh8NayVxOWdDH%;>`;jf)ywm;WKX3jdsW_f}Xb_eNHm{hf;-+y`m6@kb$aA}m zv5P^Hr7A0qZ+|5HX;`Lu7+eRwcrZ2@$~5u5_ua~mg(x9#w9z5lwEQ+M^DI!ZB-6d8 zP>asgZ~KX@#-rU)Le)Vtjr?Q3HBTF{z}@A&1ae{9r34v6)W4n<$$o^-q}VkJVddMA zZ+!L_45S;$*isIRq1J>U*@e&5K80Ba+zwdfH#_%Yc%-wMUf7tet+A>KH>ba#FipDo zXZaA^6_y!fQx2g0lLh2BLo9$@U8^}t7TE~frdC9}Xh%u?kVb0Hxfr=_4|k(|>53OSRckcAtemHstR$g#L(TW# z(5c6CH)6%Qw#7=eS~dkcS+BLZ@Y<;P!b`RXK`g*GbO~65Z)ksb!eQXxS2Z!RnmBQ@ z`3;ue^0GBE4wcx{w>IfO((wY9*)3q9)MX+fh>aOWoldD;YjIumAcx!arF^Y_3p1US zoaKm3c2-lk^5QIp_FW7-4^3}?m0^qI5*530wiXY0&`SxCq5tURRp|q=B5-e4LGOZA zL|+ka6b>pOmwc#ekDoH`<7oaj?z0=4@*&J&0H1^ZUd?@PJq!J;#o}rwKT5W4x$4^~ z$Sp$3b0oVzS8HY64h}O8lC)hfI$uq9PXwGrvacbXt&| zR(xnrW^QW@kAb+(dK-BgA&db_i0LHb*J`biYn-k+ZirhRx6Gi|FoFs!)Z!x6&wLmf zsX)12d5~4N#K?8hq3>lFH|~2s>{c(U_MZPxmN2)hZ`Y_l_`XHoA( zi!enkJWds`0PlJ6$6n;E+SM5JUd&sAIv<@-@0UtYhxi|6-gCU1 zu91@X8PlB*kEbssmSpr#f(j)M9~o|KZ4$;!tlqj(97To+wNd$JuAZXO~pl(Z2t%cLE;nvrL zr<&380Fhx*;EpsIN{+&-4as#f#(jS) zUg0;CUTFk8FYnSbzSllxtRT7-R&UIze}7RPO~GF=e#v>6(vUDxX5W$ll|G;hPQk2M$L!w zub)IO=_c1!NEyLaJiGyQ)&&exy+r{45P4CeHhuBi9IeN(UKI63>oXg~dBSp|Z2!mu zZ+{P3E3yxyMfw4U%H?3ruVG}vyI+8xfwm|>X<;v;<9VhyOg8wjiq}(uTXQW{|3Q}_5uK~1EJBa> zI}_i?#WuHR5MHG`nI8-3MqJ^ml9Bx6%{7K88d)XO<~!KkQx&9cR!mTf_Q6SIf0Fwc zPQxlf4QOSre;uVtK}qLOG^ax@47@H$>{e;W-~Hs!<}%kw z`uy4W$V6LSk;%I}~Z zd>%yp&4YZj1X5LVoe&KoZV`Qd{@NY6>qt1}DqeBk*t5k=YhK^9OQ_&1P9b8XQ2q(h z0?g4|uU;yY!}h~)65_dWFZFcIvC>Q@=C=?6I6Ut>d^ICXev}L4Hved0T4&Wz3iIVp z-N=yi5BKOB+nh zo!hhsF(kQRDwk9pCSMi4W++O7I-C3mmkmD;c_qUmy|x++yz9b6Ve5`vWqKW&buQY- zt7kW6vELs^I++S`0v#KJQB{1h?{j9oP9kIi&o6e>l5v5sE(w9#`Zp#=H@LL0SqTFVt~DkT#7!S}XC#^d zH<9Aj3fcNu-|s590b2L@F`1nJ#)r1~diN?Nf&^s^h#Lx5Scx^p%l!BwV+AE>lcy4E zyocuXY<&uU`5O40V5-HCO%~By{CtC1-i@bf?(0x`QGz8^GkT($YJ~?gr|yxoYBFzq zG;)XPM*F@K(IJ^0i8zpqn#ZmxNQSxaqpM?GPJJg901^*$Dm-5%4=!^=L`%l)SjHLx zyh0defE`#y&Q6vZ&Yd1ip&MW;`CS-_|2}N|1&;W|n!RkG_Vm5uueagD{yZ^PL z^?5qqD0$A2hME2<%-)!hqg`e@WHRvuU0LBj_N{fBdroZ}LCs+NQ-{XJ{5o)UI9de# z5KaQY!D`2JM<_JE!NtVaK_=}WL+@`4$wnTR*$S>fQScAE44IS^$ov2F1wOE$(l=q zmlDX$;0i%vy!-ZY(aEi922`tbCv$J((K&{zgaon%2f7yuH?%#kS_f~JqHtQtcXx!c z3@psGc`&YnULG_L60jMOiYt&aqfi$8)UV(ZOCv($uF<)^wsuWJ&orNslhpWju`u+C zzVBzm_A(f3y8PXdL&x@P4M4&I!i)7Jm6LyV;u6U|2$Nz+W2LZ{62dZOc0LKl{n6R% z?Q#IjWtOn{0HfLd4j%t$ileOMryK*$U3uEB@}$>mkrUBMF?}yBBL%$QQ!20OQ@`v~ zjPnUSqt)X72QVDxdWBx`n69%hkzq!;+|u`X`+?@Hz3jAC>pBHMBJ-9`jHgS_#uK(# zXn3zOFuqy`Q>In7>_Q!EujIOhJ{y1WDEq5pjcA1jJyJ09=}WGf#);CPE6W;LG4F#&U#;qWPgR!rLRLtSG4-QUA1I=+au6cTw)vW0l%70`6*O}!}e!ch{AR7E5xLL z1(Tg9WpHkeF;B0q%r$@d0!UhCYzrA&CdiH37CT)PbvY(6vl=rQVaKka9Uw4I}9qL zQ+y(F0k?1OpRr61Z4yOB!^LfhpeyNPNjLQ$C|X??5*qw1eB=r~y$fT)u4lt;-t_cS z0kZ-o;I9)y3krJh=kA6E)xlwebh11$5*Ix)s4FQGvO>8m4^4W2G22@0xbTmG1ZUkS zCFCT9#yNy!XM3GuoN5;qScp$jkIEAG?(_qYRZA*Vz^?G|@jE8IE29^>M!AXjv69mn z%j6cVb8KwY`%$qwz})Bt16zK`8Nrog-RQgNv0-$Nsu49mK@$%i{U_)3R$IIg*!3|a zl=U_rZb&i*;kDXcoFT}cvB7Rg|J3fl5RWK#EQ?&5CPH>~hy=K9h0mowrg!3vE+R`%n~d+yf;J92&ZO3tPklVJ$gR2$ z0o-*+i7-TPo`2zQRo=LFF!D4FD3^b1reL`JFStRVxs{^HFS(TcOYND@ogs21hU19E zzg;rvR+#n-R?Li^b4S_DZs`tE&wQX~nMiSc*b`QL7uT(J7Okz5h{a15415&e5+{BKJyl$Kv1Ur1@CMV!n+OBa|3zvhKMvyaPU1}IuKMt^ zR9bs~2s!TrxP^WlF?~@{yfF4vvg|XnOil@dV2>dk=uiPZUB}g#tL>^fyG^Dzxf@Ax zzK`crt2=fedJ8G2xXgKUh@RoxL_1dBfiVU%?BU?4+gz%PXAe_xKm1A}c2FjF`vJ5G z3{_XB5#gjN$EyjWOhU$;`INfno#@}boPaXu9^2)<4%>Hl)8~-nAewf9#~jWE>*Lg%ROEHs;! zM&MbOQ5M*I_TPuwgv92Y9oc^lFZvwJm_nYbU9-K?4aA#%?| znOfj&_?iCM*G{bx%{%&VaN;89mX9$1p9Q0U<;i4oyaF;7H~X*s!?Q5bUiw*~=r_aa zi8e{a+}f$f4wWJEC-K?;k!l}z)BrpAs0sZK3Rj|09tc$AhH@{2WFwvz%6XDcuJ`eh z_@`$eqocBYef7* zdFW?7IRX_?VQ!4bdUivgi3>Q5OVOM(XJXr2Hez(Fj z4t!yTL##6%vu)@FCZ=Q-_$S&3hThnaDh}E_Kpn{d561a9$H}H2t4{K?fiq#gzPpJt z5~>4tD&txx+7mDYZV)DP5mtg*%t6L^KoEabeTzo+7yotTPkR zh(GhQ1){ft#^_g}w}12RUF{=~7# zHvyOn(YQiM9O^*!)^q&&AE77U_n0XCAI%@ES}VEcFfpm#tuc4))~sXi0UuadfxK&# zCYr_-;3LEee>3FRgUrwV&KG36#VIW6)Vr=2UCdO-tY7$#Tq+wh>3lzZS%ub=DhQE{ zjB_gR=6UVIrJc~TXB}B;vV=avN8KK?u%&!fiBxA(N^5BZpG~X~DWCObwJsIEZ*#ua z`*jpanwM}3gZu3MxKVwclC+)E6LeI1h~J8^t#H57QAIc(v^|>$u$+!a9_JZji!Io` zYv(l#OF+IDYc>txZ#pfT|AMIy`8LIqQ-wX)x02;z0VCe@>r4&eW71!;tw~J9AcD>~ zt!R}@ddfoXArqbe@5sa6oj|Yu?$DS18gebdpXB8@+@vf`kLs1iER!w7+u;qyTZ&1Z z_&IO#8Mie_p&)px6PLX)-CUhk?%5G|pJ-<(BfuNrY@zG=ER)EFGsNrklK8RyWVes7 zTB$|uBc*3rtaRu}H{&eudAn z(A$iI;un#3CkDr>zNdF}B1#XIL9+UzH%=`P&s;PyBGy2C1%<&iK>|GBQSfimhpGU_ z$yIoLPsStN^DK|$qAEmC@+acOZ;-1C)tcg*;0jH#i}m%{N61;tZ(1?)mw0s(iDcP( zE{1Q7`0A`03vb8t{)F1a{K0nm6IF@K)*DIiX#mX0?Wn?*;vdQ-zYDwOyL>1ULGS+d ztxJEI3C-gwifL{#n4qNpo_gP`hKIlEE+uF@ovY0nri|ZpE#wZ1@`*|wSF=0nW2ylKTCEr-AyU3* z)>nQSvKpxgxvK}=4}#fc6w1wmchAM)#Wu?;9Z8>B<#awp$cVP8^0%^*Oktt65EH&i zi=d*Gf+~9_JYrDg4q_Ba1^n&jtiN<984?ckgV7i=Emw#&6?lD_|F=osvIg5924Zqz z5PwIT&^54OsKvn<#8}{y3k41+o%wzncHP)Aq8P|N@J;4?I|%W9@dv62Wy9F`E07k4 z+Fz6j&+@P+HAAC+Ua^D(3}{L)VT2AJ2F&{2wr!>Qy+IpY6i_rS6k4F>xRUo`GWiy* zs>5po@6wYt%tR4a4E|BBz$reau`F5fzoQgutTMG8faK7vF^Xd4f@BN;R+i9UT$|a| z@{6$_IZiwz;r!~WlH9tm-lq3dG#4o>2>NjaY1TC7Y6k192@e}|n@W1QYo4ARqCdtG zxOad^WYm6&$+OJE5I-luwmCgL@ysnQSIa&I!yGDnR0(alhHeLIMBf*m*{sg=M&(F6k z<=2<3@mY)FH&)?MZK@VNp!8XPo_C-u6~+Fk`CHEmRjD`-2j|%jVk?6MF&T=g*Vq0Z zG>LPKJY;gx7s^_6ttHrKIN}IzQ;j+BS45fp`j&TbCY&rzQ2k zqZeW&z9gcr*G;^5Kl?1qrLlCgpbCu+^<2RZWy+Y`Ol7)X6~Mal$eLNZPiZwnOGtBy ztRm0q{4!y?c+iD2ut7w79D2!UyYO4OldviH4@<;$IHZ|``Q_^eIo^0a@V%v^bbdVM zI=B#@S7#obBWtf5E2ocl)poiX*a<^i>0~0km2G&mPoeMx zDCwH37t{Zq_+aLhS0*gikFK*Jl)cv#Y2an4erMQ=Da~U59GBXC(~XBVIylgWknoqO_s7Q63J5Stv!g=E7*SH z#bw$h&q59GyW3YNvU`EvzM0a}n<;`TJn~f&g&Dibb2ImID zHG>xggSWTwa$>=u2Oj;Gcz%fb*ao*}XI92X(o>2$4ibU$=IJ5Rd!;h0CkOCkdSmz_ z=`v@<5JO=*LI3*=_M8-sz@f6<8-^A2xOTFe6dKU~WpbbP-mX6y+B6^x>v#Fr zv^}JC;$^KFzRcPnZQz*jd3wh=*VZ&fZEI2%T2mJT6{yJq7m9uIT3z^0%5PbL&z1BJ9Uv({B|ijnJzb3E7V{ zBG$F9Qi@j!&r>BUMq?u#7=<2Xjg4Ckw@fj|n2}F8Eq@Q@c?1l8y-e$C>*NT5+M&uMMtik?VfVQuZ@C z$*E!dMh-5N!kvxU_a=92*~1V-9Yi#D%obvFWeSR&=_lLC7kF`=r#Jj$X#5hl8k@hN z_>tE*Q>VRw0!s${CM&T_Pdp)*NHJ5`&!@^D`5jLvd8}Z`j~4-Tc=de#3(aw|b{1dR zLIEk?4<=w%k^+!%pvi=4is(q>U!Xt@7j40@w%L)Ab_fsIP}$_<&T)ztn<03!de zG==ALQhU#egpoo&oTAnwiC=qUI=_vGT+WjjIU1PrdIf`v*ZAQ?o#tF|M_!RJxf8tM zKz^0p_)l!Y*`)aPDND%S=YYzm=SvljUYv0<`LS(CNy?dD_m>XHpC~ZPgq+fzrosgO zv&%Y0@A4{xPd?)&9f@DNI5|Jve1c?(-Ra@Mr9%n*sp+V&ws-+~rU$7$=l3=sqK|Wi*Jd`1k*kZLC$znx>lD(8oadMLhgA}PH(3|($FqV+LI{Y( zv#TOME@;2?dY&}3DtW8RD0n|9{UZ#j$T$;3+9S9OG)dH9c&8}!U21v8weMLr7_`YY z_`|?;{0REs$1GRbw7Q2zFh?FT{AJv_l02up#(rsf2=h&$Z z=--ZvC8~&8UebN^RN#E-mwTvB3Rh@f-w3jhQqmCch(bRC-rlXYnjrGRn~6x&rj1De1_A zDl+^3;S0!HL1{qD58F9^`un>t&GumeX> z(>Wn6Qj2Mx3ymvgP2^mPHGiAg6{}r5GGOx@7{IMka0b5*O*xBIyTuBrAU(Z#5CuEeFHMHb}>&PG>Zf z%gr%A0m3p#eo!s2WEu9BVqQqr&I%athA-5Ygnna%&#Ai zu6Otk8!Nef+nOauX->`>G(m82ITo!3;9X5T?Mu0BA!k)7%VLSlxn{)~GO8)lv}z}J z)gzI-|J5Nf968@HgRnZPeyj)Ylxw7055CGt5EpZ5YtG0SeUNY8t8I1*oFtHXR4LwV z^U9JgOrU2^O@o})!n{^=1NvU$sh5thYFKFj4EKr$Q-B?n5|U z9c)_3-ob4HMsqszcC82^9H!}LS-$;@WxX&}(j;KSwz}6a!`w|oUV+3*b>Ly<`d`84 zt}B>*Rrb&RV47eu6F6mG`i#@pX^XcVA{ydXJyl1rO~xXDy_U@xEbVBv(Q!9H{gG0G zwMr}b>DWvYa#-1cY*9dx4^d zb(Ksy!do2xd>Z$W?=1CsayI*hJ=o{go!CqcgHZi$Ts)B^a3q;(rH3xb!sO_*{f&7!2q^-$+Uum?yeRs^C4d zk&vwWH>3i4x7U@8bhzLyF0;Isa&pf1oJ05E3noIEhWSGKLm zGW9f4@F7{Q2x5Yr)TpH%K@Dm0cuWC5l|vTt zYwQ<<2{*eIt&(Q4Td!a9zi&9&7eJ-0o|Cp5xcx*{T!V3pT3utv*ON|6O3^^u;h#;X z{30G~hHdZ7%2a_r-v~#Bgnetv>8C*JWt0wvT75P zP@aIsmk((DK*d~6U80|Ycob4T`Vvhqwb9iiYJR(eqicD!3X5OvME-957?6@))R3y1 zZR1u3vV&|SPPe-aiT8RPMIin*$wELa-%e@(tv%0fb6TV6DcCM577^g?Wo~_OUx$Y5 zg1y%AhI?5?=&YAa%pDD+HQWBej|v+&-9dxUbeF8RS0&`bo7@1!o)OlrXfcpW`q5_Y z?U@lboE;pz3yD?tB!2!+*Z`ce-5nXx>d|x4r4msAK?I(n&g41ZRUsBJV)1H=pOUnz z&Pk3$_i%KZ(G|339Q76pZdU7U-1&zZ%i<-3?he`Y99A|Y^MhQJ*Z+~)txqk*vV2G? z|M=lZxP+9uP z_v&O6pR(rOx@~d5urifQxV^bDOY(6oRWE6mQf?t?j5@Nm{9c=*)EQ|~i>%_>Nfw1L z2vp;5O;(~(MlSFbwh(9^@9uvP;*=}lq_dN3U^}}p7N#%r)Tf3k;bKf*T$iA2 zy580`ZKkXOh!|oE3f5B@$BF)66G_DI1wD0TmW?L`d_jE;J2*w zqbB%S`e*qq2TvuLeHP)Z6zjTSfT#p&59=`29!asvOFe@-aJYZ^*fU))gIPN zWGhOoFZ4#;J|3zR_CLufz+8RNY(3l)#zqAh&OYdK@9gK2C(ecjMP9`kqK*nJGnhKYh-1ubE)|VApoD$qWSOuaN$HszsG~A zU#fS)xAU(;3x3s~dT-lVqTg;Cu-@=P(%yM=L4~Y!!G0oEh~+vwzCYi01Qg;v#&8OT zH?PP@74Cv}p9F%Q#+R_DlqY#C3uz4ezQi2GrdEFOWoS~Ik|UEUZ&{^V@!Bpwoi<#6 zXls=(xx6~$)a-CfeTG^Kka)Kwe6=pY|ML9F9d8VXJT7t+Lz{iAoq9S=aq9A^`0eYI z3xB@m&9B{xz5Z4?XqNVVcLfTKLbGHM(5Sqa8!~q&0Xo%FG>*#YCxW+PBcs_7v?@=W zGrO%IJ=ZG*(}iwA)h3tUAa(puC)EE`X$Ag{RpLr;sDmbYDgr+xoHCn?N1**_ss~P8(~1?SF4QgnS4}ZCC|ate z-IHJ4DLRf-V9G?4jm$v1|TQ$Ist*ToIMwmt#ci=w0m5 zMOTRMKy2k^|HWsp@BfU>Ug~#bR(BvH&f(W>6?dHS&HWIPihlNgn^xWwVsqrQEkvWBUP%ht(xLfE;tqlt9 zpfMwQwgRe0iogS^MZwg13|1&ZgSq3mg1Zzo0K8|=%53s9)Y8WN{ zS`I?oI!lPuW@`)bKD9~T^Nj7h>EL#-J<bokiAoSBd76i6?K<| zNsyAJ*(h7iCGf<`X`!b~sm=FV0?F)~1>k4fAu1?C?w~(ceVuYYcFiZghwNM70S=!! zeXIH^0(Yqg6Kv%)RM;St7YTBVD&@bx2Z`{)QamG2)Bt?#P=;) znDXPUbS=ZITg@wya;YoG<&pDk!>U7o)<#X$LLos~K-3d}66wl1@_*cN>#JKR>SWvh za7y3>;%D6k)s9_w)g$=!x>enls`1s}WgAU^m>R%?n2}Yx+Q!{8Yz#Bj2xgNE-9kX1 zK|Lt4Xgx+u+?gT1%!C2}fE6Q1_;J!XcoQIDh@Qr^2uyv9*)7S4@}tYGc#T|VeA_2w ztOi!!>%)k5BE0u1sHsQYVIXxgb#{^yOj`+Z>Ir{FYbqFarPHtro=u z8{i#)B8(7@;}dOiV= z+s$;Lnv7|8ou9lS;i?d>@BG0MOy7GA`fA~V{C5}EON-FG{CX(=SI8$OSz;Ms&wsOo zUH&Eiwt=NV$PCTbT+FU+;vASaBI7yk?6cJqCYH^+nWC^M?+5mgoCkli`@4+P*+wGV zaPUuO!u*r7pf|Kie{&-Kschc!`@%9R;7KLa3;0}RLkLYsR^Dle`N*Ddei>W!Y7{te zJ2BAz$-9YUF};90-qgTS-|ogaa_dvZjqz5&3)cyC9zJ zS3_!>c9U;QST__5^Qs9K6q3YP{uM3<@#XAYp-ueFjNaRr*?lfMZdGQb;rg_Vj?H$1 zAnCNU1)Q|_vXlEEH1=~m1JjqF9<=zAyU7iv`@jiiZy|? zW^xLzsiu*|kzSsAknyhZ@n5%uszE_s6fiE(XYDmV=;D4VW6cjkx--{gVI zNsGEN{lj~j?5`3~Oy7e$T&e#4cxPhzh2BE9lNk-&>8zL+TtiZt?nn~fkd1i%5$eQr zTeo!tI=LmwXaXg`n4+%Ol_@dF%Z|ljleJ20e*6heNPV%z#rs4?_wre6wC$+4-S9X5 zv(q6l-ox463>B$+gePUxM7K;p=doJ0hXEvPp8)f-Y;lT^2dEOQ)I0n#c=wUYM<<(- zTM?vzBNd}+z%_`5ptRXEw01J~Qg?OA_(+a1AhjgMzB4(oa!>MVeTQw>ZAGx*P2%-q zBTTWwO~0j-XtG;mtx(fM@^K~)HZS3-H=BNv#u?|X9LE*037bF3#X6Q9H5W37RDL7NYK@R(#hbu4UP(j9L+rDSw=y75E}NMd|pWv|&bXvE{gH!O3k|G*xPS;s_Uv;q;7KJwoOzVvs-0l7!O7e64?uY3y&qhrv~y~I_jnT^%e11JvPrKvS% zORv1JoW``Y@*MVOm*orq95r(gQZW82JR?ui+=vOYKnD|dBh__MlcD#fNd~j@S6=v^ zGnhB5`Tefu0!FC$<9oIU0F~X7K)Pz|P}jtMZvm?&SBF~Y`v%whALw&Om$$RdTxdE* z@L|zD!&SkAxk`Zk9ywY+Z`M5enQ*kd+r;e10N42N4h6_HBltj$Uiwf&Mrj@9Kf&A- zTy*xjn3d!Ye+vIA`+J_bnv;>wZX3|?Wrr&bV2uBz+f4A+&qn4j?xm}oITk+iikt9A z6Rh}2`&Mo8U*GYyz=0jzaPB6hIWF(tE!Y1Sd}%Li9RIrfL)V=Jp3~nK0$;n;Ec~9z z5pd&l7D$g{oAO`2%fs{H877o7JUR5R;q-z)w=qpqAVgnjFFscNcVXpI8{_wo-JRY- z!oa6C7T0|&@Z=JngaF|y56`=$#-3Y0`Tb}4MO#b+*zH+B>_=Y`a4hG9AqT`Dm9jhe z)BeEV`u(ambk*MnzL%X~-!DLMcebhHqiL8#NJK;V#a0d1bzPhkB;}<5j+Kt{U}Mq0 z+S4CCoDy(}dhqTM|NZmFZp!1gY`^#Qe$zv3cFy6`oA&5n;S2bMZ63OCZL`DjC&_NE zBY?hk(p<@Je}m6OjV}QSApdRuv&iXV4gzD--Vpn9wVrwdR~;YA3~P%I#`B9jhh0`z z`4$%6$Q$e2TxeP=I1$j*>?`on0S*>1QPAD@Phzol!S(wECmCxD(6haDSKtt= zAr8E8SyY9R}!3ArAIFNdP(qdlW<~Vfc6%P`h`Aol&Zz$BMFVOS&;=$u7|YE?j0Jny5i(x<`M}lu z@RX;Y>iEH}#&N_U$NVIm z*JWW89s+pJIGBwC6?JEuIzIgjs{xw7*nk%{u~U~w8fFFoz{rZL(-ibOul@!X(6|z4 zU17yR%kxVx2dqOhD2`PMKE7jNhAjSSE2oqEwalqJ@9)Ni9as954x@|*IP+`|afYOs zbeLu9;gAP+z`h?&G){JB`FDQ@fCe{zu4^FjV~u$=Q8OOcUlzDn*W3T#@5@b1Wgbyn zpW;y8huFaj+qw1wk%3Pcy8~3uqUDiJrf2!DZ>9!1ts4Qq->Is6{Z{}?ndA>0ogMrL z@LjCtyFM_d;HR(6SFY>wg8_ziB`Is;%=r(T*8pe{DF z$4SzSPCc%BS4X?j`Z>x$`YBF=x@zIu%=NXuB|bRLb4?vc+bcQPKgSX&r@sfK;K=F# zb)Mjq&RqkPyYKh;{s_~o^}2@ts`EWS$G-P}(RLZuU?;wZH-2>~KqMaf*ZT>A{`zus z(0MgzEtMqj`F`+)>7)Ehv&-~_Zs@<^c$iTN@y-9o_XFI6kgNTinya!sNegbb<^S#kyu*-<^K8eyR#zDByw#TpmO{3H)7X!^49ukc0`sx;YFEX z-*0L^^gm|#;)tu`UK3cW`B&p$$I!F+>mS$|T0Y>;cdmUfW3T;RI~VNN&HSuk`G4S3 z_ncCLh(Cbq`Fd{Q;H2m|BaN&%!LJ|8>Y4mJhQs0bktSH(A@rW;^$&2QkC=jRgymf0 ztIrga+iwG3_Ujltg(VjMg*PM(*S|6T_XVhTV6O6AH0QnN*6jT9m45H<(O>g~ehKWG zk3`QU$*m0$e{}_TpB6Ci4LCYi_Ji}@-*|9ik@h|bn)BYXanfQJ`*W$TLkoNwwe|w- zyf`BuESR_6dk%26Q{1@>JTiMnOqlBs7iZn~03o8WxXIfOe*LQvVv%c~Z@Wy}fh1UVs9BZAj z@78vr=Il4C^qFxI?lTuS&+co+bn$6q47r1Oit(6t3&OoQir;*2W3N(zf7;)@iqvy5 zPq$qELt9$rTlCDb;}4!UL02&JY-d(MkqbD00)SSy4t z?ba24-|1@N%6+A;%_V%p6s=S^PvT&iVR3Mx>pWa)hw6E+_7n7*iK~9}NVwnG?i)Sf znq$9fNr3ZM*8l;J>9n&3k0*`zHslSeOL+$P2Mi_4hO@pTCg}a$0qwE4%7bf;wOpKQ zg4R}=U2s*mKf-($!fc-b{JdW{ZH!s5t~@^TZbnUXJmhgdZ-&WSO9}s<_O~8=CSVuk zNxQv*an=`L&NbR#0(0&1C*b|qQ(PTz+Xi z&_mQPD!Jhp9@$Gy0h$GSQ&FbaILWZULW9XbTNm~be_W^06{PrIn#{XeFI|N?=&Y~Y ze3;jPikna{=K@VUb!(|qvk9sL9V`CMcp$3@Ul_H~F)tj&U}SZuZ=;jmnUsfvE*yVX zgLhpPJ!vq2{5}D}S^dG#NA@}hD~Vs2=DpvhXEkN6HwMj}No}GJ*1JwlX*A`mui5Hc zT9X$}r)O2X`X4pbeP}vC^S?CF3-gE10@r+_56}CErJi#(KLv4|o6G(VaPrJ1ZlLFV zro7N8plPkrWj6S4j_~w&&w?g)wTjca=)5)6)3bjqK(00MvAxgaIG64Qrz%;e#?k!D zsp^$iDVX>E0#Y+Sq8ER1N$>YZUA?X&U=AFG^uTWJRa5@+M9lmE&}w^ehvV;6NrsWl zY2LnHaO}7F;gGWUrN(GQFt3!S`!XBfZvyel~s+uui58}(7Yx$GP0_RG;s zI$*)c{&`eGGoYll&krAf@c6Ph-FM$FIFCL4=7&Shjx?ebidC7xSaITjaeZ>Dh0Y7t zY5RZ7!hBd^Iqatx-!_0NH~kgwJDD_B<_cwXT-HqE>~2mT=o|1=4z zHT@t5rmDm66~B8>?>WH9@-DLKx$WaD-y{(ZP9X=5;_feK_wAZWdoF>=4$;^En#a65 zs4&C-r}w+~r70J^zxFp=^UXnrcT$e$@UDdsR)@L+_Ds#WxmLG)=K`SK_Pzhz=tEQ5 z^VxZrAqn0gEg!IWgEdTc9K{^;u=`yUhQ`dVm~!imX8i>Kb+}NcrBWj4AlL()N^ba- zgyU4ioSOtSdVK1BXd(}vxecA`{b=CV{-H^K`1{C1?1uxldN?1tJL6#N%Ql|JRc;Fa z9u8$@de1}N8XG)1_M~4mLQw3*{^Zv}_?T0e<;$NBGpdGWwJ(qmuM+{@Ox4u{`jhwt z0Wp7q_Z-aAvm$SM2}}mUxSmaM4*L_^imy|=lPG>L7jyz<1-~)?yDo$N;sdd5(D>K;bxrdqp7XXC{Q#{1&SU*% z3P%8c+r!_)!(#wAsw{jQp7XNkkSsa7D{u;gz~1{`90d^4$Fr$d&YSNsf@LJEDK9;A zy7t%p7nUHs_Hiap3qhC{O=@f5qi51w?6|-KKo7X$pYxRqX!*g|%*D^|^;Y6k?Wa%b z&KFUdJO01rmpE@F5qxR-lpZrvTD#!Qtn=6Y{rxRijq6@<|WmZ{XTPl z?BDY=k6ByuHU9ZNhqU?3|KBuCC?0*)>*pY@0)BA&{vpBV-E7e$*$v)$sln@?3Fy>X zX8n&|v=D}QnNvA*y>!kWt!z3mg6;*^YRI(g;H8wdX41j+}zgxYsJ3F|1BV?GJ^O-c@& zLc^1{$Xv{0DjHbR0uUZ7dd`uAQt=sFBKMBVKP3w@Z)3l5JV3Xx z411v&>piE&zSpl`FmS3NIPsK*Zzy_GyYedbV8WSjaA46>&Gmqk_klz_7OsXdU%9F? zuTtc#r(m4s8>2iQC34_yoCJJp_5f4AI31|(2pKMCKIY499H4EA^WcOxWdy8uOhS7MyA63x07l z9~+33z&RMO;?;?NfWFVw0?HIlrRA&U0iK>qO>5TY+J<27c6nEm+`E~nt6b`|qS06qZ6Lwx6{W2x(pU-aqysSEGj z0BzzZ(T}v^g^tsEkzc)@-^qJ!@X~JIakQB;^aB)lK5veAKItpY#ZO+C-pib5+E+b} z_f3G_Lgh?S`Ja;-{lQu94URzCT;Ip?!*RR=JVJ1t89jJdx6oBUYOB(Yj8ErS2g82CMlW#@8_12=W`naA1SOe%0(b81(5vm5oh!4cja>6ZZu54nU2Ch*fEPg}VOwnNisXo(UvV`Y-%zuA90u z@MgTz_6+{re%E`=W4<^GI0ERt>!wHizs>p9lrsE(^?qlR`yPR`cV6?U&(|!km5$B_ zUpNWut`qkDE~hTP2WXCKxtec%^0JzF&R@SiRQo4gb9K!T?yvn1;MCV2huM@ff9%gJ z(Ph^2z+(LJ*$+x%R$n|9bUmkM*(02MBO^>j+#k3}^Xhg=+&(_H}w@ z=CM}e{^Dnb9eLuvel4`-`mcFBi~26$46*G?|GmGFFTKM)@5;{vv#Mrz#NF}_{sE#^ zcJQG)$@lkILmC`>#qXLDU3U+(5GbCoJ%^zF zC_g^@)|3n})_ql&qntkC>SH|>Bsga|iBI;)!&e?Y7{?NvW4ip8jvE>g{tj@GrbolG zy!c(W_6MIGWSeg2T+UBH^Xe$SNA(1<@LLnztwEjyIHyWrHOIl<_ew%~cIUD-Ky3QZ z#cIrUrlalk!1>m=l51};VdQUqkC`Uf?Z&|Z! zFb?s_?i))JUH0$xo-dpq99SnG}e`$t}| zYd$A(851se-XEN1VwRoT4hR7rfBBWOn;0#um|K@_YsVMXn2BW z!%h3$pE?$KY59#Pj8)C~vHN}yz!77^Q`z$=U;6{oI;!iu`|cY~eKCWB3+Jk-s5eoO z(}5dKp>lH3uodQi{Ezwz0Fz*G5z**@w?0hs)8J@X@Lbgxjxeh=fno;Qd?ZXq6x)2^ zCSPsLl#Vp@d21ek?{kHZyzubZU%=LB-y*L8&@yi>=GZ-zGtuL3@S}^s*si_(OAF2< z-LHqC=PSotDcdNg&qCLka{Ci5Zt^PWqnY&atkNk?xq~=-J1N+RJV!k1jGxrzsLNhQ z0s=!EH`0bNlLAA7Ym92wyPzq~3%Iz-Z+m!EleP}2pZA-Bavm!nu;yLC!C5eu-z)?C z`F^U;v6LH~__`-gtLx23hR^;#?;d51VTSgWx%t4R7(8e zqsjLNR(WZ9ZzXZkX!}RN?b8>R(b@@u@6TZqi z%b;&6tDFKzv@c7bs3<*7pDU23pZ!e;j8c0>0MMeZpnusYVU7x^uWe0 zZepeMF<*W#*hxKeDwwl#Ha5N34^838;mht35b$V3a_124Jq!K8qQ$z7(QJMQ@VD7u z-urhA-}JeJjg+nTo21`01?mF#{30}8F??e)i*w`aT)q+#(Ag#@bV@mT2G=l`$#>z< zR+EzK*Zl6KOJ_jZ-R}zVR8Cnr&6M1}e`1%z2h%;<7sc-^XTZXnuXv8%O1&mI#^