diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index c170490d32..8180387a41 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -619,6 +619,9 @@ public protocol SharedAccountContext: class { var hasOngoingCall: ValuePromise { get } var immediateHasOngoingCall: Bool { get } + var hasGroupCallOnScreen: Signal { get } + var currentGroupCallController: ViewController? { get } + func switchToAccount(id: AccountRecordId, fromSettingsController settingsController: ViewController?, withChatListController chatListController: ViewController?) func beginNewAuth(testingEnvironment: Bool) } diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index a4e19257bb..6c680db362 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1178,8 +1178,9 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { participantsContext.activeSpeakers, self.speakingParticipantsContext.get(), adminIds, - myPeer - ).start(next: { [weak self] state, activeSpeakers, speakingParticipants, adminIds, myPeer in + myPeer, + accountContext.account.postbox.peerView(id: peerId) + ).start(next: { [weak self] state, activeSpeakers, speakingParticipants, adminIds, myPeer, view in guard let strongSelf = self else { return } @@ -1254,8 +1255,40 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { if let muteState = participant.muteState, muteState.canUnmute && strongSelf.stateValue.raisedHand { strongSelf.stateValue.raisedHand = false - let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 } - strongSelf.accountContext.sharedContext.mainWindow?.present(UndoOverlayController(presentationData: presentationData, content: .voiceChatCanSpeak(text: presentationData.strings.VoiceChat_YouCanNowSpeak), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), on: .root, blockInteraction: false, completion: {}) + + let _ = (strongSelf.accountContext.sharedContext.hasGroupCallOnScreen + |> take(1) + |> deliverOnMainQueue).start(next: { [weak self] hasGroupCallOnScreen in + let presentationData = strongSelf.accountContext.sharedContext.currentPresentationData.with { $0 } + if hasGroupCallOnScreen, let groupCallController = self?.accountContext.sharedContext.currentGroupCallController { + var animateInAsReplacement = false + groupCallController.forEachController { c in + if let c = c as? UndoOverlayController { + animateInAsReplacement = true + c.dismiss() + } + return true + } + groupCallController.present(UndoOverlayController(presentationData: presentationData, content: .voiceChatCanSpeak(text: presentationData.strings.VoiceChat_YouCanNowSpeak), elevatedLayout: false, animateInAsReplacement: animateInAsReplacement, action: { _ in return true }), in: .current) + } else { + let title: String? + if let voiceChatTitle = strongSelf.stateValue.title { + title = voiceChatTitle + } else if let peer = peerViewMainPeer(view) { + title = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) + } else { + title = nil + } + + let text: String + if let title = title { + text = presentationData.strings.VoiceChat_YouCanNowSpeakIn(title).0 + } else { + text = presentationData.strings.VoiceChat_YouCanNowSpeak + } + strongSelf.accountContext.sharedContext.mainWindow?.present(UndoOverlayController(presentationData: presentationData, content: .voiceChatCanSpeak(text: text), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), on: .root, blockInteraction: false, completion: {}) + } + }) } if let muteState = participant.muteState { @@ -1823,7 +1856,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { updatedInvitedPeers.insert(peerId, at: 0) self.invitedPeersValue = updatedInvitedPeers - let _ = inviteToGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, peerId: peerId).start() + let _ = inviteToGroupCall(account: self.account, callId: callInfo.id, accessHash: callInfo.accessHash, peerId: peerId, canUnmute: false).start() return true } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 82110e4ad4..594bca3e0e 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -782,7 +782,7 @@ public final class VoiceChatController: ViewController { let displayAsPeers: Signal<[FoundPeer], NoError> = currentAccountPeer |> then( - combineLatest(currentAccountPeer, groupCallDisplayAsAvailablePeers(network: context.account.network, postbox: context.account.postbox)) + combineLatest(currentAccountPeer, groupCallDisplayAsAvailablePeers(network: context.account.network, postbox: context.account.postbox, peerId: call.peerId)) |> map { currentAccountPeer, availablePeers -> [FoundPeer] in var result = currentAccountPeer result.append(contentsOf: availablePeers) diff --git a/submodules/TelegramCore/Sources/GroupCalls.swift b/submodules/TelegramCore/Sources/GroupCalls.swift index a9918d20e0..68bcb64068 100644 --- a/submodules/TelegramCore/Sources/GroupCalls.swift +++ b/submodules/TelegramCore/Sources/GroupCalls.swift @@ -337,6 +337,29 @@ public func getGroupCallParticipants(account: Account, callId: Int64, accessHash } } +public func inviteToGroupCall(account: Account, peerId: PeerId, callId: Int64, accessHash: Int64, users: Set, canUnmute: Bool) -> Signal { + return .complete() +// return account.postbox.transaction { transaction -> [Api.InputUser] in +// var inputUsers: [Api.InputUser] = [] +// for user in users { +// if let peer = transaction.getPeer(user), let inputUser = apiInputUser(peer) { +// inputUsers.append(inputUser) +// } +// } +// return inputUsers +// } +// |> mapToSignal { users -> Signal in +// return account.network.request(Api.functions.phone.inviteToGroupCall(flags: 0, call: .inputGroupCall(id: callId, accessHash: accessHash), users: users)) +// |> `catch` { _ -> Signal in +// return .single(Void()) +// } |> mapToSignal { updates -> Signal in +// account.stateManager.addUpdates(updates) +// +// return .single(Void()) +// } +// } +} + public enum JoinGroupCallError { case generic case anonymousNotAllowed @@ -1776,7 +1799,6 @@ public func editGroupCallTitle(account: Account, callId: Int64, accessHash: Int6 } public func groupCallDisplayAsAvailablePeers(network: Network, postbox: Postbox, peerId: PeerId) -> Signal<[FoundPeer], NoError> { - return postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } |> mapToSignal { inputPeer in @@ -1817,8 +1839,6 @@ public func groupCallDisplayAsAvailablePeers(network: Network, postbox: Postbox, } } - - } public final class CachedDisplayAsPeers: PostboxCoding { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 983fa3e5b0..eaab05896e 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -11855,7 +11855,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let context = self.context let presentationData = self.presentationData - var proceed: (PeerId) -> Void = { joinAsPeerId in + let proceed: (PeerId) -> Void = { joinAsPeerId in super.joinGroupCall(peerId: peerId, joinAsPeerId: joinAsPeerId, activeCall: activeCall) } @@ -11865,7 +11865,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return [FoundPeer(peer: peer, subscribers: nil)] } - let _ = (combineLatest(currentAccountPeer, cachedGroupCallDisplayAsAvailablePeers(account: context.account)) + let _ = (combineLatest(currentAccountPeer, groupCallDisplayAsAvailablePeers(network: context.account.network, postbox: context.account.postbox, peerId: peerId)) |> map { currentAccountPeer, availablePeers -> [FoundPeer] in var result = currentAccountPeer result.append(contentsOf: availablePeers) diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 0460a8814f..d9794be4f4 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -609,6 +609,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur var startGroup: String? var game: String? var post: String? + var voiceChat: String? if let queryItems = components.queryItems { for queryItem in queryItems { if let value = queryItem.value { @@ -622,7 +623,11 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur game = value } else if queryItem.name == "post" { post = value + } else if queryItem.name == "voicechat" { + voiceChat = value } + } else if queryItem.name == "voicechat" { + voiceChat = "" } } } @@ -638,6 +643,12 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur result += "?startgroup=\(startGroup)" } else if let game = game { result += "?game=\(game)" + } else if let voiceChat = voiceChat { + if !voiceChat.isEmpty { + result += "?voicechat=\(voiceChat)" + } else { + result += "?voicechat=" + } } convertedUrl = result } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 21d9102390..964f157805 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -2780,7 +2780,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD } if [Namespaces.Peer.CloudGroup, Namespaces.Peer.CloudChannel].contains(peerId.namespace) { - self.displayAsPeersPromise.set(cachedGroupCallDisplayAsAvailablePeers(account: context.account)) + self.displayAsPeersPromise.set(groupCallDisplayAsAvailablePeers(network: context.account.network, postbox: context.account.postbox, peerId: peerId)) } } diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 14b55ab918..428eca056c 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -100,7 +100,13 @@ public final class SharedAccountContextImpl: SharedAccountContext { private let callState = Promise(nil) private var groupCallController: VoiceChatController? - private let hasGroupCallOnScreen = ValuePromise(false, ignoreRepeated: true) + public var currentGroupCallController: ViewController? { + return self.groupCallController + } + private let hasGroupCallOnScreenPromise = ValuePromise(false, ignoreRepeated: true) + public var hasGroupCallOnScreen: Signal { + return self.hasGroupCallOnScreenPromise.get() + } private var immediateHasOngoingCallValue = Atomic(value: false) public var immediateHasOngoingCall: Bool { @@ -637,16 +643,16 @@ public final class SharedAccountContextImpl: SharedAccountContext { if let call = call, let navigationController = mainWindow.viewController as? NavigationController { mainWindow.hostView.containerView.endEditing(true) - strongSelf.hasGroupCallOnScreen.set(true) + strongSelf.hasGroupCallOnScreenPromise.set(true) let groupCallController = VoiceChatController(sharedContext: strongSelf, accountContext: call.accountContext, call: call) groupCallController.onViewDidAppear = { [weak self] in if let strongSelf = self { - strongSelf.hasGroupCallOnScreen.set(true) + strongSelf.hasGroupCallOnScreenPromise.set(true) } } groupCallController.onViewDidDisappear = { [weak self] in if let strongSelf = self { - strongSelf.hasGroupCallOnScreen.set(false) + strongSelf.hasGroupCallOnScreenPromise.set(false) } } groupCallController.navigationPresentation = .flatModal @@ -673,7 +679,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { self.callStateDisposable = combineLatest(queue: .mainQueue(), callSignal, groupCallSignal, - self.hasGroupCallOnScreen.get() + self.hasGroupCallOnScreenPromise.get() ).start(next: { [weak self] call, groupCall, hasGroupCallOnScreen in if let strongSelf = self { let statusBarContent: CallStatusBarNodeImpl.Content? diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index bbb037985c..7a1f164771 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -17,6 +17,7 @@ public enum ParsedInternalPeerUrlParameter { case groupBotStart(String) case channelMessage(Int32) case replyThread(Int32, Int32) + case voiceChat(String?) } public enum ParsedInternalUrl { @@ -135,7 +136,11 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? { return .peerName(peerName, .groupBotStart(value)) } else if queryItem.name == "game" { return nil + } else if queryItem.name == "voicechat" { + return .peerName(peerName, .voiceChat(value)) } + } else if queryItem.name == "voicechat" { + return .peerName(peerName, .voiceChat(nil)) } } } @@ -334,6 +339,8 @@ private func resolveInternalUrl(account: Account, url: ParsedInternalUrl) -> Sig } return .replyThreadMessage(replyThreadMessage: result, messageId: MessageId(peerId: result.messageId.peerId, namespace: Namespaces.Message.Cloud, id: replyId)) } + case let .voiceChat(invite): + return .single(.peer(peer.id, .default)) } } else { if let peer = peer as? TelegramUser, peer.botInfo == nil {