WIP - Provider refactorings

This commit is contained in:
Anton Stubenbord
2022-12-27 00:12:33 +01:00
parent 60aecb549d
commit bf0e186646
53 changed files with 434 additions and 416 deletions

View File

@@ -2,11 +2,7 @@ import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_mobile/core/service/connectivity_status.service.dart'; import 'package:paperless_mobile/core/service/connectivity_status.service.dart';
import 'package:injectable/injectable.dart';
@prod
@test
@lazySingleton
class ConnectivityCubit extends Cubit<ConnectivityState> { class ConnectivityCubit extends Cubit<ConnectivityState> {
final ConnectivityStatusService connectivityStatusService; final ConnectivityStatusService connectivityStatusService;
StreamSubscription<bool>? _sub; StreamSubscription<bool>? _sub;

View File

@@ -2,27 +2,25 @@ import 'dart:developer';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:http_interceptor/http_interceptor.dart'; import 'package:http_interceptor/http_interceptor.dart';
import 'package:paperless_mobile/core/store/local_vault.dart';
class AuthenticationInterceptor implements InterceptorContract { class AuthenticationInterceptor implements InterceptorContract {
final LocalVault _localVault; String? serverUrl;
AuthenticationInterceptor(this._localVault); String? token;
AuthenticationInterceptor({this.serverUrl, this.token});
@override @override
Future<BaseRequest> interceptRequest({required BaseRequest request}) async { Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
final auth = await _localVault.loadAuthenticationInformation();
if (kDebugMode) { if (kDebugMode) {
log("Intercepted ${request.method} request to ${request.url.toString()}"); log("Intercepted ${request.method} request to ${request.url.toString()}");
} }
return request.copyWith( return request.copyWith(
//Append server Url url: Uri.parse((serverUrl ?? '') + request.url.toString()),
headers: auth?.token?.isEmpty ?? true headers: token?.isEmpty ?? true
? request.headers ? request.headers
: { : {
...request.headers, ...request.headers,
'Authorization': 'Token ${auth!.token}', 'Authorization': 'Token $token',
}, },
); );
} }

View File

@@ -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<String, dynamic> 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<String>().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);
}
}

View File

@@ -12,20 +12,16 @@ class LabelRepositoriesProvider extends StatelessWidget {
return MultiRepositoryProvider( return MultiRepositoryProvider(
providers: [ providers: [
RepositoryProvider( RepositoryProvider(
create: (context) => create: (context) => context.read<LabelRepository<Correspondent>>(),
RepositoryProvider.of<LabelRepository<Correspondent>>(context),
), ),
RepositoryProvider( RepositoryProvider(
create: (context) => create: (context) => context.read<LabelRepository<DocumentType>>(),
RepositoryProvider.of<LabelRepository<DocumentType>>(context),
), ),
RepositoryProvider( RepositoryProvider(
create: (context) => create: (context) => context.read<LabelRepository<StoragePath>>(),
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
), ),
RepositoryProvider( RepositoryProvider(
create: (context) => create: (context) => context.read<LabelRepository<Tag>>(),
RepositoryProvider.of<LabelRepository<Tag>>(context),
), ),
], ],
child: child, child: child,

View File

@@ -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<SecurityContext> get securityContextChanges =>
_securityContextStreamController.stream.asBroadcastStream();
final StreamController<SecurityContext> _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'});
}
}
}

View File

@@ -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<SecurityContext> get securityContextChanges =>
_securityContextStreamController.stream.asBroadcastStream();
final StreamController<SecurityContext> _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<String>().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'});
}
}
}

View File

@@ -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,
);
}
}

View File

