diff --git a/android/fastlane/metadata/android/de-DE/changelogs/50.txt b/android/fastlane/metadata/android/de-DE/changelogs/50.txt new file mode 100644 index 0000000..acb5e08 --- /dev/null +++ b/android/fastlane/metadata/android/de-DE/changelogs/50.txt @@ -0,0 +1,2 @@ +* Beheben von inkorrekter Lokalisierung in der App +* Hinzufügen der Unterscheidung zwischen US und GB Englisch \ No newline at end of file diff --git a/android/fastlane/metadata/android/en-US/changelogs/50.txt b/android/fastlane/metadata/android/en-US/changelogs/50.txt new file mode 100644 index 0000000..4e7e5f7 --- /dev/null +++ b/android/fastlane/metadata/android/en-US/changelogs/50.txt @@ -0,0 +1,2 @@ +* Fixed incorrect localizations of dates and other texts +* Add discrimination between US and GB English (useful for date input) \ No newline at end of file diff --git a/lib/core/widgets/form_builder_fields/extended_date_range_form_field/extended_date_range_dialog.dart b/lib/core/widgets/form_builder_fields/extended_date_range_form_field/extended_date_range_dialog.dart index 7a8cac1..aac24e4 100644 --- a/lib/core/widgets/form_builder_fields/extended_date_range_form_field/extended_date_range_dialog.dart +++ b/lib/core/widgets/form_builder_fields/extended_date_range_form_field/extended_date_range_dialog.dart @@ -146,7 +146,7 @@ class _ExtendedDateRangeDialogState extends State { ) : null, ), - format: DateFormat.yMd(), + format: DateFormat.yMd(Localizations.localeOf(context).toString()), lastDate: _dateTimeMax(_before, DateTime.now()), inputType: InputType.date, onChanged: (after) { @@ -174,7 +174,7 @@ class _ExtendedDateRangeDialogState extends State { ) : null, ), - format: DateFormat.yMd(), + format: DateFormat.yMd(Localizations.localeOf(context).toString()), firstDate: _after, lastDate: DateTime.now(), onChanged: (before) { diff --git a/lib/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart b/lib/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart index b8f5a64..93355a8 100644 --- a/lib/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart +++ b/lib/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart @@ -79,7 +79,7 @@ class _FormBuilderExtendedDateRangePickerState } String _dateRangeQueryToString(DateRangeQuery query) { - final df = DateFormat.yMd(); + final df = DateFormat.yMd(Localizations.localeOf(context).toString()); if (query is UnsetDateRangeQuery) { return ''; } else if (query is AbsoluteDateRangeQuery) { diff --git a/lib/features/app_drawer/view/app_drawer.dart b/lib/features/app_drawer/view/app_drawer.dart index 61b41bb..3714f4d 100644 --- a/lib/features/app_drawer/view/app_drawer.dart +++ b/lib/features/app_drawer/view/app_drawer.dart @@ -4,6 +4,7 @@ import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:paperless_mobile/constants.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/core/widgets/paperless_logo.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart'; @@ -12,6 +13,7 @@ import 'package:paperless_mobile/features/sharing/cubit/receive_share_cubit.dart import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; import 'package:paperless_mobile/routes/typed/branches/upload_queue_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/settings_route.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -21,6 +23,10 @@ class AppDrawer extends StatelessWidget { @override Widget build(BuildContext context) { + final currentAccount = context.watch(); + final username = currentAccount.paperlessUser.username; + final serverUrl = + currentAccount.serverUrl.replaceAll(RegExp(r'https?://'), ''); return SafeArea( child: Drawer( child: Column( @@ -28,13 +34,43 @@ class AppDrawer extends StatelessWidget { children: [ Row( children: [ - const PaperlessLogo.green(), + const PaperlessLogo.green( + width: 32, + height: 32, + ), Text( "Paperless Mobile", style: Theme.of(context).textTheme.titleMedium, ), ], - ).padded(), + ).paddedLTRB(8, 8, 8, 16), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.of(context)!.loggedInAs(username), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.labelMedium?.copyWith( + color: Theme.of(context) + .colorScheme + .onBackground + .withOpacity(0.5), + ), + ), + Text( + serverUrl, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.labelMedium?.copyWith( + color: Theme.of(context) + .colorScheme + .onBackground + .withOpacity(0.5), + ), + ), + ], + ).paddedSymmetrically(horizontal: 16), const Divider(), ListTile( dense: true, @@ -42,6 +78,31 @@ class AppDrawer extends StatelessWidget { leading: const Icon(Icons.info_outline), onTap: () => _showAboutDialog(context), ), + ListTile( + dense: true, + leading: const Icon(Icons.favorite_outline), + title: Text(S.of(context)!.donate), + onTap: () { + showDialog( + context: context, + builder: (context) => AlertDialog( + icon: const Icon(Icons.favorite), + title: Text(S.of(context)!.donate), + content: Text( + S.of(context)!.donationDialogContent, + ), + actionsAlignment: MainAxisAlignment.spaceBetween, + actions: [ + Text("~ Anton"), + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(S.of(context)!.gotIt), + ), + ], + ), + ); + }, + ), ListTile( dense: true, leading: const Icon(Icons.bug_report_outlined), @@ -62,26 +123,6 @@ class AppDrawer extends StatelessWidget { ); }, ), - ListTile( - dense: true, - leading: const Icon(Icons.favorite_outline), - title: Text(S.of(context)!.donate), - onTap: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - icon: const Icon(Icons.favorite), - title: Text(S.of(context)!.donate), - content: Text( - S.of(context)!.donationDialogContent, - ), - actions: const [ - Text("~ Anton"), - ], - ), - ); - }, - ), ListTile( dense: true, leading: SvgPicture.asset( diff --git a/lib/features/document_details/cubit/document_details_cubit.dart b/lib/features/document_details/cubit/document_details_cubit.dart index 2779863..d17b5d4 100644 --- a/lib/features/document_details/cubit/document_details_cubit.dart +++ b/lib/features/document_details/cubit/document_details_cubit.dart @@ -218,7 +218,7 @@ class DocumentDetailsCubit extends Cubit { throw Exception("An error occurred while downloading the document."); } Printing.layoutPdf( - name: state.document.title, + name: state.document.title ?? 'Document', onLayout: (format) => file.readAsBytesSync(), ); } diff --git a/lib/features/document_details/view/pages/document_details_page.dart b/lib/features/document_details/view/pages/document_details_page.dart index 2ad12d6..fa8cb07 100644 --- a/lib/features/document_details/view/pages/document_details_page.dart +++ b/lib/features/document_details/view/pages/document_details_page.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl.dart'; import 'package:open_filex/open_filex.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; @@ -23,6 +25,7 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class DocumentDetailsPage extends StatefulWidget { final bool isLabelClickable; @@ -42,12 +45,18 @@ class _DocumentDetailsPageState extends State { static const double _itemSpacing = 24; final _pagingScrollController = ScrollController(); + @override + void didChangeDependencies() { + super.didChangeDependencies(); + initializeDateFormatting(Localizations.localeOf(context).toString()); + } @override Widget build(BuildContext context) { final hasMultiUserSupport = context.watch().hasMultiUserSupport; final tabLength = 4 + (hasMultiUserSupport && false ? 1 : 0); + final title = context.watch().state.document.title; return WillPopScope( onWillPop: () async { Navigator.of(context) @@ -74,11 +83,7 @@ class _DocumentDetailsPageState extends State { handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), sliver: SliverAppBar( - title: Text(context - .watch() - .state - .document - .title), + title: title != null ? Text(title) : null, leading: const BackButton(), pinned: true, forceElevated: innerBoxIsScrolled, @@ -103,6 +108,7 @@ class _DocumentDetailsPageState extends State { enableHero: false, document: state.document, fit: BoxFit.cover, + alignment: Alignment.topCenter, ), ), Positioned.fill( @@ -221,10 +227,6 @@ class _DocumentDetailsPageState extends State { document: state.document, itemSpacing: _itemSpacing, queryString: widget.titleAndContentQueryString, - availableCorrespondents: state.correspondents, - availableDocumentTypes: state.documentTypes, - availableTags: state.tags, - availableStoragePaths: state.storagePaths, ), ], ), diff --git a/lib/features/document_details/view/widgets/document_meta_data_widget.dart b/lib/features/document_details/view/widgets/document_meta_data_widget.dart index bdfcf81..3c45a44 100644 --- a/lib/features/document_details/view/widgets/document_meta_data_widget.dart +++ b/lib/features/document_details/view/widgets/document_meta_data_widget.dart @@ -44,12 +44,14 @@ class _DocumentMetaDataWidgetState extends State { document: widget.document, ).paddedOnly(bottom: widget.itemSpacing), DetailsItem.text( - DateFormat().format(widget.document.modified), + DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(widget.document.modified), context: context, label: S.of(context)!.modifiedAt, ).paddedOnly(bottom: widget.itemSpacing), DetailsItem.text( - DateFormat().format(widget.document.added), + DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(widget.document.added), context: context, label: S.of(context)!.addedAt, ).paddedOnly(bottom: widget.itemSpacing), diff --git a/lib/features/document_details/view/widgets/document_overview_widget.dart b/lib/features/document_details/view/widgets/document_overview_widget.dart index f38d266..02bcf81 100644 --- a/lib/features/document_details/view/widgets/document_overview_widget.dart +++ b/lib/features/document_details/view/widgets/document_overview_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; +import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/widgets/highlighted_text.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/document_details/view/widgets/details_item.dart'; @@ -12,81 +13,69 @@ import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; class DocumentOverviewWidget extends StatelessWidget { final DocumentModel document; - final Map availableCorrespondents; - final Map availableDocumentTypes; - final Map availableTags; - final Map availableStoragePaths; final String? queryString; final double itemSpacing; + const DocumentOverviewWidget({ super.key, required this.document, this.queryString, required this.itemSpacing, - required this.availableCorrespondents, - required this.availableDocumentTypes, - required this.availableTags, - required this.availableStoragePaths, }); @override Widget build(BuildContext context) { + final user = context.watch().paperlessUser; + final availableLabels = context.watch().state; return SliverList.list( children: [ - DetailsItem( - label: S.of(context)!.title, - content: HighlightedText( - text: document.title, - highlights: queryString?.split(" ") ?? [], - style: Theme.of(context).textTheme.bodyLarge, - ), - ).paddedOnly(bottom: itemSpacing), + if (document.title != null) + DetailsItem( + label: S.of(context)!.title, + content: HighlightedText( + text: document.title!, + highlights: queryString?.split(" ") ?? [], + style: Theme.of(context).textTheme.bodyLarge, + ), + ).paddedOnly(bottom: itemSpacing), DetailsItem.text( - DateFormat.yMMMMd().format(document.created), + DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(document.created), context: context, label: S.of(context)!.createdAt, ).paddedOnly(bottom: itemSpacing), - if (document.documentType != null && - context - .watch() - .paperlessUser - .canViewDocumentTypes) + if (document.documentType != null && user.canViewDocumentTypes) DetailsItem( label: S.of(context)!.documentType, content: LabelText( style: Theme.of(context).textTheme.bodyLarge, - label: availableDocumentTypes[document.documentType], + label: availableLabels.documentTypes[document.documentType], ), ).paddedOnly(bottom: itemSpacing), - if (document.correspondent != null && - context - .watch() - .paperlessUser - .canViewCorrespondents) + if (document.correspondent != null && user.canViewCorrespondents) DetailsItem( label: S.of(context)!.correspondent, content: LabelText( style: Theme.of(context).textTheme.bodyLarge, - label: availableCorrespondents[document.correspondent], + label: availableLabels.correspondents[document.correspondent], ), ).paddedOnly(bottom: itemSpacing), - if (document.storagePath != null && - context.watch().paperlessUser.canViewStoragePaths) + if (document.storagePath != null && user.canViewStoragePaths) DetailsItem( label: S.of(context)!.storagePath, content: LabelText( - label: availableStoragePaths[document.storagePath], + label: availableLabels.storagePaths[document.storagePath], ), ).paddedOnly(bottom: itemSpacing), - if (document.tags.isNotEmpty && - context.watch().paperlessUser.canViewTags) + if (document.tags.isNotEmpty && user.canViewTags) DetailsItem( label: S.of(context)!.tags, content: Padding( padding: const EdgeInsets.only(top: 8.0), child: TagsWidget( isClickable: false, - tags: document.tags.map((e) => availableTags[e]!).toList(), + tags: + document.tags.map((e) => availableLabels.tags[e]!).toList(), ), ), ).paddedOnly(bottom: itemSpacing), diff --git a/lib/features/document_edit/view/document_edit_page.dart b/lib/features/document_edit/view/document_edit_page.dart index d660e76..976d4bb 100644 --- a/lib/features/document_edit/view/document_edit_page.dart +++ b/lib/features/document_edit/view/document_edit_page.dart @@ -376,14 +376,16 @@ class _DocumentEditPageState extends State { label: Text(S.of(context)!.createdAt), ), initialValue: initialCreatedAtDate, - format: DateFormat.yMMMMd(), + format: DateFormat.yMMMMd(Localizations.localeOf(context).toString()), initialEntryMode: DatePickerEntryMode.calendar, ), if (filteredSuggestions?.hasSuggestedDates ?? false) _buildSuggestionsSkeleton( suggestions: filteredSuggestions!.dates, itemBuilder: (context, itemData) => ActionChip( - label: Text(DateFormat.yMMMd().format(itemData)), + label: Text( + DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(itemData)), onPressed: () => _formKey.currentState?.fields[fkCreatedDate] ?.didChange(itemData), ), diff --git a/lib/features/document_scan/view/scanner_page.dart b/lib/features/document_scan/view/scanner_page.dart index 729c8c0..d44f623 100644 --- a/lib/features/document_scan/view/scanner_page.dart +++ b/lib/features/document_scan/view/scanner_page.dart @@ -26,6 +26,7 @@ import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart' import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/helpers/permission_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/scanner_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:path/path.dart' as p; import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; diff --git a/lib/features/document_search/view/document_search_page.dart b/lib/features/document_search/view/document_search_page.dart index 6ae14f2..b2067f8 100644 --- a/lib/features/document_search/view/document_search_page.dart +++ b/lib/features/document_search/view/document_search_page.dart @@ -11,6 +11,7 @@ import 'package:paperless_mobile/features/documents/view/widgets/adaptive_docume import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class DocumentSearchPage extends StatefulWidget { const DocumentSearchPage({super.key}); diff --git a/lib/features/document_search/view/sliver_search_bar.dart b/lib/features/document_search/view/sliver_search_bar.dart index 8cea3d9..7d83861 100644 --- a/lib/features/document_search/view/sliver_search_bar.dart +++ b/lib/features/document_search/view/sliver_search_bar.dart @@ -10,12 +10,10 @@ import 'package:paperless_mobile/features/settings/view/widgets/user_avatar.dart import 'package:provider/provider.dart'; class SliverSearchBar extends StatelessWidget { - final bool floating; final bool pinned; final String titleText; const SliverSearchBar({ super.key, - this.floating = false, this.pinned = false, required this.titleText, }); diff --git a/lib/features/document_upload/view/document_upload_preparation_page.dart b/lib/features/document_upload/view/document_upload_preparation_page.dart index ca244d0..7f136bf 100644 --- a/lib/features/document_upload/view/document_upload_preparation_page.dart +++ b/lib/features/document_upload/view/document_upload_preparation_page.dart @@ -68,7 +68,6 @@ class _DocumentUploadPreparationPageState void initState() { super.initState(); _syncTitleAndFilename = widget.filename == null && widget.title == null; - initializeDateFormatting(); } @override @@ -219,7 +218,8 @@ class _DocumentUploadPreparationPageState // Created at FormBuilderDateTimePicker( autovalidateMode: AutovalidateMode.always, - format: DateFormat.yMMMMd(), + format: DateFormat.yMMMMd( + Localizations.localeOf(context).toString()), inputType: InputType.date, name: DocumentModel.createdKey, initialValue: null, diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index 62f89da..0f31032 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -25,6 +25,7 @@ import 'package:paperless_mobile/features/tasks/model/pending_tasks_notifier.dar import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:sliver_tools/sliver_tools.dart'; class DocumentFilterIntent { @@ -176,13 +177,9 @@ class _DocumentsPageState extends State { child: _showExtendedFab ? Row( children: [ - const Icon( - Icons.filter_alt_outlined, - ), + const Icon(Icons.filter_alt_outlined), const SizedBox(width: 8), - Text( - S.of(context)!.filterDocuments, - ), + Text(S.of(context)!.filterDocuments), ], ) : const Icon(Icons.filter_alt_outlined), @@ -269,7 +266,6 @@ class _DocumentsPageState extends State { builder: (context, state) { if (state.selection.isEmpty) { return SliverSearchBar( - floating: true, titleText: S.of(context)!.documents, ); } else { @@ -620,9 +616,9 @@ class _DocumentsPageState extends State { final cubit = context.read(); try { - switch (cubit.state.filter.storagePath){ - case SetIdQueryParameter(id: var id): - if (id == pathId) { + switch (cubit.state.filter.storagePath) { + case SetIdQueryParameter(id: var id): + if (id == pathId) { cubit.updateCurrentFilter( (filter) => filter.copyWith(storagePath: const UnsetIdQueryParameter()), @@ -634,14 +630,13 @@ class _DocumentsPageState extends State { ); } break; - default: - cubit.updateCurrentFilter( + default: + cubit.updateCurrentFilter( (filter) => - filter.copyWith(storagePath: SetIdQueryParameter(id: pathId)), + filter.copyWith(storagePath: SetIdQueryParameter(id: pathId)), ); break; } - } on PaperlessApiException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } diff --git a/lib/features/documents/view/widgets/delete_document_confirmation_dialog.dart b/lib/features/documents/view/widgets/delete_document_confirmation_dialog.dart index ea9c854..4b334e1 100644 --- a/lib/features/documents/view/widgets/delete_document_confirmation_dialog.dart +++ b/lib/features/documents/view/widgets/delete_document_confirmation_dialog.dart @@ -20,7 +20,7 @@ class DeleteDocumentConfirmationDialog extends StatelessWidget { ), const SizedBox(height: 16), Text( - document.title, + document.title ?? document.originalFileName ?? '-', maxLines: 2, overflow: TextOverflow.ellipsis, style: const TextStyle( diff --git a/lib/features/documents/view/widgets/document_preview.dart b/lib/features/documents/view/widgets/document_preview.dart index 623e864..6bc7e6e 100644 --- a/lib/features/documents/view/widgets/document_preview.dart +++ b/lib/features/documents/view/widgets/document_preview.dart @@ -4,6 +4,7 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:provider/provider.dart'; import 'package:shimmer/shimmer.dart'; diff --git a/lib/features/documents/view/widgets/items/document_detailed_item.dart b/lib/features/documents/view/widgets/items/document_detailed_item.dart index 8fa60df..4fee4e4 100644 --- a/lib/features/documents/view/widgets/items/document_detailed_item.dart +++ b/lib/features/documents/view/widgets/items/document_detailed_item.dart @@ -89,7 +89,8 @@ class DocumentDetailedItem extends DocumentItem { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - DateFormat.yMMMMd().format(document.created), + DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(document.created), style: Theme.of(context) .textTheme .bodySmall @@ -110,7 +111,7 @@ class DocumentDetailedItem extends DocumentItem { ], ).paddedLTRB(8, 8, 8, 4), Text( - document.title, + document.title ?? '-', style: Theme.of(context).textTheme.titleMedium, maxLines: 2, overflow: TextOverflow.ellipsis, diff --git a/lib/features/documents/view/widgets/items/document_grid_item.dart b/lib/features/documents/view/widgets/items/document_grid_item.dart index 3dcc917..7ecbafd 100644 --- a/lib/features/documents/view/widgets/items/document_grid_item.dart +++ b/lib/features/documents/view/widgets/items/document_grid_item.dart @@ -113,7 +113,7 @@ class DocumentGridItem extends DocumentItem { Padding( padding: const EdgeInsets.only(bottom: 8.0), child: Text( - document.title, + document.title ?? '-', maxLines: 3, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.titleMedium, @@ -121,7 +121,9 @@ class DocumentGridItem extends DocumentItem { ), const Spacer(), Text( - DateFormat.yMMMd().format(document.created), + DateFormat.yMMMMd( + Localizations.localeOf(context).toString()) + .format(document.created), style: Theme.of(context).textTheme.bodySmall, ), ], diff --git a/lib/features/documents/view/widgets/items/document_list_item.dart b/lib/features/documents/view/widgets/items/document_list_item.dart index 11c8d6a..873e13c 100644 --- a/lib/features/documents/view/widgets/items/document_list_item.dart +++ b/lib/features/documents/view/widgets/items/document_list_item.dart @@ -58,7 +58,7 @@ class DocumentListItem extends DocumentItem { ], ), Text( - document.title, + document.title ?? '-', overflow: TextOverflow.ellipsis, maxLines: 1, ), @@ -81,7 +81,8 @@ class DocumentListItem extends DocumentItem { maxLines: 1, overflow: TextOverflow.ellipsis, text: TextSpan( - text: DateFormat.yMMMd().format(document.created), + text: DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(document.created), style: Theme.of(context) .textTheme .labelSmall diff --git a/lib/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart b/lib/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart index d956c2a..2e20c3d 100644 --- a/lib/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart +++ b/lib/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart @@ -44,7 +44,7 @@ class BulkDeleteConfirmationDialog extends StatelessWidget { return ListTile( dense: true, title: Text( - doc.title, + doc.title ?? doc.originalFileName ?? '-', maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( diff --git a/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart b/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart index aa85dea..6ca80a1 100644 --- a/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart +++ b/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart @@ -7,6 +7,7 @@ import 'package:paperless_mobile/features/documents/view/widgets/selection/bulk_ import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class DocumentSelectionSliverAppBar extends StatelessWidget { final DocumentsState state; diff --git a/lib/features/inbox/view/pages/inbox_page.dart b/lib/features/inbox/view/pages/inbox_page.dart index b4efa5e..e04e83e 100644 --- a/lib/features/inbox/view/pages/inbox_page.dart +++ b/lib/features/inbox/view/pages/inbox_page.dart @@ -331,7 +331,8 @@ class _InboxPageState extends State if (doc.added.isYesterday) { return S.of(context)!.yesterday; } - return DateFormat.yMMMMd().format(doc.added); + return DateFormat.yMMMMd(Localizations.localeOf(context).toString()) + .format(doc.added); }, ); } diff --git a/lib/features/inbox/view/widgets/inbox_item.dart b/lib/features/inbox/view/widgets/inbox_item.dart index 70fa034..b1ac81c 100644 --- a/lib/features/inbox/view/widgets/inbox_item.dart +++ b/lib/features/inbox/view/widgets/inbox_item.dart @@ -16,6 +16,7 @@ import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class InboxItemPlaceholder extends StatelessWidget { const InboxItemPlaceholder({super.key}); @@ -350,7 +351,7 @@ class _InboxItemState extends State { Text _buildTitle() { return Text( - widget.document.title, + widget.document.title ?? '-', overflow: TextOverflow.ellipsis, maxLines: 2, style: Theme.of(context).textTheme.titleSmall, diff --git a/lib/features/labels/view/pages/labels_page.dart b/lib/features/labels/view/pages/labels_page.dart index bbe5cd2..fe2a6a7 100644 --- a/lib/features/labels/view/pages/labels_page.dart +++ b/lib/features/labels/view/pages/labels_page.dart @@ -15,6 +15,7 @@ import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dar import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/connectivity_aware_action_wrapper.dart'; import 'package:paperless_mobile/routes/typed/branches/labels_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class LabelsPage extends StatefulWidget { const LabelsPage({Key? key}) : super(key: key); diff --git a/lib/features/labels/view/widgets/label_item.dart b/lib/features/labels/view/widgets/label_item.dart index de7e5f5..edc2214 100644 --- a/lib/features/labels/view/widgets/label_item.dart +++ b/lib/features/labels/view/widgets/label_item.dart @@ -4,6 +4,7 @@ import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; import 'package:paperless_mobile/helpers/format_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/labels_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class LabelItem extends StatelessWidget { final T label; diff --git a/lib/features/landing/view/landing_page.dart b/lib/features/landing/view/landing_page.dart index b7d1df7..b2fa93a 100644 --- a/lib/features/landing/view/landing_page.dart +++ b/lib/features/landing/view/landing_page.dart @@ -12,6 +12,7 @@ import 'package:paperless_mobile/features/saved_view_details/view/saved_view_pre import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; import 'package:paperless_mobile/routes/typed/branches/inbox_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class LandingPage extends StatefulWidget { const LandingPage({super.key}); @@ -34,7 +35,6 @@ class _LandingPageState extends State { SliverOverlapAbsorber( handle: _searchBarHandle, sliver: SliverSearchBar( - floating: true, titleText: S.of(context)!.documents, ), ), diff --git a/lib/features/linked_documents/view/linked_documents_page.dart b/lib/features/linked_documents/view/linked_documents_page.dart index 5a7fdba..b7c4428 100644 --- a/lib/features/linked_documents/view/linked_documents_page.dart +++ b/lib/features/linked_documents/view/linked_documents_page.dart @@ -7,6 +7,7 @@ import 'package:paperless_mobile/features/linked_documents/cubit/linked_document import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class LinkedDocumentsPage extends StatefulWidget { const LinkedDocumentsPage({super.key}); diff --git a/lib/features/login/view/login_page.dart b/lib/features/login/view/login_page.dart index ffc2998..831be9e 100644 --- a/lib/features/login/view/login_page.dart +++ b/lib/features/login/view/login_page.dart @@ -13,6 +13,7 @@ import 'package:paperless_mobile/features/login/model/login_form_credentials.dar import 'package:paperless_mobile/features/login/view/add_account_page.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/login_route.dart'; class LoginPage extends StatelessWidget { diff --git a/lib/features/login/view/login_to_existing_account_page.dart b/lib/features/login/view/login_to_existing_account_page.dart index be2a11a..952c213 100644 --- a/lib/features/login/view/login_to_existing_account_page.dart +++ b/lib/features/login/view/login_to_existing_account_page.dart @@ -5,6 +5,7 @@ import 'package:paperless_mobile/core/config/hive/hive_extensions.dart'; import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart'; import 'package:paperless_mobile/features/users/view/widgets/user_account_list_tile.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/login_route.dart'; class LoginToExistingAccountPage extends StatelessWidget { diff --git a/lib/features/login/view/verify_identity_page.dart b/lib/features/login/view/verify_identity_page.dart index cd482da..455becc 100644 --- a/lib/features/login/view/verify_identity_page.dart +++ b/lib/features/login/view/verify_identity_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/login_route.dart'; import 'package:provider/provider.dart'; diff --git a/lib/features/saved_view_details/view/saved_view_preview.dart b/lib/features/saved_view_details/view/saved_view_preview.dart index 2ebb459..31c5103 100644 --- a/lib/features/saved_view_details/view/saved_view_preview.dart +++ b/lib/features/saved_view_details/view/saved_view_preview.dart @@ -8,6 +8,7 @@ import 'package:paperless_mobile/features/landing/view/widgets/expansion_card.da import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_preview_cubit.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:provider/provider.dart'; class SavedViewPreview extends StatelessWidget { diff --git a/lib/features/settings/view/manage_accounts_page.dart b/lib/features/settings/view/manage_accounts_page.dart index 1669716..b06fc66 100644 --- a/lib/features/settings/view/manage_accounts_page.dart +++ b/lib/features/settings/view/manage_accounts_page.dart @@ -7,6 +7,7 @@ import 'package:paperless_mobile/features/settings/view/dialogs/switch_account_d import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart'; import 'package:paperless_mobile/features/users/view/widgets/user_account_list_tile.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/add_account_route.dart'; import 'package:provider/provider.dart'; @@ -146,35 +147,7 @@ class ManageAccountsPage extends StatelessWidget { Future _onAddAccount(BuildContext context, String currentUser) async { Navigator.of(context).pop(); - AddAccountRoute().push(context); - // final userId = await Navigator.push( - // context, - // MaterialPageRoute( - // builder: (context) => AddAccountPage( - // titleText: S.of(context)!.addAccount, - // onSubmit: (context, username, password, serverUrl, - // clientCertificate) async { - // try { - // final userId = - // await context.read().addAccount( - // credentials: LoginFormCredentials( - // username: username, - // password: password, - // ), - // clientCertificate: clientCertificate, - // serverUrl: serverUrl, - // //TODO: Ask user whether to enable biometric authentication - // enableBiometricAuthentication: false, - // ); - - // Navigator.of(context).pop(userId); - // } on PaperlessFormValidationException catch (error) {} - // }, - // submitText: S.of(context)!.addAccount, - // ), - // ), - // ); - + const AddAccountRoute().push(context); } void _onSwitchAccount( diff --git a/lib/features/settings/view/widgets/language_selection_setting.dart b/lib/features/settings/view/widgets/language_selection_setting.dart index 8787acb..1a1e3cc 100644 --- a/lib/features/settings/view/widgets/language_selection_setting.dart +++ b/lib/features/settings/view/widgets/language_selection_setting.dart @@ -13,7 +13,8 @@ class LanguageSelectionSetting extends StatefulWidget { class _LanguageSelectionSettingState extends State { static const _languageOptions = { - 'en': LanguageOption('English', true), + 'en': LanguageOption('English (US)', true), + 'en_GB': LanguageOption('English (GB)', true), 'de': LanguageOption('Deutsch', true), 'es': LanguageOption("Español", true), 'fr': LanguageOption('Français', true), diff --git a/lib/features/settings/view/widgets/radio_settings_dialog.dart b/lib/features/settings/view/widgets/radio_settings_dialog.dart index ceefb29..dfcaa57 100644 --- a/lib/features/settings/view/widgets/radio_settings_dialog.dart +++ b/lib/features/settings/view/widgets/radio_settings_dialog.dart @@ -40,31 +40,34 @@ class _RadioSettingsDialogState extends State> { return AlertDialog( actions: [ const DialogCancelButton(), - widget.confirmButton ?? - DialogConfirmButton( - returnValue: _groupValue, - ), + widget.confirmButton ?? DialogConfirmButton(returnValue: _groupValue), ], title: widget.titleText != null ? Text(widget.titleText!) : null, - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (widget.descriptionText != null) - Text(widget.descriptionText!, - style: Theme.of(context).textTheme.bodySmall), - ...widget.options.map(_buildOptionListTile), - if (widget.footer != null) widget.footer!, - ], + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (widget.descriptionText != null) + Text( + widget.descriptionText!, + style: Theme.of(context).textTheme.bodySmall, + ), + ...widget.options.map(_buildOptionListTile).toList(), + if (widget.footer != null) widget.footer!, + ], + ), ), ); } - Widget _buildOptionListTile(RadioOption option) => RadioListTile( - groupValue: _groupValue, - onChanged: (value) => setState(() => _groupValue = value!), - value: option.value, - title: Text(option.label), - ); + Widget _buildOptionListTile(RadioOption option) { + return RadioListTile( + groupValue: _groupValue, + onChanged: (value) => setState(() => _groupValue = value!), + value: option.value, + title: Text(option.label), + ); + } } class RadioOption { diff --git a/lib/features/settings/view/widgets/user_avatar.dart b/lib/features/settings/view/widgets/user_avatar.dart index 19dd819..1d11cb8 100644 --- a/lib/features/settings/view/widgets/user_avatar.dart +++ b/lib/features/settings/view/widgets/user_avatar.dart @@ -15,16 +15,26 @@ class UserAvatar extends StatelessWidget { Colors.primaries[account.id.hashCode % Colors.primaries.length]; final foregroundColor = backgroundColor.computeLuminance() > 0.5 ? Colors.black : Colors.white; - return CircleAvatar( - child: Text( + return Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + border: Border.all( + color: backgroundColor.shade900.withOpacity(0.4), + width: 2, + ), + ), + child: CircleAvatar( + child: Text( (account.paperlessUser.fullName ?? account.paperlessUser.username) .split(" ") .take(2) .map((e) => e.substring(0, 1)) .map((e) => e.toUpperCase()) - .join("")), - backgroundColor: backgroundColor, - foregroundColor: foregroundColor, + .join(""), + ), + backgroundColor: backgroundColor, + foregroundColor: foregroundColor, + ), ); } } diff --git a/lib/features/sharing/view/widgets/event_listener_shell.dart b/lib/features/sharing/view/widgets/event_listener_shell.dart index 33a4426..55f82b6 100644 --- a/lib/features/sharing/view/widgets/event_listener_shell.dart +++ b/lib/features/sharing/view/widgets/event_listener_shell.dart @@ -23,6 +23,7 @@ import 'package:paperless_mobile/features/tasks/model/pending_tasks_notifier.dar import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/scanner_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:path/path.dart' as p; import 'package:receive_sharing_intent/receive_sharing_intent.dart'; diff --git a/lib/features/similar_documents/view/similar_documents_view.dart b/lib/features/similar_documents/view/similar_documents_view.dart index 3219fe7..ffaa844 100644 --- a/lib/features/similar_documents/view/similar_documents_view.dart +++ b/lib/features/similar_documents/view/similar_documents_view.dart @@ -9,6 +9,7 @@ import 'package:paperless_mobile/features/similar_documents/cubit/similar_docume import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/helpers/message_helpers.dart'; import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; class SimilarDocumentsView extends StatefulWidget { final ScrollController pagingScrollController; diff --git a/lib/main.dart b/lib/main.dart index 4b71766..002e00d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -36,31 +36,27 @@ import 'package:paperless_mobile/features/notifications/services/local_notificat import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/navigation_keys.dart'; -import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; -import 'package:paperless_mobile/routes/typed/branches/inbox_route.dart'; -import 'package:paperless_mobile/routes/typed/branches/labels_route.dart'; import 'package:paperless_mobile/routes/typed/branches/landing_route.dart'; -import 'package:paperless_mobile/routes/typed/branches/saved_views_route.dart'; -import 'package:paperless_mobile/routes/typed/branches/scanner_route.dart'; -import 'package:paperless_mobile/routes/typed/branches/upload_queue_route.dart'; -import 'package:paperless_mobile/routes/typed/shells/provider_shell_route.dart'; -import 'package:paperless_mobile/routes/typed/shells/scaffold_shell_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/authenticated_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/add_account_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/logging_out_route.dart'; import 'package:paperless_mobile/routes/typed/top_level/login_route.dart'; -import 'package:paperless_mobile/routes/typed/top_level/settings_route.dart'; import 'package:paperless_mobile/theme.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; -String get defaultPreferredLocaleSubtag { - String preferredLocale = Platform.localeName.split("_").first; - if (!S.supportedLocales - .any((locale) => locale.languageCode == preferredLocale)) { - preferredLocale = 'en'; +Locale get defaultPreferredLocale { + final deviceLocale = _stringToLocale(Platform.localeName); + if (S.supportedLocales.contains(deviceLocale)) { + return deviceLocale; + } else if (S.supportedLocales + .map((e) => e.languageCode) + .contains(deviceLocale.languageCode)) { + return Locale(deviceLocale.languageCode); + } else { + return const Locale('en'); } - return preferredLocale; } Map Function()> _migrations = { @@ -106,7 +102,7 @@ Future _initHive() async { if (!globalSettingsBox.hasValue) { await globalSettingsBox.setValue( - GlobalSettings(preferredLocaleSubtag: defaultPreferredLocaleSubtag), + GlobalSettings(preferredLocaleSubtag: defaultPreferredLocale.toString()), ); } } @@ -197,12 +193,14 @@ void main() async { value: localNotificationService), Provider.value(value: DocumentChangedNotifier()), ], - child: MultiBlocProvider( + child: MultiProvider( providers: [ - BlocProvider.value(value: connectivityCubit), - BlocProvider.value(value: authenticationCubit), + Provider.value(value: connectivityCubit), + Provider.value(value: authenticationCubit), ], - child: GoRouterShell(apiFactory: apiFactory), + child: GoRouterShell( + apiFactory: apiFactory, + ), ), ), ); @@ -221,10 +219,7 @@ void main() async { class GoRouterShell extends StatefulWidget { final PaperlessApiFactory apiFactory; - const GoRouterShell({ - super.key, - required this.apiFactory, - }); + const GoRouterShell({super.key, required this.apiFactory}); @override State createState() => _GoRouterShellState(); @@ -267,50 +262,53 @@ class _GoRouterShellState extends State { routes: [ ShellRoute( builder: (context, state, child) { - return BlocListener( - listener: (context, state) { - switch (state) { - case UnauthenticatedState( - redirectToAccountSelection: var shouldRedirect - ): - if (shouldRedirect) { - const LoginToExistingAccountRoute().go(context); - } else { - const LoginRoute().go(context); - } - break; - case RestoringSessionState(): - const RestoringSessionRoute().go(context); - break; - case VerifyIdentityState(userId: var userId): - VerifyIdentityRoute(userId: userId).go(context); - break; - case SwitchingAccountsState(): - const SwitchingAccountsRoute().push(context); - break; - case AuthenticatedState(): - const LandingRoute().go(context); - break; - case AuthenticatingState state: - AuthenticatingRoute(state.currentStage.name).push(context); - break; - case LoggingOutState(): - const LoggingOutRoute().go(context); - break; - case AuthenticationErrorState(): - if (context.canPop()) { - context.pop(); - } - // LoginRoute( - // $extra: errorState.clientCertificate, - // password: errorState.password, - // serverUrl: errorState.serverUrl, - // username: errorState.username, - // ).go(context); - break; - } - }, - child: child, + return Provider.value( + value: widget.apiFactory, + child: BlocListener( + listener: (context, state) { + switch (state) { + case UnauthenticatedState( + redirectToAccountSelection: var shouldRedirect + ): + if (shouldRedirect) { + const LoginToExistingAccountRoute().go(context); + } else { + const LoginRoute().go(context); + } + break; + case RestoringSessionState(): + const RestoringSessionRoute().go(context); + break; + case VerifyIdentityState(userId: var userId): + VerifyIdentityRoute(userId: userId).go(context); + break; + case SwitchingAccountsState(): + const SwitchingAccountsRoute().push(context); + break; + case AuthenticatedState(): + const LandingRoute().go(context); + break; + case AuthenticatingState state: + AuthenticatingRoute(state.currentStage.name).push(context); + break; + case LoggingOutState(): + const LoggingOutRoute().go(context); + break; + case AuthenticationErrorState(): + if (context.canPop()) { + context.pop(); + } + // LoginRoute( + // $extra: errorState.clientCertificate, + // password: errorState.password, + // serverUrl: errorState.serverUrl, + // username: errorState.username, + // ).go(context); + break; + } + }, + child: child, + ), ); }, navigatorKey: rootNavigatorKey, @@ -318,44 +316,7 @@ class _GoRouterShellState extends State { $loginRoute, $loggingOutRoute, $addAccountRoute, - ShellRoute( - navigatorKey: outerShellNavigatorKey, - builder: ProviderShellRoute(widget.apiFactory).build, - routes: [ - $settingsRoute, - $savedViewsRoute, - $uploadQueueRoute, - StatefulShellRoute( - navigatorContainerBuilder: - (context, navigationShell, children) { - return children[navigationShell.currentIndex]; - }, - builder: const ScaffoldShellRoute().builder, - branches: [ - StatefulShellBranch( - navigatorKey: landingNavigatorKey, - routes: [$landingRoute], - ), - StatefulShellBranch( - navigatorKey: documentsNavigatorKey, - routes: [$documentsRoute], - ), - StatefulShellBranch( - navigatorKey: scannerNavigatorKey, - routes: [$scannerRoute], - ), - StatefulShellBranch( - navigatorKey: labelsNavigatorKey, - routes: [$labelsRoute], - ), - StatefulShellBranch( - navigatorKey: inboxNavigatorKey, - routes: [$inboxRoute], - ), - ], - ), - ], - ), + $providerShellRoute, ], ), ], @@ -365,6 +326,7 @@ class _GoRouterShellState extends State { Widget build(BuildContext context) { return GlobalSettingsBuilder( builder: (context, settings) { + final locale = _stringToLocale(settings.preferredLocaleSubtag); return DynamicColorBuilder( builder: (lightDynamic, darkDynamic) { return MaterialApp.router( @@ -382,10 +344,41 @@ class _GoRouterShellState extends State { preferredColorScheme: settings.preferredColorSchemeOption, ), themeMode: settings.preferredThemeMode, - supportedLocales: S.supportedLocales, - locale: Locale.fromSubtags( - languageCode: settings.preferredLocaleSubtag, - ), + supportedLocales: const [ + Locale('en'), + Locale('de'), + Locale('en', 'GB'), + Locale('ca'), + Locale('cs'), + Locale('es'), + Locale('fr'), + Locale('pl'), + Locale('ru'), + Locale('tr'), + ], + localeResolutionCallback: (locale, supportedLocales) { + if (locale == null) { + return supportedLocales.first; + } + + final exactMatch = supportedLocales + .where((element) => + element.languageCode == locale.languageCode && + element.countryCode == locale.countryCode) + .toList(); + if (exactMatch.isNotEmpty) { + return exactMatch.first; + } + final superLanguageMatch = supportedLocales + .where((element) => + element.languageCode == locale.languageCode) + .toList(); + if (superLanguageMatch.isNotEmpty) { + return superLanguageMatch.first; + } + return supportedLocales.first; + }, + locale: locale, localizationsDelegates: S.localizationsDelegates, ); }, @@ -394,3 +387,10 @@ class _GoRouterShellState extends State { ); } } + +Locale _stringToLocale(String code) { + final codes = code.split("_"); + final languageCode = codes[0]; + final countryCode = codes.length > 1 ? codes[1] : null; + return Locale(languageCode, countryCode); +} diff --git a/lib/routes/typed/branches/documents_route.dart b/lib/routes/typed/branches/documents_route.dart index 9134681..a48ebcc 100644 --- a/lib/routes/typed/branches/documents_route.dart +++ b/lib/routes/typed/branches/documents_route.dart @@ -17,35 +17,11 @@ import 'package:paperless_mobile/routes/navigation_keys.dart'; import 'package:paperless_mobile/routes/routes.dart'; import 'package:paperless_mobile/theme.dart'; -part 'documents_route.g.dart'; - class DocumentsBranch extends StatefulShellBranchData { static final GlobalKey $navigatorKey = documentsNavigatorKey; const DocumentsBranch(); } -@TypedGoRoute( - path: "/documents", - name: R.documents, - routes: [ - TypedGoRoute( - path: "edit", - name: R.editDocument, - ), - TypedGoRoute( - path: "details", - name: R.documentDetails, - ), - TypedGoRoute( - path: "preview", - name: R.documentPreview, - ), - TypedGoRoute( - path: "bulk-edit", - name: R.bulkEditDocuments, - ), - ], -) class DocumentsRoute extends GoRouteData { @override Widget build(BuildContext context, GoRouterState state) { diff --git a/lib/routes/typed/branches/inbox_route.dart b/lib/routes/typed/branches/inbox_route.dart index 48f038f..9eb1f3c 100644 --- a/lib/routes/typed/branches/inbox_route.dart +++ b/lib/routes/typed/branches/inbox_route.dart @@ -1,14 +1,14 @@ -import 'package:flutter/src/widgets/framework.dart'; +import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart'; -import 'package:paperless_mobile/routes/routes.dart'; +import 'package:paperless_mobile/routes/navigation_keys.dart'; -part 'inbox_route.g.dart'; +class InboxBranch extends StatefulShellBranchData { + static final GlobalKey $navigatorKey = inboxNavigatorKey; + + const InboxBranch(); +} -@TypedGoRoute( - path: "/inbox", - name: R.inbox, -) class InboxRoute extends GoRouteData { @override Widget build(BuildContext context, GoRouterState state) { diff --git a/lib/routes/typed/branches/labels_route.dart b/lib/routes/typed/branches/labels_route.dart index fa81e77..c42b04f 100644 --- a/lib/routes/typed/branches/labels_route.dart +++ b/lib/routes/typed/branches/labels_route.dart @@ -14,33 +14,12 @@ import 'package:paperless_mobile/features/labels/view/pages/labels_page.dart'; import 'package:paperless_mobile/features/linked_documents/cubit/linked_documents_cubit.dart'; import 'package:paperless_mobile/features/linked_documents/view/linked_documents_page.dart'; import 'package:paperless_mobile/routes/navigation_keys.dart'; -import 'package:paperless_mobile/routes/routes.dart'; - -part 'labels_route.g.dart'; class LabelsBranch extends StatefulShellBranchData { static final GlobalKey $navigatorKey = labelsNavigatorKey; const LabelsBranch(); } -@TypedGoRoute( - path: "/labels", - name: R.labels, - routes: [ - TypedGoRoute( - path: "edit", - name: R.editLabel, - ), - TypedGoRoute( - path: "create", - name: R.createLabel, - ), - TypedGoRoute( - path: "linked-documents", - name: R.linkedDocuments, - ), - ], -) class LabelsRoute extends GoRouteData { @override Widget build(BuildContext context, GoRouterState state) { diff --git a/lib/routes/typed/branches/landing_route.dart b/lib/routes/typed/branches/landing_route.dart index 1b501c6..1411760 100644 --- a/lib/routes/typed/branches/landing_route.dart +++ b/lib/routes/typed/branches/landing_route.dart @@ -4,18 +4,12 @@ import 'package:paperless_mobile/features/landing/view/landing_page.dart'; import 'package:paperless_mobile/routes/navigation_keys.dart'; import 'package:paperless_mobile/routes/routes.dart'; -part 'landing_route.g.dart'; - class LandingBranch extends StatefulShellBranchData { static final GlobalKey $navigatorKey = landingNavigatorKey; const LandingBranch(); } -@TypedGoRoute( - path: "/landing", - name: R.landing, -) class LandingRoute extends GoRouteData { const LandingRoute(); @override diff --git a/lib/routes/typed/branches/scanner_route.dart b/lib/routes/typed/branches/scanner_route.dart index ec72171..be7f59e 100644 --- a/lib/routes/typed/branches/scanner_route.dart +++ b/lib/routes/typed/branches/scanner_route.dart @@ -10,38 +10,12 @@ import 'package:paperless_mobile/features/document_upload/view/document_upload_p import 'package:paperless_mobile/routes/navigation_keys.dart'; import 'package:paperless_mobile/routes/routes.dart'; -part 'scanner_route.g.dart'; - -// @TypedStatefulShellBranch( -// routes: [ -// TypedGoRoute( -// path: "/scanner", -// name: R.scanner, -// routes: [ -// TypedGoRoute( -// path: "upload", -// name: R.uploadDocument, -// ), -// ], -// ), -// ], -// ) class ScannerBranch extends StatefulShellBranchData { static final GlobalKey $navigatorKey = scannerNavigatorKey; const ScannerBranch(); } -@TypedGoRoute( - path: "/scanner", - name: R.scanner, - routes: [ - TypedGoRoute( - path: "upload", - name: R.uploadDocument, - ), - ], -) class ScannerRoute extends GoRouteData { const ScannerRoute(); diff --git a/lib/routes/typed/shells/authenticated_route.dart b/lib/routes/typed/shells/authenticated_route.dart new file mode 100644 index 0000000..8f66d59 --- /dev/null +++ b/lib/routes/typed/shells/authenticated_route.dart @@ -0,0 +1,155 @@ +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:flutter/widgets.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hive_flutter/adapters.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/config/hive/hive_config.dart'; +import 'package:paperless_mobile/core/database/tables/global_settings.dart'; +import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; +import 'package:paperless_mobile/core/factory/paperless_api_factory.dart'; +import 'package:paperless_mobile/features/home/view/home_shell_widget.dart'; +import 'package:paperless_mobile/features/home/view/scaffold_with_navigation_bar.dart'; +import 'package:paperless_mobile/features/sharing/cubit/receive_share_cubit.dart'; +import 'package:paperless_mobile/features/sharing/view/widgets/event_listener_shell.dart'; +import 'package:paperless_mobile/routes/navigation_keys.dart'; +import 'package:paperless_mobile/routes/routes.dart'; +import 'package:paperless_mobile/routes/typed/branches/documents_route.dart'; +import 'package:paperless_mobile/routes/typed/branches/inbox_route.dart'; +import 'package:paperless_mobile/routes/typed/branches/labels_route.dart'; +import 'package:paperless_mobile/routes/typed/branches/landing_route.dart'; +import 'package:paperless_mobile/routes/typed/branches/scanner_route.dart'; +import 'package:paperless_mobile/routes/typed/shells/scaffold_shell_route.dart'; +import 'package:paperless_mobile/routes/typed/top_level/settings_route.dart'; +import 'package:provider/provider.dart'; + +/// Key used to access + +part 'authenticated_route.g.dart'; + +@TypedShellRoute( + routes: [ + TypedGoRoute( + path: "/settings", + name: R.settings, + ), + TypedStatefulShellRoute( + branches: [ + TypedStatefulShellBranch( + routes: [ + TypedGoRoute( + path: "/landing", + name: R.landing, + ) + ], + ), + TypedStatefulShellBranch( + routes: [ + TypedGoRoute( + path: "/documents", + routes: [ + TypedGoRoute( + path: "details", + name: R.documentDetails, + ), + TypedGoRoute( + path: "edit", + name: R.editDocument, + ), + TypedGoRoute( + path: "bulk-edit", + name: R.bulkEditDocuments, + ), + TypedGoRoute( + path: 'preview', + name: R.documentPreview, + ), + ], + ) + ], + ), + TypedStatefulShellBranch( + routes: [ + TypedGoRoute( + path: "/scanner", + name: R.scanner, + routes: [ + TypedGoRoute( + path: "upload", + name: R.uploadDocument, + ), + ], + ), + ], + ), + TypedStatefulShellBranch( + routes: [ + TypedGoRoute( + path: "/labels", + name: R.labels, + routes: [ + TypedGoRoute( + path: "edit", + name: R.editLabel, + ), + TypedGoRoute( + path: "create", + name: R.createLabel, + ), + TypedGoRoute( + path: "linked-documents", + name: R.linkedDocuments, + ), + ], + ), + ], + ), + TypedStatefulShellBranch( + routes: [ + TypedGoRoute( + path: "/inbox", + name: R.inbox, + ) + ], + ), + ], + ), + ], +) +class ProviderShellRoute extends ShellRouteData { + static final GlobalKey $navigatorKey = outerShellNavigatorKey; + + const ProviderShellRoute(); + + @override + Widget builder( + BuildContext context, + GoRouterState state, + Widget navigator, + ) { + final currentUserId = Hive.box(HiveBoxes.globalSettings) + .getValue()! + .loggedInUserId; + if (currentUserId == null) { + return const SizedBox.shrink(); + } + final authenticatedUser = + Hive.box(HiveBoxes.localUserAccount).get( + currentUserId, + )!; + final apiFactory = context.read(); + return HomeShellWidget( + localUserId: authenticatedUser.id, + paperlessApiVersion: authenticatedUser.apiVersion, + paperlessProviderFactory: apiFactory, + child: ChangeNotifierProvider( + create: (context) => ConsumptionChangeNotifier() + ..loadFromConsumptionDirectory(userId: currentUserId), + child: EventListenerShell( + child: navigator, + ), + ), + ); + } +} diff --git a/lib/routes/typed/shells/provider_shell_route.dart b/lib/routes/typed/shells/provider_shell_route.dart deleted file mode 100644 index 32b4f28..0000000 --- a/lib/routes/typed/shells/provider_shell_route.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/widgets.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hive_flutter/adapters.dart'; -import 'package:paperless_mobile/core/config/hive/hive_config.dart'; -import 'package:paperless_mobile/core/database/tables/global_settings.dart'; -import 'package:paperless_mobile/core/database/tables/local_user_account.dart'; -import 'package:paperless_mobile/core/factory/paperless_api_factory.dart'; -import 'package:paperless_mobile/features/home/view/home_shell_widget.dart'; -import 'package:paperless_mobile/features/sharing/cubit/receive_share_cubit.dart'; -import 'package:paperless_mobile/features/sharing/view/widgets/event_listener_shell.dart'; -import 'package:paperless_mobile/routes/navigation_keys.dart'; -import 'package:provider/provider.dart'; - -/// Key used to access - -//part 'provider_shell_route.g.dart'; -//TODO: Wait for https://github.com/flutter/flutter/issues/127371 to be merged -// @TypedShellRoute( -// routes: [ -// TypedStatefulShellRoute( -// branches: [ -// TypedStatefulShellBranch( -// routes: [ -// TypedGoRoute( -// path: "/landing", -// // name: R.landing, -// ) -// ], -// ), -// TypedStatefulShellBranch( -// routes: [ -// TypedGoRoute( -// path: "/documents", -// routes: [ -// TypedGoRoute( -// path: "details", -// // name: R.documentDetails, -// ), -// TypedGoRoute( -// path: "edit", -// // name: R.editDocument, -// ), -// ], -// ) -// ], -// ), -// ], -// ), -// ], -// ) -class ProviderShellRoute extends ShellRouteData { - final PaperlessApiFactory apiFactory; - static final GlobalKey $navigatorKey = outerShellNavigatorKey; - - const ProviderShellRoute(this.apiFactory); - - Widget build( - BuildContext context, - GoRouterState state, - Widget navigator, - ) { - final currentUserId = Hive.box(HiveBoxes.globalSettings) - .getValue()! - .loggedInUserId; - if (currentUserId == null) { - return const SizedBox.shrink(); - } - final authenticatedUser = - Hive.box(HiveBoxes.localUserAccount).get( - currentUserId, - )!; - - return HomeShellWidget( - localUserId: authenticatedUser.id, - paperlessApiVersion: authenticatedUser.apiVersion, - paperlessProviderFactory: apiFactory, - child: ChangeNotifierProvider( - create: (context) => ConsumptionChangeNotifier() - ..loadFromConsumptionDirectory(userId: currentUserId), - child: EventListenerShell(child: navigator), - ), - ); - } -} diff --git a/lib/routes/typed/shells/scaffold_shell_route.dart b/lib/routes/typed/shells/scaffold_shell_route.dart index cd86589..abf16bd 100644 --- a/lib/routes/typed/shells/scaffold_shell_route.dart +++ b/lib/routes/typed/shells/scaffold_shell_route.dart @@ -8,6 +8,12 @@ import 'package:paperless_mobile/features/home/view/scaffold_with_navigation_bar class ScaffoldShellRoute extends StatefulShellRouteData { const ScaffoldShellRoute(); + + static Widget $navigatorContainerBuilder(BuildContext context, + StatefulNavigationShell navigationShell, List children) { + return children[navigationShell.currentIndex]; + } + @override Widget builder( BuildContext context, diff --git a/lib/routes/typed/top_level/add_account_route.dart b/lib/routes/typed/top_level/add_account_route.dart index 6c4375e..335e6b8 100644 --- a/lib/routes/typed/top_level/add_account_route.dart +++ b/lib/routes/typed/top_level/add_account_route.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/intl.dart'; import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/model/info_message_exception.dart'; import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart'; @@ -23,58 +23,61 @@ class AddAccountRoute extends GoRouteData { const AddAccountRoute(); static final $parentNavigatorKey = rootNavigatorKey; + @override - Widget build(BuildContext context, GoRouterState state) { - return AddAccountPage( - titleText: S.of(context)!.addAccount, - onSubmit: - (context, username, password, serverUrl, clientCertificate) async { - try { - final userId = await context.read().addAccount( - credentials: LoginFormCredentials( - username: username, - password: password, - ), - clientCertificate: clientCertificate, - serverUrl: serverUrl, - enableBiometricAuthentication: false, - locale: Localizations.localeOf(context).languageCode, - ); - final shoudSwitch = await showDialog( - context: context, - builder: (context) => const SwitchAccountDialog(), - ) ?? - false; - if (shoudSwitch) { - await context.read().switchAccount(userId); - } else { - while (context.canPop()) { - context.pop(); + Page buildPage(BuildContext context, GoRouterState state) { + return NoTransitionPage( + child: AddAccountPage( + titleText: S.of(context)!.addAccount, + onSubmit: + (context, username, password, serverUrl, clientCertificate) async { + try { + final userId = await context.read().addAccount( + credentials: LoginFormCredentials( + username: username, + password: password, + ), + clientCertificate: clientCertificate, + serverUrl: serverUrl, + enableBiometricAuthentication: false, + locale: Intl.getCurrentLocale(), + ); + final shoudSwitch = await showDialog( + context: context, + builder: (context) => const SwitchAccountDialog(), + ) ?? + false; + if (shoudSwitch) { + await context.read().switchAccount(userId); + } else { + while (context.canPop()) { + context.pop(); + } } - } - } on PaperlessApiException catch (error, stackTrace) { - showErrorMessage(context, error, stackTrace); - // context.pop(); - } on PaperlessFormValidationException catch (exception, stackTrace) { - if (exception.hasUnspecificErrorMessage()) { - showLocalizedError(context, exception.unspecificErrorMessage()!); + } on PaperlessApiException catch (error, stackTrace) { + showErrorMessage(context, error, stackTrace); + // context.pop(); + } on PaperlessFormValidationException catch (exception, stackTrace) { + if (exception.hasUnspecificErrorMessage()) { + showLocalizedError(context, exception.unspecificErrorMessage()!); + // context.pop(); + } else { + showGenericError( + context, + exception.validationMessages.values.first, + stackTrace, + ); //TODO: Check if we can show error message directly on field here. + } + } on InfoMessageException catch (error) { + showInfoMessage(context, error); + // context.pop(); + } catch (unknownError, stackTrace) { + showGenericError(context, unknownError.toString(), stackTrace); // context.pop(); - } else { - showGenericError( - context, - exception.validationMessages.values.first, - stackTrace, - ); //TODO: Check if we can show error message directly on field here. } - } on InfoMessageException catch (error) { - showInfoMessage(context, error); - // context.pop(); - } catch (unknownError, stackTrace) { - showGenericError(context, unknownError.toString(), stackTrace); - // context.pop(); - } - }, - submitText: S.of(context)!.addAccount, + }, + submitText: S.of(context)!.addAccount, + ), ); } } diff --git a/lib/routes/typed/top_level/logging_out_route.dart b/lib/routes/typed/top_level/logging_out_route.dart index e78479e..55378f6 100644 --- a/lib/routes/typed/top_level/logging_out_route.dart +++ b/lib/routes/typed/top_level/logging_out_route.dart @@ -1,7 +1,6 @@ -import 'dart:async'; - import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:paperless_mobile/routes/navigation_keys.dart'; import 'package:paperless_mobile/routes/routes.dart'; part 'logging_out_route.g.dart'; @@ -11,12 +10,16 @@ part 'logging_out_route.g.dart'; name: R.loggingOut, ) class LoggingOutRoute extends GoRouteData { + static final $parentNavigatorKey = rootNavigatorKey; const LoggingOutRoute(); + @override - Widget build(BuildContext context, GoRouterState state) { - return Scaffold( - body: Center( - child: Text("Logging out..."), + Page buildPage(BuildContext context, GoRouterState state) { + return const NoTransitionPage( + child: Scaffold( + body: Center( + child: Text("Logging out..."), //TODO: INTL + ), ), ); } diff --git a/lib/routes/typed/top_level/login_route.dart b/lib/routes/typed/top_level/login_route.dart index d8bf146..6e05db5 100644 --- a/lib/routes/typed/top_level/login_route.dart +++ b/lib/routes/typed/top_level/login_route.dart @@ -14,7 +14,6 @@ import 'package:paperless_mobile/features/login/view/widgets/login_transition_pa import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; import 'package:paperless_mobile/routes/navigation_keys.dart'; import 'package:paperless_mobile/routes/routes.dart'; - part 'login_route.g.dart'; @TypedGoRoute( @@ -80,10 +79,13 @@ class SwitchingAccountsRoute extends GoRouteData { static final $parentNavigatorKey = rootNavigatorKey; const SwitchingAccountsRoute(); + @override - Widget build(BuildContext context, GoRouterState state) { - return LoginTransitionPage( - text: S.of(context)!.switchingAccountsPleaseWait, + Page buildPage(BuildContext context, GoRouterState state) { + return NoTransitionPage( + child: LoginTransitionPage( + text: S.of(context)!.switchingAccountsPleaseWait, + ), ); } } @@ -93,8 +95,9 @@ class AuthenticatingRoute extends GoRouteData { final String checkLoginStageName; const AuthenticatingRoute(this.checkLoginStageName); + @override - Widget build(BuildContext context, GoRouterState state) { + Page buildPage(BuildContext context, GoRouterState state) { final stage = AuthenticatingStage.values.byName(checkLoginStageName); final text = switch (stage) { AuthenticatingStage.authenticating => S.of(context)!.authenticatingDots, @@ -103,8 +106,11 @@ class AuthenticatingRoute extends GoRouteData { AuthenticatingStage.fetchingUserInformation => S.of(context)!.fetchingUserInformation, }; - - return LoginTransitionPage(text: text); + return NoTransitionPage( + child: LoginTransitionPage( + text: text, + ), + ); } } @@ -115,8 +121,10 @@ class VerifyIdentityRoute extends GoRouteData { const VerifyIdentityRoute({required this.userId}); @override - Widget build(BuildContext context, GoRouterState state) { - return VerifyIdentityPage(userId: userId); + Page buildPage(BuildContext context, GoRouterState state) { + return NoTransitionPage( + child: VerifyIdentityPage(userId: userId), + ); } } @@ -134,8 +142,10 @@ class LoginToExistingAccountRoute extends GoRouteData { } @override - Widget build(BuildContext context, GoRouterState state) { - return const LoginToExistingAccountPage(); + Page buildPage(BuildContext context, GoRouterState state) { + return const NoTransitionPage( + child: LoginToExistingAccountPage(), + ); } } @@ -145,7 +155,11 @@ class RestoringSessionRoute extends GoRouteData { const RestoringSessionRoute(); @override - Widget build(BuildContext context, GoRouterState state) { - return LoginTransitionPage(text: S.of(context)!.restoringSession); + Page buildPage(BuildContext context, GoRouterState state) { + return NoTransitionPage( + child: LoginTransitionPage( + text: S.of(context)!.restoringSession, + ), + ); } } diff --git a/lib/routes/typed/top_level/settings_route.dart b/lib/routes/typed/top_level/settings_route.dart index 8a93e74..c992695 100644 --- a/lib/routes/typed/top_level/settings_route.dart +++ b/lib/routes/typed/top_level/settings_route.dart @@ -6,14 +6,9 @@ import 'package:paperless_mobile/routes/navigation_keys.dart'; import 'package:paperless_mobile/routes/routes.dart'; import 'package:paperless_mobile/theme.dart'; -part 'settings_route.g.dart'; - -@TypedGoRoute( - path: "/settings", - name: R.settings, -) class SettingsRoute extends GoRouteData { - static final GlobalKey $parentNavigatorKey = outerShellNavigatorKey; + static final GlobalKey $parentNavigatorKey = + outerShellNavigatorKey; @override Widget build(BuildContext context, GoRouterState state) { diff --git a/lib/translations/app_localizations_en_extensions.dart b/lib/translations/app_localizations_en_extensions.dart new file mode 100644 index 0000000..ea09f86 --- /dev/null +++ b/lib/translations/app_localizations_en_extensions.dart @@ -0,0 +1,9 @@ +import 'package:paperless_mobile/generated/l10n/app_localizations_en.dart'; + +class SEnGb extends SEn { + SEnGb() : super('en_GB'); +} + +class SEnUs extends SEn { + SEnUs() : super('en_US'); +} diff --git a/packages/paperless_api/lib/src/models/document_filter.dart b/packages/paperless_api/lib/src/models/document_filter.dart index fb9d8a9..0fd6cf7 100644 --- a/packages/paperless_api/lib/src/models/document_filter.dart +++ b/packages/paperless_api/lib/src/models/document_filter.dart @@ -185,7 +185,7 @@ class DocumentFilter extends Equatable { added.matches(document.added) && modified.matches(document.modified) && query.matches( - title: document.title, + title: document.title ?? '', content: document.content, asn: document.archiveSerialNumber, ); diff --git a/packages/paperless_api/lib/src/models/document_model.dart b/packages/paperless_api/lib/src/models/document_model.dart index 5cc85d2..cc8694a 100644 --- a/packages/paperless_api/lib/src/models/document_model.dart +++ b/packages/paperless_api/lib/src/models/document_model.dart @@ -26,7 +26,7 @@ class DocumentModel extends Equatable { static const storagePathKey = 'storage_path'; final int id; - final String title; + final String? title; final String? content; final Iterable tags; final int? documentType; @@ -71,7 +71,8 @@ class DocumentModel extends Equatable { this.permissions, }); - factory DocumentModel.fromJson(Map json) => _$DocumentModelFromJson(json); + factory DocumentModel.fromJson(Map json) => + _$DocumentModelFromJson(json); Map toJson() => _$DocumentModelToJson(this); @@ -94,15 +95,17 @@ class DocumentModel extends Equatable { title: title ?? this.title, content: content ?? this.content, documentType: documentType != null ? documentType() : this.documentType, - correspondent: correspondent != null ? correspondent() : this.correspondent, + correspondent: + correspondent != null ? correspondent() : this.correspondent, storagePath: storagePath != null ? storagePath() : this.storagePath, tags: tags ?? this.tags, created: created ?? this.created, modified: modified ?? this.modified, added: added ?? this.added, originalFileName: originalFileName ?? this.originalFileName, - archiveSerialNumber: - archiveSerialNumber != null ? archiveSerialNumber() : this.archiveSerialNumber, + archiveSerialNumber: archiveSerialNumber != null + ? archiveSerialNumber() + : this.archiveSerialNumber, archivedFileName: archivedFileName ?? this.archivedFileName, ); } diff --git a/pubspec.lock b/pubspec.lock index aea0457..806dd9d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -748,10 +748,10 @@ packages: dependency: "direct dev" description: name: go_router_builder - sha256: "89585f7cf2ddd35a3f05908c5bb54339d3f891fc5aac4f30e2864469d7ddc92b" + sha256: b004ed761578fd1326054ff9c97daaf7b94f109b24cad843ca8bd349a810f947 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.3" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 884e296..093e6cd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.0.2+49 +version: 3.0.3+50 environment: sdk: ">=3.0.0 <4.0.0" @@ -118,8 +118,7 @@ dev_dependencies: hive_generator: ^2.0.1 mock_server: path: packages/mock_server - go_router_builder: ^2.2.4 - + go_router_builder: ^2.3.3 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. diff --git a/scripts/update_translations.sh b/scripts/update_translations.sh new file mode 100644 index 0000000..6790ac6 --- /dev/null +++ b/scripts/update_translations.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo "Updating source language..." +crowdin download sources --identity=../crowdin_credentials.yml --config ../crowdin.yml --no-preserve-hierarchy +echo "Updating translations..." +crowdin download --identity=../crowdin_credentials.yml --config ../crowdin.yml \ No newline at end of file