Skip to content

Commit d4f2210

Browse files
Implemented mentioned users in sent message
1 parent 696d234 commit d4f2210

File tree

3 files changed

+95
-8
lines changed

3 files changed

+95
-8
lines changed

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ open class MessageComposerViewModel: ObservableObject {
5353
}
5454
selectedRangeLocation = 0
5555
suggestions = [String: Any]()
56+
mentionedUsers = Set<ChatUser>()
5657
}
5758
}
5859
}
@@ -136,6 +137,8 @@ open class MessageComposerViewModel: ObservableObject {
136137
with: channelController
137138
)
138139

140+
private(set) var mentionedUsers = Set<ChatUser>()
141+
139142
private var messageText: String {
140143
if let composerCommand = composerCommand,
141144
let displayInfo = composerCommand.displayInfo,
@@ -187,6 +190,9 @@ open class MessageComposerViewModel: ObservableObject {
187190
}
188191
}
189192

193+
clearRemovedMentions()
194+
let mentionedUserIds = mentionedUsers.map(\.id)
195+
190196
if let editedMessage = editedMessage {
191197
edit(message: editedMessage, completion: completion)
192198
return
@@ -213,6 +219,7 @@ open class MessageComposerViewModel: ObservableObject {
213219
messageController.createNewReply(
214220
text: messageText,
215221
attachments: attachments,
222+
mentionedUserIds: mentionedUserIds,
216223
showReplyInChannel: showReplyInChannel,
217224
quotedMessageId: quotedMessage?.id
218225
) { [weak self] in
@@ -227,6 +234,7 @@ open class MessageComposerViewModel: ObservableObject {
227234
channelController.createNewMessage(
228235
text: messageText,
229236
attachments: attachments,
237+
mentionedUserIds: mentionedUserIds,
230238
quotedMessageId: quotedMessage?.id
231239
) { [weak self] in
232240
switch $0 {
@@ -404,16 +412,40 @@ open class MessageComposerViewModel: ObservableObject {
404412
command: Binding<ComposerCommand?>,
405413
extraData: [String: Any]
406414
) {
415+
let commandId = command.wrappedValue?.id
407416
commandsHandler.handleCommand(
408417
for: text,
409418
selectedRangeLocation: selectedRangeLocation,
410419
command: command,
411420
extraData: extraData
412421
)
422+
checkForMentionedUsers(
423+
commandId: commandId,
424+
extraData: extraData
425+
)
413426
}
414427

415428
// MARK: - private
416429

430+
private func checkForMentionedUsers(
431+
commandId: String?,
432+
extraData: [String: Any]
433+
) {
434+
guard commandId == "mentions",
435+
let user = extraData["chatUser"] as? ChatUser else {
436+
return
437+
}
438+
mentionedUsers.insert(user)
439+
}
440+
441+
private func clearRemovedMentions() {
442+
for user in mentionedUsers {
443+
if !text.contains("@\(user.mentionText)") {
444+
mentionedUsers.remove(user)
445+
}
446+
}
447+
}
448+
417449
private func edit(
418450
message: ChatMessage,
419451
completion: @escaping () -> Void
@@ -443,6 +475,7 @@ open class MessageComposerViewModel: ObservableObject {
443475
addedFileURLs = []
444476
addedCustomAttachments = []
445477
composerCommand = nil
478+
mentionedUsers = Set<ChatUser>()
446479
clearText()
447480
}
448481

Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/InstantCommands/TwoStepMentionCommand.swift

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ open class TwoStepMentionCommand: CommandHandler {
8888
selectedUser != nil
8989
}
9090

91-
private func mentionText(for user: ChatUser) -> String {
92-
if let name = user.name, !name.isEmpty {
93-
return "\(mentionSymbol)\(name)"
94-
} else {
95-
return "\(mentionSymbol)\(user.id)"
96-
}
97-
}
98-
9991
public func commandHandler(for command: ComposerCommand) -> CommandHandler? {
10092
if let selectedUser = selectedUser,
10193
command.typingSuggestion.text != "\(mentionSymbol)\(selectedUser.mentionText)" {

StreamChatSwiftUITests/Tests/ChatChannel/MessageComposerViewModel_Tests.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,68 @@ class MessageComposerViewModel_Tests: StreamChatTestCase {
490490
XCTAssert(viewModel.addedAssets.isEmpty)
491491
}
492492

493+
func test_messageComposerVM_mentionUsers() {
494+
// Given
495+
let viewModel = makeComposerViewModel()
496+
let command = ComposerCommand(
497+
id: "mentions",
498+
typingSuggestion: TypingSuggestion(text: "Hey @Martin", locationRange: NSRange(location: 0, length: 11)),
499+
displayInfo: nil
500+
)
501+
let user = ChatUser.mock(id: .unique, name: "Martin")
502+
503+
// When
504+
viewModel.handleCommand(
505+
for: .constant("Hey @Martin"),
506+
selectedRangeLocation: .constant(11),
507+
command: .constant(command),
508+
extraData: ["chatUser": user]
509+
)
510+
511+
// Then
512+
XCTAssert(viewModel.mentionedUsers.count == 1)
513+
XCTAssert(viewModel.mentionedUsers.first?.name == "Martin")
514+
}
515+
516+
func test_messageComposerVM_noMentionedUsers() {
517+
// Given
518+
let viewModel = makeComposerViewModel()
519+
520+
// When
521+
viewModel.handleCommand(
522+
for: .constant("Hey Martin"),
523+
selectedRangeLocation: .constant(10),
524+
command: .constant(nil),
525+
extraData: [:]
526+
)
527+
528+
// Then
529+
XCTAssert(viewModel.mentionedUsers.isEmpty)
530+
}
531+
532+
func test_messageComposerVM_mentionedUsersClearText() {
533+
// Given
534+
let viewModel = makeComposerViewModel()
535+
let command = ComposerCommand(
536+
id: "mentions",
537+
typingSuggestion: TypingSuggestion(text: "Hey @Martin", locationRange: NSRange(location: 0, length: 11)),
538+
displayInfo: nil
539+
)
540+
let user = ChatUser.mock(id: .unique, name: "Martin")
541+
542+
// When
543+
viewModel.handleCommand(
544+
for: .constant("Hey @Martin"),
545+
selectedRangeLocation: .constant(11),
546+
command: .constant(command),
547+
extraData: ["chatUser": user]
548+
)
549+
viewModel.text = ""
550+
551+
// Then
552+
XCTAssert(viewModel.mentionedUsers.isEmpty)
553+
}
554+
493555
// MARK: - private
494556

495557
private func makeComposerViewModel() -> MessageComposerViewModel {

0 commit comments

Comments
 (0)