Skip to content

Commit 2f07f70

Browse files
Added thread replies shown in channel indicator (#518)
1 parent c00c74d commit 2f07f70

File tree

9 files changed

+120
-15
lines changed

9 files changed

+120
-15
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
33

44
# Upcoming
55

6-
### 🔄 Changed
6+
### ✅ Added
7+
- Thread replies shown in channel indicator [#518](https://github.com/GetStream/stream-chat-swiftui/pull/518)
78

89
# [4.57.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.57.0)
910
_June 07, 2024_

Sources/StreamChatSwiftUI/ChatChannel/ChannelControllerFactory.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class ChannelControllerFactory {
1010

1111
@Injected(\.chatClient) var chatClient
1212

13-
private var currentChannelController: ChatChannelController?
13+
var currentChannelController: ChatChannelController?
1414
private var messageControllers = [String: ChatMessageController]()
1515

1616
/// Creates a channel controller with the provided channel id.

Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,28 @@ public struct MessageContainerView<Factory: ViewFactory>: View {
166166
.accessibilityElement(children: .contain)
167167
.accessibilityIdentifier("MessageView")
168168

169-
if message.replyCount > 0 && !isInThread {
170-
factory.makeMessageRepliesView(
171-
channel: channel,
172-
message: message,
173-
replyCount: message.replyCount
174-
)
175-
.accessibilityElement(children: .contain)
176-
.accessibility(identifier: "MessageRepliesView")
169+
if !isInThread {
170+
if message.replyCount > 0 {
171+
factory.makeMessageRepliesView(
172+
channel: channel,
173+
message: message,
174+
replyCount: message.replyCount
175+
)
176+
.accessibilityElement(children: .contain)
177+
.accessibility(identifier: "MessageRepliesView")
178+
} else if message.showReplyInChannel,
179+
let parentId = message.parentMessageId,
180+
let controller = utils.channelControllerFactory.currentChannelController,
181+
let parentMessage = controller.dataStore.message(id: parentId) {
182+
factory.makeMessageRepliesShownInChannelView(
183+
channel: channel,
184+
message: message,
185+
parentMessage: parentMessage,
186+
replyCount: parentMessage.replyCount
187+
)
188+
.accessibilityElement(children: .contain)
189+
.accessibility(identifier: "MessageRepliesView")
190+
}
177191
}
178192

179193
if bottomReactionsShown {

Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageRepliesView.swift

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,23 @@ public struct MessageRepliesView<Factory: ViewFactory>: View {
2020
var channel: ChatChannel
2121
var message: ChatMessage
2222
var replyCount: Int
23+
var isRightAligned: Bool
24+
var showReplyCount: Bool
2325

24-
public init(factory: Factory, channel: ChatChannel, message: ChatMessage, replyCount: Int) {
26+
public init(
27+
factory: Factory,
28+
channel: ChatChannel,
29+
message: ChatMessage,
30+
replyCount: Int,
31+
showReplyCount: Bool = true,
32+
isRightAligned: Bool? = nil
33+
) {
2534
self.factory = factory
2635
self.channel = channel
2736
self.message = message
2837
self.replyCount = replyCount
38+
self.isRightAligned = isRightAligned ?? message.isRightAligned
39+
self.showReplyCount = showReplyCount
2940
}
3041

3142
public var body: some View {
@@ -41,15 +52,15 @@ public struct MessageRepliesView<Factory: ViewFactory>: View {
4152
)
4253
} label: {
4354
HStack {
44-
if !message.isRightAligned {
55+
if !isRightAligned {
4556
MessageAvatarView(
4657
avatarURL: message.threadParticipants.first?.imageURL,
4758
size: .init(width: 16, height: 16)
4859
)
4960
}
50-
Text("\(replyCount) \(repliesText)")
61+
Text(title)
5162
.font(fonts.footnoteBold)
52-
if message.isRightAligned {
63+
if isRightAligned {
5364
MessageAvatarView(
5465
avatarURL: message.threadParticipants.first?.imageURL,
5566
size: .init(width: 16, height: 16)
@@ -81,13 +92,21 @@ public struct MessageRepliesView<Factory: ViewFactory>: View {
8192
)
8293
.offset(y: -24)
8394
.rotation3DEffect(
84-
.degrees(message.isRightAligned ? 180 : 0),
95+
.degrees(isRightAligned ? 180 : 0),
8596
axis: (x: 0, y: 1, z: 0)
8697
)
8798
)
8899
.foregroundColor(colors.tintColor)
89100
}
90101
}
102+
103+
var title: String {
104+
if showReplyCount {
105+
return "\(replyCount) \(repliesText)"
106+
} else {
107+
return L10n.Message.Threads.reply
108+
}
109+
}
91110

92111
var repliesText: String {
93112
if message.replyCount == 1 {

Sources/StreamChatSwiftUI/DefaultViewFactory.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,22 @@ extension ViewFactory {
496496
)
497497
}
498498

499+
public func makeMessageRepliesShownInChannelView(
500+
channel: ChatChannel,
501+
message: ChatMessage,
502+
parentMessage: ChatMessage,
503+
replyCount: Int
504+
) -> some View {
505+
MessageRepliesView(
506+
factory: self,
507+
channel: channel,
508+
message: parentMessage,
509+
replyCount: replyCount,
510+
showReplyCount: false,
511+
isRightAligned: message.isRightAligned
512+
)
513+
}
514+
499515
public func makeMessageComposerViewType(
500516
with channelController: ChatChannelController,
501517
messageController: ChatMessageController?,

Sources/StreamChatSwiftUI/ViewFactory.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,21 @@ public protocol ViewFactory: AnyObject {
524524
message: ChatMessage,
525525
replyCount: Int
526526
) -> MessageRepliesViewType
527+
528+
associatedtype MessageRepliesShownInChannelViewType: View
529+
/// Creates the message replies view for a reply that is also shown in a channel.
530+
/// - Parameters:
531+
/// - channel: the channel where the message is sent.
532+
/// - message: the message that's being replied to.
533+
/// - parentMessage: the parent message.
534+
/// - replyCount: the current number of replies.
535+
/// - Returns: view displayed in the message replies view slot.
536+
func makeMessageRepliesShownInChannelView(
537+
channel: ChatChannel,
538+
message: ChatMessage,
539+
parentMessage: ChatMessage,
540+
replyCount: Int
541+
) -> MessageRepliesShownInChannelViewType
527542

528543
associatedtype MessageComposerViewType: View
529544
/// Creates the message composer view.

StreamChatSwiftUITests/Tests/ChatChannel/MessageView_Tests.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,30 @@ class MessageView_Tests: StreamChatTestCase {
421421
// Then
422422
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
423423
}
424+
425+
func test_messageRepliesViewShownInChannel_snapshot() {
426+
// Given
427+
let channel = ChatChannel.mockDMChannel()
428+
let message = ChatMessage.mock(
429+
id: .unique,
430+
cid: channel.cid,
431+
text: "Message with replies",
432+
author: .mock(id: .unique)
433+
)
434+
435+
// When
436+
let view = MessageRepliesView(
437+
factory: DefaultViewFactory.shared,
438+
channel: channel,
439+
message: message,
440+
replyCount: 3,
441+
showReplyCount: false
442+
)
443+
.frame(width: 300, height: 60)
444+
445+
// Then
446+
assertSnapshot(matching: view, as: .image(perceptualPrecision: precision))
447+
}
424448

425449
func test_topLeftView_snapshot() {
426450
// Given
Loading

StreamChatSwiftUITests/Tests/Utils/ViewFactory_Tests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,22 @@ class ViewFactory_Tests: StreamChatTestCase {
760760
// Then
761761
XCTAssert(view is MessageRepliesView<DefaultViewFactory>)
762762
}
763+
764+
func test_viewFactory_makeMessageRepliesShownInChannelView() {
765+
// Given
766+
let viewFactory = DefaultViewFactory.shared
767+
768+
// When
769+
let view = viewFactory.makeMessageRepliesShownInChannelView(
770+
channel: ChatChannel.mockDMChannel(),
771+
message: message,
772+
parentMessage: message,
773+
replyCount: 2
774+
)
775+
776+
// Then
777+
XCTAssert(view is MessageRepliesView<DefaultViewFactory>)
778+
}
763779

764780
func test_viewFactory_makeTypingIndicatorBottomView() {
765781
// Given

0 commit comments

Comments
 (0)