Skip to content

Commit d2b5ea5

Browse files
implemented selection of a command
1 parent c603666 commit d2b5ea5

File tree

4 files changed

+63
-51
lines changed

4 files changed

+63
-51
lines changed

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
132132
}
133133
}
134134
.overlay(
135-
viewModel.typingSuggestion != nil ? CommandsContainerView(
135+
viewModel.composerCommand != nil ? CommandsContainerView(
136136
suggestions: viewModel.suggestions,
137137
handleCommand: { commandInfo in
138138
viewModel.handleCommand(
139139
for: $viewModel.text,
140140
selectedRangeLocation: $viewModel.selectedRangeLocation,
141-
typingSuggestion: $viewModel.typingSuggestion,
141+
command: $viewModel.composerCommand,
142142
extraData: commandInfo
143143
)
144144
}

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class MessageComposerViewModel: ObservableObject {
3939
channelController.sendKeystrokeEvent()
4040
checkTypingSuggestions()
4141
} else {
42-
typingSuggestion = nil
42+
composerCommand = nil
4343
selectedRangeLocation = 0
4444
}
4545
}
@@ -78,7 +78,7 @@ public class MessageComposerViewModel: ObservableObject {
7878
}
7979
}
8080

81-
@Published var typingSuggestion: TypingSuggestion?
81+
@Published var composerCommand: ComposerCommand?
8282

8383
@Published var filePickerShown = false
8484
@Published var cameraPickerShown = false
@@ -307,32 +307,17 @@ public class MessageComposerViewModel: ObservableObject {
307307
func handleCommand(
308308
for text: Binding<String>,
309309
selectedRangeLocation: Binding<Int>,
310-
typingSuggestion: Binding<TypingSuggestion?>,
310+
command: Binding<ComposerCommand?>,
311311
extraData: [String: Any]
312312
) {
313313
commandsHandler.handleCommand(
314314
for: text,
315315
selectedRangeLocation: selectedRangeLocation,
316-
typingSuggestion: typingSuggestion,
316+
command: command,
317317
extraData: extraData
318318
)
319319
}
320320

321-
func mentionedUserSelected(_ chatUser: ChatUser) {
322-
guard let typingSuggestion = typingSuggestion else { return }
323-
let mentionText = self.mentionText(for: chatUser)
324-
let newText = (text as NSString).replacingCharacters(
325-
in: typingSuggestion.locationRange,
326-
with: mentionText
327-
)
328-
text = newText
329-
330-
let newCaretLocation =
331-
selectedRangeLocation + (mentionText.count - typingSuggestion.text.count)
332-
selectedRangeLocation = newCaretLocation
333-
self.typingSuggestion = nil
334-
}
335-
336321
// MARK: - private
337322

338323
private func mentionText(for user: ChatUser) -> String {
@@ -380,13 +365,13 @@ public class MessageComposerViewModel: ObservableObject {
380365
}
381366

382367
private func checkTypingSuggestions() {
383-
typingSuggestion = commandsHandler.canHandleCommand(
368+
composerCommand = commandsHandler.canHandleCommand(
384369
in: text,
385370
caretLocation: selectedRangeLocation
386371
)
387372

388-
if let typingSuggestion = typingSuggestion {
389-
commandsHandler.showSuggestions(for: typingSuggestion)
373+
if let composerCommand = composerCommand {
374+
commandsHandler.showSuggestions(for: composerCommand)
390375
.sink { [weak self] suggestionInfo in
391376
withAnimation {
392377
self?.suggestions[suggestionInfo.key] = suggestionInfo.value

Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/CommandsHandler.swift

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,30 @@ import SwiftUI
88

99
protocol CommandHandler {
1010

11+
var id: String { get }
12+
1113
func canHandleCommand(
1214
in text: String,
1315
caretLocation: Int
14-
) -> TypingSuggestion?
16+
) -> ComposerCommand?
1517

1618
func showSuggestions(
17-
for typingSuggestion: TypingSuggestion
19+
for command: ComposerCommand
1820
) -> Future<SuggestionInfo, Never>
1921

2022
func handleCommand(
2123
for text: Binding<String>,
2224
selectedRangeLocation: Binding<Int>,
23-
typingSuggestion: Binding<TypingSuggestion?>,
25+
command: Binding<ComposerCommand?>,
2426
extraData: [String: Any]
2527
)
2628
}
2729

30+
struct ComposerCommand {
31+
let id: String
32+
let typingSuggestion: TypingSuggestion
33+
}
34+
2835
struct SuggestionInfo {
2936
let key: String
3037
let value: Any
@@ -33,43 +40,54 @@ struct SuggestionInfo {
3340
class CommandsHandler: CommandHandler {
3441

3542
private let commands: [CommandHandler]
43+
let id: String = "main"
3644

3745
init(commands: [CommandHandler]) {
3846
self.commands = commands
3947
}
4048

41-
func canHandleCommand(in text: String, caretLocation: Int) -> TypingSuggestion? {
49+
func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
4250
for command in commands {
43-
if let suggestion = command.canHandleCommand(
51+
if let composerCommand = command.canHandleCommand(
4452
in: text,
4553
caretLocation: caretLocation
4654
) {
47-
return suggestion
55+
return composerCommand
4856
}
4957
}
5058

5159
return nil
5260
}
5361

5462
func showSuggestions(
55-
for typingSuggestion: TypingSuggestion
63+
for command: ComposerCommand
5664
) -> Future<SuggestionInfo, Never> {
57-
// TODO: picking of command
58-
commands.first!.showSuggestions(for: typingSuggestion)
65+
for handler in commands {
66+
if handler.id == command.id {
67+
return handler.showSuggestions(for: command)
68+
}
69+
}
70+
71+
// TODO: gracefully
72+
fatalError("misconfiguration of commands")
5973
}
6074

6175
func handleCommand(
6276
for text: Binding<String>,
6377
selectedRangeLocation: Binding<Int>,
64-
typingSuggestion: Binding<TypingSuggestion?>,
78+
command: Binding<ComposerCommand?>,
6579
extraData: [String: Any]
6680
) {
67-
// TODO: picking of command
68-
commands.first?.handleCommand(
69-
for: text,
70-
selectedRangeLocation: selectedRangeLocation,
71-
typingSuggestion: typingSuggestion,
72-
extraData: extraData
73-
)
81+
for handler in commands {
82+
let commandValue = command.wrappedValue
83+
if handler.id == commandValue?.id {
84+
handler.handleCommand(
85+
for: text,
86+
selectedRangeLocation: selectedRangeLocation,
87+
command: command,
88+
extraData: extraData
89+
)
90+
}
91+
}
7492
}
7593
}

Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/MentionsSuggester.swift

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import SwiftUI
88

99
public struct MentionsSuggester: CommandHandler {
1010

11+
let id: String = "mentions"
12+
1113
// TODO: read from config
1214
private var mentionAllAppUsers = false
1315
private let typingSuggester = TypingSuggester(options: .init(symbol: "@"))
@@ -20,18 +22,25 @@ public struct MentionsSuggester: CommandHandler {
2022
userSearchController = channelController.client.userSearchController()
2123
}
2224

23-
func canHandleCommand(in text: String, caretLocation: Int) -> TypingSuggestion? {
24-
typingSuggester.typingSuggestion(in: text, caretLocation: caretLocation)
25+
func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
26+
if let suggestion = typingSuggester.typingSuggestion(
27+
in: text,
28+
caretLocation: caretLocation
29+
) {
30+
return ComposerCommand(id: id, typingSuggestion: suggestion)
31+
} else {
32+
return nil
33+
}
2534
}
2635

2736
func handleCommand(
2837
for text: Binding<String>,
2938
selectedRangeLocation: Binding<Int>,
30-
typingSuggestion: Binding<TypingSuggestion?>,
39+
command: Binding<ComposerCommand?>,
3140
extraData: [String: Any]
3241
) {
3342
guard let chatUser = extraData["chatUser"] as? ChatUser,
34-
let typingSuggestionValue = typingSuggestion.wrappedValue else {
43+
let typingSuggestionValue = command.wrappedValue?.typingSuggestion else {
3544
return
3645
}
3746

@@ -45,15 +54,15 @@ public struct MentionsSuggester: CommandHandler {
4554
let newCaretLocation =
4655
selectedRangeLocation.wrappedValue + (mentionText.count - typingSuggestionValue.text.count)
4756
selectedRangeLocation.wrappedValue = newCaretLocation
48-
typingSuggestion.wrappedValue = nil
57+
command.wrappedValue = nil
4958
}
5059

5160
func showSuggestions(
52-
for typingSuggestion: TypingSuggestion
61+
for command: ComposerCommand
5362
) -> Future<SuggestionInfo, Never> {
5463
showMentionSuggestions(
55-
for: typingSuggestion.text,
56-
mentionRange: typingSuggestion.locationRange
64+
for: command.typingSuggestion.text,
65+
mentionRange: command.typingSuggestion.locationRange
5766
)
5867
}
5968

@@ -76,7 +85,7 @@ public struct MentionsSuggester: CommandHandler {
7685
by: typingMention,
7786
excludingId: currentUserId
7887
)
79-
let suggestionInfo = SuggestionInfo(key: "mentions", value: users)
88+
let suggestionInfo = SuggestionInfo(key: id, value: users)
8089
return resolve(with: suggestionInfo)
8190
}
8291
}
@@ -138,7 +147,7 @@ public struct MentionsSuggester: CommandHandler {
138147
let query = queryForMentionSuggestionsSearch(typingMention: typingMention)
139148
userSearchController.search(query: query) { _ in
140149
let users = Array(userSearchController.users)
141-
let suggestionInfo = SuggestionInfo(key: "mentions", value: users)
150+
let suggestionInfo = SuggestionInfo(key: id, value: users)
142151
promise(.success(suggestionInfo))
143152
}
144153
}

0 commit comments

Comments
 (0)