Skip to content

Commit 1b95922

Browse files
Implemented read indicators in message list
1 parent a9bd8f6 commit 1b95922

File tree

3 files changed

+97
-45
lines changed

3 files changed

+97
-45
lines changed

Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift

Lines changed: 17 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct MessageContainerView<Factory: ViewFactory>: View {
1212
@Injected(\.fonts) private var fonts
1313
@Injected(\.colors) private var colors
1414
@Injected(\.images) private var images
15+
@Injected(\.chatClient) private var chatClient
1516

1617
var factory: Factory
1718
let channel: ChatChannel
@@ -139,6 +140,14 @@ struct MessageContainerView<Factory: ViewFactory>: View {
139140
if showsAllInfo && !message.isDeleted {
140141
if isInGroup && !message.isSentByCurrentUser {
141142
MessageAuthorAndDateView(message: message)
143+
} else if message.isSentByCurrentUser {
144+
HStack(spacing: 4) {
145+
MessageReadIndicatorView(
146+
readUsers: readUsers,
147+
isGroup: isInGroup
148+
)
149+
MessageDateView(message: message)
150+
}
142151
} else {
143152
MessageDateView(message: message)
144153
}
@@ -153,6 +162,14 @@ struct MessageContainerView<Factory: ViewFactory>: View {
153162
.padding(.top, reactionsShown ? 24 : 0)
154163
}
155164

165+
private var readUsers: [ChatUser] {
166+
let readUsers = channel.reads.filter {
167+
$0.lastReadAt > message.createdAt &&
168+
$0.user.id != chatClient.currentUserId
169+
}.map(\.user)
170+
return readUsers
171+
}
172+
156173
private var contentWidth: CGFloat {
157174
let padding: CGFloat = 8
158175
let minimumWidth: CGFloat = 240
@@ -199,51 +216,6 @@ struct MessageContainerView<Factory: ViewFactory>: View {
199216
}
200217
}
201218

202-
struct MessageAuthorAndDateView: View {
203-
@Injected(\.fonts) private var fonts
204-
@Injected(\.colors) private var colors
205-
206-
var message: ChatMessage
207-
208-
var body: some View {
209-
HStack {
210-
Text(message.author.name ?? "")
211-
.font(fonts.footnoteBold)
212-
.foregroundColor(Color(colors.textLowEmphasis))
213-
MessageDateView(message: message)
214-
Spacer()
215-
}
216-
}
217-
}
218-
219-
struct MessageDateView: View {
220-
@Injected(\.utils) private var utils
221-
@Injected(\.fonts) private var fonts
222-
@Injected(\.colors) private var colors
223-
224-
private var dateFormatter: DateFormatter {
225-
utils.dateFormatter
226-
}
227-
228-
var message: ChatMessage
229-
230-
var body: some View {
231-
Text(dateFormatter.string(from: message.createdAt))
232-
.font(fonts.footnote)
233-
.foregroundColor(Color(colors.textLowEmphasis))
234-
}
235-
}
236-
237-
struct MessageSpacer: View {
238-
var spacerWidth: CGFloat?
239-
240-
var body: some View {
241-
Spacer()
242-
.frame(minWidth: spacerWidth)
243-
.layoutPriority(-1)
244-
}
245-
}
246-
247219
public struct MessageDisplayInfo {
248220
let message: ChatMessage
249221
let frame: CGRect
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//
2+
// Copyright © 2022 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import StreamChat
6+
import SwiftUI
7+
8+
struct MessageAuthorAndDateView: View {
9+
@Injected(\.fonts) private var fonts
10+
@Injected(\.colors) private var colors
11+
12+
var message: ChatMessage
13+
14+
var body: some View {
15+
HStack {
16+
Text(message.author.name ?? "")
17+
.font(fonts.footnoteBold)
18+
.foregroundColor(Color(colors.textLowEmphasis))
19+
MessageDateView(message: message)
20+
Spacer()
21+
}
22+
}
23+
}
24+
25+
struct MessageDateView: View {
26+
@Injected(\.utils) private var utils
27+
@Injected(\.fonts) private var fonts
28+
@Injected(\.colors) private var colors
29+
30+
private var dateFormatter: DateFormatter {
31+
utils.dateFormatter
32+
}
33+
34+
var message: ChatMessage
35+
36+
var body: some View {
37+
Text(dateFormatter.string(from: message.createdAt))
38+
.font(fonts.footnote)
39+
.foregroundColor(Color(colors.textLowEmphasis))
40+
}
41+
}
42+
43+
struct MessageReadIndicatorView: View {
44+
@Injected(\.images) private var images
45+
@Injected(\.fonts) private var fonts
46+
@Injected(\.colors) private var colors
47+
48+
var readUsers: [ChatUser]
49+
var isGroup: Bool
50+
51+
var body: some View {
52+
HStack(spacing: 2) {
53+
if isGroup && !readUsers.isEmpty {
54+
Text("\(readUsers.count)")
55+
.font(fonts.footnoteBold)
56+
.foregroundColor(colors.tintColor)
57+
}
58+
Image(
59+
uiImage: !readUsers.isEmpty ? images.readByAll : images.messageSent
60+
)
61+
.customizable()
62+
.foregroundColor(!readUsers.isEmpty ? colors.tintColor : nil)
63+
.frame(height: 16)
64+
}
65+
}
66+
}
67+
68+
struct MessageSpacer: View {
69+
var spacerWidth: CGFloat?
70+
71+
var body: some View {
72+
Spacer()
73+
.frame(minWidth: spacerWidth)
74+
.layoutPriority(-1)
75+
}
76+
}

StreamChatSwiftUI.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
841B2EF4278DB9E500ED619E /* MessageListHelperViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841B2EF3278DB9E500ED619E /* MessageListHelperViews.swift */; };
1011
841B64C427744DB60016FF3B /* ComposerModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841B64C327744DB60016FF3B /* ComposerModels.swift */; };
1112
841B64C82774BA770016FF3B /* CommandsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841B64C72774BA770016FF3B /* CommandsHandler.swift */; };
1213
841B64CA2775BBC10016FF3B /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841B64C92775BBC10016FF3B /* Errors.swift */; };
@@ -311,6 +312,7 @@
311312

