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:paperless_mobile/core/service/connectivity_status.service.dart';
import 'package:injectable/injectable.dart';
@prod
@test
@lazySingleton
class ConnectivityCubit extends Cubit<ConnectivityState> {
final ConnectivityStatusService connectivityStatusService;
StreamSubscription<bool>? _sub;

View File

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

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(
providers: [
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<Correspondent>>(context),
create: (context) => context.read<LabelRepository<Correspondent>>(),
),
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<DocumentType>>(context),
create: (context) => context.read<LabelRepository<DocumentType>>(),
),
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
create: (context) => context.read<LabelRepository<StoragePath>>(),
),
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<Tag>>(context),
create: (context) => context.read<LabelRepository<Tag>>(),
),
],
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>(
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<EditDocumentCubit, EditDocumentState>(
listenWhen: (previous, current) =>

View File

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

View File

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

View File

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

View File

@@ -30,15 +30,14 @@ class DocumentPreview extends StatelessWidget {
fit: fit,
alignment: Alignment.topCenter,
cacheKey: "thumb_$id",
imageUrl:
Provider.of<PaperlessDocumentsApi>(context).getThumbnailUrl(id),
imageUrl: context.read<PaperlessDocumentsApi>().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<CacheManager>(),
),
// ),
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -14,22 +14,22 @@ class LabelsBlocProvider extends StatelessWidget {
providers: [
BlocProvider<LabelCubit<StoragePath>>(
create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
context.read<LabelRepository<StoragePath>>(),
),
),
BlocProvider<LabelCubit<Correspondent>>(
create: (context) => LabelCubit<Correspondent>(
RepositoryProvider.of<LabelRepository<Correspondent>>(context),
context.read<LabelRepository<Correspondent>>(),
),
),
BlocProvider<LabelCubit<DocumentType>>(
create: (context) => LabelCubit<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context),
context.read<LabelRepository<DocumentType>>(),
),
),
BlocProvider<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) {
return BlocProvider(
create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
context.read<LabelRepository<StoragePath>>(),
),
child: child,
);

View File

