Matthias Nott
2026-03-22 69c37c43074ad20ab9c7a5b7f4464863c4d298d4
lib/widgets/message_bubble.dart
....@@ -1,5 +1,6 @@
11 import 'dart:convert';
22 import 'dart:math';
3
+import 'dart:typed_data';
34
45 import 'package:flutter/material.dart';
56 import 'package:flutter/services.dart';
....@@ -8,6 +9,9 @@
89 import '../models/message.dart';
910 import '../theme/app_theme.dart';
1011 import 'image_viewer.dart';
12
+
13
+// Cache decoded image bytes to prevent flicker on widget rebuild
14
+final Map<String, Uint8List> _imageCache = {};
1115
1216 /// Chat message bubble with support for text, voice, and image types.
1317 class MessageBubble extends StatelessWidget {
....@@ -208,11 +212,13 @@
208212 return const Text('Image unavailable');
209213 }
210214
211
- final bytes = base64Decode(
212
- message.imageBase64!.contains(',')
213
- ? message.imageBase64!.split(',').last
214
- : message.imageBase64!,
215
- );
215
+ // Cache decoded bytes to prevent flicker on rebuild
216
+ final bytes = _imageCache.putIfAbsent(message.id, () {
217
+ final raw = message.imageBase64!;
218
+ return Uint8List.fromList(base64Decode(
219
+ raw.contains(',') ? raw.split(',').last : raw,
220
+ ));
221
+ });
216222
217223 return Column(
218224 crossAxisAlignment: CrossAxisAlignment.start,
....@@ -232,6 +238,7 @@
232238 width: 260,
233239 height: 180,
234240 fit: BoxFit.cover,
241
+ gaplessPlayback: true,
235242 errorBuilder: (_, e, st) => const SizedBox(
236243 width: 260,
237244 height: 60,