Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Rare crash when accessing frame of the view [#607](https://github.com/GetStream/stream-chat-swiftui/pull/607)
- `ChatChannelListView` navigation did not trigger when using a custom container and its body reloaded [#609](https://github.com/GetStream/stream-chat-swiftui/pull/609)
- 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)
- 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)

# [4.63.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.63.0)
_September 12, 2024_
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
} else {
markDirty = false
}
checkForDeeplinks()
}
}

Expand Down Expand Up @@ -117,7 +118,13 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
public var isSearching: Bool {
!searchText.isEmpty
}


/// Creates a view model for the `ChatChannelListView`.
///
/// - Parameters:
/// - channelListController: A controller providing the list of channels. If nil, a controller with default `ChannelListQuery` is created.
/// - selectedChannelId: The id of a channel to select. If the channel is not part of the channel list query, no channel is selected.
/// Consider using ``ChatChannelScreen`` for presenting channels what might not be part of the initial page of channels.
public init(
channelListController: ChatChannelListController? = nil,
selectedChannelId: String? = nil
Expand Down Expand Up @@ -265,15 +272,16 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
}
}

/// Checks for currently loaded channels for opening a channel with id.
private func checkForDeeplinks() {
if let selectedChannelId = selectedChannelId,
let channelId = try? ChannelId(cid: selectedChannelId) {
let chatController = chatClient.channelController(
for: channelId,
messageOrdering: .topToBottom
)
selectedChannel = chatController.channel?.channelSelectionInfo
guard let selectedChannelId else { return }
do {
let channelId = try ChannelId(cid: selectedChannelId)
guard let selectedChannel = channels.first(where: { $0.cid == channelId })?.channelSelectionInfo else { return }
self.selectedChannelId = nil
self.selectedChannel = selectedChannel
} catch {
log.error("Failed to select a channel with id \(selectedChannelId) (\(error))")
}
}

Expand Down Expand Up @@ -307,7 +315,6 @@ open class ChatChannelListViewModel: ObservableObject, ChatChannelListController
if self.selectedChannel == nil {
self.updateChannels()
}
self.checkForDeeplinks()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,55 @@ class ChatChannelListViewModel_Tests: StreamChatTestCase {
// Then
XCTAssert(viewModel.hideTabBar == true)
}

func test_channelListVM_deeplinkToExistingChannel() {
// Given
let channels = (0..<3).map { ChatChannel.mock(cid: ChannelId(type: .messaging, id: "\($0)")) }
let channelListController = makeChannelListController(channels: channels)
let selectedId = channels[1].cid
let viewModel = ChatChannelListViewModel(
channelListController: channelListController,
selectedChannelId: selectedId.rawValue
)

// Then
let expectation = XCTestExpectation(description: "SelectedChannel")
let cancellable = viewModel.$selectedChannel
.filter { $0?.channel.cid == selectedId }
.sink { _ in
expectation.fulfill()
}
wait(for: [expectation], timeout: defaultTimeout)
cancellable.cancel()
}

func test_channelListVM_deeplinkToIncomingChannel() {
// Given
let channels = (0..<3).map { ChatChannel.mock(cid: ChannelId(type: .messaging, id: "\($0)")) }
let channelListController = makeChannelListController(channels: channels)
let selectedId = ChannelId(type: .messaging, id: "3")
let viewModel = ChatChannelListViewModel(
channelListController: channelListController,
selectedChannelId: selectedId.rawValue
)

// When
let expectation = XCTestExpectation(description: "SelectedChannel")
let cancellable = viewModel.$selectedChannel
.filter { $0?.channel.cid == selectedId }
.sink { _ in
expectation.fulfill()
}
let insertedChannel = ChatChannel.mock(cid: selectedId)
channelListController.simulate(
channels: channels + [insertedChannel],
changes: [.insert(insertedChannel, index: IndexPath(item: 0, section: 0))]
)

// Then
wait(for: [expectation], timeout: defaultTimeout)
cancellable.cancel()
}

// MARK: - private

Expand Down
Loading