Skip to content

Commit fe9dc14

Browse files
committed
Merge branch 'swift-6' into swift-6-ui
2 parents d6dc7e4 + e5b15f1 commit fe9dc14

File tree

8 files changed

+52
-42
lines changed

8 files changed

+52
-42
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
88
- Fix swipe to reply enabled when quoting a message is disabled [#3662](https://github.com/GetStream/stream-chat-swift/pull/3662)
99
- Fix shadowed messages increasing the channel messages unread count [#3665](https://github.com/GetStream/stream-chat-swift/pull/3665)
1010

11+
## StreamChatUI
12+
### 🐞 Fixed
13+
- Fix `ChatMessagePopupVC` transition animation when there are no reactions [#3670](https://github.com/GetStream/stream-chat-swift/pull/3670)
14+
1115
# [4.78.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.78.0)
1216
_April 24, 2025_
1317

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ You can still integrate our SDKs if your project is using Objective-C. In that c
8282

8383
---
8484

85+
## Video SDK
86+
87+
We also offer [Video SDK](https://github.com/GetStream/stream-video-swift) that seamlessly integrates with our Chat SDK. To find out more about this product, please check our [docs](https://getstream.io/video/docs/ios/).
88+
89+
---
90+
8591
## We are hiring
8692

8793
We've recently closed a [\$38 million Series B funding round](https://techcrunch.com/2021/03/04/stream-raises-38m-as-its-chat-and-activity-feed-apis-power-communications-for-1b-users/) and we keep actively growing.

Sources/StreamChat/Audio/AudioPlayer/AudioPlaying.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
131131
open func play() {
132132
do {
133133
try audioSessionConfigurator.activatePlaybackSession()
134-
MainActor.ensureIsolated {
134+
Task { @MainActor in
135135
player.play()
136136
}
137137
} catch {
@@ -141,7 +141,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
141141
}
142142

143143
open func pause() {
144-
MainActor.ensureIsolated {
144+
Task { @MainActor in
145145
player.pause()
146146
}
147147
}
@@ -170,7 +170,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
170170
}
171171

172172
open func updateRate(_ newRate: AudioPlaybackRate) {
173-
MainActor.ensureIsolated {
173+
Task { @MainActor in
174174
player.rate = newRate.rawValue
175175
}
176176
}
@@ -203,7 +203,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
203203

204204
func playbackWillStop(_ playerItem: AVPlayerItem) {
205205
let matchesCurrentItem: Bool = {
206-
MainActor.ensureIsolated {
206+
DispatchQueue.performSynchronouslyOnMainQueue {
207207
let playerItemURL = (playerItem.asset as? AVURLAsset)?.url
208208
let currentItemURL = (player.currentItem?.asset as? AVURLAsset)?.url
209209
return playerItemURL != nil && playerItemURL == currentItemURL
@@ -236,7 +236,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
236236
guard let self = self, self.context.isSeeking == false else {
237237
return
238238
}
239-
let rate = MainActor.ensureIsolated { player.rate }
239+
let rate = DispatchQueue.performSynchronouslyOnMainQueue { player.rate }
240240
self.updateContext { value in
241241
let currentTime = player.currentTime().seconds
242242
value.currentTime = currentTime.isFinite && !currentTime.isNaN
@@ -281,7 +281,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
281281
}
282282

283283
private func notifyDelegates() {
284-
MainActor.ensureIsolated {
284+
Task { @MainActor in
285285
multicastDelegate.invoke { $0.audioPlayer(self, didUpdateContext: context) }
286286
}
287287
}
@@ -308,7 +308,7 @@ open class StreamAudioPlayer: AudioPlaying, AppStateObserverDelegate, @unchecked
308308
/// We are going to check if the URL requested to load, represents the currentItem that we
309309
/// have already loaded (if any). In this case, we will try either to resume the existing playback
310310
/// or restart it, if possible.
311-
let currentItem = MainActor.ensureIsolated { player.currentItem?.asset as? AVURLAsset }
311+
let currentItem = DispatchQueue.performSynchronouslyOnMainQueue { player.currentItem?.asset as? AVURLAsset }
312312
if let currentItem,
313313
asset.url == currentItem.url,
314314
context.assetLocation == asset.url {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// Copyright © 2025 Stream.io Inc. All rights reserved.
3+
//
4+
5+
import Foundation
6+
7+
extension DispatchQueue {
8+
/// Synchronously performs the provided action on the main thread.
9+
///
10+
/// Performing this action is safe because the function checks the current thread, and if it's currently in the main
11+
/// one, it performs the action safely without dead-locking the thread.
12+
///
13+
/// - Important: Most of the time we should use `Task { @MainActor in`, but in some cases we need the blocking manner.
14+
static func performSynchronouslyOnMainQueue<T>(_ action: @MainActor() throws -> T) rethrows -> T where T: Sendable {
15+
if Thread.current.isMainThread {
16+
try MainActor.assumeIsolated {
17+
try action()
18+
}
19+
} else {
20+
try DispatchQueue.main.sync {
21+
try action()
22+
}
23+
}
24+
}
25+
}

Sources/StreamChat/Utils/MainQueue+Synchronous.swift

Lines changed: 0 additions & 26 deletions
This file was deleted.

Sources/StreamChatUI/MessageActionsPopup/MessageActionsTransitionController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ open class ChatMessageActionsTransitionController: NSObject, UIViewControllerTra
9595
toVC.messageContentView = messageView
9696
toVC.messageViewFrame = messageViewFrame
9797
toVC.setUpLayout()
98+
toVC.view.layoutIfNeeded()
9899

99100
let blurView = UIVisualEffectView()
100101
blurView.frame = transitionContext.finalFrame(for: toVC)

StreamChat.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@
277277
4F6AD5E52CABEAB6007E769C /* KeyPath+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6AD5E32CABEAB0007E769C /* KeyPath+Extensions.swift */; };
278278
4F6B84102D008D6E005645B0 /* MemberUpdatePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6B840F2D008D5F005645B0 /* MemberUpdatePayload.swift */; };
279279
4F6B84112D008D6E005645B0 /* MemberUpdatePayload.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6B840F2D008D5F005645B0 /* MemberUpdatePayload.swift */; };
280+
4F6FB1AB2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */; };
281+
4F6FB1AC2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */; };
280282
4F73F3982B91BD3000563CD9 /* MessageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F73F3972B91BD3000563CD9 /* MessageState.swift */; };
281283
4F73F3992B91BD3000563CD9 /* MessageState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F73F3972B91BD3000563CD9 /* MessageState.swift */; };
282284
4F73F39E2B91C7BF00563CD9 /* MessageState+Observer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F73F39D2B91C7BF00563CD9 /* MessageState+Observer.swift */; };
@@ -612,7 +614,6 @@
612614
797EEA4624FFAF4F00C81203 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EEA4524FFAF4F00C81203 /* DataStore.swift */; };
613615
797EEA4824FFB4C200C81203 /* DataStore_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EEA4724FFB4C200C81203 /* DataStore_Tests.swift */; };
614616
797EEA4A24FFC37600C81203 /* ConnectionStatus_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797EEA4924FFC37600C81203 /* ConnectionStatus_Tests.swift */; };
615-
7985BDAA252B1E53002B8C30 /* MainQueue+Synchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */; };
616617
79877A092498E4BC00015F8B /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79877A012498E4BB00015F8B /* User.swift */; };
617618
79877A0A2498E4BC00015F8B /* Device.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79877A022498E4BB00015F8B /* Device.swift */; };
618619
79877A0B2498E4BC00015F8B /* Member.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79877A032498E4BB00015F8B /* Member.swift */; };
@@ -2213,7 +2214,6 @@
22132214
C121E8EC274544B200023E4C /* Publisher+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA4AA3B92502731900FAAF6E /* Publisher+Extensions.swift */; };
22142215
C121E8ED274544B200023E4C /* UniqueId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 797E10A724EAF6DE00353791 /* UniqueId.swift */; };
22152216
C121E8EE274544B200023E4C /* MulticastDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79CD959124F9380B00E87377 /* MulticastDelegate.swift */; };
2216-
C121E8EF274544B200023E4C /* MainQueue+Synchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */; };
22172217
C121E8F0274544B200023E4C /* Dictionary+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 88EA9AD725470F6A007EE76B /* Dictionary+Extensions.swift */; };
22182218
C121E8F1274544B200023E4C /* MultipartFormData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 881506EB258212BF0013935B /* MultipartFormData.swift */; };
22192219
C121E8F2274544B200023E4C /* SystemEnvironment+Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7AD954E25D536AA00076DC3 /* SystemEnvironment+Version.swift */; };
@@ -3269,6 +3269,7 @@
32693269
4F6A77032D2FD09A0019CAF8 /* AppSettings_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings_Tests.swift; sourceTree = "<group>"; };
32703270
4F6AD5E32CABEAB0007E769C /* KeyPath+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "KeyPath+Extensions.swift"; sourceTree = "<group>"; };
32713271
4F6B840F2D008D5F005645B0 /* MemberUpdatePayload.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberUpdatePayload.swift; sourceTree = "<group>"; };
3272+
4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Extensions.swift"; sourceTree = "<group>"; };
32723273
4F73F3972B91BD3000563CD9 /* MessageState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageState.swift; sourceTree = "<group>"; };
32733274
4F73F39D2B91C7BF00563CD9 /* MessageState+Observer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageState+Observer.swift"; sourceTree = "<group>"; };
32743275
4F7B58942DCB6B5A0034CC0F /* AllocatedUnfairLock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllocatedUnfairLock.swift; sourceTree = "<group>"; };
@@ -3537,7 +3538,6 @@
35373538
797EEA4524FFAF4F00C81203 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = "<group>"; };
35383539
797EEA4724FFB4C200C81203 /* DataStore_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore_Tests.swift; sourceTree = "<group>"; };
35393540
797EEA4924FFC37600C81203 /* ConnectionStatus_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectionStatus_Tests.swift; sourceTree = "<group>"; };
3540-
7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MainQueue+Synchronous.swift"; sourceTree = "<group>"; };
35413541
798779F62498E47700015F8B /* Member.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Member.json; sourceTree = "<group>"; };
35423542
798779F72498E47700015F8B /* Channel.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Channel.json; sourceTree = "<group>"; };
35433543
798779F82498E47700015F8B /* OtherUser.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = OtherUser.json; sourceTree = "<group>"; };
@@ -5850,10 +5850,10 @@
58505850
792A4F3E247FFDE700EAF71D /* Data+Gzip.swift */,
58515851
40789D3B29F6AD9C0018C2BB /* Debouncer.swift */,
58525852
88EA9AD725470F6A007EE76B /* Dictionary+Extensions.swift */,
5853+
4F6FB1AA2DE05758003DF330 /* DispatchQueue+Extensions.swift */,
58535854
84CF9C72274D473D00BCDE2D /* EventBatcher.swift */,
58545855
C173538D27D9F804008AC412 /* KeyedDecodingContainer+Array.swift */,
58555856
DBCAFE2325C44B920015AD58 /* LazyCachedMapCollection.swift */,
5856-
7985BDA9252B1E53002B8C30 /* MainQueue+Synchronous.swift */,
58575857
4FE56B8C2D5DFE3A00589F9A /* MarkdownParser.swift */,
58585858
79CD959124F9380B00E87377 /* MulticastDelegate.swift */,
58595859
881506EB258212BF0013935B /* MultipartFormData.swift */,
@@ -11542,7 +11542,6 @@
1154211542
4F1BEE792BE384FE00B6685C /* ReactionListState.swift in Sources */,
1154311543
79C5CBE825F66DBD00D98001 /* ChatChannelWatcherListController.swift in Sources */,
1154411544
8A62706E24BF45360040BFD6 /* BanEnabling.swift in Sources */,
11545-
7985BDAA252B1E53002B8C30 /* MainQueue+Synchronous.swift in Sources */,
1154611545
ADF9E1F72A03E7E400109108 /* MessagesPaginationState.swift in Sources */,
1154711546
79983C8126663436000995F6 /* ChatMessageVideoAttachment.swift in Sources */,
1154811547
ADEEB7F22BD1368900C76602 /* MessageReactionGroupPayload.swift in Sources */,
@@ -11835,6 +11834,7 @@
1183511834
AD7DFC3625D2FA8100DD9DA3 /* CurrentUserUpdater.swift in Sources */,
1183611835
AD0CC0342BDC4A6B005E2C66 /* ReactionListController+Combine.swift in Sources */,
1183711836
88206FC425B18C88009D086A /* ConnectionRepository.swift in Sources */,
11837+
4F6FB1AB2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */,
1183811838
79682C4B24BF37CB0071578E /* ChannelListPayload.swift in Sources */,
1183911839
AD545E642D52827B008FD399 /* DraftListQuery.swift in Sources */,
1184011840
79D6CE3725F7C84600BE2EEC /* ChatChannelWatcherListController+SwiftUI.swift in Sources */,
@@ -12729,6 +12729,7 @@
1272912729
841BAA052BCE94F8000C73E4 /* QueryPollsRequestBody.swift in Sources */,
1273012730
C121E8B4274544B000023E4C /* CurrentUserController+SwiftUI.swift in Sources */,
1273112731
40789D1E29F6AC500018C2BB /* AudioPlayingDelegate.swift in Sources */,
12732+
4F6FB1AC2DE05760003DF330 /* DispatchQueue+Extensions.swift in Sources */,
1273212733
ADF2BBEC2B9B622B0069D467 /* AppSettingsPayload.swift in Sources */,
1273312734
C121E8B5274544B000023E4C /* CurrentUserController+Combine.swift in Sources */,
1273412735
C121E8B6274544B000023E4C /* ConnectionController.swift in Sources */,
@@ -12821,7 +12822,6 @@
1282112822
C121E8EC274544B200023E4C /* Publisher+Extensions.swift in Sources */,
1282212823
C121E8ED274544B200023E4C /* UniqueId.swift in Sources */,
1282312824
C121E8EE274544B200023E4C /* MulticastDelegate.swift in Sources */,
12824-
C121E8EF274544B200023E4C /* MainQueue+Synchronous.swift in Sources */,
1282512825
C121E8F0274544B200023E4C /* Dictionary+Extensions.swift in Sources */,
1282612826
C121E8F1274544B200023E4C /* MultipartFormData.swift in Sources */,
1282712827
AD545E672D53C271008FD399 /* DraftMessagesRepository.swift in Sources */,

