mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-08 08:07:56 -06:00
feat: Add print feature, refine gradient on details page
This commit is contained in:
@@ -11,6 +11,7 @@ import 'package:paperless_mobile/core/repository/label_repository.dart';
|
|||||||
import 'package:paperless_mobile/core/service/file_description.dart';
|
import 'package:paperless_mobile/core/service/file_description.dart';
|
||||||
import 'package:paperless_mobile/core/service/file_service.dart';
|
import 'package:paperless_mobile/core/service/file_service.dart';
|
||||||
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
||||||
|
import 'package:printing/printing.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:cross_file/cross_file.dart';
|
import 'package:cross_file/cross_file.dart';
|
||||||
|
|
||||||
@@ -98,6 +99,7 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
|
|||||||
|
|
||||||
Future<ResultType> openDocumentInSystemViewer() async {
|
Future<ResultType> openDocumentInSystemViewer() async {
|
||||||
final cacheDir = await FileService.temporaryDirectory;
|
final cacheDir = await FileService.temporaryDirectory;
|
||||||
|
//TODO: Why is this cleared here?
|
||||||
await FileService.clearDirectoryContent(PaperlessDirectoryType.temporary);
|
await FileService.clearDirectoryContent(PaperlessDirectoryType.temporary);
|
||||||
if (state.metaData == null) {
|
if (state.metaData == null) {
|
||||||
await loadMetaData();
|
await loadMetaData();
|
||||||
@@ -199,6 +201,26 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> printDocument() async {
|
||||||
|
if (state.metaData == null) {
|
||||||
|
await loadMetaData();
|
||||||
|
}
|
||||||
|
final filePath = _buildDownloadFilePath(false, await FileService.temporaryDirectory);
|
||||||
|
await _api.downloadToFile(
|
||||||
|
state.document,
|
||||||
|
filePath,
|
||||||
|
original: false,
|
||||||
|
);
|
||||||
|
final file = File(filePath);
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
throw Exception("An error occurred while downloading the document.");
|
||||||
|
}
|
||||||
|
Printing.layoutPdf(
|
||||||
|
name: state.document.title,
|
||||||
|
onLayout: (format) => file.readAsBytesSync(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
String _buildDownloadFilePath(bool original, Directory dir) {
|
String _buildDownloadFilePath(bool original, Directory dir) {
|
||||||
final description = FileDescription.fromPath(
|
final description = FileDescription.fromPath(
|
||||||
state.metaData!.mediaFilename.replaceAll("/", " "), // Flatten directory structure
|
state.metaData!.mediaFilename.replaceAll("/", " "), // Flatten directory structure
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
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_localizations/flutter_localizations.dart';
|
||||||
import 'package:open_filex/open_filex.dart';
|
import 'package:open_filex/open_filex.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
@@ -44,11 +46,6 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
|
|
||||||
final _pagingScrollController = ScrollController();
|
final _pagingScrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final apiVersion = context.watch<ApiVersion>();
|
final apiVersion = context.watch<ApiVersion>();
|
||||||
@@ -87,22 +84,24 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
alignment: Alignment.topCenter,
|
alignment: Alignment.topCenter,
|
||||||
children: [
|
children: [
|
||||||
BlocBuilder<DocumentDetailsCubit, DocumentDetailsState>(
|
BlocBuilder<DocumentDetailsCubit, DocumentDetailsState>(
|
||||||
builder: (context, state) => Positioned.fill(
|
builder: (context, state) {
|
||||||
child: DocumentPreview(
|
return Positioned.fill(
|
||||||
document: state.document,
|
child: DocumentPreview(
|
||||||
fit: BoxFit.cover,
|
document: state.document,
|
||||||
),
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
top: 0,
|
top: 0,
|
||||||
child: Container(
|
child: DecoratedBox(
|
||||||
height: 100,
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Colors.black.withOpacity(0.7),
|
Theme.of(context).colorScheme.background.withOpacity(0.8),
|
||||||
Colors.black.withOpacity(0.2),
|
Theme.of(context).colorScheme.background.withOpacity(0.5),
|
||||||
|
Colors.transparent,
|
||||||
Colors.transparent,
|
Colors.transparent,
|
||||||
Colors.transparent,
|
Colors.transparent,
|
||||||
],
|
],
|
||||||
@@ -310,7 +309,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
tooltip: S.of(context)!.previewTooltip,
|
tooltip: S.of(context)!.previewTooltip,
|
||||||
icon: const Icon(Icons.visibility),
|
icon: const Icon(Icons.visibility),
|
||||||
onPressed: (isConnected && false) ? () => _onOpen(state.document) : null,
|
onPressed: (isConnected) ? () => _onOpen(state.document) : null,
|
||||||
).paddedOnly(right: 4.0),
|
).paddedOnly(right: 4.0),
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: S.of(context)!.openInSystemViewer,
|
tooltip: S.of(context)!.openInSystemViewer,
|
||||||
@@ -318,6 +317,11 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
onPressed: isConnected ? _onOpenFileInSystemViewer : null,
|
onPressed: isConnected ? _onOpenFileInSystemViewer : null,
|
||||||
).paddedOnly(right: 4.0),
|
).paddedOnly(right: 4.0),
|
||||||
DocumentShareButton(document: state.document),
|
DocumentShareButton(document: state.document),
|
||||||
|
IconButton(
|
||||||
|
tooltip: "Print", //TODO: INTL
|
||||||
|
onPressed: () => context.read<DocumentDetailsCubit>().printDocument(),
|
||||||
|
icon: const Icon(Icons.print),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -404,7 +408,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => DocumentView(
|
builder: (_) => DocumentView(
|
||||||
documentBytes: context.read<PaperlessDocumentsApi>().getPreview(document.id),
|
documentBytes: context.read<PaperlessDocumentsApi>().download(document),
|
||||||
|
title: document.title,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ class _ScannerPageState extends State<ScannerPage> with SingleTickerProviderStat
|
|||||||
? () => Navigator.of(context).push(
|
? () => Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => DocumentView(
|
builder: (context) => DocumentView(
|
||||||
|
|
||||||
documentBytes: _assembleFileBytes(
|
documentBytes: _assembleFileBytes(
|
||||||
state,
|
state,
|
||||||
forcePdf: true,
|
forcePdf: true,
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_pdfview/flutter_pdfview.dart';
|
||||||
|
|
||||||
class DocumentView extends StatefulWidget {
|
class DocumentView extends StatefulWidget {
|
||||||
final Future<Uint8List> documentBytes;
|
final Future<Uint8List> documentBytes;
|
||||||
|
final String? title;
|
||||||
const DocumentView({
|
const DocumentView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.documentBytes,
|
required this.documentBytes,
|
||||||
|
this.title,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -14,37 +16,90 @@ class DocumentView extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _DocumentViewState extends State<DocumentView> {
|
class _DocumentViewState extends State<DocumentView> {
|
||||||
// late PdfController _pdfController;
|
int? _currentPage;
|
||||||
|
int? _totalPages;
|
||||||
@override
|
PDFViewController? _controller;
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
// _pdfController = PdfController(
|
|
||||||
// document: PdfDocument.openData(
|
|
||||||
// widget.documentBytes,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container();
|
final isInitialized = _controller != null && _currentPage != null && _totalPages != null;
|
||||||
// return Scaffold(
|
final canGoToNextPage = isInitialized && _currentPage! + 1 < _totalPages!;
|
||||||
// appBar: AppBar(
|
final canGoToPreviousPage = isInitialized && _currentPage! > 0;
|
||||||
// title: Text(S.of(context)!.preview),
|
return Scaffold(
|
||||||
// ),
|
appBar: AppBar(
|
||||||
// body: PdfView(
|
title: widget.title != null ? Text(widget.title!) : null,
|
||||||
// builders: PdfViewBuilders<DefaultBuilderOptions>(
|
),
|
||||||
// options: const DefaultBuilderOptions(
|
bottomNavigationBar: BottomAppBar(
|
||||||
// loaderSwitchDuration: Duration(milliseconds: 500),
|
child: Row(
|
||||||
// ),
|
children: [
|
||||||
// pageLoaderBuilder: (context) => const Center(
|
Flexible(
|
||||||
// child: CircularProgressIndicator(),
|
child: Row(
|
||||||
// ),
|
children: [
|
||||||
// ),
|
IconButton.filled(
|
||||||
// scrollDirection: Axis.vertical,
|
onPressed: canGoToPreviousPage
|
||||||
// controller: _pdfController,
|
? () {
|
||||||
// ),
|
_controller?.setPage(_currentPage! - 1);
|
||||||
// );
|
}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.arrow_left),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
IconButton.filled(
|
||||||
|
onPressed: canGoToNextPage
|
||||||
|
? () {
|
||||||
|
_controller?.setPage(_currentPage! + 1);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
icon: const Icon(Icons.arrow_right),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_currentPage != null && _totalPages != null)
|
||||||
|
Text(
|
||||||
|
"${_currentPage! + 1}/$_totalPages",
|
||||||
|
style: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: widget.documentBytes,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (!snapshot.hasData) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return PDFView(
|
||||||
|
pdfData: snapshot.data,
|
||||||
|
defaultPage: 0,
|
||||||
|
enableSwipe: true,
|
||||||
|
fitPolicy: FitPolicy.BOTH,
|
||||||
|
swipeHorizontal: true,
|
||||||
|
onRender: (pages) {
|
||||||
|
setState(() {
|
||||||
|
_currentPage = 0;
|
||||||
|
_totalPages = pages ?? -1;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onPageChanged: (page, total) {
|
||||||
|
setState(() {
|
||||||
|
_currentPage = page;
|
||||||
|
_totalPages = total;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onViewCreated: (controller) {
|
||||||
|
_controller = controller;
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
print(error.toString());
|
||||||
|
},
|
||||||
|
onPageError: (page, error) {
|
||||||
|
print('$page: ${error.toString()}');
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ Future<void> _initHive() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
|
Paint.enableDithering = true;
|
||||||
if (kDebugMode) {
|
if (kDebugMode) {
|
||||||
// URL: http://localhost:3131
|
// URL: http://localhost:3131
|
||||||
// Login: admin:test
|
// Login: admin:test
|
||||||
|
|||||||
18
pubspec.lock
18
pubspec.lock
@@ -617,6 +617,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.18"
|
version: "2.2.18"
|
||||||
|
flutter_pdfview:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_pdfview
|
||||||
|
sha256: d9735fd8991609910742a25c63a5f87060849e57e60112c677b802ddb64bed72
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1267,6 +1275,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
printing:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: printing
|
||||||
|
sha256: e7c383dca95ee7b88c02dc1c66638628d3dcdc2fb2cc47e7a595facd47e46b56
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.11.0"
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1802,4 +1818,4 @@ packages:
|
|||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.0.0 <4.0.0"
|
dart: ">=3.0.0 <4.0.0"
|
||||||
flutter: ">=3.7.0"
|
flutter: ">=3.10.0"
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ dependencies:
|
|||||||
flutter_secure_storage: ^8.0.0
|
flutter_secure_storage: ^8.0.0
|
||||||
sliver_tools: ^0.2.10
|
sliver_tools: ^0.2.10
|
||||||
webview_flutter: ^4.2.1
|
webview_flutter: ^4.2.1
|
||||||
|
printing: ^5.11.0
|
||||||
|
flutter_pdfview: ^1.3.1
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
|
|||||||
Reference in New Issue
Block a user