@@ -12,7 +12,7 @@ class TagBlocProvider extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => LabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context),
context.read<LabelRepository<Tag>>(),
),
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/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<DocumentType>(
RepositoryProvider.of<LabelRepository<DocumentType>>(context),
),
return DocumentTypeBlocProvider(
child: AbsorbPointer(
absorbing: !isClickable,
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/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<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
),
return StoragePathBlocProvider(
child: AbsorbPointer(
absorbing: !isClickable,
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 {
final Tag? tag = await Navigator.of(context).push<Tag>(
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<Tag>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<Tag>>(),
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/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<LabelsPage>
body: TabBarView(
controller: _tabController,
children: [
BlocProvider(
create: (context) => LabelCubit(
RepositoryProvider.of<LabelRepository<Correspondent>>(
context),
),
CorrespondentBlocProvider(
child: LabelTabView<Correspondent>(
filterBuilder: (label) => DocumentFilter(
correspondent: IdQueryParameter.fromId(label.id),
@@ -139,11 +139,7 @@ class _LabelsPageState extends State<LabelsPage>
onAddNew: _openAddCorrespondentPage,
),
),
BlocProvider(
create: (context) => LabelCubit(
RepositoryProvider.of<LabelRepository<DocumentType>>(
context),
),
DocumentTypeBlocProvider(
child: LabelTabView<DocumentType>(
filterBuilder: (label) => DocumentFilter(
documentType: IdQueryParameter.fromId(label.id),
@@ -159,10 +155,7 @@ class _LabelsPageState extends State<LabelsPage>
onAddNew: _openAddDocumentTypePage,
),
),
BlocProvider(
create: (context) => LabelCubit<Tag>(
RepositoryProvider.of<LabelRepository<Tag>>(context),
),
TagBlocProvider(
child: LabelTabView<Tag>(
filterBuilder: (label) => DocumentFilter(
tags: IdsTagsQuery.fromIds([label.id!]),
@@ -186,11 +179,7 @@ class _LabelsPageState extends State<LabelsPage>
onAddNew: _openAddTagPage,
),
),
BlocProvider(
create: (context) => LabelCubit<StoragePath>(
RepositoryProvider.of<LabelRepository<StoragePath>>(
context),
),
StoragePathBlocProvider(
child: LabelTabView<StoragePath>(
onEdit: _openEditStoragePathPage,
filterBuilder: (label) => DocumentFilter(
@@ -219,8 +208,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<Correspondent>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<Correspondent>>(),
child: EditCorrespondentPage(correspondent: correspondent),
),
),
@@ -231,8 +220,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<DocumentType>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<DocumentType>>(),
child: EditDocumentTypePage(documentType: docType),
),
),
@@ -243,8 +232,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<Tag>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<Tag>>(),
child: EditTagPage(tag: tag),
),
),
@@ -255,8 +244,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<StoragePath>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<StoragePath>>(),
child: EditStoragePathPage(
storagePath: path,
),
@@ -269,8 +258,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<Correspondent>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<Correspondent>>(),
child: const AddCorrespondentPage(),
),
),
@@ -281,8 +270,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<DocumentType>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<DocumentType>>(),
child: const AddDocumentTypePage(),
),
),
@@ -293,8 +282,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<Tag>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<Tag>>(),
child: const AddTagPage(),
),
),
@@ -305,8 +294,8 @@ class _LabelsPageState extends State<LabelsPage>
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RepositoryProvider.value(
value: RepositoryProvider.of<LabelRepository<StoragePath>>(context),
builder: (_) => RepositoryProvider(
create: (context) => context.read<LabelRepository<StoragePath>>(),
child: const AddStoragePathPage(),
),
),

View File

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

View File

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

View File

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

View File

@@ -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<AuthenticationState> {
final LocalAuthenticationService _localAuthService;
final PaperlessAuthenticationApi _authApi;
final LocalVault _localVault;
final SecurityContextAwareDioManager _dioWrapper;
final AuthenticationAwareDioManager _dioWrapper;
AuthenticationCubit(
this._localVault,

View File

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

View File

@@ -92,7 +92,7 @@ class _LoginPageState extends State<LoginPage> {
setState(() => _isLoginLoading = true);
final form = _formKey.currentState!.value;
try {
await BlocProvider.of<AuthenticationCubit>(context).login(
await context.read<AuthenticationCubit>().login(
credentials: form[UserCredentialsFormField.fkCredentials],
serverUrl: form[ServerAddressFormField.fkServerAddress],
clientCertificate:

View File

@@ -63,8 +63,8 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
}
//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<ConnectivityStatusService>(context, listen: false)
final isReachable = await context
.read<ConnectivityStatusService>()
.isServerReachable(address);
if (isReachable) {
setState(() => _reachabilityStatus = ReachabilityStatus.reachable);

View File

@@ -129,7 +129,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
);
if (newView != null) {
try {
await BlocProvider.of<SavedViewCubit>(context).add(newView);
await context.read<SavedViewCubit>().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<SavedViewCubit>(context).selectView(view);
context.read<SavedViewCubit>().selectView(view);
} else {
BlocProvider.of<SavedViewCubit>(context).selectView(null);
context.read<SavedViewCubit>().selectView(null);
}
}
@@ -154,7 +154,7 @@ class SavedViewSelectionWidget extends StatelessWidget {
false;
if (delete) {
try {
BlocProvider.of<SavedViewCubit>(context).remove(view);
context.read<SavedViewCubit>().remove(view);
} on PaperlessServerException catch (error, stackTrace) {
showErrorMessage(context, error, stackTrace);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -38,14 +38,14 @@ class ThemeModeSetting extends StatelessWidget {
S.of(context).settingsPageAppearanceSettingDarkThemeLabel,
)
],
initialValue: BlocProvider.of<ApplicationSettingsCubit>(context)
initialValue: context
.read<ApplicationSettingsCubit>()
.state
.preferredThemeMode,
title: Text(S.of(context).settingsPageAppearanceSettingTitle),
),
).then((value) {
return BlocProvider.of<ApplicationSettingsCubit>(context)
.setThemeMode(value);
return context.read<ApplicationSettingsCubit>().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: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<PaperlessLabelsApi>.value(value: labelsApi),
Provider<PaperlessServerStatsApi>.value(value: statsApi),
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<ConnectivityStatusService>.value(
value: connectivityStatusService,
@@ -148,17 +212,8 @@ void main() async {
],
child: MultiBlocProvider(
providers: [
BlocProvider(
create: (context) => AuthenticationCubit(
localVault,
localAuthService,
authApi,
dioWrapper,
),
),
BlocProvider<ConnectivityCubit>.value(
value: connectivityCubit,
),
BlocProvider<AuthenticationCubit>.value(value: authCubit),
BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
],
child: const PaperlessMobileEntrypoint(),
),
@@ -225,10 +280,7 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
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<AuthenticationWrapper> {
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,