Merge branch 'fix/chrome_save' into feat/mobile
This commit is contained in:
commit
9e0ae1dcfe
|
|
@ -182,6 +182,7 @@ class DocumentStateNotifier extends StateNotifier<Document> {
|
|||
);
|
||||
if (result != null) return result;
|
||||
} catch (_) {
|
||||
debugPrint('Warning: export in isolate failed');
|
||||
// Fall back to main-isolate export if isolate fails (e.g., engine limitations).
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'package:image/image.dart' as img;
|
|||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:pdf/pdf.dart' as pdf;
|
||||
import 'package:pdfrx_engine/pdfrx_engine.dart' as engine;
|
||||
import 'package:pdfrx/pdfrx.dart' show pdfrxFlutterInitialize;
|
||||
import '../../domain/models/model.dart';
|
||||
import '../../utils/rotation_utils.dart' as rot;
|
||||
import '../../utils/background_removal.dart' as br;
|
||||
|
|
@ -104,15 +105,14 @@ class ExportService {
|
|||
}
|
||||
|
||||
// Initialize engine (safe to call multiple times)
|
||||
try {
|
||||
await engine.pdfrxInitialize();
|
||||
} catch (_) {}
|
||||
pdfrxFlutterInitialize();
|
||||
|
||||
// Open source document from memory; if not supported, write temp file
|
||||
engine.PdfDocument? doc;
|
||||
try {
|
||||
doc = await engine.PdfDocument.openData(srcBytes);
|
||||
} catch (_) {
|
||||
debugPrint('Warning: pdfrx openData failed');
|
||||
final tmp = File(
|
||||
'${Directory.systemTemp.path}/pdfrx_src_${DateTime.now().millisecondsSinceEpoch}.pdf',
|
||||
);
|
||||
|
|
@ -120,7 +120,9 @@ class ExportService {
|
|||
doc = await engine.PdfDocument.openFile(tmp.path);
|
||||
try {
|
||||
tmp.deleteSync();
|
||||
} catch (_) {}
|
||||
} catch (_) {
|
||||
debugPrint('Warning: temp file delete failed');
|
||||
}
|
||||
}
|
||||
// doc is guaranteed to be assigned by either openData or openFile above
|
||||
|
||||
|
|
@ -221,6 +223,7 @@ class ExportService {
|
|||
|
||||
final bytes = await out.save();
|
||||
doc.dispose();
|
||||
debugPrint('exportSignedPdfFromBytes succeeded');
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +236,7 @@ class ExportService {
|
|||
await file.writeAsBytes(bytes, flush: true);
|
||||
return true;
|
||||
} catch (_) {
|
||||
debugPrint('Error: saveBytesToFile failed');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,6 +221,8 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
if (out != null) {
|
||||
ok = await downloadBytes(out, filename: suggested);
|
||||
savedPath = suggested;
|
||||
} else {
|
||||
debugPrint('_saveSignedPdf: export to bytes failed');
|
||||
}
|
||||
}
|
||||
if (!kIsWeb) {
|
||||
|
|
@ -235,7 +237,6 @@ class _PdfSignatureHomePageState extends ConsumerState<PdfSignatureHomePage> {
|
|||
),
|
||||
),
|
||||
);
|
||||
// ignore: avoid_print
|
||||
debugPrint('_saveSignedPdf: SnackBar shown ok=' + ok.toString());
|
||||
} else {
|
||||
messenger.showSnackBar(
|
||||
|
|
|
|||
|
|
@ -1,11 +1,17 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'download_stub.dart' if (dart.library.html) 'download_web.dart' as impl;
|
||||
// On modern Flutter Web (Wasm GC, e.g., Chromium), dart:html is not available.
|
||||
// Use js_interop capability to select the web implementation that relies on
|
||||
// package:web instead of dart:html.
|
||||
import 'download_stub.dart'
|
||||
if (dart.library.js_interop) 'download_web.dart'
|
||||
as impl;
|
||||
|
||||
/// Initiates a platform-appropriate download/save operation.
|
||||
///
|
||||
/// On Web: triggers a browser download with the provided filename.
|
||||
/// On non-Web: returns false (no-op). Use your existing IO save flow instead.
|
||||
Future<bool> downloadBytes(Uint8List bytes, {required String filename}) {
|
||||
debugPrint('downloadBytes: initiating download');
|
||||
return impl.downloadBytes(bytes, filename: filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
Future<bool> downloadBytes(Uint8List bytes, {required String filename}) async {
|
||||
// Not supported on non-web. Return false so caller can fallback to file save.
|
||||
debugPrint('downloadBytes: not supported on this platform');
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,28 @@
|
|||
// ignore_for_file: deprecated_member_use
|
||||
// ignore: avoid_web_libraries_in_flutter
|
||||
import 'dart:html' as html;
|
||||
import 'dart:typed_data';
|
||||
// Implementation for Web using package:web to support Wasm GC (Chromium)
|
||||
// without importing dart:html directly.
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:web/web.dart' as web;
|
||||
|
||||
Future<bool> downloadBytes(Uint8List bytes, {required String filename}) async {
|
||||
try {
|
||||
final blob = html.Blob([bytes], 'application/pdf');
|
||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||
// Use a data URL to avoid Blob/typed array interop issues under Wasm GC.
|
||||
final url = 'data:application/pdf;base64,${base64Encode(bytes)}';
|
||||
|
||||
// Create an anchor element and trigger a click to download
|
||||
final anchor =
|
||||
html.document.createElement('a') as html.AnchorElement
|
||||
web.HTMLAnchorElement()
|
||||
..href = url
|
||||
..download = filename
|
||||
..style.display = 'none';
|
||||
html.document.body?.children.add(anchor);
|
||||
|
||||
web.document.body?.append(anchor);
|
||||
anchor.click();
|
||||
anchor.remove();
|
||||
html.Url.revokeObjectUrl(url);
|
||||
|
||||
return true;
|
||||
} catch (_) {
|
||||
} catch (e, st) {
|
||||
debugPrint('Error: downloadBytes failed: $e\n$st');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ dependencies:
|
|||
responsive_framework: ^1.5.1
|
||||
# disable_web_context_menu: ^1.1.0
|
||||
# ml_linalg: ^13.12.6
|
||||
web: ^1.1.1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue