mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-09 16:07:57 -06:00
Added possibility to upload documents from file system
This commit is contained in:
@@ -46,5 +46,6 @@ enum ErrorCode {
|
||||
createSavedViewError,
|
||||
deleteSavedViewError,
|
||||
requestTimedOut,
|
||||
storagePathAlreadyExists;
|
||||
storagePathAlreadyExists,
|
||||
unsupportedFileFormat;
|
||||
}
|
||||
|
||||
@@ -29,10 +29,11 @@ import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class DocumentUploadPage extends StatefulWidget {
|
||||
final Uint8List pdfBytes;
|
||||
final Uint8List fileBytes;
|
||||
|
||||
const DocumentUploadPage({
|
||||
Key? key,
|
||||
required this.pdfBytes,
|
||||
required this.fileBytes,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -190,7 +191,7 @@ class _DocumentUploadPageState extends State<DocumentUploadPage> {
|
||||
_isUploadLoading = true;
|
||||
});
|
||||
await BlocProvider.of<DocumentsCubit>(context).addDocument(
|
||||
widget.pdfBytes,
|
||||
widget.fileBytes,
|
||||
_formKey.currentState?.value[fkFileName],
|
||||
onConsumptionFinished: (document) {
|
||||
ScaffoldMessenger.of(rootScaffoldKey.currentContext!).showSnackBar(
|
||||
|
||||
@@ -2,9 +2,13 @@ import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:edge_detection/edge_detection.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
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/label_bloc_provider.dart';
|
||||
import 'package:paperless_mobile/core/model/error_message.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/home/view/widget/info_drawer.dart';
|
||||
@@ -12,6 +16,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';
|
||||
@@ -25,6 +30,14 @@ 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;
|
||||
@override
|
||||
@@ -109,18 +122,8 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
}
|
||||
|
||||
void _export(BuildContext context) async {
|
||||
final pw.Document doc = pw.Document();
|
||||
|
||||
for (var element in BlocProvider.of<DocumentScannerCubit>(context).state) {
|
||||
final img = pw.MemoryImage(element.readAsBytesSync());
|
||||
doc.addPage(
|
||||
pw.Page(
|
||||
pageFormat:
|
||||
PdfPageFormat(img.width!.toDouble(), img.height!.toDouble()),
|
||||
build: (context) => pw.Image(img),
|
||||
),
|
||||
);
|
||||
}
|
||||
final doc = _buildDocumentFromImageFiles(
|
||||
BlocProvider.of<DocumentScannerCubit>(context).state);
|
||||
final bytes = await doc.save();
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
@@ -128,7 +131,7 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
value: getIt<DocumentsCubit>(),
|
||||
child: LabelBlocProvider(
|
||||
child: DocumentUploadPage(
|
||||
pdfBytes: bytes,
|
||||
fileBytes: bytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -144,10 +147,27 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
}
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
S.of(context).documentScannerPageEmptyStateText,
|
||||
textAlign: TextAlign.center,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).documentScannerPageEmptyStateText,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
TextButton(
|
||||
child:
|
||||
Text(S.of(context).documentScannerPageAddScanButtonLabel),
|
||||
onPressed: () => _openDocumentScanner(context),
|
||||
),
|
||||
Text(S.of(context).documentScannerPageOrText),
|
||||
TextButton(
|
||||
child: Text(S
|
||||
.of(context)
|
||||
.documentScannerPageUploadFromThisDeviceButtonLabel),
|
||||
onPressed: _onUploadFromFilesystem,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -185,4 +205,53 @@ class _ScannerPageState extends State<ScannerPage>
|
||||
Permission.camera.request();
|
||||
}
|
||||
}
|
||||
|
||||
void _onUploadFromFilesystem() async {
|
||||
FilePickerResult? result = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: _supportedExtensions,
|
||||
withData: true,
|
||||
);
|
||||
if (result?.files.single.path != null) {
|
||||
File file = File(result!.files.single.path!);
|
||||
|
||||
final mimeType = lookupMimeType(file.path) ?? '';
|
||||
late Uint8List fileBytes;
|
||||
if (mimeType.startsWith('image')) {
|
||||
fileBytes = await _buildDocumentFromImageFiles([file]).save();
|
||||
} else {
|
||||
// pdf
|
||||
fileBytes = file.readAsBytesSync();
|
||||
}
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BlocProvider.value(
|
||||
value: getIt<DocumentsCubit>(),
|
||||
child: LabelBlocProvider(
|
||||
child: DocumentUploadPage(
|
||||
fileBytes: fileBytes,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pw.Document _buildDocumentFromImageFiles(List<File> files) {
|
||||
final doc = pw.Document();
|
||||
for (final file in files) {
|
||||
final img = pw.MemoryImage(file.readAsBytesSync());
|
||||
doc.addPage(
|
||||
pw.Page(
|
||||
pageFormat:
|
||||
PdfPageFormat(img.width!.toDouble(), img.height!.toDouble()),
|
||||
build: (context) => pw.Image(img),
|
||||
),
|
||||
);
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,9 @@
|
||||
"documentScannerPageTitle": "Scanner",
|
||||
"documentScannerPageResetButtonTooltipText": "Alle scans löschen",
|
||||
"documentScannerPageUploadButtonTooltip": "Dokument hochladen",
|
||||
"documentScannerPageAddScanButtonLabel": "Scanne ein Dokument",
|
||||
"documentScannerPageOrText": "oder",
|
||||
"documentScannerPageUploadFromThisDeviceButtonLabel": "Lade ein Dokument von diesem Gerät hoch",
|
||||
"addTagPageTitle": "Neuer Tag",
|
||||
"addCorrespondentPageTitle": "Neuer Korrespondent",
|
||||
"addDocumentTypePageTitle": "Neuer Dokumententyp",
|
||||
@@ -182,4 +185,5 @@
|
||||
"referencedDocumentsReadOnlyHintText": "Dies ist eine schreibgeschützte Ansicht! Dokumente können nicht bearbeitet oder entfernt werden.",
|
||||
"editLabelPageConfirmDeletionDialogTitle": "Löschen bestätigen",
|
||||
"editLabelPageDeletionDialogText": "Dieser Kennzeichner wird von Dokumenten referenziert. Durch das Löschen dieses Kennzeichners werden alle Referenzen entfernt. Fortfahren?"
|
||||
|
||||
}
|
||||
@@ -101,6 +101,9 @@
|
||||
"documentScannerPageTitle": "Scan",
|
||||
"documentScannerPageResetButtonTooltipText": "Delete all scans",
|
||||
"documentScannerPageUploadButtonTooltip": "Upload to Paperless",
|
||||
"documentScannerPageAddScanButtonLabel": "Scan a document",
|
||||
"documentScannerPageOrText": "or",
|
||||
"documentScannerPageUploadFromThisDeviceButtonLabel": "Upload a document from this device",
|
||||
"addTagPageTitle": "New Tag",
|
||||
"addCorrespondentPageTitle": "New Correspondent",
|
||||
"addDocumentTypePageTitle": "New Document Type",
|
||||
|
||||
Reference in New Issue
Block a user