Skip to content

Commit 9320b72

Browse files
committed
Channel was sometimes not selected if ChatChannelViewModel.selectedChannelId was set to a channel created a moments ago
1 parent 89a3b4e commit 9320b72

File tree

3 files changed

+66
-9
lines changed

3 files changed

+66
-9
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
77
- Rare crash when accessing frame of the view [#607](https://github.com/GetStream/stream-chat-swiftui/pull/607)
88
- `ChatChannelListView` navigation did not trigger when using a custom container and its body reloaded [#609](https://github.com/GetStream/stream-chat-swiftui/pull/609)
99
- Channel was sometimes not marked as read when tapping the x on the unread message pill in the message list [#610](https://github.com/GetStream/stream-chat-swiftui/pull/610)
10+
- Channel was sometimes not selected if `ChatChannelViewModel.selectedChannelId` was set to a channel created a moments ago [#611](https://github.com/GetStream/stream-chat-swiftui/pull/611)
1011

1112
# [4.63.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.63.0)
1213
_September 12, 2024_

Sources/StreamChatSwiftUI/ChatChannelList/ChatChannelListViewModel.swift

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
5353
} else {
5454
markDirty = false
5555
}
56+
checkForDeeplinks()
5657
}
5758
}
5859

@@ -117,7 +118,13 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
117118
public var isSearching: Bool {
118119
!searchText.isEmpty
119120
}
120-
121+
122+
/// Creates a view model for the `ChatChannelListView`.
123+
///
124+
/// - Parameters:
125+
/// - channelListController: A controller providing the list of channels. If nil, a controller with default `ChannelListQuery` is created.
126+
/// - selectedChannelId: The id of a channel to select. If the channel is not part of the channel list query, no channel is selected.
127+
/// Consider using ``ChatChannelScreen`` for presenting channels what might not be part of the initial page of channels.
121128
public init(
122129
channelListController: ChatChannelListController? = nil,
123130
selectedChannelId: String? = nil
@@ -265,15 +272,16 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
265272
}
266273
}
267274

275+
/// Checks for currently loaded channels for opening a channel with id.
268276
private func checkForDeeplinks() {
269-
if let selectedChannelId = selectedChannelId,
270-
let channelId = try? ChannelId(cid: selectedChannelId) {
271-
let chatController = chatClient.channelController(
272-
for: channelId,
273-
messageOrdering: .topToBottom
274-
)
275-
selectedChannel = chatController.channel?.channelSelectionInfo
277+
guard let selectedChannelId else { return }
278+
do {
279+
let channelId = try ChannelId(cid: selectedChannelId)
280+
guard let selectedChannel = channels.first(where: { $0.cid == channelId })?.channelSelectionInfo else { return }
276281
self.selectedChannelId = nil
282+
self.selectedChannel = selectedChannel
283+
} catch {
284+
log.error("Failed to select a channel with id \(selectedChannelId) (\(error))")
277285
}
278286
}
279287

@@ -307,7 +315,6 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
307315
if self.selectedChannel == nil {
308316
self.updateChannels()
309317
}
310-
self.checkForDeeplinks()
311318
}
312319
}
313320
}

StreamChatSwiftUITests/Tests/ChatChannelList/ChatChannelListViewModel_Tests.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,55 @@ class ChatChannelListViewModel_Tests: StreamChatTestCase {
270270
// Then
271271
XCTAssert(viewModel.hideTabBar == true)
272272
}
273+
274+
func test_channelListVM_deeplinkToExistingChannel() {
275+
// Given
276+
let channels = (0..<3).map { ChatChannel.mock(cid: ChannelId(type: .messaging, id: "\($0)")) }
277+
let channelListController = makeChannelListController(channels: channels)
278+
let selectedId = channels[1].cid
279+
let viewModel = ChatChannelListViewModel(
280+
channelListController: channelListController,
281+
selectedChannelId: selectedId.rawValue
282+
)
283+
284+
// Then
285+
let expectation = XCTestExpectation(description: "SelectedChannel")
286+
let cancellable = viewModel.$selectedChannel
287+
.filter { $0?.channel.cid == selectedId }
288+
.sink { _ in
289+
expectation.fulfill()
290+
}
291+
wait(for: [expectation], timeout: defaultTimeout)
292+
cancellable.cancel()
293+
}
294+
295+
func test_channelListVM_deeplinkToIncomingChannel() {
296+
// Given
297+
let channels = (0..<3).map { ChatChannel.mock(cid: ChannelId(type: .messaging, id: "\($0)")) }
298+
let channelListController = makeChannelListController(channels: channels)
299+
let selectedId = ChannelId(type: .messaging, id: "3")
300+
let viewModel = ChatChannelListViewModel(
301+
channelListController: channelListController,
302+
selectedChannelId: selectedId.rawValue
303+
)
304+
305+
// When
306+
let expectation = XCTestExpectation(description: "SelectedChannel")
307+
let cancellable = viewModel.$selectedChannel
308+
.filter { $0?.channel.cid == selectedId }
309+
.sink { _ in
310+
expectation.fulfill()
311+
}
312+
let insertedChannel = ChatChannel.mock(cid: selectedId)
313+
channelListController.simulate(
314+
channels: channels + [insertedChannel],
315+
changes: [.insert(insertedChannel, index: IndexPath(item: 0, section: 0))]
316+
)
317+
318+
// Then
319+
wait(for: [expectation], timeout: defaultTimeout)
320+
cancellable.cancel()
321+
}
273322

274323
// MARK: - private
275324

0 commit comments

Comments
 (0)