@@ -187,14 +187,14 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
Navigator.push<bool>( Navigator.push<bool>(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BlocProvider( builder: (context) => BlocProvider.value(
create: (context) => EditDocumentCubit( value: EditDocumentCubit(
document, document,
documentsApi: context.watch(), documentsApi: context.read(),
correspondentRepository: context.watch(), correspondentRepository: context.read(),
documentTypeRepository: context.watch(), documentTypeRepository: context.read(),
storagePathRepository: context.watch(), storagePathRepository: context.read(),
tagRepository: context.watch(), tagRepository: context.read(),
), ),
child: BlocListener<EditDocumentCubit, EditDocumentState>( child: BlocListener<EditDocumentCubit, EditDocumentState>(
listenWhen: (previous, current) => listenWhen: (previous, current) =>

View File

@@ -166,8 +166,9 @@ class _DocumentUploadPreparationPageState
notAssignedSelectable: false, notAssignedSelectable: false,
formBuilderState: _formKey.currentState, formBuilderState: _formKey.currentState,
labelCreationWidgetBuilder: (initialName) => labelCreationWidgetBuilder: (initialName) =>
RepositoryProvider<LabelRepository<DocumentType>>( RepositoryProvider(
create: (context) => context.watch(), create: (context) =>
context.read<LabelRepository<DocumentType>>(),
child: AddDocumentTypePage(initialName: initialName), child: AddDocumentTypePage(initialName: initialName),
), ),
textFieldLabel: textFieldLabel:
@@ -180,8 +181,9 @@ class _DocumentUploadPreparationPageState
notAssignedSelectable: false, notAssignedSelectable: false,
formBuilderState: _formKey.currentState, formBuilderState: _formKey.currentState,
labelCreationWidgetBuilder: (initialName) => labelCreationWidgetBuilder: (initialName) =>
RepositoryProvider<LabelRepository<Correspondent>>( RepositoryProvider(
create: (context) => context.watch(), create: (context) =>
context.read<LabelRepository<Correspondent>>(),
child: AddCorrespondentPage(initialName: initialName), child: AddCorrespondentPage(initialName: initialName),
), ),
textFieldLabel: textFieldLabel:

View File

@@ -99,9 +99,8 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
return LabelFormField<StoragePath>( return LabelFormField<StoragePath>(
notAssignedSelectable: false, notAssignedSelectable: false,
formBuilderState: _formKey.currentState, formBuilderState: _formKey.currentState,
labelCreationWidgetBuilder: (initialValue) => labelCreationWidgetBuilder: (initialValue) => RepositoryProvider(
RepositoryProvider<LabelRepository<StoragePath>>( create: (context) => context.read<LabelRepository<StoragePath>>(),
create: (context) => context.watch(),
child: AddStoragePathPage(initalValue: initialValue), child: AddStoragePathPage(initalValue: initialValue),
), ),
textFieldLabel: S.of(context).documentStoragePathPropertyLabel, textFieldLabel: S.of(context).documentStoragePathPropertyLabel,
@@ -117,9 +116,8 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
return LabelFormField<Correspondent>( return LabelFormField<Correspondent>(
notAssignedSelectable: false, notAssignedSelectable: false,
formBuilderState: _formKey.currentState, formBuilderState: _formKey.currentState,
labelCreationWidgetBuilder: (initialValue) => labelCreationWidgetBuilder: (initialValue) => RepositoryProvider(
RepositoryProvider<LabelRepository<Correspondent>>( create: (context) => context.read<LabelRepository<Correspondent>>(),
create: context.watch(),
child: AddCorrespondentPage(initialName: initialValue), child: AddCorrespondentPage(initialName: initialValue),
), ),
textFieldLabel: S.of(context).documentCorrespondentPropertyLabel, textFieldLabel: S.of(context).documentCorrespondentPropertyLabel,
@@ -135,9 +133,8 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
return LabelFormField<DocumentType>( return LabelFormField<DocumentType>(
notAssignedSelectable: false, notAssignedSelectable: false,
formBuilderState: _formKey.currentState, formBuilderState: _formKey.currentState,
labelCreationWidgetBuilder: (currentInput) => labelCreationWidgetBuilder: (currentInput) => RepositoryProvider(
RepositoryProvider<LabelRepository<DocumentType>>( create: (context) => context.read<LabelRepository<DocumentType>>(),
create: (context) => context.watch(),
child: AddDocumentTypePage( child: AddDocumentTypePage(
initialName: currentInput, initialName: currentInput,
), ),

View File

@@ -32,9 +32,6 @@ class DocumentsPage extends StatefulWidget {
} }
class _DocumentsPageState extends State<DocumentsPage> { class _DocumentsPageState extends State<DocumentsPage> {
late final DocumentsCubit _documentsCubit;
late final SavedViewCubit _savedViewCubit;
final _pagingController = PagingController<int, DocumentModel>( final _pagingController = PagingController<int, DocumentModel>(
firstPageKey: 1, firstPageKey: 1,
); );
@@ -42,10 +39,8 @@ class _DocumentsPageState extends State<DocumentsPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_documentsCubit = context.watch();
_savedViewCubit = context.watch();
try { try {
_documentsCubit.load(); context.read<DocumentsCubit>().load();
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
@@ -66,7 +61,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
current == ConnectivityState.connected, current == ConnectivityState.connected,
listener: (context, state) { listener: (context, state) {
try { try {
_documentsCubit.load(); context.read<DocumentsCubit>().load();
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
@@ -74,9 +69,9 @@ class _DocumentsPageState extends State<DocumentsPage> {
builder: (context, connectivityState) { builder: (context, connectivityState) {
return Scaffold( return Scaffold(
drawer: BlocProvider.value( drawer: BlocProvider.value(
value: BlocProvider.of<AuthenticationCubit>(context), value: context.read<AuthenticationCubit>(),
child: InfoDrawer( child: InfoDrawer(
afterInboxClosed: () => _documentsCubit.reload(), afterInboxClosed: () => context.read<DocumentsCubit>().reload(),
), ),
), ),
floatingActionButton: BlocBuilder<DocumentsCubit, DocumentsState>( floatingActionButton: BlocBuilder<DocumentsCubit, DocumentsState>(
@@ -111,22 +106,25 @@ class _DocumentsPageState extends State<DocumentsPage> {
), ),
), ),
isScrollControlled: true, isScrollControlled: true,
builder: (context) => DraggableScrollableSheet( builder: (_) => BlocProvider.value(
expand: false, value: context.read<DocumentsCubit>(),
snap: true, child: DraggableScrollableSheet(
initialChildSize: .9, expand: false,
maxChildSize: .9, snap: true,
builder: (context, controller) => LabelsBlocProvider( initialChildSize: .9,
child: DocumentFilterPanel( maxChildSize: .9,
initialFilter: _documentsCubit.state.filter, builder: (context, controller) => LabelsBlocProvider(
scrollController: controller, child: DocumentFilterPanel(
initialFilter: context.read<DocumentsCubit>().state.filter,
scrollController: controller,
),
), ),
), ),
), ),
); );
if (filter != null) { if (filter != null) {
_documentsCubit.updateFilter(filter: filter); context.read<DocumentsCubit>().updateFilter(filter: filter);
_savedViewCubit.resetSelection(); context.read<SavedViewCubit>().resetSelection();
} }
} }
@@ -177,8 +175,8 @@ class _DocumentsPageState extends State<DocumentsPage> {
child: DocumentsEmptyState( child: DocumentsEmptyState(
state: state, state: state,
onReset: () { onReset: () {
_documentsCubit.resetFilter(); context.read<DocumentsCubit>().resetFilter();
_savedViewCubit.resetSelection(); context.read<SavedViewCubit>().resetSelection();
}, },
), ),
); );
@@ -196,13 +194,15 @@ class _DocumentsPageState extends State<DocumentsPage> {
listener: (context, state) { listener: (context, state) {
try { try {
if (state.selectedSavedViewId == null) { if (state.selectedSavedViewId == null) {
_documentsCubit.resetFilter(); context.read<DocumentsCubit>().resetFilter();
} else { } else {
final newFilter = state final newFilter = state
.value[state.selectedSavedViewId] .value[state.selectedSavedViewId]
?.toDocumentFilter(); ?.toDocumentFilter();
if (newFilter != null) { if (newFilter != null) {
_documentsCubit.updateFilter(filter: newFilter); context
.read<DocumentsCubit>()
.updateFilter(filter: newFilter);
} }
} }
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
@@ -220,11 +220,11 @@ class _DocumentsPageState extends State<DocumentsPage> {
? Icons.list ? Icons.list
: Icons.grid_view, : Icons.grid_view,
), ),
onPressed: () => onPressed: () => context
BlocProvider.of<ApplicationSettingsCubit>(context) .read<ApplicationSettingsCubit>()
.setViewType( .setViewType(
settings.preferredViewType.toggle(), settings.preferredViewType.toggle(),
), ),
), ),
], ],
), ),
@@ -243,7 +243,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
await Navigator.of(context).push<DocumentModel?>( await Navigator.of(context).push<DocumentModel?>(
_buildDetailsPageRoute(document), _buildDetailsPageRoute(document),
); );
_documentsCubit.reload(); context.read<DocumentsCubit>().reload();
} }
MaterialPageRoute<DocumentModel?> _buildDetailsPageRoute( MaterialPageRoute<DocumentModel?> _buildDetailsPageRoute(
@@ -251,7 +251,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
return MaterialPageRoute( return MaterialPageRoute(
builder: (_) => BlocProvider( builder: (_) => BlocProvider(
create: (context) => DocumentDetailsCubit( create: (context) => DocumentDetailsCubit(
context.watch(), context.read<PaperlessDocumentsApi>(),
document, document,
), ),
child: const LabelRepositoriesProvider( child: const LabelRepositoriesProvider(
@@ -263,21 +263,22 @@ class _DocumentsPageState extends State<DocumentsPage> {
void _addTagToFilter(int tagId) { void _addTagToFilter(int tagId) {
try { try {
final tagsQuery = _documentsCubit.state.filter.tags is IdsTagsQuery final tagsQuery =
? _documentsCubit.state.filter.tags as IdsTagsQuery context.read<DocumentsCubit>().state.filter.tags is IdsTagsQuery
: const IdsTagsQuery(); ? context.read<DocumentsCubit>().state.filter.tags as IdsTagsQuery
: const IdsTagsQuery();
if (tagsQuery.includedIds.contains(tagId)) { if (tagsQuery.includedIds.contains(tagId)) {
_documentsCubit.updateCurrentFilter( context.read<DocumentsCubit>().updateCurrentFilter(
(filter) => filter.copyWith( (filter) => filter.copyWith(
tags: tagsQuery.withIdsRemoved([tagId]), tags: tagsQuery.withIdsRemoved([tagId]),
), ),
); );
} else { } else {
_documentsCubit.updateCurrentFilter( context.read<DocumentsCubit>().updateCurrentFilter(
(filter) => filter.copyWith( (filter) => filter.copyWith(
tags: tagsQuery.withIdQueriesAdded([IncludeTagIdQuery(tagId)]), tags: tagsQuery.withIdQueriesAdded([IncludeTagIdQuery(tagId)]),
), ),
); );
} }
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
@@ -285,7 +286,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
} }
void _addCorrespondentToFilter(int? correspondentId) { void _addCorrespondentToFilter(int? correspondentId) {
final cubit = BlocProvider.of<DocumentsCubit>(context); final cubit = context.read<DocumentsCubit>();
try { try {
if (cubit.state.filter.correspondent.id == correspondentId) { if (cubit.state.filter.correspondent.id == correspondentId) {
cubit.updateCurrentFilter( cubit.updateCurrentFilter(
@@ -304,7 +305,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
} }
void _addDocumentTypeToFilter(int? documentTypeId) { void _addDocumentTypeToFilter(int? documentTypeId) {
final cubit = BlocProvider.of<DocumentsCubit>(context); final cubit = context.read<DocumentsCubit>();
try { try {
if (cubit.state.filter.documentType.id == documentTypeId) { if (cubit.state.filter.documentType.id == documentTypeId) {
cubit.updateCurrentFilter( cubit.updateCurrentFilter(
@@ -323,7 +324,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
} }
void _addStoragePathToFilter(int? pathId) { void _addStoragePathToFilter(int? pathId) {
final cubit = BlocProvider.of<DocumentsCubit>(context); final cubit = context.read<DocumentsCubit>();
try { try {
if (cubit.state.filter.correspondent.id == pathId) { if (cubit.state.filter.correspondent.id == pathId) {
cubit.updateCurrentFilter( cubit.updateCurrentFilter(
@@ -342,28 +343,29 @@ class _DocumentsPageState extends State<DocumentsPage> {
} }
Future<void> _loadNewPage(int pageKey) async { Future<void> _loadNewPage(int pageKey) async {
final pageCount = _documentsCubit.state final documentsCubit = context.read<DocumentsCubit>();
.inferPageCount(pageSize: _documentsCubit.state.filter.pageSize); final pageCount = documentsCubit.state
.inferPageCount(pageSize: documentsCubit.state.filter.pageSize);
if (pageCount <= pageKey + 1) { if (pageCount <= pageKey + 1) {
_pagingController.nextPageKey = null; _pagingController.nextPageKey = null;
} }
try { try {
await _documentsCubit.loadMore(); await documentsCubit.loadMore();
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
} }
void _onSelected(DocumentModel model) { void _onSelected(DocumentModel model) {
_documentsCubit.toggleDocumentSelection(model); context.read<DocumentsCubit>().toggleDocumentSelection(model);
} }
Future<void> _onRefresh() async { Future<void> _onRefresh() async {
try { try {
_documentsCubit.updateCurrentFilter( context.read<DocumentsCubit>().updateCurrentFilter(
(filter) => filter.copyWith(page: 1), (filter) => filter.copyWith(page: 1),
); );
_savedViewCubit.reload(); context.read<SavedViewCubit>().reload();
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }

View File

@@ -30,15 +30,14 @@ class DocumentPreview extends StatelessWidget {
fit: fit, fit: fit,
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
cacheKey: "thumb_$id", cacheKey: "thumb_$id",
imageUrl: imageUrl: context.read<PaperlessDocumentsApi>().getThumbnailUrl(id),
Provider.of<PaperlessDocumentsApi>(context).getThumbnailUrl(id),
errorWidget: (ctxt, msg, __) => Text(msg), errorWidget: (ctxt, msg, __) => Text(msg),
placeholder: (context, value) => Shimmer.fromColors( placeholder: (context, value) => Shimmer.fromColors(
baseColor: Colors.grey[300]!, baseColor: Colors.grey[300]!,
highlightColor: Colors.grey[100]!, highlightColor: Colors.grey[100]!,
child: const SizedBox(height: 100, width: 100), child: const SizedBox(height: 100, width: 100),
), ),
cacheManager: context.watch(), cacheManager: context.watch<CacheManager>(),
), ),
// ), // ),
); );

View File

@@ -48,8 +48,7 @@ class _DocumentsPageAppBarState extends State<DocumentsPageAppBar> {
), ),
leading: IconButton( leading: IconButton(
icon: const Icon(Icons.close), icon: const Icon(Icons.close),
onPressed: () => onPressed: () => context.read<DocumentsCubit>().resetSelection(),
BlocProvider.of<DocumentsCubit>(context).resetSelection(),
), ),
title: Text( title: Text(
'${documentsState.selection.length} ${S.of(context).documentsSelectedText}'), '${documentsState.selection.length} ${S.of(context).documentsSelectedText}'),
@@ -111,7 +110,8 @@ class _DocumentsPageAppBarState extends State<DocumentsPageAppBar> {
false; false;
if (shouldDelete) { if (shouldDelete) {
try { try {
await BlocProvider.of<DocumentsCubit>(context) await context
.read<DocumentsCubit>()
.bulkRemove(documentsState.selection); .bulkRemove(documentsState.selection);
showSnackBar( showSnackBar(
context, context,

View File

@@ -29,20 +29,19 @@ class SortDocumentsButton extends StatelessWidget {
), ),
), ),
builder: (_) => BlocProvider<DocumentsCubit>.value( builder: (_) => BlocProvider<DocumentsCubit>.value(
value: BlocProvider.of<DocumentsCubit>(context), value: context.read<DocumentsCubit>(),
child: FractionallySizedBox( child: FractionallySizedBox(
heightFactor: .6, heightFactor: .6,
child: MultiBlocProvider( child: MultiBlocProvider(
providers: [ providers: [
BlocProvider( BlocProvider(
create: (context) => LabelCubit<DocumentType>( create: (context) => LabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context), context.read<LabelRepository<DocumentType>>(),
), ),
), ),
BlocProvider( BlocProvider(
create: (context) => LabelCubit<Correspondent>( create: (context) => LabelCubit<Correspondent>(
RepositoryProvider.of<LabelRepository<Correspondent>>( context.read<LabelRepository<Correspondent>>(),
context),
), ),
), ),
], ],
@@ -52,13 +51,12 @@ class SortDocumentsButton extends StatelessWidget {
initialSortField: state.filter.sortField, initialSortField: state.filter.sortField,
initialSortOrder: state.filter.sortOrder, initialSortOrder: state.filter.sortOrder,
onSubmit: (field, order) => onSubmit: (field, order) =>
BlocProvider.of<DocumentsCubit>(context) context.read<DocumentsCubit>().updateCurrentFilter(
.updateCurrentFilter( (filter) => filter.copyWith(
(filter) => filter.copyWith( sortField: field,
sortField: field, sortOrder: order,
sortOrder: order, ),
), ),
),
); );
}, },
), ),

View File

@@ -24,7 +24,7 @@ class AddLabelPage<T extends Label> extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit( create: (context) => EditLabelCubit(
RepositoryProvider.of<LabelRepository<T>>(context), context.read<LabelRepository<T>>(),
), ),
child: AddLabelFormWidget( child: AddLabelFormWidget(
pageTitle: pageTitle, pageTitle: pageTitle,
@@ -62,7 +62,7 @@ class AddLabelFormWidget<T extends Label> extends StatelessWidget {
submitButtonConfig: SubmitButtonConfig<T>( submitButtonConfig: SubmitButtonConfig<T>(
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
label: Text(S.of(context).genericActionCreateLabel), label: Text(S.of(context).genericActionCreateLabel),
onSubmit: BlocProvider.of<EditLabelCubit<T>>(context).create, onSubmit: context.read<EditLabelCubit<T>>().create,
), ),
additionalFields: additionalFields, additionalFields: additionalFields,
), ),

View File

@@ -22,7 +22,7 @@ class EditLabelPage<T extends Label> extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit( create: (context) => EditLabelCubit(
RepositoryProvider.of<LabelRepository<T>>(context), context.read<LabelRepository<T>>(),
), ),
child: EditLabelForm( child: EditLabelForm(
label: label, label: label,
@@ -63,7 +63,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
submitButtonConfig: SubmitButtonConfig<T>( submitButtonConfig: SubmitButtonConfig<T>(
icon: const Icon(Icons.update), icon: const Icon(Icons.update),
label: Text(S.of(context).genericActionUpdateLabel), label: Text(S.of(context).genericActionUpdateLabel),
onSubmit: BlocProvider.of<EditLabelCubit<T>>(context).update, onSubmit: context.read<EditLabelCubit<T>>().update,
), ),
additionalFields: additionalFields, additionalFields: additionalFields,
), ),
@@ -99,11 +99,11 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
) ?? ) ??
false; false;
if (shouldDelete) { if (shouldDelete) {
BlocProvider.of<EditLabelCubit<T>>(context).delete(label); context.read<EditLabelCubit<T>>().delete(label);
Navigator.pop(context); Navigator.pop(context);
} }
} else { } else {
BlocProvider.of<EditLabelCubit<T>>(context).delete(label); context.read<EditLabelCubit<T>>().delete(label);
Navigator.pop(context); Navigator.pop(context);
} }
} }

View File

@@ -14,7 +14,7 @@ class AddCorrespondentPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<Correspondent>( create: (context) => EditLabelCubit<Correspondent>(
RepositoryProvider.of<LabelRepository<Correspondent>>(context), context.read<LabelRepository<Correspondent>>(),
), ),
child: AddLabelPage<Correspondent>( child: AddLabelPage<Correspondent>(
pageTitle: Text(S.of(context).addCorrespondentPageTitle), pageTitle: Text(S.of(context).addCorrespondentPageTitle),

View File

@@ -17,7 +17,7 @@ class AddDocumentTypePage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<DocumentType>( create: (context) => EditLabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context), context.read<LabelRepository<DocumentType>>(),
), ),
child: AddLabelPage<DocumentType>( child: AddLabelPage<DocumentType>(
pageTitle: Text(S.of(context).addDocumentTypePageTitle), pageTitle: Text(S.of(context).addDocumentTypePageTitle),

View File

@@ -15,7 +15,7 @@ class AddStoragePathPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<StoragePath>( create: (context) => EditLabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context), context.read<LabelRepository<StoragePath>>(),
), ),
child: AddLabelPage<StoragePath>( child: AddLabelPage<StoragePath>(
pageTitle: Text(S.of(context).addStoragePathPageTitle), pageTitle: Text(S.of(context).addStoragePathPageTitle),

View File

@@ -18,7 +18,7 @@ class AddTagPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<Tag>( create: (context) => EditLabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context), context.read<LabelRepository<Tag>>(),
), ),
child: AddLabelPage<Tag>( child: AddLabelPage<Tag>(
pageTitle: Text(S.of(context).addTagPageTitle), pageTitle: Text(S.of(context).addTagPageTitle),

View File

@@ -14,7 +14,7 @@ class EditCorrespondentPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<Correspondent>( create: (context) => EditLabelCubit<Correspondent>(
RepositoryProvider.of<LabelRepository<Correspondent>>(context), context.read<LabelRepository<Correspondent>>(),
), ),
child: EditLabelPage<Correspondent>( child: EditLabelPage<Correspondent>(
label: correspondent, label: correspondent,

View File

@@ -13,7 +13,7 @@ class EditDocumentTypePage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<DocumentType>( create: (context) => EditLabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context), context.read<LabelRepository<DocumentType>>(),
), ),
child: EditLabelPage<DocumentType>( child: EditLabelPage<DocumentType>(
label: documentType, label: documentType,

View File

@@ -14,7 +14,7 @@ class EditStoragePathPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<StoragePath>( create: (context) => EditLabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context), context.read<LabelRepository<StoragePath>>(),
), ),
child: EditLabelPage<StoragePath>( child: EditLabelPage<StoragePath>(
label: storagePath, label: storagePath,

View File

@@ -17,7 +17,7 @@ class EditTagPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => EditLabelCubit<Tag>( create: (context) => EditLabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context), context.read<LabelRepository<Tag>>(),
), ),
child: EditLabelPage<Tag>( child: EditLabelPage<Tag>(
label: tag, label: tag,

View File

@@ -55,13 +55,14 @@ class _HomePageState extends State<HomePage> {
body: [ body: [
MultiBlocProvider( MultiBlocProvider(
providers: [ providers: [
BlocProvider.value( BlocProvider(
value: create: (context) => DocumentsCubit(
DocumentsCubit(Provider.of<PaperlessDocumentsApi>(context)), context.read<PaperlessDocumentsApi>(),
),
), ),
BlocProvider( BlocProvider(
create: (context) => SavedViewCubit( create: (context) => SavedViewCubit(
RepositoryProvider.of<SavedViewRepository>(context), context.read<SavedViewRepository>(),
), ),
), ),
], ],
@@ -71,12 +72,7 @@ class _HomePageState extends State<HomePage> {
value: _scannerCubit, value: _scannerCubit,
child: const ScannerPage(), child: const ScannerPage(),
), ),
BlocProvider( const LabelsPage(),
create: (context) => DocumentsCubit(
Provider.of<PaperlessDocumentsApi>(context),
),
child: const LabelsPage(),
),
][_currentIndex], ][_currentIndex],
), ),
); );

View File

@@ -155,9 +155,8 @@ class _InfoDrawerState extends State<InfoDrawer> {
), ),
onTap: () => Navigator.of(context).push( onTap: () => Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BlocProvider( builder: (context) => BlocProvider.value(
create: (context) => value: context.read<ApplicationSettingsCubit>(),
Provider.of<ApplicationSettingsCubit>(context),
child: const SettingsPage(), child: const SettingsPage(),
), ),
), ),
@@ -214,20 +213,14 @@ class _InfoDrawerState extends State<InfoDrawer> {
title: Text(S.of(context).appDrawerLogoutLabel), title: Text(S.of(context).appDrawerLogoutLabel),
onTap: () { onTap: () {
try { try {
BlocProvider.of<AuthenticationCubit>(context).logout(); context.read<AuthenticationCubit>().logout();
Provider.of<LocalVault>(context).clear(); context.read<LocalVault>().clear();
BlocProvider.of<ApplicationSettingsCubit>(context).clear(); context.read<ApplicationSettingsCubit>().clear();
RepositoryProvider.of<LabelRepository<Tag>>(context) context.read<LabelRepository<Tag>>().clear();
.clear(); context.read<LabelRepository<Correspondent>>().clear();
RepositoryProvider.of<LabelRepository<Correspondent>>( context.read<LabelRepository<DocumentType>>().clear();
context) context.read<LabelRepository<StoragePath>>().clear();
.clear(); context.read<SavedViewRepository>().clear();
RepositoryProvider.of<LabelRepository<DocumentType>>(
context)
.clear();
RepositoryProvider.of<LabelRepository<StoragePath>>(context)
.clear();
RepositoryProvider.of<SavedViewRepository>(context).clear();
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
@@ -246,8 +239,8 @@ class _InfoDrawerState extends State<InfoDrawer> {
builder: (_) => LabelRepositoriesProvider( builder: (_) => LabelRepositoriesProvider(
child: BlocProvider( child: BlocProvider(
create: (context) => InboxCubit( create: (context) => InboxCubit(
RepositoryProvider.of<LabelRepository<Tag>>(context), context.read<LabelRepository<Tag>>(),
Provider.of<PaperlessDocumentsApi>(context), context.read<PaperlessDocumentsApi>(),
)..loadInbox(), )..loadInbox(),
child: const InboxPage(), child: const InboxPage(),
), ),

View File

@@ -125,7 +125,7 @@ class _InboxPageState extends State<InboxPage> {
.toList(); .toList();
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => BlocProvider.of<InboxCubit>(context).loadInbox(), onRefresh: () => context.read<InboxCubit>().loadInbox(),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
@@ -205,14 +205,13 @@ class _InboxPageState extends State<InboxPage> {
) ?? ) ??
false; false;
if (isActionConfirmed) { if (isActionConfirmed) {
await BlocProvider.of<InboxCubit>(context).clearInbox(); await context.read<InboxCubit>().clearInbox();
} }
} }
Future<bool> _onItemDismissed(DocumentModel doc) async { Future<bool> _onItemDismissed(DocumentModel doc) async {
try { try {
final removedTags = final removedTags = await context.read<InboxCubit>().remove(doc);
await BlocProvider.of<InboxCubit>(context).remove(doc);
showSnackBar( showSnackBar(
context, context,
S.of(context).inboxPageDocumentRemovedMessageText, S.of(context).inboxPageDocumentRemovedMessageText,
@@ -239,8 +238,7 @@ class _InboxPageState extends State<InboxPage> {
Iterable<int> removedTags, Iterable<int> removedTags,
) async { ) async {
try { try {
await BlocProvider.of<InboxCubit>(context) await context.read<InboxCubit>().undoRemove(document, removedTags);
.undoRemove(document, removedTags);
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }

View File

@@ -16,7 +16,7 @@ class InboxEmptyWidget extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return RefreshIndicator( return RefreshIndicator(
key: _emptyStateRefreshIndicatorKey, key: _emptyStateRefreshIndicatorKey,
onRefresh: () => BlocProvider.of<InboxCubit>(context).loadInbox(), onRefresh: () => context.read<InboxCubit>().loadInbox(),
child: Center( child: Center(
child: Column( child: Column(
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,

View File

@@ -48,9 +48,9 @@ class InboxItem extends StatelessWidget {
onTap: () => Navigator.push( onTap: () => Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => BlocProvider( builder: (context) => BlocProvider(
create: (context) => DocumentDetailsCubit( create: (context) => DocumentDetailsCubit(
Provider.of<PaperlessDocumentsApi>(context), context.read<PaperlessDocumentsApi>(),
document, document,
), ),
child: const LabelRepositoriesProvider( child: const LabelRepositoriesProvider(

View File

@@ -12,7 +12,7 @@ class CorrespondentBlocProvider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => LabelCubit<Correspondent>( create: (context) => LabelCubit<Correspondent>(
RepositoryProvider.of<LabelRepository<Correspondent>>(context), context.read<LabelRepository<Correspondent>>(),
), ),
child: child, child: child,
); );

View File

@@ -12,7 +12,7 @@ class DocumentTypeBlocProvider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => LabelCubit<DocumentType>( create: (context) => LabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context), context.read<LabelRepository<DocumentType>>(),
), ),
child: child, child: child,
); );

View File

@@ -14,22 +14,22 @@ class LabelsBlocProvider extends StatelessWidget {
providers: [ providers: [
BlocProvider<LabelCubit<StoragePath>>( BlocProvider<LabelCubit<StoragePath>>(
create: (context) => LabelCubit<StoragePath>( create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context), context.read<LabelRepository<StoragePath>>(),
), ),
), ),
BlocProvider<LabelCubit<Correspondent>>( BlocProvider<LabelCubit<Correspondent>>(
create: (context) => LabelCubit<Correspondent>( create: (context) => LabelCubit<Correspondent>(
RepositoryProvider.of<LabelRepository<Correspondent>>(context), context.read<LabelRepository<Correspondent>>(),
), ),
), ),
BlocProvider<LabelCubit<DocumentType>>( BlocProvider<LabelCubit<DocumentType>>(
create: (context) => LabelCubit<DocumentType>( create: (context) => LabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context), context.read<LabelRepository<DocumentType>>(),
), ),
), ),
BlocProvider<LabelCubit<Tag>>( BlocProvider<LabelCubit<Tag>>(
create: (context) => LabelCubit<Tag>( create: (context) => LabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context), context.read<LabelRepository<Tag>>(),
), ),
), ),
], ],

View File

@@ -12,7 +12,7 @@ class StoragePathBlocProvider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => LabelCubit<StoragePath>( create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context), context.read<LabelRepository<StoragePath>>(),
), ),
child: child, child: child,
); );

View File

@@ -12,7 +12,7 @@ class TagBlocProvider extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => LabelCubit<Tag>( create: (context) => LabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context), context.read<LabelRepository<Tag>>(),
), ),
child: child, child: child,
); );

View File

@@ -4,6 +4,7 @@ import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.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_cubit.dart';
import 'package:paperless_mobile/features/labels/bloc/label_state.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 { class DocumentTypeWidget extends StatelessWidget {
final int? documentTypeId; final int? documentTypeId;
@@ -20,10 +21,7 @@ class DocumentTypeWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return DocumentTypeBlocProvider(
create: (context) => LabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context),
),
child: AbsorbPointer( child: AbsorbPointer(
absorbing: !isClickable, absorbing: !isClickable,
child: GestureDetector( child: GestureDetector(

View File

@@ -4,6 +4,7 @@ import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/label_repository.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_cubit.dart';
import 'package:paperless_mobile/features/labels/bloc/label_state.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 { class StoragePathWidget extends StatelessWidget {
final int? pathId; final int? pathId;
@@ -21,10 +22,7 @@ class StoragePathWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return StoragePathBlocProvider(
create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
),
child: AbsorbPointer( child: AbsorbPointer(
absorbing: !isClickable, absorbing: !isClickable,
child: BlocBuilder<LabelCubit<StoragePath>, LabelState<StoragePath>>( child: BlocBuilder<LabelCubit<StoragePath>, LabelState<StoragePath>>(

View File

@@ -218,8 +218,8 @@ class _TagFormFieldState extends State<TagFormField> {
void _onAddTag(BuildContext context, FormFieldState<TagsQuery> field) async { void _onAddTag(BuildContext context, FormFieldState<TagsQuery> field) async {
final Tag? tag = await Navigator.of(context).push<Tag>( final Tag? tag = await Navigator.of(context).push<Tag>(
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<Tag>>(context), create: (context) => context.read<LabelRepository<Tag>>(),
child: AddTagPage(initialValue: _textEditingController.text), child: AddTagPage(initialValue: _textEditingController.text),
), ),
), ),

View File

@@ -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/edit_label/view/impl/edit_tag_page.dart';
import 'package:paperless_mobile/features/home/view/widget/info_drawer.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/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/features/labels/view/widgets/label_tab_view.dart';
import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/generated/l10n.dart';
@@ -119,11 +123,7 @@ class _LabelsPageState extends State<LabelsPage>
body: TabBarView( body: TabBarView(
controller: _tabController, controller: _tabController,
children: [ children: [
BlocProvider( CorrespondentBlocProvider(
create: (context) => LabelCubit(
RepositoryProvider.of<LabelRepository<Correspondent>>(
context),
),
child: LabelTabView<Correspondent>( child: LabelTabView<Correspondent>(
filterBuilder: (label) => DocumentFilter( filterBuilder: (label) => DocumentFilter(
correspondent: IdQueryParameter.fromId(label.id), correspondent: IdQueryParameter.fromId(label.id),
@@ -139,11 +139,7 @@ class _LabelsPageState extends State<LabelsPage>
onAddNew: _openAddCorrespondentPage, onAddNew: _openAddCorrespondentPage,
), ),
), ),
BlocProvider( DocumentTypeBlocProvider(
create: (context) => LabelCubit(
RepositoryProvider.of<LabelRepository<DocumentType>>(
context),
),
child: LabelTabView<DocumentType>( child: LabelTabView<DocumentType>(
filterBuilder: (label) => DocumentFilter( filterBuilder: (label) => DocumentFilter(
documentType: IdQueryParameter.fromId(label.id), documentType: IdQueryParameter.fromId(label.id),
@@ -159,10 +155,7 @@ class _LabelsPageState extends State<LabelsPage>
onAddNew: _openAddDocumentTypePage, onAddNew: _openAddDocumentTypePage,
), ),
), ),
BlocProvider( TagBlocProvider(
create: (context) => LabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context),
),
child: LabelTabView<Tag>( child: LabelTabView<Tag>(
filterBuilder: (label) => DocumentFilter( filterBuilder: (label) => DocumentFilter(
tags: IdsTagsQuery.fromIds([label.id!]), tags: IdsTagsQuery.fromIds([label.id!]),
@@ -186,11 +179,7 @@ class _LabelsPageState extends State<LabelsPage>
onAddNew: _openAddTagPage, onAddNew: _openAddTagPage,
), ),
), ),
BlocProvider( StoragePathBlocProvider(
create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(
context),
),
child: LabelTabView<StoragePath>( child: LabelTabView<StoragePath>(
onEdit: _openEditStoragePathPage, onEdit: _openEditStoragePathPage,
filterBuilder: (label) => DocumentFilter( filterBuilder: (label) => DocumentFilter(
@@ -219,8 +208,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<Correspondent>>(context), create: (context) => context.read<LabelRepository<Correspondent>>(),
child: EditCorrespondentPage(correspondent: correspondent), child: EditCorrespondentPage(correspondent: correspondent),
), ),
), ),
@@ -231,8 +220,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<DocumentType>>(context), create: (context) => context.read<LabelRepository<DocumentType>>(),
child: EditDocumentTypePage(documentType: docType), child: EditDocumentTypePage(documentType: docType),
), ),
), ),
@@ -243,8 +232,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<Tag>>(context), create: (context) => context.read<LabelRepository<Tag>>(),
child: EditTagPage(tag: tag), child: EditTagPage(tag: tag),
), ),
), ),
@@ -255,8 +244,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<StoragePath>>(context), create: (context) => context.read<LabelRepository<StoragePath>>(),
child: EditStoragePathPage( child: EditStoragePathPage(
storagePath: path, storagePath: path,
), ),
@@ -269,8 +258,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<Correspondent>>(context), create: (context) => context.read<LabelRepository<Correspondent>>(),
child: const AddCorrespondentPage(), child: const AddCorrespondentPage(),
), ),
), ),
@@ -281,8 +270,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<DocumentType>>(context), create: (context) => context.read<LabelRepository<DocumentType>>(),
child: const AddDocumentTypePage(), child: const AddDocumentTypePage(),
), ),
), ),
@@ -293,8 +282,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<Tag>>(context), create: (context) => context.read<LabelRepository<Tag>>(),
child: const AddTagPage(), child: const AddTagPage(),
), ),
), ),
@@ -305,8 +294,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => RepositoryProvider.value( builder: (_) => RepositoryProvider(
value: RepositoryProvider.of<LabelRepository<StoragePath>>(context), create: (context) => context.read<LabelRepository<StoragePath>>(),
child: const AddStoragePathPage(), child: const AddStoragePathPage(),
), ),
), ),

View File

@@ -47,7 +47,7 @@ class LabelItem<T extends Label> extends StatelessWidget {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BlocProvider( builder: (context) => BlocProvider(
create: (context) => LinkedDocumentsCubit( create: (context) => LinkedDocumentsCubit(
Provider.of<PaperlessDocumentsApi>(context), context.read<PaperlessDocumentsApi>(),
filter, filter,
), ),
child: const LinkedDocumentsPage(), child: const LinkedDocumentsPage(),

View File

@@ -63,7 +63,7 @@ class LabelTabView<T extends Label> extends StatelessWidget {
); );
} }
return RefreshIndicator( return RefreshIndicator(
onRefresh: BlocProvider.of<LabelCubit<T>>(context).reload, onRefresh: context.read<LabelCubit<T>>().reload,
child: ListView( child: ListView(
children: labels children: labels
.map( .map(

View File

@@ -65,8 +65,7 @@ class _LinkedDocumentsPageState extends State<LinkedDocumentsPage> {
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BlocProvider( builder: (context) => BlocProvider(
create: (context) => DocumentDetailsCubit( create: (context) => DocumentDetailsCubit(
Provider.of<PaperlessDocumentsApi>( context.read<PaperlessDocumentsApi>(),
context),
document, document,
), ),
child: const DocumentDetailsPage( child: const DocumentDetailsPage(

View File

@@ -1,9 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:paperless_api/paperless_api.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/core/store/local_vault.dart';
import 'package:paperless_mobile/features/login/bloc/authentication_state.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/model/authentication_information.dart';
@@ -16,7 +15,7 @@ class AuthenticationCubit extends HydratedCubit<AuthenticationState> {
final LocalAuthenticationService _localAuthService; final LocalAuthenticationService _localAuthService;
final PaperlessAuthenticationApi _authApi; final PaperlessAuthenticationApi _authApi;
final LocalVault _localVault; final LocalVault _localVault;
final SecurityContextAwareDioManager _dioWrapper; final AuthenticationAwareDioManager _dioWrapper;
AuthenticationCubit( AuthenticationCubit(
this._localVault, this._localVault,

View File

@@ -20,7 +20,7 @@ class AuthenticationState {
required this.wasLoginStored, required this.wasLoginStored,
this.wasLocalAuthenticationSuccessful, this.wasLocalAuthenticationSuccessful,
this.authentication, this.authentication,
}); }) : assert(!isAuthenticated || authentication != null);
AuthenticationState copyWith({ AuthenticationState copyWith({
bool? wasLoginStored, bool? wasLoginStored,

View File

@@ -92,12 +92,12 @@ class _LoginPageState extends State<LoginPage> {
setState(() => _isLoginLoading = true); setState(() => _isLoginLoading = true);
final form = _formKey.currentState!.value; final form = _formKey.currentState!.value;
try { try {
await BlocProvider.of<AuthenticationCubit>(context).login( await context.read<AuthenticationCubit>().login(
credentials: form[UserCredentialsFormField.fkCredentials], credentials: form[UserCredentialsFormField.fkCredentials],
serverUrl: form[ServerAddressFormField.fkServerAddress], serverUrl: form[ServerAddressFormField.fkServerAddress],
clientCertificate: clientCertificate:
form[ClientCertificateFormField.fkClientCertificate], form[ClientCertificateFormField.fkClientCertificate],
); );
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} on Map<String, dynamic> catch (error, stackTrace) { } on Map<String, dynamic> catch (error, stackTrace) {

View File

@@ -63,9 +63,9 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
} }
//https://stackoverflow.com/questions/49648022/check-whether-there-is-an-internet-connection-available-on-flutter-app //https://stackoverflow.com/questions/49648022/check-whether-there-is-an-internet-connection-available-on-flutter-app
setState(() => _reachabilityStatus = ReachabilityStatus.testing); setState(() => _reachabilityStatus = ReachabilityStatus.testing);
final isReachable = final isReachable = await context
await Provider.of<ConnectivityStatusService>(context, listen: false) .read<ConnectivityStatusService>()
.isServerReachable(address); .isServerReachable(address);
if (isReachable) { if (isReachable) {
setState(() => _reachabilityStatus = ReachabilityStatus.reachable); setState(() => _reachabilityStatus = ReachabilityStatus.reachable);
} else { } else {

View File

@@ -129,7 +129,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
); );
if (newView != null) { if (newView != null) {
try { try {
await BlocProvider.of<SavedViewCubit>(context).add(newView); await context.read<SavedViewCubit>().add(newView);
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
@@ -139,9 +139,9 @@ class SavedViewSelectionWidget extends StatelessWidget {
void _onSelected( void _onSelected(
bool isSelected, BuildContext context, SavedView view) async { bool isSelected, BuildContext context, SavedView view) async {
if (isSelected) { if (isSelected) {
BlocProvider.of<SavedViewCubit>(context).selectView(view); context.read<SavedViewCubit>().selectView(view);
} else { } else {
BlocProvider.of<SavedViewCubit>(context).selectView(null); context.read<SavedViewCubit>().selectView(null);
} }
} }
@@ -154,7 +154,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
false; false;
if (delete) { if (delete) {
try { try {
BlocProvider.of<SavedViewCubit>(context).remove(view); context.read<SavedViewCubit>().remove(view);
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }

View File

@@ -126,12 +126,12 @@ class _ScannerPageState extends State<ScannerPage>
if (kDebugMode) { if (kDebugMode) {
dev.log('[ScannerPage] Wrote image to temporary file: ${file.path}'); dev.log('[ScannerPage] Wrote image to temporary file: ${file.path}');
} }
BlocProvider.of<DocumentScannerCubit>(context).addScan(file); context.read<DocumentScannerCubit>().addScan(file);
} }
void _onPrepareDocumentUpload(BuildContext context) async { void _onPrepareDocumentUpload(BuildContext context) async {
final doc = _buildDocumentFromImageFiles( final doc = _buildDocumentFromImageFiles(
BlocProvider.of<DocumentScannerCubit>(context).state, context.read<DocumentScannerCubit>().state,
); );
final bytes = await doc.save(); final bytes = await doc.save();
final uploaded = await Navigator.of(context).push( final uploaded = await Navigator.of(context).push(
@@ -139,19 +139,13 @@ class _ScannerPageState extends State<ScannerPage>
builder: (_) => LabelRepositoriesProvider( builder: (_) => LabelRepositoriesProvider(
child: BlocProvider( child: BlocProvider(
create: (context) => DocumentUploadCubit( create: (context) => DocumentUploadCubit(
localVault: Provider.of<LocalVault>(context), localVault: context.read<LocalVault>(),
documentApi: Provider.of<PaperlessDocumentsApi>(context), documentApi: context.read<PaperlessDocumentsApi>(),
correspondentRepository: correspondentRepository:
RepositoryProvider.of<LabelRepository<Correspondent>>( context.read<LabelRepository<Correspondent>>(),
context,
),
documentTypeRepository: documentTypeRepository:
RepositoryProvider.of<LabelRepository<DocumentType>>( context.read<LabelRepository<DocumentType>>(),
context, tagRepository: context.read<LabelRepository<Tag>>(),
),
tagRepository: RepositoryProvider.of<LabelRepository<Tag>>(
context,
),
), ),
child: DocumentUploadPreparationPage( child: DocumentUploadPreparationPage(
fileBytes: bytes, fileBytes: bytes,
@@ -162,7 +156,7 @@ class _ScannerPageState extends State<ScannerPage>
) ?? ) ??
false; false;
if (uploaded) { if (uploaded) {
BlocProvider.of<DocumentScannerCubit>(context).reset(); context.read<DocumentScannerCubit>().reset();
} }
} }
@@ -216,8 +210,7 @@ class _ScannerPageState extends State<ScannerPage>
file: scans[index], file: scans[index],
onDelete: () async { onDelete: () async {
try { try {
BlocProvider.of<DocumentScannerCubit>(context) context.read<DocumentScannerCubit>().removeScan(index);
.removeScan(index);
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
@@ -230,7 +223,7 @@ class _ScannerPageState extends State<ScannerPage>
void _reset(BuildContext context) { void _reset(BuildContext context) {
try { try {
BlocProvider.of<DocumentScannerCubit>(context).reset(); context.read<DocumentScannerCubit>().reset();
} on PaperlessServerException catch (error, stackTrace) { } on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace); showErrorMessage(context, error, stackTrace);
} }
@@ -274,19 +267,13 @@ class _ScannerPageState extends State<ScannerPage>
builder: (_) => LabelRepositoriesProvider( builder: (_) => LabelRepositoriesProvider(
child: BlocProvider( child: BlocProvider(
create: (context) => DocumentUploadCubit( create: (context) => DocumentUploadCubit(
localVault: Provider.of<LocalVault>(context), localVault: context.read<LocalVault>(),
documentApi: Provider.of<PaperlessDocumentsApi>(context), documentApi: context.read<PaperlessDocumentsApi>(),
correspondentRepository: correspondentRepository:
RepositoryProvider.of<LabelRepository<Correspondent>>( context.read<LabelRepository<Correspondent>>(),
context,
),
documentTypeRepository: documentTypeRepository:
RepositoryProvider.of<LabelRepository<DocumentType>>( context.read<LabelRepository<DocumentType>>(),
context, tagRepository: context.read<LabelRepository<Tag>>(),
),
tagRepository: RepositoryProvider.of<LabelRepository<Tag>>(
context,
),
), ),
child: DocumentUploadPreparationPage( child: DocumentUploadPreparationPage(
fileBytes: fileBytes, fileBytes: fileBytes,

View File

@@ -44,9 +44,10 @@ class SettingsPage extends StatelessWidget {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (ctxt) => BlocProvider.value( builder: (context) => BlocProvider.value(
value: BlocProvider.of<ApplicationSettingsCubit>(context), value: context.read<ApplicationSettingsCubit>(),
child: page), child: page,
),
maintainState: true, maintainState: true,
), ),
); );

View File

@@ -19,8 +19,7 @@ class BiometricAuthenticationSetting extends StatelessWidget {
subtitle: Text( subtitle: Text(
S.of(context).appSettingsBiometricAuthenticationDescriptionText), S.of(context).appSettingsBiometricAuthenticationDescriptionText),
onChanged: (val) async { onChanged: (val) async {
final settingsBloc = final settingsBloc = context.read<ApplicationSettingsCubit>();
BlocProvider.of<ApplicationSettingsCubit>(context);
final String localizedReason = val final String localizedReason = val
? S ? S
.of(context) .of(context)
@@ -28,9 +27,9 @@ class BiometricAuthenticationSetting extends StatelessWidget {
: S : S
.of(context) .of(context)
.appSettingsDisableBiometricAuthenticationReasonText; .appSettingsDisableBiometricAuthenticationReasonText;
final changeValue = final changeValue = await context
await Provider.of<LocalAuthenticationService>(context) .read<LocalAuthenticationService>()
.authenticateLocalUser(localizedReason); .authenticateLocalUser(localizedReason);
if (changeValue) { if (changeValue) {
settingsBloc.setIsBiometricAuthenticationEnabled(val); settingsBloc.setIsBiometricAuthenticationEnabled(val);
} }

View File

@@ -13,7 +13,7 @@ class ClearStorageSetting extends StatelessWidget {
subtitle: subtitle:
Text("Remove downloaded files, scans and clear the cache's content"), Text("Remove downloaded files, scans and clear the cache's content"),
onTap: () { onTap: () {
Provider.of<cm.CacheManager>(context).emptyCache(); context.read<cm.CacheManager>().emptyCache();
FileService.clearUserData(); FileService.clearUserData();
}, },
); );

View File

@@ -44,12 +44,13 @@ class _LanguageSelectionSettingState extends State<LanguageSelectionSetting> {
label: _languageOptions['cs']!, label: _languageOptions['cs']!,
) )
], ],
initialValue: BlocProvider.of<ApplicationSettingsCubit>(context) initialValue: context
.read<ApplicationSettingsCubit>()
.state .state
.preferredLocaleSubtag, .preferredLocaleSubtag,
), ),
).then((value) => BlocProvider.of<ApplicationSettingsCubit>(context) ).then((value) =>
.setLocale(value)), context.read<ApplicationSettingsCubit>().setLocale(value)),
); );
}, },
); );

View File

@@ -38,14 +38,14 @@ class ThemeModeSetting extends StatelessWidget {
S.of(context).settingsPageAppearanceSettingDarkThemeLabel, S.of(context).settingsPageAppearanceSettingDarkThemeLabel,
) )
], ],
initialValue: BlocProvider.of<ApplicationSettingsCubit>(context) initialValue: context
.read<ApplicationSettingsCubit>()
.state .state
.preferredThemeMode, .preferredThemeMode,
title: Text(S.of(context).settingsPageAppearanceSettingTitle), title: Text(S.of(context).settingsPageAppearanceSettingTitle),
), ),
).then((value) { ).then((value) {
return BlocProvider.of<ApplicationSettingsCubit>(context) return context.read<ApplicationSettingsCubit>().setThemeMode(value);
.setThemeMode(value);
}), }),
); );
}, },

View File

@@ -10,19 +10,20 @@ import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:form_builder_validators/form_builder_validators.dart'; import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:http/http.dart';
import 'package:http/io_client.dart'; import 'package:http/io_client.dart';
import 'package:http_interceptor/http/intercepted_client.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/date_symbol_data_local.dart';
import 'package:intl/intl_standalone.dart'; import 'package:intl/intl_standalone.dart';
import 'package:local_auth/local_auth.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_api/paperless_api.dart';
import 'package:paperless_mobile/core/bloc/bloc_changes_observer.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/connectivity_cubit.dart';
import 'package:paperless_mobile/core/bloc/paperless_server_information_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/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/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/correspondent_repository_impl.dart';
import 'package:paperless_mobile/core/repository/impl/document_type_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'; 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/impl/tag_repository_impl.dart';
import 'package:paperless_mobile/core/repository/label_repository.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/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/connectivity_status.service.dart';
import 'package:paperless_mobile/core/service/file_service.dart'; import 'package:paperless_mobile/core/service/file_service.dart';
import 'package:paperless_mobile/core/store/local_vault.dart'; import 'package:paperless_mobile/core/store/local_vault.dart';
import 'package:paperless_mobile/extensions/flutter_extensions.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/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/cubit/document_upload_cubit.dart';
import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.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/home/view/home_page.dart';
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.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/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/services/authentication_service.dart';
import 'package:paperless_mobile/features/login/view/login_page.dart'; import 'package:paperless_mobile/features/login/view/login_page.dart';
import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart'; import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart';
@@ -62,18 +65,12 @@ void main() async {
await findSystemLocale(); await findSystemLocale();
// Required for self signed client certificates // Required for self signed client certificates
final dioWrapper = SecurityContextAwareDioManager(); final dioWrapper = AuthenticationAwareDioManager();
IOClient httpClient = IOClient();
dioWrapper.securityContextChanges.listen(
(context) => httpClient = IOClient(HttpClient(context: context)),
);
// Initialize External dependencies // Initialize External dependencies
final connectivity = Connectivity(); final connectivity = Connectivity();
final encryptedSharedPreferences = EncryptedSharedPreferences(); final encryptedSharedPreferences = EncryptedSharedPreferences();
final localAuthentication = LocalAuthentication(); final localAuthentication = LocalAuthentication();
final cacheManager = cm.CacheManager(cm.Config('cacheKey',
fileService: cm.HttpFileService(httpClient: httpClient)));
// Initialize Paperless APIs // Initialize Paperless APIs
final authApi = PaperlessAuthenticationApiImpl(dioWrapper.client); final authApi = PaperlessAuthenticationApiImpl(dioWrapper.client);
@@ -104,8 +101,35 @@ void main() async {
authApi, authApi,
dioWrapper, 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 // Create repositories
final tagRepository = TagRepositoryImpl(labelsApi); final tagRepository = TagRepositoryImpl(labelsApi);
@@ -122,7 +146,47 @@ void main() async {
Provider<PaperlessLabelsApi>.value(value: labelsApi), Provider<PaperlessLabelsApi>.value(value: labelsApi),
Provider<PaperlessServerStatsApi>.value(value: statsApi), Provider<PaperlessServerStatsApi>.value(value: statsApi),
Provider<PaperlessSavedViewsApi>.value(value: savedViewsApi), Provider<PaperlessSavedViewsApi>.value(value: savedViewsApi),
Provider<cm.CacheManager>.value(value: cacheManager), ProxyProvider<SecurityContext, cm.CacheManager>(
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<LocalVault>.value(value: localVault), Provider<LocalVault>.value(value: localVault),
Provider<ConnectivityStatusService>.value( Provider<ConnectivityStatusService>.value(
value: connectivityStatusService, value: connectivityStatusService,
@@ -148,17 +212,8 @@ void main() async {
], ],
child: MultiBlocProvider( child: MultiBlocProvider(
providers: [ providers: [
BlocProvider( BlocProvider<AuthenticationCubit>.value(value: authCubit),
create: (context) => AuthenticationCubit( BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
localVault,
localAuthService,
authApi,
dioWrapper,
),
),
BlocProvider<ConnectivityCubit>.value(
value: connectivityCubit,
),
], ],
child: const PaperlessMobileEntrypoint(), child: const PaperlessMobileEntrypoint(),
), ),
@@ -225,10 +280,7 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [
BlocProvider( BlocProvider(
create: (context) => ConnectivityCubit(context.watch()), create: (context) => PaperlessServerInformationCubit(context.read()),
),
BlocProvider(
create: (context) => PaperlessServerInformationCubit(context.watch()),
), ),
BlocProvider( BlocProvider(
create: (context) => ApplicationSettingsCubit(), create: (context) => ApplicationSettingsCubit(),
@@ -313,13 +365,13 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
final success = await Navigator.push( final success = await Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => BlocProvider( builder: (context) => BlocProvider.value(
create: (BuildContext context) => DocumentUploadCubit( value: DocumentUploadCubit(
localVault: context.watch(), localVault: context.read(),
documentApi: context.watch(), documentApi: context.read(),
tagRepository: context.watch(), tagRepository: context.read(),
correspondentRepository: context.watch(), correspondentRepository: context.read(),
documentTypeRepository: context.watch(), documentTypeRepository: context.read(),
), ),
child: DocumentUploadPreparationPage( child: DocumentUploadPreparationPage(
fileBytes: bytes, fileBytes: bytes,