Skip to content

Commit b27aa70

Browse files
Implemented channel config
2 parents 4f2f073 + 435db51 commit b27aa70

22 files changed

+330
-124
lines changed

Sources/StreamChatSwiftUI/ChatChannel/ChannelHeader/ChatChannelHeaderViewModifier.swift

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ public struct DefaultChatChannelHeader: ToolbarContent {
2525
chatClient.currentUserId ?? ""
2626
}
2727

28+
private var shouldShowTypingIndicator: Bool {
29+
!channel.currentlyTypingUsersFiltered(currentUserId: currentUserId).isEmpty
30+
&& utils.typingIndicatorPlacement == .navigationBar
31+
&& channel.config.typingEventsEnabled
32+
}
33+
34+
private var onlineIndicatorShown: Bool {
35+
!channel.lastActiveMembers.filter { member in
36+
member.id != chatClient.currentUserId && member.isOnline
37+
}
38+
.isEmpty
39+
}
40+
2841
public var channel: ChatChannel
2942
public var headerImage: UIImage
3043

@@ -33,8 +46,7 @@ public struct DefaultChatChannelHeader: ToolbarContent {
3346
VStack(spacing: 2) {
3447
Text(channelNamer(channel, currentUserId) ?? "")
3548
.font(fonts.bodyBold)
36-
if !channel.currentlyTypingUsersFiltered(currentUserId: currentUserId).isEmpty
37-
&& utils.typingIndicatorPlacement == .navigationBar {
49+
if shouldShowTypingIndicator {
3850
HStack {
3951
TypingIndicatorView()
4052
SubtitleText(text: channel.typingIndicatorString(currentUserId: currentUserId))
@@ -56,13 +68,6 @@ public struct DefaultChatChannelHeader: ToolbarContent {
5668
.offset(x: 8)
5769
}
5870
}
59-
60-
private var onlineIndicatorShown: Bool {
61-
!channel.lastActiveMembers.filter { member in
62-
member.id != chatClient.currentUserId && member.isOnline
63-
}
64-
.isEmpty
65-
}
6671
}
6772

6873
/// The default header modifier.

Sources/StreamChatSwiftUI/ChatChannel/Composer/AttachmentPickerTypeView.swift

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright © 2022 Stream.io Inc. All rights reserved.
33
//
44

5+
import StreamChat
56
import SwiftUI
67

78
/// Enum for the picker type state.
@@ -30,22 +31,31 @@ public struct AttachmentPickerTypeView: View {
3031
@Injected(\.colors) private var colors
3132

3233
@Binding var pickerTypeState: PickerTypeState
34+
var channelConfig: ChannelConfig?
35+
36+
private var commandsAvailable: Bool {
37+
channelConfig?.commands.count ?? 0 > 0
38+
}
3339

3440
public var body: some View {
3541
HStack(spacing: 16) {
3642
switch pickerTypeState {
3743
case let .expanded(attachmentPickerType):
38-
PickerTypeButton(
39-
pickerTypeState: $pickerTypeState,
40-
pickerType: .media,
41-
selected: attachmentPickerType
42-
)
44+
if channelConfig?.uploadsEnabled == true {
45+
PickerTypeButton(
46+
pickerTypeState: $pickerTypeState,
47+
pickerType: .media,
48+
selected: attachmentPickerType
49+
)
50+
}
4351

44-
PickerTypeButton(
45-
pickerTypeState: $pickerTypeState,
46-
pickerType: .instantCommands,
47-
selected: attachmentPickerType
48-
)
52+
if commandsAvailable {
53+
PickerTypeButton(
54+
pickerTypeState: $pickerTypeState,
55+
pickerType: .instantCommands,
56+
selected: attachmentPickerType
57+
)
58+
}
4959
case .collapsed:
5060
Button {
5161
withAnimation {

Sources/StreamChatSwiftUI/ChatChannel/Composer/ComposerTextInputView.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct ComposerTextInputView: UIViewRepresentable {
1212
@Binding var selectedRangeLocation: Int
1313

1414
var placeholder: String
15+
var maxMessageLength: Int?
1516

1617
func makeUIView(context: Context) -> InputTextView {
1718
let inputTextView = InputTextView()
@@ -34,16 +35,21 @@ struct ComposerTextInputView: UIViewRepresentable {
3435
}
3536

3637
func makeCoordinator() -> Coordinator {
37-
Coordinator(textInput: self)
38+
Coordinator(textInput: self, maxMessageLength: maxMessageLength)
3839
}
3940

4041
class Coordinator: NSObject, UITextViewDelegate, NSLayoutManagerDelegate {
4142
weak var textView: InputTextView?
4243

4344
var textInput: ComposerTextInputView
45+
var maxMessageLength: Int?
4446

45-
init(textInput: ComposerTextInputView) {
47+
init(
48+
textInput: ComposerTextInputView,
49+
maxMessageLength: Int?
50+
) {
4651
self.textInput = textInput
52+
self.maxMessageLength = maxMessageLength
4753
}
4854

4955
func textViewDidChange(_ textView: UITextView) {
@@ -56,7 +62,9 @@ struct ComposerTextInputView: UIViewRepresentable {
5662
shouldChangeTextIn range: NSRange,
5763
replacementText text: String
5864
) -> Bool {
59-
true
65+
guard let maxMessageLength = maxMessageLength else { return true }
66+
let newMessageLength = textView.text.count + (text.count - range.length)
67+
return newMessageLength <= maxMessageLength
6068
}
6169

6270
func layoutManager(

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerView.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
1515
@State private var composerHeight: CGFloat = 0
1616

1717
private var factory: Factory
18+
private var channelConfig: ChannelConfig?
1819
@Binding var quotedMessage: ChatMessage?
1920
@Binding var editedMessage: ChatMessage?
2021

@@ -27,6 +28,7 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
2728
onMessageSent: @escaping () -> Void
2829
) {
2930
factory = viewFactory
31+
channelConfig = channelController.channel?.config
3032
_viewModel = StateObject(
3133
wrappedValue: ViewModelsFactory.makeMessageComposerViewModel(
3234
with: channelController,
@@ -55,7 +57,10 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
5557
}
5658

5759
HStack(alignment: .bottom) {
58-
factory.makeLeadingComposerView(state: $viewModel.pickerTypeState)
60+
factory.makeLeadingComposerView(
61+
state: $viewModel.pickerTypeState,
62+
channelConfig: channelConfig
63+
)
5964

6065
factory.makeComposerInputView(
6166
text: $viewModel.text,
@@ -65,6 +70,7 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
6570
addedFileURLs: viewModel.addedFileURLs,
6671
addedCustomAttachments: viewModel.addedCustomAttachments,
6772
quotedMessage: $quotedMessage,
73+
maxMessageLength: channelConfig?.maxMessageLength,
6874
onCustomAttachmentTap: viewModel.customAttachmentTapped(_:),
6975
shouldScroll: viewModel.inputComposerShouldScroll,
7076
removeAttachmentWithId: viewModel.removeAttachment(with:)
@@ -135,7 +141,7 @@ public struct MessageComposerView<Factory: ViewFactory>: View, KeyboardReadable
135141
}
136142
}
137143
.overlay(
138-
viewModel.composerCommand != nil ?
144+
viewModel.showCommandsOverlay ?
139145
factory.makeCommandsContainerView(
140146
suggestions: viewModel.suggestions,
141147
handleCommand: { commandInfo in
@@ -174,6 +180,7 @@ public struct ComposerInputView<Factory: ViewFactory>: View {
174180
var addedFileURLs: [URL]
175181
var addedCustomAttachments: [CustomAttachment]
176182
var quotedMessage: Binding<ChatMessage?>
183+
var maxMessageLength: Int?
177184
var onCustomAttachmentTap: (CustomAttachment) -> Void
178185
var removeAttachmentWithId: (String) -> Void
179186

@@ -250,7 +257,8 @@ public struct ComposerInputView<Factory: ViewFactory>: View {
250257
text: $text,
251258
height: $textHeight,
252259
selectedRangeLocation: $selectedRangeLocation,
253-
placeholder: L10n.Composer.Placeholder.message
260+
placeholder: L10n.Composer.Placeholder.message,
261+
maxMessageLength: maxMessageLength
254262
)
255263
.frame(height: textFieldHeight)
256264
.overlay(

Sources/StreamChatSwiftUI/ChatChannel/Composer/MessageComposerViewModel.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ open class MessageComposerViewModel: ObservableObject {
239239
channelController.channel?.isDirectMessageChannel ?? false
240240
}
241241

242+
public var showCommandsOverlay: Bool {
243+
let commandAvailable = composerCommand != nil
244+
let configuredCommandsAvailable = channelController.channel?.config.commands.count ?? 0 > 0
245+
return commandAvailable && configuredCommandsAvailable
246+
}
247+
242248
public func change(pickerState: AttachmentPickerState) {
243249
if pickerState != self.pickerState {
244250
self.pickerState = pickerState

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

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,41 @@ public class DefaultCommandsConfig: CommandsConfig {
3333
public func makeCommandsHandler(
3434
with channelController: ChatChannelController
3535
) -> CommandsHandler {
36-
let mentionsCommand = MentionsCommandHandler(
36+
let mentionsCommandHandler = MentionsCommandHandler(
3737
channelController: channelController,
3838
commandSymbol: mentionsSymbol,
3939
mentionAllAppUsers: false
4040
)
41-
let giphyCommand = GiphyCommandHandler(commandSymbol: "/giphy")
42-
let muteCommand = MuteCommandHandler(
43-
channelController: channelController,
44-
commandSymbol: "/mute"
45-
)
46-
let unmuteCommand = UnmuteCommandHandler(
47-
channelController: channelController,
48-
commandSymbol: "/unmute"
49-
)
50-
let instantCommands = InstantCommandsHandler(
51-
commands: [giphyCommand, muteCommand, unmuteCommand]
41+
42+
var instantCommands = [CommandHandler]()
43+
44+
let channelConfig = channelController.channel?.config
45+
46+
let giphyEnabled = channelConfig?.commands.first(where: { command in
47+
command.name == "giphy"
48+
}) != nil
49+
50+
if giphyEnabled {
51+
let giphyCommand = GiphyCommandHandler(commandSymbol: "/giphy")
52+
instantCommands.append(giphyCommand)
53+
}
54+
55+
if channelConfig?.mutesEnabled == true {
56+
let muteCommand = MuteCommandHandler(
57+
channelController: channelController,
58+
commandSymbol: "/mute"
59+
)
60+
let unmuteCommand = UnmuteCommandHandler(
61+
channelController: channelController,
62+
commandSymbol: "/unmute"
63+
)
64+
instantCommands.append(muteCommand)
65+
instantCommands.append(unmuteCommand)
66+
}
67+
68+
let instantCommandsHandler = InstantCommandsHandler(
69+
commands: instantCommands
5270
)
53-
return CommandsHandler(commands: [mentionsCommand, instantCommands])
71+
return CommandsHandler(commands: [mentionsCommandHandler, instantCommandsHandler])
5472
}
5573
}

Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ struct MessageContainerView<Factory: ViewFactory>: View {
103103
coordinateSpace: .local
104104
)
105105
.updating($offset) { (value, gestureState, _) in
106-
if message.isDeleted {
106+
if message.isDeleted || !channel.config.repliesEnabled {
107107
return
108108
}
109109
// Using updating since onEnded is not called if the gesture is canceled.
@@ -138,15 +138,15 @@ struct MessageContainerView<Factory: ViewFactory>: View {
138138
}
139139

140140
if showsAllInfo && !message.isDeleted {
141-
if message.isSentByCurrentUser {
141+
if message.isSentByCurrentUser && channel.config.readEventsEnabled {
142142
HStack(spacing: 4) {
143143
factory.makeMessageReadIndicatorView(
144144
channel: channel,
145145
message: message
146146
)
147147
MessageDateView(message: message)
148148
}
149-
} else if isInGroup {
149+
} else if !message.isSentByCurrentUser && isInGroup {
150150
MessageAuthorAndDateView(message: message)
151151
} else {
152152
MessageDateView(message: message)
@@ -176,7 +176,9 @@ struct MessageContainerView<Factory: ViewFactory>: View {
176176
}
177177

178178
private var reactionsShown: Bool {
179-
!message.reactionScores.isEmpty && !message.isDeleted
179+
!message.reactionScores.isEmpty
180+
&& !message.isDeleted
181+
&& channel.config.reactionsEnabled
180182
}
181183

182184
private func dragChanged(to value: CGFloat) {

Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageListView.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ struct MessageListView<Factory: ViewFactory>: View, KeyboardReadable {
3535
utils.dateFormatter
3636
}
3737

38+
private var shouldShowTypingIndicator: Bool {
39+
!channel.currentlyTypingUsersFiltered(currentUserId: chatClient.currentUserId).isEmpty
40+
&& utils.typingIndicatorPlacement == .bottomOverlay
41+
&& channel.config.typingEventsEnabled
42+
}
43+
3844
private let scrollAreaId = "scrollArea"
3945

4046
var body: some View {
@@ -146,8 +152,7 @@ struct MessageListView<Factory: ViewFactory>: View, KeyboardReadable {
146152
DateIndicatorView(date: date)
147153
}
148154

149-
if !channel.currentlyTypingUsersFiltered(currentUserId: chatClient.currentUserId).isEmpty
150-
&& utils.typingIndicatorPlacement == .bottomOverlay {
155+
if shouldShowTypingIndicator {
151156
TypingIndicatorBottomView(
152157
typingIndicatorString: channel.typingIndicatorString(currentUserId: chatClient.currentUserId)
153158
)

0 commit comments

Comments
 (0)