Skip to content

Commit 14e8077

Browse files
authored
Fix incorrect channel list sorting when sorted by .hasUnread (#3646)
* Fix incorrect channel list sorting when sorted by `.hasUnread` * Update CHANGELOG.md * Fix test
1 parent b22b640 commit 14e8077

File tree

7 files changed

+95
-15
lines changed

7 files changed

+95
-15
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
## StreamChat
77
### 🐞 Fixed
88
- Fix `FilterKey.id` not returning any channels in `ChannelListQuery` [#3643](https://github.com/GetStream/stream-chat-swift/pull/3643)
9+
- Fix incorrect channel list sorting when sorted by `.hasUnread` [#3646](https://github.com/GetStream/stream-chat-swift/pull/3646)
910

1011
## StreamChatUI
1112
### 🐞 Fixed

DemoApp/StreamChat/Components/DemoChatChannelListVC.swift

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,23 @@ final class DemoChatChannelListVC: ChatChannelListVC {
4141
.equal(.hidden, to: true)
4242
]))
4343

44-
lazy var unreadChannelsQuery: ChannelListQuery = .init(filter: .and([
45-
.containMembers(userIds: [currentUserId]),
46-
.hasUnread
47-
]), sort: [.init(key: .unreadCount, isAscending: false)])
44+
lazy var unreadCountChannelsQuery: ChannelListQuery = .init(
45+
filter: .and([
46+
.containMembers(userIds: [currentUserId]),
47+
.hasUnread
48+
]),
49+
sort: [.init(key: .unreadCount, isAscending: false)]
50+
)
51+
52+
lazy var sortedByHasUnreadChannelsQuery: ChannelListQuery = .init(
53+
filter: .and([
54+
.containMembers(userIds: [currentUserId])
55+
]),
56+
sort: [
57+
.init(key: .hasUnread, isAscending: false),
58+
.init(key: .updatedAt, isAscending: false)
59+
]
60+
)
4861

4962
lazy var mutedChannelsQuery: ChannelListQuery = .init(filter: .and([
5063
.containMembers(userIds: [currentUserId]),
@@ -132,12 +145,21 @@ final class DemoChatChannelListVC: ChatChannelListVC {
132145
}
133146
)
134147

135-
let unreadChannelsAction = UIAlertAction(
136-
title: "Unread Channels",
148+
let unreadCountChannelsAction = UIAlertAction(
149+
title: "Unread Count Channels",
150+
style: .default,
151+
handler: { [weak self] _ in
152+
self?.title = "Unread Count Channels"
153+
self?.setUnreadCountChannelsQuery()
154+
}
155+
)
156+
157+
let hasUnreadChannelsAction = UIAlertAction(
158+
title: "Sorted hasUnread Channels",
137159
style: .default,
138160
handler: { [weak self] _ in
139-
self?.title = "Unread Channels"
140-
self?.setUnreadChannelsQuery()
161+
self?.title = "Sorted hasUnread Channels"
162+
self?.setSortedByHasUnreadChannelsQuery()
141163
}
142164
)
143165

@@ -187,7 +209,8 @@ final class DemoChatChannelListVC: ChatChannelListVC {
187209
title: "Filter Channels",
188210
actions: [
189211
defaultChannelsAction,
190-
unreadChannelsAction,
212+
unreadCountChannelsAction,
213+
hasUnreadChannelsAction,
191214
hiddenChannelsAction,
192215
mutedChannelsAction,
193216
coolChannelsAction,
@@ -204,8 +227,12 @@ final class DemoChatChannelListVC: ChatChannelListVC {
204227
replaceQuery(hiddenChannelsQuery)
205228
}
206229

207-
func setUnreadChannelsQuery() {
208-
replaceQuery(unreadChannelsQuery)
230+
func setUnreadCountChannelsQuery() {
231+
replaceQuery(unreadCountChannelsQuery)
232+
}
233+
234+
func setSortedByHasUnreadChannelsQuery() {
235+
replaceQuery(sortedByHasUnreadChannelsQuery)
209236
}
210237

211238
func setMutedChannelsQuery() {

Sources/StreamChat/Database/DTOs/ChannelDTO.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ class ChannelDTO: NSManagedObject {
6565
@NSManaged var messages: Set<MessageDTO>
6666
@NSManaged var pinnedMessages: Set<MessageDTO>
6767
@NSManaged var reads: Set<ChannelReadDTO>
68+
69+
/// Helper properties used for sorting channels with unread counts of the current user.
6870
@NSManaged var currentUserUnreadMessagesCount: Int32
71+
@NSManaged var hasUnreadSorting: Int16
72+
6973
@NSManaged var watchers: Set<UserDTO>
7074
@NSManaged var memberListQueries: Set<ChannelMemberListQueryDTO>
7175
@NSManaged var previewMessage: MessageDTO?
@@ -82,12 +86,13 @@ class ChannelDTO: NSManagedObject {
8286
}
8387

8488
// Update the unreadMessagesCount for the current user.
85-
// At the moment this computed property is used for `hasUnread` automatic channel list filtering.
89+
// At the moment this computed property is used for `hasUnread` and `unreadCount` automatic channel list filtering.
8690
if let currentUserId = managedObjectContext?.currentUser?.user.id {
8791
let currentUserUnread = reads.first(where: { $0.user.id == currentUserId })
8892
let newUnreadCount = currentUserUnread?.unreadMessageCount ?? 0
8993
if newUnreadCount != currentUserUnreadMessagesCount {
9094
currentUserUnreadMessagesCount = newUnreadCount
95+
hasUnreadSorting = newUnreadCount > 0 ? 1 : 0
9196
}
9297
}
9398

Sources/StreamChat/Database/StreamChatModel.xcdatamodeld/StreamChatModel.xcdatamodel/contents

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<attribute name="defaultSortingAt" attributeType="Date" usesScalarValueType="NO" spotlightIndexingEnabled="YES"/>
4545
<attribute name="deletedAt" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
4646
<attribute name="extraData" attributeType="Binary"/>
47+
<attribute name="hasUnreadSorting" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
4748
<attribute name="id" optional="YES" attributeType="String"/>
4849
<attribute name="imageURL" optional="YES" attributeType="URI"/>
4950
<attribute name="isBlocked" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>

Sources/StreamChat/Query/Sorting/ChannelListSortingKey.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public struct ChannelListSortingKey: SortingKey, Equatable {
6363
/// **Note:** If you want to sort by number of unreads, you should use the `unreadCount` sorting key.
6464
public static let hasUnread = Self(
6565
keyPath: \.hasUnread,
66-
localKey: nil,
66+
localKey: #keyPath(ChannelDTO.hasUnreadSorting),
6767
remoteKey: "has_unread"
6868
)
6969

Tests/StreamChatTests/Controllers/ChannelListController/ChannelListController_Tests.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,51 @@ final class ChannelListController_Tests: XCTestCase {
16321632
)
16331633
}
16341634

1635+
func test_filterPredicate_sortedByHasUnread_returnsExpectedResults() throws {
1636+
let cid1 = ChannelId.unique
1637+
let cid2 = ChannelId.unique
1638+
let cid3 = ChannelId.unique
1639+
let cid4 = ChannelId.unique
1640+
let currentUserId = UserId.unique
1641+
let createdAt = Date()
1642+
1643+
try assertFilterPredicate(
1644+
.in(.cid, values: [cid1, cid2, cid3, cid4]),
1645+
sort: [
1646+
.init(key: .hasUnread, isAscending: false),
1647+
.init(key: .createdAt, isAscending: false)
1648+
],
1649+
currentUserId: currentUserId,
1650+
channelsInDB: [
1651+
.dummy(
1652+
channel: .dummy(cid: cid1, createdAt: createdAt.addingTimeInterval(100)),
1653+
channelReads: [
1654+
.init(
1655+
user: .dummy(userId: currentUserId),
1656+
lastReadAt: .unique,
1657+
lastReadMessageId: nil,
1658+
unreadMessagesCount: 3
1659+
)
1660+
]
1661+
),
1662+
.dummy(channel: .dummy(cid: cid3, createdAt: createdAt.addingTimeInterval(200))),
1663+
.dummy(channel: .dummy(cid: cid4, createdAt: createdAt.addingTimeInterval(300))),
1664+
.dummy(
1665+
channel: .dummy(cid: cid2, createdAt: createdAt),
1666+
channelReads: [
1667+
.init(
1668+
user: .dummy(userId: currentUserId),
1669+
lastReadAt: .unique,
1670+
lastReadMessageId: nil,
1671+
unreadMessagesCount: 20
1672+
)
1673+
]
1674+
)
1675+
],
1676+
expectedResult: [cid2, cid1, cid3, cid4]
1677+
)
1678+
}
1679+
16351680
func test_filterPredicate_muted_returnsExpectedResults() throws {
16361681
let cid1 = ChannelId.unique
16371682
let userId = memberId

Tests/StreamChatTests/Query/Sorting/ChannelListSortingKey_Tests.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,10 @@ final class ChannelListSortingKey_Tests: XCTestCase {
7474
XCTAssertEqual(key.remoteKey, "cid")
7575
XCTAssertFalse(key.requiresRuntimeSorting)
7676
case .hasUnread:
77-
XCTAssertNil(key.sortDescriptor(isAscending: true))
77+
XCTAssertNotNil(key.sortDescriptor(isAscending: false))
78+
XCTAssertEqual(key.localKey, "hasUnreadSorting")
7879
XCTAssertEqual(key.remoteKey, "has_unread")
79-
XCTAssertTrue(key.requiresRuntimeSorting)
80+
XCTAssertFalse(key.requiresRuntimeSorting)
8081
case .unreadCount:
8182
XCTAssertNotNil(key.sortDescriptor(isAscending: true))
8283
XCTAssertEqual(key.remoteKey, "unread_count")

0 commit comments

Comments
 (0)