TestTools/StreamChatTestTools/Mocks/StreamChat/VoiceRecording/MockAVPlayer.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class MockAVPlayer: AVPlayer {
4444
override public func replaceCurrentItem(
4545
with item: AVPlayerItem?
4646
) {
47-
MainActor.ensureIsolated {
47+
DispatchQueue.performSynchronouslyOnMainQueue {
4848
replaceCurrentItemWasCalled = true
4949
replaceCurrentItemWasCalledWithItem = item
5050
}
@@ -57,7 +57,7 @@ public class MockAVPlayer: AVPlayer {
5757
toleranceAfter: CMTime,
5858
completionHandler: @escaping @Sendable(Bool) -> Void
5959
) {
60-
MainActor.ensureIsolated {
60+
DispatchQueue.performSynchronouslyOnMainQueue {
6161
seekWasCalledWithTime = time
6262
seekWasCalledWithToleranceBefore = toleranceBefore
6363
seekWasCalledWithToleranceAfter = toleranceAfter
@@ -67,7 +67,7 @@ public class MockAVPlayer: AVPlayer {
6767
toleranceBefore: toleranceBefore,
6868
toleranceAfter: toleranceAfter,
6969
completionHandler: { _ in
70-
MainActor.ensureIsolated {
70+
Task { @MainActor in
7171
completionHandler(!self.holdSeekCompletion)
7272
}
7373
}

0 commit comments

Comments
 (0)