Fix PDF rendering on my smartphone
This commit is contained in:
@ -1,16 +1,14 @@
|
|||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:alert_dialog/alert_dialog.dart';
|
|
||||||
import 'package:confirm_dialog/confirm_dialog.dart';
|
import 'package:confirm_dialog/confirm_dialog.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_pdfview/flutter_pdfview.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:logging/logging.dart';
|
|
||||||
import 'package:moneymgr_mobile/services/storage/expenses.dart';
|
import 'package:moneymgr_mobile/services/storage/expenses.dart';
|
||||||
import 'package:moneymgr_mobile/services/storage/prefs.dart';
|
import 'package:moneymgr_mobile/services/storage/prefs.dart';
|
||||||
import 'package:moneymgr_mobile/utils/extensions.dart';
|
import 'package:moneymgr_mobile/utils/extensions.dart';
|
||||||
import 'package:moneymgr_mobile/utils/time_utils.dart';
|
import 'package:moneymgr_mobile/utils/time_utils.dart';
|
||||||
|
import 'package:moneymgr_mobile/widgets/pdf_viewer.dart';
|
||||||
|
|
||||||
class ExpenseEditor extends HookConsumerWidget {
|
class ExpenseEditor extends HookConsumerWidget {
|
||||||
final Uint8List file;
|
final Uint8List file;
|
||||||
@ -88,14 +86,7 @@ class ExpenseEditor extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
// Expense preview
|
// Expense preview
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PDFView(
|
child: PDFViewer(pdfBytes: file, fit: BoxFit.contain),
|
||||||
pdfData: file,
|
|
||||||
onError: (e) {
|
|
||||||
Logger.root.warning("Failed to render PDF $e");
|
|
||||||
alert(context, content: Text("Failed to render PDF $e"));
|
|
||||||
},
|
|
||||||
fitPolicy: FitPolicy.BOTH,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
|
104
moneymgr_mobile/lib/widgets/pdf_viewer.dart
Normal file
104
moneymgr_mobile/lib/widgets/pdf_viewer.dart
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:pdf_image_renderer/pdf_image_renderer.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
|
part 'pdf_viewer.g.dart';
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<Uint8List> _renderPdf(
|
||||||
|
Ref ref, {
|
||||||
|
String? path,
|
||||||
|
Uint8List? pdfBytes,
|
||||||
|
}) async {
|
||||||
|
assert(path != null || pdfBytes != null);
|
||||||
|
|
||||||
|
// Create temporary file if required
|
||||||
|
var isTemp = false;
|
||||||
|
if (path == null) {
|
||||||
|
path = p.join(
|
||||||
|
(await getTemporaryDirectory()).absolute.path,
|
||||||
|
"render-${Random().nextInt(10000).toString()}+.pdf",
|
||||||
|
);
|
||||||
|
|
||||||
|
await File(path).writeAsBytes(pdfBytes!);
|
||||||
|
isTemp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final pdf = PdfImageRenderer(path: path);
|
||||||
|
await pdf.open();
|
||||||
|
await pdf.openPage(pageIndex: 0);
|
||||||
|
|
||||||
|
// get the render size after the page is loaded
|
||||||
|
final size = await pdf.getPageSize(pageIndex: 0);
|
||||||
|
|
||||||
|
// get the actual image of the page
|
||||||
|
final img = await pdf.renderPage(
|
||||||
|
pageIndex: 0,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: size.width,
|
||||||
|
// you can pass a custom size here to crop the image
|
||||||
|
height: size.height,
|
||||||
|
// you can pass a custom size here to crop the image
|
||||||
|
scale: 1,
|
||||||
|
// increase the scale for better quality (e.g. for zooming)
|
||||||
|
background: Colors.white,
|
||||||
|
);
|
||||||
|
|
||||||
|
// close the page again
|
||||||
|
await pdf.closePage(pageIndex: 0);
|
||||||
|
|
||||||
|
// close the PDF after rendering the page
|
||||||
|
pdf.close();
|
||||||
|
|
||||||
|
return img!;
|
||||||
|
} finally {
|
||||||
|
if (isTemp) {
|
||||||
|
await File(path).delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PDFViewer extends ConsumerWidget {
|
||||||
|
final String? pdfPath;
|
||||||
|
final Uint8List? pdfBytes;
|
||||||
|
final double? width;
|
||||||
|
final double? height;
|
||||||
|
final BoxFit? fit;
|
||||||
|
|
||||||
|
const PDFViewer({
|
||||||
|
super.key,
|
||||||
|
this.pdfPath,
|
||||||
|
this.pdfBytes,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.fit,
|
||||||
|
}) : assert(pdfPath != null || pdfBytes != null);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final provider = ref.watch(
|
||||||
|
_renderPdfProvider(path: pdfPath, pdfBytes: pdfBytes),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Perform a switch-case on the result to handle loading/error states
|
||||||
|
return switch (provider) {
|
||||||
|
AsyncData(:final value) => Image(
|
||||||
|
image: MemoryImage(value),
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
fit: fit,
|
||||||
|
),
|
||||||
|
AsyncError(:final error) => Text('PDF error: $error'),
|
||||||
|
_ => const CircularProgressIndicator(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -382,14 +382,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.6"
|
version: "2.4.6"
|
||||||
flutter_pdfview:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: flutter_pdfview
|
|
||||||
sha256: c402ad1f51ba8ea73b9fb04c003ca0a9286118ba5ac9787ee2aa58956b3fcf8a
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.4.1+1"
|
|
||||||
flutter_riverpod:
|
flutter_riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -728,6 +720,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
pdf_image_renderer:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: pdf_image_renderer
|
||||||
|
sha256: "0ec76118b14663f17f9b6a8c29ec59cb1b82e466a3c16fbb2ed9f1b613fc41b7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -89,8 +89,8 @@ dependencies:
|
|||||||
path_provider: ^2.1.5
|
path_provider: ^2.1.5
|
||||||
path: ^1.9.1
|
path: ^1.9.1
|
||||||
|
|
||||||
# PDF viewer
|
# PDF renderer
|
||||||
flutter_pdfview: ^1.4.1+1
|
pdf_image_renderer: ^1.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Reference in New Issue
Block a user