mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-07 09:15:49 -06:00
WIP - Provider refactorings
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
38
lib/core/interceptor/dio_http_error_interceptor.dart
Normal file
38
lib/core/interceptor/dio_http_error_interceptor.dart
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
60
lib/core/security/authentication_aware_dio_manager.dart
Normal file
60
lib/core/security/authentication_aware_dio_manager.dart
Normal 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'});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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'});
|
||||
}
|
||||
}
|
||||
}
|
||||
22
lib/extensions/security_context_extension.dart
Normal file
22
lib/extensions/security_context_extension.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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) =>
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>(),
|
||||
),
|
||||
// ),
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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>>(),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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>>(
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -20,7 +20,7 @@ class AuthenticationState {
|
||||
required this.wasLoginStored,
|
||||
this.wasLocalAuthenticationSuccessful,
|
||||
this.authentication,
|
||||
});
|
||||
}) : assert(!isAuthenticated || authentication != null);
|
||||
|
||||
AuthenticationState copyWith({
|
||||
bool? wasLoginStored,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}),
|
||||
);
|
||||
},
|
||||
|
||||
122
lib/main.dart
122
lib/main.dart
@@ -10,19 +10,20 @@ import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_native_splash/flutter_native_splash.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:form_builder_validators/form_builder_validators.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:http/io_client.dart';
|
||||
import 'package:http_interceptor/http/intercepted_client.dart';
|
||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||
import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:intl/intl_standalone.dart';
|
||||
import 'package:local_auth/local_auth.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/bloc/bloc_changes_observer.dart';
|
||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||
import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart';
|
||||
import 'package:paperless_mobile/core/global/constants.dart';
|
||||
import 'package:paperless_mobile/core/interceptor/authentication.interceptor.dart';
|
||||
import 'package:paperless_mobile/core/logic/error_code_localization_mapper.dart';
|
||||
import 'package:paperless_mobile/core/model/paperless_statistics_state.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/correspondent_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/document_type_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/impl/saved_view_repository_impl.dart';
|
||||
@@ -30,17 +31,19 @@ import 'package:paperless_mobile/core/repository/impl/storage_path_repository_im
|
||||
import 'package:paperless_mobile/core/repository/impl/tag_repository_impl.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
import 'package:paperless_mobile/core/security/security_context_aware_dio_manager.dart';
|
||||
import 'package:paperless_mobile/core/security/authentication_aware_dio_manager.dart';
|
||||
import 'package:paperless_mobile/core/service/connectivity_status.service.dart';
|
||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||
import 'package:paperless_mobile/core/store/local_vault.dart';
|
||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||
import 'package:paperless_mobile/extensions/security_context_extension.dart';
|
||||
import 'package:paperless_mobile/features/app_intro/application_intro_slideshow.dart';
|
||||
import 'package:paperless_mobile/features/document_upload/cubit/document_upload_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.dart';
|
||||
import 'package:paperless_mobile/features/home/view/home_page.dart';
|
||||
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
|
||||
import 'package:paperless_mobile/features/login/bloc/authentication_state.dart';
|
||||
import 'package:paperless_mobile/features/login/model/authentication_information.dart';
|
||||
import 'package:paperless_mobile/features/login/services/authentication_service.dart';
|
||||
import 'package:paperless_mobile/features/login/view/login_page.dart';
|
||||
import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart';
|
||||
@@ -62,18 +65,12 @@ void main() async {
|
||||
await findSystemLocale();
|
||||
|
||||
// Required for self signed client certificates
|
||||
final dioWrapper = SecurityContextAwareDioManager();
|
||||
IOClient httpClient = IOClient();
|
||||
final dioWrapper = AuthenticationAwareDioManager();
|
||||
|
||||
dioWrapper.securityContextChanges.listen(
|
||||
(context) => httpClient = IOClient(HttpClient(context: context)),
|
||||
);
|
||||
// Initialize External dependencies
|
||||
final connectivity = Connectivity();
|
||||
final encryptedSharedPreferences = EncryptedSharedPreferences();
|
||||
final localAuthentication = LocalAuthentication();
|
||||
final cacheManager = cm.CacheManager(cm.Config('cacheKey',
|
||||
fileService: cm.HttpFileService(httpClient: httpClient)));
|
||||
|
||||
// Initialize Paperless APIs
|
||||
final authApi = PaperlessAuthenticationApiImpl(dioWrapper.client);
|
||||
@@ -104,8 +101,35 @@ void main() async {
|
||||
authApi,
|
||||
dioWrapper,
|
||||
);
|
||||
//TODO: Check if hydrated cubit restores state.
|
||||
//await authCubit.restoreSessionState();
|
||||
|
||||
String? currentServerUrl;
|
||||
String? currentAuthToken;
|
||||
|
||||
if (authCubit.state.isAuthenticated) {
|
||||
final auth = authCubit.state.authentication!;
|
||||
dioWrapper.updateSettings(
|
||||
baseUrl: auth.serverUrl,
|
||||
authToken: auth.token,
|
||||
clientCertificate: auth.clientCertificate,
|
||||
);
|
||||
currentServerUrl = auth.serverUrl;
|
||||
currentAuthToken = auth.token;
|
||||
}
|
||||
|
||||
SecurityContext securityContext = SecurityContext();
|
||||
authCubit.stream.asBroadcastStream().listen((event) {
|
||||
if (event.isAuthenticated) {
|
||||
final auth = event.authentication!;
|
||||
securityContext =
|
||||
SecurityContext().withClientCertificate(auth.clientCertificate);
|
||||
currentServerUrl = auth.serverUrl;
|
||||
currentAuthToken = auth.token;
|
||||
} else {
|
||||
securityContext = SecurityContext();
|
||||
currentServerUrl = null;
|
||||
currentAuthToken = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Create repositories
|
||||
final tagRepository = TagRepositoryImpl(labelsApi);
|
||||
@@ -122,7 +146,47 @@ void main() async {
|
||||
Provider<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,
|
||||
|
||||
Reference in New Issue
Block a user