Skip to content

Commit 3cdc4c2

Browse files
committed
Make message spacing in message list configurable (#830)
1 parent 8f0ac18 commit 3cdc4c2

File tree

7 files changed

+80
-2
lines changed

7 files changed

+80
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
### ✅ Added
77
- Add extra data to user display info [#819](https://github.com/GetStream/stream-chat-swiftui/pull/819)
88
- Make message spacing in message list configurable [#830](https://github.com/GetStream/stream-chat-swiftui/pull/830)
9+
- Show time, relative date, weekday, or short date for last message in channel list and search [#833](https://github.com/GetStream/stream-chat-swiftui/pull/833)
910
### 🐞 Fixed
1011
- Fix swipe to reply enabled when quoting a message is disabled [#824](https://github.com/GetStream/stream-chat-swiftui/pull/824)
1112
- Fix mark unread action not removed when read events are disabled [#823](https://github.com/GetStream/stream-chat-swiftui/pull/823)

Sources/StreamChatSwiftUI/ChatChannel/MessageList/MessageContainerView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public struct MessageContainerView<Factory: ViewFactory>: View {
3636
private var paddingValue: CGFloat {
3737
utils.messageListConfig.messagePaddings.singleBottom
3838
}
39+
3940
private var groupMessageInterItemSpacing: CGFloat {
4041
utils.messageListConfig.messagePaddings.groupBottom
4142
}

Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListItem.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ extension ChatChannel {
337337

338338
public var timestampText: String {
339339
if let lastMessageAt = lastMessageAt {
340-
return InjectedValues[\.utils].dateFormatter.string(from: lastMessageAt)
340+
return InjectedValues[\.utils].channelListDateFormatter.string(from: lastMessageAt)
341341
} else {
342342
return ""
343343
}

Sources/StreamChatSwiftUI/ChatChannelList/SearchResultsView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ struct SearchResultItem<Factory: ViewFactory, ChannelDestination: View>: View {
158158

159159
private var timestampText: String {
160160
if let lastMessageAt = searchResult.channel.lastMessageAt {
161-
return utils.dateFormatter.string(from: lastMessageAt)
161+
return utils.channelListDateFormatter.string(from: lastMessageAt)
162162
} else {
163163
return ""
164164
}

Sources/StreamChatSwiftUI/Utils.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public class Utils {
1313
var markdownFormatter = MarkdownFormatter()
1414

1515
public var dateFormatter: DateFormatter
16+
public var channelListDateFormatter: DateFormatter
1617
public var videoPreviewLoader: VideoPreviewLoader
1718
public var imageLoader: ImageLoading
1819
public var imageCDN: ImageCDN
@@ -69,6 +70,7 @@ public class Utils {
6970

7071
public init(
7172
dateFormatter: DateFormatter = .makeDefault(),
73+
channelListDateFormatter: DateFormatter = ChannelListDateFormatter(),
7274
videoPreviewLoader: VideoPreviewLoader = DefaultVideoPreviewLoader(),
7375
imageLoader: ImageLoading = NukeImageLoader(),
7476
imageCDN: ImageCDN = StreamImageCDN(),
@@ -93,6 +95,7 @@ public class Utils {
9395
shouldSyncChannelControllerOnAppear: @escaping (ChatChannelController) -> Bool = { _ in true }
9496
) {
9597
self.dateFormatter = dateFormatter
98+
self.channelListDateFormatter = channelListDateFormatter
9699
self.videoPreviewLoader = videoPreviewLoader
97100
self.imageLoader = imageLoader
98101
self.imageCDN = imageCDN
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// Copyright © 2025 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import Foundation
6+
7+
/// A formatter that converts last message timestamps in the channel list.
8+
///
9+
/// Shows time, relative date, weekday or short date based on days passed.
10+
public final class ChannelListDateFormatter: DateFormatter, @unchecked Sendable {
11+
override public init() {
12+
super.init()
13+
locale = .autoupdatingCurrent
14+
dateStyle = .short
15+
timeStyle = .none
16+
}
17+
18+
@available(*, unavailable)
19+
required init?(coder: NSCoder) {
20+
fatalError("init(coder:) has not been implemented")
21+
}
22+
23+
override public func string(from date: Date) -> String {
24+
if calendar.isDateInToday(date) {
25+
return time.string(from: date)
26+
}
27+
if calendar.isDateInYesterday(date) {
28+
return shortRelativeDate.string(from: date)
29+
}
30+
if calendar.isDateInLastWeek(date) {
31+
return weekday.string(from: date)
32+
}
33+
34+
return super.string(from: date)
35+
}
36+
37+
private let time: DateFormatter = {
38+
let formatter = DateFormatter()
39+
formatter.locale = .autoupdatingCurrent
40+
formatter.dateStyle = .none
41+
formatter.timeStyle = .short
42+
return formatter
43+
}()
44+
45+
private let shortRelativeDate: DateFormatter = {
46+
let formatter = DateFormatter()
47+
formatter.locale = .autoupdatingCurrent
48+
formatter.dateStyle = .short
49+
formatter.timeStyle = .none
50+
formatter.doesRelativeDateFormatting = true
51+
return formatter
52+
}()
53+
54+
private let weekday: DateFormatter = {
55+
let formatter = DateFormatter()
56+
formatter.locale = .autoupdatingCurrent
57+
formatter.setLocalizedDateFormatFromTemplate("EEEE")
58+
return formatter
59+
}()
60+
}
61+
62+
private extension Calendar {
63+
func isDateInLastWeek(_ date: Date) -> Bool {
64+
guard let dateBefore7days = self.date(byAdding: .day, value: -7, to: Date()) else {
65+
return false
66+
}
67+
return date > dateBefore7days
68+
}
69+
}

StreamChatSwiftUI.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
4F6D83352C0F05040098C298 /* PollCommentsViewModel_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6D83342C0F05040098C298 /* PollCommentsViewModel_Tests.swift */; };
1717
4F6D83512C1079A00098C298 /* AlertBannerViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6D83502C1079A00098C298 /* AlertBannerViewModifier.swift */; };
1818
4F6D83542C1094220098C298 /* AlertBannerViewModifier_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6D83532C1094220098C298 /* AlertBannerViewModifier_Tests.swift */; };
19+
4F7613792DDCB2C900F996E3 /* ChannelListDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7613782DDCB2AD00F996E3 /* ChannelListDateFormatter.swift */; };
1920
4F7720AE2C58C45200BAEC02 /* OnLoadViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7720AD2C58C45000BAEC02 /* OnLoadViewModifier.swift */; };
2021
4F7DD9A02BFC7C6100599AA6 /* ChatClient+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7DD99F2BFC7C6100599AA6 /* ChatClient+Extensions.swift */; };
2122
4F7DD9A22BFCB2EF00599AA6 /* ChatClientExtensions_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F7DD9A12BFCB2EF00599AA6 /* ChatClientExtensions_Tests.swift */; };
@@ -612,6 +613,7 @@
612613
4F6D83342C0F05040098C298 /* PollCommentsViewModel_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PollCommentsViewModel_Tests.swift; sourceTree = "<group>"; };
613614
4F6D83502C1079A00098C298 /* AlertBannerViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertBannerViewModifier.swift; sourceTree = "<group>"; };
614615
4F6D83532C1094220098C298 /* AlertBannerViewModifier_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertBannerViewModifier_Tests.swift; sourceTree = "<group>"; };
616+
4F7613782DDCB2AD00F996E3 /* ChannelListDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelListDateFormatter.swift; sourceTree = "<group>"; };
615617
4F7720AD2C58C45000BAEC02 /* OnLoadViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnLoadViewModifier.swift; sourceTree = "<group>"; };
616618
4F7DD99F2BFC7C6100599AA6 /* ChatClient+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChatClient+Extensions.swift"; sourceTree = "<group>"; };
617619
4F7DD9A12BFCB2EF00599AA6 /* ChatClientExtensions_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatClientExtensions_Tests.swift; sourceTree = "<group>"; };
@@ -1924,6 +1926,7 @@
19241926
4FCD7DBC2D633F6C000EEB0F /* AttributedString+Extensions.swift */,
19251927
8465FD392746A95600AF091E /* AutoLayoutHelpers.swift */,
19261928
8465FD452746A95600AF091E /* Cache.swift */,
1929+
4F7613782DDCB2AD00F996E3 /* ChannelListDateFormatter.swift */,
19271930
8465FD412746A95600AF091E /* ChatChannelNamer.swift */,
19281931
4F7DD99F2BFC7C6100599AA6 /* ChatClient+Extensions.swift */,
19291932
8465FD442746A95600AF091E /* ChatMessage+Extensions.swift */,
@@ -2806,6 +2809,7 @@
28062809
8465FDA52746A95700AF091E /* Modifiers.swift in Sources */,
28072810
8465FDBB2746A95700AF091E /* LoadingView.swift in Sources */,
28082811
84D6E4F62B2CA4E300D0056C /* RecordingTipView.swift in Sources */,
2812+
4F7613792DDCB2C900F996E3 /* ChannelListDateFormatter.swift in Sources */,
28092813
846608E3278C303800D3D7B3 /* TypingIndicatorView.swift in Sources */,
28102814
84A1CACF2816BCF00046595A /* AddUsersView.swift in Sources */,
28112815
82D64BF02AD7E5B700C5C79E /* DataLoading.swift in Sources */,

0 commit comments

Comments
 (0)