Skip to content

Commit ff442ca

Browse files
committed
Improve the composer view model code by having a fillDraftMessage and a computed draftMessage property
1 parent 23f57c5 commit ff442ca

File tree

4 files changed

+64
-39
lines changed

4 files changed

+64
-39
lines changed

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
215215
viewModel.selectedRangeLocation = editedMessage?.text.count ?? 0
216216
}
217217
}
218+
.onAppear(perform: {
219+
viewModel.fillDraftMessage()
220+
})
218221
.onDisappear(perform: {
219222
viewModel.updateDraftMessage(quotedMessage: quotedMessage)
220223
})

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,11 @@ open class MessageComposerViewModel: ObservableObject {
124124
}
125125
}
126126

127-
@Published public var draftMessage: DraftMessage? {
128-
didSet {
129-
if let draftMessage = draftMessage {
130-
DispatchQueue.main.async {
131-
self.fillDraftMessage(draftMessage)
132-
}
133-
}
127+
public var draftMessage: DraftMessage? {
128+
if let messageController {
129+
return messageController.message?.draftReply
134130
}
131+
return channelController.channel?.draftMessage
135132
}
136133

137134
@Published public var filePickerShown = false
@@ -228,12 +225,6 @@ open class MessageComposerViewModel: ObservableObject {
228225
self.eventsController = eventsController ?? channelController.client.eventsController()
229226
self.quotedMessage = quotedMessage
230227

231-
if let messageController {
232-
draftMessage = messageController.message?.draftReply
233-
} else {
234-
draftMessage = channelController.channel?.draftMessage
235-
}
236-
237228
self.eventsController.delegate = self
238229

239230
listenToCooldownUpdates()
@@ -246,7 +237,12 @@ open class MessageComposerViewModel: ObservableObject {
246237
)
247238
}
248239

249-
public func fillDraftMessage(_ message: DraftMessage) {
240+
/// Populates the draft message in the composer with the current controller's draft information.
241+
public func fillDraftMessage() {
242+
guard let message = draftMessage else {
243+
return
244+
}
245+
250246
text = message.text
251247
mentionedUsers = message.mentionedUsers
252248
quotedMessage?.wrappedValue = message.quotedMessage
@@ -274,6 +270,7 @@ open class MessageComposerViewModel: ObservableObject {
274270
}
275271
}
276272

273+
/// Updates the draft message locally and on the server.
277274
public func updateDraftMessage(
278275
quotedMessage: ChatMessage?,
279276
isSilent: Bool = false,
@@ -775,14 +772,12 @@ open class MessageComposerViewModel: ObservableObject {
775772
/// Same as clearText() but it just clears the command id.
776773
private func clearCommandText() {
777774
guard let command = composerCommand else { return }
778-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
779-
guard let currentText = self?.text else { return }
780-
if let value = self?.getValueOfCommand(currentText) {
781-
self?.text = value
782-
return
783-
}
784-
self?.text = ""
775+
let currentText = text
776+
if let value = getValueOfCommand(currentText) {
777+
text = value
778+
return
785779
}
780+
text = ""
786781
}
787782

788783
private func getValueOfCommand(_ currentText: String) -> String? {
@@ -838,7 +833,7 @@ extension MessageComposerViewModel: EventsControllerDelegate {
838833
let isFromSameThread = messageController?.messageId == event.draftMessage.threadId
839834
let isFromSameChannel = channelController.cid == event.cid && messageController == nil
840835
if isFromSameThread || isFromSameChannel {
841-
draftMessage = event.draftMessage
836+
fillDraftMessage()
842837
}
843838
}
844839
}

StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,26 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
695695

696696
// MARK: - Draft Message Tests
697697

698+
func test_messageComposerVM_command() {
699+
// Given
700+
let draftMessage = DraftMessage.mock(text: "/giphy text")
701+
let channelController = makeChannelController()
702+
channelController.channel_mock = .mock(
703+
cid: channelController.cid!,
704+
config: ChannelConfig(commands: [Command(name: "giphy", description: "", set: "", args: "")]),
705+
draftMessage: draftMessage
706+
)
707+
let viewModel = makeComposerDraftsViewModel(
708+
channelController: channelController,
709+
messageController: nil
710+
)
711+
viewModel.fillDraftMessage()
712+
713+
// When
714+
XCTAssertEqual(viewModel.composerCommand?.id, "/giphy")
715+
XCTAssertEqual(viewModel.text, "text")
716+
}
717+
698718
func test_messageComposerVM_updateDraftMessage() {
699719
// Given
700720
let channelController = makeChannelController()
@@ -738,15 +758,15 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
738758

739759
func test_messageComposerVM_whenTextErased_shouldDeleteDraftMessage() {
740760
// Given
761+
let draftMessage = DraftMessage.mock(text: "text")
741762
let channelController = makeChannelController()
763+
channelController.channel_mock = .mock(cid: channelController.cid!, draftMessage: draftMessage)
742764
let viewModel = makeComposerDraftsViewModel(
743765
channelController: channelController,
744766
messageController: nil
745767
)
746-
let draftMessage = DraftMessage.mock(text: "text")
747768

748769
// When
749-
viewModel.draftMessage = draftMessage
750770
viewModel.text = ""
751771

752772
// Then
@@ -761,14 +781,14 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
761781
cid: .unique,
762782
messageId: .unique
763783
)
784+
let draftMessage = DraftMessage.mock(text: "reply")
785+
messageController.message_mock = .mock(draftReply: draftMessage)
764786
let viewModel = makeComposerDraftsViewModel(
765787
channelController: channelController,
766788
messageController: messageController
767789
)
768-
let draftMessage = DraftMessage.mock(text: "reply")
769790

770791
// When
771-
viewModel.draftMessage = draftMessage
772792
viewModel.text = ""
773793

774794
// Then
@@ -778,14 +798,14 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
778798
func test_messageComposerVM_whenMessagePublished_deleteDraftMessage() {
779799
// Given
780800
let channelController = makeChannelController()
801+
let draftMessage = DraftMessage.mock(text: "text")
802+
channelController.channel_mock = .mock(cid: channelController.cid!, draftMessage: draftMessage)
781803
let viewModel = makeComposerDraftsViewModel(
782804
channelController: channelController,
783805
messageController: nil
784806
)
785-
let draftMessage = DraftMessage.mock(text: "text")
786807

787808
// When
788-
viewModel.draftMessage = draftMessage
789809
viewModel.sendMessage(quotedMessage: nil, editedMessage: nil) {}
790810

791811
// Then
@@ -801,14 +821,14 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
801821
cid: .unique,
802822
messageId: .unique
803823
)
824+
let draftMessage = DraftMessage.mock(text: "reply")
825+
messageController.message_mock = .mock(draftReply: draftMessage)
804826
let viewModel = makeComposerDraftsViewModel(
805827
channelController: channelController,
806828
messageController: messageController
807829
)
808-
let draftMessage = DraftMessage.mock(text: "reply")
809830

810831
// When
811-
viewModel.draftMessage = draftMessage
812832
viewModel.sendMessage(quotedMessage: nil, editedMessage: nil) {}
813833

814834
// Then
@@ -818,20 +838,21 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
818838
func test_messageComposerVM_draftMessageUpdatedEvent() throws {
819839
// Given
820840
let channelController = makeChannelController()
841+
channelController.channel_mock = .mock(cid: .unique, draftMessage: .mock(text: "Draft"))
821842
let viewModel = makeComposerDraftsViewModel(
822843
channelController: channelController,
823844
messageController: nil
824845
)
825-
viewModel.draftMessage = .mock(text: "Draft")
826846

827847
// When
828848
let draftMessage = DraftMessage.mock(text: "Draft from event")
849+
channelController.channel_mock = .mock(cid: .unique, draftMessage: draftMessage)
829850
let cid = try XCTUnwrap(channelController.cid)
830851
let event = DraftUpdatedEvent(cid: cid, channel: .mock(cid: cid), draftMessage: draftMessage, createdAt: .unique)
831852
viewModel.eventsController(viewModel.eventsController, didReceiveEvent: event)
832853

833854
// Then
834-
XCTAssertEqual(viewModel.draftMessage?.text, "Draft from event")
855+
XCTAssertEqual(viewModel.text, "Draft from event")
835856
}
836857

837858
func test_messageComposerVM_draftReplyUpdatedEvent() throws {
@@ -842,23 +863,24 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
842863
cid: channelController.cid!,
843864
messageId: .unique
844865
)
866+
messageController.message_mock = .mock(draftReply: .mock(text: "Draft"))
845867
let viewModel = makeComposerDraftsViewModel(
846868
channelController: channelController,
847869
messageController: messageController
848870
)
849-
viewModel.draftMessage = .mock(text: "Draft")
850871

851872
// When
852873
let draftMessage = DraftMessage.mock(
853874
threadId: messageController.messageId,
854875
text: "Draft reply from event"
855876
)
877+
messageController.message_mock = .mock(draftReply: draftMessage)
856878
let cid = try XCTUnwrap(channelController.cid)
857879
let event = DraftUpdatedEvent(cid: cid, channel: .mock(cid: cid), draftMessage: draftMessage, createdAt: .unique)
858880
viewModel.eventsController(viewModel.eventsController, didReceiveEvent: event)
859881

860882
// Then
861-
XCTAssertEqual(viewModel.draftMessage?.text, "Draft reply from event")
883+
XCTAssertEqual(viewModel.text, "Draft reply from event")
862884
}
863885

864886
func test_messageComposerVM_draftReplyUpdatedEventFromOtherThread_shouldNotUpdate() throws {
@@ -869,23 +891,25 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
869891
cid: channelController.cid!,
870892
messageId: .unique
871893
)
894+
messageController.message_mock = .mock(draftReply: .mock(text: "Draft"))
872895
let viewModel = makeComposerDraftsViewModel(
873896
channelController: channelController,
874897
messageController: messageController
875898
)
876-
viewModel.draftMessage = .mock(text: "Draft")
899+
viewModel.fillDraftMessage()
877900

878901
// When
879902
let draftMessage = DraftMessage.mock(
880903
threadId: .unique,
881904
text: "Draft reply from event"
882905
)
906+
messageController.message_mock = .mock(draftReply: draftMessage)
883907
let cid = try XCTUnwrap(channelController.cid)
884908
let event = DraftUpdatedEvent(cid: cid, channel: .mock(cid: cid), draftMessage: draftMessage, createdAt: .unique)
885909
viewModel.eventsController(viewModel.eventsController, didReceiveEvent: event)
886910

887911
// Then
888-
XCTAssertEqual(viewModel.draftMessage?.text, "Draft")
912+
XCTAssertEqual(viewModel.text, "Draft")
889913
}
890914

891915
// MARK: - private

StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerView_Tests.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -576,15 +576,18 @@ class MessageComposerView_Tests: StreamChatTestCase {
576576
private func makeComposerView(with draftMessage: DraftMessage) -> some View {
577577
let factory = DefaultViewFactory.shared
578578
let channelController = ChatChannelTestHelpers.makeChannelController(chatClient: chatClient)
579+
channelController.channel_mock = .mock(
580+
cid: .unique,
581+
config: ChannelConfig(commands: [Command(name: "giphy", description: "", set: "", args: "")]),
582+
draftMessage: draftMessage
583+
)
579584
let viewModel = MessageComposerViewModel(channelController: channelController, messageController: nil)
580-
viewModel.fillDraftMessage(draftMessage)
581585

582-
var quotedMessage: ChatMessage?
583586
return MessageComposerView(
584587
viewFactory: factory,
585588
viewModel: viewModel,
586589
channelController: channelController,
587-
quotedMessage: .init(get: { quotedMessage }, set: { quotedMessage = $0 }),
590+
quotedMessage: .constant(nil),
588591
editedMessage: .constant(nil),
589592
onMessageSent: {}
590593
)

0 commit comments

Comments
 (0)