Skip to content

Commit 6295145

Browse files
added code docs
1 parent 7431319 commit 6295145

File tree

11 files changed

+142
-43
lines changed

11 files changed

+142
-43
lines changed

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -132,19 +132,20 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
132132
}
133133
}
134134
.overlay(
135-
viewModel.composerCommand != nil ? CommandsContainerView(
136-
suggestions: viewModel.suggestions,
137-
handleCommand: { commandInfo in
138-
viewModel.handleCommand(
139-
for: $viewModel.text,
140-
selectedRangeLocation: $viewModel.selectedRangeLocation,
141-
command: $viewModel.composerCommand,
142-
extraData: commandInfo
143-
)
144-
}
145-
)
146-
.offset(y: -composerHeight)
147-
.animation(nil) : nil,
135+
viewModel.composerCommand != nil ?
136+
factory.makeCommandsContainerView(
137+
suggestions: viewModel.suggestions,
138+
handleCommand: { commandInfo in
139+
viewModel.handleCommand(
140+
for: $viewModel.text,
141+
selectedRangeLocation: $viewModel.selectedRangeLocation,
142+
command: $viewModel.composerCommand,
143+
extraData: commandInfo
144+
)
145+
}
146+
)
147+
.offset(y: -composerHeight)
148+
.animation(nil) : nil,
148149
alignment: .bottom
149150
)
150151
.alert(isPresented: $viewModel.errorShown) {

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import SwiftUI
1010
/// View model for the `MessageComposerView`.
1111
public class MessageComposerViewModel: ObservableObject {
1212
@Injected(\.chatClient) private var chatClient
13+
@Injected(\.utils) private var utils
1314

1415
@Published var pickerState: AttachmentPickerState = .photos {
1516
didSet {
@@ -89,19 +90,19 @@ public class MessageComposerViewModel: ObservableObject {
8990
private let channelController: ChatChannelController
9091
private var messageController: ChatMessageController?
9192

92-
private let mentionsSuggester: MentionsSuggester
9393
private var cancellables = Set<AnyCancellable>()
94-
private lazy var commandsHandler = CommandsHandler(commands: [
95-
MentionsSuggester(channelController: channelController)
96-
])
94+
private lazy var commandsHandler = utils
95+
.commandsConfig
96+
.makeCommandsHandler(
97+
with: channelController
98+
)
9799

98100
public init(
99101
channelController: ChatChannelController,
100102
messageController: ChatMessageController?
101103
) {
102104
self.channelController = channelController
103105
self.messageController = messageController
104-
mentionsSuggester = MentionsSuggester(channelController: channelController)
105106
}
106107

107108
public func sendMessage(
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// Copyright © 2021 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import Foundation
6+
import StreamChat
7+
8+
/// Configuration for the commands in the composer.
9+
public protocol CommandsConfig {
10+
11+
/// Creates the main commands handler.
12+
/// - Parameter channelController: the controller of the channel.
13+
/// - Returns: `CommandsHandler`.
14+
func makeCommandsHandler(
15+
with channelController: ChatChannelController
16+
) -> CommandsHandler
17+
}
18+
19+
/// Default commands configuration.
20+
public struct DefaultCommandsConfig: CommandsConfig {
21+
22+
public init() {}
23+
24+
public func makeCommandsHandler(
25+
with channelController: ChatChannelController
26+
) -> CommandsHandler {
27+
let mentionsCommand = MentionsCommandHandler(
28+
channelController: channelController,
29+
commandSymbol: "@",
30+
mentionAllAppUsers: false
31+
)
32+
return CommandsHandler(commands: [mentionsCommand])
33+
}
34+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import StreamChat
66
import SwiftUI
77

8+
/// Default implementation of the commands container.
89
struct CommandsContainerView: View {
910

1011
var suggestions: [String: Any]

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

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,35 @@ import Combine
66
import StreamChat
77
import SwiftUI
88

9-
protocol CommandHandler {
9+
/// Defines methods for handling commands.
10+
public protocol CommandHandler {
1011

12+
/// Identifier of the command.
1113
var id: String { get }
1214

15+
/// Checks whether the command can be handled.
16+
/// - Parameters:
17+
/// - text: the user entered text.
18+
/// - caretLocation: the end location of a selected text range.
19+
/// - Returns: optional `ComposerCommand` (if the handler can handle the command).
1320
func canHandleCommand(
1421
in text: String,
1522
caretLocation: Int
1623
) -> ComposerCommand?
1724

25+
/// Shows suggestions for the provided command.
26+
/// - Parameter command: the command whose suggestions will be shown.
27+
/// - Returns: `Future` with the suggestions, or an error.
1828
func showSuggestions(
1929
for command: ComposerCommand
2030
) -> Future<SuggestionInfo, Error>
2131

32+
/// Handles the provided command.
33+
/// - Parameters:
34+
/// - text: the user entered text.
35+
/// - selectedRangeLocation: the end location of the selected text.
36+
/// - command: binding of the command.
37+
/// - extraData: additional data that can be passed from the command.
2238
func handleCommand(
2339
for text: Binding<String>,
2440
selectedRangeLocation: Binding<Int>,
@@ -27,26 +43,34 @@ protocol CommandHandler {
2743
)
2844
}
2945

30-
struct ComposerCommand {
46+
/// Model for the composer's commands.
47+
public struct ComposerCommand {
48+
/// Identifier of the command.
3149
let id: String
50+
/// Typing suggestion that invokes the command.
3251
let typingSuggestion: TypingSuggestion
3352
}
3453

35-
struct SuggestionInfo {
54+
/// Provides information about the suggestion.
55+
public struct SuggestionInfo {
56+
/// Identifies the suggestion.
3657
let key: String
58+
/// Any value that can be passed to the suggestion.
3759
let value: Any
3860
}
3961

40-
class CommandsHandler: CommandHandler {
62+
/// Main commands handler - decides which commands to invoke.
63+
/// Command is matched if there's an id matching.
64+
public class CommandsHandler: CommandHandler {
4165

4266
private let commands: [CommandHandler]
43-
let id: String = "main"
67+
public let id: String = "main"
4468

4569
init(commands: [CommandHandler]) {
4670
self.commands = commands
4771
}
4872

49-
func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
73+
public func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
5074
for command in commands {
5175
if let composerCommand = command.canHandleCommand(
5276
in: text,
@@ -59,7 +83,7 @@ class CommandsHandler: CommandHandler {
5983
return nil
6084
}
6185

62-
func showSuggestions(
86+
public func showSuggestions(
6387
for command: ComposerCommand
6488
) -> Future<SuggestionInfo, Error> {
6589
for handler in commands {
@@ -71,7 +95,7 @@ class CommandsHandler: CommandHandler {
7195
return StreamChatError.wrongConfig.asFailedPromise()
7296
}
7397

74-
func handleCommand(
98+
public func handleCommand(
7599
for text: Binding<String>,
76100
selectedRangeLocation: Binding<Int>,
77101
command: Binding<ComposerCommand?>,

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
import StreamChat
66
import SwiftUI
77

8-
struct MentionUsersView: View {
8+
/// View for the mentioned users.
9+
public struct MentionUsersView: View {
910

1011
@Injected(\.colors) private var colors
1112

@@ -14,7 +15,7 @@ struct MentionUsersView: View {
1415
var users: [ChatUser]
1516
var userSelected: (ChatUser) -> Void
1617

17-
var body: some View {
18+
public var body: some View {
1819
ScrollView {
1920
LazyVStack {
2021
ForEach(users) { user in
@@ -42,14 +43,15 @@ struct MentionUsersView: View {
4243
}
4344
}
4445

45-
struct MentionUserView: View {
46+
/// View for one user that can be mentioned.
47+
public struct MentionUserView: View {
4648
@Injected(\.fonts) private var fonts
4749
@Injected(\.colors) private var colors
4850

4951
var user: ChatUser
5052
var userSelected: (ChatUser) -> Void
5153

52-
var body: some View {
54+
public var body: some View {
5355
HStack {
5456
MessageAvatarView(
5557
author: user,

Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/MentionsSuggester.swift renamed to Sources/StreamChatSwiftUI/ChatChannel/Composer/Suggestions/MentionsCommandHandler.swift

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,31 @@ import Combine
66
import StreamChat
77
import SwiftUI
88

9-
public struct MentionsSuggester: CommandHandler {
9+
/// Handles the mention command and provides suggestions.
10+
public struct MentionsCommandHandler: CommandHandler {
1011

11-
let id: String = "mentions"
12+
public let id: String
1213

13-
// TODO: read from config
14-
private var mentionAllAppUsers = false
15-
private let typingSuggester = TypingSuggester(options: .init(symbol: "@"))
14+
private let mentionAllAppUsers: Bool
15+
private let typingSuggester: TypingSuggester
1616

1717
private let channelController: ChatChannelController
1818
private let userSearchController: ChatUserSearchController
1919

20-
init(channelController: ChatChannelController) {
20+
init(
21+
channelController: ChatChannelController,
22+
commandSymbol: String,
23+
mentionAllAppUsers: Bool,
24+
id: String = "mentions"
25+
) {
26+
self.id = id
2127
self.channelController = channelController
28+
self.mentionAllAppUsers = mentionAllAppUsers
29+
typingSuggester = TypingSuggester(options: .init(symbol: commandSymbol))
2230
userSearchController = channelController.client.userSearchController()
2331
}
2432

25-
func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
33+
public func canHandleCommand(in text: String, caretLocation: Int) -> ComposerCommand? {
2634
if let suggestion = typingSuggester.typingSuggestion(
2735
in: text,
2836
caretLocation: caretLocation
@@ -33,7 +41,7 @@ public struct MentionsSuggester: CommandHandler {
3341
}
3442
}
3543

36-
func handleCommand(
44+
public func handleCommand(
3745
for text: Binding<String>,
3846
selectedRangeLocation: Binding<Int>,
3947
command: Binding<ComposerCommand?>,
@@ -57,7 +65,7 @@ public struct MentionsSuggester: CommandHandler {
5765
command.wrappedValue = nil
5866
}
5967

60-
func showSuggestions(
68+
public func showSuggestions(
6169
for command: ComposerCommand
6270
) -> Future<SuggestionInfo, Error> {
6371
showMentionSuggestions(

Sources/StreamChatSwiftUI/DefaultViewFactory.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,16 @@ extension ViewFactory {
507507
) -> some View {
508508
EditMessageHeaderView(editedMessage: editedMessage)
509509
}
510+
511+
public func makeCommandsContainerView(
512+
suggestions: [String: Any],
513+
handleCommand: @escaping ([String: Any]) -> Void
514+
) -> some View {
515+
CommandsContainerView(
516+
suggestions: suggestions,
517+
handleCommand: handleCommand
518+
)
519+
}
510520
}
511521

512522
/// Default class conforming to `ViewFactory`, used throughout the SDK.

Sources/StreamChatSwiftUI/Utils.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class Utils {
1717
public var channelAvatarsMerger: ChannelAvatarsMerging
1818
public var messageTypeResolver: MessageTypeResolving
1919
public var messageActionsResolver: MessageActionsResolving
20+
public var commandsConfig: CommandsConfig
2021

2122
public init(
2223
dateFormatter: DateFormatter = .makeDefault(),
@@ -28,6 +29,7 @@ public class Utils {
2829
channelAvatarsMerger: ChannelAvatarsMerging = ChannelAvatarsMerger(),
2930
messageTypeResolver: MessageTypeResolving = MessageTypeResolver(),
3031
messageActionResolver: MessageActionsResolving = MessageActionsResolver(),
32+
commandsConfig: CommandsConfig = DefaultCommandsConfig(),
3133
channelNamer: @escaping ChatChannelNamer = DefaultChatChannelNamer()
3234
) {
3335
self.dateFormatter = dateFormatter
@@ -40,5 +42,6 @@ public class Utils {
4042
self.channelAvatarsMerger = channelAvatarsMerger
4143
self.messageTypeResolver = messageTypeResolver
4244
messageActionsResolver = messageActionResolver
45+
self.commandsConfig = commandsConfig
4346
}
4447
}

Sources/StreamChatSwiftUI/ViewFactory.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,4 +482,15 @@ public protocol ViewFactory: AnyObject {
482482
func makeEditedMessageHeaderView(
483483
editedMessage: Binding<ChatMessage?>
484484
) -> EditedMessageHeaderViewType
485+
486+
associatedtype CommandsContainerViewType: View
487+
/// Creates the commands container view, above the composer.
488+
/// - Parameters:
489+
/// - suggestions: key-value based suggestions, depending on the command type.
490+
/// - handleCommand: should be invoked by views when a command is executed.
491+
/// - Returns: view displayed in the commands container slot.
492+
func makeCommandsContainerView(
493+
suggestions: [String: Any],
494+
handleCommand: @escaping ([String: Any]) -> Void
495+
) -> CommandsContainerViewType
485496
}

0 commit comments

Comments
 (0)