Fix PDF rendering on my smartphone
This commit is contained in:
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(),
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user