Skip to content

Commit dbe7538

Browse files
testableapplemartinmitrevskilaevandusStream Bot
authored
Merge develop to v5 (#3960)
* [CI] Convert Xcode groups to buildable folders (#3940) * [CI] Delete unused test artifact (#3944) * [CI] Resolve mock server compilation issue (#3946) * [CI] Resolve target membership issues after migrating to buildable folders (#3949) * Make the members and messages size in ChannelListQuery optional (#3951) * Prevent adding back deleted reactions in case of client errors (#3956) * Fix refreshing channel when setting push notification preference for the first time (#3954) * Bump 4.97.1 * Update release version to snapshot --------- Co-authored-by: Martin Mitrevski <martinmitrevski.oh@gmail.com> Co-authored-by: Toomas Vahter <toomas.vahter@getstream.io> Co-authored-by: Stream Bot <ci@getstream.io>
1 parent c1a1d53 commit dbe7538

6 files changed

Lines changed: 144 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66
### 🔄 Changed
77
- Messages and members limit in `ChannelListQuery` are now using server-side defaults [#3951](https://github.com/GetStream/stream-chat-swift/pull/3951)
88

9+
# [4.97.1](https://github.com/GetStream/stream-chat-swift/releases/tag/4.97.1)
10+
_February 11, 2026_
11+
12+
### 🔄 Changed
13+
- Messages and members limit in `ChannelListQuery` are now using server-side defaults [#3951](https://github.com/GetStream/stream-chat-swift/pull/3951)
14+
915
# [4.97.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.97.0)
1016
_January 27, 2026_
1117

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<a href="https://sonarcloud.io/summary/new_code?id=GetStream_stream-chat-swift"><img src="https://sonarcloud.io/api/project_badges/measure?project=GetStream_stream-chat-swift&metric=coverage" /></a>
1212
</p>
1313
<p align="center">
14-
<img id="stream-chat-label" alt="StreamChat" src="https://img.shields.io/badge/StreamChat-8.63%20MB-blue"/>
14+
<img id="stream-chat-label" alt="StreamChat" src="https://img.shields.io/badge/StreamChat-8.6%20MB-blue"/>
1515
<img id="stream-chat-ui-label" alt="StreamChatUI" src="https://img.shields.io/badge/StreamChatUI-4.91%20MB-blue"/>
1616
<img id="stream-chat-common-ui-label" alt="StreamChatCommonUI" src="https://img.shields.io/badge/StreamChatCommonUI-0.75%20MB-blue"/>
1717
</p>

Sources/StreamChat/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>4.97.0</string>
18+
<string>4.97.1</string>
1919
<key>CFBundleVersion</key>
2020
<string>$(CURRENT_PROJECT_VERSION)</string>
2121
</dict>

Sources/StreamChat/Workers/ChannelUpdater.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -732,16 +732,22 @@ class ChannelUpdater: Worker, @unchecked Sendable {
732732
completion(.failure(ClientError.ChannelDoesNotExist(cid: cid)))
733733
return
734734
}
735-
self?.database.write {
736-
try $0.savePushPreference(
735+
self?.database.write({
736+
let dto = try $0.savePushPreference(
737737
id: cid.rawValue,
738738
payload: .init(
739739
chatLevel: channelPref.level.rawValue,
740740
disabledUntil: channelPref.disabledUntil
741741
)
742742
)
743-
}
744-
completion(.success(channelPref))
743+
$0.channel(cid: cid)?.pushPreference = dto
744+
}, completion: { error in
745+
if let error = error {
746+
completion(.failure(error))
747+
} else {
748+
completion(.success(channelPref))
749+
}
750+
})
745751
case let .failure(error):
746752
completion(.failure(error))
747753
}

Sources/StreamChatUI/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>4.97.0</string>
18+
<string>4.97.1</string>
1919
<key>CFBundleVersion</key>
2020
<string>$(CURRENT_PROJECT_VERSION)</string>
2121
</dict>

Tests/StreamChatTests/Workers/ChannelUpdater_Tests.swift

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2402,4 +2402,129 @@ final class ChannelUpdater_Tests: XCTestCase {
24022402
// THEN
24032403
AssertAsync.willBeTrue(completionError is ClientError.ChannelDoesNotExist)
24042404
}
2405+
2406+
func test_setPushPreference_firstTimeUpdate_associatesPushPreferenceWithChannel() throws {
2407+
// GIVEN
2408+
// Create a channel without any push preference
2409+
let cid: ChannelId = .unique
2410+
try database.writeSynchronously { session in
2411+
try session.saveChannel(payload: .dummy(cid: cid), query: nil, cache: nil)
2412+
}
2413+
2414+
// Verify channel exists but has no push preference initially
2415+
XCTAssertNotNil(database.viewContext.channel(cid: cid))
2416+
XCTAssertNil(database.viewContext.channel(cid: cid)?.pushPreference)
2417+
2418+
let preference = PushPreferenceRequestPayload(
2419+
chatLevel: "mentions",
2420+
channelId: cid.rawValue,
2421+
disabledUntil: nil,
2422+
removeDisable: true
2423+
)
2424+
2425+
let response = PushPreferencesPayloadResponse(
2426+
userPreferences: [:],
2427+
channelPreferences: [
2428+
"userId": [
2429+
cid.rawValue: PushPreferencePayload(
2430+
chatLevel: "mentions",
2431+
disabledUntil: nil
2432+
)
2433+
]
2434+
]
2435+
)
2436+
2437+
// WHEN
2438+
let exp = expectation(description: "setPushPreference completion")
2439+
var receivedPreference: PushPreference?
2440+
channelUpdater.setPushPreference(preference, cid: cid) { result in
2441+
if case .success(let pref) = result {
2442+
receivedPreference = pref
2443+
}
2444+
exp.fulfill()
2445+
}
2446+
2447+
apiClient.test_simulateResponse(.success(response))
2448+
2449+
waitForExpectations(timeout: defaultTimeout)
2450+
2451+
// THEN
2452+
// Verify the push preference was successfully set
2453+
XCTAssertEqual(receivedPreference?.level, .mentions)
2454+
XCTAssertNil(receivedPreference?.disabledUntil)
2455+
2456+
// Verify the channel now has the push preference associated
2457+
let channel: ChatChannel? = try database.readSynchronously { session in
2458+
try session.channel(cid: cid)?.asModel()
2459+
}
2460+
XCTAssertNotNil(channel?.pushPreference)
2461+
XCTAssertEqual(channel?.pushPreference?.level, .mentions)
2462+
XCTAssertNil(channel?.pushPreference?.disabledUntil)
2463+
}
2464+
2465+
func test_setPushPreference_subsequentUpdate_updatesPushPreferenceCorrectly() throws {
2466+
// GIVEN
2467+
// Create a channel with an existing push preference
2468+
let cid: ChannelId = .unique
2469+
try database.writeSynchronously { session in
2470+
try session.saveChannel(payload: .dummy(cid: cid), query: nil, cache: nil)
2471+
let pushPreferenceDTO = try session.savePushPreference(
2472+
id: cid.rawValue,
2473+
payload: .init(
2474+
chatLevel: "none",
2475+
disabledUntil: nil
2476+
)
2477+
)
2478+
session.channel(cid: cid)?.pushPreference = pushPreferenceDTO
2479+
}
2480+
2481+
// Verify channel has the initial push preference
2482+
XCTAssertEqual(database.viewContext.channel(cid: cid)?.pushPreference?.chatLevel, "none")
2483+
2484+
let preference = PushPreferenceRequestPayload(
2485+
chatLevel: "all",
2486+
channelId: cid.rawValue,
2487+
disabledUntil: nil,
2488+
removeDisable: true
2489+
)
2490+
2491+
let response = PushPreferencesPayloadResponse(
2492+
userPreferences: [:],
2493+
channelPreferences: [
2494+
"userId": [
2495+
cid.rawValue: PushPreferencePayload(
2496+
chatLevel: "all",
2497+
disabledUntil: nil
2498+
)
2499+
]
2500+
]
2501+
)
2502+
2503+
// WHEN
2504+
let exp = expectation(description: "setPushPreference completion")
2505+
var receivedPreference: PushPreference?
2506+
channelUpdater.setPushPreference(preference, cid: cid) { result in
2507+
if case .success(let pref) = result {
2508+
receivedPreference = pref
2509+
}
2510+
exp.fulfill()
2511+
}
2512+
2513+
apiClient.test_simulateResponse(.success(response))
2514+
2515+
waitForExpectations(timeout: defaultTimeout)
2516+
2517+
// THEN
2518+
// Verify the push preference was successfully updated
2519+
XCTAssertEqual(receivedPreference?.level, .all)
2520+
XCTAssertNil(receivedPreference?.disabledUntil)
2521+
2522+
// Verify the channel's push preference was updated
2523+
let channel: ChatChannel? = try database.readSynchronously { session in
2524+
try session.channel(cid: cid)?.asModel()
2525+
}
2526+
XCTAssertNotNil(channel?.pushPreference)
2527+
XCTAssertEqual(channel?.pushPreference?.level, .all)
2528+
XCTAssertNil(channel?.pushPreference?.disabledUntil)
2529+
}
24052530
}

0 commit comments

Comments
 (0)