Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## StreamChat
### ✅ Added
- Add support for `user.messages.deleted` event [#3792](https://github.com/GetStream/stream-chat-swift/pull/3792)
### 🐞 Fixed
- Fix channel getting removed from channel list which includes blocked channels [#3794](https://github.com/GetStream/stream-chat-swift/pull/3794)

## StreamChatUI
### 🐞 Fixed
- Fix input text view's placeholder alignment in RTL [#3790](https://github.com/GetStream/stream-chat-swift/pull/3790)
Expand Down
24 changes: 24 additions & 0 deletions DemoApp/StreamChat/Components/DemoChatChannelListVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ final class DemoChatChannelListVC: ChatChannelListVC {
.equal(.blocked, to: true)
])
]))

lazy var blockedUnblockedWithHiddenChannelsQuery: ChannelListQuery = .init(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this one? We already have:

lazy var allBlockedChannelsQuery: ChannelListQuery = .init(filter: .and([
        .containMembers(userIds: [currentUserId]),
        .or([
            .equal(.blocked, to: false),
            .equal(.blocked, to: true)
        ])
    ]))

This is the one customers would use.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I learned was that they are going to use the one with blocked and hidden fields.

filter: .and([
.containMembers(userIds: [currentUserId]),
.or([
.and([.equal(.blocked, to: false), .equal(.hidden, to: false)]),
.and([.equal(.blocked, to: true), .equal(.hidden, to: true)])
])
])
)

