From 760575f2e50a1fb448463ee12e055d9c1b8fb223 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 1 Nov 2022 16:14:18 +0400 Subject: [PATCH 01/15] [WIP] Call session --- .../Sources/OngoingCallContext.swift | 2 +- .../OngoingCallThreadLocalContext.h | 19 ++++++++++++- .../Sources/OngoingCallThreadLocalContext.mm | 27 ++++++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/submodules/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index 8f24013ef5..574dbcb347 100644 --- a/submodules/TelegramVoip/Sources/OngoingCallContext.swift +++ b/submodules/TelegramVoip/Sources/OngoingCallContext.swift @@ -886,7 +886,7 @@ public final class OngoingCallContext { callSessionManager.sendSignalingData(internalId: internalId, data: data) } } - }, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec, audioInputDeviceId: "") + }, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec, audioInputDeviceId: "", useManualAudioSessionControl: true) strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context)) context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in diff --git a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h index d75206844c..81db3ec7fc 100644 --- a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h +++ b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h @@ -206,7 +206,24 @@ typedef NS_ENUM(int32_t, OngoingCallDataSavingWebrtc) { @property (nonatomic, copy) void (^ _Nullable signalBarsChanged)(int32_t); @property (nonatomic, copy) void (^ _Nullable audioLevelUpdated)(float); -- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing connections:(NSArray * _Nonnull)connections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P allowTCP:(BOOL)allowTCP enableStunMarking:(BOOL)enableStunMarking logPath:(NSString * _Nonnull)logPath statsLogPath:(NSString * _Nonnull)statsLogPath sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec audioInputDeviceId: (NSString * _Nonnull)audioInputDeviceId; +- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id _Nonnull)queue + proxy:(VoipProxyServerWebrtc * _Nullable)proxy + networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving + derivedState:(NSData * _Nonnull)derivedState + key:(NSData * _Nonnull)key + isOutgoing:(bool)isOutgoing + connections:(NSArray * _Nonnull)connections maxLayer:(int32_t)maxLayer + allowP2P:(BOOL)allowP2P + allowTCP:(BOOL)allowTCP + enableStunMarking:(BOOL)enableStunMarking + logPath:(NSString * _Nonnull)logPath + statsLogPath:(NSString * _Nonnull)statsLogPath + sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer + preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec + audioInputDeviceId:(NSString * _Nonnull)audioInputDeviceId + useManualAudioSessionControl:(bool)useManualAudioSessionControl; + +- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive; - (void)beginTermination; - (void)stop:(void (^_Nullable)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile))completion; diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 32c1ddb7d2..636c7248a3 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -705,6 +705,8 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls: id _queue; int32_t _contextId; + bool _useManualAudioSessionControl; + OngoingCallNetworkTypeWebrtc _networkType; NSTimeInterval _callReceiveTimeout; NSTimeInterval _callRingTimeout; @@ -843,7 +845,22 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; } } -- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id _Nonnull)queue proxy:(VoipProxyServerWebrtc * _Nullable)proxy networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving derivedState:(NSData * _Nonnull)derivedState key:(NSData * _Nonnull)key isOutgoing:(bool)isOutgoing connections:(NSArray * _Nonnull)connections maxLayer:(int32_t)maxLayer allowP2P:(BOOL)allowP2P allowTCP:(BOOL)allowTCP enableStunMarking:(BOOL)enableStunMarking logPath:(NSString * _Nonnull)logPath statsLogPath:(NSString * _Nonnull)statsLogPath sendSignalingData:(void (^)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec audioInputDeviceId: (NSString * _Nonnull)audioInputDeviceId { +- (instancetype _Nonnull)initWithVersion:(NSString * _Nonnull)version queue:(id _Nonnull)queue + proxy:(VoipProxyServerWebrtc * _Nullable)proxy + networkType:(OngoingCallNetworkTypeWebrtc)networkType dataSaving:(OngoingCallDataSavingWebrtc)dataSaving + derivedState:(NSData * _Nonnull)derivedState + key:(NSData * _Nonnull)key + isOutgoing:(bool)isOutgoing + connections:(NSArray * _Nonnull)connections maxLayer:(int32_t)maxLayer + allowP2P:(BOOL)allowP2P + allowTCP:(BOOL)allowTCP + enableStunMarking:(BOOL)enableStunMarking + logPath:(NSString * _Nonnull)logPath + statsLogPath:(NSString * _Nonnull)statsLogPath + sendSignalingData:(void (^ _Nonnull)(NSData * _Nonnull))sendSignalingData videoCapturer:(OngoingCallThreadLocalContextVideoCapturer * _Nullable)videoCapturer + preferredVideoCodec:(NSString * _Nullable)preferredVideoCodec + audioInputDeviceId:(NSString * _Nonnull)audioInputDeviceId + useManualAudioSessionControl:(bool)useManualAudioSessionControl { self = [super init]; if (self != nil) { _version = version; @@ -852,6 +869,8 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; assert([[OngoingCallThreadLocalContextWebrtc versionsWithIncludeReference:true] containsObject:version]); + _useManualAudioSessionControl = useManualAudioSessionControl; + _callReceiveTimeout = 20.0; _callRingTimeout = 90.0; _callConnectTimeout = 30.0; @@ -1094,6 +1113,12 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; - (void)beginTermination { } +- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive { + if (_useManualAudioSessionControl) { + + } +} + + (void)stopWithTerminationResult:(OngoingCallThreadLocalContextWebrtcTerminationResult *)terminationResult completion:(void (^)(NSString *, int64_t, int64_t, int64_t, int64_t))completion { if (completion) { if (terminationResult) { From feafa89a5b9e634738fa57c1a489f04d517b8d48 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 1 Nov 2022 17:46:07 +0400 Subject: [PATCH 02/15] [WIP] Call session setup --- .../Sources/CallKitIntegration.swift | 2 +- .../Sources/PresentationCall.swift | 4 +- .../Sources/OngoingCallContext.swift | 99 +++++++++++++++---- .../Sources/OngoingCallThreadLocalContext.mm | 11 ++- submodules/TgVoipWebrtc/tgcalls | 2 +- 5 files changed, 96 insertions(+), 22 deletions(-) diff --git a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift index 3629693c2b..ee37b01142 100644 --- a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift +++ b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift @@ -321,6 +321,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { } func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { + print("provider didActivate default? \(audioSession === AVAudioSession.sharedInstance())") self.audioSessionActivationChanged?(true) self.audioSessionActivePromise?.set(true) } @@ -330,4 +331,3 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { self.audioSessionActivePromise?.set(false) } } - diff --git a/submodules/TelegramCallsUI/Sources/PresentationCall.swift b/submodules/TelegramCallsUI/Sources/PresentationCall.swift index e877e21ebb..21640fac09 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCall.swift @@ -437,7 +437,7 @@ public final class PresentationCallImpl: PresentationCall { let audioSessionActive: Signal if let callKitIntegration = strongSelf.callKitIntegration { audioSessionActive = callKitIntegration.audioSessionActive - |> filter { $0 } + /*|> filter { $0 } |> timeout(2.0, queue: Queue.mainQueue(), alternate: Signal { subscriber in if let strongSelf = self, let _ = strongSelf.audioSessionControl { //audioSessionControl.activate({ _ in }) @@ -445,7 +445,7 @@ public final class PresentationCallImpl: PresentationCall { subscriber.putNext(true) subscriber.putCompletion() return EmptyDisposable - }) + })*/ } else { audioSessionControl.activate({ _ in }) audioSessionActive = .single(true) diff --git a/submodules/TelegramVoip/Sources/OngoingCallContext.swift b/submodules/TelegramVoip/Sources/OngoingCallContext.swift index 574dbcb347..776b3d71c2 100644 --- a/submodules/TelegramVoip/Sources/OngoingCallContext.swift +++ b/submodules/TelegramVoip/Sources/OngoingCallContext.swift @@ -326,6 +326,7 @@ private protocol OngoingCallThreadLocalContextProtocol: AnyObject { func nativeVersion() -> String func nativeGetDerivedState() -> Data func addExternalAudioData(data: Data) + func nativeSetIsAudioSessionActive(isActive: Bool) } private final class OngoingCallThreadLocalContextHolder { @@ -381,6 +382,9 @@ extension OngoingCallThreadLocalContext: OngoingCallThreadLocalContextProtocol { func addExternalAudioData(data: Data) { } + + func nativeSetIsAudioSessionActive(isActive: Bool) { + } } public final class OngoingCallVideoCapturer { @@ -573,6 +577,10 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt func addExternalAudioData(data: Data) { self.addExternalAudioData(data) } + + func nativeSetIsAudioSessionActive(isActive: Bool) { + self.setManualAudioSessionIsActive(isActive) + } } private extension OngoingCallContextState.State { @@ -726,6 +734,7 @@ public final class OngoingCallContext { } private let audioSessionDisposable = MetaDisposable() + private let audioSessionActiveDisposable = MetaDisposable() private var networkTypeDisposable: Disposable? public static var maxLayer: Int32 { @@ -950,6 +959,16 @@ public final class OngoingCallContext { self?.audioLevelPromise.set(.single(level)) } + strongSelf.audioSessionActiveDisposable.set((audioSessionActive + |> deliverOn(queue)).start(next: { isActive in + guard let strongSelf = self else { + return + } + strongSelf.withContext { context in + context.nativeSetIsAudioSessionActive(isActive: isActive) + } + })) + strongSelf.networkTypeDisposable = (updatedNetworkType |> deliverOn(queue)).start(next: { networkType in self?.withContext { context in @@ -1010,6 +1029,7 @@ public final class OngoingCallContext { } self.audioSessionDisposable.dispose() + self.audioSessionActiveDisposable.dispose() self.networkTypeDisposable?.dispose() } @@ -1256,6 +1276,8 @@ private final class CallSignalingConnectionImpl: CallSignalingConnection { } func start() { + OngoingCallThreadLocalContextWebrtc.logMessage("CallSignaling: Connecting...") + self.connection.start(queue: self.queue.queue) self.receivePacketHeader() } @@ -1399,48 +1421,91 @@ private final class CallSignalingConnectionImpl: CallSignalingConnection { } private final class CallSignalingConnectionManager { + private final class ConnectionContext { + let connection: CallSignalingConnection + let host: String + let port: UInt16 + + init(connection: CallSignalingConnection, host: String, port: UInt16) { + self.connection = connection + self.host = host + self.port = port + } + } + private let queue: Queue + private let peerTag: Data + private let dataReceived: (Data) -> Void + + private var isRunning: Bool = false private var nextConnectionId: Int = 0 - private var connections: [Int: CallSignalingConnection] = [:] + private var connections: [Int: ConnectionContext] = [:] init(queue: Queue, peerTag: Data, servers: [OngoingCallConnectionDescriptionWebrtc], dataReceived: @escaping (Data) -> Void) { self.queue = queue + self.peerTag = peerTag + self.dataReceived = dataReceived for server in servers { if server.hasTcp { - let id = self.nextConnectionId - self.nextConnectionId += 1 - if #available(iOS 12.0, *) { - let connection = CallSignalingConnectionImpl(queue: queue, host: server.ip, port: UInt16(server.port), peerTag: peerTag, dataReceived: { data in - dataReceived(data) - }, isClosed: { [weak self] in - guard let strongSelf = self else { - return - } - let _ = strongSelf - }) - connections[id] = connection - } + self.spawnConnection(host: server.ip, port: UInt16(server.port)) } } } func start() { + if self.isRunning { + return + } + self.isRunning = true + for (_, connection) in self.connections { - connection.start() + connection.connection.start() } } func stop() { + if !self.isRunning { + return + } + self.isRunning = false + for (_, connection) in self.connections { - connection.stop() + connection.connection.stop() } } func send(payloadData: Data) { for (_, connection) in self.connections { - connection.send(payloadData: payloadData) + connection.connection.send(payloadData: payloadData) + } + } + + private func spawnConnection(host: String, port: UInt16) { + let id = self.nextConnectionId + self.nextConnectionId += 1 + if #available(iOS 12.0, *) { + let dataReceived = self.dataReceived + let connection = CallSignalingConnectionImpl(queue: queue, host: host, port: port, peerTag: self.peerTag, dataReceived: { data in + dataReceived(data) + }, isClosed: { [weak self] in + guard let self else { + return + } + self.handleConnectionFailed(id: id) + }) + self.connections[id] = ConnectionContext(connection: connection, host: host, port: port) + if self.isRunning { + connection.start() + } + } + } + + private func handleConnectionFailed(id: Int) { + if let connection = self.connections.removeValue(forKey: id) { + connection.connection.stop() + self.spawnConnection(host: connection.host, port: connection.port) } } } diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 636c7248a3..12e0019f94 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -28,6 +28,9 @@ #include "platform/darwin/iOS/tgcalls_audio_device_module_ios.h" +#include "platform/darwin/iOS/RTCAudioSession.h" +#include "platform/darwin/iOS/RTCAudioSessionConfiguration.h" + #endif #import "group/GroupInstanceImpl.h" @@ -870,6 +873,7 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; assert([[OngoingCallThreadLocalContextWebrtc versionsWithIncludeReference:true] containsObject:version]); _useManualAudioSessionControl = useManualAudioSessionControl; + [RTCAudioSession sharedInstance].useManualAudio = true; _callReceiveTimeout = 20.0; _callRingTimeout = 90.0; @@ -1115,7 +1119,12 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; - (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive { if (_useManualAudioSessionControl) { - + if (isAudioSessionActive) { + [[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]]; + } else { + [[RTCAudioSession sharedInstance] audioSessionDidDeactivate:[AVAudioSession sharedInstance]]; + } + [RTCAudioSession sharedInstance].isAudioEnabled = isAudioSessionActive; } } diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 07b225568f..53bb1711ae 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 07b225568fb596ba44d472c3fa413da2f8bd3f2e +Subproject commit 53bb1711ae0b3810d34edb1c81982b18d70c5506 From c1c2a458ff5c049acfc84e3c2ed99917dc7d00e7 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 1 Nov 2022 20:23:25 +0400 Subject: [PATCH 03/15] [WIP] Audio session --- .../Sources/ManagedAudioSession.swift | 59 +++++++++++++++++++ .../Sources/CallKitIntegration.swift | 29 +++++++++ .../Sources/PresentationCall.swift | 14 ++++- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/submodules/TelegramAudio/Sources/ManagedAudioSession.swift b/submodules/TelegramAudio/Sources/ManagedAudioSession.swift index 2b3a8c16a3..de023e5d59 100644 --- a/submodules/TelegramAudio/Sources/ManagedAudioSession.swift +++ b/submodules/TelegramAudio/Sources/ManagedAudioSession.swift @@ -179,6 +179,8 @@ public class ManagedAudioSessionControl { } public final class ManagedAudioSession { + public private(set) static var shared: ManagedAudioSession? + private var nextId: Int32 = 0 private let queue: Queue private let hasLoudspeaker: Bool @@ -256,6 +258,8 @@ public final class ManagedAudioSession { self.isHeadsetPluggedInValue = self.isHeadsetPluggedIn() self.updateCurrentAudioRouteInfo() } + + ManagedAudioSession.shared = self } deinit { @@ -784,6 +788,61 @@ public final class ManagedAudioSession { } } + public func applyVoiceChatOutputModeInCurrentAudioSession(outputMode: AudioSessionOutputMode) { + managedAudioSessionLog("applyVoiceChatOutputModeInCurrentAudioSession \(outputMode)") + + do { + var resetToBuiltin = false + switch outputMode { + case .system: + resetToBuiltin = true + case let .custom(output): + switch output { + case .builtin: + resetToBuiltin = true + case .speaker: + if let routes = AVAudioSession.sharedInstance().availableInputs { + for route in routes { + if route.portType == .builtInMic { + let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route) + break + } + } + } + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.speaker) + case .headphones: + break + case let .port(port): + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) + if let routes = AVAudioSession.sharedInstance().availableInputs { + for route in routes { + if route.uid == port.uid { + let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route) + break + } + } + } + } + case .speakerIfNoHeadphones: + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) + } + + if resetToBuiltin { + try AVAudioSession.sharedInstance().overrideOutputAudioPort(.none) + if let routes = AVAudioSession.sharedInstance().availableInputs { + for route in routes { + if route.portType == .builtInMic { + let _ = try? AVAudioSession.sharedInstance().setPreferredInput(route) + break + } + } + } + } + } catch let e { + managedAudioSessionLog("applyVoiceChatOutputModeInCurrentAudioSession error: \(e)") + } + } + private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws { managedAudioSessionLog("ManagedAudioSession setup \(outputMode) for \(type)") var resetToBuiltin = false diff --git a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift index ee37b01142..62eb4d84d1 100644 --- a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift +++ b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift @@ -8,6 +8,7 @@ import TelegramCore import SwiftSignalKit import AppBundle import AccountContext +import TelegramAudio private let sharedProviderDelegate: AnyObject? = { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { @@ -107,6 +108,10 @@ public final class CallKitIntegration { } } } + + public func applyVoiceChatOutputMode(outputMode: AudioSessionOutputMode) { + (sharedProviderDelegate as? CallKitProviderDelegate)?.applyVoiceChatOutputMode(outputMode: outputMode) + } } @available(iOSApplicationExtension 10.0, iOS 10.0, *) @@ -125,6 +130,9 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { private var setCallMuted: ((UUID, Bool) -> Void)? private var audioSessionActivationChanged: ((Bool) -> Void)? + private var isAudioSessionActive: Bool = false + private var pendingVoiceChatOutputMode: AudioSessionOutputMode? + private let disposableSet = DisposableSet() fileprivate var audioSessionActivePromise: ValuePromise? @@ -238,6 +246,12 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { update.supportsDTMF = false update.hasVideo = isVideo + do { + try AVAudioSession.sharedInstance().setMode(.default) + } catch let e { + print("AVAudioSession.sharedInstance().setMode(.default) error \(e)") + } + self.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in completion?(error as NSError?) }) @@ -322,12 +336,27 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { print("provider didActivate default? \(audioSession === AVAudioSession.sharedInstance())") + self.isAudioSessionActive = true self.audioSessionActivationChanged?(true) self.audioSessionActivePromise?.set(true) + + if let outputMode = self.pendingVoiceChatOutputMode { + self.pendingVoiceChatOutputMode = nil + ManagedAudioSession.shared?.applyVoiceChatOutputModeInCurrentAudioSession(outputMode: outputMode) + } } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { + self.isAudioSessionActive = false self.audioSessionActivationChanged?(false) self.audioSessionActivePromise?.set(false) } + + func applyVoiceChatOutputMode(outputMode: AudioSessionOutputMode) { + if self.isAudioSessionActive { + ManagedAudioSession.shared?.applyVoiceChatOutputModeInCurrentAudioSession(outputMode: outputMode) + } else { + self.pendingVoiceChatOutputMode = outputMode + } + } } diff --git a/submodules/TelegramCallsUI/Sources/PresentationCall.swift b/submodules/TelegramCallsUI/Sources/PresentationCall.swift index 21640fac09..80c132529c 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCall.swift @@ -534,8 +534,12 @@ public final class PresentationCallImpl: PresentationCall { } if let audioSessionControl = audioSessionControl, previous == nil || previousControl == nil { - audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue)) - audioSessionControl.setup(synchronous: true) + if let callKitIntegration = self.callKitIntegration { + callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue)) + } else { + audioSessionControl.setOutputMode(.custom(self.currentAudioOutputValue)) + audioSessionControl.setup(synchronous: true) + } } let mappedVideoState: PresentationCallState.VideoState @@ -1031,7 +1035,11 @@ public final class PresentationCallImpl: PresentationCall { )) if let audioSessionControl = self.audioSessionControl { - audioSessionControl.setOutputMode(.custom(output)) + if let callKitIntegration = self.callKitIntegration { + callKitIntegration.applyVoiceChatOutputMode(outputMode: .custom(self.currentAudioOutputValue)) + } else { + audioSessionControl.setOutputMode(.custom(output)) + } } } From 4a131b47a7f6647bc2a7ee75db81dc0c6297367b Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 2 Nov 2022 16:23:33 +0400 Subject: [PATCH 04/15] Bump version --- versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.json b/versions.json index 137a9ecf35..48efc7a309 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "9.1.0", + "app": "9.1.1", "bazel": "5.3.1", "xcode": "14.0" } From 2ffb3c6f71e3a345a17f7fa612cd20d51c444e0e Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 2 Nov 2022 20:31:19 +0400 Subject: [PATCH 05/15] Unbump version --- versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.json b/versions.json index 48efc7a309..137a9ecf35 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "9.1.1", + "app": "9.1.0", "bazel": "5.3.1", "xcode": "14.0" } From 7d335e817a5a67214fa968075f108ba6aad03e37 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 2 Nov 2022 21:01:52 +0400 Subject: [PATCH 06/15] Fix hide messages --- submodules/TelegramUI/Sources/ChatController.swift | 7 ++++++- submodules/TelegramUI/Sources/ChatHistoryListNode.swift | 7 ++++++- .../Sources/ChatMessageAnimatedStickerItemNode.swift | 1 - .../TelegramUI/Sources/ChatMessageBubbleItemNode.swift | 1 - .../TelegramUI/Sources/ChatMessageReplyInfoNode.swift | 9 ++++++--- .../TelegramUI/Sources/ChatMessageStickerItemNode.swift | 1 - 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index aad6535a8e..d276c26b59 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -6132,12 +6132,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } + var buttonKeyboardMessage = combinedInitialData.buttonKeyboardMessage + if let buttonKeyboardMessageValue = buttonKeyboardMessage, buttonKeyboardMessageValue.isRestricted(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with({ $0 })) { + buttonKeyboardMessage = nil + } + strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { updated in var updated = updated updated = updated.updatedInterfaceState({ _ in return interfaceState }) - updated = updated.updatedKeyboardButtonsMessage(combinedInitialData.buttonKeyboardMessage) + updated = updated.updatedKeyboardButtonsMessage(buttonKeyboardMessage) updated = updated.updatedPinnedMessageId(pinnedMessageId) updated = updated.updatedPinnedMessage(pinnedMessage) updated = updated.updatedPeerIsBlocked(peerIsBlocked) diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index d499b6df55..f8ac9b5f22 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1396,7 +1396,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { forceUpdateAll = true } - let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: view.topTaggedMessages.first, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: updateAllOnEachVersion || forceUpdateAll) + var keyboardButtonsMessage = view.topTaggedMessages.first + if let keyboardButtonsMessageValue = keyboardButtonsMessage, keyboardButtonsMessageValue.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with({ $0 })) { + keyboardButtonsMessage = nil + } + + let rawTransition = preparedChatHistoryViewTransition(from: previous, to: processedView, reason: reason, reverse: reverse, chatLocation: chatLocation, controllerInteraction: controllerInteraction, scrollPosition: updatedScrollPosition, scrollAnimationCurve: scrollAnimationCurve, initialData: initialData?.initialData, keyboardButtonsMessage: keyboardButtonsMessage, cachedData: initialData?.cachedData, cachedDataMessages: initialData?.cachedDataMessages, readStateData: initialData?.readStateData, flashIndicators: flashIndicators, updatedMessageSelection: previousSelectedMessages != selectedMessages, messageTransitionNode: messageTransitionNode(), allUpdated: updateAllOnEachVersion || forceUpdateAll) var mappedTransition = mappedChatHistoryViewListTransition(context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, mode: mode, lastHeaderId: lastHeaderId, transition: rawTransition) if disableAnimations { diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 3cdddc2b07..e08be944a7 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1167,7 +1167,6 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] { if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId { - } else if let threadId = item.message.threadId, Int64(replyAttribute.messageId.id) == threadId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) { } else { replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments( presentationData: item.presentationData, diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index e74f736ce1..130feae189 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1426,7 +1426,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode } } else if let attribute = attribute as? ReplyMessageAttribute { if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == attribute.messageId { - } else if let threadId = firstMessage.threadId, Int64(attribute.messageId.id) == threadId, let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) { } else { replyMessage = firstMessage.associatedMessages[attribute.messageId] } diff --git a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift index ac2d2e9950..171c10999c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReplyInfoNode.swift @@ -97,8 +97,6 @@ class ChatMessageReplyInfoNode: ASDisplayNode { let previousMediaReference = maybeNode?.previousMediaReference return { arguments in - //presentationData, strings, context, type, message, parentMessage, constrainedSize - let fontSize = floor(arguments.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0) let titleFont = Font.medium(fontSize) let textFont = Font.regular(fontSize) @@ -114,7 +112,12 @@ class ChatMessageReplyInfoNode: ASDisplayNode { } } - let (textString, isMedia, isText) = descriptionStringForMessage(contentSettings: arguments.context.currentContentSettings.with { $0 }, message: EngineMessage(arguments.message), strings: arguments.strings, nameDisplayOrder: arguments.presentationData.nameDisplayOrder, dateTimeFormat: arguments.presentationData.dateTimeFormat, accountPeerId: arguments.context.account.peerId) + var (textString, isMedia, isText) = descriptionStringForMessage(contentSettings: arguments.context.currentContentSettings.with { $0 }, message: EngineMessage(arguments.message), strings: arguments.strings, nameDisplayOrder: arguments.presentationData.nameDisplayOrder, dateTimeFormat: arguments.presentationData.dateTimeFormat, accountPeerId: arguments.context.account.peerId) + + if let threadId = arguments.parentMessage.threadId, Int64(arguments.message.id.id) == threadId, let channel = arguments.parentMessage.peers[arguments.parentMessage.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum), let threadInfo = arguments.parentMessage.associatedThreadInfo { + titleString = "\(threadInfo.title)" + textString = NSAttributedString() + } let placeholderColor: UIColor = arguments.message.effectivelyIncoming(arguments.context.account.peerId) ? arguments.presentationData.theme.theme.chat.message.incoming.mediaPlaceholderColor : arguments.presentationData.theme.theme.chat.message.outgoing.mediaPlaceholderColor let titleColor: UIColor diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index 787fd8f8fb..d79c16eb07 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -611,7 +611,6 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] { if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.messageId == replyAttribute.messageId { - } else if let threadId = item.message.threadId, Int64(replyAttribute.messageId.id) == threadId, let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) { } else { replyInfoApply = makeReplyInfoLayout(ChatMessageReplyInfoNode.Arguments( presentationData: item.presentationData, From f1864a43b9db488ba63c1cb3f38800167befe891 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 16:55:23 +0400 Subject: [PATCH 07/15] Topic improvements --- .../ChatListUI/Sources/ChatContextMenus.swift | 2 +- .../Sources/ChatListController.swift | 2 +- .../Postbox/Sources/ChatListViewState.swift | 2 +- submodules/TelegramApi/Sources/Api0.swift | 3 +- submodules/TelegramApi/Sources/Api20.swift | 44 ++++++++++-- submodules/TelegramApi/Sources/Api29.swift | 20 ++++++ .../Account/AccountIntermediateState.swift | 13 ++-- .../TelegramCore/Sources/ForumChannels.swift | 18 ++--- .../State/AccountStateManagementUtils.swift | 71 +++++++++++++++---- .../Sources/State/Serialization.swift | 2 +- .../Peers/TelegramEnginePeers.swift | 24 ++++++- .../ChatInterfaceStateInputPanels.swift | 27 ++++--- submodules/TelegramUI/Sources/OpenUrl.swift | 29 ++++++-- 13 files changed, 200 insertions(+), 57 deletions(-) diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index f53523f584..079a76380b 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -519,7 +519,7 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: items.append(.action(ContextMenuActionItem(text: isPinned ? presentationData.strings.ChatList_Context_Unpin : presentationData.strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in f(.default) - let _ = context.engine.peers.setForumChannelTopicPinned(id: peerId, threadId: threadId, isPinned: !isPinned).start() + let _ = context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId).start() }))) } diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 89aa2c0196..e8c19ebc81 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -3851,7 +3851,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } private func setPeerThreadPinned(peerId: EnginePeer.Id, threadId: Int64, isPinned: Bool) { - self.actionDisposables.add(self.context.engine.peers.setForumChannelTopicPinned(id: peerId, threadId: threadId, isPinned: isPinned).start()) + self.actionDisposables.add(self.context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId).start()) } public func maybeAskForPeerChatRemoval(peer: EngineRenderedPeer, joined: Bool = false, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) { diff --git a/submodules/Postbox/Sources/ChatListViewState.swift b/submodules/Postbox/Sources/ChatListViewState.swift index 73a86ae8f0..1a52c171fe 100644 --- a/submodules/Postbox/Sources/ChatListViewState.swift +++ b/submodules/Postbox/Sources/ChatListViewState.swift @@ -268,7 +268,7 @@ private final class ChatListViewSpaceState { } postboxLog("allIndices not unique, repeated: \(debugRepeatedIndices)") - assert(false) + //assert(false) //preconditionFailure() } if Set(allEntityIds).count != allEntityIds.count { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 3b335113a1..a08bc82d73 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -778,7 +778,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-761649164] = { return Api.Update.parse_updateChannelMessageForwards($0) } dict[-232346616] = { return Api.Update.parse_updateChannelMessageViews($0) } dict[-1738720581] = { return Api.Update.parse_updateChannelParticipant($0) } - dict[-158027602] = { return Api.Update.parse_updateChannelPinnedTopic($0) } + dict[422509539] = { return Api.Update.parse_updateChannelPinnedTopic($0) } + dict[-31881726] = { return Api.Update.parse_updateChannelPinnedTopics($0) } dict[-366410403] = { return Api.Update.parse_updateChannelReadMessagesContents($0) } dict[277713951] = { return Api.Update.parse_updateChannelTooLong($0) } dict[-1937192669] = { return Api.Update.parse_updateChannelUserTyping($0) } diff --git a/submodules/TelegramApi/Sources/Api20.swift b/submodules/TelegramApi/Sources/Api20.swift index 5efcea25c9..9d016b2a92 100644 --- a/submodules/TelegramApi/Sources/Api20.swift +++ b/submodules/TelegramApi/Sources/Api20.swift @@ -671,7 +671,8 @@ public extension Api { case updateChannelMessageForwards(channelId: Int64, id: Int32, forwards: Int32) case updateChannelMessageViews(channelId: Int64, id: Int32, views: Int32) case updateChannelParticipant(flags: Int32, channelId: Int64, date: Int32, actorId: Int64, userId: Int64, prevParticipant: Api.ChannelParticipant?, newParticipant: Api.ChannelParticipant?, invite: Api.ExportedChatInvite?, qts: Int32) - case updateChannelPinnedTopic(flags: Int32, channelId: Int64, topicId: Int32?) + case updateChannelPinnedTopic(flags: Int32, channelId: Int64, topicId: Int32) + case updateChannelPinnedTopics(flags: Int32, channelId: Int64, order: [Int32]?) case updateChannelReadMessagesContents(flags: Int32, channelId: Int64, topMsgId: Int32?, messages: [Int32]) case updateChannelTooLong(flags: Int32, channelId: Int64, pts: Int32?) case updateChannelUserTyping(flags: Int32, channelId: Int64, topMsgId: Int32?, fromId: Api.Peer, action: Api.SendMessageAction) @@ -927,11 +928,23 @@ public extension Api { break case .updateChannelPinnedTopic(let flags, let channelId, let topicId): if boxed { - buffer.appendInt32(-158027602) + buffer.appendInt32(422509539) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt64(channelId, buffer: buffer, boxed: false) - if Int(flags) & Int(1 << 0) != 0 {serializeInt32(topicId!, buffer: buffer, boxed: false)} + serializeInt32(topicId, buffer: buffer, boxed: false) + break + case .updateChannelPinnedTopics(let flags, let channelId, let order): + if boxed { + buffer.appendInt32(-31881726) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt64(channelId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order!.count)) + for item in order! { + serializeInt32(item, buffer: buffer, boxed: false) + }} break case .updateChannelReadMessagesContents(let flags, let channelId, let topMsgId, let messages): if boxed { @@ -1741,6 +1754,8 @@ public extension Api { return ("updateChannelParticipant", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("date", String(describing: date)), ("actorId", String(describing: actorId)), ("userId", String(describing: userId)), ("prevParticipant", String(describing: prevParticipant)), ("newParticipant", String(describing: newParticipant)), ("invite", String(describing: invite)), ("qts", String(describing: qts))]) case .updateChannelPinnedTopic(let flags, let channelId, let topicId): return ("updateChannelPinnedTopic", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("topicId", String(describing: topicId))]) + case .updateChannelPinnedTopics(let flags, let channelId, let order): + return ("updateChannelPinnedTopics", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("order", String(describing: order))]) case .updateChannelReadMessagesContents(let flags, let channelId, let topMsgId, let messages): return ("updateChannelReadMessagesContents", [("flags", String(describing: flags)), ("channelId", String(describing: channelId)), ("topMsgId", String(describing: topMsgId)), ("messages", String(describing: messages))]) case .updateChannelTooLong(let flags, let channelId, let pts): @@ -2307,12 +2322,31 @@ public extension Api { var _2: Int64? _2 = reader.readInt64() var _3: Int32? - if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() } + _3 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + if _c1 && _c2 && _c3 { + return Api.Update.updateChannelPinnedTopic(flags: _1!, channelId: _2!, topicId: _3!) + } + else { + return nil + } + } + public static func parse_updateChannelPinnedTopics(_ reader: BufferReader) -> Update? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int64? + _2 = reader.readInt64() + var _3: [Int32]? + if Int(_1!) & Int(1 << 0) != 0 {if let _ = reader.readInt32() { + _3 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil if _c1 && _c2 && _c3 { - return Api.Update.updateChannelPinnedTopic(flags: _1!, channelId: _2!, topicId: _3) + return Api.Update.updateChannelPinnedTopics(flags: _1!, channelId: _2!, order: _3) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api29.swift b/submodules/TelegramApi/Sources/Api29.swift index dbfb3fc069..1830877551 100644 --- a/submodules/TelegramApi/Sources/Api29.swift +++ b/submodules/TelegramApi/Sources/Api29.swift @@ -2443,6 +2443,26 @@ public extension Api.functions.channels { }) } } +public extension Api.functions.channels { + static func reorderPinnedForumTopics(channel: Api.InputChannel, order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-529811367) + channel.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "channels.reorderPinnedForumTopics", parameters: [("channel", String(describing: channel)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } +} public extension Api.functions.channels { static func reorderUsernames(channel: Api.InputChannel, order: [String]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift index adb0f1a6dc..950622bcb8 100644 --- a/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift +++ b/submodules/TelegramCore/Sources/Account/AccountIntermediateState.swift @@ -93,7 +93,8 @@ enum AccountStateMutationOperation { case ReadSecretOutbox(peerId: PeerId, maxTimestamp: Int32, actionTimestamp: Int32) case AddPeerInputActivity(chatPeerId: PeerActivitySpace, peerId: PeerId?, activity: PeerInputActivity?) case UpdatePinnedItemIds(PeerGroupId, AccountStateUpdatePinnedItemIdsOperation) - case UpdatePinnedTopic(peerId: PeerId, threadId: Int64?) + case UpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool) + case UpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64]) case ReadMessageContents((PeerId?, [Int32])) case UpdateMessageImpressionCount(MessageId, Int32) case UpdateMessageForwardsCount(MessageId, Int32) @@ -475,8 +476,12 @@ struct AccountMutableState { self.addOperation(.UpdatePinnedItemIds(groupId, operation)) } - mutating func addUpdatePinnedTopic(peerId: PeerId, threadId: Int64?) { - self.addOperation(.UpdatePinnedTopic(peerId: peerId, threadId: threadId)) + mutating func addUpdatePinnedTopic(peerId: PeerId, threadId: Int64, isPinned: Bool) { + self.addOperation(.UpdatePinnedTopic(peerId: peerId, threadId: threadId, isPinned: isPinned)) + } + + mutating func addUpdatePinnedTopicOrder(peerId: PeerId, threadIds: [Int64]) { + self.addOperation(.UpdatePinnedTopicOrder(peerId: peerId, threadIds: threadIds)) } mutating func addReadMessagesContents(_ peerIdsAndMessageIds: (PeerId?, [Int32])) { @@ -545,7 +550,7 @@ struct AccountMutableState { mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic: break case let .AddMessages(messages, location): for message in messages { diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index 21bf65483d..a4042fbe92 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -367,21 +367,16 @@ func _internal_setForumChannelTopicClosed(account: Account, id: EnginePeer.Id, t public enum SetForumChannelTopicPinnedError { case generic + case limitReached(Int) } -func _internal_setForumChannelTopicPinned(account: Account, id: EnginePeer.Id, threadId: Int64, isPinned: Bool) -> Signal { +func _internal_setForumChannelPinnedTopics(account: Account, id: EnginePeer.Id, threadIds: [Int64]) -> Signal { return account.postbox.transaction { transaction -> Api.InputChannel? in guard let inputChannel = transaction.getPeer(id).flatMap(apiInputChannel) else { return nil } - if isPinned { - transaction.setPeerPinnedThreads(peerId: id, threadIds: [threadId]) - } else { - if transaction.getPeerPinnedThreads(peerId: id).contains(threadId) { - transaction.setPeerPinnedThreads(peerId: id, threadIds: []) - } - } + transaction.setPeerPinnedThreads(peerId: id, threadIds: threadIds) return inputChannel } @@ -390,13 +385,10 @@ func _internal_setForumChannelTopicPinned(account: Account, id: EnginePeer.Id, t guard let inputChannel = inputChannel else { return .fail(.generic) } - var flags: Int32 = 0 - flags |= (1 << 2) - return account.network.request(Api.functions.channels.updatePinnedForumTopic( + return account.network.request(Api.functions.channels.reorderPinnedForumTopics( channel: inputChannel, - topicId: Int32(clamping: threadId), - pinned: isPinned ? .boolTrue : .boolFalse + order: threadIds.map(Int32.init(clamping:)) )) |> mapError { _ -> SetForumChannelTopicPinnedError in return .generic diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 96da863315..e8538fcfb9 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -114,6 +114,11 @@ private func peerIdsRequiringLocalChatStateFromUpdates(_ updates: [Api.Update]) case let .updateChannelTooLong(_, channelId, _): let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) peerIds.insert(peerId) + case let .updateChannelPinnedTopics(_, channelId, order): + if order == nil { + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) + peerIds.insert(peerId) + } case let .updateFolderPeers(folderPeers, _, _): for peer in folderPeers { switch peer { @@ -337,11 +342,16 @@ private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.upda peerIds.insert(messageId.peerId) } switch update { - case let .updateChannelTooLong(_, channelId, _): + case let .updateChannelTooLong(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) + peerIds.insert(peerId) + case let .updateChannelPinnedTopics(_, channelId, order): + if order == nil { let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) peerIds.insert(peerId) - default: - break + } + default: + break } } case .differenceEmpty: @@ -359,11 +369,16 @@ private func peerIdsRequiringLocalChatStateFromDifference(_ difference: Api.upda peerIds.insert(messageId.peerId) } switch update { - case let .updateChannelTooLong(_, channelId, _): + case let .updateChannelTooLong(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) + peerIds.insert(peerId) + case let .updateChannelPinnedTopics(_, channelId, order): + if order == nil { let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) peerIds.insert(peerId) - default: - break + } + default: + break } } case .differenceTooLong: @@ -725,6 +740,20 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] { } else { updatesByChannel[peerId]!.append(update) } + case let .updateChannelPinnedTopic(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } + case let .updateChannelPinnedTopics(_, channelId, _): + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) + if updatesByChannel[peerId] == nil { + updatesByChannel[peerId] = [update] + } else { + updatesByChannel[peerId]!.append(update) + } case let .updateDeleteChannelMessages(channelId, _, _, _): let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) if updatesByChannel[peerId] == nil { @@ -860,6 +889,15 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: channelsToPoll.insert(peerId) } } + case let .updateChannelPinnedTopics(_, channelId, order): + if let order = order { + updatedState.addUpdatePinnedTopicOrder(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadIds: order.map(Int64.init)) + } else { + let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) + if !channelsToPoll.contains(peerId) { + channelsToPoll.insert(peerId) + } + } case let .updateDeleteChannelMessages(channelId, messages, pts: pts, ptsCount): let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)) if let previousState = updatedState.channelStates[peerId] { @@ -1375,8 +1413,9 @@ private func finalStateWithUpdatesAndServerTime(accountPeerId: PeerId, postbox: } else { updatedState.addUpdatePinnedItemIds(groupId: groupId, operation: .sync) } - case let .updateChannelPinnedTopic(_, channelId, topicId): - updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: topicId.flatMap(Int64.init)) + case let .updateChannelPinnedTopic(flags, channelId, topicId): + let isPinned = (flags & (1 << 0)) != 0 + updatedState.addUpdatePinnedTopic(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), threadId: Int64(topicId), isPinned: isPinned) case let .updateReadMessagesContents(messages, _, _): updatedState.addReadMessagesContents((nil, messages)) case let .updateChannelReadMessagesContents(_, channelId, topMsgId, messages): @@ -2847,7 +2886,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddScheduledMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -3757,12 +3796,18 @@ func replayFinalState( case .sync: addSynchronizePinnedChatsOperation(transaction: transaction, groupId: groupId) } - case let .UpdatePinnedTopic(peerId, threadId): - if let threadId = threadId { - transaction.setPeerPinnedThreads(peerId: peerId, threadIds: [threadId]) + case let .UpdatePinnedTopic(peerId, threadId, isPinned): + var currentThreadIds = transaction.getPeerPinnedThreads(peerId: peerId) + if isPinned { + if !currentThreadIds.contains(threadId) { + currentThreadIds.insert(threadId, at: 0) + } } else { - transaction.setPeerPinnedThreads(peerId: peerId, threadIds: []) + currentThreadIds.removeAll(where: { $0 == threadId }) } + transaction.setPeerPinnedThreads(peerId: peerId, threadIds: currentThreadIds) + case let .UpdatePinnedTopicOrder(peerId, threadIds): + transaction.setPeerPinnedThreads(peerId: peerId, threadIds: threadIds) case let .ReadMessageContents(peerIdAndMessageIds): let (peerId, messageIds) = peerIdAndMessageIds diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index ec2600126f..d1296ecee5 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 148 + return 149 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 4b1d5b6328..7b2a20a312 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -858,8 +858,28 @@ public extension TelegramEngine { |> ignoreValues } - public func setForumChannelTopicPinned(id: EnginePeer.Id, threadId: Int64, isPinned: Bool) -> Signal { - return _internal_setForumChannelTopicPinned(account: self.account, id: id, threadId: threadId, isPinned: isPinned) + public func toggleForumChannelTopicPinned(id: EnginePeer.Id, threadId: Int64) -> Signal { + return self.account.postbox.transaction { transaction -> [Int64] in + return transaction.getPeerPinnedThreads(peerId: id) + } + |> castError(SetForumChannelTopicPinnedError.self) + |> mapToSignal { threadIds -> Signal in + var threadIds = threadIds + if threadIds.contains(threadId) { + threadIds.removeAll(where: { $0 == threadId }) + } else { + if threadIds.count + 1 > 5 { + return .fail(.limitReached(5)) + } + threadIds.insert(threadId, at: 0) + } + + return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds) + } + } + + public func setForumChannelPinnedTopics(id: EnginePeer.Id, threadIds: [Int64]) -> Signal { + return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds) } public func forumChannelTopicNotificationExceptions(id: EnginePeer.Id) -> Signal<[EngineMessageHistoryThread.NotificationException], NoError> { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift index c3fe327cdc..2bb9fa07dd 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateInputPanels.swift @@ -181,17 +181,6 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState } } } - } else { - if chatPresentationInterfaceState.interfaceState.replyMessageId == nil { - if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) { - return (currentPanel, nil) - } else { - let panel = ChatRestrictedInputPanelNode() - panel.context = context - panel.interfaceInteraction = interfaceInteraction - return (panel, nil) - } - } } } @@ -248,6 +237,22 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState } } } + + if channel.flags.contains(.isForum) { + if let _ = chatPresentationInterfaceState.threadData { + } else { + if chatPresentationInterfaceState.interfaceState.replyMessageId == nil { + if let currentPanel = (currentPanel as? ChatRestrictedInputPanelNode) ?? (currentSecondaryPanel as? ChatRestrictedInputPanelNode) { + return (currentPanel, nil) + } else { + let panel = ChatRestrictedInputPanelNode() + panel.context = context + panel.interfaceInteraction = interfaceInteraction + return (panel, nil) + } + } + } + } } else if let group = peer as? TelegramGroup { switch group.membership { case .Removed, .Left: diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 4092b160f3..a6da62508f 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -621,6 +621,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur if let components = URLComponents(string: "/?" + query) { var channelId: Int64? var postId: Int32? + var threadId: Int64? if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { @@ -628,12 +629,22 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur channelId = Int64(value) } else if queryItem.name == "post" { postId = Int32(value) + } else if queryItem.name == "thread" { + threadId = Int64(value) } } } } - if let channelId = channelId, let postId = postId { - convertedUrl = "https://t.me/c/\(channelId)/\(postId)" + if let channelId = channelId { + if let postId = postId { + if let threadId = threadId { + convertedUrl = "https://t.me/c/\(channelId)/\(threadId)/\(postId)" + } else { + convertedUrl = "https://t.me/c/\(channelId)/\(postId)" + } + } else if let threadId = threadId { + convertedUrl = "https://t.me/c/\(channelId)/\(threadId)" + } } } } @@ -652,6 +663,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur var attach: String? var startAttach: String? var choose: String? + var threadId: Int64? if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { @@ -677,6 +689,8 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur startAttach = value } else if queryItem.name == "choose" { choose = value + } else if queryItem.name == "thread" { + threadId = Int64(value) } } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) { voiceChat = "" @@ -694,8 +708,15 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur convertedUrl = "https://t.me/+\(phone)" } else if let domain = domain { var result = "https://t.me/\(domain)" - if let post = post, let postValue = Int(post) { - result += "/\(postValue)" + if let threadId = threadId { + result += "/\(threadId)" + if let post = post, let postValue = Int(post) { + result += "/\(postValue)" + } + } else { + if let post = post, let postValue = Int(post) { + result += "/\(postValue)" + } } if let start = start { result += "?start=\(start)" From 42c35903299f66284afd1d3299b8e55e2243f5a0 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 17:53:00 +0400 Subject: [PATCH 08/15] Fix external audio route change --- submodules/TelegramCallsUI/Sources/CallKitIntegration.swift | 2 +- submodules/TelegramCallsUI/Sources/PresentationCall.swift | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift index 62eb4d84d1..7fdfee4ea1 100644 --- a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift +++ b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift @@ -171,7 +171,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { private func requestTransaction(_ transaction: CXTransaction, completion: ((Bool) -> Void)? = nil) { self.callController.request(transaction) { error in if let error = error { - print("Error requesting transaction: \(error)") + print("Error requesting transaction \(transaction): \(error)") } completion?(error == nil) } diff --git a/submodules/TelegramCallsUI/Sources/PresentationCall.swift b/submodules/TelegramCallsUI/Sources/PresentationCall.swift index 80c132529c..6cf0a084d5 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationCall.swift @@ -413,6 +413,9 @@ public final class PresentationCallImpl: PresentationCall { return } strongSelf.audioOutputStateValue = (availableOutputs, currentOutput) + if let currentOutput = currentOutput { + strongSelf.currentAudioOutputValue = currentOutput + } var signal: Signal<([AudioSessionOutput], AudioSessionOutput?), NoError> = .single((availableOutputs, currentOutput)) if !didReceiveAudioOutputs { From 89e0f4b2450a2d9862c282b48f293c7e91e6f38d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 17:54:20 +0400 Subject: [PATCH 09/15] Update tgcalls --- submodules/TgVoipWebrtc/tgcalls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 53bb1711ae..c507d7044a 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 53bb1711ae0b3810d34edb1c81982b18d70c5506 +Subproject commit c507d7044adf849b0645bdefebb1aa7284417ff5 From fa959069627b513066af7325e86e95da2757682e Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 19:15:25 +0400 Subject: [PATCH 10/15] Support multiple pinned threads --- .../Telegram-iOS/en.lproj/Localizable.strings | 3 + .../ChatListUI/Sources/ChatContextMenus.swift | 14 +- .../Sources/Node/ChatListNode.swift | 199 ++++++++++++------ .../TelegramCore/Sources/ForumChannels.swift | 6 + .../Peers/TelegramEnginePeers.swift | 6 + 5 files changed, 165 insertions(+), 63 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 20084fa97d..31c6d17ad9 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8241,3 +8241,6 @@ Sorry for the inconvenience."; "Attachment.DiscardPasteboardAlertText" = "Discard pasted items?"; "Undo.DeletedTopic" = "Topic Deleted"; + +"ChatList.MaxThreadPinsFinalText_1" = "Sorry, you can't pin more than **%@** thread to the top. Unpin some that are currently pinned."; +"ChatList.MaxThreadPinsFinalText_any" = "Sorry, you can't pin more than **%@** threads to the top. Unpin some that are currently pinned."; diff --git a/submodules/ChatListUI/Sources/ChatContextMenus.swift b/submodules/ChatListUI/Sources/ChatContextMenus.swift index 079a76380b..8d0fbc5c01 100644 --- a/submodules/ChatListUI/Sources/ChatContextMenus.swift +++ b/submodules/ChatListUI/Sources/ChatContextMenus.swift @@ -519,7 +519,19 @@ func chatForumTopicMenuItems(context: AccountContext, peerId: PeerId, threadId: items.append(.action(ContextMenuActionItem(text: isPinned ? presentationData.strings.ChatList_Context_Unpin : presentationData.strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in f(.default) - let _ = context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId).start() + let _ = (context.engine.peers.toggleForumChannelTopicPinned(id: peerId, threadId: threadId) + |> deliverOnMainQueue).start(error: { error in + switch error { + case let .limitReached(count): + if let chatListController = chatListController { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let text = presentationData.strings.ChatList_MaxThreadPinsFinalText(Int32(count)) + chatListController.present(textAlertController(context: context, title: presentationData.strings.Premium_LimitReached, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})], parseMarkdown: true), in: .window(.root)) + } + default: + break + } + }) }))) } diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index 1438dcf409..0ab3d0eb17 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -1697,85 +1697,160 @@ public final class ChatListNode: ListView { }) self.reorderItem = { [weak self] fromIndex, toIndex, transactionOpaqueState -> Signal in - if let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries { - guard case let .chatList(groupId) = strongSelf.location else { - return .single(false) + guard let strongSelf = self, let filteredEntries = (transactionOpaqueState as? ChatListOpaqueTransactionState)?.chatListView.filteredEntries else { + return .single(false) + } + guard fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count else { + return .single(false) + } + + switch strongSelf.location { + case let .chatList(groupId): + let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] + let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] + + var referenceId: EngineChatList.PinnedItem.Id? + var beforeAll = false + switch toEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _): + if promoInfo != nil { + beforeAll = true + } else { + if case let .chatList(chatListIndex) = index { + referenceId = .peer(chatListIndex.messageIndex.id.peerId) + } + } + default: + break } - if fromIndex >= 0 && fromIndex < filteredEntries.count && toIndex >= 0 && toIndex < filteredEntries.count { - let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] - let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] + if case let .index(index) = fromEntry.sortIndex, case let .chatList(chatListIndex) = index, let _ = chatListIndex.pinningIndex { + let location: TogglePeerChatPinnedLocation + if let chatListFilter = chatListFilter { + location = .filter(chatListFilter.id) + } else { + location = .group(groupId._asGroup()) + } - var referenceId: EngineChatList.PinnedItem.Id? - var beforeAll = false - switch toEntry { - case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _): - if promoInfo != nil { - beforeAll = true - } else { - if case let .chatList(chatListIndex) = index { - referenceId = .peer(chatListIndex.messageIndex.id.peerId) + let engine = strongSelf.context.engine + return engine.peers.getPinnedItemIds(location: location) + |> mapToSignal { itemIds -> Signal in + var itemIds = itemIds + + var itemId: EngineChatList.PinnedItem.Id? + switch fromEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + if case let .chatList(index) = index { + itemId = .peer(index.messageIndex.id.peerId) } - } default: break - } - - if case let .index(index) = fromEntry.sortIndex, case let .chatList(chatListIndex) = index, let _ = chatListIndex.pinningIndex { - let location: TogglePeerChatPinnedLocation - if let chatListFilter = chatListFilter { - location = .filter(chatListFilter.id) - } else { - location = .group(groupId._asGroup()) } - - let engine = strongSelf.context.engine - return engine.peers.getPinnedItemIds(location: location) - |> mapToSignal { itemIds -> Signal in - var itemIds = itemIds - - var itemId: EngineChatList.PinnedItem.Id? - switch fromEntry { - case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): - if case let .chatList(index) = index { - itemId = .peer(index.messageIndex.id.peerId) - } - default: - break - } - - if let itemId = itemId { - itemIds = itemIds.filter({ $0 != itemId }) - if let referenceId = referenceId { - var inserted = false - for i in 0 ..< itemIds.count { - if itemIds[i] == referenceId { - if fromIndex < toIndex { - itemIds.insert(itemId, at: i + 1) - } else { - itemIds.insert(itemId, at: i) - } - inserted = true - break + + if let itemId = itemId { + itemIds = itemIds.filter({ $0 != itemId }) + if let referenceId = referenceId { + var inserted = false + for i in 0 ..< itemIds.count { + if itemIds[i] == referenceId { + if fromIndex < toIndex { + itemIds.insert(itemId, at: i + 1) + } else { + itemIds.insert(itemId, at: i) } + inserted = true + break } - if !inserted { - itemIds.append(itemId) - } - } else if beforeAll { - itemIds.insert(itemId, at: 0) - } else { + } + if !inserted { itemIds.append(itemId) } - return engine.peers.reorderPinnedItemIds(location: location, itemIds: itemIds) + } else if beforeAll { + itemIds.insert(itemId, at: 0) } else { - return .single(false) + itemIds.append(itemId) } + return engine.peers.reorderPinnedItemIds(location: location, itemIds: itemIds) + } else { + return .single(false) } } + } else { + return .single(false) + } + case let .forum(peerId): + let fromEntry = filteredEntries[filteredEntries.count - 1 - fromIndex] + let toEntry = filteredEntries[filteredEntries.count - 1 - toIndex] + + var referenceId: Int64? + var beforeAll = false + switch toEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, promoInfo, _, _, _): + if promoInfo != nil { + beforeAll = true + } else { + if case let .forum(_, _, threadId, _, _) = index { + referenceId = threadId + } + } + default: + break + } + + if case let .index(index) = fromEntry.sortIndex, case let .forum(pinningIndex, _, _, _, _) = index, case .index = pinningIndex { + let engine = strongSelf.context.engine + return engine.peers.getForumChannelPinnedTopics(id: peerId) + |> mapToSignal { itemIds -> Signal in + var itemIds = itemIds + + var itemId: Int64? + switch fromEntry { + case let .PeerEntry(index, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): + if case let .forum(_, _, threadId, _, _) = index { + itemId = threadId + } + default: + break + } + + if let itemId = itemId { + itemIds = itemIds.filter({ $0 != itemId }) + if let referenceId = referenceId { + var inserted = false + for i in 0 ..< itemIds.count { + if itemIds[i] == referenceId { + if fromIndex < toIndex { + itemIds.insert(itemId, at: i + 1) + } else { + itemIds.insert(itemId, at: i) + } + inserted = true + break + } + } + if !inserted { + itemIds.append(itemId) + } + } else if beforeAll { + itemIds.insert(itemId, at: 0) + } else { + itemIds.append(itemId) + } + return engine.peers.setForumChannelPinnedTopics(id: peerId, threadIds: itemIds) + |> map { _ -> Bool in + } + |> `catch` { _ -> Signal in + return .single(false) + } + |> then(Signal.single(true)) + } else { + return .single(false) + } + } + } else { + return .single(false) } } - return .single(false) } var startedScrollingAtUpperBound = false diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index a4042fbe92..84a1bf30dc 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -386,6 +386,12 @@ func _internal_setForumChannelPinnedTopics(account: Account, id: EnginePeer.Id, return .fail(.generic) } + #if DEBUG + if "".isEmpty { + return .complete() + } + #endif + return account.network.request(Api.functions.channels.reorderPinnedForumTopics( channel: inputChannel, order: threadIds.map(Int32.init(clamping:)) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 7b2a20a312..bc38a263fc 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -878,6 +878,12 @@ public extension TelegramEngine { } } + public func getForumChannelPinnedTopics(id: EnginePeer.Id) -> Signal<[Int64], NoError> { + return self.account.postbox.transaction { transcation -> [Int64] in + return transcation.getPeerPinnedThreads(peerId: id) + } + } + public func setForumChannelPinnedTopics(id: EnginePeer.Id, threadIds: [Int64]) -> Signal { return _internal_setForumChannelPinnedTopics(account: self.account, id: id, threadIds: threadIds) } From fa041d197880cef2e9d917d6a9ec6363edb8f69a Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 22:58:54 +0400 Subject: [PATCH 11/15] Experimental call improvements --- .../Sources/PresentationGroupCall.swift | 4 +- .../Sources/GroupCallContext.swift | 17 ++++++-- .../OngoingCallThreadLocalContext.h | 2 + .../Sources/OngoingCallThreadLocalContext.mm | 41 +++++++++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 369a610dff..51ef7b5d83 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1648,7 +1648,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { outgoingAudioBitrateKbit = Int32(value) } - genericCallContext = .call(OngoingGroupCallContext(video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in + genericCallContext = .call(OngoingGroupCallContext(audioSessionActive: self.audioSessionActive.get(), video: self.videoCapturer, requestMediaChannelDescriptions: { [weak self] ssrcs, completion in let disposable = MetaDisposable() Queue.mainQueue().async { guard let strongSelf = self else { @@ -2966,7 +2966,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.hasScreencast = true - let screencastCallContext = OngoingGroupCallContext(video: self.screencastCapturer, requestMediaChannelDescriptions: { _, _ in EmptyDisposable }, rejoinNeeded: { }, outgoingAudioBitrateKbit: nil, videoContentType: .screencast, enableNoiseSuppression: false, disableAudioInput: true, preferX264: false, logPath: "") + let screencastCallContext = OngoingGroupCallContext(audioSessionActive: .single(true), video: self.screencastCapturer, requestMediaChannelDescriptions: { _, _ in EmptyDisposable }, rejoinNeeded: { }, outgoingAudioBitrateKbit: nil, videoContentType: .screencast, enableNoiseSuppression: false, disableAudioInput: true, preferX264: false, logPath: "") self.screencastCallContext = screencastCallContext self.screencastJoinDisposable.set((screencastCallContext.joinPayload diff --git a/submodules/TelegramVoip/Sources/GroupCallContext.swift b/submodules/TelegramVoip/Sources/GroupCallContext.swift index cc912d35a3..1e47048fb3 100644 --- a/submodules/TelegramVoip/Sources/GroupCallContext.swift +++ b/submodules/TelegramVoip/Sources/GroupCallContext.swift @@ -416,7 +416,9 @@ public final class OngoingGroupCallContext { private let broadcastPartsSource = Atomic(value: nil) - init(queue: Queue, inputDeviceId: String, outputDeviceId: String, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) { + private let audioSessionActiveDisposable = MetaDisposable() + + init(queue: Queue, inputDeviceId: String, outputDeviceId: String, audioSessionActive: Signal, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) { self.queue = queue var networkStateUpdatedImpl: ((GroupCallNetworkState) -> Void)? @@ -571,9 +573,18 @@ public final class OngoingGroupCallContext { strongSelf.joinPayload.set(.single((payload, ssrc))) } }) + + self.audioSessionActiveDisposable.set((audioSessionActive + |> deliverOn(queue)).start(next: { [weak self] isActive in + guard let self else { + return + } + self.context.setManualAudioSessionIsActive(isActive) + })) } deinit { + self.audioSessionActiveDisposable.dispose() } func setJoinResponse(payload: String) { @@ -936,10 +947,10 @@ public final class OngoingGroupCallContext { } } - public init(inputDeviceId: String = "", outputDeviceId: String = "", video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) { + public init(inputDeviceId: String = "", outputDeviceId: String = "", audioSessionActive: Signal, video: OngoingCallVideoCapturer?, requestMediaChannelDescriptions: @escaping (Set, @escaping ([MediaChannelDescription]) -> Void) -> Disposable, rejoinNeeded: @escaping () -> Void, outgoingAudioBitrateKbit: Int32?, videoContentType: VideoContentType, enableNoiseSuppression: Bool, disableAudioInput: Bool, preferX264: Bool, logPath: String) { let queue = self.queue self.impl = QueueLocalObject(queue: queue, generate: { - return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, video: video, requestMediaChannelDescriptions: requestMediaChannelDescriptions, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, videoContentType: videoContentType, enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, preferX264: preferX264, logPath: logPath) + return Impl(queue: queue, inputDeviceId: inputDeviceId, outputDeviceId: outputDeviceId, audioSessionActive: audioSessionActive, video: video, requestMediaChannelDescriptions: requestMediaChannelDescriptions, rejoinNeeded: rejoinNeeded, outgoingAudioBitrateKbit: outgoingAudioBitrateKbit, videoContentType: videoContentType, enableNoiseSuppression: enableNoiseSuppression, disableAudioInput: disableAudioInput, preferX264: preferX264, logPath: logPath) }) } diff --git a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h index 81db3ec7fc..ea6855191d 100644 --- a/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h +++ b/submodules/TgVoipWebrtc/PublicHeaders/TgVoipWebrtc/OngoingCallThreadLocalContext.h @@ -377,6 +377,8 @@ typedef NS_ENUM(int32_t, OngoingGroupCallRequestedVideoQuality) { - (void)stop; +- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive; + - (void)setConnectionMode:(OngoingCallConnectionMode)connectionMode keepBroadcastConnectedIfWasEnabled:(bool)keepBroadcastConnectedIfWasEnabled isUnifiedBroadcast:(bool)isUnifiedBroadcast; - (void)emitJoinPayload:(void (^ _Nonnull)(NSString * _Nonnull, uint32_t))completion; diff --git a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm index 12e0019f94..24a0167e99 100644 --- a/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm +++ b/submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm @@ -875,6 +875,22 @@ static void (*InternalVoipLoggingFunction)(NSString *) = NULL; _useManualAudioSessionControl = useManualAudioSessionControl; [RTCAudioSession sharedInstance].useManualAudio = true; +#ifdef WEBRTC_IOS + RTCAudioSessionConfiguration *sharedConfiguration = [RTCAudioSessionConfiguration webRTCConfiguration]; + if (useManualAudioSessionControl) { + sharedConfiguration.mode = AVAudioSessionModeDefault; + } else { + sharedConfiguration.mode = AVAudioSessionModeVoiceChat; + } + sharedConfiguration.categoryOptions |= AVAudioSessionCategoryOptionMixWithOthers; + sharedConfiguration.outputNumberOfChannels = 1; + [RTCAudioSessionConfiguration setWebRTCConfiguration:sharedConfiguration]; + + /*[RTCAudioSession sharedInstance].useManualAudio = true; + [[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]]; + [RTCAudioSession sharedInstance].isAudioEnabled = true;*/ +#endif + _callReceiveTimeout = 20.0; _callRingTimeout = 90.0; _callConnectTimeout = 30.0; @@ -1463,6 +1479,22 @@ private: } } +#ifdef WEBRTC_IOS + RTCAudioSessionConfiguration *sharedConfiguration = [RTCAudioSessionConfiguration webRTCConfiguration]; + sharedConfiguration.mode = AVAudioSessionModeVoiceChat; + sharedConfiguration.categoryOptions |= AVAudioSessionCategoryOptionMixWithOthers; + if (disableAudioInput) { + sharedConfiguration.outputNumberOfChannels = 2; + } else { + sharedConfiguration.outputNumberOfChannels = 1; + } + [RTCAudioSessionConfiguration setWebRTCConfiguration:sharedConfiguration]; + + /*[RTCAudioSession sharedInstance].useManualAudio = true; + [[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]]; + [RTCAudioSession sharedInstance].isAudioEnabled = true;*/ +#endif + std::vector videoCodecPreferences; int minOutgoingVideoBitrateKbit = 500; @@ -1646,6 +1678,15 @@ private: } } +- (void)setManualAudioSessionIsActive:(bool)isAudioSessionActive { + if (isAudioSessionActive) { + [[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]]; + } else { + [[RTCAudioSession sharedInstance] audioSessionDidDeactivate:[AVAudioSession sharedInstance]]; + } + [RTCAudioSession sharedInstance].isAudioEnabled = isAudioSessionActive; +} + - (void)setConnectionMode:(OngoingCallConnectionMode)connectionMode keepBroadcastConnectedIfWasEnabled:(bool)keepBroadcastConnectedIfWasEnabled isUnifiedBroadcast:(bool)isUnifiedBroadcast { if (_instance) { tgcalls::GroupConnectionMode mappedConnectionMode; From a04f9d1bec7bebf2d17efc40f083750707417d32 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 22:59:46 +0400 Subject: [PATCH 12/15] Update tgcalls --- submodules/TgVoipWebrtc/tgcalls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index c507d7044a..0aa4b1277f 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit c507d7044adf849b0645bdefebb1aa7284417ff5 +Subproject commit 0aa4b1277fd018e56bf194d72b5405e397c6918b From 7608829e2d5c2038a35c821e92722c435faf99cf Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 23:34:52 +0400 Subject: [PATCH 13/15] Fix chat list message hiding --- submodules/ChatListUI/Sources/Node/ChatListItem.swift | 6 +++--- .../ChatListUI/Sources/Node/ChatListItemStrings.swift | 6 +++++- .../Sources/PlatformRestrictionMatching.swift | 10 ++++++++-- .../TelegramUI/Sources/ChatMessageItemView.swift | 2 +- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index e45a1d9459..c101f0eec5 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -795,7 +795,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else { result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage } - let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) + let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author { result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" } @@ -829,7 +829,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { } else { result += item.presentationData.strings.VoiceOver_ChatList_OutgoingMessage } - let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) + let (_, initialHideAuthor, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: peer, accountPeerId: item.context.account.peerId, isPeerGroup: false) if message.flags.contains(.Incoming), !initialHideAuthor, let author = message.author, case .user = author { result += "\n\(item.presentationData.strings.VoiceOver_ChatList_MessageFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).string)" } @@ -1387,7 +1387,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { var hideAuthor = false switch contentPeer { case let .chat(itemPeer): - var (peer, initialHideAuthor, messageText, spoilers, customEmojiRanges) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup) + var (peer, initialHideAuthor, messageText, spoilers, customEmojiRanges) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: messages, chatPeer: itemPeer, accountPeerId: item.context.account.peerId, enableMediaEmoji: !enableChatListPhotos, isPeerGroup: isPeerGroup) if case let .psa(_, maybePsaText) = promoInfo, let psaText = maybePsaText { initialHideAuthor = true diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 1048701c8a..03c682039f 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -45,11 +45,15 @@ private func messageGroupType(messages: [EngineMessage]) -> MessageGroupType { return currentType } -public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?) { +public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, contentSettings: ContentSettings, messages: [EngineMessage], chatPeer: EngineRenderedPeer, accountPeerId: EnginePeer.Id, enableMediaEmoji: Bool = true, isPeerGroup: Bool = false) -> (peer: EnginePeer?, hideAuthor: Bool, messageText: String, spoilers: [NSRange]?, customEmojiRanges: [(NSRange, ChatTextInputTextCustomEmojiAttribute)]?) { let peer: EnginePeer? let message = messages.last + if let restrictionReason = message?._asMessage().restrictionReason(platform: "ios", contentSettings: contentSettings) { + return (nil, false, restrictionReason, nil, nil) + } + var hideAuthor = false var messageText: String var spoilers: [NSRange]? diff --git a/submodules/PlatformRestrictionMatching/Sources/PlatformRestrictionMatching.swift b/submodules/PlatformRestrictionMatching/Sources/PlatformRestrictionMatching.swift index b3ed30e88a..ca8c03185b 100644 --- a/submodules/PlatformRestrictionMatching/Sources/PlatformRestrictionMatching.swift +++ b/submodules/PlatformRestrictionMatching/Sources/PlatformRestrictionMatching.swift @@ -4,10 +4,16 @@ import Postbox public extension Message { func isRestricted(platform: String, contentSettings: ContentSettings) -> Bool { + return self.restrictionReason(platform: platform, contentSettings: contentSettings) != nil + } + + func restrictionReason(platform: String, contentSettings: ContentSettings) -> String? { if let attribute = self.restrictedContentAttribute { - return attribute.platformText(platform: platform, contentSettings: contentSettings) != nil + if let value = attribute.platformText(platform: platform, contentSettings: contentSettings) { + return value + } } - return false + return nil } } diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index 514c8ebdba..549e1668fa 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -207,7 +207,7 @@ final class ChatMessageAccessibilityData { if let chatPeer = message.peers[item.message.id.peerId] { let authorName = message.author.flatMap(EnginePeer.init)?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) - let (_, _, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId) + let (_, _, messageText, _, _) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, contentSettings: item.context.currentContentSettings.with { $0 }, messages: [EngineMessage(message)], chatPeer: EngineRenderedPeer(peer: EnginePeer(chatPeer)), accountPeerId: item.context.account.peerId) var text = messageText From 38c0fd0bf2eab2388ceeb25e828282556b5cf685 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 4 Nov 2022 23:47:20 +0400 Subject: [PATCH 14/15] Fix peer restriction handling --- submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift | 3 +++ submodules/TelegramCore/Sources/Utils/PeerUtils.swift | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index 03c682039f..b4a7b82ea0 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -53,6 +53,9 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: if let restrictionReason = message?._asMessage().restrictionReason(platform: "ios", contentSettings: contentSettings) { return (nil, false, restrictionReason, nil, nil) } + if let restrictionReason = chatPeer.chatMainPeer?.restrictionText(platform: "ios", contentSettings: contentSettings) { + return (nil, false, restrictionReason, nil, nil) + } var hideAuthor = false var messageText: String diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 39134577c0..47d99d047d 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -30,7 +30,7 @@ public extension Peer { if let restrictionInfo = restrictionInfo { for rule in restrictionInfo.rules { - if rule.platform == "all" || rule.platform == platform { + if rule.platform == "all" || rule.platform == platform || contentSettings.addContentRestrictionReasons.contains(rule.platform) { if !contentSettings.ignoreContentRestrictionReasons.contains(rule.reason) { return rule.text } From 3fde9cf0336fc36abe092e4d62b75ff693b8505d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 5 Nov 2022 00:18:06 +0400 Subject: [PATCH 15/15] Update API --- submodules/TelegramApi/Sources/Api29.swift | 7 ++++--- submodules/TelegramCore/Sources/ForumChannels.swift | 7 +------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/submodules/TelegramApi/Sources/Api29.swift b/submodules/TelegramApi/Sources/Api29.swift index 1830877551..1ba4add6d3 100644 --- a/submodules/TelegramApi/Sources/Api29.swift +++ b/submodules/TelegramApi/Sources/Api29.swift @@ -2444,16 +2444,17 @@ public extension Api.functions.channels { } } public extension Api.functions.channels { - static func reorderPinnedForumTopics(channel: Api.InputChannel, order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func reorderPinnedForumTopics(flags: Int32, channel: Api.InputChannel, order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-529811367) + buffer.appendInt32(693150095) + serializeInt32(flags, buffer: buffer, boxed: false) channel.serialize(buffer, true) buffer.appendInt32(481674261) buffer.appendInt32(Int32(order.count)) for item in order { serializeInt32(item, buffer: buffer, boxed: false) } - return (FunctionDescription(name: "channels.reorderPinnedForumTopics", parameters: [("channel", String(describing: channel)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + return (FunctionDescription(name: "channels.reorderPinnedForumTopics", parameters: [("flags", String(describing: flags)), ("channel", String(describing: channel)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/ForumChannels.swift b/submodules/TelegramCore/Sources/ForumChannels.swift index 84a1bf30dc..4b4fa8e79d 100644 --- a/submodules/TelegramCore/Sources/ForumChannels.swift +++ b/submodules/TelegramCore/Sources/ForumChannels.swift @@ -386,13 +386,8 @@ func _internal_setForumChannelPinnedTopics(account: Account, id: EnginePeer.Id, return .fail(.generic) } - #if DEBUG - if "".isEmpty { - return .complete() - } - #endif - return account.network.request(Api.functions.channels.reorderPinnedForumTopics( + flags: 1 << 0, channel: inputChannel, order: threadIds.map(Int32.init(clamping:)) ))