From 42cd2e88a07e18e9e962323f8930efea287c1f74 Mon Sep 17 00:00:00 2001 From: Xare123 <57245242+Xare123@users.noreply.github.com> Date: Sat, 15 Aug 2026 17:22:21 -0700 Subject: [PATCH] Keep composer drafts until queue acceptance --- .../widgets/message/send_animation.dart | 4 +- .../ui/chat/conversation_view_controller.dart | 6 +- .../conversation_view_controller_test.dart | 57 +++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 test/services/conversation_view_controller_test.dart diff --git a/lib/app/layouts/conversation_view/widgets/message/send_animation.dart b/lib/app/layouts/conversation_view/widgets/message/send_animation.dart index 5f4d73957d..4889aff814 100644 --- a/lib/app/layouts/conversation_view/widgets/message/send_animation.dart +++ b/lib/app/layouts/conversation_view/widgets/message/send_animation.dart @@ -148,7 +148,7 @@ class _SendAnimationState ], ); _message.generateTempGuid(); - outq.queue(OutgoingItem( + await outq.queue(OutgoingItem( type: QueueType.sendMessage, chat: controller.chat, message: _message, @@ -253,4 +253,4 @@ class _SendAnimationState ), ); } -} \ No newline at end of file +} diff --git a/lib/services/ui/chat/conversation_view_controller.dart b/lib/services/ui/chat/conversation_view_controller.dart index a26709b9cc..379660cd6c 100644 --- a/lib/services/ui/chat/conversation_view_controller.dart +++ b/lib/services/ui/chat/conversation_view_controller.dart @@ -260,7 +260,11 @@ class ConversationViewController extends StatefulController with GetSingleTicker } Future send(List attachments, AttributedBody text, String subject, String? replyGuid, int? replyPart, String? effectId, PayloadData? payload, bool isAudioMessage, DateTime? scheduledDate) async { - sendFunc?.call(Tuple7(attachments, text, subject, replyGuid, replyPart, effectId, payload), isAudioMessage, scheduledDate); + final callback = sendFunc; + if (callback == null) { + throw StateError("Conversation send handler is not ready"); + } + await callback(Tuple7(attachments, text, subject, replyGuid, replyPart, effectId, payload), isAudioMessage, scheduledDate); } void queueImage(Tuple4> item) { diff --git a/test/services/conversation_view_controller_test.dart b/test/services/conversation_view_controller_test.dart new file mode 100644 index 0000000000..a1b737145d --- /dev/null +++ b/test/services/conversation_view_controller_test.dart @@ -0,0 +1,57 @@ +import 'dart:async'; + +import 'package:bluebubbles/database/models.dart'; +import 'package:bluebubbles/services/services.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('send waits for the composer handler to finish', () async { + final controller = + ConversationViewController(Chat(guid: 'iMessage;-;send-await-test')); + final handler = Completer(); + controller.sendFunc = (_, __, ___) => handler.future; + + var completed = false; + final sending = controller + .send( + [], + AttributedBody.raw('message'), + '', + null, + null, + null, + null, + false, + null, + ) + .then((_) => completed = true); + + await Future.delayed(Duration.zero); + expect(completed, isFalse); + + handler.complete(); + await sending; + expect(completed, isTrue); + }); + + test('send fails when the composer handler is not ready', () async { + final controller = + ConversationViewController(Chat(guid: 'iMessage;-;send-missing-test')); + + await expectLater( + controller.send( + [], + AttributedBody.raw('message'), + '', + null, + null, + null, + null, + false, + null, + ), + throwsStateError, + ); + }); +}