From ec7707e4a41dfb9e66858d50cec8db4f55bd9e8a Mon Sep 17 00:00:00 2001 From: Anton Stubenbord Date: Fri, 2 Dec 2022 01:48:13 +0100 Subject: [PATCH] Externalized API and models as own package --- .gitignore | 5 +- .../login/login_integration_test.dart | 17 + .../paperless_server_information_cubit.dart | 16 +- .../paperless_server_information_state.dart | 11 + .../authentication.interceptor.dart | 25 +- .../logic/error_code_localization_mapper.dart | 2 +- lib/core/logic/timeout_client.dart | 40 +- .../model/paperless_statistics_state.dart | 4 +- lib/core/service/file_service.dart | 4 +- .../paperless_server_information_service.dart | 37 - .../service/paperless_statistics_service.dart | 29 - lib/core/service/status.service.dart | 5 +- lib/di_modules.dart | 25 + .../biometric_authentication_intro_slide.dart | 2 +- .../bloc/document_details_cubit.dart | 13 +- .../view/pages/document_details_page.dart | 17 +- .../documents/bloc/documents_cubit.dart | 27 +- .../documents/bloc/documents_state.dart | 4 +- .../repository/saved_views_repository.dart | 56 -- .../view/pages/document_edit_page.dart | 20 +- .../documents/view/pages/document_view.dart | 3 - .../documents/view/pages/documents_page.dart | 16 +- .../delete_document_confirmation_dialog.dart | 2 +- .../view/widgets/document_preview.dart | 4 +- .../view/widgets/documents_empty_state.dart | 3 +- .../view/widgets/grid/document_grid.dart | 3 +- .../view/widgets/grid/document_grid_item.dart | 2 +- .../view/widgets/list/document_list.dart | 4 +- .../view/widgets/list/document_list_item.dart | 3 +- .../view/widgets/order_by_dropdown.dart | 2 +- .../widgets/search/document_filter_panel.dart | 16 +- .../widgets/search/query_type_form_field.dart | 2 +- .../sort_field_selection_bottom_sheet.dart | 17 +- .../bulk_delete_confirmation_dialog.dart | 2 +- .../confirm_delete_saved_view_dialog.dart | 2 +- .../selection/documents_page_app_bar.dart | 8 +- .../view/widgets/sort_documents_button.dart | 10 - lib/features/home/view/home_page.dart | 5 +- .../home/view/widget/info_drawer.dart | 18 +- lib/features/inbox/bloc/inbox_cubit.dart | 26 +- .../inbox/bloc/state/inbox_state.dart | 2 +- lib/features/inbox/view/pages/inbox_page.dart | 15 +- .../view/widgets/inbox_empty_widget.dart | 5 +- .../inbox/view/widgets/inbox_item.dart | 5 +- lib/features/labels/bloc/label_cubit.dart | 9 +- .../labels/{model => bloc}/label_state.dart | 2 +- .../bloc/correspondents_cubit.dart | 11 +- .../view/pages/add_correspondent_page.dart | 2 +- .../view/pages/edit_correspondent_page.dart | 7 +- .../view/widgets/correspondent_widget.dart | 9 +- .../bloc/document_type_cubit.dart | 12 +- .../view/pages/add_document_type_page.dart | 2 +- .../view/pages/edit_document_type_page.dart | 9 +- .../view/widgets/document_type_widget.dart | 8 +- .../storage_path/bloc/storage_path_cubit.dart | 12 +- .../view/pages/add_storage_path_page.dart | 2 +- .../view/pages/edit_storage_path_page.dart | 7 +- .../view/widgets/storage_path_widget.dart | 8 +- lib/features/labels/tags/bloc/tags_cubit.dart | 10 +- .../labels/tags/view/pages/add_tag_page.dart | 2 +- .../labels/tags/view/pages/edit_tag_page.dart | 7 +- .../labels/tags/view/widgets/tag_widget.dart | 2 +- .../tags/view/widgets/tags_form_field.dart | 5 +- .../labels/tags/view/widgets/tags_widget.dart | 4 +- .../labels/view/pages/add_label_page.dart | 15 +- .../labels/view/pages/edit_label_page.dart | 6 +- .../labels/view/pages/labels_page.dart | 12 +- .../labels/view/widgets/label_form_field.dart | 6 +- .../labels/view/widgets/label_item.dart | 7 +- .../labels/view/widgets/label_tab_view.dart | 5 +- .../bloc/linked_documents_cubit.dart | 10 +- .../bloc/state/linked_documents_state.dart | 4 +- .../view/pages/linked_documents_page.dart | 5 +- .../login/bloc/authentication_cubit.dart | 23 +- .../bloc/local_authentication_cubit.dart | 5 +- .../services/authentication.service.dart | 46 +- lib/features/login/view/login_page.dart | 6 +- .../saved_view/bloc/saved_view_cubit.dart | 13 +- .../saved_view/bloc/saved_view_state.dart | 7 +- .../view}/add_saved_view_page.dart | 3 +- .../view}/saved_view_selection_widget.dart | 11 +- .../scan/bloc/document_scanner_cubit.dart | 26 +- .../scan/view/document_upload_page.dart | 21 +- lib/features/scan/view/scanner_page.dart | 11 +- .../biometric_authentication_setting.dart | 2 +- .../widgets/language_selection_setting.dart | 26 +- lib/l10n/intl_cs.arb | 6 +- lib/l10n/intl_de.arb | 4 +- lib/l10n/intl_en.arb | 838 +++++++++--------- lib/main.dart | 7 +- lib/util.dart | 11 +- packages/paperless_api/.gitignore | 30 + packages/paperless_api/.metadata | 10 + packages/paperless_api/CHANGELOG.md | 3 + packages/paperless_api/LICENSE | 1 + packages/paperless_api/README.md | 39 + packages/paperless_api/analysis_options.yaml | 4 + packages/paperless_api/lib/paperless_api.dart | 4 + packages/paperless_api/lib/src/constants.dart | 3 + .../lib/src/models/bulk_edit_model.dart | 8 +- .../lib/src/models}/document_filter.dart | 28 +- .../src/models/document_meta_data_model.dart | 0 .../lib/src/models/document_model.dart | 5 +- .../lib/src/models/filter_rule_model.dart | 27 +- .../models/labels/correspondent_model.dart | 18 +- .../models/labels/document_type_model.dart | 9 +- .../lib/src/models/labels/label_model.dart | 26 +- .../models/labels}/matching_algorithm.dart | 0 .../src/models/labels/storage_path_model.dart | 12 +- .../lib/src/models/labels/tag_model.dart | 16 +- .../paperless_api/lib/src/models/models.dart | 26 + .../lib/src/models}/paged_search_result.dart | 9 +- .../models/paperless_server_exception.dart | 6 +- .../paperless_server_information_model.dart | 5 +- .../paperless_server_statistics_model.dart | 8 +- .../models}/query_parameters/asn_query.dart | 2 +- .../query_parameters/correspondent_query.dart | 2 +- .../query_parameters/document_type_query.dart | 2 +- .../query_parameters/id_query_parameter.dart | 2 - .../models}/query_parameters/query_type.dart | 0 .../models}/query_parameters/sort_field.dart | 0 .../models}/query_parameters/sort_order.dart | 0 .../query_parameters/storage_path_query.dart | 2 +- .../models}/query_parameters/tags_query.dart | 10 +- .../lib/src/models/saved_view_model.dart | 15 +- .../src/models/similar_document_model.dart | 11 +- .../authentication_api.dart | 7 + .../authentication_api_impl.dart | 53 ++ .../paperless_documents_api.dart | 21 +- .../paperless_documents_api_impl.dart | 142 ++- .../labels_api/paperless_labels_api.dart | 19 +- .../labels_api/paperless_labels_api_impl.dart | 157 ++-- .../lib/src/modules/modules.dart | 11 + .../paperless_saved_views_api.dart | 8 + .../paperless_saved_views_api_impl.dart | 54 ++ .../paperless_server_stats_api.dart | 7 + .../paperless_server_stats_api_impl.dart | 53 ++ .../paperless_api/lib/src/utils.dart | 47 +- packages/paperless_api/pubspec.yaml | 63 ++ .../paperless_api/test}/saved_view_test.dart | 20 +- pubspec.lock | 15 +- pubspec.yaml | 2 + test/src/bloc/document_cubit_test.dart | 13 +- 143 files changed, 1496 insertions(+), 1339 deletions(-) create mode 100644 integration_test/login/login_integration_test.dart create mode 100644 lib/core/bloc/paperless_server_information_state.dart delete mode 100644 lib/core/service/paperless_server_information_service.dart delete mode 100644 lib/core/service/paperless_statistics_service.dart delete mode 100644 lib/features/documents/repository/saved_views_repository.dart rename lib/features/labels/{model => bloc}/label_state.dart (81%) rename lib/features/{documents/view/widgets/selection => saved_view/view}/add_saved_view_page.dart (94%) rename lib/features/{documents/view/widgets/selection => saved_view/view}/saved_view_selection_widget.dart (91%) create mode 100644 packages/paperless_api/.gitignore create mode 100644 packages/paperless_api/.metadata create mode 100644 packages/paperless_api/CHANGELOG.md create mode 100644 packages/paperless_api/LICENSE create mode 100644 packages/paperless_api/README.md create mode 100644 packages/paperless_api/analysis_options.yaml create mode 100644 packages/paperless_api/lib/paperless_api.dart create mode 100644 packages/paperless_api/lib/src/constants.dart rename lib/features/documents/model/bulk_edit.model.dart => packages/paperless_api/lib/src/models/bulk_edit_model.dart (89%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/document_filter.dart (78%) rename lib/features/documents/model/document_meta_data.model.dart => packages/paperless_api/lib/src/models/document_meta_data_model.dart (100%) rename lib/features/documents/model/document.model.dart => packages/paperless_api/lib/src/models/document_model.dart (97%) rename lib/features/documents/model/filter_rule.model.dart => packages/paperless_api/lib/src/models/filter_rule_model.dart (86%) rename lib/features/labels/correspondent/model/correspondent.model.dart => packages/paperless_api/lib/src/models/labels/correspondent_model.dart (72%) rename lib/features/labels/document_type/model/document_type.model.dart => packages/paperless_api/lib/src/models/labels/document_type_model.dart (71%) rename lib/features/labels/model/label.model.dart => packages/paperless_api/lib/src/models/labels/label_model.dart (68%) rename {lib/features/labels/document_type/model => packages/paperless_api/lib/src/models/labels}/matching_algorithm.dart (100%) rename lib/features/labels/storage_path/model/storage_path.model.dart => packages/paperless_api/lib/src/models/labels/storage_path_model.dart (74%) rename lib/features/labels/tags/model/tag.model.dart => packages/paperless_api/lib/src/models/labels/tag_model.dart (82%) create mode 100644 packages/paperless_api/lib/src/models/models.dart rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/paged_search_result.dart (90%) rename lib/core/model/error_message.dart => packages/paperless_api/lib/src/models/paperless_server_exception.dart (88%) rename lib/core/model/paperless_server_information.dart => packages/paperless_api/lib/src/models/paperless_server_information_model.dart (82%) rename lib/core/model/paperless_statistics.dart => packages/paperless_api/lib/src/models/paperless_server_statistics_model.dart (61%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/asn_query.dart (75%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/correspondent_query.dart (78%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/document_type_query.dart (77%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/id_query_parameter.dart (95%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/query_type.dart (100%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/sort_field.dart (100%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/sort_order.dart (100%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/storage_path_query.dart (77%) rename {lib/features/documents/model => packages/paperless_api/lib/src/models}/query_parameters/tags_query.dart (94%) rename lib/features/documents/model/saved_view.model.dart => packages/paperless_api/lib/src/models/saved_view_model.dart (83%) rename lib/features/documents/model/similar_document.model.dart => packages/paperless_api/lib/src/models/similar_document_model.dart (81%) create mode 100644 packages/paperless_api/lib/src/modules/authentication_api/authentication_api.dart create mode 100644 packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart rename lib/features/documents/repository/document_repository.dart => packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api.dart (56%) rename lib/features/documents/repository/document_repository_impl.dart => packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart (60%) rename lib/features/labels/repository/label_repository.dart => packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api.dart (66%) rename lib/features/labels/repository/label_repository_impl.dart => packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api_impl.dart (59%) create mode 100644 packages/paperless_api/lib/src/modules/modules.dart create mode 100644 packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart create mode 100644 packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart create mode 100644 packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api.dart create mode 100644 packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart rename lib/core/util.dart => packages/paperless_api/lib/src/utils.dart (54%) create mode 100644 packages/paperless_api/pubspec.yaml rename {test/src => packages/paperless_api/test}/saved_view_test.dart (90%) diff --git a/.gitignore b/.gitignore index 117ea42..275e0b4 100644 --- a/.gitignore +++ b/.gitignore @@ -56,4 +56,7 @@ di_initializer.config.dart # l10n generated files: lib/generated/* -untranslated_messages.txt \ No newline at end of file +untranslated_messages.txt + +#lakos generated files +**/dot_images/* \ No newline at end of file diff --git a/integration_test/login/login_integration_test.dart b/integration_test/login/login_integration_test.dart new file mode 100644 index 0000000..9ad8155 --- /dev/null +++ b/integration_test/login/login_integration_test.dart @@ -0,0 +1,17 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:integration_test/integration_test.dart'; + +void main() { + final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + + testWidgets('screenshot', (WidgetTester tester) async { + // Build the app. + + // This is required prior to taking the screenshot (Android only). + await binding.convertFlutterSurfaceToImage(); + + // Trigger a frame. + await tester.pumpAndSettle(); + await binding.takeScreenshot('screenshot-1'); + }); +} diff --git a/lib/core/bloc/paperless_server_information_cubit.dart b/lib/core/bloc/paperless_server_information_cubit.dart index 5c53cac..1e3ec45 100644 --- a/lib/core/bloc/paperless_server_information_cubit.dart +++ b/lib/core/bloc/paperless_server_information_cubit.dart @@ -1,17 +1,21 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/core/model/paperless_server_information.dart'; -import 'package:paperless_mobile/core/service/paperless_server_information_service.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart'; @singleton class PaperlessServerInformationCubit - extends Cubit { - final PaperlessServerInformationService service; + extends Cubit { + final PaperlessServerStatsApi service; PaperlessServerInformationCubit(this.service) - : super(PaperlessServerInformation()); + : super(PaperlessServerInformationState()); Future updateInformtion() async { - emit(await service.getInformation()); + final information = await service.getServerInformation(); + emit(PaperlessServerInformationState( + isLoaded: true, + information: information, + )); } } diff --git a/lib/core/bloc/paperless_server_information_state.dart b/lib/core/bloc/paperless_server_information_state.dart new file mode 100644 index 0000000..aa63eab --- /dev/null +++ b/lib/core/bloc/paperless_server_information_state.dart @@ -0,0 +1,11 @@ +import 'package:paperless_api/paperless_api.dart'; + +class PaperlessServerInformationState { + final bool isLoaded; + final PaperlessServerInformationModel? information; + + PaperlessServerInformationState({ + this.isLoaded = false, + this.information, + }); +} diff --git a/lib/core/interceptor/authentication.interceptor.dart b/lib/core/interceptor/authentication.interceptor.dart index 5c0aba9..92e3c9a 100644 --- a/lib/core/interceptor/authentication.interceptor.dart +++ b/lib/core/interceptor/authentication.interceptor.dart @@ -1,35 +1,32 @@ import 'dart:developer'; import 'package:flutter/foundation.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/store/local_vault.dart'; import 'package:http_interceptor/http_interceptor.dart'; import 'package:injectable/injectable.dart'; @injectable class AuthenticationInterceptor implements InterceptorContract { - AuthenticationCubit authenticationCubit; - AuthenticationInterceptor(this.authenticationCubit); + final LocalVault _localVault; + AuthenticationInterceptor(this._localVault); @override Future interceptRequest({required BaseRequest request}) async { - final authState = authenticationCubit.state; + final auth = await _localVault.loadAuthenticationInformation(); + if (kDebugMode) { log("Intercepted ${request.method} request to ${request.url.toString()}"); } - if (authState.authentication == null) { - throw const ErrorMessage(ErrorCode.notAuthenticated); + if (auth == null) { + throw const PaperlessServerException(ErrorCode.notAuthenticated); } return request.copyWith( //Append server Url - url: Uri.parse( - authState.authentication!.serverUrl + request.url.toString()), - headers: authState.authentication!.token.isEmpty + url: Uri.parse(auth.serverUrl + request.url.toString()), + headers: auth.token.isEmpty ? request.headers - : { - ...request.headers, - 'Authorization': 'Token ${authState.authentication!.token}' - }, + : {...request.headers, 'Authorization': 'Token ${auth.token}'}, ); } diff --git a/lib/core/logic/error_code_localization_mapper.dart b/lib/core/logic/error_code_localization_mapper.dart index b1d4f28..cdb0d4b 100644 --- a/lib/core/logic/error_code_localization_mapper.dart +++ b/lib/core/logic/error_code_localization_mapper.dart @@ -1,5 +1,5 @@ import 'package:flutter/cupertino.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/generated/l10n.dart'; String translateError(BuildContext context, ErrorCode code) { diff --git a/lib/core/logic/timeout_client.dart b/lib/core/logic/timeout_client.dart index 35cca34..4d8173d 100644 --- a/lib/core/logic/timeout_client.dart +++ b/lib/core/logic/timeout_client.dart @@ -2,7 +2,7 @@ import 'dart:typed_data'; import 'dart:convert'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/service/connectivity_status.service.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/di_initializer.dart'; @@ -24,8 +24,8 @@ class TimeoutClient implements BaseClient { Future send(BaseRequest request) async { return getIt().send(request).timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ); } @@ -47,8 +47,8 @@ class TimeoutClient implements BaseClient { .delete(url, headers: headers, body: body, encoding: encoding) .timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ), ); } @@ -62,8 +62,8 @@ class TimeoutClient implements BaseClient { return _handle400Error( await getIt().get(url, headers: headers).timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ), ); } @@ -77,8 +77,8 @@ class TimeoutClient implements BaseClient { return _handle400Error( await getIt().head(url, headers: headers).timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ), ); } @@ -96,8 +96,8 @@ class TimeoutClient implements BaseClient { .patch(url, headers: headers, body: body, encoding: encoding) .timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ), ); } @@ -115,8 +115,8 @@ class TimeoutClient implements BaseClient { .post(url, headers: headers, body: body, encoding: encoding) .timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ), ); } @@ -134,8 +134,8 @@ class TimeoutClient implements BaseClient { .put(url, headers: headers, body: body, encoding: encoding) .timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ), ); } @@ -148,8 +148,8 @@ class TimeoutClient implements BaseClient { await _handleOfflineState(); return getIt().read(url, headers: headers).timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ); } @@ -161,8 +161,8 @@ class TimeoutClient implements BaseClient { await _handleOfflineState(); return getIt().readBytes(url, headers: headers).timeout( requestTimeout, - onTimeout: () => - Future.error(const ErrorMessage(ErrorCode.requestTimedOut)), + onTimeout: () => Future.error( + const PaperlessServerException(ErrorCode.requestTimedOut)), ); } @@ -188,7 +188,7 @@ class TimeoutClient implements BaseClient { Future _handleOfflineState() async { if (!(await connectivityStatusService.isConnectedToInternet())) { - throw const ErrorMessage(ErrorCode.deviceOffline); + throw const PaperlessServerException(ErrorCode.deviceOffline); } } } diff --git a/lib/core/model/paperless_statistics_state.dart b/lib/core/model/paperless_statistics_state.dart index 3cf1910..12fede2 100644 --- a/lib/core/model/paperless_statistics_state.dart +++ b/lib/core/model/paperless_statistics_state.dart @@ -1,8 +1,8 @@ -import 'package:paperless_mobile/core/model/paperless_statistics.dart'; +import 'package:paperless_api/paperless_api.dart'; class PaperlessStatisticsState { final bool isLoaded; - final PaperlessStatistics? statistics; + final PaperlessServerStatisticsModel? statistics; PaperlessStatisticsState({ required this.isLoaded, diff --git a/lib/core/service/file_service.dart b/lib/core/service/file_service.dart index 558c319..aef7558 100644 --- a/lib/core/service/file_service.dart +++ b/lib/core/service/file_service.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:path_provider/path_provider.dart'; import 'package:uuid/uuid.dart'; @@ -12,7 +12,7 @@ class FileService { ) async { final dir = await documentsDirectory; if (dir == null) { - throw const ErrorMessage.unknown(); //TODO: better handling + throw const PaperlessServerException.unknown(); //TODO: better handling } File file = File("${dir.path}/$filename"); return file..writeAsBytes(bytes); diff --git a/lib/core/service/paperless_server_information_service.dart b/lib/core/service/paperless_server_information_service.dart deleted file mode 100644 index e94c9a4..0000000 --- a/lib/core/service/paperless_server_information_service.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'dart:convert'; - -import 'package:http/http.dart'; -import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/core/model/paperless_server_information.dart'; -import 'package:paperless_mobile/core/store/local_vault.dart'; - -@injectable -class PaperlessServerInformationService { - final BaseClient client; - final LocalVault localStore; - - PaperlessServerInformationService( - @Named("timeoutClient") this.client, - this.localStore, - ); - - Future getInformation() async { - final response = await client.get(Uri.parse("/api/ui_settings/")); - final version = - response.headers[PaperlessServerInformation.versionHeader] ?? 'unknown'; - final apiVersion = int.tryParse( - response.headers[PaperlessServerInformation.apiVersionHeader] ?? '1'); - final String username = - jsonDecode(utf8.decode(response.bodyBytes))['username']; - final String? host = - response.headers[PaperlessServerInformation.hostHeader] ?? - response.request?.headers[PaperlessServerInformation.hostHeader] ?? - ('${response.request?.url.host}:${response.request?.url.port}'); - return PaperlessServerInformation( - username: username, - version: version, - apiVersion: apiVersion, - host: host, - ); - } -} diff --git a/lib/core/service/paperless_statistics_service.dart b/lib/core/service/paperless_statistics_service.dart deleted file mode 100644 index 598e899..0000000 --- a/lib/core/service/paperless_statistics_service.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:convert'; - -import 'package:http/http.dart'; -import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/model/paperless_statistics.dart'; -import 'package:paperless_mobile/core/type/types.dart'; - -abstract class PaperlessStatisticsService { - Future getStatistics(); -} - -@Injectable(as: PaperlessStatisticsService) -class PaperlessStatisticsServiceImpl extends PaperlessStatisticsService { - final BaseClient client; - - PaperlessStatisticsServiceImpl(@Named('timeoutClient') this.client); - - @override - Future getStatistics() async { - final response = await client.get(Uri.parse('/api/statistics/')); - if (response.statusCode == 200) { - return PaperlessStatistics.fromJson( - jsonDecode(utf8.decode(response.bodyBytes)) as JSON, - ); - } - throw const ErrorMessage.unknown(); - } -} diff --git a/lib/core/service/status.service.dart b/lib/core/service/status.service.dart index 55f3292..1362b39 100644 --- a/lib/core/service/status.service.dart +++ b/lib/core/service/status.service.dart @@ -3,14 +3,13 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; +import 'package:injectable/injectable.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/document_status_cubit.dart'; import 'package:paperless_mobile/core/model/document_processing_status.dart'; import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; import 'package:paperless_mobile/features/login/model/authentication_information.dart'; import 'package:paperless_mobile/util.dart'; -import 'package:injectable/injectable.dart'; import 'package:web_socket_channel/io.dart'; abstract class StatusService { diff --git a/lib/di_modules.dart b/lib/di_modules.dart index 9b570dd..aa91789 100644 --- a/lib/di_modules.dart +++ b/lib/di_modules.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:encrypted_shared_preferences/encrypted_shared_preferences.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/interceptor/authentication.interceptor.dart'; import 'package:paperless_mobile/core/interceptor/language_header.interceptor.dart'; import 'package:paperless_mobile/core/interceptor/response_conversion.interceptor.dart'; @@ -51,4 +52,28 @@ abstract class RegisterModule { CacheManager getCacheManager(BaseClient client) => CacheManager( Config('cacheKey', fileService: HttpFileService(httpClient: client))); + + PaperlessAuthenticationApi authenticationModule(BaseClient client) => + PaperlessAuthenticationApiImpl(client); + + PaperlessLabelsApi labelsModule( + @Named('timeoutClient') BaseClient timeoutClient, + ) => + PaperlessLabelApiImpl(timeoutClient); + + PaperlessDocumentsApi documentsModule( + @Named('timeoutClient') BaseClient timeoutClient, + HttpClient httpClient, + ) => + PaperlessDocumentsApiImpl(timeoutClient, httpClient); + + PaperlessSavedViewsApi savedViewsModule( + @Named('timeoutClient') BaseClient timeoutClient, + ) => + PaperlessSavedViewsApiImpl(timeoutClient); + + PaperlessServerStatsApi serverStatsModule( + @Named('timeoutClient') BaseClient timeoutClient, + ) => + PaperlessServerStatsApiImpl(timeoutClient); } diff --git a/lib/features/app_intro/widgets/biometric_authentication_intro_slide.dart b/lib/features/app_intro/widgets/biometric_authentication_intro_slide.dart index e8df018..56a9fd9 100644 --- a/lib/features/app_intro/widgets/biometric_authentication_intro_slide.dart +++ b/lib/features/app_intro/widgets/biometric_authentication_intro_slide.dart @@ -62,7 +62,7 @@ class _BiometricAuthenticationIntroSlideState final settings = BlocProvider.of(context) .state; - getIt() + getIt() .authenticateLocalUser( "Please authenticate to secure Paperless Mobile") .then((isEnabled) { diff --git a/lib/features/document_details/bloc/document_details_cubit.dart b/lib/features/document_details/bloc/document_details_cubit.dart index f4c92c5..68f437f 100644 --- a/lib/features/document_details/bloc/document_details_cubit.dart +++ b/lib/features/document_details/bloc/document_details_cubit.dart @@ -1,29 +1,28 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; +import 'package:paperless_api/paperless_api.dart'; part 'document_details_state.dart'; class DocumentDetailsCubit extends Cubit { - final DocumentRepository _documentRepository; + final PaperlessDocumentsApi _api; - DocumentDetailsCubit(this._documentRepository, DocumentModel initialDocument) + DocumentDetailsCubit(this._api, DocumentModel initialDocument) : super(DocumentDetailsState(document: initialDocument)); Future delete(DocumentModel document) async { - await _documentRepository.delete(document); + await _api.delete(document); emit(const DocumentDetailsState()); } Future update(DocumentModel document) async { - final updatedDocument = await _documentRepository.update(document); + final updatedDocument = await _api.update(document); emit(DocumentDetailsState(document: updatedDocument)); } Future assignAsn(DocumentModel document) async { if (document.archiveSerialNumber == null) { - final int asn = await _documentRepository.findNextAsn(); + final int asn = await _api.findNextAsn(); update(document.copyWith(archiveSerialNumber: asn)); } } 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 f278fa3..7abba7a 100644 --- a/lib/features/document_details/view/pages/document_details_page.dart +++ b/lib/features/document_details/view/pages/document_details_page.dart @@ -7,14 +7,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/highlighted_text.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_meta_data.model.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/features/documents/view/pages/document_edit_page.dart'; import 'package:paperless_mobile/features/documents/view/pages/document_view.dart'; import 'package:paperless_mobile/features/documents/view/widgets/delete_document_confirmation_dialog.dart'; @@ -235,7 +232,7 @@ class _DocumentDetailsPageState extends State { Widget _buildDocumentMetaDataView(DocumentModel document) { return FutureBuilder( - future: getIt().getMetaData(document), + future: getIt().getMetaData(document), builder: (context, snapshot) { if (!snapshot.hasData) { return const Center(child: CircularProgressIndicator()); @@ -295,7 +292,7 @@ class _DocumentDetailsPageState extends State { Future _assignAsn(DocumentModel document) async { try { await BlocProvider.of(context).assignAsn(document); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } @@ -414,7 +411,7 @@ class _DocumentDetailsPageState extends State { return; } setState(() => _isDownloadPending = true); - getIt().download(document).then((bytes) async { + getIt().download(document).then((bytes) async { final Directory dir = (await getExternalStorageDirectories( type: StorageDirectory.downloads))! .first; @@ -431,7 +428,7 @@ class _DocumentDetailsPageState extends State { /// Future _onShare(DocumentModel document) async { Uint8List documentBytes = - await getIt().download(document); + await getIt().download(document); final dir = await getTemporaryDirectory(); final String path = "${dir.path}/${document.originalFileName}"; await File(path).writeAsBytes(documentBytes); @@ -459,7 +456,7 @@ class _DocumentDetailsPageState extends State { try { await BlocProvider.of(context).delete(document); showSnackBar(context, S.of(context).documentDeleteSuccessMessage); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } finally { // Document deleted => go back to primary route @@ -472,7 +469,7 @@ class _DocumentDetailsPageState extends State { Navigator.of(context).push( MaterialPageRoute( builder: (context) => DocumentView( - documentBytes: getIt().getPreview(document.id), + documentBytes: getIt().getPreview(document.id), ), ), ); diff --git a/lib/features/documents/bloc/documents_cubit.dart b/lib/features/documents/bloc/documents_cubit.dart index 0cb1c5a..8ee60a1 100644 --- a/lib/features/documents/bloc/documents_cubit.dart +++ b/lib/features/documents/bloc/documents_cubit.dart @@ -2,21 +2,17 @@ import 'dart:typed_data'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injectable/injectable.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/bulk_edit.model.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; @singleton class DocumentsCubit extends Cubit { - final DocumentRepository documentRepository; + final PaperlessDocumentsApi _api; - DocumentsCubit(this.documentRepository) : super(DocumentsState.initial); + DocumentsCubit(this._api) : super(DocumentsState.initial); Future bulkRemove(List documents) async { - await documentRepository.bulkAction( + await _api.bulkAction( BulkDeleteAction(documents.map((doc) => doc.id)), ); await reload(); @@ -27,7 +23,7 @@ class DocumentsCubit extends Cubit { Iterable addTags = const [], Iterable removeTags = const [], }) async { - await documentRepository.bulkAction(BulkModifyTagsAction( + await _api.bulkAction(BulkModifyTagsAction( documents.map((doc) => doc.id), addTags: addTags, removeTags: removeTags, @@ -40,13 +36,13 @@ class DocumentsCubit extends Cubit { bool updateRemote = true, ]) async { if (updateRemote) { - await documentRepository.update(document); + await _api.update(document); } await reload(); } Future load() async { - final result = await documentRepository.find(state.filter); + final result = await _api.find(state.filter); emit(DocumentsState( isLoaded: true, value: [...state.value, result], @@ -60,15 +56,14 @@ class DocumentsCubit extends Cubit { } var newPages = []; for (final page in state.value) { - final result = await documentRepository - .find(state.filter.copyWith(page: page.pageKey)); + final result = await _api.find(state.filter.copyWith(page: page.pageKey)); newPages.add(result); } emit(DocumentsState(isLoaded: true, value: newPages, filter: state.filter)); } Future _bulkReloadDocuments() async { - final result = await documentRepository + final result = await _api .find(state.filter.copyWith(page: 1, pageSize: state.documents.length)); emit(DocumentsState(isLoaded: true, value: [result], filter: state.filter)); } @@ -78,7 +73,7 @@ class DocumentsCubit extends Cubit { return; } final newFilter = state.filter.copyWith(page: state.filter.page + 1); - final result = await documentRepository.find(newFilter); + final result = await _api.find(newFilter); emit( DocumentsState( isLoaded: true, value: [...state.value, result], filter: newFilter), @@ -91,7 +86,7 @@ class DocumentsCubit extends Cubit { Future updateFilter({ final DocumentFilter filter = DocumentFilter.initial, }) async { - final result = await documentRepository.find(filter.copyWith(page: 1)); + final result = await _api.find(filter.copyWith(page: 1)); emit(DocumentsState(filter: filter, value: [result], isLoaded: true)); } diff --git a/lib/features/documents/bloc/documents_state.dart b/lib/features/documents/bloc/documents_state.dart index 05d99c8..b016f9f 100644 --- a/lib/features/documents/bloc/documents_state.dart +++ b/lib/features/documents/bloc/documents_state.dart @@ -1,7 +1,5 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; +import 'package:paperless_api/paperless_api.dart'; class DocumentsState extends Equatable { final bool isLoaded; diff --git a/lib/features/documents/repository/saved_views_repository.dart b/lib/features/documents/repository/saved_views_repository.dart deleted file mode 100644 index 75220f2..0000000 --- a/lib/features/documents/repository/saved_views_repository.dart +++ /dev/null @@ -1,56 +0,0 @@ -import 'dart:convert'; - -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/util.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; -import 'package:http/http.dart'; -import 'package:injectable/injectable.dart'; - -abstract class SavedViewsRepository { - Future> getAll(); - - Future save(SavedView view); - Future delete(SavedView view); -} - -@Injectable(as: SavedViewsRepository) -class SavedViewRepositoryImpl implements SavedViewsRepository { - final BaseClient httpClient; - - SavedViewRepositoryImpl(@Named("timeoutClient") this.httpClient); - - @override - Future> getAll() { - return getCollection( - "/api/saved_views/", - SavedView.fromJson, - ErrorCode.loadSavedViewsError, - ); - } - - @override - Future save(SavedView view) async { - final response = await httpClient.post( - Uri.parse("/api/saved_views/"), - body: jsonEncode(view.toJson()), - headers: {'Content-Type': 'application/json'}, - ); - if (response.statusCode == 201) { - return SavedView.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); - } - throw ErrorMessage(ErrorCode.createSavedViewError, - httpStatusCode: response.statusCode); - } - - @override - Future delete(SavedView view) async { - final response = - await httpClient.delete(Uri.parse("/api/saved_views/${view.id}/")); - if (response.statusCode == 204) { - return view.id!; - } - throw ErrorMessage(ErrorCode.deleteSavedViewError, - httpStatusCode: response.statusCode); - } -} diff --git a/lib/features/documents/view/pages/document_edit_page.dart b/lib/features/documents/view/pages/document_edit_page.dart index d6f2944..6afb833 100644 --- a/lib/features/documents/view/pages/document_edit_page.dart +++ b/lib/features/documents/view/pages/document_edit_page.dart @@ -6,26 +6,15 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:intl/intl.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/pages/add_correspondent_page.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; import 'package:paperless_mobile/features/labels/document_type/view/pages/add_document_type_page.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; import 'package:paperless_mobile/features/labels/storage_path/view/pages/add_storage_path_page.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart'; @@ -62,7 +51,8 @@ class _DocumentEditPageState extends State { @override void initState() { super.initState(); - documentBytes = getIt().getPreview(widget.document.id); + documentBytes = + getIt().getPreview(widget.document.id); } @override @@ -92,7 +82,7 @@ class _DocumentEditPageState extends State { try { await widget.onEdit(updatedDocument); showSnackBar(context, S.of(context).documentUpdateSuccessMessage); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } finally { setState(() { diff --git a/lib/features/documents/view/pages/document_view.dart b/lib/features/documents/view/pages/document_view.dart index 5f7e83c..f4a3348 100644 --- a/lib/features/documents/view/pages/document_view.dart +++ b/lib/features/documents/view/pages/document_view.dart @@ -1,8 +1,5 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:pdfx/pdfx.dart'; diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index e120d20..fd8beeb 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -1,16 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart'; import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/features/documents/view/widgets/documents_empty_state.dart'; import 'package:paperless_mobile/features/documents/view/widgets/grid/document_grid.dart'; import 'package:paperless_mobile/features/documents/view/widgets/list/document_list.dart'; @@ -48,7 +45,7 @@ class _DocumentsPageState extends State { super.initState(); try { BlocProvider.of(context).load(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } _pagingController.addPageRequestListener(_loadNewPage); @@ -69,7 +66,7 @@ class _DocumentsPageState extends State { } try { await documentsCubit.loadMore(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } @@ -83,7 +80,7 @@ class _DocumentsPageState extends State { await BlocProvider.of(context).updateCurrentFilter( (filter) => filter.copyWith(page: 1), ); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } @@ -254,7 +251,8 @@ class _DocumentsPageState extends State { value: BlocProvider.of(context), ), BlocProvider.value( - value: DocumentDetailsCubit(getIt(), document), + value: + DocumentDetailsCubit(getIt(), document), ), ], child: const DocumentDetailsPage(), @@ -281,7 +279,7 @@ class _DocumentsPageState extends State { ), ); } - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException 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 4317d45..bc6b761 100644 --- a/lib/features/documents/view/widgets/delete_document_confirmation_dialog.dart +++ b/lib/features/documents/view/widgets/delete_document_confirmation_dialog.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/generated/l10n.dart'; class DeleteDocumentConfirmationDialog extends StatelessWidget { diff --git a/lib/features/documents/view/widgets/document_preview.dart b/lib/features/documents/view/widgets/document_preview.dart index e99c8ad..482a61b 100644 --- a/lib/features/documents/view/widgets/document_preview.dart +++ b/lib/features/documents/view/widgets/document_preview.dart @@ -1,8 +1,8 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:shimmer/shimmer.dart'; class DocumentPreview extends StatelessWidget { @@ -30,7 +30,7 @@ class DocumentPreview extends StatelessWidget { fit: fit, alignment: Alignment.topCenter, cacheKey: "thumb_$id", - imageUrl: getIt().getThumbnailUrl(id), + imageUrl: getIt().getThumbnailUrl(id), errorWidget: (ctxt, msg, __) => Text(msg), placeholder: (context, value) => Shimmer.fromColors( baseColor: Colors.grey[300]!, diff --git a/lib/features/documents/view/widgets/documents_empty_state.dart b/lib/features/documents/view/widgets/documents_empty_state.dart index 9bcbb2c..60f47e9 100644 --- a/lib/features/documents/view/widgets/documents_empty_state.dart +++ b/lib/features/documents/view/widgets/documents_empty_state.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/empty_state.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; import 'package:paperless_mobile/features/saved_view/bloc/saved_view_cubit.dart'; import 'package:paperless_mobile/generated/l10n.dart'; -import 'package:paperless_mobile/util.dart'; class DocumentsEmptyState extends StatelessWidget { final DocumentsState state; diff --git a/lib/features/documents/view/widgets/grid/document_grid.dart b/lib/features/documents/view/widgets/grid/document_grid.dart index 911e1ba..bf0ca40 100644 --- a/lib/features/documents/view/widgets/grid/document_grid.dart +++ b/lib/features/documents/view/widgets/grid/document_grid.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; import 'package:paperless_mobile/features/documents/view/widgets/grid/document_grid_item.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; diff --git a/lib/features/documents/view/widgets/grid/document_grid_item.dart b/lib/features/documents/view/widgets/grid/document_grid_item.dart index 0463f9e..84a8956 100644 --- a/lib/features/documents/view/widgets/grid/document_grid_item.dart +++ b/lib/features/documents/view/widgets/grid/document_grid_item.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart'; import 'package:paperless_mobile/features/labels/document_type/view/widgets/document_type_widget.dart'; diff --git a/lib/features/documents/view/widgets/list/document_list.dart b/lib/features/documents/view/widgets/list/document_list.dart index 5556b64..f8fb268 100644 --- a/lib/features/documents/view/widgets/list/document_list.dart +++ b/lib/features/documents/view/widgets/list/document_list.dart @@ -1,12 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.dart'; import 'package:paperless_mobile/core/widgets/offline_widget.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; import 'package:paperless_mobile/features/documents/view/widgets/list/document_list_item.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; class DocumentListView extends StatelessWidget { final void Function(DocumentModel) onTap; diff --git a/lib/features/documents/view/widgets/list/document_list_item.dart b/lib/features/documents/view/widgets/list/document_list_item.dart index 1551c4d..ec5e4d4 100644 --- a/lib/features/documents/view/widgets/list/document_list_item.dart +++ b/lib/features/documents/view/widgets/list/document_list_item.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.dart'; class DocumentListItem extends StatelessWidget { diff --git a/lib/features/documents/view/widgets/order_by_dropdown.dart b/lib/features/documents/view/widgets/order_by_dropdown.dart index 32f8a12..2432e6e 100644 --- a/lib/features/documents/view/widgets/order_by_dropdown.dart +++ b/lib/features/documents/view/widgets/order_by_dropdown.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; +import 'package:paperless_api/paperless_api.dart'; class OrderByDropdown extends StatefulWidget { static const fkOrderBy = "orderBy"; diff --git a/lib/features/documents/view/widgets/search/document_filter_panel.dart b/lib/features/documents/view/widgets/search/document_filter_panel.dart index 5f26517..0bbc980 100644 --- a/lib/features/documents/view/widgets/search/document_filter_panel.dart +++ b/lib/features/documents/view/widgets/search/document_filter_panel.dart @@ -1,25 +1,15 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/query_type.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; import 'package:paperless_mobile/features/documents/view/widgets/search/query_type_form_field.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart'; import 'package:paperless_mobile/features/saved_view/bloc/saved_view_cubit.dart'; @@ -468,7 +458,7 @@ class _DocumentFilterPanelState extends State { BlocProvider.of(context).resetSelection(); FocusScope.of(context).unfocus(); widget.panelController.close(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/documents/view/widgets/search/query_type_form_field.dart b/lib/features/documents/view/widgets/search/query_type_form_field.dart index d421ece..d32123f 100644 --- a/lib/features/documents/view/widgets/search/query_type_form_field.dart +++ b/lib/features/documents/view/widgets/search/query_type_form_field.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/query_type.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/generated/l10n.dart'; class QueryTypeFormField extends StatelessWidget { diff --git a/lib/features/documents/view/widgets/search/sort_field_selection_bottom_sheet.dart b/lib/features/documents/view/widgets/search/sort_field_selection_bottom_sheet.dart index b0b9e3e..5041b3c 100644 --- a/lib/features/documents/view/widgets/search/sort_field_selection_bottom_sheet.dart +++ b/lib/features/documents/view/widgets/search/sort_field_selection_bottom_sheet.dart @@ -1,12 +1,9 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; @@ -20,16 +17,6 @@ class SortFieldSelectionBottomSheet extends StatefulWidget { class _SortFieldSelectionBottomSheetState extends State { - static const _sortFields = [ - SortField.created, - SortField.added, - SortField.modified, - SortField.title, - SortField.correspondentName, - SortField.documentType, - SortField.archiveSerialNumber - ]; - SortField? _selectedFieldLoading; SortOrder? _selectedOrderLoading; @@ -49,7 +36,7 @@ class _SortFieldSelectionBottomSheetState ).padded( const EdgeInsets.symmetric(horizontal: 16, vertical: 16)), Column( - children: _sortFields + children: SortField.values .map( (e) => _buildSortOption( e, 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 5a8ae1c..34c8f0d 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 @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; import 'package:paperless_mobile/generated/l10n.dart'; class BulkDeleteConfirmationDialog extends StatelessWidget { diff --git a/lib/features/documents/view/widgets/selection/confirm_delete_saved_view_dialog.dart b/lib/features/documents/view/widgets/selection/confirm_delete_saved_view_dialog.dart index 885c7a1..422e5d8 100644 --- a/lib/features/documents/view/widgets/selection/confirm_delete_saved_view_dialog.dart +++ b/lib/features/documents/view/widgets/selection/confirm_delete_saved_view_dialog.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/generated/l10n.dart'; class ConfirmDeleteSavedViewDialog extends StatelessWidget { diff --git a/lib/features/documents/view/widgets/selection/documents_page_app_bar.dart b/lib/features/documents/view/widgets/selection/documents_page_app_bar.dart index 7d40660..ad09ea6 100644 --- a/lib/features/documents/view/widgets/selection/documents_page_app_bar.dart +++ b/lib/features/documents/view/widgets/selection/documents_page_app_bar.dart @@ -1,12 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; import 'package:paperless_mobile/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart'; -import 'package:paperless_mobile/features/documents/view/widgets/selection/saved_view_selection_widget.dart'; -import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart'; +import 'package:paperless_mobile/features/saved_view/view/saved_view_selection_widget.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/util.dart'; @@ -104,7 +102,7 @@ class _DocumentsPageAppBarState extends State { context, S.of(context).documentsPageBulkDeleteSuccessfulText, ); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/documents/view/widgets/sort_documents_button.dart b/lib/features/documents/view/widgets/sort_documents_button.dart index 64929cc..de56c46 100644 --- a/lib/features/documents/view/widgets/sort_documents_button.dart +++ b/lib/features/documents/view/widgets/sort_documents_button.dart @@ -1,18 +1,8 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:paperless_mobile/features/documents/view/widgets/search/sort_field_selection_bottom_sheet.dart'; -import 'package:paperless_mobile/generated/l10n.dart'; -import 'package:paperless_mobile/util.dart'; class SortDocumentsButton extends StatefulWidget { const SortDocumentsButton({ diff --git a/lib/features/home/view/home_page.dart b/lib/features/home/view/home_page.dart index f2c3d36..01610d9 100644 --- a/lib/features/home/view/home_page.dart +++ b/lib/features/home/view/home_page.dart @@ -1,9 +1,8 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/core/widgets/offline_banner.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; @@ -90,7 +89,7 @@ class _HomePageState extends State { getIt().initialize(), getIt().initialize(), ]); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); return Future.error(error); } diff --git a/lib/features/home/view/widget/info_drawer.dart b/lib/features/home/view/widget/info_drawer.dart index 66cf6fd..b5184f9 100644 --- a/lib/features/home/view/widget/info_drawer.dart +++ b/lib/features/home/view/widget/info_drawer.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/model/paperless_server_information.dart'; +import 'package:paperless_mobile/core/bloc/paperless_server_information_state.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; @@ -67,8 +67,12 @@ class InfoDrawer extends StatelessWidget { Align( alignment: Alignment.bottomRight, child: BlocBuilder( + PaperlessServerInformationState>( builder: (context, state) { + if (!state.isLoaded) { + return Container(); + } + final info = state.information!; return Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ @@ -77,7 +81,7 @@ class InfoDrawer extends StatelessWidget { dense: true, title: Text( S.of(context).appDrawerHeaderLoggedInAsText + - (state.username ?? '?'), + (info.username ?? '?'), style: Theme.of(context).textTheme.bodyText2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.end, @@ -87,7 +91,7 @@ class InfoDrawer extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( - state.host ?? '', + state.information!.host ?? '', style: Theme.of(context).textTheme.bodyText2, overflow: TextOverflow.ellipsis, @@ -95,7 +99,7 @@ class InfoDrawer extends StatelessWidget { maxLines: 1, ), Text( - '${S.of(context).serverInformationPaperlessVersionText} ${state.version} (API v${state.apiVersion})', + '${S.of(context).serverInformationPaperlessVersionText} ${info.version} (API v${info.apiVersion})', style: Theme.of(context).textTheme.caption, overflow: TextOverflow.ellipsis, textAlign: TextAlign.end, @@ -189,7 +193,7 @@ class InfoDrawer extends StatelessWidget { getIt().reset(); getIt().reset(); getIt().reset(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } }, diff --git a/lib/features/inbox/bloc/inbox_cubit.dart b/lib/features/inbox/bloc/inbox_cubit.dart index 9f7a18e..5f086d9 100644 --- a/lib/features/inbox/bloc/inbox_cubit.dart +++ b/lib/features/inbox/bloc/inbox_cubit.dart @@ -1,28 +1,20 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/features/documents/model/bulk_edit.model.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/inbox/bloc/state/inbox_state.dart'; -import 'package:paperless_mobile/features/labels/repository/label_repository.dart'; @injectable class InboxCubit extends Cubit { - final LabelRepository _labelRepository; - final DocumentRepository _documentRepository; + final PaperlessLabelsApi _labelApi; + final PaperlessDocumentsApi _documentsApi; - InboxCubit(this._labelRepository, this._documentRepository) - : super(const InboxState()); + InboxCubit(this._labelApi, this._documentsApi) : super(const InboxState()); /// /// Fetches inbox tag ids and loads the inbox items (documents). /// Future loadInbox() async { - final inboxTags = await _labelRepository.getTags().then( + final inboxTags = await _labelApi.getTags().then( (tags) => tags.where((t) => t.isInboxTag ?? false).map((t) => t.id!), ); if (inboxTags.isEmpty) { @@ -33,7 +25,7 @@ class InboxCubit extends Cubit { inboxTags: [], )); } - final inboxDocuments = await _documentRepository + final inboxDocuments = await _documentsApi .find(DocumentFilter( tags: AnyAssignedTagsQuery(tagIds: inboxTags), sortField: SortField.added, @@ -57,7 +49,7 @@ class InboxCubit extends Cubit { final updatedTags = {...document.tags}..removeAll(tagsToRemove); - await _documentRepository.update( + await _documentsApi.update( document.copyWith( tags: updatedTags, overwriteTags: true, @@ -85,7 +77,7 @@ class InboxCubit extends Cubit { tags: {...document.tags, ...removedTags}, overwriteTags: true, ); - await _documentRepository.update(updatedDoc); + await _documentsApi.update(updatedDoc); emit( InboxState( isLoaded: true, @@ -100,7 +92,7 @@ class InboxCubit extends Cubit { /// Removes inbox tags from all documents in the inbox. /// Future clearInbox() async { - await _documentRepository.bulkAction( + await _documentsApi.bulkAction( BulkModifyTagsAction.removeTags( state.inboxItems.map((e) => e.id), state.inboxTags, diff --git a/lib/features/inbox/bloc/state/inbox_state.dart b/lib/features/inbox/bloc/state/inbox_state.dart index 9853dbb..8dd2cac 100644 --- a/lib/features/inbox/bloc/state/inbox_state.dart +++ b/lib/features/inbox/bloc/state/inbox_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; +import 'package:paperless_api/paperless_api.dart'; class InboxState with EquatableMixin { final bool isLoaded; diff --git a/lib/features/inbox/view/pages/inbox_page.dart b/lib/features/inbox/view/pages/inbox_page.dart index b9bedcb..951897f 100644 --- a/lib/features/inbox/view/pages/inbox_page.dart +++ b/lib/features/inbox/view/pages/inbox_page.dart @@ -1,19 +1,18 @@ +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.dart'; +import 'package:paperless_mobile/extensions/dart_extensions.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; import 'package:paperless_mobile/features/inbox/bloc/inbox_cubit.dart'; import 'package:paperless_mobile/features/inbox/bloc/state/inbox_state.dart'; -import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart'; import 'package:paperless_mobile/features/inbox/view/widgets/inbox_empty_widget.dart'; +import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/util.dart'; -import 'package:collection/collection.dart'; -import 'package:paperless_mobile/extensions/dart_extensions.dart'; class InboxPage extends StatefulWidget { const InboxPage({super.key}); @@ -230,13 +229,13 @@ class _InboxPageState extends State { ), ); return true; - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); return false; } catch (error) { showErrorMessage( context, - const ErrorMessage.unknown(), + const PaperlessServerException.unknown(), ); return false; } @@ -249,7 +248,7 @@ class _InboxPageState extends State { try { await BlocProvider.of(context) .undoRemove(document, removedTags); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/inbox/view/widgets/inbox_empty_widget.dart b/lib/features/inbox/view/widgets/inbox_empty_widget.dart index 485927c..b9db3c7 100644 --- a/lib/features/inbox/view/widgets/inbox_empty_widget.dart +++ b/lib/features/inbox/view/widgets/inbox_empty_widget.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_mobile/features/inbox/bloc/inbox_cubit.dart'; +import 'package:paperless_mobile/generated/l10n.dart'; class InboxEmptyWidget extends StatelessWidget { const InboxEmptyWidget({ @@ -22,11 +23,11 @@ class InboxEmptyWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('You do not have unseen documents.'), + Text(S.of(context).inboxPageNoNewDocumentsText), TextButton( onPressed: () => _emptyStateRefreshIndicatorKey.currentState?.show(), - child: Text('Refresh'), + child: Text(S.of(context).inboxPageNoNewDocumentsRefreshLabel), ), ], ), diff --git a/lib/features/inbox/view/widgets/inbox_item.dart b/lib/features/inbox/view/widgets/inbox_item.dart index bc0901c..d0c9d09 100644 --- a/lib/features/inbox/view/widgets/inbox_item.dart +++ b/lib/features/inbox/view/widgets/inbox_item.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart'; import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.dart'; @@ -54,7 +53,7 @@ class InboxItem extends StatelessWidget { additionalProviders: [ BlocProvider( create: (context) => DocumentDetailsCubit( - getIt(), + getIt(), document, ), ), diff --git a/lib/features/labels/bloc/label_cubit.dart b/lib/features/labels/bloc/label_cubit.dart index c4bc823..3ad09ce 100644 --- a/lib/features/labels/bloc/label_cubit.dart +++ b/lib/features/labels/bloc/label_cubit.dart @@ -1,13 +1,12 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; -import 'package:paperless_mobile/features/labels/repository/label_repository.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; abstract class LabelCubit extends Cubit> { - final LabelRepository labelRepository; + final PaperlessLabelsApi labelsApi; - LabelCubit(this.labelRepository) : super(LabelState.initial()); + LabelCubit(this.labelsApi) : super(LabelState.initial()); @protected void loadFrom(Iterable items) { diff --git a/lib/features/labels/model/label_state.dart b/lib/features/labels/bloc/label_state.dart similarity index 81% rename from lib/features/labels/model/label_state.dart rename to lib/features/labels/bloc/label_state.dart index b47ae48..5f7c860 100644 --- a/lib/features/labels/model/label_state.dart +++ b/lib/features/labels/bloc/label_state.dart @@ -1,4 +1,4 @@ -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_api/paperless_api.dart'; class LabelState { LabelState.initial() : this(isLoaded: false, labels: {}); diff --git a/lib/features/labels/correspondent/bloc/correspondents_cubit.dart b/lib/features/labels/correspondent/bloc/correspondents_cubit.dart index 6bb70c9..1265275 100644 --- a/lib/features/labels/correspondent/bloc/correspondents_cubit.dart +++ b/lib/features/labels/correspondent/bloc/correspondents_cubit.dart @@ -1,5 +1,5 @@ +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:injectable/injectable.dart'; @singleton @@ -8,18 +8,17 @@ class CorrespondentCubit extends LabelCubit { @override Future initialize() async { - return labelRepository.getCorrespondents().then(loadFrom); + return labelsApi.getCorrespondents().then(loadFrom); } @override Future save(Correspondent item) => - labelRepository.saveCorrespondent(item); + labelsApi.saveCorrespondent(item); @override Future update(Correspondent item) => - labelRepository.updateCorrespondent(item); + labelsApi.updateCorrespondent(item); @override - Future delete(Correspondent item) => - labelRepository.deleteCorrespondent(item); + Future delete(Correspondent item) => labelsApi.deleteCorrespondent(item); } diff --git a/lib/features/labels/correspondent/view/pages/add_correspondent_page.dart b/lib/features/labels/correspondent/view/pages/add_correspondent_page.dart index 51dca79..6ab6e03 100644 --- a/lib/features/labels/correspondent/view/pages/add_correspondent_page.dart +++ b/lib/features/labels/correspondent/view/pages/add_correspondent_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:paperless_mobile/features/labels/view/pages/add_label_page.dart'; import 'package:paperless_mobile/generated/l10n.dart'; diff --git a/lib/features/labels/correspondent/view/pages/edit_correspondent_page.dart b/lib/features/labels/correspondent/view/pages/edit_correspondent_page.dart index b6b32db..644b041 100644 --- a/lib/features/labels/correspondent/view/pages/edit_correspondent_page.dart +++ b/lib/features/labels/correspondent/view/pages/edit_correspondent_page.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:paperless_mobile/features/labels/view/pages/edit_label_page.dart'; import 'package:paperless_mobile/util.dart'; @@ -38,7 +35,7 @@ class EditCorrespondentPage extends StatelessWidget { ); } Navigator.pop(context); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/correspondent/view/widgets/correspondent_widget.dart b/lib/features/labels/correspondent/view/widgets/correspondent_widget.dart index e499e91..986cbe7 100644 --- a/lib/features/labels/correspondent/view/widgets/correspondent_widget.dart +++ b/lib/features/labels/correspondent/view/widgets/correspondent_widget.dart @@ -1,12 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/di_initializer.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/util.dart'; class CorrespondentWidget extends StatelessWidget { @@ -60,7 +57,7 @@ class CorrespondentWidget extends StatelessWidget { ); } afterSelected?.call(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/document_type/bloc/document_type_cubit.dart b/lib/features/labels/document_type/bloc/document_type_cubit.dart index f10a6b6..347b32f 100644 --- a/lib/features/labels/document_type/bloc/document_type_cubit.dart +++ b/lib/features/labels/document_type/bloc/document_type_cubit.dart @@ -1,6 +1,5 @@ -import 'package:flutter/foundation.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; import 'package:injectable/injectable.dart'; @singleton @@ -9,18 +8,17 @@ class DocumentTypeCubit extends LabelCubit { @override Future initialize() async { - labelRepository.getDocumentTypes().then(loadFrom); + labelsApi.getDocumentTypes().then(loadFrom); } @override Future save(DocumentType item) => - labelRepository.saveDocumentType(item); + labelsApi.saveDocumentType(item); @override Future update(DocumentType item) => - labelRepository.updateDocumentType(item); + labelsApi.updateDocumentType(item); @override - Future delete(DocumentType item) => - labelRepository.deleteDocumentType(item); + Future delete(DocumentType item) => labelsApi.deleteDocumentType(item); } diff --git a/lib/features/labels/document_type/view/pages/add_document_type_page.dart b/lib/features/labels/document_type/view/pages/add_document_type_page.dart index f05491c..b4aabc5 100644 --- a/lib/features/labels/document_type/view/pages/add_document_type_page.dart +++ b/lib/features/labels/document_type/view/pages/add_document_type_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; import 'package:paperless_mobile/features/labels/view/pages/add_label_page.dart'; import 'package:paperless_mobile/generated/l10n.dart'; diff --git a/lib/features/labels/document_type/view/pages/edit_document_type_page.dart b/lib/features/labels/document_type/view/pages/edit_document_type_page.dart index 5faec7e..11dbda7 100644 --- a/lib/features/labels/document_type/view/pages/edit_document_type_page.dart +++ b/lib/features/labels/document_type/view/pages/edit_document_type_page.dart @@ -1,11 +1,8 @@ import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; import 'package:paperless_mobile/features/labels/view/pages/edit_label_page.dart'; import 'package:paperless_mobile/util.dart'; @@ -33,8 +30,8 @@ class EditDocumentTypePage extends StatelessWidget { .copyWith(documentType: const DocumentTypeQuery.unset()), ); } - } on ErrorMessage catch (e) { - showSnackBar(context, translateError(context, e.code)); + } on PaperlessServerException catch (error, stackTrace) { + showErrorMessage(context, error, stackTrace); } finally { Navigator.pop(context); } diff --git a/lib/features/labels/document_type/view/widgets/document_type_widget.dart b/lib/features/labels/document_type/view/widgets/document_type_widget.dart index 9655ce3..d9ad55b 100644 --- a/lib/features/labels/document_type/view/widgets/document_type_widget.dart +++ b/lib/features/labels/document_type/view/widgets/document_type_widget.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/util.dart'; class DocumentTypeWidget extends StatelessWidget { @@ -55,7 +53,7 @@ class DocumentTypeWidget extends StatelessWidget { ); } afterSelected?.call(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/storage_path/bloc/storage_path_cubit.dart b/lib/features/labels/storage_path/bloc/storage_path_cubit.dart index a2ac69d..507a096 100644 --- a/lib/features/labels/storage_path/bloc/storage_path_cubit.dart +++ b/lib/features/labels/storage_path/bloc/storage_path_cubit.dart @@ -1,6 +1,6 @@ import 'package:injectable/injectable.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; @singleton class StoragePathCubit extends LabelCubit { @@ -8,18 +8,16 @@ class StoragePathCubit extends LabelCubit { @override Future initialize() async { - return labelRepository.getStoragePaths().then(loadFrom); + return labelsApi.getStoragePaths().then(loadFrom); } @override - Future save(StoragePath item) => - labelRepository.saveStoragePath(item); + Future save(StoragePath item) => labelsApi.saveStoragePath(item); @override Future update(StoragePath item) => - labelRepository.updateStoragePath(item); + labelsApi.updateStoragePath(item); @override - Future delete(StoragePath item) => - labelRepository.deleteStoragePath(item); + Future delete(StoragePath item) => labelsApi.deleteStoragePath(item); } diff --git a/lib/features/labels/storage_path/view/pages/add_storage_path_page.dart b/lib/features/labels/storage_path/view/pages/add_storage_path_page.dart index 2c83293..7dd6227 100644 --- a/lib/features/labels/storage_path/view/pages/add_storage_path_page.dart +++ b/lib/features/labels/storage_path/view/pages/add_storage_path_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart'; import 'package:paperless_mobile/features/labels/view/pages/add_label_page.dart'; import 'package:paperless_mobile/generated/l10n.dart'; diff --git a/lib/features/labels/storage_path/view/pages/edit_storage_path_page.dart b/lib/features/labels/storage_path/view/pages/edit_storage_path_page.dart index cce1bab..8a4d5b5 100644 --- a/lib/features/labels/storage_path/view/pages/edit_storage_path_page.dart +++ b/lib/features/labels/storage_path/view/pages/edit_storage_path_page.dart @@ -1,11 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart'; import 'package:paperless_mobile/features/labels/view/pages/edit_label_page.dart'; import 'package:paperless_mobile/util.dart'; @@ -43,7 +40,7 @@ class EditStoragePathPage extends StatelessWidget { ); } Navigator.pop(context); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/storage_path/view/widgets/storage_path_widget.dart b/lib/features/labels/storage_path/view/widgets/storage_path_widget.dart index a554e60..bb499d2 100644 --- a/lib/features/labels/storage_path/view/widgets/storage_path_widget.dart +++ b/lib/features/labels/storage_path/view/widgets/storage_path_widget.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; import 'package:paperless_mobile/util.dart'; class StoragePathWidget extends StatelessWidget { @@ -59,7 +57,7 @@ class StoragePathWidget extends StatelessWidget { ); } afterSelected?.call(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/tags/bloc/tags_cubit.dart b/lib/features/labels/tags/bloc/tags_cubit.dart index 4af8bed..38cbf76 100644 --- a/lib/features/labels/tags/bloc/tags_cubit.dart +++ b/lib/features/labels/tags/bloc/tags_cubit.dart @@ -1,5 +1,5 @@ +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:injectable/injectable.dart'; @singleton @@ -8,15 +8,15 @@ class TagCubit extends LabelCubit { @override Future initialize() async { - return labelRepository.getTags().then(loadFrom); + return labelsApi.getTags().then(loadFrom); } @override - Future save(Tag item) => labelRepository.saveTag(item); + Future save(Tag item) => labelsApi.saveTag(item); @override - Future update(Tag item) => labelRepository.updateTag(item); + Future update(Tag item) => labelsApi.updateTag(item); @override - Future delete(Tag item) => labelRepository.deleteTag(item); + Future delete(Tag item) => labelsApi.deleteTag(item); } diff --git a/lib/features/labels/tags/view/pages/add_tag_page.dart b/lib/features/labels/tags/view/pages/add_tag_page.dart index b527643..a714cda 100644 --- a/lib/features/labels/tags/view/pages/add_tag_page.dart +++ b/lib/features/labels/tags/view/pages/add_tag_page.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:paperless_mobile/features/labels/view/pages/add_label_page.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:form_builder_extra_fields/form_builder_extra_fields.dart'; diff --git a/lib/features/labels/tags/view/pages/edit_tag_page.dart b/lib/features/labels/tags/view/pages/edit_tag_page.dart index 26e1473..aba0364 100644 --- a/lib/features/labels/tags/view/pages/edit_tag_page.dart +++ b/lib/features/labels/tags/view/pages/edit_tag_page.dart @@ -2,12 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_extra_fields/form_builder_extra_fields.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:paperless_mobile/features/labels/view/pages/edit_label_page.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/util.dart'; @@ -61,7 +58,7 @@ class EditTagPage extends StatelessWidget { } cubit.updateFilter(filter: updatedFilter); Navigator.pop(context); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/tags/view/widgets/tag_widget.dart b/lib/features/labels/tags/view/widgets/tag_widget.dart index 64bb639..bd51682 100644 --- a/lib/features/labels/tags/view/widgets/tag_widget.dart +++ b/lib/features/labels/tags/view/widgets/tag_widget.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; +import 'package:paperless_api/paperless_api.dart'; class TagWidget extends StatelessWidget { final Tag tag; diff --git a/lib/features/labels/tags/view/widgets/tags_form_field.dart b/lib/features/labels/tags/view/widgets/tags_form_field.dart index 5f02490..59a3332 100644 --- a/lib/features/labels/tags/view/widgets/tags_form_field.dart +++ b/lib/features/labels/tags/view/widgets/tags_form_field.dart @@ -2,10 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:paperless_mobile/features/labels/tags/view/pages/add_tag_page.dart'; import 'package:paperless_mobile/generated/l10n.dart'; diff --git a/lib/features/labels/tags/view/widgets/tags_widget.dart b/lib/features/labels/tags/view/widgets/tags_widget.dart index 5b6c256..da091c6 100644 --- a/lib/features/labels/tags/view/widgets/tags_widget.dart +++ b/lib/features/labels/tags/view/widgets/tags_widget.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tag_widget.dart'; class TagsWidget extends StatefulWidget { diff --git a/lib/features/labels/view/pages/add_label_page.dart b/lib/features/labels/view/pages/add_label_page.dart index 7f0bf61..783ba97 100644 --- a/lib/features/labels/view/pages/add_label_page.dart +++ b/lib/features/labels/view/pages/add_label_page.dart @@ -1,17 +1,12 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/util.dart'; -import 'package:form_builder_validators/form_builder_validators.dart'; class AddLabelPage extends StatefulWidget { final String? initialName; @@ -107,8 +102,8 @@ class _AddLabelPageState extends State> { final label = await widget.cubit .add(widget.fromJson(_formKey.currentState!.value)); Navigator.pop(context, label); - } on ErrorMessage catch (e) { - showSnackBar(context, translateError(context, e.code)); + } on PaperlessServerException catch (error, stackTrace) { + showErrorMessage(context, error, stackTrace); } on PaperlessValidationErrors catch (json) { setState(() => _errors = json); } diff --git a/lib/features/labels/view/pages/edit_label_page.dart b/lib/features/labels/view/pages/edit_label_page.dart index 366d386..1eaae5c 100644 --- a/lib/features/labels/view/pages/edit_label_page.dart +++ b/lib/features/labels/view/pages/edit_label_page.dart @@ -3,11 +3,9 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/util.dart'; @@ -146,7 +144,7 @@ class _EditLabelPageState extends State> { Navigator.pop(context); } on PaperlessValidationErrors catch (errorMessages) { setState(() => _errors = errorMessages); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/labels/view/pages/labels_page.dart b/lib/features/labels/view/pages/labels_page.dart index 6fd2f17..ace28ab 100644 --- a/lib/features/labels/view/pages/labels_page.dart +++ b/lib/features/labels/view/pages/labels_page.dart @@ -1,28 +1,20 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; import 'package:paperless_mobile/features/home/view/widget/info_drawer.dart'; +import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/pages/add_correspondent_page.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/pages/edit_correspondent_page.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; import 'package:paperless_mobile/features/labels/document_type/view/pages/add_document_type_page.dart'; import 'package:paperless_mobile/features/labels/document_type/view/pages/edit_document_type_page.dart'; import 'package:paperless_mobile/features/labels/storage_path/bloc/storage_path_cubit.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; import 'package:paperless_mobile/features/labels/storage_path/view/pages/add_storage_path_page.dart'; import 'package:paperless_mobile/features/labels/storage_path/view/pages/edit_storage_path_page.dart'; import 'package:paperless_mobile/features/labels/tags/bloc/tags_cubit.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:paperless_mobile/features/labels/tags/view/pages/add_tag_page.dart'; import 'package:paperless_mobile/features/labels/tags/view/pages/edit_tag_page.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart'; diff --git a/lib/features/labels/view/widgets/label_form_field.dart b/lib/features/labels/view/widgets/label_form_field.dart index 27da9ae..4b1aca8 100644 --- a/lib/features/labels/view/widgets/label_form_field.dart +++ b/lib/features/labels/view/widgets/label_form_field.dart @@ -1,10 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:form_builder_extra_fields/form_builder_extra_fields.dart'; diff --git a/lib/features/labels/view/widgets/label_item.dart b/lib/features/labels/view/widgets/label_item.dart index 5946d6d..82edefe 100644 --- a/lib/features/labels/view/widgets/label_item.dart +++ b/lib/features/labels/view/widgets/label_item.dart @@ -1,13 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; import 'package:paperless_mobile/features/linked_documents_preview/bloc/linked_documents_cubit.dart'; import 'package:paperless_mobile/features/linked_documents_preview/view/pages/linked_documents_page.dart'; diff --git a/lib/features/labels/view/widgets/label_tab_view.dart b/lib/features/labels/view/widgets/label_tab_view.dart index f853bb0..299eb14 100644 --- a/lib/features/labels/view/widgets/label_tab_view.dart +++ b/lib/features/labels/view/widgets/label_tab_view.dart @@ -1,11 +1,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; import 'package:paperless_mobile/core/widgets/offline_widget.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_item.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; diff --git a/lib/features/linked_documents_preview/bloc/linked_documents_cubit.dart b/lib/features/linked_documents_preview/bloc/linked_documents_cubit.dart index 2f23c5c..af270de 100644 --- a/lib/features/linked_documents_preview/bloc/linked_documents_cubit.dart +++ b/lib/features/linked_documents_preview/bloc/linked_documents_cubit.dart @@ -1,18 +1,16 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/linked_documents_preview/bloc/state/linked_documents_state.dart'; @injectable class LinkedDocumentsCubit extends Cubit { - final DocumentRepository _documentRepository; + final PaperlessDocumentsApi _api; - LinkedDocumentsCubit(this._documentRepository) - : super(LinkedDocumentsState()); + LinkedDocumentsCubit(this._api) : super(LinkedDocumentsState()); Future initialize(DocumentFilter filter) async { - final documents = await _documentRepository.find( + final documents = await _api.find( filter.copyWith( pageSize: 100, ), diff --git a/lib/features/linked_documents_preview/bloc/state/linked_documents_state.dart b/lib/features/linked_documents_preview/bloc/state/linked_documents_state.dart index 76f5ace..80482a9 100644 --- a/lib/features/linked_documents_preview/bloc/state/linked_documents_state.dart +++ b/lib/features/linked_documents_preview/bloc/state/linked_documents_state.dart @@ -1,6 +1,4 @@ -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; +import 'package:paperless_api/paperless_api.dart'; class LinkedDocumentsState { final bool isLoaded; diff --git a/lib/features/linked_documents_preview/view/pages/linked_documents_page.dart b/lib/features/linked_documents_preview/view/pages/linked_documents_page.dart index c026ae3..4fec91f 100644 --- a/lib/features/linked_documents_preview/view/pages/linked_documents_page.dart +++ b/lib/features/linked_documents_preview/view/pages/linked_documents_page.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart'; import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/features/documents/view/widgets/list/document_list_item.dart'; import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; import 'package:paperless_mobile/features/linked_documents_preview/bloc/linked_documents_cubit.dart'; @@ -69,7 +68,7 @@ class _LinkedDocumentsPageState extends State { additionalProviders: [ BlocProvider.value( value: DocumentDetailsCubit( - getIt(), + getIt(), document, ), ), diff --git a/lib/features/login/bloc/authentication_cubit.dart b/lib/features/login/bloc/authentication_cubit.dart index fa2692d..e9dbf44 100644 --- a/lib/features/login/bloc/authentication_cubit.dart +++ b/lib/features/login/bloc/authentication_cubit.dart @@ -1,8 +1,8 @@ -import 'dart:developer'; import 'dart:io'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:injectable/injectable.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/store/local_vault.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/login/model/authentication_information.dart'; @@ -10,18 +10,19 @@ import 'package:paperless_mobile/features/login/model/client_certificate.dart'; import 'package:paperless_mobile/features/login/model/user_credentials.model.dart'; import 'package:paperless_mobile/features/login/services/authentication.service.dart'; import 'package:paperless_mobile/features/settings/model/application_settings_state.dart'; -import 'package:injectable/injectable.dart'; const authenticationKey = "authentication"; @singleton class AuthenticationCubit extends Cubit { + final LocalAuthenticationService _localAuthService; + final PaperlessAuthenticationApi _authApi; final LocalVault localStore; - final AuthenticationService authenticationService; AuthenticationCubit( this.localStore, - this.authenticationService, + this._localAuthService, + this._authApi, ) : super(AuthenticationState.initial); Future initialize() { @@ -49,7 +50,7 @@ class AuthenticationCubit extends Cubit { ), ), ); - final token = await authenticationService.login( + final token = await _authApi.login( username: credentials.username!, password: credentials.password!, serverUrl: serverUrl, @@ -70,14 +71,14 @@ class AuthenticationCubit extends Cubit { authentication: auth, )); } on TlsException catch (_) { - const error = - ErrorMessage(ErrorCode.invalidClientCertificateConfiguration); + const error = PaperlessServerException( + ErrorCode.invalidClientCertificateConfiguration); throw error; } on SocketException catch (err) { if (err.message.contains("connection timed out")) { - throw const ErrorMessage(ErrorCode.requestTimedOut); + throw const PaperlessServerException(ErrorCode.requestTimedOut); } else { - throw ErrorMessage.unknown(); + throw const PaperlessServerException.unknown(); } } } @@ -95,7 +96,7 @@ class AuthenticationCubit extends Cubit { emit(AuthenticationState(isAuthenticated: false, wasLoginStored: false)); } else { if (!appSettings.isLocalAuthenticationEnabled || - await authenticationService + await _localAuthService .authenticateLocalUser("Authenticate to log back in")) { registerSecurityContext(storedAuth.clientCertificate); emit( diff --git a/lib/features/login/bloc/local_authentication_cubit.dart b/lib/features/login/bloc/local_authentication_cubit.dart index d72ebe1..33e50ec 100644 --- a/lib/features/login/bloc/local_authentication_cubit.dart +++ b/lib/features/login/bloc/local_authentication_cubit.dart @@ -1,5 +1,5 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:local_auth/local_auth.dart'; @@ -12,7 +12,8 @@ class LocalAuthenticationCubit extends Cubit { if (isAuthenticationSuccessful) { emit(LocalAuthenticationState(true)); } else { - throw const ErrorMessage(ErrorCode.biometricAuthenticationFailed); + throw const PaperlessServerException( + ErrorCode.biometricAuthenticationFailed); } } } diff --git a/lib/features/login/services/authentication.service.dart b/lib/features/login/services/authentication.service.dart index 52943fc..1d7eee5 100644 --- a/lib/features/login/services/authentication.service.dart +++ b/lib/features/login/services/authentication.service.dart @@ -1,57 +1,17 @@ -import 'dart:convert'; - -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/store/local_vault.dart'; -import 'package:http/http.dart'; import 'package:injectable/injectable.dart'; import 'package:local_auth/local_auth.dart'; +import 'package:paperless_mobile/core/store/local_vault.dart'; @singleton -class AuthenticationService { - final BaseClient httpClient; +class LocalAuthenticationService { final LocalVault localStore; final LocalAuthentication localAuthentication; - AuthenticationService( + LocalAuthenticationService( this.localStore, this.localAuthentication, - @Named("timeoutClient") this.httpClient, ); - /// - /// Returns the authentication token. - /// - Future login({ - required String username, - required String password, - required String serverUrl, - }) async { - late Response response; - try { - response = await httpClient.post( - Uri.parse("/api/token/"), - body: {"username": username, "password": password}, - ); - } on FormatException catch (e) { - final source = e.source; - if (source is String && - source.contains("400 No required SSL certificate was sent")) { - throw const ErrorMessage(ErrorCode.missingClientCertificate); - } - } - if (response.statusCode == 200) { - final data = jsonDecode(utf8.decode(response.bodyBytes)); - return data['token']; - } else if (response.statusCode == 400 && - response.body - .toLowerCase() - .contains("no required certificate was sent")) { - throw const ErrorMessage(ErrorCode.invalidClientCertificateConfiguration); - } else { - throw const ErrorMessage(ErrorCode.authenticationFailed); - } - } - Future authenticateLocalUser(String localizedReason) async { if (await localAuthentication.isDeviceSupported()) { return await localAuthentication.authenticate( diff --git a/lib/features/login/view/login_page.dart b/lib/features/login/view/login_page.dart index 393972e..8ce3832 100644 --- a/lib/features/login/view/login_page.dart +++ b/lib/features/login/view/login_page.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart'; import 'package:paperless_mobile/features/login/view/widgets/client_certificate_form_field.dart'; @@ -97,12 +97,12 @@ class _LoginPageState extends State { clientCertificate: form[ClientCertificateFormField.fkClientCertificate], ); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } on Map catch (error, stackTrace) { showGenericError(context, error.values.first, stackTrace); } catch (unknownError, stackTrace) { - showErrorMessage(context, ErrorMessage.unknown(), stackTrace); + showGenericError(context, unknownError.toString(), stackTrace); } finally { setState(() => _isLoginLoading = false); } diff --git a/lib/features/saved_view/bloc/saved_view_cubit.dart b/lib/features/saved_view/bloc/saved_view_cubit.dart index 998ec64..f268530 100644 --- a/lib/features/saved_view/bloc/saved_view_cubit.dart +++ b/lib/features/saved_view/bloc/saved_view_cubit.dart @@ -1,20 +1,19 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; -import 'package:paperless_mobile/features/documents/repository/saved_views_repository.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/saved_view/bloc/saved_view_state.dart'; @singleton class SavedViewCubit extends Cubit { - SavedViewCubit() : super(SavedViewState(value: {})); + final PaperlessSavedViewsApi _api; + SavedViewCubit(this._api) : super(SavedViewState(value: {})); void selectView(SavedView? view) { emit(SavedViewState(value: state.value, selectedSavedViewId: view?.id)); } Future add(SavedView view) async { - final savedView = await getIt().save(view); + final savedView = await _api.save(view); emit( SavedViewState( value: {...state.value, savedView.id!: savedView}, @@ -25,7 +24,7 @@ class SavedViewCubit extends Cubit { } Future remove(SavedView view) async { - final id = await getIt().delete(view); + final id = await _api.delete(view); final newValue = {...state.value}; newValue.removeWhere((key, value) => key == id); emit( @@ -40,7 +39,7 @@ class SavedViewCubit extends Cubit { } Future initialize() async { - final views = await getIt().getAll(); + final views = await _api.getAll(); final values = {for (var element in views) element.id!: element}; emit(SavedViewState(value: values)); } diff --git a/lib/features/saved_view/bloc/saved_view_state.dart b/lib/features/saved_view/bloc/saved_view_state.dart index b82739b..d46aeac 100644 --- a/lib/features/saved_view/bloc/saved_view_state.dart +++ b/lib/features/saved_view/bloc/saved_view_state.dart @@ -1,5 +1,5 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; +import 'package:paperless_api/paperless_api.dart'; class SavedViewState with EquatableMixin { final Map value; @@ -11,5 +11,8 @@ class SavedViewState with EquatableMixin { }); @override - List get props => [value, selectedSavedViewId]; + List get props => [ + value, + selectedSavedViewId, + ]; } diff --git a/lib/features/documents/view/widgets/selection/add_saved_view_page.dart b/lib/features/saved_view/view/add_saved_view_page.dart similarity index 94% rename from lib/features/documents/view/widgets/selection/add_saved_view_page.dart rename to lib/features/saved_view/view/add_saved_view_page.dart index e0c2bb2..761668e 100644 --- a/lib/features/documents/view/widgets/selection/add_saved_view_page.dart +++ b/lib/features/saved_view/view/add_saved_view_page.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/generated/l10n.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; diff --git a/lib/features/documents/view/widgets/selection/saved_view_selection_widget.dart b/lib/features/saved_view/view/saved_view_selection_widget.dart similarity index 91% rename from lib/features/documents/view/widgets/selection/saved_view_selection_widget.dart rename to lib/features/saved_view/view/saved_view_selection_widget.dart index 94f2e35..61764b3 100644 --- a/lib/features/documents/view/widgets/selection/saved_view_selection_widget.dart +++ b/lib/features/saved_view/view/saved_view_selection_widget.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; -import 'package:paperless_mobile/features/documents/view/widgets/selection/add_saved_view_page.dart'; +import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart'; import 'package:paperless_mobile/features/documents/view/widgets/selection/confirm_delete_saved_view_dialog.dart'; import 'package:paperless_mobile/features/saved_view/bloc/saved_view_cubit.dart'; import 'package:paperless_mobile/features/saved_view/bloc/saved_view_state.dart'; @@ -87,7 +86,7 @@ class SavedViewSelectionWidget extends StatelessWidget { if (newView != null) { try { await BlocProvider.of(context).add(newView); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } @@ -104,7 +103,7 @@ class SavedViewSelectionWidget extends StatelessWidget { BlocProvider.of(context).updateFilter(); BlocProvider.of(context).selectView(null); } - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } @@ -119,7 +118,7 @@ class SavedViewSelectionWidget extends StatelessWidget { if (delete) { try { BlocProvider.of(context).remove(view); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } diff --git a/lib/features/scan/bloc/document_scanner_cubit.dart b/lib/features/scan/bloc/document_scanner_cubit.dart index 3ea1144..60c4e35 100644 --- a/lib/features/scan/bloc/document_scanner_cubit.dart +++ b/lib/features/scan/bloc/document_scanner_cubit.dart @@ -4,18 +4,18 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/di_initializer.dart'; +import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart'; @injectable class DocumentScannerCubit extends Cubit> { - final DocumentRepository documentRepository; + final PaperlessDocumentsApi _api; static List initialState = []; - DocumentScannerCubit(this.documentRepository) : super(initialState); + DocumentScannerCubit(this._api) : super(initialState); void addScan(File file) => emit([...state, file]); @@ -26,7 +26,7 @@ class DocumentScannerCubit extends Cubit> { scans.removeAt(fileIndex); emit(scans); } catch (_) { - throw const ErrorMessage(ErrorCode.scanRemoveFailed); + throw const PaperlessServerException(ErrorCode.scanRemoveFailed); } } @@ -41,7 +41,7 @@ class DocumentScannerCubit extends Cubit> { imageCache.clear(); emit(initialState); } catch (_) { - throw const ErrorMessage(ErrorCode.scanRemoveFailed); + throw const PaperlessServerException(ErrorCode.scanRemoveFailed); } } @@ -55,17 +55,23 @@ class DocumentScannerCubit extends Cubit> { Iterable tags = const [], DateTime? createdAt, }) async { - await documentRepository.create( + final auth = getIt().state.authentication; + if (auth == null) { + throw const PaperlessServerException(ErrorCode.notAuthenticated); + } + await _api.create( bytes, - fileName, + filename: fileName, title: title, documentType: documentType, correspondent: correspondent, tags: tags, createdAt: createdAt, + authToken: auth.token, + serverUrl: auth.serverUrl, ); if (onConsumptionFinished != null) { - documentRepository + _api .waitForConsumptionFinished(fileName, title) .then((value) => onConsumptionFinished(value)); } diff --git a/lib/features/scan/view/document_upload_page.dart b/lib/features/scan/view/document_upload_page.dart index c23ec44..1fd4515 100644 --- a/lib/features/scan/view/document_upload_page.dart +++ b/lib/features/scan/view/document_upload_page.dart @@ -3,23 +3,15 @@ import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/type/types.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; import 'package:paperless_mobile/features/labels/correspondent/bloc/correspondents_cubit.dart'; import 'package:paperless_mobile/features/labels/document_type/bloc/document_type_cubit.dart'; -import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; import 'package:paperless_mobile/features/labels/correspondent/view/pages/add_correspondent_page.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; import 'package:paperless_mobile/features/labels/document_type/view/pages/add_document_type_page.dart'; -import 'package:paperless_mobile/features/labels/model/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart'; import 'package:paperless_mobile/features/scan/bloc/document_scanner_cubit.dart'; @@ -258,12 +250,13 @@ class _DocumentUploadPageState extends State { showSnackBar(context, S.of(context).documentUploadSuccessText); Navigator.pop(context); widget.afterUpload?.call(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); - } on PaperlessValidationErrors catch (errorMessages) { - setState(() => _errors = errorMessages); + } on PaperlessValidationErrors catch (PaperlessServerExceptions) { + setState(() => _errors = PaperlessServerExceptions); } catch (unknownError, stackTrace) { - showErrorMessage(context, const ErrorMessage.unknown(), stackTrace); + showErrorMessage( + context, const PaperlessServerException.unknown(), stackTrace); } finally { setState(() { _isUploadLoading = false; diff --git a/lib/features/scan/view/scanner_page.dart b/lib/features/scan/view/scanner_page.dart index 2389fe6..5df8650 100644 --- a/lib/features/scan/view/scanner_page.dart +++ b/lib/features/scan/view/scanner_page.dart @@ -8,13 +8,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:mime/mime.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; import 'package:paperless_mobile/core/global/constants.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/core/service/file_service.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; import 'package:paperless_mobile/features/documents/view/pages/document_view.dart'; import 'package:paperless_mobile/features/home/view/widget/info_drawer.dart'; import 'package:paperless_mobile/features/scan/bloc/document_scanner_cubit.dart'; @@ -193,7 +190,7 @@ class _ScannerPageState extends State try { BlocProvider.of(context) .removeScan(index); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } }, @@ -206,7 +203,7 @@ class _ScannerPageState extends State void _reset(BuildContext context) { try { BlocProvider.of(context).reset(); - } on ErrorMessage catch (error, stackTrace) { + } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } @@ -231,7 +228,7 @@ class _ScannerPageState extends State )) { showErrorMessage( context, - const ErrorMessage(ErrorCode.unsupportedFileFormat), + const PaperlessServerException(ErrorCode.unsupportedFileFormat), ); return; } diff --git a/lib/features/settings/view/widgets/biometric_authentication_setting.dart b/lib/features/settings/view/widgets/biometric_authentication_setting.dart index cf6d388..6a5c4a9 100644 --- a/lib/features/settings/view/widgets/biometric_authentication_setting.dart +++ b/lib/features/settings/view/widgets/biometric_authentication_setting.dart @@ -28,7 +28,7 @@ class BiometricAuthenticationSetting extends StatelessWidget { : S .of(context) .appSettingsDisableBiometricAuthenticationReasonText; - final changeValue = await getIt() + final changeValue = await getIt() .authenticateLocalUser(localizedReason); if (changeValue) { settingsBloc.setIsBiometricAuthenticationEnabled(val); diff --git a/lib/features/settings/view/widgets/language_selection_setting.dart b/lib/features/settings/view/widgets/language_selection_setting.dart index caad25b..252cb6c 100644 --- a/lib/features/settings/view/widgets/language_selection_setting.dart +++ b/lib/features/settings/view/widgets/language_selection_setting.dart @@ -14,13 +14,18 @@ class LanguageSelectionSetting extends StatefulWidget { } class _LanguageSelectionSettingState extends State { + static const _languageOptions = { + 'en': 'English', + 'de': 'Deutsch', + 'cs': 'Česky', + }; @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, settings) { return ListTile( title: Text(S.of(context).settingsPageLanguageSettingLabel), - subtitle: Text(_mapSubtagToLanguage(settings.preferredLocaleSubtag)), + subtitle: Text(_languageOptions[settings.preferredLocaleSubtag]!), onTap: () => showDialog( context: context, builder: (_) => RadioSettingsDialog( @@ -28,12 +33,16 @@ class _LanguageSelectionSettingState extends State { options: [ RadioOption( value: 'en', - label: _mapSubtagToLanguage('en'), + label: _languageOptions['en']!, ), RadioOption( value: 'de', - label: _mapSubtagToLanguage('de'), + label: _languageOptions['de']!, ), + RadioOption( + value: 'cs', + label: _languageOptions['cs']!, + ) ], initialValue: BlocProvider.of(context) .state @@ -45,15 +54,4 @@ class _LanguageSelectionSettingState extends State { }, ); } - - _mapSubtagToLanguage(String subtag) { - switch (subtag) { - case 'en': - return "English"; - case 'de': - return "Deutsch"; - default: - return "English"; - } - } } diff --git a/lib/l10n/intl_cs.arb b/lib/l10n/intl_cs.arb index 609a34b..c80f288 100644 --- a/lib/l10n/intl_cs.arb +++ b/lib/l10n/intl_cs.arb @@ -415,5 +415,7 @@ "tagInboxTagPropertyLabel": "Tag inboxu", "@tagInboxTagPropertyLabel": {}, "uploadPageAutomaticallInferredFieldsHintText": "Pokud specifikuješ hodnoty pro tato pole, paperless instance nebude automaticky přiřazovat naučené hodnoty. Pokud mají být tato pole automaticky vyplňována, nevyplňujte zde nic.", - "@uploadPageAutomaticallInferredFieldsHintText": {} -} + "@uploadPageAutomaticallInferredFieldsHintText": {}, + "inboxPageNoNewDocumentsText": "You do not have unseen documents.", + "inboxPageNoNewDocumentsRefreshLabel": "Refresh" +} \ No newline at end of file diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index ff964ed..3167197 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -415,5 +415,7 @@ "tagInboxTagPropertyLabel": "Posteingangs-Tag", "@tagInboxTagPropertyLabel": {}, "uploadPageAutomaticallInferredFieldsHintText": "Wenn Werte für diese Felder angegeben werden, wird Paperless nicht automatisch einen Wert zuweisen. Wenn diese Felder automatisch von Paperless erkannt werden sollen, sollten die Felder leer bleiben.", - "@uploadPageAutomaticallInferredFieldsHintText": {} + "@uploadPageAutomaticallInferredFieldsHintText": {}, + "inboxPageNoNewDocumentsText": "You do not have unseen documents.", + "inboxPageNoNewDocumentsRefreshLabel": "Refresh" } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index ce3e64e..3d81f8e 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,419 +1,421 @@ { - "@@locale": "en", - "aboutDialogDevelopedByText": "Developed by", - "@aboutDialogDevelopedByText": {}, - "addCorrespondentPageTitle": "New Correspondent", - "@addCorrespondentPageTitle": {}, - "addDocumentTypePageTitle": "New Document Type", - "@addDocumentTypePageTitle": {}, - "addStoragePathPageTitle": "New Storage Path", - "@addStoragePathPageTitle": {}, - "addTagPageTitle": "New Tag", - "@addTagPageTitle": {}, - "appDrawerAboutInfoLoadingText": "Retrieving application information...", - "@appDrawerAboutInfoLoadingText": {}, - "appDrawerAboutLabel": "About this app", - "@appDrawerAboutLabel": {}, - "appDrawerHeaderLoggedInAsText": "Logged in as ", - "@appDrawerHeaderLoggedInAsText": {}, - "appDrawerLogoutLabel": "Disconnect", - "@appDrawerLogoutLabel": {}, - "appDrawerReportBugLabel": "Report a Bug", - "@appDrawerReportBugLabel": {}, - "appDrawerSettingsLabel": "Settings", - "@appDrawerSettingsLabel": {}, - "appSettingsBiometricAuthenticationDescriptionText": "Authenticate on app start", - "@appSettingsBiometricAuthenticationDescriptionText": {}, - "appSettingsBiometricAuthenticationLabel": "Biometric authentication", - "@appSettingsBiometricAuthenticationLabel": {}, - "appSettingsDisableBiometricAuthenticationReasonText": "Authenticate to disable biometric authentication", - "@appSettingsDisableBiometricAuthenticationReasonText": {}, - "appSettingsEnableBiometricAuthenticationReasonText": "Authenticate to enable biometric authentication", - "@appSettingsEnableBiometricAuthenticationReasonText": {}, - "appTitleText": "Paperless Mobile", - "@appTitleText": {}, - "bottomNavDocumentsPageLabel": "Documents", - "@bottomNavDocumentsPageLabel": {}, - "bottomNavInboxPageLabel": "Inbox", - "@bottomNavInboxPageLabel": {}, - "bottomNavLabelsPageLabel": "Labels", - "@bottomNavLabelsPageLabel": {}, - "bottomNavScannerPageLabel": "Scanner", - "@bottomNavScannerPageLabel": {}, - "correspondentFormFieldSearchHintText": "Start typing...", - "@correspondentFormFieldSearchHintText": {}, - "deleteViewDialogContentText": "Do you really want to delete this view?", - "@deleteViewDialogContentText": {}, - "deleteViewDialogTitleText": "Delete view ", - "@deleteViewDialogTitleText": {}, - "documentAddedPropertyLabel": "Added At", - "@documentAddedPropertyLabel": {}, - "documentArchiveSerialNumberPropertyLongLabel": "Archive Serial Number", - "@documentArchiveSerialNumberPropertyLongLabel": {}, - "documentArchiveSerialNumberPropertyShortLabel": "ASN", - "@documentArchiveSerialNumberPropertyShortLabel": {}, - "documentCorrespondentPropertyLabel": "Correspondent", - "@documentCorrespondentPropertyLabel": {}, - "documentCreatedPropertyLabel": "Created At", - "@documentCreatedPropertyLabel": {}, - "documentDeleteSuccessMessage": "Document successfully deleted.", - "@documentDeleteSuccessMessage": {}, - "documentDetailsPageAssignAsnButtonLabel": "Assign", - "@documentDetailsPageAssignAsnButtonLabel": {}, - "documentDetailsPageSimilarDocumentsLabel": "Similar Documents", - "@documentDetailsPageSimilarDocumentsLabel": {}, - "documentDetailsPageTabContentLabel": "Content", - "@documentDetailsPageTabContentLabel": {}, - "documentDetailsPageTabMetaDataLabel": "Meta Data", - "@documentDetailsPageTabMetaDataLabel": {}, - "documentDetailsPageTabOverviewLabel": "Overview", - "@documentDetailsPageTabOverviewLabel": {}, - "documentDocumentTypePropertyLabel": "Document Type", - "@documentDocumentTypePropertyLabel": {}, - "documentEditPageTitle": "Edit Document", - "@documentEditPageTitle": {}, - "documentMetaDataChecksumLabel": "Original MD5-Checksum", - "@documentMetaDataChecksumLabel": {}, - "documentMetaDataMediaFilenamePropertyLabel": "Media Filename", - "@documentMetaDataMediaFilenamePropertyLabel": {}, - "documentMetaDataOriginalFileSizeLabel": "Original File Size", - "@documentMetaDataOriginalFileSizeLabel": {}, - "documentMetaDataOriginalMimeTypeLabel": "Original MIME-Type", - "@documentMetaDataOriginalMimeTypeLabel": {}, - "documentModifiedPropertyLabel": "Modified At", - "@documentModifiedPropertyLabel": {}, - "documentPreviewPageTitle": "Preview", - "@documentPreviewPageTitle": {}, - "documentScannerPageAddScanButtonLabel": "Scan a document", - "@documentScannerPageAddScanButtonLabel": {}, - "documentScannerPageEmptyStateText": "No documents scanned yet.", - "@documentScannerPageEmptyStateText": {}, - "documentScannerPageOrText": "or", - "@documentScannerPageOrText": {}, - "documentScannerPageResetButtonTooltipText": "Delete all scans", - "@documentScannerPageResetButtonTooltipText": {}, - "documentScannerPageTitle": "Scan", - "@documentScannerPageTitle": {}, - "documentScannerPageUploadButtonTooltip": "Upload to Paperless", - "@documentScannerPageUploadButtonTooltip": {}, - "documentScannerPageUploadFromThisDeviceButtonLabel": "Upload a document from this device", - "@documentScannerPageUploadFromThisDeviceButtonLabel": {}, - "documentsFilterPageAdvancedLabel": "Advanced", - "@documentsFilterPageAdvancedLabel": {}, - "documentsFilterPageApplyFilterLabel": "Apply", - "@documentsFilterPageApplyFilterLabel": {}, - "documentsFilterPageDateRangeFieldEndLabel": "To", - "@documentsFilterPageDateRangeFieldEndLabel": {}, - "documentsFilterPageDateRangeFieldStartLabel": "From", - "@documentsFilterPageDateRangeFieldStartLabel": {}, - "documentsFilterPageDateRangeLastMonthLabel": "Last Month", - "@documentsFilterPageDateRangeLastMonthLabel": {}, - "documentsFilterPageDateRangeLastSevenDaysLabel": "Last 7 Days", - "@documentsFilterPageDateRangeLastSevenDaysLabel": {}, - "documentsFilterPageDateRangeLastThreeMonthsLabel": "Last 3 Months", - "@documentsFilterPageDateRangeLastThreeMonthsLabel": {}, - "documentsFilterPageDateRangeLastYearLabel": "Last Year", - "@documentsFilterPageDateRangeLastYearLabel": {}, - "documentsFilterPageQueryOptionsAsnLabel": "ASN", - "@documentsFilterPageQueryOptionsAsnLabel": {}, - "documentsFilterPageQueryOptionsExtendedLabel": "Extended", - "@documentsFilterPageQueryOptionsExtendedLabel": {}, - "documentsFilterPageQueryOptionsTitleAndContentLabel": "Title & Content", - "@documentsFilterPageQueryOptionsTitleAndContentLabel": {}, - "documentsFilterPageQueryOptionsTitleLabel": "Title", - "@documentsFilterPageQueryOptionsTitleLabel": {}, - "documentsFilterPageResetFilterLabel": "Reset", - "@documentsFilterPageResetFilterLabel": {}, - "documentsFilterPageSearchLabel": "Search", - "@documentsFilterPageSearchLabel": {}, - "documentsFilterPageTitle": "Filter Documents", - "@documentsFilterPageTitle": {}, - "documentsPageBulkDeleteSuccessfulText": "Documents successfully deleted.", - "@documentsPageBulkDeleteSuccessfulText": {}, - "documentsPageEmptyStateNothingHereText": "There seems to be nothing here...", - "@documentsPageEmptyStateNothingHereText": {}, - "documentsPageEmptyStateOopsText": "Oops.", - "@documentsPageEmptyStateOopsText": {}, - "documentsPageOrderByLabel": "Order By", - "@documentsPageOrderByLabel": {}, - "documentsPageSelectionBulkDeleteDialogContinueText": "This action is irreversible. Do you wish to proceed anyway?", - "@documentsPageSelectionBulkDeleteDialogContinueText": {}, - "documentsPageSelectionBulkDeleteDialogTitle": "Confirm deletion", - "@documentsPageSelectionBulkDeleteDialogTitle": {}, - "documentsPageSelectionBulkDeleteDialogWarningTextMany": "Are you sure you want to delete the following documents?", - "@documentsPageSelectionBulkDeleteDialogWarningTextMany": {}, - "documentsPageSelectionBulkDeleteDialogWarningTextOne": "Are you sure you want to delete the following document?", - "@documentsPageSelectionBulkDeleteDialogWarningTextOne": {}, - "documentsPageTitle": "Documents", - "@documentsPageTitle": {}, - "documentsSelectedText": "selected", - "@documentsSelectedText": {}, - "documentStoragePathPropertyLabel": "Storage Path", - "@documentStoragePathPropertyLabel": {}, - "documentsUploadPageTitle": "Prepare document", - "@documentsUploadPageTitle": {}, - "documentTagsPropertyLabel": "Tags", - "@documentTagsPropertyLabel": {}, - "documentTitlePropertyLabel": "Title", - "@documentTitlePropertyLabel": {}, - "documentTypeFormFieldSearchHintText": "Start typing...", - "@documentTypeFormFieldSearchHintText": {}, - "documentUpdateSuccessMessage": "Document successfully updated.", - "@documentUpdateSuccessMessage": {}, - "documentUploadFileNameLabel": "File Name", - "@documentUploadFileNameLabel": {}, - "documentUploadPageSynchronizeTitleAndFilenameLabel": "Synchronize title and filename", - "@documentUploadPageSynchronizeTitleAndFilenameLabel": {}, - "documentUploadProcessingSuccessfulReloadActionText": "Reload", - "@documentUploadProcessingSuccessfulReloadActionText": {}, - "documentUploadProcessingSuccessfulText": "Document successfully processed.", - "@documentUploadProcessingSuccessfulText": {}, - "documentUploadSuccessText": "Document successfully uploaded, processing...", - "@documentUploadSuccessText": {}, - "editLabelPageConfirmDeletionDialogTitle": "Confirm deletion", - "@editLabelPageConfirmDeletionDialogTitle": {}, - "editLabelPageDeletionDialogText": "This label contains references to other documents. By deleting this label, all references will be removed. Continue?", - "@editLabelPageDeletionDialogText": {}, - "errorMessageAuthenticationFailed": "Authentication failed, please try again.", - "@errorMessageAuthenticationFailed": {}, - "errorMessageAutocompleteQueryError": "An error ocurred while trying to autocomplete your query.", - "@errorMessageAutocompleteQueryError": {}, - "errorMessageBiometricAuthenticationFailed": "Biometric authentication failed.", - "@errorMessageBiometricAuthenticationFailed": {}, - "errorMessageBiotmetricsNotSupported": "Biometric authentication not supported on this device.", - "@errorMessageBiotmetricsNotSupported": {}, - "errorMessageBulkActionFailed": "Could not bulk edit documents.", - "@errorMessageBulkActionFailed": {}, - "errorMessageCorrespondentCreateFailed": "Could not create correspondent, please try again.", - "@errorMessageCorrespondentCreateFailed": {}, - "errorMessageCorrespondentLoadFailed": "Could not load correspondents.", - "@errorMessageCorrespondentLoadFailed": {}, - "errorMessageCreateSavedViewError": "Could not create saved view, please try again.", - "@errorMessageCreateSavedViewError": {}, - "errorMessageDeleteSavedViewError": "Could not delete saved view, please try again", - "@errorMessageDeleteSavedViewError": {}, - "errorMessageDeviceOffline": "Could not fetch data: You are not connected to the internet.", - "@errorMessageDeviceOffline": {}, - "errorMessageDocumentAsnQueryFailed": "Could not assign archive serial number.", - "@errorMessageDocumentAsnQueryFailed": {}, - "errorMessageDocumentDeleteFailed": "Could not delete document, please try again.", - "@errorMessageDocumentDeleteFailed": {}, - "errorMessageDocumentLoadFailed": "Could not load documents, please try again.", - "@errorMessageDocumentLoadFailed": {}, - "errorMessageDocumentPreviewFailed": "Could not load document preview.", - "@errorMessageDocumentPreviewFailed": {}, - "errorMessageDocumentTypeCreateFailed": "Could not create document, please try again.", - "@errorMessageDocumentTypeCreateFailed": {}, - "errorMessageDocumentTypeLoadFailed": "Could not load document types, please try again.", - "@errorMessageDocumentTypeLoadFailed": {}, - "errorMessageDocumentUpdateFailed": "Could not update document, please try again.", - "@errorMessageDocumentUpdateFailed": {}, - "errorMessageDocumentUploadFailed": "Could not upload document, please try again.", - "@errorMessageDocumentUploadFailed": {}, - "errorMessageInvalidClientCertificateConfiguration": "Invalid certificate or missing passphrase, please try again", - "@errorMessageInvalidClientCertificateConfiguration": {}, - "errorMessageLoadSavedViewsError": "Could not load saved views.", - "@errorMessageLoadSavedViewsError": {}, - "errorMessageMissingClientCertificate": "A client certificate was expected but not sent. Please provide a valid client certificate.", - "@errorMessageMissingClientCertificate": {}, - "errorMessageNotAuthenticated": "User is not authenticated.", - "@errorMessageNotAuthenticated": {}, - "errorMessageRequestTimedOut": "The request to the server timed out.", - "@errorMessageRequestTimedOut": {}, - "errorMessageScanRemoveFailed": "An error occurred removing the scans.", - "@errorMessageScanRemoveFailed": {}, - "errorMessageServerUnreachable": "Could not reach your Paperless server, is it up and running?", - "@errorMessageServerUnreachable": {}, - "errorMessageSimilarQueryError": "Could not load similar documents.", - "@errorMessageSimilarQueryError": {}, - "errorMessageStoragePathCreateFailed": "Could not create storage path, please try again.", - "@errorMessageStoragePathCreateFailed": {}, - "errorMessageStoragePathLoadFailed": "Could not load storage paths.", - "@errorMessageStoragePathLoadFailed": {}, - "errorMessageTagCreateFailed": "Could not create tag, please try again.", - "@errorMessageTagCreateFailed": {}, - "errorMessageTagLoadFailed": "Could not load tags.", - "@errorMessageTagLoadFailed": {}, - "errorMessageUnknonwnError": "An unknown error occurred.", - "@errorMessageUnknonwnError": {}, - "errorMessageUnsupportedFileFormat": "This file format is not supported.", - "@errorMessageUnsupportedFileFormat": {}, - "errorReportLabel": "REPORT", - "@errorReportLabel": {}, - "genericActionCancelLabel": "Cancel", - "@genericActionCancelLabel": {}, - "genericActionCreateLabel": "Create", - "@genericActionCreateLabel": {}, - "genericActionDeleteLabel": "Delete", - "@genericActionDeleteLabel": {}, - "genericActionEditLabel": "Edit", - "@genericActionEditLabel": {}, - "genericActionOkLabel": "Ok", - "@genericActionOkLabel": {}, - "genericActionSaveLabel": "Save", - "@genericActionSaveLabel": {}, - "genericActionSelectText": "Select", - "@genericActionSelectText": {}, - "genericActionUpdateLabel": "Update", - "@genericActionUpdateLabel": {}, - "genericActionUploadLabel": "Upload", - "@genericActionUploadLabel": {}, - "genericMessageOfflineText": "You're offline. Check your connection.", - "@genericMessageOfflineText": {}, - "inboxPageDocumentRemovedMessageText": "Document removed from inbox.", - "@inboxPageDocumentRemovedMessageText": {}, - "inboxPageMarkAllAsSeenConfirmationDialogText": "Are you sure you want to mark all documents as seen? This will perform a bulk edit operation removing all inbox tags from the documents.\nThis action is not reversible! Are you sure you want to continue?", - "@inboxPageMarkAllAsSeenConfirmationDialogText": {}, - "inboxPageMarkAllAsSeenConfirmationDialogTitleText": "Mark all as seen?", - "@inboxPageMarkAllAsSeenConfirmationDialogTitleText": {}, - "inboxPageMarkAllAsSeenLabel": "Mark all as seen", - "@inboxPageMarkAllAsSeenLabel": {}, - "inboxPageMarkAsSeenText": "Mark as seen", - "@inboxPageMarkAsSeenText": {}, - "inboxPageTodayText": "Today", - "@inboxPageTodayText": {}, - "inboxPageUndoRemoveText": "UNDO", - "@inboxPageUndoRemoveText": {}, - "inboxPageUnseenText": "unseen", - "@inboxPageUnseenText": {}, - "inboxPageUsageHintText": "Hint: Swipe left to mark a document as seen and remove all inbox tags from the document.", - "@inboxPageUsageHintText": {}, - "inboxPageYesterdayText": "Yesterday", - "@inboxPageYesterdayText": {}, - "labelAnyAssignedText": "Any assigned", - "@labelAnyAssignedText": {}, - "labelFormFieldNoItemsFoundText": "No items found!", - "@labelFormFieldNoItemsFoundText": {}, - "labelIsInsensivitePropertyLabel": "Case Irrelevant", - "@labelIsInsensivitePropertyLabel": {}, - "labelMatchingAlgorithmPropertyLabel": "Matching Algorithm", - "@labelMatchingAlgorithmPropertyLabel": {}, - "labelMatchPropertyLabel": "Match", - "@labelMatchPropertyLabel": {}, - "labelNamePropertyLabel": "Name", - "@labelNamePropertyLabel": {}, - "labelNotAssignedText": "Not assigned", - "@labelNotAssignedText": {}, - "labelsPageCorrespondentEmptyStateAddNewLabel": "Add new correspondent", - "@labelsPageCorrespondentEmptyStateAddNewLabel": {}, - "labelsPageCorrespondentEmptyStateDescriptionText": "You don't seem to have any correspondents set up.", - "@labelsPageCorrespondentEmptyStateDescriptionText": {}, - "labelsPageCorrespondentsTitleText": "Correspondents", - "@labelsPageCorrespondentsTitleText": {}, - "labelsPageDocumentTypeEmptyStateAddNewLabel": "Add new document type", - "@labelsPageDocumentTypeEmptyStateAddNewLabel": {}, - "labelsPageDocumentTypeEmptyStateDescriptionText": "You don't seem to have any document types set up.", - "@labelsPageDocumentTypeEmptyStateDescriptionText": {}, - "labelsPageDocumentTypesTitleText": "Document Types", - "@labelsPageDocumentTypesTitleText": {}, - "labelsPageStoragePathEmptyStateAddNewLabel": "Add new storage path", - "@labelsPageStoragePathEmptyStateAddNewLabel": {}, - "labelsPageStoragePathEmptyStateDescriptionText": "You don't seem to have any storage paths set up.", - "@labelsPageStoragePathEmptyStateDescriptionText": {}, - "labelsPageStoragePathTitleText": "Storage Paths", - "@labelsPageStoragePathTitleText": {}, - "labelsPageTagsEmptyStateAddNewLabel": "Add new tag", - "@labelsPageTagsEmptyStateAddNewLabel": {}, - "labelsPageTagsEmptyStateDescriptionText": "You don't seem to have any tags set up.", - "@labelsPageTagsEmptyStateDescriptionText": {}, - "labelsPageTagsTitleText": "Tags", - "@labelsPageTagsTitleText": {}, - "linkedDocumentsPageTitle": "Linked Documents", - "@linkedDocumentsPageTitle": {}, - "loginPageAdvancedLabel": "Advanced Settings", - "@loginPageAdvancedLabel": {}, - "loginPageClientCertificatePassphraseLabel": "Passphrase", - "@loginPageClientCertificatePassphraseLabel": {}, - "loginPageClientCertificateSettingDescriptionText": "Configure Mutual TLS Authentication", - "@loginPageClientCertificateSettingDescriptionText": {}, - "loginPageClientCertificateSettingInvalidFileFormatValidationText": "Invalid certificate format, only .pfx is allowed", - "@loginPageClientCertificateSettingInvalidFileFormatValidationText": {}, - "loginPageClientCertificateSettingLabel": "Client Certificate", - "@loginPageClientCertificateSettingLabel": {}, - "loginPageClientCertificateSettingSelectFileText": "Select file...", - "@loginPageClientCertificateSettingSelectFileText": {}, - "loginPageIncorrectOrMissingCertificatePassphraseErrorMessageText": "Incorrect or missing certificate passphrase.", - "@loginPageIncorrectOrMissingCertificatePassphraseErrorMessageText": {}, - "loginPageLoginButtonLabel": "Connect", - "@loginPageLoginButtonLabel": {}, - "loginPagePasswordFieldLabel": "Password", - "@loginPagePasswordFieldLabel": {}, - "loginPagePasswordValidatorMessageText": "Password must not be empty.", - "@loginPagePasswordValidatorMessageText": {}, - "loginPageServerUrlFieldLabel": "Server Address", - "@loginPageServerUrlFieldLabel": {}, - "loginPageServerUrlValidatorMessageText": "Server address must not be empty.", - "@loginPageServerUrlValidatorMessageText": {}, - "loginPageTitle": "Connect to Paperless", - "@loginPageTitle": {}, - "loginPageUsernameLabel": "Username", - "@loginPageUsernameLabel": {}, - "loginPageUsernameValidatorMessageText": "Username must not be empty.", - "@loginPageUsernameValidatorMessageText": {}, - "offlineWidgetText": "An internet connection could not be established.", - "@offlineWidgetText": {}, - "onboardingDoneButtonLabel": "Done", - "@onboardingDoneButtonLabel": {}, - "onboardingNextButtonLabel": "Next", - "@onboardingNextButtonLabel": {}, - "referencedDocumentsReadOnlyHintText": "This is a read-only view! You cannot edit or remove documents. A maximum of 100 referenced documents will be loaded.", - "@referencedDocumentsReadOnlyHintText": {}, - "savedViewCreateNewLabel": "New View", - "@savedViewCreateNewLabel": {}, - "savedViewCreateTooltipText": "Creates a new view based on the current filter criteria.", - "@savedViewCreateTooltipText": {}, - "savedViewNameLabel": "Name", - "@savedViewNameLabel": {}, - "savedViewsEmptyStateText": "Create views to quickly filter your documents.", - "@savedViewsEmptyStateText": {}, - "savedViewShowInSidebarLabel": "Show in sidebar", - "@savedViewShowInSidebarLabel": {}, - "savedViewShowOnDashboardLabel": "Show on dashboard", - "@savedViewShowOnDashboardLabel": {}, - "savedViewsLabel": "Saved Views", - "@savedViewsLabel": {}, - "serverInformationPaperlessVersionText": "Paperless server version", - "@serverInformationPaperlessVersionText": {}, - "settingsPageAppearanceSettingDarkThemeLabel": "Dark Theme", - "@settingsPageAppearanceSettingDarkThemeLabel": {}, - "settingsPageAppearanceSettingLightThemeLabel": "Light Theme", - "@settingsPageAppearanceSettingLightThemeLabel": {}, - "settingsPageAppearanceSettingSystemThemeLabel": "Use system theme", - "@settingsPageAppearanceSettingSystemThemeLabel": {}, - "settingsPageAppearanceSettingTitle": "Appearance", - "@settingsPageAppearanceSettingTitle": {}, - "settingsPageApplicationSettingsDescriptionText": "Language and visual appearance", - "@settingsPageApplicationSettingsDescriptionText": {}, - "settingsPageApplicationSettingsLabel": "Application", - "@settingsPageApplicationSettingsLabel": {}, - "settingsPageLanguageSettingLabel": "Language", - "@settingsPageLanguageSettingLabel": {}, - "settingsPageSecuritySettingsDescriptionText": "Biometric authentication", - "@settingsPageSecuritySettingsDescriptionText": {}, - "settingsPageSecuritySettingsLabel": "Security", - "@settingsPageSecuritySettingsLabel": {}, - "settingsPageStorageSettingsDescriptionText": "Manage files and storage space", - "@settingsPageStorageSettingsDescriptionText": {}, - "settingsPageStorageSettingsLabel": "Storage", - "@settingsPageStorageSettingsLabel": {}, - "settingsThemeModeDarkLabel": "Dark", - "@settingsThemeModeDarkLabel": {}, - "settingsThemeModeLightLabel": "Light", - "@settingsThemeModeLightLabel": {}, - "settingsThemeModeSystemLabel": "System", - "@settingsThemeModeSystemLabel": {}, - "storagePathParameterDayLabel": "day", - "@storagePathParameterDayLabel": {}, - "storagePathParameterMonthLabel": "month", - "@storagePathParameterMonthLabel": {}, - "storagePathParameterYearLabel": "year", - "@storagePathParameterYearLabel": {}, - "tagColorPropertyLabel": "Color", - "@tagColorPropertyLabel": {}, - "tagFormFieldSearchHintText": "Filter tags...", - "@tagFormFieldSearchHintText": {}, - "tagInboxTagPropertyLabel": "Inbox-Tag", - "@tagInboxTagPropertyLabel": {}, - "uploadPageAutomaticallInferredFieldsHintText": "If you specify values for these fields, your paperless instance will not automatically derive a value. If you want these values to be automatically populated by your server, leave the fields blank.", - "@uploadPageAutomaticallInferredFieldsHintText": {} - } \ No newline at end of file + "@@locale": "en", + "aboutDialogDevelopedByText": "Developed by", + "@aboutDialogDevelopedByText": {}, + "addCorrespondentPageTitle": "New Correspondent", + "@addCorrespondentPageTitle": {}, + "addDocumentTypePageTitle": "New Document Type", + "@addDocumentTypePageTitle": {}, + "addStoragePathPageTitle": "New Storage Path", + "@addStoragePathPageTitle": {}, + "addTagPageTitle": "New Tag", + "@addTagPageTitle": {}, + "appDrawerAboutInfoLoadingText": "Retrieving application information...", + "@appDrawerAboutInfoLoadingText": {}, + "appDrawerAboutLabel": "About this app", + "@appDrawerAboutLabel": {}, + "appDrawerHeaderLoggedInAsText": "Logged in as ", + "@appDrawerHeaderLoggedInAsText": {}, + "appDrawerLogoutLabel": "Disconnect", + "@appDrawerLogoutLabel": {}, + "appDrawerReportBugLabel": "Report a Bug", + "@appDrawerReportBugLabel": {}, + "appDrawerSettingsLabel": "Settings", + "@appDrawerSettingsLabel": {}, + "appSettingsBiometricAuthenticationDescriptionText": "Authenticate on app start", + "@appSettingsBiometricAuthenticationDescriptionText": {}, + "appSettingsBiometricAuthenticationLabel": "Biometric authentication", + "@appSettingsBiometricAuthenticationLabel": {}, + "appSettingsDisableBiometricAuthenticationReasonText": "Authenticate to disable biometric authentication", + "@appSettingsDisableBiometricAuthenticationReasonText": {}, + "appSettingsEnableBiometricAuthenticationReasonText": "Authenticate to enable biometric authentication", + "@appSettingsEnableBiometricAuthenticationReasonText": {}, + "appTitleText": "Paperless Mobile", + "@appTitleText": {}, + "bottomNavDocumentsPageLabel": "Documents", + "@bottomNavDocumentsPageLabel": {}, + "bottomNavInboxPageLabel": "Inbox", + "@bottomNavInboxPageLabel": {}, + "bottomNavLabelsPageLabel": "Labels", + "@bottomNavLabelsPageLabel": {}, + "bottomNavScannerPageLabel": "Scanner", + "@bottomNavScannerPageLabel": {}, + "correspondentFormFieldSearchHintText": "Start typing...", + "@correspondentFormFieldSearchHintText": {}, + "deleteViewDialogContentText": "Do you really want to delete this view?", + "@deleteViewDialogContentText": {}, + "deleteViewDialogTitleText": "Delete view ", + "@deleteViewDialogTitleText": {}, + "documentAddedPropertyLabel": "Added At", + "@documentAddedPropertyLabel": {}, + "documentArchiveSerialNumberPropertyLongLabel": "Archive Serial Number", + "@documentArchiveSerialNumberPropertyLongLabel": {}, + "documentArchiveSerialNumberPropertyShortLabel": "ASN", + "@documentArchiveSerialNumberPropertyShortLabel": {}, + "documentCorrespondentPropertyLabel": "Correspondent", + "@documentCorrespondentPropertyLabel": {}, + "documentCreatedPropertyLabel": "Created At", + "@documentCreatedPropertyLabel": {}, + "documentDeleteSuccessMessage": "Document successfully deleted.", + "@documentDeleteSuccessMessage": {}, + "documentDetailsPageAssignAsnButtonLabel": "Assign", + "@documentDetailsPageAssignAsnButtonLabel": {}, + "documentDetailsPageSimilarDocumentsLabel": "Similar Documents", + "@documentDetailsPageSimilarDocumentsLabel": {}, + "documentDetailsPageTabContentLabel": "Content", + "@documentDetailsPageTabContentLabel": {}, + "documentDetailsPageTabMetaDataLabel": "Meta Data", + "@documentDetailsPageTabMetaDataLabel": {}, + "documentDetailsPageTabOverviewLabel": "Overview", + "@documentDetailsPageTabOverviewLabel": {}, + "documentDocumentTypePropertyLabel": "Document Type", + "@documentDocumentTypePropertyLabel": {}, + "documentEditPageTitle": "Edit Document", + "@documentEditPageTitle": {}, + "documentMetaDataChecksumLabel": "Original MD5-Checksum", + "@documentMetaDataChecksumLabel": {}, + "documentMetaDataMediaFilenamePropertyLabel": "Media Filename", + "@documentMetaDataMediaFilenamePropertyLabel": {}, + "documentMetaDataOriginalFileSizeLabel": "Original File Size", + "@documentMetaDataOriginalFileSizeLabel": {}, + "documentMetaDataOriginalMimeTypeLabel": "Original MIME-Type", + "@documentMetaDataOriginalMimeTypeLabel": {}, + "documentModifiedPropertyLabel": "Modified At", + "@documentModifiedPropertyLabel": {}, + "documentPreviewPageTitle": "Preview", + "@documentPreviewPageTitle": {}, + "documentScannerPageAddScanButtonLabel": "Scan a document", + "@documentScannerPageAddScanButtonLabel": {}, + "documentScannerPageEmptyStateText": "No documents scanned yet.", + "@documentScannerPageEmptyStateText": {}, + "documentScannerPageOrText": "or", + "@documentScannerPageOrText": {}, + "documentScannerPageResetButtonTooltipText": "Delete all scans", + "@documentScannerPageResetButtonTooltipText": {}, + "documentScannerPageTitle": "Scan", + "@documentScannerPageTitle": {}, + "documentScannerPageUploadButtonTooltip": "Upload to Paperless", + "@documentScannerPageUploadButtonTooltip": {}, + "documentScannerPageUploadFromThisDeviceButtonLabel": "Upload a document from this device", + "@documentScannerPageUploadFromThisDeviceButtonLabel": {}, + "documentsFilterPageAdvancedLabel": "Advanced", + "@documentsFilterPageAdvancedLabel": {}, + "documentsFilterPageApplyFilterLabel": "Apply", + "@documentsFilterPageApplyFilterLabel": {}, + "documentsFilterPageDateRangeFieldEndLabel": "To", + "@documentsFilterPageDateRangeFieldEndLabel": {}, + "documentsFilterPageDateRangeFieldStartLabel": "From", + "@documentsFilterPageDateRangeFieldStartLabel": {}, + "documentsFilterPageDateRangeLastMonthLabel": "Last Month", + "@documentsFilterPageDateRangeLastMonthLabel": {}, + "documentsFilterPageDateRangeLastSevenDaysLabel": "Last 7 Days", + "@documentsFilterPageDateRangeLastSevenDaysLabel": {}, + "documentsFilterPageDateRangeLastThreeMonthsLabel": "Last 3 Months", + "@documentsFilterPageDateRangeLastThreeMonthsLabel": {}, + "documentsFilterPageDateRangeLastYearLabel": "Last Year", + "@documentsFilterPageDateRangeLastYearLabel": {}, + "documentsFilterPageQueryOptionsAsnLabel": "ASN", + "@documentsFilterPageQueryOptionsAsnLabel": {}, + "documentsFilterPageQueryOptionsExtendedLabel": "Extended", + "@documentsFilterPageQueryOptionsExtendedLabel": {}, + "documentsFilterPageQueryOptionsTitleAndContentLabel": "Title & Content", + "@documentsFilterPageQueryOptionsTitleAndContentLabel": {}, + "documentsFilterPageQueryOptionsTitleLabel": "Title", + "@documentsFilterPageQueryOptionsTitleLabel": {}, + "documentsFilterPageResetFilterLabel": "Reset", + "@documentsFilterPageResetFilterLabel": {}, + "documentsFilterPageSearchLabel": "Search", + "@documentsFilterPageSearchLabel": {}, + "documentsFilterPageTitle": "Filter Documents", + "@documentsFilterPageTitle": {}, + "documentsPageBulkDeleteSuccessfulText": "Documents successfully deleted.", + "@documentsPageBulkDeleteSuccessfulText": {}, + "documentsPageEmptyStateNothingHereText": "There seems to be nothing here...", + "@documentsPageEmptyStateNothingHereText": {}, + "documentsPageEmptyStateOopsText": "Oops.", + "@documentsPageEmptyStateOopsText": {}, + "documentsPageOrderByLabel": "Order By", + "@documentsPageOrderByLabel": {}, + "documentsPageSelectionBulkDeleteDialogContinueText": "This action is irreversible. Do you wish to proceed anyway?", + "@documentsPageSelectionBulkDeleteDialogContinueText": {}, + "documentsPageSelectionBulkDeleteDialogTitle": "Confirm deletion", + "@documentsPageSelectionBulkDeleteDialogTitle": {}, + "documentsPageSelectionBulkDeleteDialogWarningTextMany": "Are you sure you want to delete the following documents?", + "@documentsPageSelectionBulkDeleteDialogWarningTextMany": {}, + "documentsPageSelectionBulkDeleteDialogWarningTextOne": "Are you sure you want to delete the following document?", + "@documentsPageSelectionBulkDeleteDialogWarningTextOne": {}, + "documentsPageTitle": "Documents", + "@documentsPageTitle": {}, + "documentsSelectedText": "selected", + "@documentsSelectedText": {}, + "documentStoragePathPropertyLabel": "Storage Path", + "@documentStoragePathPropertyLabel": {}, + "documentsUploadPageTitle": "Prepare document", + "@documentsUploadPageTitle": {}, + "documentTagsPropertyLabel": "Tags", + "@documentTagsPropertyLabel": {}, + "documentTitlePropertyLabel": "Title", + "@documentTitlePropertyLabel": {}, + "documentTypeFormFieldSearchHintText": "Start typing...", + "@documentTypeFormFieldSearchHintText": {}, + "documentUpdateSuccessMessage": "Document successfully updated.", + "@documentUpdateSuccessMessage": {}, + "documentUploadFileNameLabel": "File Name", + "@documentUploadFileNameLabel": {}, + "documentUploadPageSynchronizeTitleAndFilenameLabel": "Synchronize title and filename", + "@documentUploadPageSynchronizeTitleAndFilenameLabel": {}, + "documentUploadProcessingSuccessfulReloadActionText": "Reload", + "@documentUploadProcessingSuccessfulReloadActionText": {}, + "documentUploadProcessingSuccessfulText": "Document successfully processed.", + "@documentUploadProcessingSuccessfulText": {}, + "documentUploadSuccessText": "Document successfully uploaded, processing...", + "@documentUploadSuccessText": {}, + "editLabelPageConfirmDeletionDialogTitle": "Confirm deletion", + "@editLabelPageConfirmDeletionDialogTitle": {}, + "editLabelPageDeletionDialogText": "This label contains references to other documents. By deleting this label, all references will be removed. Continue?", + "@editLabelPageDeletionDialogText": {}, + "errorMessageAuthenticationFailed": "Authentication failed, please try again.", + "@errorMessageAuthenticationFailed": {}, + "errorMessageAutocompleteQueryError": "An error ocurred while trying to autocomplete your query.", + "@errorMessageAutocompleteQueryError": {}, + "errorMessageBiometricAuthenticationFailed": "Biometric authentication failed.", + "@errorMessageBiometricAuthenticationFailed": {}, + "errorMessageBiotmetricsNotSupported": "Biometric authentication not supported on this device.", + "@errorMessageBiotmetricsNotSupported": {}, + "errorMessageBulkActionFailed": "Could not bulk edit documents.", + "@errorMessageBulkActionFailed": {}, + "errorMessageCorrespondentCreateFailed": "Could not create correspondent, please try again.", + "@errorMessageCorrespondentCreateFailed": {}, + "errorMessageCorrespondentLoadFailed": "Could not load correspondents.", + "@errorMessageCorrespondentLoadFailed": {}, + "errorMessageCreateSavedViewError": "Could not create saved view, please try again.", + "@errorMessageCreateSavedViewError": {}, + "errorMessageDeleteSavedViewError": "Could not delete saved view, please try again", + "@errorMessageDeleteSavedViewError": {}, + "errorMessageDeviceOffline": "Could not fetch data: You are not connected to the internet.", + "@errorMessageDeviceOffline": {}, + "errorMessageDocumentAsnQueryFailed": "Could not assign archive serial number.", + "@errorMessageDocumentAsnQueryFailed": {}, + "errorMessageDocumentDeleteFailed": "Could not delete document, please try again.", + "@errorMessageDocumentDeleteFailed": {}, + "errorMessageDocumentLoadFailed": "Could not load documents, please try again.", + "@errorMessageDocumentLoadFailed": {}, + "errorMessageDocumentPreviewFailed": "Could not load document preview.", + "@errorMessageDocumentPreviewFailed": {}, + "errorMessageDocumentTypeCreateFailed": "Could not create document, please try again.", + "@errorMessageDocumentTypeCreateFailed": {}, + "errorMessageDocumentTypeLoadFailed": "Could not load document types, please try again.", + "@errorMessageDocumentTypeLoadFailed": {}, + "errorMessageDocumentUpdateFailed": "Could not update document, please try again.", + "@errorMessageDocumentUpdateFailed": {}, + "errorMessageDocumentUploadFailed": "Could not upload document, please try again.", + "@errorMessageDocumentUploadFailed": {}, + "errorMessageInvalidClientCertificateConfiguration": "Invalid certificate or missing passphrase, please try again", + "@errorMessageInvalidClientCertificateConfiguration": {}, + "errorMessageLoadSavedViewsError": "Could not load saved views.", + "@errorMessageLoadSavedViewsError": {}, + "errorMessageMissingClientCertificate": "A client certificate was expected but not sent. Please provide a valid client certificate.", + "@errorMessageMissingClientCertificate": {}, + "errorMessageNotAuthenticated": "User is not authenticated.", + "@errorMessageNotAuthenticated": {}, + "errorMessageRequestTimedOut": "The request to the server timed out.", + "@errorMessageRequestTimedOut": {}, + "errorMessageScanRemoveFailed": "An error occurred removing the scans.", + "@errorMessageScanRemoveFailed": {}, + "errorMessageServerUnreachable": "Could not reach your Paperless server, is it up and running?", + "@errorMessageServerUnreachable": {}, + "errorMessageSimilarQueryError": "Could not load similar documents.", + "@errorMessageSimilarQueryError": {}, + "errorMessageStoragePathCreateFailed": "Could not create storage path, please try again.", + "@errorMessageStoragePathCreateFailed": {}, + "errorMessageStoragePathLoadFailed": "Could not load storage paths.", + "@errorMessageStoragePathLoadFailed": {}, + "errorMessageTagCreateFailed": "Could not create tag, please try again.", + "@errorMessageTagCreateFailed": {}, + "errorMessageTagLoadFailed": "Could not load tags.", + "@errorMessageTagLoadFailed": {}, + "errorMessageUnknonwnError": "An unknown error occurred.", + "@errorMessageUnknonwnError": {}, + "errorMessageUnsupportedFileFormat": "This file format is not supported.", + "@errorMessageUnsupportedFileFormat": {}, + "errorReportLabel": "REPORT", + "@errorReportLabel": {}, + "genericActionCancelLabel": "Cancel", + "@genericActionCancelLabel": {}, + "genericActionCreateLabel": "Create", + "@genericActionCreateLabel": {}, + "genericActionDeleteLabel": "Delete", + "@genericActionDeleteLabel": {}, + "genericActionEditLabel": "Edit", + "@genericActionEditLabel": {}, + "genericActionOkLabel": "Ok", + "@genericActionOkLabel": {}, + "genericActionSaveLabel": "Save", + "@genericActionSaveLabel": {}, + "genericActionSelectText": "Select", + "@genericActionSelectText": {}, + "genericActionUpdateLabel": "Update", + "@genericActionUpdateLabel": {}, + "genericActionUploadLabel": "Upload", + "@genericActionUploadLabel": {}, + "genericMessageOfflineText": "You're offline. Check your connection.", + "@genericMessageOfflineText": {}, + "inboxPageDocumentRemovedMessageText": "Document removed from inbox.", + "@inboxPageDocumentRemovedMessageText": {}, + "inboxPageMarkAllAsSeenConfirmationDialogText": "Are you sure you want to mark all documents as seen? This will perform a bulk edit operation removing all inbox tags from the documents.\nThis action is not reversible! Are you sure you want to continue?", + "@inboxPageMarkAllAsSeenConfirmationDialogText": {}, + "inboxPageMarkAllAsSeenConfirmationDialogTitleText": "Mark all as seen?", + "@inboxPageMarkAllAsSeenConfirmationDialogTitleText": {}, + "inboxPageMarkAllAsSeenLabel": "Mark all as seen", + "@inboxPageMarkAllAsSeenLabel": {}, + "inboxPageMarkAsSeenText": "Mark as seen", + "@inboxPageMarkAsSeenText": {}, + "inboxPageTodayText": "Today", + "@inboxPageTodayText": {}, + "inboxPageUndoRemoveText": "UNDO", + "@inboxPageUndoRemoveText": {}, + "inboxPageUnseenText": "unseen", + "@inboxPageUnseenText": {}, + "inboxPageUsageHintText": "Hint: Swipe left to mark a document as seen and remove all inbox tags from the document.", + "@inboxPageUsageHintText": {}, + "inboxPageYesterdayText": "Yesterday", + "@inboxPageYesterdayText": {}, + "labelAnyAssignedText": "Any assigned", + "@labelAnyAssignedText": {}, + "labelFormFieldNoItemsFoundText": "No items found!", + "@labelFormFieldNoItemsFoundText": {}, + "labelIsInsensivitePropertyLabel": "Case Irrelevant", + "@labelIsInsensivitePropertyLabel": {}, + "labelMatchingAlgorithmPropertyLabel": "Matching Algorithm", + "@labelMatchingAlgorithmPropertyLabel": {}, + "labelMatchPropertyLabel": "Match", + "@labelMatchPropertyLabel": {}, + "labelNamePropertyLabel": "Name", + "@labelNamePropertyLabel": {}, + "labelNotAssignedText": "Not assigned", + "@labelNotAssignedText": {}, + "labelsPageCorrespondentEmptyStateAddNewLabel": "Add new correspondent", + "@labelsPageCorrespondentEmptyStateAddNewLabel": {}, + "labelsPageCorrespondentEmptyStateDescriptionText": "You don't seem to have any correspondents set up.", + "@labelsPageCorrespondentEmptyStateDescriptionText": {}, + "labelsPageCorrespondentsTitleText": "Correspondents", + "@labelsPageCorrespondentsTitleText": {}, + "labelsPageDocumentTypeEmptyStateAddNewLabel": "Add new document type", + "@labelsPageDocumentTypeEmptyStateAddNewLabel": {}, + "labelsPageDocumentTypeEmptyStateDescriptionText": "You don't seem to have any document types set up.", + "@labelsPageDocumentTypeEmptyStateDescriptionText": {}, + "labelsPageDocumentTypesTitleText": "Document Types", + "@labelsPageDocumentTypesTitleText": {}, + "labelsPageStoragePathEmptyStateAddNewLabel": "Add new storage path", + "@labelsPageStoragePathEmptyStateAddNewLabel": {}, + "labelsPageStoragePathEmptyStateDescriptionText": "You don't seem to have any storage paths set up.", + "@labelsPageStoragePathEmptyStateDescriptionText": {}, + "labelsPageStoragePathTitleText": "Storage Paths", + "@labelsPageStoragePathTitleText": {}, + "labelsPageTagsEmptyStateAddNewLabel": "Add new tag", + "@labelsPageTagsEmptyStateAddNewLabel": {}, + "labelsPageTagsEmptyStateDescriptionText": "You don't seem to have any tags set up.", + "@labelsPageTagsEmptyStateDescriptionText": {}, + "labelsPageTagsTitleText": "Tags", + "@labelsPageTagsTitleText": {}, + "linkedDocumentsPageTitle": "Linked Documents", + "@linkedDocumentsPageTitle": {}, + "loginPageAdvancedLabel": "Advanced Settings", + "@loginPageAdvancedLabel": {}, + "loginPageClientCertificatePassphraseLabel": "Passphrase", + "@loginPageClientCertificatePassphraseLabel": {}, + "loginPageClientCertificateSettingDescriptionText": "Configure Mutual TLS Authentication", + "@loginPageClientCertificateSettingDescriptionText": {}, + "loginPageClientCertificateSettingInvalidFileFormatValidationText": "Invalid certificate format, only .pfx is allowed", + "@loginPageClientCertificateSettingInvalidFileFormatValidationText": {}, + "loginPageClientCertificateSettingLabel": "Client Certificate", + "@loginPageClientCertificateSettingLabel": {}, + "loginPageClientCertificateSettingSelectFileText": "Select file...", + "@loginPageClientCertificateSettingSelectFileText": {}, + "loginPageIncorrectOrMissingCertificatePassphraseErrorMessageText": "Incorrect or missing certificate passphrase.", + "@loginPageIncorrectOrMissingCertificatePassphraseErrorMessageText": {}, + "loginPageLoginButtonLabel": "Connect", + "@loginPageLoginButtonLabel": {}, + "loginPagePasswordFieldLabel": "Password", + "@loginPagePasswordFieldLabel": {}, + "loginPagePasswordValidatorMessageText": "Password must not be empty.", + "@loginPagePasswordValidatorMessageText": {}, + "loginPageServerUrlFieldLabel": "Server Address", + "@loginPageServerUrlFieldLabel": {}, + "loginPageServerUrlValidatorMessageText": "Server address must not be empty.", + "@loginPageServerUrlValidatorMessageText": {}, + "loginPageTitle": "Connect to Paperless", + "@loginPageTitle": {}, + "loginPageUsernameLabel": "Username", + "@loginPageUsernameLabel": {}, + "loginPageUsernameValidatorMessageText": "Username must not be empty.", + "@loginPageUsernameValidatorMessageText": {}, + "offlineWidgetText": "An internet connection could not be established.", + "@offlineWidgetText": {}, + "onboardingDoneButtonLabel": "Done", + "@onboardingDoneButtonLabel": {}, + "onboardingNextButtonLabel": "Next", + "@onboardingNextButtonLabel": {}, + "referencedDocumentsReadOnlyHintText": "This is a read-only view! You cannot edit or remove documents. A maximum of 100 referenced documents will be loaded.", + "@referencedDocumentsReadOnlyHintText": {}, + "savedViewCreateNewLabel": "New View", + "@savedViewCreateNewLabel": {}, + "savedViewCreateTooltipText": "Creates a new view based on the current filter criteria.", + "@savedViewCreateTooltipText": {}, + "savedViewNameLabel": "Name", + "@savedViewNameLabel": {}, + "savedViewsEmptyStateText": "Create views to quickly filter your documents.", + "@savedViewsEmptyStateText": {}, + "savedViewShowInSidebarLabel": "Show in sidebar", + "@savedViewShowInSidebarLabel": {}, + "savedViewShowOnDashboardLabel": "Show on dashboard", + "@savedViewShowOnDashboardLabel": {}, + "savedViewsLabel": "Saved Views", + "@savedViewsLabel": {}, + "serverInformationPaperlessVersionText": "Paperless server version", + "@serverInformationPaperlessVersionText": {}, + "settingsPageAppearanceSettingDarkThemeLabel": "Dark Theme", + "@settingsPageAppearanceSettingDarkThemeLabel": {}, + "settingsPageAppearanceSettingLightThemeLabel": "Light Theme", + "@settingsPageAppearanceSettingLightThemeLabel": {}, + "settingsPageAppearanceSettingSystemThemeLabel": "Use system theme", + "@settingsPageAppearanceSettingSystemThemeLabel": {}, + "settingsPageAppearanceSettingTitle": "Appearance", + "@settingsPageAppearanceSettingTitle": {}, + "settingsPageApplicationSettingsDescriptionText": "Language and visual appearance", + "@settingsPageApplicationSettingsDescriptionText": {}, + "settingsPageApplicationSettingsLabel": "Application", + "@settingsPageApplicationSettingsLabel": {}, + "settingsPageLanguageSettingLabel": "Language", + "@settingsPageLanguageSettingLabel": {}, + "settingsPageSecuritySettingsDescriptionText": "Biometric authentication", + "@settingsPageSecuritySettingsDescriptionText": {}, + "settingsPageSecuritySettingsLabel": "Security", + "@settingsPageSecuritySettingsLabel": {}, + "settingsPageStorageSettingsDescriptionText": "Manage files and storage space", + "@settingsPageStorageSettingsDescriptionText": {}, + "settingsPageStorageSettingsLabel": "Storage", + "@settingsPageStorageSettingsLabel": {}, + "settingsThemeModeDarkLabel": "Dark", + "@settingsThemeModeDarkLabel": {}, + "settingsThemeModeLightLabel": "Light", + "@settingsThemeModeLightLabel": {}, + "settingsThemeModeSystemLabel": "System", + "@settingsThemeModeSystemLabel": {}, + "storagePathParameterDayLabel": "day", + "@storagePathParameterDayLabel": {}, + "storagePathParameterMonthLabel": "month", + "@storagePathParameterMonthLabel": {}, + "storagePathParameterYearLabel": "year", + "@storagePathParameterYearLabel": {}, + "tagColorPropertyLabel": "Color", + "@tagColorPropertyLabel": {}, + "tagFormFieldSearchHintText": "Filter tags...", + "@tagFormFieldSearchHintText": {}, + "tagInboxTagPropertyLabel": "Inbox-Tag", + "@tagInboxTagPropertyLabel": {}, + "uploadPageAutomaticallInferredFieldsHintText": "If you specify values for these fields, your paperless instance will not automatically derive a value. If you want these values to be automatically populated by your server, leave the fields blank.", + "@uploadPageAutomaticallInferredFieldsHintText": {}, + "inboxPageNoNewDocumentsText": "You do not have unseen documents.", + "inboxPageNoNewDocumentsRefreshLabel": "Refresh" +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index e46c2b5..b16a870 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,3 @@ -import 'dart:developer'; import 'dart:io'; import 'package:flutter/material.dart'; @@ -11,15 +10,14 @@ import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:intl/intl.dart'; import 'package:intl/intl_standalone.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/bloc/bloc_changes_observer.dart'; import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart'; import 'package:paperless_mobile/features/labels/bloc/global_state_bloc_provider.dart'; import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart'; -import 'package:paperless_mobile/core/global/asset_images.dart'; import 'package:paperless_mobile/core/global/constants.dart'; import 'package:paperless_mobile/core/global/http_self_signed_certificate_override.dart'; import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:paperless_mobile/core/service/file_service.dart'; import 'package:paperless_mobile/di_initializer.dart'; import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart'; @@ -119,15 +117,16 @@ class _PaperlessMobileEntrypointState extends State { supportedLocales: const [ Locale('en'), // Default if system locale is not available Locale('de'), + Locale('cs'), ], locale: Locale.fromSubtags( languageCode: settings.preferredLocaleSubtag), localizationsDelegates: const [ S.delegate, GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, GlobalWidgetsLocalizations.delegate, FormBuilderLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, ], home: const AuthenticationWrapper(), ); diff --git a/lib/util.dart b/lib/util.dart index 0adda71..6776cd0 100644 --- a/lib/util.dart +++ b/lib/util.dart @@ -1,21 +1,16 @@ import 'dart:async'; -import 'dart:convert'; import 'dart:developer'; -import 'dart:io'; -import 'dart:typed_data'; import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; import 'package:intl/intl.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:paperless_api/paperless_api.dart'; +import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; import 'package:paperless_mobile/core/service/github_issue_service.dart'; -import 'package:paperless_mobile/generated/intl/messages_de.dart'; import 'package:paperless_mobile/generated/l10n.dart'; -import 'package:path_provider/path_provider.dart'; final dateFormat = DateFormat("yyyy-MM-dd"); final GlobalKey rootScaffoldKey = GlobalKey(); @@ -65,7 +60,7 @@ void showGenericError( void showErrorMessage( BuildContext context, - ErrorMessage error, [ + PaperlessServerException error, [ StackTrace? stackTrace, ]) { showSnackBar( diff --git a/packages/paperless_api/.gitignore b/packages/paperless_api/.gitignore new file mode 100644 index 0000000..96486fd --- /dev/null +++ b/packages/paperless_api/.gitignore @@ -0,0 +1,30 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. +/pubspec.lock +**/doc/api/ +.dart_tool/ +.packages +build/ diff --git a/packages/paperless_api/.metadata b/packages/paperless_api/.metadata new file mode 100644 index 0000000..fbfa6df --- /dev/null +++ b/packages/paperless_api/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 + channel: stable + +project_type: package diff --git a/packages/paperless_api/CHANGELOG.md b/packages/paperless_api/CHANGELOG.md new file mode 100644 index 0000000..41cc7d8 --- /dev/null +++ b/packages/paperless_api/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/packages/paperless_api/LICENSE b/packages/paperless_api/LICENSE new file mode 100644 index 0000000..ba75c69 --- /dev/null +++ b/packages/paperless_api/LICENSE @@ -0,0 +1 @@ +TODO: Add your license here. diff --git a/packages/paperless_api/README.md b/packages/paperless_api/README.md new file mode 100644 index 0000000..02fe8ec --- /dev/null +++ b/packages/paperless_api/README.md @@ -0,0 +1,39 @@ + + +TODO: Put a short description of the package here that helps potential users +know whether this package might be useful for them. + +## Features + +TODO: List what your package can do. Maybe include images, gifs, or videos. + +## Getting started + +TODO: List prerequisites and provide or point to information on how to +start using the package. + +## Usage + +TODO: Include short and useful examples for package users. Add longer examples +to `/example` folder. + +```dart +const like = 'sample'; +``` + +## Additional information + +TODO: Tell users more about the package: where to find more information, how to +contribute to the package, how to file issues, what response they can expect +from the package authors, and more. diff --git a/packages/paperless_api/analysis_options.yaml b/packages/paperless_api/analysis_options.yaml new file mode 100644 index 0000000..a5744c1 --- /dev/null +++ b/packages/paperless_api/analysis_options.yaml @@ -0,0 +1,4 @@ +include: package:flutter_lints/flutter.yaml + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/packages/paperless_api/lib/paperless_api.dart b/packages/paperless_api/lib/paperless_api.dart new file mode 100644 index 0000000..6272edc --- /dev/null +++ b/packages/paperless_api/lib/paperless_api.dart @@ -0,0 +1,4 @@ +library paperless_api; + +export 'src/models/models.dart'; +export 'src/modules/modules.dart'; diff --git a/packages/paperless_api/lib/src/constants.dart b/packages/paperless_api/lib/src/constants.dart new file mode 100644 index 0000000..12d003d --- /dev/null +++ b/packages/paperless_api/lib/src/constants.dart @@ -0,0 +1,3 @@ +import 'package:intl/intl.dart'; + +final DateFormat apiDateFormat = DateFormat('yyyy-MM-dd'); diff --git a/lib/features/documents/model/bulk_edit.model.dart b/packages/paperless_api/lib/src/models/bulk_edit_model.dart similarity index 89% rename from lib/features/documents/model/bulk_edit.model.dart rename to packages/paperless_api/lib/src/models/bulk_edit_model.dart index cdfce1a..e04300f 100644 --- a/lib/features/documents/model/bulk_edit.model.dart +++ b/packages/paperless_api/lib/src/models/bulk_edit_model.dart @@ -1,18 +1,16 @@ -import 'package:paperless_mobile/core/type/types.dart'; - abstract class BulkAction { final Iterable documentIds; BulkAction(this.documentIds); - JSON toJson(); + Map toJson(); } class BulkDeleteAction extends BulkAction { BulkDeleteAction(super.documents); @override - JSON toJson() { + Map toJson() { return { 'documents': documentIds.toList(), 'method': 'delete', @@ -39,7 +37,7 @@ class BulkModifyTagsAction extends BulkAction { removeTags = tags; @override - JSON toJson() { + Map toJson() { return { 'documents': documentIds.toList(), 'method': 'modify_tags', diff --git a/lib/features/documents/model/document_filter.dart b/packages/paperless_api/lib/src/models/document_filter.dart similarity index 78% rename from lib/features/documents/model/document_filter.dart rename to packages/paperless_api/lib/src/models/document_filter.dart index 71d778e..e24de6f 100644 --- a/lib/features/documents/model/document_filter.dart +++ b/packages/paperless_api/lib/src/models/document_filter.dart @@ -1,15 +1,15 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/asn_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/query_type.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/util.dart'; +import 'package:paperless_api/src/constants.dart'; +import 'package:paperless_api/src/models/query_parameters/asn_query.dart'; +import 'package:paperless_api/src/models/query_parameters/correspondent_query.dart'; +import 'package:paperless_api/src/models/query_parameters/document_type_query.dart'; +import 'package:paperless_api/src/models/query_parameters/query_type.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_field.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_order.dart'; +import 'package:paperless_api/src/models/query_parameters/storage_path_query.dart'; +import 'package:paperless_api/src/models/query_parameters/tags_query.dart'; -class DocumentFilter with EquatableMixin { +class DocumentFilter extends Equatable { static const _oneDay = Duration(days: 1); static const DocumentFilter initial = DocumentFilter(); @@ -71,22 +71,22 @@ class DocumentFilter with EquatableMixin { // Add/subtract one day in the following because paperless uses gt/lt not gte/lte if (addedDateAfter != null) { sb.write( - "&added__date__gt=${dateFormat.format(addedDateAfter!.subtract(_oneDay))}"); + "&added__date__gt=${apiDateFormat.format(addedDateAfter!.subtract(_oneDay))}"); } if (addedDateBefore != null) { sb.write( - "&added__date__lt=${dateFormat.format(addedDateBefore!.add(_oneDay))}"); + "&added__date__lt=${apiDateFormat.format(addedDateBefore!.add(_oneDay))}"); } if (createdDateAfter != null) { sb.write( - "&created__date__gt=${dateFormat.format(createdDateAfter!.subtract(_oneDay))}"); + "&created__date__gt=${apiDateFormat.format(createdDateAfter!.subtract(_oneDay))}"); } if (createdDateBefore != null) { sb.write( - "&created__date__lt=${dateFormat.format(createdDateBefore!.add(_oneDay))}"); + "&created__date__lt=${apiDateFormat.format(createdDateBefore!.add(_oneDay))}"); } return sb.toString(); diff --git a/lib/features/documents/model/document_meta_data.model.dart b/packages/paperless_api/lib/src/models/document_meta_data_model.dart similarity index 100% rename from lib/features/documents/model/document_meta_data.model.dart rename to packages/paperless_api/lib/src/models/document_meta_data_model.dart diff --git a/lib/features/documents/model/document.model.dart b/packages/paperless_api/lib/src/models/document_model.dart similarity index 97% rename from lib/features/documents/model/document.model.dart rename to packages/paperless_api/lib/src/models/document_model.dart index b0732d5..ad55482 100644 --- a/lib/features/documents/model/document.model.dart +++ b/packages/paperless_api/lib/src/models/document_model.dart @@ -1,7 +1,6 @@ // ignore_for_file: non_constant_identifier_names import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/core/type/types.dart'; class DocumentModel extends Equatable { static const idKey = 'id'; @@ -48,7 +47,7 @@ class DocumentModel extends Equatable { this.storagePath, }); - DocumentModel.fromJson(JSON json) + DocumentModel.fromJson(Map json) : id = json[idKey], title = json[titleKey], content = json[contentKey], @@ -63,7 +62,7 @@ class DocumentModel extends Equatable { documentType = json[documentTypeKey], storagePath = json[storagePathKey]; - JSON toJson() { + Map toJson() { return { idKey: id, titleKey: title, diff --git a/lib/features/documents/model/filter_rule.model.dart b/packages/paperless_api/lib/src/models/filter_rule_model.dart similarity index 86% rename from lib/features/documents/model/filter_rule.model.dart rename to packages/paperless_api/lib/src/models/filter_rule_model.dart index 7d6eafa..5de3454 100644 --- a/lib/features/documents/model/filter_rule.model.dart +++ b/packages/paperless_api/lib/src/models/filter_rule_model.dart @@ -1,12 +1,11 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/query_type.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/util.dart'; +import 'package:paperless_api/src/constants.dart'; +import 'package:paperless_api/src/models/document_filter.dart'; +import 'package:paperless_api/src/models/query_parameters/correspondent_query.dart'; +import 'package:paperless_api/src/models/query_parameters/document_type_query.dart'; +import 'package:paperless_api/src/models/query_parameters/query_type.dart'; +import 'package:paperless_api/src/models/query_parameters/storage_path_query.dart'; +import 'package:paperless_api/src/models/query_parameters/tags_query.dart'; class FilterRule with EquatableMixin { static const int titleRule = 0; @@ -42,11 +41,11 @@ class FilterRule with EquatableMixin { FilterRule(this.ruleType, this.value); - FilterRule.fromJson(JSON json) + FilterRule.fromJson(Map json) : ruleType = json['rule_type'], value = json['value']; - JSON toJson() { + Map toJson() { return { 'rule_type': ruleType, 'value': value, @@ -182,19 +181,19 @@ class FilterRule with EquatableMixin { } if (filter.createdDateAfter != null) { filterRules.add(FilterRule( - createdAfterRule, dateFormat.format(filter.createdDateAfter!))); + createdAfterRule, apiDateFormat.format(filter.createdDateAfter!))); } if (filter.createdDateBefore != null) { filterRules.add(FilterRule( - createdBeforeRule, dateFormat.format(filter.createdDateBefore!))); + createdBeforeRule, apiDateFormat.format(filter.createdDateBefore!))); } if (filter.addedDateAfter != null) { filterRules.add(FilterRule( - addedAfterRule, dateFormat.format(filter.addedDateAfter!))); + addedAfterRule, apiDateFormat.format(filter.addedDateAfter!))); } if (filter.addedDateBefore != null) { filterRules.add(FilterRule( - addedBeforeRule, dateFormat.format(filter.addedDateBefore!))); + addedBeforeRule, apiDateFormat.format(filter.addedDateBefore!))); } return filterRules; } diff --git a/lib/features/labels/correspondent/model/correspondent.model.dart b/packages/paperless_api/lib/src/models/labels/correspondent_model.dart similarity index 72% rename from lib/features/labels/correspondent/model/correspondent.model.dart rename to packages/paperless_api/lib/src/models/labels/correspondent_model.dart index 7fbfd6b..bdbed30 100644 --- a/lib/features/labels/correspondent/model/correspondent.model.dart +++ b/packages/paperless_api/lib/src/models/labels/correspondent_model.dart @@ -1,7 +1,5 @@ -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/extensions/dart_extensions.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_api/src/models/labels/label_model.dart'; +import 'package:paperless_api/src/models/labels/matching_algorithm.dart'; class Correspondent extends Label { static const lastCorrespondenceKey = 'last_correspondence'; @@ -19,7 +17,7 @@ class Correspondent extends Label { this.lastCorrespondence, }); - Correspondent.fromJson(JSON json) + Correspondent.fromJson(Map json) : lastCorrespondence = DateTime.tryParse(json[lastCorrespondenceKey] ?? ''), super.fromJson(json); @@ -30,11 +28,11 @@ class Correspondent extends Label { } @override - void addSpecificFieldsToJson(JSON json) { - json.tryPutIfAbsent( - lastCorrespondenceKey, - () => lastCorrespondence?.toIso8601String(), - ); + void addSpecificFieldsToJson(Map json) { + if (lastCorrespondence != null) { + json.putIfAbsent( + lastCorrespondenceKey, () => lastCorrespondence!.toIso8601String()); + } } @override diff --git a/lib/features/labels/document_type/model/document_type.model.dart b/packages/paperless_api/lib/src/models/labels/document_type_model.dart similarity index 71% rename from lib/features/labels/document_type/model/document_type.model.dart rename to packages/paperless_api/lib/src/models/labels/document_type_model.dart index 29240e1..df646fa 100644 --- a/lib/features/labels/document_type/model/document_type.model.dart +++ b/packages/paperless_api/lib/src/models/labels/document_type_model.dart @@ -1,6 +1,5 @@ -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_api/src/models/labels/label_model.dart'; +import 'package:paperless_api/src/models/labels/matching_algorithm.dart'; class DocumentType extends Label { DocumentType({ @@ -13,10 +12,10 @@ class DocumentType extends Label { super.documentCount, }); - DocumentType.fromJson(JSON json) : super.fromJson(json); + DocumentType.fromJson(Map json) : super.fromJson(json); @override - void addSpecificFieldsToJson(JSON json) {} + void addSpecificFieldsToJson(Map json) {} @override String get queryEndpoint => 'document_types'; diff --git a/lib/features/labels/model/label.model.dart b/packages/paperless_api/lib/src/models/labels/label_model.dart similarity index 68% rename from lib/features/labels/model/label.model.dart rename to packages/paperless_api/lib/src/models/labels/label_model.dart index 3cd9b4a..1e9b3ab 100644 --- a/lib/features/labels/model/label.model.dart +++ b/packages/paperless_api/lib/src/models/labels/label_model.dart @@ -1,7 +1,5 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/extensions/dart_extensions.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; +import 'package:paperless_api/src/models/labels/matching_algorithm.dart'; abstract class Label with EquatableMixin implements Comparable { static const idKey = "id"; @@ -32,7 +30,7 @@ abstract class Label with EquatableMixin implements Comparable { this.slug, }); - Label.fromJson(JSON json) + Label.fromJson(Map json) : id = json[idKey], name = json[nameKey], slug = json[slugKey], @@ -42,20 +40,20 @@ abstract class Label with EquatableMixin implements Comparable { isInsensitive = json[isInsensitiveKey], documentCount = json[documentCountKey]; - JSON toJson() { - JSON json = {}; - json.tryPutIfAbsent(idKey, () => id); - json.tryPutIfAbsent(nameKey, () => name); - json.tryPutIfAbsent(slugKey, () => slug); - json.tryPutIfAbsent(matchKey, () => match); - json.tryPutIfAbsent(matchingAlgorithmKey, () => matchingAlgorithm?.value); - json.tryPutIfAbsent(isInsensitiveKey, () => isInsensitive); - json.tryPutIfAbsent(documentCountKey, () => documentCount); + Map toJson() { + Map json = {}; + json.putIfAbsent(idKey, () => id); + json.putIfAbsent(nameKey, () => name); + json.putIfAbsent(slugKey, () => slug); + json.putIfAbsent(matchKey, () => match); + json.putIfAbsent(matchingAlgorithmKey, () => matchingAlgorithm?.value); + json.putIfAbsent(isInsensitiveKey, () => isInsensitive); + json.putIfAbsent(documentCountKey, () => documentCount); addSpecificFieldsToJson(json); return json; } - void addSpecificFieldsToJson(JSON json); + void addSpecificFieldsToJson(Map json); Label copyWith({ int? id, diff --git a/lib/features/labels/document_type/model/matching_algorithm.dart b/packages/paperless_api/lib/src/models/labels/matching_algorithm.dart similarity index 100% rename from lib/features/labels/document_type/model/matching_algorithm.dart rename to packages/paperless_api/lib/src/models/labels/matching_algorithm.dart diff --git a/lib/features/labels/storage_path/model/storage_path.model.dart b/packages/paperless_api/lib/src/models/labels/storage_path_model.dart similarity index 74% rename from lib/features/labels/storage_path/model/storage_path.model.dart rename to packages/paperless_api/lib/src/models/labels/storage_path_model.dart index 2b48c34..fdd1393 100644 --- a/lib/features/labels/storage_path/model/storage_path.model.dart +++ b/packages/paperless_api/lib/src/models/labels/storage_path_model.dart @@ -1,7 +1,5 @@ -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/extensions/dart_extensions.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_api/src/models/labels/label_model.dart'; +import 'package:paperless_api/src/models/labels/matching_algorithm.dart'; class StoragePath extends Label { static const pathKey = 'path'; @@ -19,7 +17,7 @@ class StoragePath extends Label { required this.path, }); - StoragePath.fromJson(JSON json) + StoragePath.fromJson(Map json) : path = json[pathKey], super.fromJson(json); @@ -29,8 +27,8 @@ class StoragePath extends Label { } @override - void addSpecificFieldsToJson(JSON json) { - json.tryPutIfAbsent( + void addSpecificFieldsToJson(Map json) { + json.putIfAbsent( pathKey, () => path, ); diff --git a/lib/features/labels/tags/model/tag.model.dart b/packages/paperless_api/lib/src/models/labels/tag_model.dart similarity index 82% rename from lib/features/labels/tags/model/tag.model.dart rename to packages/paperless_api/lib/src/models/labels/tag_model.dart index 01b79de..f5bc3a3 100644 --- a/lib/features/labels/tags/model/tag.model.dart +++ b/packages/paperless_api/lib/src/models/labels/tag_model.dart @@ -1,10 +1,8 @@ import 'dart:developer'; import 'dart:ui'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/extensions/dart_extensions.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/matching_algorithm.dart'; -import 'package:paperless_mobile/features/labels/model/label.model.dart'; +import 'package:paperless_api/src/models/labels/label_model.dart'; +import 'package:paperless_api/src/models/labels/matching_algorithm.dart'; class Tag extends Label { static const colorKey = 'color'; @@ -29,7 +27,7 @@ class Tag extends Label { this.isInboxTag, }); - Tag.fromJson(JSON json) + Tag.fromJson(Map json) : isInboxTag = json[isInboxTagKey], textColor = Color(_colorStringToInt(json[textColorKey]) ?? 0), color = _parseColorFromJson(json), @@ -39,7 +37,7 @@ class Tag extends Label { /// The `color` field of the json object can either be of type [Color] or a hex [String]. /// Since API version 2, the old attribute `colour` has been replaced with `color`. /// - static Color _parseColorFromJson(JSON json) { + static Color _parseColorFromJson(Map json) { if (json.containsKey(legacyColourKey)) { return Color(_colorStringToInt(json[legacyColourKey]) ?? 0); } @@ -55,9 +53,9 @@ class Tag extends Label { } @override - void addSpecificFieldsToJson(JSON json) { - json.tryPutIfAbsent(colorKey, () => _toHex(color)); - json.tryPutIfAbsent(isInboxTagKey, () => isInboxTag); + void addSpecificFieldsToJson(Map json) { + json.putIfAbsent(colorKey, () => _toHex(color)); + json.putIfAbsent(isInboxTagKey, () => isInboxTag); } @override diff --git a/packages/paperless_api/lib/src/models/models.dart b/packages/paperless_api/lib/src/models/models.dart new file mode 100644 index 0000000..12e48f7 --- /dev/null +++ b/packages/paperless_api/lib/src/models/models.dart @@ -0,0 +1,26 @@ +export 'labels/correspondent_model.dart'; +export 'labels/document_type_model.dart'; +export 'labels/label_model.dart'; +export 'labels/matching_algorithm.dart'; +export 'labels/storage_path_model.dart'; +export 'labels/tag_model.dart'; +export 'query_parameters/asn_query.dart'; +export 'query_parameters/correspondent_query.dart'; +export 'query_parameters/document_type_query.dart'; +export 'query_parameters/id_query_parameter.dart'; +export 'query_parameters/query_type.dart'; +export 'query_parameters/sort_field.dart'; +export 'query_parameters/sort_order.dart'; +export 'query_parameters/storage_path_query.dart'; +export 'query_parameters/tags_query.dart'; +export 'bulk_edit_model.dart'; +export 'document_filter.dart'; +export 'document_meta_data_model.dart'; +export 'document_model.dart'; +export 'filter_rule_model.dart'; +export 'paged_search_result.dart'; +export 'paperless_server_exception.dart'; +export 'paperless_server_information_model.dart'; +export 'paperless_server_statistics_model.dart'; +export 'saved_view_model.dart'; +export 'similar_document_model.dart'; diff --git a/lib/features/documents/model/paged_search_result.dart b/packages/paperless_api/lib/src/models/paged_search_result.dart similarity index 90% rename from lib/features/documents/model/paged_search_result.dart rename to packages/paperless_api/lib/src/models/paged_search_result.dart index c95878a..adc8500 100644 --- a/lib/features/documents/model/paged_search_result.dart +++ b/packages/paperless_api/lib/src/models/paged_search_result.dart @@ -1,12 +1,11 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; +import 'package:paperless_api/src/models/document_model.dart'; const pageRegex = r".*page=(\d+).*"; class PagedSearchResultJsonSerializer { - final JSON json; - final T Function(JSON) fromJson; + final Map json; + final T Function(Map) fromJson; PagedSearchResultJsonSerializer(this.json, this.fromJson); } @@ -58,7 +57,7 @@ class PagedSearchResult extends Equatable { count: serializer.json['count'], next: serializer.json['next'], previous: serializer.json['previous'], - results: List.from(serializer.json['results']) + results: List>.from(serializer.json['results']) .map(serializer.fromJson) .toList(), ); diff --git a/lib/core/model/error_message.dart b/packages/paperless_api/lib/src/models/paperless_server_exception.dart similarity index 88% rename from lib/core/model/error_message.dart rename to packages/paperless_api/lib/src/models/paperless_server_exception.dart index 098bbb1..aa2b6ba 100644 --- a/lib/core/model/error_message.dart +++ b/packages/paperless_api/lib/src/models/paperless_server_exception.dart @@ -1,17 +1,17 @@ -class ErrorMessage implements Exception { +class PaperlessServerException implements Exception { final ErrorCode code; final String? details; final StackTrace? stackTrace; final int? httpStatusCode; - const ErrorMessage( + const PaperlessServerException( this.code, { this.details, this.stackTrace, this.httpStatusCode, }); - const ErrorMessage.unknown() : this(ErrorCode.unknown); + const PaperlessServerException.unknown() : this(ErrorCode.unknown); @override String toString() { diff --git a/lib/core/model/paperless_server_information.dart b/packages/paperless_api/lib/src/models/paperless_server_information_model.dart similarity index 82% rename from lib/core/model/paperless_server_information.dart rename to packages/paperless_api/lib/src/models/paperless_server_information_model.dart index aabece9..70fb3f4 100644 --- a/lib/core/model/paperless_server_information.dart +++ b/packages/paperless_api/lib/src/models/paperless_server_information_model.dart @@ -1,4 +1,4 @@ -class PaperlessServerInformation { +class PaperlessServerInformationModel { static const String versionHeader = 'x-version'; static const String apiVersionHeader = 'x-api-version'; static const String hostHeader = 'x-served-by'; @@ -6,7 +6,8 @@ class PaperlessServerInformation { final int? apiVersion; final String? username; final String? host; - PaperlessServerInformation({ + + PaperlessServerInformationModel({ this.host, this.username, this.version = 'unknown', diff --git a/lib/core/model/paperless_statistics.dart b/packages/paperless_api/lib/src/models/paperless_server_statistics_model.dart similarity index 61% rename from lib/core/model/paperless_statistics.dart rename to packages/paperless_api/lib/src/models/paperless_server_statistics_model.dart index 3e70054..d5ac901 100644 --- a/lib/core/model/paperless_statistics.dart +++ b/packages/paperless_api/lib/src/models/paperless_server_statistics_model.dart @@ -1,15 +1,13 @@ -import 'package:paperless_mobile/core/type/types.dart'; - -class PaperlessStatistics { +class PaperlessServerStatisticsModel { final int documentsTotal; final int documentsInInbox; - PaperlessStatistics({ + PaperlessServerStatisticsModel({ required this.documentsTotal, required this.documentsInInbox, }); - PaperlessStatistics.fromJson(JSON json) + PaperlessServerStatisticsModel.fromJson(Map json) : documentsTotal = json['documents_total'], documentsInInbox = json['documents_inbox']; } diff --git a/lib/features/documents/model/query_parameters/asn_query.dart b/packages/paperless_api/lib/src/models/query_parameters/asn_query.dart similarity index 75% rename from lib/features/documents/model/query_parameters/asn_query.dart rename to packages/paperless_api/lib/src/models/query_parameters/asn_query.dart index ef8003f..93b890b 100644 --- a/lib/features/documents/model/query_parameters/asn_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/asn_query.dart @@ -1,4 +1,4 @@ -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; +import 'package:paperless_api/src/models/query_parameters/id_query_parameter.dart'; class AsnQuery extends IdQueryParameter { const AsnQuery.fromId(super.id) : super.fromId(); diff --git a/lib/features/documents/model/query_parameters/correspondent_query.dart b/packages/paperless_api/lib/src/models/query_parameters/correspondent_query.dart similarity index 78% rename from lib/features/documents/model/query_parameters/correspondent_query.dart rename to packages/paperless_api/lib/src/models/query_parameters/correspondent_query.dart index 27239f3..f64b2e1 100644 --- a/lib/features/documents/model/query_parameters/correspondent_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/correspondent_query.dart @@ -1,4 +1,4 @@ -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; +import 'package:paperless_api/src/models/query_parameters/id_query_parameter.dart'; class CorrespondentQuery extends IdQueryParameter { const CorrespondentQuery.fromId(super.id) : super.fromId(); diff --git a/lib/features/documents/model/query_parameters/document_type_query.dart b/packages/paperless_api/lib/src/models/query_parameters/document_type_query.dart similarity index 77% rename from lib/features/documents/model/query_parameters/document_type_query.dart rename to packages/paperless_api/lib/src/models/query_parameters/document_type_query.dart index b8df06b..ca6a009 100644 --- a/lib/features/documents/model/query_parameters/document_type_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/document_type_query.dart @@ -1,4 +1,4 @@ -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; +import 'package:paperless_api/src/models/query_parameters/id_query_parameter.dart'; class DocumentTypeQuery extends IdQueryParameter { const DocumentTypeQuery.fromId(super.id) : super.fromId(); diff --git a/lib/features/documents/model/query_parameters/id_query_parameter.dart b/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart similarity index 95% rename from lib/features/documents/model/query_parameters/id_query_parameter.dart rename to packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart index 6274a87..7e7a489 100644 --- a/lib/features/documents/model/query_parameters/id_query_parameter.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/id_query_parameter.dart @@ -1,5 +1,4 @@ import 'package:equatable/equatable.dart'; -import 'package:flutter/widgets.dart'; abstract class IdQueryParameter extends Equatable { final int? _assignmentStatus; @@ -29,7 +28,6 @@ abstract class IdQueryParameter extends Equatable { int? get id => _id; - @protected String get queryParameterKey; String toQueryParameter() { diff --git a/lib/features/documents/model/query_parameters/query_type.dart b/packages/paperless_api/lib/src/models/query_parameters/query_type.dart similarity index 100% rename from lib/features/documents/model/query_parameters/query_type.dart rename to packages/paperless_api/lib/src/models/query_parameters/query_type.dart diff --git a/lib/features/documents/model/query_parameters/sort_field.dart b/packages/paperless_api/lib/src/models/query_parameters/sort_field.dart similarity index 100% rename from lib/features/documents/model/query_parameters/sort_field.dart rename to packages/paperless_api/lib/src/models/query_parameters/sort_field.dart diff --git a/lib/features/documents/model/query_parameters/sort_order.dart b/packages/paperless_api/lib/src/models/query_parameters/sort_order.dart similarity index 100% rename from lib/features/documents/model/query_parameters/sort_order.dart rename to packages/paperless_api/lib/src/models/query_parameters/sort_order.dart diff --git a/lib/features/documents/model/query_parameters/storage_path_query.dart b/packages/paperless_api/lib/src/models/query_parameters/storage_path_query.dart similarity index 77% rename from lib/features/documents/model/query_parameters/storage_path_query.dart rename to packages/paperless_api/lib/src/models/query_parameters/storage_path_query.dart index 65cc915..e0ccc98 100644 --- a/lib/features/documents/model/query_parameters/storage_path_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/storage_path_query.dart @@ -1,4 +1,4 @@ -import 'package:paperless_mobile/features/documents/model/query_parameters/id_query_parameter.dart'; +import 'package:paperless_api/src/models/query_parameters/id_query_parameter.dart'; class StoragePathQuery extends IdQueryParameter { const StoragePathQuery.fromId(super.id) : super.fromId(); diff --git a/lib/features/documents/model/query_parameters/tags_query.dart b/packages/paperless_api/lib/src/models/query_parameters/tags_query.dart similarity index 94% rename from lib/features/documents/model/query_parameters/tags_query.dart rename to packages/paperless_api/lib/src/models/query_parameters/tags_query.dart index 687d0b0..5b272ce 100644 --- a/lib/features/documents/model/query_parameters/tags_query.dart +++ b/packages/paperless_api/lib/src/models/query_parameters/tags_query.dart @@ -1,15 +1,12 @@ import 'package:equatable/equatable.dart'; -abstract class TagsQuery with EquatableMixin { +abstract class TagsQuery { const TagsQuery(); String toQueryParameter(); } class OnlyNotAssignedTagsQuery extends TagsQuery { const OnlyNotAssignedTagsQuery(); - @override - List get props => []; - @override String toQueryParameter() { return '&is_tagged=0'; @@ -22,8 +19,6 @@ class AnyAssignedTagsQuery extends TagsQuery { const AnyAssignedTagsQuery({ this.tagIds = const [], }); - @override - List get props => []; @override String toQueryParameter() { @@ -98,9 +93,6 @@ class IdsTagsQuery extends TagsQuery { } return sb.toString(); } - - @override - List get props => [_idQueries]; } abstract class TagIdQuery with EquatableMixin { diff --git a/lib/features/documents/model/saved_view.model.dart b/packages/paperless_api/lib/src/models/saved_view_model.dart similarity index 83% rename from lib/features/documents/model/saved_view.model.dart rename to packages/paperless_api/lib/src/models/saved_view_model.dart index cc375c0..4dfeda0 100644 --- a/lib/features/documents/model/saved_view.model.dart +++ b/packages/paperless_api/lib/src/models/saved_view_model.dart @@ -1,9 +1,8 @@ import 'package:equatable/equatable.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/filter_rule.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; +import 'package:paperless_api/src/models/document_filter.dart'; +import 'package:paperless_api/src/models/filter_rule_model.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_field.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_order.dart'; class SavedView with EquatableMixin { final int? id; @@ -42,7 +41,7 @@ class SavedView with EquatableMixin { filterRules ]; - SavedView.fromJson(JSON json) + SavedView.fromJson(Map json) : this( id: json['id'], name: json['name'], @@ -53,7 +52,7 @@ class SavedView with EquatableMixin { .first, sortReverse: json['sort_reverse'], filterRules: (json['filter_rules'] as List) - .cast() + .cast>() .map(FilterRule.fromJson) .toList(), ); @@ -83,7 +82,7 @@ class SavedView with EquatableMixin { sortReverse: filter.sortOrder == SortOrder.descending, ); - JSON toJson() { + Map toJson() { return { 'id': id, 'name': name, diff --git a/lib/features/documents/model/similar_document.model.dart b/packages/paperless_api/lib/src/models/similar_document_model.dart similarity index 81% rename from lib/features/documents/model/similar_document.model.dart rename to packages/paperless_api/lib/src/models/similar_document_model.dart index de897c6..db033b7 100644 --- a/lib/features/documents/model/similar_document.model.dart +++ b/packages/paperless_api/lib/src/models/similar_document_model.dart @@ -1,5 +1,4 @@ -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; +import 'package:paperless_api/src/models/document_model.dart'; class SimilarDocumentModel extends DocumentModel { final SearchHit searchHit; @@ -22,13 +21,13 @@ class SimilarDocumentModel extends DocumentModel { }); @override - JSON toJson() { + Map toJson() { final json = super.toJson(); json['__search_hit__'] = searchHit.toJson(); return json; } - SimilarDocumentModel.fromJson(JSON json) + SimilarDocumentModel.fromJson(Map json) : searchHit = SearchHit.fromJson(json), super.fromJson(json); } @@ -44,7 +43,7 @@ class SearchHit { required this.rank, }); - JSON toJson() { + Map toJson() { return { 'score': score, 'highlights': highlights, @@ -52,7 +51,7 @@ class SearchHit { }; } - SearchHit.fromJson(JSON json) + SearchHit.fromJson(Map json) : score = json['score'], highlights = json['highlights'], rank = json['rank']; diff --git a/packages/paperless_api/lib/src/modules/authentication_api/authentication_api.dart b/packages/paperless_api/lib/src/modules/authentication_api/authentication_api.dart new file mode 100644 index 0000000..ea5bba2 --- /dev/null +++ b/packages/paperless_api/lib/src/modules/authentication_api/authentication_api.dart @@ -0,0 +1,7 @@ +abstract class PaperlessAuthenticationApi { + Future login({ + required String username, + required String password, + required String serverUrl, + }); +} diff --git a/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart b/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart new file mode 100644 index 0000000..735c0bf --- /dev/null +++ b/packages/paperless_api/lib/src/modules/authentication_api/authentication_api_impl.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:http/http.dart'; +import 'package:paperless_api/src/models/paperless_server_exception.dart'; +import 'package:paperless_api/src/modules/authentication_api/authentication_api.dart'; + +class PaperlessAuthenticationApiImpl implements PaperlessAuthenticationApi { + final BaseClient client; + + PaperlessAuthenticationApiImpl(this.client); + + @override + Future login({ + required String username, + required String password, + required String serverUrl, + }) async { + late Response response; + try { + response = await client.post( + Uri.parse("/api/token/"), + body: {"username": username, "password": password}, + ); + } on FormatException catch (e) { + final source = e.source; + if (source is String && + source.contains("400 No required SSL certificate was sent")) { + throw PaperlessServerException( + ErrorCode.missingClientCertificate, + httpStatusCode: response.statusCode, + ); + } + } + if (response.statusCode == HttpStatus.ok) { + final data = jsonDecode(utf8.decode(response.bodyBytes)); + return data['token']; + } else if (response.statusCode == HttpStatus.badRequest && + response.body + .toLowerCase() + .contains("no required certificate was sent")) { + throw PaperlessServerException( + ErrorCode.invalidClientCertificateConfiguration, + httpStatusCode: response.statusCode, + ); + } else { + throw PaperlessServerException( + ErrorCode.authenticationFailed, + httpStatusCode: response.statusCode, + ); + } + } +} diff --git a/lib/features/documents/repository/document_repository.dart b/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api.dart similarity index 56% rename from lib/features/documents/repository/document_repository.dart rename to packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api.dart index 27f1356..cb3d15e 100644 --- a/lib/features/documents/repository/document_repository.dart +++ b/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api.dart @@ -1,18 +1,19 @@ import 'dart:typed_data'; -import 'package:paperless_mobile/features/documents/model/bulk_edit.model.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/document_meta_data.model.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; -import 'package:paperless_mobile/features/documents/model/similar_document.model.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; +import 'package:paperless_api/src/models/bulk_edit_model.dart'; +import 'package:paperless_api/src/models/document_filter.dart'; +import 'package:paperless_api/src/models/document_meta_data_model.dart'; +import 'package:paperless_api/src/models/document_model.dart'; +import 'package:paperless_api/src/models/paged_search_result.dart'; +import 'package:paperless_api/src/models/similar_document_model.dart'; -abstract class DocumentRepository { +abstract class PaperlessDocumentsApi { Future create( - Uint8List documentBytes, - String filename, { + Uint8List documentBytes, { + required String filename, required String title, + required String authToken, + required String serverUrl, int? documentType, int? correspondent, Iterable tags = const [], diff --git a/lib/features/documents/repository/document_repository_impl.dart b/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart similarity index 60% rename from lib/features/documents/repository/document_repository_impl.dart rename to packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart index 49639f5..11e6890 100644 --- a/lib/features/documents/repository/document_repository_impl.dart +++ b/packages/paperless_api/lib/src/modules/documents_api/paperless_documents_api_impl.dart @@ -1,64 +1,45 @@ -import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:math'; -import 'dart:typed_data'; - +import 'package:http/src/boundary_characters.dart'; import 'package:flutter/foundation.dart'; import 'package:http/http.dart'; -import 'package:http/src/boundary_characters.dart'; //TODO: remove once there is either a paperless API update or there is a better solution... -import 'package:injectable/injectable.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/store/local_vault.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/core/util.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/extensions/dart_extensions.dart'; -import 'package:paperless_mobile/features/documents/model/bulk_edit.model.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/document_meta_data.model.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/asn_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; -import 'package:paperless_mobile/features/documents/model/similar_document.model.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; -import 'package:paperless_mobile/util.dart'; +import 'package:paperless_api/src/constants.dart'; +import 'package:paperless_api/src/models/bulk_edit_model.dart'; +import 'package:paperless_api/src/models/document_filter.dart'; +import 'package:paperless_api/src/models/document_meta_data_model.dart'; +import 'package:paperless_api/src/models/document_model.dart'; +import 'package:paperless_api/src/models/paged_search_result.dart'; +import 'package:paperless_api/src/models/paperless_server_exception.dart'; +import 'package:paperless_api/src/models/query_parameters/asn_query.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_field.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_order.dart'; +import 'package:paperless_api/src/models/similar_document_model.dart'; +import 'paperless_documents_api.dart'; -@Injectable(as: DocumentRepository) -class DocumentRepositoryImpl implements DocumentRepository { - //// - //final StatusService statusService; - final LocalVault localStorage; - final BaseClient httpClient; +class PaperlessDocumentsApiImpl implements PaperlessDocumentsApi { + final BaseClient baseClient; + final HttpClient httpClient; + + PaperlessDocumentsApiImpl(this.baseClient, this.httpClient); - DocumentRepositoryImpl( - //this.statusService, - this.localStorage, - @Named("timeoutClient") this.httpClient, - ); @override Future create( - Uint8List documentBytes, - String filename, { + Uint8List documentBytes, { + required String filename, required String title, + required String authToken, + required String serverUrl, int? documentType, int? correspondent, Iterable tags = const [], DateTime? createdAt, }) async { - final auth = await localStorage.loadAuthenticationInformation(); - - if (auth == null) { - throw const ErrorMessage(ErrorCode.notAuthenticated); - } - // The multipart request has to be generated from scratch as the http library does // not allow the same key (tags) to be added multiple times. However, this is what the // paperless api expects, i.e. one block for each tag. - final request = await getIt().postUrl( - Uri.parse("${auth.serverUrl}/api/documents/post_document/"), + final request = await httpClient.postUrl( + Uri.parse("$serverUrl/api/documents/post_document/"), ); final boundary = _boundaryString(); @@ -66,13 +47,16 @@ class DocumentRepositoryImpl implements DocumentRepository { StringBuffer bodyBuffer = StringBuffer(); var fields = {}; - - fields.tryPutIfAbsent('title', () => title); - fields.tryPutIfAbsent('created', () => formatDateNullable(createdAt)); - fields.tryPutIfAbsent('correspondent', - () => correspondent == null ? null : json.encode(correspondent)); - fields.tryPutIfAbsent('document_type', - () => documentType == null ? null : json.encode(documentType)); + fields.putIfAbsent('title', () => title); + if (createdAt != null) { + fields.putIfAbsent('created', () => apiDateFormat.format(createdAt)); + } + if (correspondent != null) { + fields.putIfAbsent('correspondent', () => jsonEncode(correspondent)); + } + if (documentType != null) { + fields.putIfAbsent('document_type', () => jsonEncode(documentType)); + } for (final key in fields.keys) { bodyBuffer.write(_buildMultipartField(key, fields[key]!, boundary)); @@ -87,14 +71,14 @@ class DocumentRepositoryImpl implements DocumentRepository { "\r\nContent-type: application/octet-stream" "\r\n\r\n"); - final closing = "\r\n--" + boundary + "--\r\n"; + final closing = "\r\n--$boundary--\r\n"; // Set headers request.headers.set(HttpHeaders.contentTypeHeader, - "multipart/form-data; boundary=" + boundary); + "multipart/form-data; boundary=$boundary"); request.headers.set(HttpHeaders.contentLengthHeader, "${bodyBuffer.length + closing.length + documentBytes.lengthInBytes}"); - request.headers.set(HttpHeaders.authorizationHeader, "Token ${auth.token}"); + request.headers.set(HttpHeaders.authorizationHeader, "Token $authToken"); //Write fields to request request.write(bodyBuffer.toString()); @@ -106,12 +90,15 @@ class DocumentRepositoryImpl implements DocumentRepository { final response = await request.close(); if (response.statusCode != 200) { - throw ErrorMessage(ErrorCode.documentUploadFailed, - httpStatusCode: response.statusCode); + throw PaperlessServerException( + ErrorCode.documentUploadFailed, + httpStatusCode: response.statusCode, + ); } } String _buildMultipartField(String fieldName, String value, String boundary) { + // ignore: prefer_interpolation_to_compose_strings return '--$boundary' '\r\nContent-Disposition: form-data; name="$fieldName"' '\r\nContent-type: text/plain' @@ -133,24 +120,24 @@ class DocumentRepositoryImpl implements DocumentRepository { @override Future update(DocumentModel doc) async { - final response = await httpClient.put( + final response = await baseClient.put( Uri.parse("/api/documents/${doc.id}/"), body: json.encode(doc.toJson()), headers: {"Content-Type": "application/json"}, ); if (response.statusCode == 200) { return DocumentModel.fromJson( - jsonDecode(utf8.decode(response.bodyBytes)) as JSON, + jsonDecode(utf8.decode(response.bodyBytes)) as Map, ); } else { - throw const ErrorMessage(ErrorCode.documentUpdateFailed); + throw const PaperlessServerException(ErrorCode.documentUpdateFailed); } } @override Future> find(DocumentFilter filter) async { final filterParams = filter.toQueryString(); - final response = await httpClient.get( + final response = await baseClient.get( Uri.parse("/api/documents/?$filterParams"), ); if (response.statusCode == 200) { @@ -162,19 +149,19 @@ class DocumentRepositoryImpl implements DocumentRepository { ), ); } else { - throw const ErrorMessage(ErrorCode.documentLoadFailed); + throw const PaperlessServerException(ErrorCode.documentLoadFailed); } } @override Future delete(DocumentModel doc) async { final response = - await httpClient.delete(Uri.parse("/api/documents/${doc.id}/")); + await baseClient.delete(Uri.parse("/api/documents/${doc.id}/")); if (response.statusCode == 204) { return Future.value(doc.id); } - throw const ErrorMessage(ErrorCode.documentDeleteFailed); + throw const PaperlessServerException(ErrorCode.documentDeleteFailed); } @override @@ -188,11 +175,11 @@ class DocumentRepositoryImpl implements DocumentRepository { @override Future getPreview(int documentId) async { - final response = await httpClient.get(Uri.parse(getPreviewUrl(documentId))); + final response = await baseClient.get(Uri.parse(getPreviewUrl(documentId))); if (response.statusCode == 200) { return response.bodyBytes; } - throw const ErrorMessage(ErrorCode.documentPreviewFailed); + throw const PaperlessServerException(ErrorCode.documentPreviewFailed); } @override @@ -210,14 +197,14 @@ class DocumentRepositoryImpl implements DocumentRepository { .map((e) => e.archiveSerialNumber) .firstWhere((asn) => asn != null, orElse: () => 0)! + 1; - } on ErrorMessage catch (_) { - throw const ErrorMessage(ErrorCode.documentAsnQueryFailed); + } on PaperlessServerException catch (_) { + throw const PaperlessServerException(ErrorCode.documentAsnQueryFailed); } } @override Future> bulkAction(BulkAction action) async { - final response = await httpClient.post( + final response = await baseClient.post( Uri.parse("/api/documents/bulk_edit/"), body: json.encode(action.toJson()), headers: {'Content-Type': 'application/json'}, @@ -225,15 +212,13 @@ class DocumentRepositoryImpl implements DocumentRepository { if (response.statusCode == 200) { return action.documentIds; } else { - throw const ErrorMessage(ErrorCode.documentBulkActionFailed); + throw const PaperlessServerException(ErrorCode.documentBulkActionFailed); } } @override Future waitForConsumptionFinished( String fileName, String title) async { - // Always wait 5 seconds, processing usually takes longer... - //await Future.delayed(const Duration(seconds: 5)); PagedSearchResult results = await find(DocumentFilter.latestDocument); @@ -247,41 +232,40 @@ class DocumentRepositoryImpl implements DocumentRepository { try { return results.results.first; } on StateError { - throw const ErrorMessage(ErrorCode.documentUploadFailed); + throw const PaperlessServerException(ErrorCode.documentUploadFailed); } } @override Future download(DocumentModel document) async { - //TODO: Check if this works... - final response = await httpClient + final response = await baseClient .get(Uri.parse("/api/documents/${document.id}/download/")); return response.bodyBytes; } @override Future getMetaData(DocumentModel document) async { - final response = await httpClient + final response = await baseClient .get(Uri.parse("/api/documents/${document.id}/metadata/")); return compute( DocumentMetaData.fromJson, - jsonDecode(utf8.decode(response.bodyBytes)) as JSON, + jsonDecode(utf8.decode(response.bodyBytes)) as Map, ); } @override Future> autocomplete(String query, [int limit = 10]) async { - final response = await httpClient + final response = await baseClient .get(Uri.parse("/api/search/autocomplete/?query=$query&limit=$limit}")); if (response.statusCode == 200) { return jsonDecode(utf8.decode(response.bodyBytes)) as List; } - throw const ErrorMessage(ErrorCode.autocompleteQueryError); + throw const PaperlessServerException(ErrorCode.autocompleteQueryError); } @override Future> findSimilar(int docId) async { - final response = await httpClient + final response = await baseClient .get(Uri.parse("/api/documents/?more_like=$docId&pageSize=10")); if (response.statusCode == 200) { return (await compute( @@ -293,6 +277,6 @@ class DocumentRepositoryImpl implements DocumentRepository { )) .results; } - throw const ErrorMessage(ErrorCode.similarQueryError); + throw const PaperlessServerException(ErrorCode.similarQueryError); } } diff --git a/lib/features/labels/repository/label_repository.dart b/packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api.dart similarity index 66% rename from lib/features/labels/repository/label_repository.dart rename to packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api.dart index 7d117ba..d78c8da 100644 --- a/lib/features/labels/repository/label_repository.dart +++ b/packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api.dart @@ -1,9 +1,18 @@ -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; +import 'package:paperless_api/src/models/labels/correspondent_model.dart'; +import 'package:paperless_api/src/models/labels/document_type_model.dart'; +import 'package:paperless_api/src/models/labels/storage_path_model.dart'; +import 'package:paperless_api/src/models/labels/tag_model.dart'; -abstract class LabelRepository { +/// +/// Provides basic CRUD operations for labels, including: +///
    +///
  • Correspondents
  • +///
  • Document Types
  • +///
  • Tags
  • +///
  • Storage Paths
  • +///
+/// +abstract class PaperlessLabelsApi { Future getCorrespondent(int id); Future> getCorrespondents(); Future saveCorrespondent(Correspondent correspondent); diff --git a/lib/features/labels/repository/label_repository_impl.dart b/packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api_impl.dart similarity index 59% rename from lib/features/labels/repository/label_repository_impl.dart rename to packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api_impl.dart index fcbcf28..f48f4f9 100644 --- a/lib/features/labels/repository/label_repository_impl.dart +++ b/packages/paperless_api/lib/src/modules/labels_api/paperless_labels_api_impl.dart @@ -1,35 +1,37 @@ import 'dart:convert'; +import 'dart:io'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/util.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; -import 'package:paperless_mobile/features/labels/repository/label_repository.dart'; -import 'package:paperless_mobile/features/labels/storage_path/model/storage_path.model.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:http/http.dart'; -import 'package:injectable/injectable.dart'; +import 'package:paperless_api/src/models/labels/correspondent_model.dart'; +import 'package:paperless_api/src/models/labels/document_type_model.dart'; +import 'package:paperless_api/src/models/labels/storage_path_model.dart'; +import 'package:paperless_api/src/models/labels/tag_model.dart'; +import 'package:paperless_api/src/models/paperless_server_exception.dart'; +import 'package:paperless_api/src/modules/labels_api/paperless_labels_api.dart'; +import 'package:paperless_api/src/utils.dart'; -@Singleton(as: LabelRepository) -class LabelRepositoryImpl implements LabelRepository { - final BaseClient httpClient; - - LabelRepositoryImpl(@Named("timeoutClient") this.httpClient); +class PaperlessLabelApiImpl implements PaperlessLabelsApi { + final BaseClient client; + PaperlessLabelApiImpl(this.client); @override Future getCorrespondent(int id) async { return getSingleResult( "/api/correspondents/$id/", Correspondent.fromJson, ErrorCode.correspondentLoadFailed, + client: client, ); } @override Future getTag(int id) async { return getSingleResult( - "/api/tags/$id/", Tag.fromJson, ErrorCode.tagLoadFailed); + "/api/tags/$id/", + Tag.fromJson, + ErrorCode.tagLoadFailed, + client: client, + ); } @override @@ -38,6 +40,7 @@ class LabelRepositoryImpl implements LabelRepository { "/api/tags/?page=1&page_size=100000", Tag.fromJson, ErrorCode.tagLoadFailed, + client: client, minRequiredApiVersion: 2, ); return results @@ -51,6 +54,7 @@ class LabelRepositoryImpl implements LabelRepository { "/api/document_types/$id/", DocumentType.fromJson, ErrorCode.documentTypeLoadFailed, + client: client, ); } @@ -60,6 +64,7 @@ class LabelRepositoryImpl implements LabelRepository { "/api/correspondents/?page=1&page_size=100000", Correspondent.fromJson, ErrorCode.correspondentLoadFailed, + client: client, ); } @@ -69,43 +74,52 @@ class LabelRepositoryImpl implements LabelRepository { "/api/document_types/?page=1&page_size=100000", DocumentType.fromJson, ErrorCode.documentTypeLoadFailed, + client: client, ); } @override Future saveCorrespondent(Correspondent correspondent) async { - final response = await httpClient.post( + final response = await client.post( Uri.parse('/api/correspondents/'), - body: json.encode(correspondent.toJson()), + body: jsonEncode(correspondent.toJson()), headers: {"Content-Type": "application/json"}, encoding: Encoding.getByName("utf-8"), ); - if (response.statusCode == 201) { + if (response.statusCode == HttpStatus.created) { return Correspondent.fromJson( - jsonDecode(utf8.decode(response.bodyBytes))); + jsonDecode(utf8.decode(response.bodyBytes)), + ); } - throw ErrorMessage(ErrorCode.correspondentCreateFailed, - httpStatusCode: response.statusCode); + throw PaperlessServerException( + ErrorCode.correspondentCreateFailed, + httpStatusCode: response.statusCode, + ); } @override Future saveDocumentType(DocumentType type) async { - final response = await httpClient.post( + final response = await client.post( Uri.parse('/api/document_types/'), body: json.encode(type.toJson()), headers: {"Content-Type": "application/json"}, encoding: Encoding.getByName("utf-8"), ); - if (response.statusCode == 201) { - return DocumentType.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); + if (response.statusCode == HttpStatus.created) { + return DocumentType.fromJson( + jsonDecode(utf8.decode(response.bodyBytes)), + ); } - throw const ErrorMessage(ErrorCode.documentTypeCreateFailed); + throw PaperlessServerException( + ErrorCode.documentTypeCreateFailed, + httpStatusCode: response.statusCode, + ); } @override Future saveTag(Tag tag) async { final body = json.encode(tag.toJson()); - final response = await httpClient.post( + final response = await client.post( Uri.parse('/api/tags/'), body: body, headers: { @@ -114,79 +128,97 @@ class LabelRepositoryImpl implements LabelRepository { }, encoding: Encoding.getByName("utf-8"), ); - if (response.statusCode == 201) { + if (response.statusCode == HttpStatus.created) { return Tag.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); } - throw const ErrorMessage(ErrorCode.tagCreateFailed); + throw PaperlessServerException( + ErrorCode.tagCreateFailed, + httpStatusCode: response.statusCode, + ); } @override Future deleteCorrespondent(Correspondent correspondent) async { assert(correspondent.id != null); - final response = await httpClient + final response = await client .delete(Uri.parse('/api/correspondents/${correspondent.id}/')); - if (response.statusCode == 204) { + if (response.statusCode == HttpStatus.noContent) { return correspondent.id!; } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future deleteDocumentType(DocumentType documentType) async { assert(documentType.id != null); - final response = await httpClient + final response = await client .delete(Uri.parse('/api/document_types/${documentType.id}/')); - if (response.statusCode == 204) { + if (response.statusCode == HttpStatus.noContent) { return documentType.id!; } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future deleteTag(Tag tag) async { assert(tag.id != null); - final response = await httpClient.delete(Uri.parse('/api/tags/${tag.id}/')); - if (response.statusCode == 204) { + final response = await client.delete(Uri.parse('/api/tags/${tag.id}/')); + if (response.statusCode == HttpStatus.noContent) { return tag.id!; } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future updateCorrespondent(Correspondent correspondent) async { assert(correspondent.id != null); - final response = await httpClient.put( + final response = await client.put( Uri.parse('/api/correspondents/${correspondent.id}/'), headers: {"Content-Type": "application/json"}, body: json.encode(correspondent.toJson()), encoding: Encoding.getByName("utf-8"), ); - if (response.statusCode == 200) { + if (response.statusCode == HttpStatus.ok) { return Correspondent.fromJson( jsonDecode(utf8.decode(response.bodyBytes))); } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future updateDocumentType(DocumentType documentType) async { assert(documentType.id != null); - final response = await httpClient.put( + final response = await client.put( Uri.parse('/api/document_types/${documentType.id}/'), headers: {"Content-Type": "application/json"}, body: json.encode(documentType.toJson()), encoding: Encoding.getByName("utf-8"), ); - if (response.statusCode == 200) { + if (response.statusCode == HttpStatus.ok) { return DocumentType.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future updateTag(Tag tag) async { assert(tag.id != null); - final response = await httpClient.put( + final response = await client.put( Uri.parse('/api/tags/${tag.id}/'), headers: { "Accept": "application/json; version=2", @@ -195,27 +227,37 @@ class LabelRepositoryImpl implements LabelRepository { body: json.encode(tag.toJson()), encoding: Encoding.getByName("utf-8"), ); - if (response.statusCode == 200) { + if (response.statusCode == HttpStatus.ok) { return Tag.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future deleteStoragePath(StoragePath path) async { assert(path.id != null); final response = - await httpClient.delete(Uri.parse('/api/storage_paths/${path.id}/')); - if (response.statusCode == 204) { + await client.delete(Uri.parse('/api/storage_paths/${path.id}/')); + if (response.statusCode == HttpStatus.noContent) { return path.id!; } - throw const ErrorMessage(ErrorCode.unknown); + throw PaperlessServerException( + ErrorCode.unknown, + httpStatusCode: response.statusCode, + ); } @override Future getStoragePath(int id) { - return getSingleResult("/api/storage_paths/?page=1&page_size=100000", - StoragePath.fromJson, ErrorCode.storagePathLoadFailed); + return getSingleResult( + "/api/storage_paths/?page=1&page_size=100000", + StoragePath.fromJson, + ErrorCode.storagePathLoadFailed, + client: client, + ); } @override @@ -224,34 +266,35 @@ class LabelRepositoryImpl implements LabelRepository { "/api/storage_paths/?page=1&page_size=100000", StoragePath.fromJson, ErrorCode.storagePathLoadFailed, + client: client, ); } @override Future saveStoragePath(StoragePath path) async { - final response = await httpClient.post( + final response = await client.post( Uri.parse('/api/storage_paths/'), body: json.encode(path.toJson()), headers: {"Content-Type": "application/json"}, ); - if (response.statusCode == 201) { + if (response.statusCode == HttpStatus.created) { return StoragePath.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); } - throw ErrorMessage(ErrorCode.storagePathCreateFailed, + throw PaperlessServerException(ErrorCode.storagePathCreateFailed, httpStatusCode: response.statusCode); } @override Future updateStoragePath(StoragePath path) async { assert(path.id != null); - final response = await httpClient.put( + final response = await client.put( Uri.parse('/api/storage_paths/${path.id}/'), headers: {"Content-Type": "application/json"}, body: json.encode(path.toJson()), ); - if (response.statusCode == 200) { + if (response.statusCode == HttpStatus.ok) { return StoragePath.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); } - throw const ErrorMessage(ErrorCode.unknown); + throw const PaperlessServerException(ErrorCode.unknown); } } diff --git a/packages/paperless_api/lib/src/modules/modules.dart b/packages/paperless_api/lib/src/modules/modules.dart new file mode 100644 index 0000000..1343d89 --- /dev/null +++ b/packages/paperless_api/lib/src/modules/modules.dart @@ -0,0 +1,11 @@ +export 'authentication_api/authentication_api.dart'; +export 'authentication_api/authentication_api_impl.dart'; + +export 'labels_api/paperless_labels_api.dart'; +export 'labels_api/paperless_labels_api_impl.dart'; +export 'documents_api/paperless_documents_api.dart'; +export 'documents_api/paperless_documents_api_impl.dart'; +export 'saved_views_api/paperless_saved_views_api.dart'; +export 'saved_views_api/paperless_saved_views_api_impl.dart'; +export 'server_stats_api/paperless_server_stats_api.dart'; +export 'server_stats_api/paperless_server_stats_api_impl.dart'; diff --git a/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart new file mode 100644 index 0000000..60595b2 --- /dev/null +++ b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api.dart @@ -0,0 +1,8 @@ +import 'package:paperless_api/src/models/saved_view_model.dart'; + +abstract class PaperlessSavedViewsApi { + Future> getAll(); + + Future save(SavedView view); + Future delete(SavedView view); +} diff --git a/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart new file mode 100644 index 0000000..901a998 --- /dev/null +++ b/packages/paperless_api/lib/src/modules/saved_views_api/paperless_saved_views_api_impl.dart @@ -0,0 +1,54 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:http/http.dart'; +import 'package:paperless_api/src/models/paperless_server_exception.dart'; +import 'package:paperless_api/src/models/saved_view_model.dart'; +import 'package:paperless_api/src/utils.dart'; + +import 'paperless_saved_views_api.dart'; + +class PaperlessSavedViewsApiImpl implements PaperlessSavedViewsApi { + final BaseClient client; + + PaperlessSavedViewsApiImpl(this.client); + + @override + Future> getAll() { + return getCollection( + "/api/saved_views/", + SavedView.fromJson, + ErrorCode.loadSavedViewsError, + client: client, + ); + } + + @override + Future save(SavedView view) async { + final response = await client.post( + Uri.parse("/api/saved_views/"), + body: jsonEncode(view.toJson()), + headers: {'Content-Type': 'application/json'}, + ); + if (response.statusCode == HttpStatus.created) { + return SavedView.fromJson(jsonDecode(utf8.decode(response.bodyBytes))); + } + throw PaperlessServerException( + ErrorCode.createSavedViewError, + httpStatusCode: response.statusCode, + ); + } + + @override + Future delete(SavedView view) async { + final response = + await client.delete(Uri.parse("/api/saved_views/${view.id}/")); + if (response.statusCode == HttpStatus.noContent) { + return view.id!; + } + throw PaperlessServerException( + ErrorCode.deleteSavedViewError, + httpStatusCode: response.statusCode, + ); + } +} diff --git a/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api.dart b/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api.dart new file mode 100644 index 0000000..6dba8f1 --- /dev/null +++ b/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api.dart @@ -0,0 +1,7 @@ +import 'package:paperless_api/src/models/paperless_server_information_model.dart'; +import 'package:paperless_api/src/models/paperless_server_statistics_model.dart'; + +abstract class PaperlessServerStatsApi { + Future getServerInformation(); + Future getServerStatistics(); +} diff --git a/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart b/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart new file mode 100644 index 0000000..5ff7529 --- /dev/null +++ b/packages/paperless_api/lib/src/modules/server_stats_api/paperless_server_stats_api_impl.dart @@ -0,0 +1,53 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; +import 'package:paperless_api/src/models/paperless_server_exception.dart'; +import 'package:paperless_api/src/models/paperless_server_information_model.dart'; +import 'package:paperless_api/src/models/paperless_server_statistics_model.dart'; + +import 'paperless_server_stats_api.dart'; + +/// +/// API for retrieving information about paperless server state, +/// such as version number, and statistics including documents in +/// inbox and total number of documents. +/// +class PaperlessServerStatsApiImpl implements PaperlessServerStatsApi { + final BaseClient client; + + PaperlessServerStatsApiImpl(this.client); + + @override + Future getServerInformation() async { + final response = await client.get(Uri.parse("/api/ui_settings/")); + final version = + response.headers[PaperlessServerInformationModel.versionHeader] ?? + 'unknown'; + final apiVersion = int.tryParse( + response.headers[PaperlessServerInformationModel.apiVersionHeader] ?? + '1'); + final String username = + jsonDecode(utf8.decode(response.bodyBytes))['username']; + final String host = response + .headers[PaperlessServerInformationModel.hostHeader] ?? + response.request?.headers[PaperlessServerInformationModel.hostHeader] ?? + ('${response.request?.url.host}:${response.request?.url.port}'); + return PaperlessServerInformationModel( + username: username, + version: version, + apiVersion: apiVersion, + host: host, + ); + } + + @override + Future getServerStatistics() async { + final response = await client.get(Uri.parse('/api/statistics/')); + if (response.statusCode == 200) { + return PaperlessServerStatisticsModel.fromJson( + jsonDecode(utf8.decode(response.bodyBytes)) as Map, + ); + } + throw const PaperlessServerException.unknown(); + } +} diff --git a/lib/core/util.dart b/packages/paperless_api/lib/src/utils.dart similarity index 54% rename from lib/core/util.dart rename to packages/paperless_api/lib/src/utils.dart index b28c42d..b03e97b 100644 --- a/lib/core/util.dart +++ b/packages/paperless_api/lib/src/utils.dart @@ -1,45 +1,47 @@ import 'dart:convert'; -import 'package:flutter/foundation.dart'; -import 'package:paperless_mobile/core/model/error_message.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/di_initializer.dart'; -import 'package:http/http.dart'; +import 'dart:io'; -const requestTimeout = Duration(seconds: 5); +import 'package:flutter/foundation.dart'; +import 'package:http/http.dart'; +import 'package:paperless_api/src/models/paperless_server_exception.dart'; Future getSingleResult( String url, - T Function(JSON) fromJson, + T Function(Map) fromJson, ErrorCode errorCode, { + required BaseClient client, int minRequiredApiVersion = 1, }) async { - final httpClient = getIt(instanceName: "timeoutClient"); - final response = await httpClient.get( + final response = await client.get( Uri.parse(url), headers: {'accept': 'application/json; version=$minRequiredApiVersion'}, ); - if (response.statusCode == 200) { + if (response.statusCode == HttpStatus.ok) { return compute( fromJson, - jsonDecode(utf8.decode(response.bodyBytes)) as JSON, + jsonDecode(utf8.decode(response.bodyBytes)) as Map, ); } - throw ErrorMessage(errorCode); + throw PaperlessServerException( + errorCode, + httpStatusCode: response.statusCode, + ); } Future> getCollection( String url, - T Function(JSON) fromJson, + T Function(Map) fromJson, ErrorCode errorCode, { + required BaseClient client, int minRequiredApiVersion = 1, }) async { - final httpClient = getIt(instanceName: "timeoutClient"); - final response = await httpClient.get( + final response = await client.get( Uri.parse(url), headers: {'accept': 'application/json; version=$minRequiredApiVersion'}, ); - if (response.statusCode == 200) { - final JSON body = jsonDecode(utf8.decode(response.bodyBytes)); + if (response.statusCode == HttpStatus.ok) { + final Map body = + jsonDecode(utf8.decode(response.bodyBytes)); if (body.containsKey('count')) { if (body['count'] == 0) { return []; @@ -47,12 +49,15 @@ Future> getCollection( return compute( _collectionFromJson, _CollectionFromJsonSerializationParams( - fromJson, (body['results'] as List).cast()), + fromJson, (body['results'] as List).cast>()), ); } } } - throw ErrorMessage(errorCode); + throw PaperlessServerException( + errorCode, + httpStatusCode: response.statusCode, + ); } List _collectionFromJson( @@ -61,8 +66,8 @@ List _collectionFromJson( } class _CollectionFromJsonSerializationParams { - final T Function(JSON) fromJson; - final List list; + final T Function(Map) fromJson; + final List> list; _CollectionFromJsonSerializationParams(this.fromJson, this.list); } diff --git a/packages/paperless_api/pubspec.yaml b/packages/paperless_api/pubspec.yaml new file mode 100644 index 0000000..2d70e17 --- /dev/null +++ b/packages/paperless_api/pubspec.yaml @@ -0,0 +1,63 @@ +name: paperless_api +description: An SDK for paperless(-ng*) +version: 1.0.0+1 + +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: "none" # Remove this line if you wish to publish to pub.dev + +environment: + sdk: ">=2.18.5 <3.0.0" + flutter: ">=1.17.0" + +dependencies: + flutter: + sdk: flutter + equatable: ^2.0.5 + http: ^0.13.5 + json_annotation: ^4.7.0 + intl: ^0.17.0 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_lints: ^2.0.0 + json_serializable: ^6.5.4 + build_runner: ^2.3.2 + +# 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 packages. +flutter: + + # To add assets to your package, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + # + # For details regarding assets in packages, see + # https://flutter.dev/assets-and-images/#from-packages + # + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/assets-and-images/#resolution-aware + + # To add custom fonts to your package, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts in packages, see + # https://flutter.dev/custom-fonts/#from-packages diff --git a/test/src/saved_view_test.dart b/packages/paperless_api/test/saved_view_test.dart similarity index 90% rename from test/src/saved_view_test.dart rename to packages/paperless_api/test/saved_view_test.dart index f760dee..38d6511 100644 --- a/test/src/saved_view_test.dart +++ b/packages/paperless_api/test/saved_view_test.dart @@ -1,13 +1,13 @@ -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/filter_rule.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/document_type_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/query_type.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_order.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/storage_path_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/tags_query.dart'; -import 'package:paperless_mobile/features/documents/model/saved_view.model.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/correspondent_query.dart'; -import 'package:paperless_mobile/features/documents/model/query_parameters/sort_field.dart'; +import 'package:paperless_api/src/models/document_filter.dart'; +import 'package:paperless_api/src/models/filter_rule_model.dart'; +import 'package:paperless_api/src/models/query_parameters/correspondent_query.dart'; +import 'package:paperless_api/src/models/query_parameters/document_type_query.dart'; +import 'package:paperless_api/src/models/query_parameters/query_type.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_field.dart'; +import 'package:paperless_api/src/models/query_parameters/sort_order.dart'; +import 'package:paperless_api/src/models/query_parameters/storage_path_query.dart'; +import 'package:paperless_api/src/models/query_parameters/tags_query.dart'; +import 'package:paperless_api/src/models/saved_view_model.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { diff --git a/pubspec.lock b/pubspec.lock index 0b05d1c..900c6be 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -373,7 +373,7 @@ packages: name: equatable url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.5" extension: dependency: transitive description: @@ -657,7 +657,7 @@ packages: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.4" + version: "0.13.5" http_interceptor: dependency: "direct main" description: @@ -753,7 +753,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.5.0" + version: "4.7.0" lints: dependency: transitive description: @@ -922,6 +922,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + paperless_api: + dependency: "direct main" + description: + path: "packages/paperless_api" + relative: true + source: path + version: "1.0.0+1" path: dependency: transitive description: @@ -1544,5 +1551,5 @@ packages: source: hosted version: "3.1.1" sdks: - dart: ">=2.18.0 <3.0.0" + dart: ">=2.18.5 <3.0.0" flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index c8f199f..2533bdb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -78,6 +78,8 @@ dependencies: uuid: ^3.0.6 flutter_typeahead: ^4.1.1 fluttertoast: ^8.1.1 + paperless_api: + path: packages/paperless_api dev_dependencies: integration_test: diff --git a/test/src/bloc/document_cubit_test.dart b/test/src/bloc/document_cubit_test.dart index 452caa9..812318b 100644 --- a/test/src/bloc/document_cubit_test.dart +++ b/test/src/bloc/document_cubit_test.dart @@ -1,19 +1,13 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/bloc/documents_state.dart'; -import 'package:paperless_mobile/features/documents/model/document.model.dart'; -import 'package:paperless_mobile/features/documents/model/document_filter.dart'; -import 'package:paperless_mobile/features/documents/model/paged_search_result.dart'; -import 'package:paperless_mobile/features/documents/repository/document_repository.dart'; -import 'package:paperless_mobile/features/labels/correspondent/model/correspondent.model.dart'; -import 'package:paperless_mobile/features/labels/document_type/model/document_type.model.dart'; -import 'package:paperless_mobile/features/labels/tags/model/tag.model.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; import 'package:mockito/mockito.dart'; import '../../utils.dart'; -@GenerateNiceMocks([MockSpec()]) +@GenerateNiceMocks([MockSpec()]) import 'document_cubit_test.mocks.dart'; void main() async { @@ -35,7 +29,8 @@ void main() async { DocumentType.fromJson), ); - final MockDocumentRepository documentRepository = MockDocumentRepository(); + final MockPaperlessDocumentsApi documentRepository = + MockPaperlessDocumentsApi(); group("Test DocumentsCubit reloadDocuments", () { test("Assert correct initial state", () {