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