Skip to content

Commit 07b400c

Browse files
Added scrolling for instant commands
1 parent b18cfbc commit 07b400c

File tree

6 files changed

+111
-18
lines changed

6 files changed

+111
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
55

66
### ✅ Added
77
- Support for custom message receipt states
8+
- Scrolling of instant commands
89

910
### 🔄 Changed
1011
- Updated Nuke dependency to 11.3.0 for SPM

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

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,40 +15,66 @@ struct InstantCommandsView: View {
1515
var instantCommands: [CommandHandler]
1616
var commandSelected: (ComposerCommand) -> Void
1717

18+
@State private var itemHeight: CGFloat = 40
19+
1820
var body: some View {
1921
VStack {
2022
InstantCommandsHeader()
2123
.standardPadding()
2224
.accessibilityElement(children: .contain)
2325

24-
ForEach(0..<instantCommands.count, id: \.self) { i in
25-
let command = instantCommands[i]
26-
if let displayInfo = command.displayInfo {
27-
InstantCommandView(displayInfo: displayInfo)
28-
.standardPadding()
29-
.highPriorityGesture(
30-
TapGesture()
31-
.onEnded { _ in
32-
let instantCommand = ComposerCommand(
33-
id: command.id,
34-
typingSuggestion: TypingSuggestion.empty,
35-
displayInfo: command.displayInfo,
36-
replacesMessageSent: command.replacesMessageSent
37-
)
38-
commandSelected(instantCommand)
26+
ScrollView {
27+
VStack {
28+
ForEach(0..<instantCommands.count, id: \.self) { i in
29+
let command = instantCommands[i]
30+
if let displayInfo = command.displayInfo {
31+
InstantCommandView(displayInfo: displayInfo)
32+
.standardPadding()
33+
.overlay(
34+
GeometryReader { geo in
35+
Color.clear.preference(key: HeightPreferenceKey.self, value: geo.size.height)
36+
}
37+
)
38+
.onPreferenceChange(HeightPreferenceKey.self) { value in
39+
if let value = value, value != itemHeight {
40+
itemHeight = value
41+
}
3942
}
40-
)
41-
.accessibilityElement(children: .contain)
42-
.accessibilityIdentifier("InstantCommandView")
43+
.highPriorityGesture(
44+
TapGesture()
45+
.onEnded { _ in
46+
let instantCommand = ComposerCommand(
47+
id: command.id,
48+
typingSuggestion: TypingSuggestion.empty,
49+
displayInfo: command.displayInfo,
50+
replacesMessageSent: command.replacesMessageSent
51+
)
52+
commandSelected(instantCommand)
53+
}
54+
)
55+
.accessibilityElement(children: .contain)
56+
.accessibilityIdentifier("InstantCommandView")
57+
}
58+
}
4359
}
4460
}
4561
}
4662
.background(Color(colors.background))
63+
.frame(height: viewHeight)
4764
.modifier(ShadowViewModifier())
4865
.padding(.all, 8)
4966
.animation(.spring())
5067
.accessibilityElement(children: .contain)
5168
}
69+
70+
private var viewHeight: CGFloat {
71+
if instantCommands.isEmpty {
72+
return 40
73+
}
74+
let height = CGFloat(instantCommands.count) * itemHeight + 70
75+
let maxHeight: CGFloat = 320
76+
return height > maxHeight ? maxHeight : height
77+
}
5278
}
5379

5480
/// View for the instant commands header.

StreamChatSwiftUITests/Tests/ChatChannel/Suggestions/InstantCommandsView_Tests.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,70 @@ class InstantCommandsView_Tests: StreamChatTestCase {
2525
// Then
2626
assertSnapshot(matching: view, as: .image)
2727
}
28+
29+
func test_instantCommandsContainerViewEmpty_snapshot() {
30+
// Given
31+
let commands: [CommandHandler] = []
32+
33+
// When
34+
let view = InstantCommandsView(instantCommands: commands, commandSelected: { _ in })
35+
.applyDefaultSize()
36+
37+
// Then
38+
assertSnapshot(matching: view, as: .image)
39+
}
40+
41+
func test_instantCommandsContainerView_snapshot() {
42+
// Given
43+
let commands: [CommandHandler] = defaultCommands()
44+
45+
// When
46+
let view = InstantCommandsView(instantCommands: commands, commandSelected: { _ in })
47+
.applyDefaultSize()
48+
49+
// Then
50+
assertSnapshot(matching: view, as: .image)
51+
}
52+
53+
func test_instantCommandsContainerMaxSize_snapshot() {
54+
// Given
55+
var commands = [CommandHandler]()
56+
for i in 0..<5 {
57+
commands.append(contentsOf: defaultCommands(suffix: "\(i)"))
58+
}
59+
60+
// When
61+
let view = InstantCommandsView(instantCommands: commands, commandSelected: { _ in })
62+
.applyDefaultSize()
63+
64+
// Then
65+
assertSnapshot(matching: view, as: .image)
66+
}
67+
68+
private func defaultCommands(suffix: String = "") -> [CommandHandler] {
69+
let channelController = ChatChannelTestHelpers.makeChannelController(
70+
chatClient: chatClient,
71+
messages: []
72+
)
73+
var instantCommands = [CommandHandler]()
74+
let giphyCommand = GiphyCommandHandler(
75+
commandSymbol: "/giphy",
76+
id: "/giphy\(suffix)"
77+
)
78+
instantCommands.append(giphyCommand)
79+
let muteCommand = MuteCommandHandler(
80+
channelController: channelController,
81+
commandSymbol: "/mute",
82+
id: "/mute\(suffix)"
83+
)
84+
let unmuteCommand = UnmuteCommandHandler(
85+
channelController: channelController,
86+
commandSymbol: "/unmute",
87+
id: "/unmute\(suffix)"
88+
)
89+
instantCommands.append(muteCommand)
90+
instantCommands.append(unmuteCommand)
91+
92+
return instantCommands
93+
}
2894
}
Loading
Loading
Loading

0 commit comments

Comments
 (0)