Improved error handling, added multithreading for fromJson calls, made receive sharing intent more robust

This commit is contained in:
Anton Stubenbord
2022-11-13 14:41:42 +01:00
parent afbd4bddb4
commit 1cafd5d246
43 changed files with 644 additions and 746 deletions

View File

@@ -22,19 +22,22 @@ class DocumentScannerCubit extends Cubit<List<File>> {
scans.removeAt(fileIndex);
emit(scans);
} catch (_) {
addError(const ErrorMessage(ErrorCode.scanRemoveFailed));
throw const ErrorMessage(ErrorCode.scanRemoveFailed);
}
}
void reset() {
for (final doc in state) {
doc.deleteSync();
if (kDebugMode) {
log('[ScannerCubit]: Removed ${doc.path}');
try {
for (final doc in state) {
doc.deleteSync();
if (kDebugMode) {
log('[ScannerCubit]: Removed ${doc.path}');
}
}
imageCache.clear();
emit(initialState);
} catch (_) {
throw const ErrorMessage(ErrorCode.scanRemoveFailed);
}
imageCache.clear();
emit(initialState);
}
}

View File

@@ -185,51 +185,32 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
}
void _onSubmit() async {
_formKey.currentState?.save();
if (_formKey.currentState?.validate() ?? false) {
if (_formKey.currentState?.saveAndValidate() ?? false) {
try {
setState(() {
_isUploadLoading = true;
});
setState(() => _isUploadLoading = true);
final fv = _formKey.currentState!.value;
final createdAt = fv[DocumentModel.createdKey] as DateTime?;
final title = fv[DocumentModel.titleKey] as String;
final docType = fv[DocumentModel.documentTypeKey] as IdQueryParameter;
final tags = fv[DocumentModel.tagsKey] as TagsQuery;
final correspondent =
fv[DocumentModel.correspondentKey] as IdQueryParameter;
await BlocProvider.of<DocumentsCubit>(context).addDocument(
widget.fileBytes,
_formKey.currentState?.value[fkFileName],
onConsumptionFinished: (document) {
ScaffoldMessenger.of(rootScaffoldKey.currentContext!).showSnackBar(
SnackBar(
action: SnackBarAction(
onPressed: () {
getIt<DocumentsCubit>().reloadDocuments();
},
label: S
.of(context)
.documentUploadProcessingSuccessfulReloadActionText,
),
content:
Text(S.of(context).documentUploadProcessingSuccessfulText),
),
);
},
title: _formKey.currentState?.value[DocumentModel.titleKey],
documentType: (_formKey.currentState
?.value[DocumentModel.documentTypeKey] as IdQueryParameter)
.id,
correspondent: (_formKey.currentState
?.value[DocumentModel.correspondentKey] as IdQueryParameter)
.id,
tags:
(_formKey.currentState?.value[DocumentModel.tagsKey] as TagsQuery)
.ids,
createdAt: (_formKey.currentState?.value[DocumentModel.createdKey]
as DateTime?),
propagateEventOnError: false,
onConsumptionFinished: _onConsumptionFinished,
title: title,
documentType: docType.id,
correspondent: correspondent.id,
tags: tags.ids,
createdAt: createdAt,
);
setState(() {
_isUploadLoading = false;
});
getIt<DocumentScannerCubit>().reset();
Navigator.pop(context);
getIt<DocumentScannerCubit>().reset(); //TODO: Access via provider
showSnackBar(context, S.of(context).documentUploadSuccessText);
Navigator.pop(context);
widget.afterUpload?.call();
} on ErrorMessage catch (error) {
showError(context, error);
@@ -239,9 +220,28 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
showSnackBar(context, other.toString());
} finally {
setState(() {
_isUploadLoading = true;
_isUploadLoading = false;
});
}
}
}
void _onConsumptionFinished(document) {
ScaffoldMessenger.of(rootScaffoldKey.currentContext!).showSnackBar(
SnackBar(
action: SnackBarAction(
onPressed: () async {
try {
getIt<DocumentsCubit>().reloadDocuments();
} on ErrorMessage catch (error) {
showError(context, error);
}
},
label:
S.of(context).documentUploadProcessingSuccessfulReloadActionText,
),
content: Text(S.of(context).documentUploadProcessingSuccessfulText),
),
);
}
}

View File

@@ -8,8 +8,8 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mime/mime.dart';
import 'package:paperless_mobile/core/bloc/global_error_cubit.dart';
import 'package:paperless_mobile/core/bloc/label_bloc_provider.dart';
import 'package:paperless_mobile/core/global/constants.dart';
import 'package:paperless_mobile/core/model/error_message.dart';
import 'package:paperless_mobile/core/service/file_service.dart';
import 'package:paperless_mobile/di_initializer.dart';
@@ -19,6 +19,7 @@ import 'package:paperless_mobile/features/scan/bloc/document_scanner_cubit.dart'
import 'package:paperless_mobile/features/scan/view/document_upload_page.dart';
import 'package:paperless_mobile/features/scan/view/widgets/grid_image_item_widget.dart';
import 'package:paperless_mobile/generated/l10n.dart';
import 'package:paperless_mobile/util.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:permission_handler/permission_handler.dart';
@@ -32,15 +33,6 @@ class ScannerPage extends StatefulWidget {
class _ScannerPageState extends State<ScannerPage>
with SingleTickerProviderStateMixin {
static const _supportedExtensions = [
'pdf',
'png',
'tiff',
'gif',
'jpg',
'jpeg'
];
late final AnimationController _fabPulsingController;
late final Animation _animation;
@@ -205,8 +197,14 @@ class _ScannerPageState extends State<ScannerPage>
itemBuilder: (context, index) {
return GridImageItemWidget(
file: scans[index],
onDelete: () => BlocProvider.of<DocumentScannerCubit>(context)
.removeScan(index),
onDelete: () async {
try {
BlocProvider.of<DocumentScannerCubit>(context)
.removeScan(index);
} on ErrorMessage catch (error) {
showError(context, error);
}
},
index: index,
totalNumberOfFiles: scans.length,
);
@@ -214,7 +212,11 @@ class _ScannerPageState extends State<ScannerPage>
}
void _reset(BuildContext context) {
BlocProvider.of<DocumentScannerCubit>(context).reset();
try {
BlocProvider.of<DocumentScannerCubit>(context).reset();
} on ErrorMessage catch (error) {
showError(context, error);
}
}
Future<void> _requestCameraPermissions() async {
@@ -227,15 +229,14 @@ class _ScannerPageState extends State<ScannerPage>
void _onUploadFromFilesystem() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: _supportedExtensions,
allowedExtensions: supportedFileExtensions,
withData: true,
);
if (result?.files.single.path != null) {
File file = File(result!.files.single.path!);
if (!_supportedExtensions.contains(file.path.split('.').last)) {
return getIt<GlobalErrorCubit>().add(
const ErrorMessage(ErrorCode.unsupportedFileFormat),
);
if (!supportedFileExtensions.contains(file.path.split('.').last)) {
//TODO: Show error message;
return;
}
final mimeType = lookupMimeType(file.path) ?? '';
late Uint8List fileBytes;