mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-09 00:07:49 -06:00
FEATURE download a document pdf file without uploading it to server
This commit is contained in:
@@ -347,6 +347,7 @@ Future<DocumentUploadResult?> pushDocumentUploadPreparationPage(
|
|||||||
create: (_) => DocumentUploadCubit(
|
create: (_) => DocumentUploadCubit(
|
||||||
context.read(),
|
context.read(),
|
||||||
context.read(),
|
context.read(),
|
||||||
|
context.read(),
|
||||||
),
|
),
|
||||||
child: DocumentUploadPreparationPage(
|
child: DocumentUploadPreparationPage(
|
||||||
fileBytes: bytes,
|
fileBytes: bytes,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import 'package:equatable/equatable.dart';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
|
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
||||||
|
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||||
|
|
||||||
part 'document_upload_state.dart';
|
part 'document_upload_state.dart';
|
||||||
|
|
||||||
@@ -13,7 +15,9 @@ class DocumentUploadCubit extends Cubit<DocumentUploadState> {
|
|||||||
|
|
||||||
final LabelRepository _labelRepository;
|
final LabelRepository _labelRepository;
|
||||||
|
|
||||||
DocumentUploadCubit(this._labelRepository, this._documentApi)
|
final LocalNotificationService _notificationService;
|
||||||
|
|
||||||
|
DocumentUploadCubit(this._labelRepository, this._documentApi, this._notificationService)
|
||||||
: super(const DocumentUploadState()) {
|
: super(const DocumentUploadState()) {
|
||||||
_labelRepository.addListener(
|
_labelRepository.addListener(
|
||||||
this,
|
this,
|
||||||
@@ -49,6 +53,18 @@ class DocumentUploadCubit extends Cubit<DocumentUploadState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveLocally(
|
||||||
|
Uint8List bytes, String fileName, String preferredLocaleSubtag
|
||||||
|
) async {
|
||||||
|
var file = await FileService.saveToFile(bytes, fileName);
|
||||||
|
_notificationService.notifyFileSaved(
|
||||||
|
filename: fileName,
|
||||||
|
filePath: file.path,
|
||||||
|
finished: true,
|
||||||
|
locale: preferredLocaleSubtag,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
_labelRepository.removeListener(this);
|
_labelRepository.removeListener(this);
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/constants.dart';
|
||||||
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
import 'package:paperless_mobile/core/type/types.dart';
|
import 'package:paperless_mobile/core/type/types.dart';
|
||||||
@@ -19,6 +24,8 @@ import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.d
|
|||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||||
|
import 'package:paperless_mobile/helpers/permission_helpers.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
|
||||||
class DocumentUploadResult {
|
class DocumentUploadResult {
|
||||||
final bool success;
|
final bool success;
|
||||||
@@ -75,6 +82,8 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
child: LinearProgressIndicator(), preferredSize: Size.fromHeight(4.0))
|
child: LinearProgressIndicator(), preferredSize: Size.fromHeight(4.0))
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
|
bottomNavigationBar: _buildBottomAppBar(),
|
||||||
|
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
|
||||||
floatingActionButton: Visibility(
|
floatingActionButton: Visibility(
|
||||||
visible: MediaQuery.of(context).viewInsets.bottom == 0,
|
visible: MediaQuery.of(context).viewInsets.bottom == 0,
|
||||||
child: FloatingActionButton.extended(
|
child: FloatingActionButton.extended(
|
||||||
@@ -291,6 +300,30 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlocBuilder<DocumentUploadCubit, DocumentUploadState> _buildBottomAppBar() {
|
||||||
|
return BlocBuilder<DocumentUploadCubit, DocumentUploadState>(
|
||||||
|
builder: (context, state) {
|
||||||
|
return BottomAppBar(
|
||||||
|
child: BlocBuilder<DocumentUploadCubit, DocumentUploadState>(
|
||||||
|
builder: (context, connectivityState) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
tooltip: "Save a local copy",
|
||||||
|
icon: const Icon(Icons.download),
|
||||||
|
onPressed: () => _onLocalSave(),
|
||||||
|
).paddedOnly(right: 4.0),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String _padWithExtension(String source, [String? extension]) {
|
String _padWithExtension(String source, [String? extension]) {
|
||||||
final ext = extension ?? '.pdf';
|
final ext = extension ?? '.pdf';
|
||||||
return source.endsWith(ext) ? source : '$source$ext';
|
return source.endsWith(ext) ? source : '$source$ext';
|
||||||
@@ -299,4 +332,27 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
String _formatFilename(String source) {
|
String _formatFilename(String source) {
|
||||||
return source.replaceAll(RegExp(r"[\W_]"), "_").toLowerCase();
|
return source.replaceAll(RegExp(r"[\W_]"), "_").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onLocalSave() async {
|
||||||
|
final cubit = context.read<DocumentUploadCubit>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
|
||||||
|
if (Platform.isAndroid && androidInfo!.version.sdkInt <= 29) {
|
||||||
|
final isGranted = await askForPermission(Permission.storage);
|
||||||
|
if (!isGranted) {
|
||||||
|
return;
|
||||||
|
//TODO: Ask user to grant permissions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final title = (_formKey.currentState?.fields[fkFileName]?.value ?? widget.filename) as String;
|
||||||
|
|
||||||
|
var fileName = "$title.${widget.fileExtension}";
|
||||||
|
|
||||||
|
await cubit.saveLocally(widget.fileBytes, fileName, globalSettings.preferredLocaleSubtag);
|
||||||
|
} catch (error) {
|
||||||
|
showGenericError(context, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,6 +90,50 @@ class LocalNotificationService {
|
|||||||
); //TODO: INTL
|
); //TODO: INTL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> notifyFileSaved({
|
||||||
|
required String filename,
|
||||||
|
required String filePath,
|
||||||
|
required bool finished,
|
||||||
|
required String locale,
|
||||||
|
}) async {
|
||||||
|
final tr = await S.delegate.load(Locale(locale));
|
||||||
|
|
||||||
|
await _plugin.show(
|
||||||
|
filePath.hashCode,
|
||||||
|
filename,
|
||||||
|
finished
|
||||||
|
? tr.notificationDownloadComplete
|
||||||
|
: tr.notificationDownloadingDocument,
|
||||||
|
NotificationDetails(
|
||||||
|
android: AndroidNotificationDetails(
|
||||||
|
NotificationChannel.documentDownload.id + "_$filename",
|
||||||
|
NotificationChannel.documentDownload.name,
|
||||||
|
ongoing: !finished,
|
||||||
|
indeterminate: true,
|
||||||
|
importance: Importance.max,
|
||||||
|
priority: Priority.high,
|
||||||
|
showProgress: !finished,
|
||||||
|
when: DateTime.now().millisecondsSinceEpoch,
|
||||||
|
category: AndroidNotificationCategory.progress,
|
||||||
|
icon: finished ? 'file_download_done' : 'downloading',
|
||||||
|
),
|
||||||
|
iOS: DarwinNotificationDetails(
|
||||||
|
attachments: [
|
||||||
|
DarwinNotificationAttachment(
|
||||||
|
filePath,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
payload: jsonEncode(
|
||||||
|
OpenDownloadedDocumentPayload(
|
||||||
|
filePath: filePath,
|
||||||
|
).toJson(),
|
||||||
|
),
|
||||||
|
); //TODO: INTL
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//TODO: INTL
|
//TODO: INTL
|
||||||
Future<void> notifyTaskChanged(Task task) {
|
Future<void> notifyTaskChanged(Task task) {
|
||||||
log("[LocalNotificationService] notifyTaskChanged: ${task.toString()}");
|
log("[LocalNotificationService] notifyTaskChanged: ${task.toString()}");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ dependencies:
|
|||||||
logging: ^1.1.1
|
logging: ^1.1.1
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
http: ^0.13.4
|
http: ^0.13.5
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user