lazy var unreadCountChannelsQuery: ChannelListQuery = .init(
filter: .and([
Expand Down Expand Up @@ -161,6 +171,15 @@ final class DemoChatChannelListVC: ChatChannelListVC {
self?.setAllBlockedChannelsQuery()
}
)

let blockedUnBlockedExcludingDeletedChannelsAction = UIAlertAction(
title: "Blocked Unblocked with Matching Hidden Channels",
style: .default,
handler: { [weak self] _ in
self?.title = "Blocked Unblocked with Matching Hidden Channels"
self?.setBlockedUnblockedWithHiddenChannelsQuery()
}
)

let unreadCountChannelsAction = UIAlertAction(
title: "Unread Count Channels",
Expand Down Expand Up @@ -230,6 +249,7 @@ final class DemoChatChannelListVC: ChatChannelListVC {
hasUnreadChannelsAction,
hiddenChannelsAction,
allBlockedChannelsAction,
blockedUnBlockedExcludingDeletedChannelsAction,
mutedChannelsAction,
coolChannelsAction,
pinnedChannelsAction,
Expand All @@ -248,6 +268,10 @@ final class DemoChatChannelListVC: ChatChannelListVC {
func setAllBlockedChannelsQuery() {
replaceQuery(allBlockedChannelsQuery)
}

func setBlockedUnblockedWithHiddenChannelsQuery() {
replaceQuery(blockedUnblockedWithHiddenChannelsQuery)
}

func setUnreadCountChannelsQuery() {
replaceQuery(unreadCountChannelsQuery)
Expand Down
2 changes: 0 additions & 2 deletions Sources/StreamChat/Database/DTOs/ChannelDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,6 @@ extension NSManagedObjectContext {
// for blocked 1:1 channels on channel list query
if let isBlocked = payload.isBlocked {
dto.isBlocked = isBlocked
} else {
dto.isBlocked = false
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through manual regression testing steps for blocked, and all was good.


// Backend only returns a boolean for hidden state
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23605" systemVersion="24F74" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23788.4" systemVersion="24F74" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AttachmentDTO" representedClassName="AttachmentDTO" syncable="YES">
<attribute name="data" attributeType="Binary"/>
<attribute name="id" attributeType="String"/>
Expand Down Expand Up @@ -49,7 +49,7 @@
<attribute name="hasUnreadSorting" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="String"/>
<attribute name="imageURL" optional="YES" attributeType="URI"/>
<attribute name="isBlocked" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="isBlocked" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Safe if default value is set, but it is optional (since now ChannelDTO might not update the property anymore).

<attribute name="isDisabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="isFrozen" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="isHidden" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extension ChannelDetailPayload {
config: ChannelConfig = .mock(),
ownCapabilities: [String] = [],
isFrozen: Bool = false,
isBlocked: Bool = false,
isBlocked: Bool? = false,
isDisabled: Bool = false,
isHidden: Bool? = nil,
members: [MemberPayload] = [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ extension XCTestCase {
ownCapabilities: [String] = [],
channelExtraData: [String: RawJSON] = [:],
createdAt: Date = XCTestCase.channelCreatedDate,
blocked: Bool? = false,
hidden: Bool? = nil,
truncatedAt: Date? = nil,
cooldownDuration: Int? = nil,
channelReads: [ChannelReadPayload]? = nil
Expand Down Expand Up @@ -189,8 +191,8 @@ extension XCTestCase {
ownCapabilities: ownCapabilities,
isDisabled: false,
isFrozen: true,
isBlocked: false,
isHidden: nil,
isBlocked: blocked,
isHidden: hidden,
members: members,
memberCount: 100,
team: .unique,
Expand Down Expand Up @@ -409,9 +411,9 @@ extension XCTestCase {
latestAnswers: [PollVotePayload?]? = nil,
options: [PollOptionPayload?] = [],
ownVotes: [PollVotePayload?] = [],
custom: [String : RawJSON] = [:],
latestVotesByOption: [String : [PollVotePayload]] = [:],
voteCountsByOption: [String : Int] = [:],
custom: [String: RawJSON] = [:],
latestVotesByOption: [String: [PollVotePayload]] = [:],
voteCountsByOption: [String: Int] = [:],
isClosed: Bool? = nil,
maxVotesAllowed: Int? = nil,
votingVisibility: String? = nil,
Expand Down Expand Up @@ -501,7 +503,7 @@ private extension MemberPayload {
isInvisible: true,
isBanned: true,
teams: [],
language: nil,
language: nil,
extraData: [:]
),
userId: userId,
Expand Down
67 changes: 65 additions & 2 deletions Tests/StreamChatTests/StateLayer/ChannelList_Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,65 @@ final class ChannelList_Tests: XCTestCase {
cancellable.cancel()
}

func test_updatingChannels_whenBlockedAndUnblockedWithHiddenQuery() async throws {
await setUpChannelList(
usesMockedChannelUpdater: false,
filter: .and([
.containMembers(userIds: [memberId]),
.or([
.and([.equal(.blocked, to: false), .equal(.hidden, to: false)]),
.and([.equal(.blocked, to: true), .equal(.hidden, to: true)])
])
])
)

// Get initial batch of channels where 2 are blocked, 3 are not
let blockedOffsets = Set([1, 3])
let hiddenOffsets = Set([1, 3])
let firstChannelListPayload = makeMatchingChannelListPayload(
channelCount: 5,
createdAtOffset: 0,
blocked: { _, offset in blockedOffsets.contains(offset) },
hidden: { _, offset in hiddenOffsets.contains(offset) }
)
env.client.mockAPIClient.test_mockResponseResult(.success(firstChannelListPayload))
try await channelList.get()
await XCTAssertEqual(5, channelList.state.channels.count)
await XCTAssertEqual(2, channelList.state.channels.filter(\.isBlocked).count)
await XCTAssertEqual(2, channelList.state.channels.filter(\.isHidden).count)

// Send an event which does not include blocked and hidden states, but contains channel info
// Channel gets saved to DB and should not change blocked and hidden states.
let secondChannel = firstChannelListPayload.channels[1].channel
let channelPayloadWithoutBlockedAndHidden = ChannelDetailPayload.dummy(
cid: secondChannel.cid,
isBlocked: nil,
isHidden: nil,
members: secondChannel.members ?? []
)
let eventPayload = EventPayload(
eventType: .notificationMarkRead,
cid: channelPayloadWithoutBlockedAndHidden.cid,
user: .dummy(userId: memberId),
channel: channelPayloadWithoutBlockedAndHidden,
unreadCount: .init(channels: 0, messages: 0, threads: 0),
createdAt: Date()
)
let notificationMarkReadEvent = try NotificationMarkReadEventDTO(from: eventPayload)
let expectation = XCTestExpectation()
env.client.eventNotificationCenter.process(notificationMarkReadEvent, postNotification: true) {
expectation.fulfill()
}
await fulfillment(of: [expectation])

let secondChannelDataAfterEvent = try env.client.databaseContainer.readSynchronously { session in
try XCTUnwrap(session.channel(cid: secondChannel.cid)).asModel()
}
XCTAssertEqual(true, secondChannelDataAfterEvent.isBlocked, "State did not change")
XCTAssertEqual(true, secondChannelDataAfterEvent.isHidden, "State did not change")
await XCTAssertEqual(5, channelList.state.channels.count)
}

// MARK: - Linking and Unlinking Channels

func test_observingEvents_whenAddedToChannelEventReceived_thenChannelIsLinkedAndStateUpdates() async throws {
Expand Down Expand Up @@ -487,7 +546,9 @@ final class ChannelList_Tests: XCTestCase {
createdAtOffset: Int,
namePrefix: String = "Name",
membersCreator: ((ChannelId, Int) -> [MemberPayload])? = nil,
messagesCreator: ((ChannelId, Int) -> [MessagePayload])? = nil
messagesCreator: ((ChannelId, Int) -> [MessagePayload])? = nil,
blocked: ((ChannelId, Int) -> Bool) = { _, _ in false },
hidden: ((ChannelId, Int) -> Bool) = { _, _ in false }
) -> ChannelListPayload {
let channelPayloads = (0..<channelCount)
.map {
Expand All @@ -498,7 +559,9 @@ final class ChannelList_Tests: XCTestCase {
name: "\(namePrefix) \($0 + createdAtOffset)",
members: members,
messages: messagesCreator?(channelId, $0 + createdAtOffset),
createdAt: Date(timeIntervalSinceReferenceDate: TimeInterval($0 + createdAtOffset))
createdAt: Date(timeIntervalSinceReferenceDate: TimeInterval($0 + createdAtOffset)),
blocked: blocked(channelId, $0 + createdAtOffset),
hidden: hidden(channelId, $0 + createdAtOffset)
)
}
return ChannelListPayload(channels: channelPayloads)
Expand Down
Loading