Fix PDF rendering on my smartphone
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing

This commit is contained in:
2025-07-14 16:03:45 +02:00
parent 768706e2d4
commit dd035f8a15
4 changed files with 116 additions and 21 deletions

View File

@ -1,16 +1,14 @@
import 'dart:typed_data';
import 'package:alert_dialog/alert_dialog.dart';
import 'package:confirm_dialog/confirm_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_pdfview/flutter_pdfview.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/prefs.dart';
import 'package:moneymgr_mobile/utils/extensions.dart';
import 'package:moneymgr_mobile/utils/time_utils.dart';
import 'package:moneymgr_mobile/widgets/pdf_viewer.dart';
class ExpenseEditor extends HookConsumerWidget {
final Uint8List file;
@ -88,14 +86,7 @@ class ExpenseEditor extends HookConsumerWidget {
children: [
// Expense preview
Expanded(
child: PDFView(
pdfData: file,
onError: (e) {
Logger.root.warning("Failed to render PDF $e");
alert(context, content: Text("Failed to render PDF $e"));
},
fitPolicy: FitPolicy.BOTH,
),
child: PDFViewer(pdfBytes: file, fit: BoxFit.contain),
),
SizedBox(height: 10),

View 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(),
};
}
}

View File

@ -382,14 +382,6 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:
@ -728,6 +720,14 @@ packages:
url: "https://pub.dev"
source: hosted
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:
dependency: transitive
description:

View File

@ -89,8 +89,8 @@ dependencies:
path_provider: ^2.1.5
path: ^1.9.1
# PDF viewer
flutter_pdfview: ^1.4.1+1
# PDF renderer
pdf_image_renderer: ^1.0.1
dev_dependencies:
flutter_test: