From bf0e186646baf3de1a26ef66e2d2bd34d30d2f61 Mon Sep 17 00:00:00 2001 From: Anton Stubenbord Date: Tue, 27 Dec 2022 00:12:33 +0100 Subject: [PATCH] WIP - Provider refactorings --- lib/core/bloc/connectivity_cubit.dart | 4 - .../authentication.interceptor.dart | 14 +- .../dio_http_error_interceptor.dart | 38 ++++++ .../provider/label_repositories_provider.dart | 12 +- .../authentication_aware_dio_manager.dart | 60 +++++++++ .../security_context_aware_dio_manager.dart | 100 -------------- .../security_context_extension.dart | 22 ++++ .../view/pages/document_details_page.dart | 14 +- .../document_upload_preparation_page.dart | 10 +- .../view/pages/document_edit_page.dart | 15 +-- .../documents/view/pages/documents_page.dart | 112 ++++++++-------- .../view/widgets/document_preview.dart | 5 +- .../selection/documents_page_app_bar.dart | 6 +- .../view/widgets/sort_documents_button.dart | 20 ++- .../edit_label/view/add_label_page.dart | 4 +- .../edit_label/view/edit_label_page.dart | 8 +- .../view/impl/add_correspondent_page.dart | 2 +- .../view/impl/add_document_type_page.dart | 2 +- .../view/impl/add_storage_path_page.dart | 2 +- .../edit_label/view/impl/add_tag_page.dart | 2 +- .../view/impl/edit_correspondent_page.dart | 2 +- .../view/impl/edit_document_type_page.dart | 2 +- .../view/impl/edit_storage_path_page.dart | 2 +- .../edit_label/view/impl/edit_tag_page.dart | 2 +- lib/features/home/view/home_page.dart | 16 +-- .../home/view/widget/info_drawer.dart | 31 ++--- lib/features/inbox/view/pages/inbox_page.dart | 10 +- .../view/widgets/inbox_empty_widget.dart | 2 +- .../inbox/view/widgets/inbox_item.dart | 4 +- .../correspondent_bloc_provider.dart | 2 +- .../document_type_bloc_provider.dart | 2 +- .../bloc/providers/labels_bloc_provider.dart | 8 +- .../providers/storage_path_bloc_provider.dart | 2 +- .../bloc/providers/tag_bloc_provider.dart | 2 +- .../view/widgets/document_type_widget.dart | 6 +- .../view/widgets/storage_path_widget.dart | 6 +- .../tags/view/widgets/tags_form_field.dart | 4 +- .../labels/view/pages/labels_page.dart | 59 ++++----- .../labels/view/widgets/label_item.dart | 2 +- .../labels/view/widgets/label_tab_view.dart | 2 +- .../view/pages/linked_documents_page.dart | 3 +- .../login/bloc/authentication_cubit.dart | 5 +- .../login/bloc/authentication_state.dart | 2 +- lib/features/login/view/login_page.dart | 12 +- .../widgets/server_address_form_field.dart | 6 +- .../view/saved_view_selection_widget.dart | 8 +- lib/features/scan/view/scanner_page.dart | 43 +++--- lib/features/settings/view/settings_page.dart | 7 +- .../biometric_authentication_setting.dart | 9 +- .../view/widgets/clear_storage_setting.dart | 2 +- .../widgets/language_selection_setting.dart | 7 +- .../view/widgets/theme_mode_setting.dart | 6 +- lib/main.dart | 122 +++++++++++++----- 53 files changed, 434 insertions(+), 416 deletions(-) create mode 100644 lib/core/interceptor/dio_http_error_interceptor.dart create mode 100644 lib/core/security/authentication_aware_dio_manager.dart delete mode 100644 lib/core/security/security_context_aware_dio_manager.dart create mode 100644 lib/extensions/security_context_extension.dart diff --git a/lib/core/bloc/connectivity_cubit.dart b/lib/core/bloc/connectivity_cubit.dart index 08f7054..c7fa6e1 100644 --- a/lib/core/bloc/connectivity_cubit.dart +++ b/lib/core/bloc/connectivity_cubit.dart @@ -2,11 +2,7 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:paperless_mobile/core/service/connectivity_status.service.dart'; -import 'package:injectable/injectable.dart'; -@prod -@test -@lazySingleton class ConnectivityCubit extends Cubit { final ConnectivityStatusService connectivityStatusService; StreamSubscription? _sub; diff --git a/lib/core/interceptor/authentication.interceptor.dart b/lib/core/interceptor/authentication.interceptor.dart index 4552006..c89bb61 100644 --- a/lib/core/interceptor/authentication.interceptor.dart +++ b/lib/core/interceptor/authentication.interceptor.dart @@ -2,27 +2,25 @@ import 'dart:developer'; import 'package:flutter/foundation.dart'; import 'package:http_interceptor/http_interceptor.dart'; -import 'package:paperless_mobile/core/store/local_vault.dart'; class AuthenticationInterceptor implements InterceptorContract { - final LocalVault _localVault; - AuthenticationInterceptor(this._localVault); + String? serverUrl; + String? token; + AuthenticationInterceptor({this.serverUrl, this.token}); @override Future interceptRequest({required BaseRequest request}) async { - final auth = await _localVault.loadAuthenticationInformation(); - if (kDebugMode) { log("Intercepted ${request.method} request to ${request.url.toString()}"); } return request.copyWith( - //Append server Url - headers: auth?.token?.isEmpty ?? true + url: Uri.parse((serverUrl ?? '') + request.url.toString()), + headers: token?.isEmpty ?? true ? request.headers : { ...request.headers, - 'Authorization': 'Token ${auth!.token}', + 'Authorization': 'Token $token', }, ); } diff --git a/lib/core/interceptor/dio_http_error_interceptor.dart b/lib/core/interceptor/dio_http_error_interceptor.dart new file mode 100644 index 0000000..81b7b8c --- /dev/null +++ b/lib/core/interceptor/dio_http_error_interceptor.dart @@ -0,0 +1,38 @@ +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:paperless_mobile/core/type/types.dart'; + +class DioHttpErrorInterceptor implements InterceptorsWrapper { + @override + void onError(DioError e, ErrorInterceptorHandler handler) { + //TODO: Implement and debug how error handling works, or if request has to be resolved. + if (e.response?.statusCode == 400) { + // try to parse contained error message, otherwise return response + final Map json = jsonDecode(e.response?.data); + final PaperlessValidationErrors errorMessages = {}; + for (final entry in json.entries) { + if (entry.value is List) { + errorMessages.putIfAbsent( + entry.key, () => (entry.value as List).cast().first); + } else if (entry.value is String) { + errorMessages.putIfAbsent(entry.key, () => entry.value); + } else { + errorMessages.putIfAbsent(entry.key, () => entry.value.toString()); + } + } + throw errorMessages; + } + handler.next(e); + } + + @override + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { + handler.next(options); + } + + @override + void onResponse(Response response, ResponseInterceptorHandler handler) { + handler.next(response); + } +} diff --git a/lib/core/repository/provider/label_repositories_provider.dart b/lib/core/repository/provider/label_repositories_provider.dart index c1c83f0..759a46c 100644 --- a/lib/core/repository/provider/label_repositories_provider.dart +++ b/lib/core/repository/provider/label_repositories_provider.dart @@ -12,20 +12,16 @@ class LabelRepositoriesProvider extends StatelessWidget { return MultiRepositoryProvider( providers: [ RepositoryProvider( - create: (context) => - RepositoryProvider.of>(context), + create: (context) => context.read>(), ), RepositoryProvider( - create: (context) => - RepositoryProvider.of>(context), + create: (context) => context.read>(), ), RepositoryProvider( - create: (context) => - RepositoryProvider.of>(context), + create: (context) => context.read>(), ), RepositoryProvider( - create: (context) => - RepositoryProvider.of>(context), + create: (context) => context.read>(), ), ], child: child, diff --git a/lib/core/security/authentication_aware_dio_manager.dart b/lib/core/security/authentication_aware_dio_manager.dart new file mode 100644 index 0000000..91da1c7 --- /dev/null +++ b/lib/core/security/authentication_aware_dio_manager.dart @@ -0,0 +1,60 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:dio/adapter.dart'; +import 'package:dio/dio.dart'; +import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart'; +import 'package:paperless_mobile/extensions/security_context_extension.dart'; +import 'package:paperless_mobile/features/login/model/client_certificate.dart'; + +/// +/// Convenience http client handling timeouts. +/// +class AuthenticationAwareDioManager { + final Dio _dio; + + /// Some dependencies require an [HttpClient], therefore this is also maintained here. + + AuthenticationAwareDioManager() : _dio = _initDio(); + + Dio get client => _dio; + + Stream get securityContextChanges => + _securityContextStreamController.stream.asBroadcastStream(); + + final StreamController _securityContextStreamController = + StreamController.broadcast(); + + static Dio _initDio() { + //en- and decoded by utf8 by default + final Dio dio = Dio(BaseOptions()); + dio.options.receiveTimeout = const Duration(seconds: 25).inMilliseconds; + dio.options.responseType = ResponseType.json; + (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = + (client) => client..badCertificateCallback = (cert, host, port) => true; + dio.interceptors.add(DioHttpErrorInterceptor()); + return dio; + } + + void updateSettings({ + String? baseUrl, + String? authToken, + ClientCertificate? clientCertificate, + }) { + if (clientCertificate != null) { + final context = + SecurityContext().withClientCertificate(clientCertificate); + (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = + (client) => HttpClient(context: context) + ..badCertificateCallback = + (X509Certificate cert, String host, int port) => true; + _securityContextStreamController.add(context); + } + if (baseUrl != null) { + _dio.options.baseUrl = baseUrl; + } + if (authToken != null) { + _dio.options.headers.addAll({'Authorization': 'Token $authToken'}); + } + } +} diff --git a/lib/core/security/security_context_aware_dio_manager.dart b/lib/core/security/security_context_aware_dio_manager.dart deleted file mode 100644 index 5d891ac..0000000 --- a/lib/core/security/security_context_aware_dio_manager.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:dio/adapter.dart'; -import 'package:dio/dio.dart'; -import 'package:paperless_mobile/core/type/types.dart'; -import 'package:paperless_mobile/features/login/model/client_certificate.dart'; - -/// -/// Convenience http client handling timeouts. -/// -class SecurityContextAwareDioManager { - final Dio _dio; - // Some dependencies require an [HttpClient], therefore this is also maintained here. - final HttpClient _httpClient; - SecurityContextAwareDioManager() - : _dio = _initDio(), - _httpClient = HttpClient(); - - Dio get client => _dio; - - Stream get securityContextChanges => - _securityContextStreamController.stream.asBroadcastStream(); - - final StreamController _securityContextStreamController = - StreamController.broadcast(); - - static Dio _initDio() { - //en- and decoded by utf8 by default - final Dio dio = Dio(BaseOptions()); - dio.options.receiveTimeout = const Duration(seconds: 25).inMilliseconds; - dio.options.responseType = ResponseType.json; - (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = - (client) => client - ..badCertificateCallback = - (X509Certificate cert, String host, int port) => true; - dio.interceptors.add( - //TODO: Refactor, create own class... - InterceptorsWrapper( - onError: (e, handler) { - //TODO: Implement and debug how error handling works, or if request has to be resolved. - if (e.response?.statusCode == 400) { - // try to parse contained error message, otherwise return response - final JSON json = jsonDecode(e.response?.data); - final PaperlessValidationErrors errorMessages = {}; - for (final entry in json.entries) { - if (entry.value is List) { - errorMessages.putIfAbsent(entry.key, - () => (entry.value as List).cast().first); - } else if (entry.value is String) { - errorMessages.putIfAbsent(entry.key, () => entry.value); - } else { - errorMessages.putIfAbsent( - entry.key, () => entry.value.toString()); - } - } - throw errorMessages; - } - handler.next(e); - }, - ), - ); - return dio; - } - - void updateSettings({ - String? baseUrl, - String? authToken, - ClientCertificate? clientCertificate, - }) { - if (clientCertificate != null) { - final sc = SecurityContext() - ..usePrivateKeyBytes( - clientCertificate.bytes, - password: clientCertificate.passphrase, - ) - ..useCertificateChainBytes( - clientCertificate.bytes, - password: clientCertificate.passphrase, - ) - ..setTrustedCertificatesBytes( - clientCertificate.bytes, - password: clientCertificate.passphrase, - ); - (_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate = - (client) => HttpClient( - context: sc, - )..badCertificateCallback = - (X509Certificate cert, String host, int port) => true; - _securityContextStreamController.add(sc); - } - if (baseUrl != null) { - _dio.options.baseUrl = baseUrl; - } - if (authToken != null) { - _dio.options.headers.addAll({'Authorization': 'Token $authToken'}); - } - } -} diff --git a/lib/extensions/security_context_extension.dart b/lib/extensions/security_context_extension.dart new file mode 100644 index 0000000..26e7789 --- /dev/null +++ b/lib/extensions/security_context_extension.dart @@ -0,0 +1,22 @@ +import 'dart:io'; + +import 'package:paperless_mobile/features/login/model/client_certificate.dart'; + +extension ClientCertificateHandlingSecurityContext on SecurityContext { + SecurityContext withClientCertificate(ClientCertificate? clientCertificate) { + if (clientCertificate == null) return this; + return this + ..usePrivateKeyBytes( + clientCertificate.bytes, + password: clientCertificate.passphrase, + ) + ..useCertificateChainBytes( + clientCertificate.bytes, + password: clientCertificate.passphrase, + ) + ..setTrustedCertificatesBytes( + clientCertificate.bytes, + password: clientCertificate.passphrase, + ); + } +} 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 1e8cf0e..b64caba 100644 --- a/lib/features/document_details/view/pages/document_details_page.dart +++ b/lib/features/document_details/view/pages/document_details_page.dart @@ -187,14 +187,14 @@ class _DocumentDetailsPageState extends State { Navigator.push( context, MaterialPageRoute( - builder: (context) => BlocProvider( - create: (context) => EditDocumentCubit( + builder: (context) => BlocProvider.value( + value: EditDocumentCubit( document, - documentsApi: context.watch(), - correspondentRepository: context.watch(), - documentTypeRepository: context.watch(), - storagePathRepository: context.watch(), - tagRepository: context.watch(), + documentsApi: context.read(), + correspondentRepository: context.read(), + documentTypeRepository: context.read(), + storagePathRepository: context.read(), + tagRepository: context.read(), ), child: BlocListener( listenWhen: (previous, current) => diff --git a/lib/features/document_upload/view/document_upload_preparation_page.dart b/lib/features/document_upload/view/document_upload_preparation_page.dart index 5faa053..8702bee 100644 --- a/lib/features/document_upload/view/document_upload_preparation_page.dart +++ b/lib/features/document_upload/view/document_upload_preparation_page.dart @@ -166,8 +166,9 @@ class _DocumentUploadPreparationPageState notAssignedSelectable: false, formBuilderState: _formKey.currentState, labelCreationWidgetBuilder: (initialName) => - RepositoryProvider>( - create: (context) => context.watch(), + RepositoryProvider( + create: (context) => + context.read>(), child: AddDocumentTypePage(initialName: initialName), ), textFieldLabel: @@ -180,8 +181,9 @@ class _DocumentUploadPreparationPageState notAssignedSelectable: false, formBuilderState: _formKey.currentState, labelCreationWidgetBuilder: (initialName) => - RepositoryProvider>( - create: (context) => context.watch(), + RepositoryProvider( + create: (context) => + context.read>(), child: AddCorrespondentPage(initialName: initialName), ), textFieldLabel: diff --git a/lib/features/documents/view/pages/document_edit_page.dart b/lib/features/documents/view/pages/document_edit_page.dart index af971bf..7b085cf 100644 --- a/lib/features/documents/view/pages/document_edit_page.dart +++ b/lib/features/documents/view/pages/document_edit_page.dart @@ -99,9 +99,8 @@ class _DocumentEditPageState extends State { return LabelFormField( notAssignedSelectable: false, formBuilderState: _formKey.currentState, - labelCreationWidgetBuilder: (initialValue) => - RepositoryProvider>( - create: (context) => context.watch(), + labelCreationWidgetBuilder: (initialValue) => RepositoryProvider( + create: (context) => context.read>(), child: AddStoragePathPage(initalValue: initialValue), ), textFieldLabel: S.of(context).documentStoragePathPropertyLabel, @@ -117,9 +116,8 @@ class _DocumentEditPageState extends State { return LabelFormField( notAssignedSelectable: false, formBuilderState: _formKey.currentState, - labelCreationWidgetBuilder: (initialValue) => - RepositoryProvider>( - create: context.watch(), + labelCreationWidgetBuilder: (initialValue) => RepositoryProvider( + create: (context) => context.read>(), child: AddCorrespondentPage(initialName: initialValue), ), textFieldLabel: S.of(context).documentCorrespondentPropertyLabel, @@ -135,9 +133,8 @@ class _DocumentEditPageState extends State { return LabelFormField( notAssignedSelectable: false, formBuilderState: _formKey.currentState, - labelCreationWidgetBuilder: (currentInput) => - RepositoryProvider>( - create: (context) => context.watch(), + labelCreationWidgetBuilder: (currentInput) => RepositoryProvider( + create: (context) => context.read>(), child: AddDocumentTypePage( initialName: currentInput, ), diff --git a/lib/features/documents/view/pages/documents_page.dart b/lib/features/documents/view/pages/documents_page.dart index c1edfa3..047c752 100644 --- a/lib/features/documents/view/pages/documents_page.dart +++ b/lib/features/documents/view/pages/documents_page.dart @@ -32,9 +32,6 @@ class DocumentsPage extends StatefulWidget { } class _DocumentsPageState extends State { - late final DocumentsCubit _documentsCubit; - late final SavedViewCubit _savedViewCubit; - final _pagingController = PagingController( firstPageKey: 1, ); @@ -42,10 +39,8 @@ class _DocumentsPageState extends State { @override void initState() { super.initState(); - _documentsCubit = context.watch(); - _savedViewCubit = context.watch(); try { - _documentsCubit.load(); + context.read().load(); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } @@ -66,7 +61,7 @@ class _DocumentsPageState extends State { current == ConnectivityState.connected, listener: (context, state) { try { - _documentsCubit.load(); + context.read().load(); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } @@ -74,9 +69,9 @@ class _DocumentsPageState extends State { builder: (context, connectivityState) { return Scaffold( drawer: BlocProvider.value( - value: BlocProvider.of(context), + value: context.read(), child: InfoDrawer( - afterInboxClosed: () => _documentsCubit.reload(), + afterInboxClosed: () => context.read().reload(), ), ), floatingActionButton: BlocBuilder( @@ -111,22 +106,25 @@ class _DocumentsPageState extends State { ), ), isScrollControlled: true, - builder: (context) => DraggableScrollableSheet( - expand: false, - snap: true, - initialChildSize: .9, - maxChildSize: .9, - builder: (context, controller) => LabelsBlocProvider( - child: DocumentFilterPanel( - initialFilter: _documentsCubit.state.filter, - scrollController: controller, + builder: (_) => BlocProvider.value( + value: context.read(), + child: DraggableScrollableSheet( + expand: false, + snap: true, + initialChildSize: .9, + maxChildSize: .9, + builder: (context, controller) => LabelsBlocProvider( + child: DocumentFilterPanel( + initialFilter: context.read().state.filter, + scrollController: controller, + ), ), ), ), ); if (filter != null) { - _documentsCubit.updateFilter(filter: filter); - _savedViewCubit.resetSelection(); + context.read().updateFilter(filter: filter); + context.read().resetSelection(); } } @@ -177,8 +175,8 @@ class _DocumentsPageState extends State { child: DocumentsEmptyState( state: state, onReset: () { - _documentsCubit.resetFilter(); - _savedViewCubit.resetSelection(); + context.read().resetFilter(); + context.read().resetSelection(); }, ), ); @@ -196,13 +194,15 @@ class _DocumentsPageState extends State { listener: (context, state) { try { if (state.selectedSavedViewId == null) { - _documentsCubit.resetFilter(); + context.read().resetFilter(); } else { final newFilter = state .value[state.selectedSavedViewId] ?.toDocumentFilter(); if (newFilter != null) { - _documentsCubit.updateFilter(filter: newFilter); + context + .read() + .updateFilter(filter: newFilter); } } } on PaperlessServerException catch (error, stackTrace) { @@ -220,11 +220,11 @@ class _DocumentsPageState extends State { ? Icons.list : Icons.grid_view, ), - onPressed: () => - BlocProvider.of(context) - .setViewType( - settings.preferredViewType.toggle(), - ), + onPressed: () => context + .read() + .setViewType( + settings.preferredViewType.toggle(), + ), ), ], ), @@ -243,7 +243,7 @@ class _DocumentsPageState extends State { await Navigator.of(context).push( _buildDetailsPageRoute(document), ); - _documentsCubit.reload(); + context.read().reload(); } MaterialPageRoute _buildDetailsPageRoute( @@ -251,7 +251,7 @@ class _DocumentsPageState extends State { return MaterialPageRoute( builder: (_) => BlocProvider( create: (context) => DocumentDetailsCubit( - context.watch(), + context.read(), document, ), child: const LabelRepositoriesProvider( @@ -263,21 +263,22 @@ class _DocumentsPageState extends State { void _addTagToFilter(int tagId) { try { - final tagsQuery = _documentsCubit.state.filter.tags is IdsTagsQuery - ? _documentsCubit.state.filter.tags as IdsTagsQuery - : const IdsTagsQuery(); + final tagsQuery = + context.read().state.filter.tags is IdsTagsQuery + ? context.read().state.filter.tags as IdsTagsQuery + : const IdsTagsQuery(); if (tagsQuery.includedIds.contains(tagId)) { - _documentsCubit.updateCurrentFilter( - (filter) => filter.copyWith( - tags: tagsQuery.withIdsRemoved([tagId]), - ), - ); + context.read().updateCurrentFilter( + (filter) => filter.copyWith( + tags: tagsQuery.withIdsRemoved([tagId]), + ), + ); } else { - _documentsCubit.updateCurrentFilter( - (filter) => filter.copyWith( - tags: tagsQuery.withIdQueriesAdded([IncludeTagIdQuery(tagId)]), - ), - ); + context.read().updateCurrentFilter( + (filter) => filter.copyWith( + tags: tagsQuery.withIdQueriesAdded([IncludeTagIdQuery(tagId)]), + ), + ); } } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); @@ -285,7 +286,7 @@ class _DocumentsPageState extends State { } void _addCorrespondentToFilter(int? correspondentId) { - final cubit = BlocProvider.of(context); + final cubit = context.read(); try { if (cubit.state.filter.correspondent.id == correspondentId) { cubit.updateCurrentFilter( @@ -304,7 +305,7 @@ class _DocumentsPageState extends State { } void _addDocumentTypeToFilter(int? documentTypeId) { - final cubit = BlocProvider.of(context); + final cubit = context.read(); try { if (cubit.state.filter.documentType.id == documentTypeId) { cubit.updateCurrentFilter( @@ -323,7 +324,7 @@ class _DocumentsPageState extends State { } void _addStoragePathToFilter(int? pathId) { - final cubit = BlocProvider.of(context); + final cubit = context.read(); try { if (cubit.state.filter.correspondent.id == pathId) { cubit.updateCurrentFilter( @@ -342,28 +343,29 @@ class _DocumentsPageState extends State { } Future _loadNewPage(int pageKey) async { - final pageCount = _documentsCubit.state - .inferPageCount(pageSize: _documentsCubit.state.filter.pageSize); + final documentsCubit = context.read(); + final pageCount = documentsCubit.state + .inferPageCount(pageSize: documentsCubit.state.filter.pageSize); if (pageCount <= pageKey + 1) { _pagingController.nextPageKey = null; } try { - await _documentsCubit.loadMore(); + await documentsCubit.loadMore(); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } } void _onSelected(DocumentModel model) { - _documentsCubit.toggleDocumentSelection(model); + context.read().toggleDocumentSelection(model); } Future _onRefresh() async { try { - _documentsCubit.updateCurrentFilter( - (filter) => filter.copyWith(page: 1), - ); - _savedViewCubit.reload(); + context.read().updateCurrentFilter( + (filter) => filter.copyWith(page: 1), + ); + context.read().reload(); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } diff --git a/lib/features/documents/view/widgets/document_preview.dart b/lib/features/documents/view/widgets/document_preview.dart index cdad066..5ab83e0 100644 --- a/lib/features/documents/view/widgets/document_preview.dart +++ b/lib/features/documents/view/widgets/document_preview.dart @@ -30,15 +30,14 @@ class DocumentPreview extends StatelessWidget { fit: fit, alignment: Alignment.topCenter, cacheKey: "thumb_$id", - imageUrl: - Provider.of(context).getThumbnailUrl(id), + imageUrl: context.read().getThumbnailUrl(id), errorWidget: (ctxt, msg, __) => Text(msg), placeholder: (context, value) => Shimmer.fromColors( baseColor: Colors.grey[300]!, highlightColor: Colors.grey[100]!, child: const SizedBox(height: 100, width: 100), ), - cacheManager: context.watch(), + cacheManager: context.watch(), ), // ), ); 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 1b547c1..1a1b3ac 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 @@ -48,8 +48,7 @@ class _DocumentsPageAppBarState extends State { ), leading: IconButton( icon: const Icon(Icons.close), - onPressed: () => - BlocProvider.of(context).resetSelection(), + onPressed: () => context.read().resetSelection(), ), title: Text( '${documentsState.selection.length} ${S.of(context).documentsSelectedText}'), @@ -111,7 +110,8 @@ class _DocumentsPageAppBarState extends State { false; if (shouldDelete) { try { - await BlocProvider.of(context) + await context + .read() .bulkRemove(documentsState.selection); showSnackBar( context, diff --git a/lib/features/documents/view/widgets/sort_documents_button.dart b/lib/features/documents/view/widgets/sort_documents_button.dart index 3f06569..4806d3e 100644 --- a/lib/features/documents/view/widgets/sort_documents_button.dart +++ b/lib/features/documents/view/widgets/sort_documents_button.dart @@ -29,20 +29,19 @@ class SortDocumentsButton extends StatelessWidget { ), ), builder: (_) => BlocProvider.value( - value: BlocProvider.of(context), + value: context.read(), child: FractionallySizedBox( heightFactor: .6, child: MultiBlocProvider( providers: [ BlocProvider( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), ), BlocProvider( create: (context) => LabelCubit( - RepositoryProvider.of>( - context), + context.read>(), ), ), ], @@ -52,13 +51,12 @@ class SortDocumentsButton extends StatelessWidget { initialSortField: state.filter.sortField, initialSortOrder: state.filter.sortOrder, onSubmit: (field, order) => - BlocProvider.of(context) - .updateCurrentFilter( - (filter) => filter.copyWith( - sortField: field, - sortOrder: order, - ), - ), + context.read().updateCurrentFilter( + (filter) => filter.copyWith( + sortField: field, + sortOrder: order, + ), + ), ); }, ), diff --git a/lib/features/edit_label/view/add_label_page.dart b/lib/features/edit_label/view/add_label_page.dart index 973bd66..f3e7931 100644 --- a/lib/features/edit_label/view/add_label_page.dart +++ b/lib/features/edit_label/view/add_label_page.dart @@ -24,7 +24,7 @@ class AddLabelPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: AddLabelFormWidget( pageTitle: pageTitle, @@ -62,7 +62,7 @@ class AddLabelFormWidget extends StatelessWidget { submitButtonConfig: SubmitButtonConfig( icon: const Icon(Icons.add), label: Text(S.of(context).genericActionCreateLabel), - onSubmit: BlocProvider.of>(context).create, + onSubmit: context.read>().create, ), additionalFields: additionalFields, ), diff --git a/lib/features/edit_label/view/edit_label_page.dart b/lib/features/edit_label/view/edit_label_page.dart index 22374a7..c901507 100644 --- a/lib/features/edit_label/view/edit_label_page.dart +++ b/lib/features/edit_label/view/edit_label_page.dart @@ -22,7 +22,7 @@ class EditLabelPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: EditLabelForm( label: label, @@ -63,7 +63,7 @@ class EditLabelForm extends StatelessWidget { submitButtonConfig: SubmitButtonConfig( icon: const Icon(Icons.update), label: Text(S.of(context).genericActionUpdateLabel), - onSubmit: BlocProvider.of>(context).update, + onSubmit: context.read>().update, ), additionalFields: additionalFields, ), @@ -99,11 +99,11 @@ class EditLabelForm extends StatelessWidget { ) ?? false; if (shouldDelete) { - BlocProvider.of>(context).delete(label); + context.read>().delete(label); Navigator.pop(context); } } else { - BlocProvider.of>(context).delete(label); + context.read>().delete(label); Navigator.pop(context); } } diff --git a/lib/features/edit_label/view/impl/add_correspondent_page.dart b/lib/features/edit_label/view/impl/add_correspondent_page.dart index 60b5615..21913cf 100644 --- a/lib/features/edit_label/view/impl/add_correspondent_page.dart +++ b/lib/features/edit_label/view/impl/add_correspondent_page.dart @@ -14,7 +14,7 @@ class AddCorrespondentPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: AddLabelPage( pageTitle: Text(S.of(context).addCorrespondentPageTitle), diff --git a/lib/features/edit_label/view/impl/add_document_type_page.dart b/lib/features/edit_label/view/impl/add_document_type_page.dart index 7652f45..f0ada5c 100644 --- a/lib/features/edit_label/view/impl/add_document_type_page.dart +++ b/lib/features/edit_label/view/impl/add_document_type_page.dart @@ -17,7 +17,7 @@ class AddDocumentTypePage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: AddLabelPage( pageTitle: Text(S.of(context).addDocumentTypePageTitle), diff --git a/lib/features/edit_label/view/impl/add_storage_path_page.dart b/lib/features/edit_label/view/impl/add_storage_path_page.dart index 4a2bf31..33738b0 100644 --- a/lib/features/edit_label/view/impl/add_storage_path_page.dart +++ b/lib/features/edit_label/view/impl/add_storage_path_page.dart @@ -15,7 +15,7 @@ class AddStoragePathPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: AddLabelPage( pageTitle: Text(S.of(context).addStoragePathPageTitle), diff --git a/lib/features/edit_label/view/impl/add_tag_page.dart b/lib/features/edit_label/view/impl/add_tag_page.dart index 55ce11c..5b4b468 100644 --- a/lib/features/edit_label/view/impl/add_tag_page.dart +++ b/lib/features/edit_label/view/impl/add_tag_page.dart @@ -18,7 +18,7 @@ class AddTagPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: AddLabelPage( pageTitle: Text(S.of(context).addTagPageTitle), diff --git a/lib/features/edit_label/view/impl/edit_correspondent_page.dart b/lib/features/edit_label/view/impl/edit_correspondent_page.dart index 3fd8d42..7fe472b 100644 --- a/lib/features/edit_label/view/impl/edit_correspondent_page.dart +++ b/lib/features/edit_label/view/impl/edit_correspondent_page.dart @@ -14,7 +14,7 @@ class EditCorrespondentPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: EditLabelPage( label: correspondent, diff --git a/lib/features/edit_label/view/impl/edit_document_type_page.dart b/lib/features/edit_label/view/impl/edit_document_type_page.dart index e4448af..5a89571 100644 --- a/lib/features/edit_label/view/impl/edit_document_type_page.dart +++ b/lib/features/edit_label/view/impl/edit_document_type_page.dart @@ -13,7 +13,7 @@ class EditDocumentTypePage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: EditLabelPage( label: documentType, diff --git a/lib/features/edit_label/view/impl/edit_storage_path_page.dart b/lib/features/edit_label/view/impl/edit_storage_path_page.dart index 1dcebe8..d4ffd11 100644 --- a/lib/features/edit_label/view/impl/edit_storage_path_page.dart +++ b/lib/features/edit_label/view/impl/edit_storage_path_page.dart @@ -14,7 +14,7 @@ class EditStoragePathPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: EditLabelPage( label: storagePath, diff --git a/lib/features/edit_label/view/impl/edit_tag_page.dart b/lib/features/edit_label/view/impl/edit_tag_page.dart index 3c89e82..dc11d9d 100644 --- a/lib/features/edit_label/view/impl/edit_tag_page.dart +++ b/lib/features/edit_label/view/impl/edit_tag_page.dart @@ -17,7 +17,7 @@ class EditTagPage extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => EditLabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: EditLabelPage( label: tag, diff --git a/lib/features/home/view/home_page.dart b/lib/features/home/view/home_page.dart index 0e75904..5f5562e 100644 --- a/lib/features/home/view/home_page.dart +++ b/lib/features/home/view/home_page.dart @@ -55,13 +55,14 @@ class _HomePageState extends State { body: [ MultiBlocProvider( providers: [ - BlocProvider.value( - value: - DocumentsCubit(Provider.of(context)), + BlocProvider( + create: (context) => DocumentsCubit( + context.read(), + ), ), BlocProvider( create: (context) => SavedViewCubit( - RepositoryProvider.of(context), + context.read(), ), ), ], @@ -71,12 +72,7 @@ class _HomePageState extends State { value: _scannerCubit, child: const ScannerPage(), ), - BlocProvider( - create: (context) => DocumentsCubit( - Provider.of(context), - ), - child: const LabelsPage(), - ), + const LabelsPage(), ][_currentIndex], ), ); diff --git a/lib/features/home/view/widget/info_drawer.dart b/lib/features/home/view/widget/info_drawer.dart index f367755..2c83dd5 100644 --- a/lib/features/home/view/widget/info_drawer.dart +++ b/lib/features/home/view/widget/info_drawer.dart @@ -155,9 +155,8 @@ class _InfoDrawerState extends State { ), onTap: () => Navigator.of(context).push( MaterialPageRoute( - builder: (context) => BlocProvider( - create: (context) => - Provider.of(context), + builder: (context) => BlocProvider.value( + value: context.read(), child: const SettingsPage(), ), ), @@ -214,20 +213,14 @@ class _InfoDrawerState extends State { title: Text(S.of(context).appDrawerLogoutLabel), onTap: () { try { - BlocProvider.of(context).logout(); - Provider.of(context).clear(); - BlocProvider.of(context).clear(); - RepositoryProvider.of>(context) - .clear(); - RepositoryProvider.of>( - context) - .clear(); - RepositoryProvider.of>( - context) - .clear(); - RepositoryProvider.of>(context) - .clear(); - RepositoryProvider.of(context).clear(); + context.read().logout(); + context.read().clear(); + context.read().clear(); + context.read>().clear(); + context.read>().clear(); + context.read>().clear(); + context.read>().clear(); + context.read().clear(); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } @@ -246,8 +239,8 @@ class _InfoDrawerState extends State { builder: (_) => LabelRepositoriesProvider( child: BlocProvider( create: (context) => InboxCubit( - RepositoryProvider.of>(context), - Provider.of(context), + context.read>(), + context.read(), )..loadInbox(), child: const InboxPage(), ), diff --git a/lib/features/inbox/view/pages/inbox_page.dart b/lib/features/inbox/view/pages/inbox_page.dart index f81996e..2e818f7 100644 --- a/lib/features/inbox/view/pages/inbox_page.dart +++ b/lib/features/inbox/view/pages/inbox_page.dart @@ -125,7 +125,7 @@ class _InboxPageState extends State { .toList(); return RefreshIndicator( - onRefresh: () => BlocProvider.of(context).loadInbox(), + onRefresh: () => context.read().loadInbox(), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -205,14 +205,13 @@ class _InboxPageState extends State { ) ?? false; if (isActionConfirmed) { - await BlocProvider.of(context).clearInbox(); + await context.read().clearInbox(); } } Future _onItemDismissed(DocumentModel doc) async { try { - final removedTags = - await BlocProvider.of(context).remove(doc); + final removedTags = await context.read().remove(doc); showSnackBar( context, S.of(context).inboxPageDocumentRemovedMessageText, @@ -239,8 +238,7 @@ class _InboxPageState extends State { Iterable removedTags, ) async { try { - await BlocProvider.of(context) - .undoRemove(document, removedTags); + await context.read().undoRemove(document, removedTags); } 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 b9db3c7..b23fce3 100644 --- a/lib/features/inbox/view/widgets/inbox_empty_widget.dart +++ b/lib/features/inbox/view/widgets/inbox_empty_widget.dart @@ -16,7 +16,7 @@ class InboxEmptyWidget extends StatelessWidget { Widget build(BuildContext context) { return RefreshIndicator( key: _emptyStateRefreshIndicatorKey, - onRefresh: () => BlocProvider.of(context).loadInbox(), + onRefresh: () => context.read().loadInbox(), child: Center( child: Column( mainAxisSize: MainAxisSize.max, diff --git a/lib/features/inbox/view/widgets/inbox_item.dart b/lib/features/inbox/view/widgets/inbox_item.dart index 5b57538..d657e74 100644 --- a/lib/features/inbox/view/widgets/inbox_item.dart +++ b/lib/features/inbox/view/widgets/inbox_item.dart @@ -48,9 +48,9 @@ class InboxItem extends StatelessWidget { onTap: () => Navigator.push( context, MaterialPageRoute( - builder: (_) => BlocProvider( + builder: (context) => BlocProvider( create: (context) => DocumentDetailsCubit( - Provider.of(context), + context.read(), document, ), child: const LabelRepositoriesProvider( diff --git a/lib/features/labels/bloc/providers/correspondent_bloc_provider.dart b/lib/features/labels/bloc/providers/correspondent_bloc_provider.dart index a290167..b3a3a05 100644 --- a/lib/features/labels/bloc/providers/correspondent_bloc_provider.dart +++ b/lib/features/labels/bloc/providers/correspondent_bloc_provider.dart @@ -12,7 +12,7 @@ class CorrespondentBlocProvider extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: child, ); diff --git a/lib/features/labels/bloc/providers/document_type_bloc_provider.dart b/lib/features/labels/bloc/providers/document_type_bloc_provider.dart index be1dba2..9b87313 100644 --- a/lib/features/labels/bloc/providers/document_type_bloc_provider.dart +++ b/lib/features/labels/bloc/providers/document_type_bloc_provider.dart @@ -12,7 +12,7 @@ class DocumentTypeBlocProvider extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: child, ); diff --git a/lib/features/labels/bloc/providers/labels_bloc_provider.dart b/lib/features/labels/bloc/providers/labels_bloc_provider.dart index 47c4fa0..6d6f1a8 100644 --- a/lib/features/labels/bloc/providers/labels_bloc_provider.dart +++ b/lib/features/labels/bloc/providers/labels_bloc_provider.dart @@ -14,22 +14,22 @@ class LabelsBlocProvider extends StatelessWidget { providers: [ BlocProvider>( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), ), BlocProvider>( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), ), BlocProvider>( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), ), BlocProvider>( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), ), ], diff --git a/lib/features/labels/bloc/providers/storage_path_bloc_provider.dart b/lib/features/labels/bloc/providers/storage_path_bloc_provider.dart index 5f6e16c..526458f 100644 --- a/lib/features/labels/bloc/providers/storage_path_bloc_provider.dart +++ b/lib/features/labels/bloc/providers/storage_path_bloc_provider.dart @@ -12,7 +12,7 @@ class StoragePathBlocProvider extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: child, ); diff --git a/lib/features/labels/bloc/providers/tag_bloc_provider.dart b/lib/features/labels/bloc/providers/tag_bloc_provider.dart index 5e414f1..fd0e862 100644 --- a/lib/features/labels/bloc/providers/tag_bloc_provider.dart +++ b/lib/features/labels/bloc/providers/tag_bloc_provider.dart @@ -12,7 +12,7 @@ class TagBlocProvider extends StatelessWidget { Widget build(BuildContext context) { return BlocProvider( create: (context) => LabelCubit( - RepositoryProvider.of>(context), + context.read>(), ), child: child, ); 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 519aa85..9987b72 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 @@ -4,6 +4,7 @@ import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/providers/document_type_bloc_provider.dart'; class DocumentTypeWidget extends StatelessWidget { final int? documentTypeId; @@ -20,10 +21,7 @@ class DocumentTypeWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) => LabelCubit( - RepositoryProvider.of>(context), - ), + return DocumentTypeBlocProvider( child: AbsorbPointer( absorbing: !isClickable, child: GestureDetector( 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 75d0849..cc524a4 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 @@ -4,6 +4,7 @@ import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; import 'package:paperless_mobile/features/labels/bloc/label_state.dart'; +import 'package:paperless_mobile/features/labels/bloc/providers/storage_path_bloc_provider.dart'; class StoragePathWidget extends StatelessWidget { final int? pathId; @@ -21,10 +22,7 @@ class StoragePathWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) => LabelCubit( - RepositoryProvider.of>(context), - ), + return StoragePathBlocProvider( child: AbsorbPointer( absorbing: !isClickable, child: BlocBuilder, LabelState>( 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 c16cf67..eef2da8 100644 --- a/lib/features/labels/tags/view/widgets/tags_form_field.dart +++ b/lib/features/labels/tags/view/widgets/tags_form_field.dart @@ -218,8 +218,8 @@ class _TagFormFieldState extends State { void _onAddTag(BuildContext context, FormFieldState field) async { final Tag? tag = await Navigator.of(context).push( MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: AddTagPage(initialValue: _textEditingController.text), ), ), diff --git a/lib/features/labels/view/pages/labels_page.dart b/lib/features/labels/view/pages/labels_page.dart index 18c29ed..f4f9c6e 100644 --- a/lib/features/labels/view/pages/labels_page.dart +++ b/lib/features/labels/view/pages/labels_page.dart @@ -14,6 +14,10 @@ import 'package:paperless_mobile/features/edit_label/view/impl/edit_storage_path import 'package:paperless_mobile/features/edit_label/view/impl/edit_tag_page.dart'; import 'package:paperless_mobile/features/home/view/widget/info_drawer.dart'; import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart'; +import 'package:paperless_mobile/features/labels/bloc/providers/correspondent_bloc_provider.dart'; +import 'package:paperless_mobile/features/labels/bloc/providers/document_type_bloc_provider.dart'; +import 'package:paperless_mobile/features/labels/bloc/providers/storage_path_bloc_provider.dart'; +import 'package:paperless_mobile/features/labels/bloc/providers/tag_bloc_provider.dart'; import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart'; import 'package:paperless_mobile/generated/l10n.dart'; @@ -119,11 +123,7 @@ class _LabelsPageState extends State body: TabBarView( controller: _tabController, children: [ - BlocProvider( - create: (context) => LabelCubit( - RepositoryProvider.of>( - context), - ), + CorrespondentBlocProvider( child: LabelTabView( filterBuilder: (label) => DocumentFilter( correspondent: IdQueryParameter.fromId(label.id), @@ -139,11 +139,7 @@ class _LabelsPageState extends State onAddNew: _openAddCorrespondentPage, ), ), - BlocProvider( - create: (context) => LabelCubit( - RepositoryProvider.of>( - context), - ), + DocumentTypeBlocProvider( child: LabelTabView( filterBuilder: (label) => DocumentFilter( documentType: IdQueryParameter.fromId(label.id), @@ -159,10 +155,7 @@ class _LabelsPageState extends State onAddNew: _openAddDocumentTypePage, ), ), - BlocProvider( - create: (context) => LabelCubit( - RepositoryProvider.of>(context), - ), + TagBlocProvider( child: LabelTabView( filterBuilder: (label) => DocumentFilter( tags: IdsTagsQuery.fromIds([label.id!]), @@ -186,11 +179,7 @@ class _LabelsPageState extends State onAddNew: _openAddTagPage, ), ), - BlocProvider( - create: (context) => LabelCubit( - RepositoryProvider.of>( - context), - ), + StoragePathBlocProvider( child: LabelTabView( onEdit: _openEditStoragePathPage, filterBuilder: (label) => DocumentFilter( @@ -219,8 +208,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: EditCorrespondentPage(correspondent: correspondent), ), ), @@ -231,8 +220,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: EditDocumentTypePage(documentType: docType), ), ), @@ -243,8 +232,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: EditTagPage(tag: tag), ), ), @@ -255,8 +244,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: EditStoragePathPage( storagePath: path, ), @@ -269,8 +258,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: const AddCorrespondentPage(), ), ), @@ -281,8 +270,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: const AddDocumentTypePage(), ), ), @@ -293,8 +282,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: const AddTagPage(), ), ), @@ -305,8 +294,8 @@ class _LabelsPageState extends State Navigator.push( context, MaterialPageRoute( - builder: (_) => RepositoryProvider.value( - value: RepositoryProvider.of>(context), + builder: (_) => RepositoryProvider( + create: (context) => context.read>(), child: const AddStoragePathPage(), ), ), diff --git a/lib/features/labels/view/widgets/label_item.dart b/lib/features/labels/view/widgets/label_item.dart index 482b5de..a0b0bdf 100644 --- a/lib/features/labels/view/widgets/label_item.dart +++ b/lib/features/labels/view/widgets/label_item.dart @@ -47,7 +47,7 @@ class LabelItem extends StatelessWidget { MaterialPageRoute( builder: (context) => BlocProvider( create: (context) => LinkedDocumentsCubit( - Provider.of(context), + context.read(), filter, ), child: const LinkedDocumentsPage(), diff --git a/lib/features/labels/view/widgets/label_tab_view.dart b/lib/features/labels/view/widgets/label_tab_view.dart index a63d233..035274c 100644 --- a/lib/features/labels/view/widgets/label_tab_view.dart +++ b/lib/features/labels/view/widgets/label_tab_view.dart @@ -63,7 +63,7 @@ class LabelTabView extends StatelessWidget { ); } return RefreshIndicator( - onRefresh: BlocProvider.of>(context).reload, + onRefresh: context.read>().reload, child: ListView( children: labels .map( 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 183c878..25c144c 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 @@ -65,8 +65,7 @@ class _LinkedDocumentsPageState extends State { MaterialPageRoute( builder: (context) => BlocProvider( create: (context) => DocumentDetailsCubit( - Provider.of( - context), + context.read(), document, ), child: const DocumentDetailsPage( diff --git a/lib/features/login/bloc/authentication_cubit.dart b/lib/features/login/bloc/authentication_cubit.dart index fbb6f9d..4757309 100644 --- a/lib/features/login/bloc/authentication_cubit.dart +++ b/lib/features/login/bloc/authentication_cubit.dart @@ -1,9 +1,8 @@ import 'dart:io'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:paperless_api/paperless_api.dart'; -import 'package:paperless_mobile/core/security/security_context_aware_dio_manager.dart'; +import 'package:paperless_mobile/core/security/authentication_aware_dio_manager.dart'; import 'package:paperless_mobile/core/store/local_vault.dart'; import 'package:paperless_mobile/features/login/bloc/authentication_state.dart'; import 'package:paperless_mobile/features/login/model/authentication_information.dart'; @@ -16,7 +15,7 @@ class AuthenticationCubit extends HydratedCubit { final LocalAuthenticationService _localAuthService; final PaperlessAuthenticationApi _authApi; final LocalVault _localVault; - final SecurityContextAwareDioManager _dioWrapper; + final AuthenticationAwareDioManager _dioWrapper; AuthenticationCubit( this._localVault, diff --git a/lib/features/login/bloc/authentication_state.dart b/lib/features/login/bloc/authentication_state.dart index ef244f4..9be2ab5 100644 --- a/lib/features/login/bloc/authentication_state.dart +++ b/lib/features/login/bloc/authentication_state.dart @@ -20,7 +20,7 @@ class AuthenticationState { required this.wasLoginStored, this.wasLocalAuthenticationSuccessful, this.authentication, - }); + }) : assert(!isAuthenticated || authentication != null); AuthenticationState copyWith({ bool? wasLoginStored, diff --git a/lib/features/login/view/login_page.dart b/lib/features/login/view/login_page.dart index e6cec2a..5da78a0 100644 --- a/lib/features/login/view/login_page.dart +++ b/lib/features/login/view/login_page.dart @@ -92,12 +92,12 @@ class _LoginPageState extends State { setState(() => _isLoginLoading = true); final form = _formKey.currentState!.value; try { - await BlocProvider.of(context).login( - credentials: form[UserCredentialsFormField.fkCredentials], - serverUrl: form[ServerAddressFormField.fkServerAddress], - clientCertificate: - form[ClientCertificateFormField.fkClientCertificate], - ); + await context.read().login( + credentials: form[UserCredentialsFormField.fkCredentials], + serverUrl: form[ServerAddressFormField.fkServerAddress], + clientCertificate: + form[ClientCertificateFormField.fkClientCertificate], + ); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } on Map catch (error, stackTrace) { diff --git a/lib/features/login/view/widgets/server_address_form_field.dart b/lib/features/login/view/widgets/server_address_form_field.dart index 176b380..03e5b47 100644 --- a/lib/features/login/view/widgets/server_address_form_field.dart +++ b/lib/features/login/view/widgets/server_address_form_field.dart @@ -63,9 +63,9 @@ class _ServerAddressFormFieldState extends State { } //https://stackoverflow.com/questions/49648022/check-whether-there-is-an-internet-connection-available-on-flutter-app setState(() => _reachabilityStatus = ReachabilityStatus.testing); - final isReachable = - await Provider.of(context, listen: false) - .isServerReachable(address); + final isReachable = await context + .read() + .isServerReachable(address); if (isReachable) { setState(() => _reachabilityStatus = ReachabilityStatus.reachable); } else { diff --git a/lib/features/saved_view/view/saved_view_selection_widget.dart b/lib/features/saved_view/view/saved_view_selection_widget.dart index 01ffa92..6ba4247 100644 --- a/lib/features/saved_view/view/saved_view_selection_widget.dart +++ b/lib/features/saved_view/view/saved_view_selection_widget.dart @@ -129,7 +129,7 @@ class SavedViewSelectionWidget extends StatelessWidget { ); if (newView != null) { try { - await BlocProvider.of(context).add(newView); + await context.read().add(newView); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } @@ -139,9 +139,9 @@ class SavedViewSelectionWidget extends StatelessWidget { void _onSelected( bool isSelected, BuildContext context, SavedView view) async { if (isSelected) { - BlocProvider.of(context).selectView(view); + context.read().selectView(view); } else { - BlocProvider.of(context).selectView(null); + context.read().selectView(null); } } @@ -154,7 +154,7 @@ class SavedViewSelectionWidget extends StatelessWidget { false; if (delete) { try { - BlocProvider.of(context).remove(view); + context.read().remove(view); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } diff --git a/lib/features/scan/view/scanner_page.dart b/lib/features/scan/view/scanner_page.dart index 8b88e97..1b222ff 100644 --- a/lib/features/scan/view/scanner_page.dart +++ b/lib/features/scan/view/scanner_page.dart @@ -126,12 +126,12 @@ class _ScannerPageState extends State if (kDebugMode) { dev.log('[ScannerPage] Wrote image to temporary file: ${file.path}'); } - BlocProvider.of(context).addScan(file); + context.read().addScan(file); } void _onPrepareDocumentUpload(BuildContext context) async { final doc = _buildDocumentFromImageFiles( - BlocProvider.of(context).state, + context.read().state, ); final bytes = await doc.save(); final uploaded = await Navigator.of(context).push( @@ -139,19 +139,13 @@ class _ScannerPageState extends State builder: (_) => LabelRepositoriesProvider( child: BlocProvider( create: (context) => DocumentUploadCubit( - localVault: Provider.of(context), - documentApi: Provider.of(context), + localVault: context.read(), + documentApi: context.read(), correspondentRepository: - RepositoryProvider.of>( - context, - ), + context.read>(), documentTypeRepository: - RepositoryProvider.of>( - context, - ), - tagRepository: RepositoryProvider.of>( - context, - ), + context.read>(), + tagRepository: context.read>(), ), child: DocumentUploadPreparationPage( fileBytes: bytes, @@ -162,7 +156,7 @@ class _ScannerPageState extends State ) ?? false; if (uploaded) { - BlocProvider.of(context).reset(); + context.read().reset(); } } @@ -216,8 +210,7 @@ class _ScannerPageState extends State file: scans[index], onDelete: () async { try { - BlocProvider.of(context) - .removeScan(index); + context.read().removeScan(index); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } @@ -230,7 +223,7 @@ class _ScannerPageState extends State void _reset(BuildContext context) { try { - BlocProvider.of(context).reset(); + context.read().reset(); } on PaperlessServerException catch (error, stackTrace) { showErrorMessage(context, error, stackTrace); } @@ -274,19 +267,13 @@ class _ScannerPageState extends State builder: (_) => LabelRepositoriesProvider( child: BlocProvider( create: (context) => DocumentUploadCubit( - localVault: Provider.of(context), - documentApi: Provider.of(context), + localVault: context.read(), + documentApi: context.read(), correspondentRepository: - RepositoryProvider.of>( - context, - ), + context.read>(), documentTypeRepository: - RepositoryProvider.of>( - context, - ), - tagRepository: RepositoryProvider.of>( - context, - ), + context.read>(), + tagRepository: context.read>(), ), child: DocumentUploadPreparationPage( fileBytes: fileBytes, diff --git a/lib/features/settings/view/settings_page.dart b/lib/features/settings/view/settings_page.dart index 68b4d0a..89db6ad 100644 --- a/lib/features/settings/view/settings_page.dart +++ b/lib/features/settings/view/settings_page.dart @@ -44,9 +44,10 @@ class SettingsPage extends StatelessWidget { Navigator.push( context, MaterialPageRoute( - builder: (ctxt) => BlocProvider.value( - value: BlocProvider.of(context), - child: page), + builder: (context) => BlocProvider.value( + value: context.read(), + child: page, + ), maintainState: true, ), ); diff --git a/lib/features/settings/view/widgets/biometric_authentication_setting.dart b/lib/features/settings/view/widgets/biometric_authentication_setting.dart index f6ab030..bedd7e6 100644 --- a/lib/features/settings/view/widgets/biometric_authentication_setting.dart +++ b/lib/features/settings/view/widgets/biometric_authentication_setting.dart @@ -19,8 +19,7 @@ class BiometricAuthenticationSetting extends StatelessWidget { subtitle: Text( S.of(context).appSettingsBiometricAuthenticationDescriptionText), onChanged: (val) async { - final settingsBloc = - BlocProvider.of(context); + final settingsBloc = context.read(); final String localizedReason = val ? S .of(context) @@ -28,9 +27,9 @@ class BiometricAuthenticationSetting extends StatelessWidget { : S .of(context) .appSettingsDisableBiometricAuthenticationReasonText; - final changeValue = - await Provider.of(context) - .authenticateLocalUser(localizedReason); + final changeValue = await context + .read() + .authenticateLocalUser(localizedReason); if (changeValue) { settingsBloc.setIsBiometricAuthenticationEnabled(val); } diff --git a/lib/features/settings/view/widgets/clear_storage_setting.dart b/lib/features/settings/view/widgets/clear_storage_setting.dart index c6c6279..a956cfe 100644 --- a/lib/features/settings/view/widgets/clear_storage_setting.dart +++ b/lib/features/settings/view/widgets/clear_storage_setting.dart @@ -13,7 +13,7 @@ class ClearStorageSetting extends StatelessWidget { subtitle: Text("Remove downloaded files, scans and clear the cache's content"), onTap: () { - Provider.of(context).emptyCache(); + context.read().emptyCache(); FileService.clearUserData(); }, ); diff --git a/lib/features/settings/view/widgets/language_selection_setting.dart b/lib/features/settings/view/widgets/language_selection_setting.dart index 252cb6c..8622410 100644 --- a/lib/features/settings/view/widgets/language_selection_setting.dart +++ b/lib/features/settings/view/widgets/language_selection_setting.dart @@ -44,12 +44,13 @@ class _LanguageSelectionSettingState extends State { label: _languageOptions['cs']!, ) ], - initialValue: BlocProvider.of(context) + initialValue: context + .read() .state .preferredLocaleSubtag, ), - ).then((value) => BlocProvider.of(context) - .setLocale(value)), + ).then((value) => + context.read().setLocale(value)), ); }, ); diff --git a/lib/features/settings/view/widgets/theme_mode_setting.dart b/lib/features/settings/view/widgets/theme_mode_setting.dart index fd97f85..4430e2e 100644 --- a/lib/features/settings/view/widgets/theme_mode_setting.dart +++ b/lib/features/settings/view/widgets/theme_mode_setting.dart @@ -38,14 +38,14 @@ class ThemeModeSetting extends StatelessWidget { S.of(context).settingsPageAppearanceSettingDarkThemeLabel, ) ], - initialValue: BlocProvider.of(context) + initialValue: context + .read() .state .preferredThemeMode, title: Text(S.of(context).settingsPageAppearanceSettingTitle), ), ).then((value) { - return BlocProvider.of(context) - .setThemeMode(value); + return context.read().setThemeMode(value); }), ); }, diff --git a/lib/main.dart b/lib/main.dart index 4604708..c1f3979 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,19 +10,20 @@ import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:http/http.dart'; import 'package:http/io_client.dart'; +import 'package:http_interceptor/http/intercepted_client.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl_standalone.dart'; import 'package:local_auth/local_auth.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/core/bloc/paperless_server_information_cubit.dart'; import 'package:paperless_mobile/core/global/constants.dart'; +import 'package:paperless_mobile/core/interceptor/authentication.interceptor.dart'; import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart'; -import 'package:paperless_mobile/core/model/paperless_statistics_state.dart'; import 'package:paperless_mobile/core/repository/impl/correspondent_repository_impl.dart'; import 'package:paperless_mobile/core/repository/impl/document_type_repository_impl.dart'; import 'package:paperless_mobile/core/repository/impl/saved_view_repository_impl.dart'; @@ -30,17 +31,19 @@ import 'package:paperless_mobile/core/repository/impl/storage_path_repository_im import 'package:paperless_mobile/core/repository/impl/tag_repository_impl.dart'; import 'package:paperless_mobile/core/repository/label_repository.dart'; import 'package:paperless_mobile/core/repository/saved_view_repository.dart'; -import 'package:paperless_mobile/core/security/security_context_aware_dio_manager.dart'; +import 'package:paperless_mobile/core/security/authentication_aware_dio_manager.dart'; import 'package:paperless_mobile/core/service/connectivity_status.service.dart'; import 'package:paperless_mobile/core/service/file_service.dart'; import 'package:paperless_mobile/core/store/local_vault.dart'; import 'package:paperless_mobile/extensions/flutter_extensions.dart'; +import 'package:paperless_mobile/extensions/security_context_extension.dart'; import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart'; import 'package:paperless_mobile/features/document_upload/cubit/document_upload_cubit.dart'; import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.dart'; import 'package:paperless_mobile/features/home/view/home_page.dart'; import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart'; import 'package:paperless_mobile/features/login/bloc/authentication_state.dart'; +import 'package:paperless_mobile/features/login/model/authentication_information.dart'; import 'package:paperless_mobile/features/login/services/authentication_service.dart'; import 'package:paperless_mobile/features/login/view/login_page.dart'; import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart'; @@ -62,18 +65,12 @@ void main() async { await findSystemLocale(); // Required for self signed client certificates - final dioWrapper = SecurityContextAwareDioManager(); - IOClient httpClient = IOClient(); + final dioWrapper = AuthenticationAwareDioManager(); - dioWrapper.securityContextChanges.listen( - (context) => httpClient = IOClient(HttpClient(context: context)), - ); // Initialize External dependencies final connectivity = Connectivity(); final encryptedSharedPreferences = EncryptedSharedPreferences(); final localAuthentication = LocalAuthentication(); - final cacheManager = cm.CacheManager(cm.Config('cacheKey', - fileService: cm.HttpFileService(httpClient: httpClient))); // Initialize Paperless APIs final authApi = PaperlessAuthenticationApiImpl(dioWrapper.client); @@ -104,8 +101,35 @@ void main() async { authApi, dioWrapper, ); - //TODO: Check if hydrated cubit restores state. - //await authCubit.restoreSessionState(); + + String? currentServerUrl; + String? currentAuthToken; + + if (authCubit.state.isAuthenticated) { + final auth = authCubit.state.authentication!; + dioWrapper.updateSettings( + baseUrl: auth.serverUrl, + authToken: auth.token, + clientCertificate: auth.clientCertificate, + ); + currentServerUrl = auth.serverUrl; + currentAuthToken = auth.token; + } + + SecurityContext securityContext = SecurityContext(); + authCubit.stream.asBroadcastStream().listen((event) { + if (event.isAuthenticated) { + final auth = event.authentication!; + securityContext = + SecurityContext().withClientCertificate(auth.clientCertificate); + currentServerUrl = auth.serverUrl; + currentAuthToken = auth.token; + } else { + securityContext = SecurityContext(); + currentServerUrl = null; + currentAuthToken = null; + } + }); // Create repositories final tagRepository = TagRepositoryImpl(labelsApi); @@ -122,7 +146,47 @@ void main() async { Provider.value(value: labelsApi), Provider.value(value: statsApi), Provider.value(value: savedViewsApi), - Provider.value(value: cacheManager), + ProxyProvider( + create: (context) => cm.CacheManager( + cm.Config( + 'cacheKey', + fileService: cm.HttpFileService( + httpClient: InterceptedClient.build( + interceptors: [ + AuthenticationInterceptor( + serverUrl: currentServerUrl, + token: currentAuthToken, + ), + ], + client: IOClient( + HttpClient( + context: securityContext, + ), + ), + ), + ), + ), + ), + update: (context, securityContext, previous) => cm.CacheManager( + cm.Config( + 'cacheKey', + fileService: cm.HttpFileService( + httpClient: InterceptedClient.build( + interceptors: [ + AuthenticationInterceptor( + serverUrl: currentServerUrl, + token: currentAuthToken, + ), + ], + client: IOClient( + HttpClient( + context: securityContext, + ), + ), + )), + ), + ), + ), Provider.value(value: localVault), Provider.value( value: connectivityStatusService, @@ -148,17 +212,8 @@ void main() async { ], child: MultiBlocProvider( providers: [ - BlocProvider( - create: (context) => AuthenticationCubit( - localVault, - localAuthService, - authApi, - dioWrapper, - ), - ), - BlocProvider.value( - value: connectivityCubit, - ), + BlocProvider.value(value: authCubit), + BlocProvider.value(value: connectivityCubit), ], child: const PaperlessMobileEntrypoint(), ), @@ -225,10 +280,7 @@ class _PaperlessMobileEntrypointState extends State { return MultiBlocProvider( providers: [ BlocProvider( - create: (context) => ConnectivityCubit(context.watch()), - ), - BlocProvider( - create: (context) => PaperlessServerInformationCubit(context.watch()), + create: (context) => PaperlessServerInformationCubit(context.read()), ), BlocProvider( create: (context) => ApplicationSettingsCubit(), @@ -313,13 +365,13 @@ class _AuthenticationWrapperState extends State { final success = await Navigator.push( context, MaterialPageRoute( - builder: (context) => BlocProvider( - create: (BuildContext context) => DocumentUploadCubit( - localVault: context.watch(), - documentApi: context.watch(), - tagRepository: context.watch(), - correspondentRepository: context.watch(), - documentTypeRepository: context.watch(), + builder: (context) => BlocProvider.value( + value: DocumentUploadCubit( + localVault: context.read(), + documentApi: context.read(), + tagRepository: context.read(), + correspondentRepository: context.read(), + documentTypeRepository: context.read(), ), child: DocumentUploadPreparationPage( fileBytes: bytes,