Matthias Nott
2026-03-23 1a2c703fbbb14c75bc41ad9341618ac7c72b3cc5
fix: file picker shows caption dialog before sending
1 files modified
changed files
lib/screens/chat_screen.dart patch | view | blame | history
lib/screens/chat_screen.dart
....@@ -678,38 +678,79 @@
678678 final bytes = await File(file.path!).readAsBytes();
679679 final b64 = base64Encode(bytes);
680680 final mimeType = _guessMimeType(file.name);
681
-
682681 attachments.add({
683682 'data': b64,
684683 'mimeType': mimeType,
685684 'fileName': file.name,
686685 });
686
+ }
687
+ if (attachments.isEmpty) return;
687688
688
- // Show in chat
689
- if (mimeType.startsWith('image/')) {
690
- ref.read(messagesProvider.notifier).addMessage(Message.image(
691
- role: MessageRole.user,
692
- imageBase64: b64,
693
- content: file.name,
694
- status: MessageStatus.sent,
695
- ));
696
- } else {
697
- ref.read(messagesProvider.notifier).addMessage(Message.text(
698
- role: MessageRole.user,
699
- content: 'šŸ“Ž ${file.name} (${_formatSize(bytes.length)})',
700
- status: MessageStatus.sent,
701
- ));
689
+ // Show caption dialog
690
+ final fileNames = result.files.map((f) => f.name).join(', ');
691
+ final caption = await _showCaptionDialog(result.files.length);
692
+ if (caption == null) return;
693
+
694
+ // Handle voice caption
695
+ String textCaption = caption;
696
+ String? voiceB64;
697
+ if (caption.startsWith('__voice__:')) {
698
+ final voicePath = caption.substring('__voice__:'.length);
699
+ final voiceFile = File(voicePath);
700
+ if (await voiceFile.exists()) {
701
+ voiceB64 = base64Encode(await voiceFile.readAsBytes());
702702 }
703
+ textCaption = '';
704
+ }
705
+
706
+ // Send voice first if present
707
+ if (voiceB64 != null) {
708
+ final voiceMsg = Message.voice(
709
+ role: MessageRole.user,
710
+ audioUri: caption.substring('__voice__:'.length),
711
+ status: MessageStatus.sent,
712
+ );
713
+ ref.read(messagesProvider.notifier).addMessage(voiceMsg);
714
+ _ws?.send({
715
+ 'type': 'voice',
716
+ 'audioBase64': voiceB64,
717
+ 'content': '',
718
+ 'messageId': voiceMsg.id,
719
+ 'sessionId': targetSessionId,
720
+ });
703721 }
704722
705723 // Send all files as one atomic bundle
706724 _ws?.send({
707725 'type': 'bundle',
708
- 'caption': '',
726
+ 'caption': textCaption,
709727 'attachments': attachments,
710728 'sessionId': targetSessionId,
711729 });
712730
731
+ // Show in chat
732
+ for (final att in attachments) {
733
+ final mime = att['mimeType'] as String;
734
+ final name = att['fileName'] as String? ?? 'file';
735
+ if (mime.startsWith('image/')) {
736
+ ref.read(messagesProvider.notifier).addMessage(Message.image(
737
+ role: MessageRole.user,
738
+ imageBase64: att['data'] as String,
739
+ content: name,
740
+ status: MessageStatus.sent,
741
+ ));
742
+ } else {
743
+ final size = base64Decode(att['data'] as String).length;
744
+ ref.read(messagesProvider.notifier).addMessage(Message.text(
745
+ role: MessageRole.user,
746
+ content: textCaption.isNotEmpty
747
+ ? '$textCaption\nšŸ“Ž $name (${_formatSize(size)})'
748
+ : 'šŸ“Ž $name (${_formatSize(size)})',
749
+ status: MessageStatus.sent,
750
+ ));
751
+ }
752
+ }
753
+
713754 _scrollToBottom();
714755 }
715756