From c9739ac4a22733d45167173446c1d3ce65a767eb Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sat, 11 Apr 2026 09:39:07 +0200
Subject: [PATCH] feat: inline PDF viewer with pinch-to-zoom
---
lib/widgets/message_bubble.dart | 23 +++++++++++++++++++++--
1 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/lib/widgets/message_bubble.dart b/lib/widgets/message_bubble.dart
index df9e238..63bbac4 100644
--- a/lib/widgets/message_bubble.dart
+++ b/lib/widgets/message_bubble.dart
@@ -14,6 +14,7 @@
import '../models/message.dart';
import '../theme/app_theme.dart';
import 'image_viewer.dart';
+import 'pdf_viewer.dart';
// Cache decoded image bytes to prevent flicker on widget rebuild
final Map<String, Uint8List> _imageCache = {};
@@ -425,15 +426,33 @@
if (data == null || data.isEmpty) return;
try {
- final bytes = base64Decode(data.contains(',') ? data.split(',').last : data);
+ final bytes = Uint8List.fromList(
+ base64Decode(data.contains(',') ? data.split(',').last : data),
+ );
final mime = message.mimeType ?? 'application/octet-stream';
+
+ // PDFs: open inline viewer
+ if (mime == 'application/pdf') {
+ if (context.mounted) {
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (_) => PdfViewerScreen(
+ pdfBytes: bytes,
+ title: message.content.isNotEmpty ? message.content : 'PDF',
+ ),
+ ),
+ );
+ }
+ return;
+ }
+
+ // Other files: save to temp and share
final ext = _mimeToExt(mime);
final dir = await getTemporaryDirectory();
final fileName = '${message.content.isNotEmpty ? message.content.replaceAll(RegExp(r'[^\w\s.-]'), '').trim() : 'file'}.$ext';
final file = File('${dir.path}/$fileName');
await file.writeAsBytes(bytes);
- // Use share sheet — works for PDFs, Office docs, and all file types on iOS
await SharePlus.instance.share(
ShareParams(files: [XFile(file.path, mimeType: mime)]),
);
--
Gitblit v1.3.1