312313
/* Begin PBXFileReference section */
313314
4A65451E274BA170003C5FA8 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
315+
841B2EF3278DB9E500ED619E /* MessageListHelperViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListHelperViews.swift; sourceTree = "<group>"; };
314316
841B64C327744DB60016FF3B /* ComposerModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerModels.swift; sourceTree = "<group>"; };
315317
841B64C72774BA770016FF3B /* CommandsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandsHandler.swift; sourceTree = "<group>"; };
316318
841B64C92775BBC10016FF3B /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; };
@@ -823,6 +825,7 @@
823825
8465FD092746A95600AF091E /* WebView.swift */,
824826
8465FD0A2746A95600AF091E /* SystemMessageView.swift */,
825827
842383E327678A4D00888CFC /* QuotedMessageView.swift */,
828+
841B2EF3278DB9E500ED619E /* MessageListHelperViews.swift */,
826829
);
827830
path = MessageList;
828831
sourceTree = "<group>";
@@ -1474,6 +1477,7 @@
14741477
8465FDD72746A95800AF091E /* Appearance.swift in Sources */,
14751478
8465FD8A2746A95700AF091E /* DiscardAttachmentButton.swift in Sources */,
14761479
8465FDCB2746A95700AF091E /* ChatChannelListView.swift in Sources */,
1480+
841B2EF4278DB9E500ED619E /* MessageListHelperViews.swift in Sources */,
14771481
8465FDD22746A95800AF091E /* Utils.swift in Sources */,
14781482
8465FDA12746A95700AF091E /* ChatChannelHeaderViewModifier.swift in Sources */,
14791483
84F2908A276B90610045472D /* GalleryView.swift in Sources */,

0 commit comments

Comments
 (0)