diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift index b43b0f491c..70dd623548 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchControllerNode.swift @@ -484,7 +484,13 @@ class ChannelMembersSearchControllerNode: ASDisplayNode { index += 1 } - if case .inviteToCall = mode { + if case .inviteToCall = mode, !filters.contains(where: { filter in + if case .excludeNonMembers = filter { + return true + } else { + return false + } + }) { for peer in contactsView.peers { entries.append(ChannelMembersSearchEntry.contact(index, peer, contactsView.peerPresences[peer.id] as? TelegramUserPresence)) index += 1 diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index 2f65717ca6..37d8d1bd28 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -1102,13 +1102,15 @@ public final class PresentationGroupCallImpl: PresentationGroupCall { self.callContext = nil self._canBeRemoved.set(.single(true)) - let toneRenderer = PresentationCallToneRenderer(tone: .groupLeft) - self.toneRenderer = toneRenderer - toneRenderer.setAudioSessionActive(self.isAudioSessionActive) - - Queue.mainQueue().after(0.5, { - self.wasRemoved.set(.single(true)) - }) + if self.didConnectOnce { + let toneRenderer = PresentationCallToneRenderer(tone: .groupLeft) + self.toneRenderer = toneRenderer + toneRenderer.setAudioSessionActive(self.isAudioSessionActive) + + Queue.mainQueue().after(0.5, { + self.wasRemoved.set(.single(true)) + }) + } } public func leave(terminateIfPossible: Bool) -> Signal { diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 56a65f0341..745e060047 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -562,7 +562,7 @@ public final class VoiceChatController: ViewController { guard let strongSelf = self else { return } - guard let groupPeer = groupPeer as? TelegramChannel else { + guard let groupPeer = groupPeer else { return } @@ -570,8 +570,14 @@ public final class VoiceChatController: ViewController { if let currentCallMembers = strongSelf.currentCallMembers { filters.append(.disable(Array(currentCallMembers.map { $0.peer.id }))) } - if !groupPeer.hasPermission(.inviteMembers) { - filters.append(.excludeNonMembers) + if let groupPeer = groupPeer as? TelegramChannel { + if !groupPeer.hasPermission(.inviteMembers) { + filters.append(.excludeNonMembers) + } + } else if let groupPeer = groupPeer as? TelegramGroup { + if !groupPeer.hasBannedPermission(.banAddMembers) { + filters.append(.excludeNonMembers) + } } filters.append(.excludeBots) @@ -598,73 +604,143 @@ public final class VoiceChatController: ViewController { return } - let selfController = strongSelf.controller - let inviteDisposable = strongSelf.inviteDisposable - var inviteSignal = strongSelf.context.peerChannelMemberCategoriesContextsManager.addMembers(account: strongSelf.context.account, peerId: groupPeer.id, memberIds: [peer.id]) - var cancelImpl: (() -> Void)? - let progressSignal = Signal { [weak selfController] subscriber in - let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: { - cancelImpl?() - })) - selfController?.present(controller, in: .window(.root)) - return ActionDisposable { [weak controller] in - Queue.mainQueue().async() { - controller?.dismiss() + if let groupPeer = groupPeer as? TelegramChannel { + let selfController = strongSelf.controller + let inviteDisposable = strongSelf.inviteDisposable + var inviteSignal = strongSelf.context.peerChannelMemberCategoriesContextsManager.addMembers(account: strongSelf.context.account, peerId: groupPeer.id, memberIds: [peer.id]) + var cancelImpl: (() -> Void)? + let progressSignal = Signal { [weak selfController] subscriber in + let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: { + cancelImpl?() + })) + selfController?.present(controller, in: .window(.root)) + return ActionDisposable { [weak controller] in + Queue.mainQueue().async() { + controller?.dismiss() + } } } - } - |> runOn(Queue.mainQueue()) - |> delay(0.15, queue: Queue.mainQueue()) - let progressDisposable = progressSignal.start() - - inviteSignal = inviteSignal - |> afterDisposed { - Queue.mainQueue().async { - progressDisposable.dispose() - } - } - cancelImpl = { - inviteDisposable.set(nil) - } - - inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in - dismissController?() - guard let strongSelf = self else { - return - } - let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + |> runOn(Queue.mainQueue()) + |> delay(0.15, queue: Queue.mainQueue()) + let progressDisposable = progressSignal.start() - let text: String - switch error { - case .limitExceeded: - text = presentationData.strings.Channel_ErrorAddTooMuch - case .tooMuchJoined: - text = presentationData.strings.Invite_ChannelsTooMuch - case .generic: - text = presentationData.strings.Login_UnknownError - case .restricted: - text = presentationData.strings.Channel_ErrorAddBlocked - case .notMutualContact: - text = presentationData.strings.GroupInfo_AddUserLeftError - case .botDoesntSupportGroups: - text = presentationData.strings.Channel_BotDoesntSupportGroups - case .tooMuchBots: - text = presentationData.strings.Channel_TooMuchBots - case .bot: - text = presentationData.strings.Login_UnknownError + inviteSignal = inviteSignal + |> afterDisposed { + Queue.mainQueue().async { + progressDisposable.dispose() + } } - strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - }, completed: { - guard let strongSelf = self else { + cancelImpl = { + inviteDisposable.set(nil) + } + + inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in dismissController?() - return + guard let strongSelf = self else { + return + } + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + + let text: String + switch error { + case .limitExceeded: + text = presentationData.strings.Channel_ErrorAddTooMuch + case .tooMuchJoined: + text = presentationData.strings.Invite_ChannelsTooMuch + case .generic: + text = presentationData.strings.Login_UnknownError + case .restricted: + text = presentationData.strings.Channel_ErrorAddBlocked + case .notMutualContact: + text = presentationData.strings.GroupInfo_AddUserLeftError + case .botDoesntSupportGroups: + text = presentationData.strings.Channel_BotDoesntSupportGroups + case .tooMuchBots: + text = presentationData.strings.Channel_TooMuchBots + case .bot: + text = presentationData.strings.Login_UnknownError + } + strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }, completed: { + guard let strongSelf = self else { + dismissController?() + return + } + dismissController?() + + if strongSelf.call.invitePeer(peer.id) { + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), elevatedLayout: false, action: { _ in return false }), in: .current) + } + })) + } else if let groupPeer = groupPeer as? TelegramGroup { + let selfController = strongSelf.controller + let inviteDisposable = strongSelf.inviteDisposable + var inviteSignal = addGroupMember(account: strongSelf.context.account, peerId: groupPeer.id, memberId: peer.id) + var cancelImpl: (() -> Void)? + let progressSignal = Signal { [weak selfController] subscriber in + let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: { + cancelImpl?() + })) + selfController?.present(controller, in: .window(.root)) + return ActionDisposable { [weak controller] in + Queue.mainQueue().async() { + controller?.dismiss() + } + } } - dismissController?() + |> runOn(Queue.mainQueue()) + |> delay(0.15, queue: Queue.mainQueue()) + let progressDisposable = progressSignal.start() - if strongSelf.call.invitePeer(peer.id) { - strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), elevatedLayout: false, action: { _ in return false }), in: .current) + inviteSignal = inviteSignal + |> afterDisposed { + Queue.mainQueue().async { + progressDisposable.dispose() + } } - })) + cancelImpl = { + inviteDisposable.set(nil) + } + + inviteDisposable.set((inviteSignal |> deliverOnMainQueue).start(error: { error in + dismissController?() + guard let strongSelf = self else { + return + } + let context = strongSelf.context + let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + + switch error { + case .privacy: + let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peer.id) + |> deliverOnMainQueue).start(next: { peer in + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(peer.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + case .notMutualContact: + let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peer.id) + |> deliverOnMainQueue).start(next: { peer in + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.GroupInfo_AddUserLeftError, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + case .tooManyChannels: + let _ = (strongSelf.context.account.postbox.loadedPeerWithId(peer.id) + |> deliverOnMainQueue).start(next: { peer in + self?.controller?.present(textAlertController(context: context, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + case .groupFull, .generic: + strongSelf.controller?.present(textAlertController(context: strongSelf.context, forceTheme: strongSelf.darkTheme, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + } + }, completed: { + guard let strongSelf = self else { + dismissController?() + return + } + dismissController?() + + if strongSelf.call.invitePeer(peer.id) { + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, text: strongSelf.presentationData.strings.VoiceChat_InvitedPeerText(peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)).0), elevatedLayout: false, action: { _ in return false }), in: .current) + } + })) + } })]), in: .window(.root)) } }) @@ -921,13 +997,24 @@ public final class VoiceChatController: ViewController { strongSelf.controller?.dataReady.set(true) } - if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel { - if channel.hasPermission(.manageCalls) { - strongSelf.optionsButton.isUserInteractionEnabled = true - strongSelf.optionsButton.alpha = 1.0 - } else { - strongSelf.optionsButton.isUserInteractionEnabled = false - strongSelf.optionsButton.alpha = 0.0 + if let peer = peerViewMainPeer(view) { + if let channel = peer as? TelegramChannel { + if channel.hasPermission(.manageCalls) { + strongSelf.optionsButton.isUserInteractionEnabled = true + strongSelf.optionsButton.alpha = 1.0 + } else { + strongSelf.optionsButton.isUserInteractionEnabled = false + strongSelf.optionsButton.alpha = 0.0 + } + } else if let group = peer as? TelegramGroup { + switch group.role { + case .creator, .admin: + strongSelf.optionsButton.isUserInteractionEnabled = true + strongSelf.optionsButton.alpha = 1.0 + default: + strongSelf.optionsButton.isUserInteractionEnabled = false + strongSelf.optionsButton.alpha = 0.0 + } } } }) diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index 6ae73f4c38..0184a4bf26 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit 6ae73f4c388854d86a0ce66bf243561a11d9e719 +Subproject commit 0184a4bf26ed749bf59543c70ff413d4f3579c2b