Voice Chat UI improvements

This commit is contained in:
Ilya Laktyushin 2020-11-30 11:22:25 +04:00
parent 572bc95254
commit 41bcbd14f0
8 changed files with 125 additions and 62 deletions

View File

@ -1353,7 +1353,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
case let .peer(_, renderedPeer, _, _, presence, _ ,_ ,_, _, _, displayAsMessage, _): case let .peer(_, renderedPeer, _, _, presence, _ ,_ ,_, _, _, displayAsMessage, _):
if !displayAsMessage { if !displayAsMessage {
if let peer = renderedPeer.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId { if let peer = renderedPeer.peer as? TelegramUser, let presence = presence as? TelegramUserPresence, !isServicePeer(peer) && !peer.flags.contains(.isSupport) && peer.id != item.context.account.peerId {
var updatedPresence = TelegramUserPresence(status: presence.status, lastActivity: 0) let updatedPresence = TelegramUserPresence(status: presence.status, lastActivity: 0)
let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp) let relativeStatus = relativeUserPresenceStatus(updatedPresence, relativeTo: timestamp)
if case .online = relativeStatus { if case .online = relativeStatus {
online = true online = true
@ -1361,10 +1361,10 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
animateOnline = true animateOnline = true
} else if let channel = renderedPeer.peer as? TelegramChannel { } else if let channel = renderedPeer.peer as? TelegramChannel {
onlineIsVoiceChat = true onlineIsVoiceChat = true
if channel.flags.contains(.hasVoiceChat) { if channel.flags.contains(.hasVoiceChat) && item.interaction.searchTextHighightState == nil {
online = true online = true
animateOnline = true
} }
animateOnline = true
} }
} }

View File

@ -47,7 +47,15 @@ private final class Curve {
let minSpeed: CGFloat let minSpeed: CGFloat
let maxSpeed: CGFloat let maxSpeed: CGFloat
var size: CGSize var size: CGSize {
didSet {
if self.size != oldValue {
self.fromPoints = nil
self.toPoints = nil
self.animateToNewShape()
}
}
}
let alpha: CGFloat let alpha: CGFloat
var currentOffset: CGFloat = 1.0 var currentOffset: CGFloat = 1.0
var minOffset: CGFloat = 0.0 var minOffset: CGFloat = 0.0
@ -177,7 +185,7 @@ private final class Curve {
private func generateNextCurve(for size: CGSize) -> [CGPoint] { private func generateNextCurve(for size: CGSize) -> [CGPoint] {
let randomness = minRandomness + (maxRandomness - minRandomness) * speedLevel let randomness = minRandomness + (maxRandomness - minRandomness) * speedLevel
return curve(pointsCount: pointsCount, randomness: randomness).map { return curve(pointsCount: pointsCount, randomness: randomness).map {
return CGPoint(x: $0.x * CGFloat(size.width), y: size.height - 14.0 + $0.y * 12.0) return CGPoint(x: $0.x * CGFloat(size.width), y: size.height - 17.0 + $0.y * 12.0)
} }
} }
@ -545,6 +553,6 @@ public class CallStatusBarNodeImpl: CallStatusBarNode {
self.subtitleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - subtitleSize.height) / 2.0)), size: subtitleSize) self.subtitleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - subtitleSize.height) / 2.0)), size: subtitleSize)
self.backgroundNode.speaking = !self.currentIsMuted self.backgroundNode.speaking = !self.currentIsMuted
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 14.0)) self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 17.0))
} }
} }

View File

@ -71,6 +71,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
let titleNode: ImmediateTextNode let titleNode: ImmediateTextNode
let textNode: ImmediateTextNode let textNode: ImmediateTextNode
private var textIsActive = false
private let muteIconNode: ASImageNode private let muteIconNode: ASImageNode
private let avatarsContext: AnimatedAvatarSetContext private let avatarsContext: AnimatedAvatarSetContext
@ -229,6 +230,22 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme) self.muteIconNode.image = PresentationResourcesChat.chatTitleMuteIcon(presentationData.theme)
} }
private func animateTextChange() {
if let snapshotView = self.textNode.view.snapshotContentTree() {
let offset: CGFloat = self.textIsActive ? -7.0 : 7.0
self.textNode.view.superview?.insertSubview(snapshotView, belowSubview: self.textNode.view)
snapshotView.frame = self.textNode.frame
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -offset), duration: 0.2, removeOnCompletion: false, additive: true)
self.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
self.textNode.layer.animatePosition(from: CGPoint(x: 0.0, y: offset), to: CGPoint(), duration: 0.2, additive: true)
}
}
public func update(data: GroupCallPanelData) { public func update(data: GroupCallPanelData) {
let previousData = self.currentData let previousData = self.currentData
self.currentData = data self.currentData = data
@ -271,6 +288,11 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
membersTextIsActive = false membersTextIsActive = false
} }
if strongSelf.textIsActive != membersTextIsActive {
strongSelf.textIsActive = membersTextIsActive
strongSelf.animateTextChange()
}
strongSelf.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: membersTextIsActive ? strongSelf.theme.chat.inputPanel.panelControlAccentColor : strongSelf.theme.chat.inputPanel.secondaryTextColor) strongSelf.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: membersTextIsActive ? strongSelf.theme.chat.inputPanel.panelControlAccentColor : strongSelf.theme.chat.inputPanel.secondaryTextColor)
strongSelf.avatarsContent = strongSelf.avatarsContext.update(peers: summaryState.topParticipants.map { $0.peer }, animated: false) strongSelf.avatarsContent = strongSelf.avatarsContext.update(peers: summaryState.topParticipants.map { $0.peer }, animated: false)
@ -368,6 +390,11 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
membersTextIsActive = false membersTextIsActive = false
} }
if self.textIsActive != membersTextIsActive {
self.textIsActive = membersTextIsActive
self.animateTextChange()
}
self.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: membersTextIsActive ? self.theme.chat.inputPanel.panelControlAccentColor : self.theme.chat.inputPanel.secondaryTextColor) self.textNode.attributedText = NSAttributedString(string: membersText, font: Font.regular(13.0), textColor: membersTextIsActive ? self.theme.chat.inputPanel.panelControlAccentColor : self.theme.chat.inputPanel.secondaryTextColor)
self.avatarsContent = self.avatarsContext.update(peers: data.topParticipants.map { $0.peer }, animated: false) self.avatarsContent = self.avatarsContext.update(peers: data.topParticipants.map { $0.peer }, animated: false)
@ -481,7 +508,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
let foregroundFrame = self.micButtonForegroundNode.view.convert(self.micButtonForegroundNode.bounds, to: nil) let foregroundFrame = self.micButtonForegroundNode.view.convert(self.micButtonForegroundNode.bounds, to: nil)
let backgroundView = UIView() let backgroundView = UIView()
backgroundView.backgroundColor = UIColor(rgb: 0x30b251) backgroundView.backgroundColor = (self.micButtonBackgroundNodeIsMuted ?? true) ? UIColor(rgb: 0xb6b6bb) : UIColor(rgb: 0x30b251)
backgroundView.frame = backgroundFrame backgroundView.frame = backgroundFrame
backgroundView.layer.cornerRadius = backgroundFrame.height / 2.0 backgroundView.layer.cornerRadius = backgroundFrame.height / 2.0

View File

@ -576,7 +576,9 @@ private class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
self.animator = animator self.animator = animator
} }
animator.isPaused = false animator.isPaused = false
animator.frameInterval = state.frameInterval if self.transition == nil {
animator.frameInterval = state.frameInterval
}
} else { } else {
self.animator?.isPaused = true self.animator?.isPaused = true
} }
@ -619,7 +621,7 @@ private class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
var appearanceProgress: CGFloat = 1.0 var appearanceProgress: CGFloat = 1.0
var glowScale: CGFloat = 0.75 var glowScale: CGFloat = 0.75
if let transition = parameters.transition, transition.previousState == .connecting { if let transition = parameters.transition, transition.previousState == .connecting || transition.previousState == .disabled {
appearanceProgress = transition.transition appearanceProgress = transition.transition
} }
@ -751,15 +753,18 @@ private class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
} }
} }
var clearInside: CGFloat? var clearInsideTransition: CGFloat?
if parameters.state is VoiceChatActionButtonBackgroundNodeBlobState { if parameters.state is VoiceChatActionButtonBackgroundNodeBlobState {
let path = CGMutablePath() let path = CGMutablePath()
path.addEllipse(in: buttonRect.insetBy(dx: -lineWidth / 2.0, dy: -lineWidth / 2.0)) path.addEllipse(in: buttonRect.insetBy(dx: -lineWidth / 2.0, dy: -lineWidth / 2.0))
context.addPath(path) context.addPath(path)
context.clip() context.clip()
if let transition = parameters.transition, transition.previousState == .connecting || transition.previousState == .disabled, transition.transition > 0.5 { if let transition = parameters.transition {
let progress = (transition.transition - 0.5) / 0.5 if transition.previousState == .connecting, transition.transition > 0.5 {
clearInside = progress clearInsideTransition = (transition.transition - 0.5) / 0.5
} else if transition.previousState == .disabled {
clearInsideTransition = transition.transition
}
} }
drawGradient = true drawGradient = true
@ -774,9 +779,9 @@ private class VoiceChatActionButtonBackgroundNode: ASDisplayNode {
} }
} }
if let clearInside = clearInside { if let transition = clearInsideTransition {
context.setFillColor(greyColor.cgColor) context.setFillColor(greyColor.cgColor)
context.fillEllipse(in: buttonRect.insetBy(dx: clearInside * radius, dy: clearInside * radius)) context.fillEllipse(in: buttonRect.insetBy(dx: transition * radius, dy: transition * radius))
} }
} }
} }

View File

@ -89,7 +89,7 @@ private final class VoiceChatControllerTitleView: UIView {
} }
public final class VoiceChatController: ViewController { public final class VoiceChatController: ViewController {
private final class Node: ViewControllerTracingNode { private final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
private struct ListTransition { private struct ListTransition {
let deletions: [ListViewDeleteItem] let deletions: [ListViewDeleteItem]
let insertions: [ListViewInsertItem] let insertions: [ListViewInsertItem]
@ -412,7 +412,7 @@ public final class VoiceChatController: ViewController {
} }
} }
if let callState = strongSelf.callState, (callState.canManageCall && !callState.adminIds.contains(strongSelf.context.account.peerId)) { if let callState = strongSelf.callState, (callState.canManageCall && !callState.adminIds.contains(peer.id)) {
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.VoiceChat_RemovePeer, textColor: .destructive, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Clear"), color: theme.actionSheet.destructiveActionTextColor)
}, action: { [weak self] _, f in }, action: { [weak self] _, f in
@ -523,15 +523,19 @@ public final class VoiceChatController: ViewController {
return return
} }
if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel {
if !(channel.addressName ?? "").isEmpty || (channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers)) {
strongSelf.optionsButton.isHidden = false
} else {
strongSelf.optionsButton.isHidden = true
}
}
if !strongSelf.didSetDataReady { if !strongSelf.didSetDataReady {
if let peer = peerViewMainPeer(view), let channel = peer as? TelegramChannel {
let addressName = channel.addressName ?? ""
if !addressName.isEmpty || (channel.flags.contains(.isCreator) || channel.hasPermission(.inviteMembers)) {
if addressName.isEmpty {
let _ = ensuredExistingPeerExportedInvitation(account: strongSelf.context.account, peerId: call.peerId).start()
}
} else {
strongSelf.optionsButton.isUserInteractionEnabled = false
strongSelf.optionsButton.alpha = 0.0
}
}
strongSelf.didSetDataReady = true strongSelf.didSetDataReady = true
strongSelf.controller?.dataReady.set(true) strongSelf.controller?.dataReady.set(true)
} }
@ -675,8 +679,6 @@ public final class VoiceChatController: ViewController {
optionsButtonItem.target = self optionsButtonItem.target = self
optionsButtonItem.action = #selector(self.rightNavigationButtonAction) optionsButtonItem.action = #selector(self.rightNavigationButtonAction)
self.controller?.navigationItem.setRightBarButton(optionsButtonItem, animated: false) self.controller?.navigationItem.setRightBarButton(optionsButtonItem, animated: false)
let _ = ensuredExistingPeerExportedInvitation(account: self.context.account, peerId: call.peerId).start()
} }
deinit { deinit {
@ -701,6 +703,7 @@ public final class VoiceChatController: ViewController {
let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.actionButtonPressGesture(_:))) let longTapRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.actionButtonPressGesture(_:)))
longTapRecognizer.minimumPressDuration = 0.001 longTapRecognizer.minimumPressDuration = 0.001
longTapRecognizer.delegate = self
self.actionButton.view.addGestureRecognizer(longTapRecognizer) self.actionButton.view.addGestureRecognizer(longTapRecognizer)
let panRecognizer = CallPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))) let panRecognizer = CallPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
@ -714,7 +717,9 @@ public final class VoiceChatController: ViewController {
} }
@objc private func rightNavigationButtonAction() { @objc private func rightNavigationButtonAction() {
self.optionsButton.contextAction?(self.optionsButton.containerNode, nil) if self.optionsButton.isUserInteractionEnabled {
self.optionsButton.contextAction?(self.optionsButton.containerNode, nil)
}
} }
@objc private func leavePressed() { @objc private func leavePressed() {
@ -726,6 +731,14 @@ public final class VoiceChatController: ViewController {
private var actionButtonPressGestureStartTime: Double = 0.0 private var actionButtonPressGestureStartTime: Double = 0.0
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let callState = self.callState, case .connected = callState.networkState, let muteState = callState.muteState, !muteState.canUnmute {
return false
} else {
return true
}
}
@objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) { @objc private func actionButtonPressGesture(_ gestureRecognizer: UILongPressGestureRecognizer) {
guard let callState = self.callState else { guard let callState = self.callState else {
return return
@ -1010,7 +1023,7 @@ public final class VoiceChatController: ViewController {
} }
} }
if let (backgroundView, foregroundView) = sourcePanel.rightButtonSnapshotViews(), !self.optionsButton.isHidden { if let (backgroundView, foregroundView) = sourcePanel.rightButtonSnapshotViews(), self.optionsButton.isUserInteractionEnabled {
self.view.addSubview(backgroundView) self.view.addSubview(backgroundView)
self.view.addSubview(foregroundView) self.view.addSubview(foregroundView)
@ -1190,6 +1203,7 @@ public final class VoiceChatController: ViewController {
memberState = .speaking memberState = .speaking
} else { } else {
memberState = .listening memberState = .listening
memberMuteState = member.muteState
} }
} else { } else {
memberState = speakingPeers.contains(member.peer.id) ? .speaking : .listening memberState = speakingPeers.contains(member.peer.id) ? .speaking : .listening

View File

@ -14,14 +14,14 @@ func optionsButtonImage() -> UIImage? {
}) })
} }
final class VoiceChatOptionsButton: HighlightableButtonNode { final class VoiceChatOptionsButton: ASDisplayNode {
let extractedContainerNode: ContextExtractedContentContainingNode let extractedContainerNode: ContextExtractedContentContainingNode
let containerNode: ContextControllerSourceNode let containerNode: ContextControllerSourceNode
private let iconNode: ASImageNode private let iconNode: ASImageNode
var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
init() { override init() {
self.extractedContainerNode = ContextExtractedContentContainingNode() self.extractedContainerNode = ContextExtractedContentContainingNode()
self.containerNode = ContextControllerSourceNode() self.containerNode = ContextControllerSourceNode()
self.containerNode.isGestureEnabled = false self.containerNode.isGestureEnabled = false

View File

@ -379,8 +379,8 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
let verticalOffset: CGFloat = 0.0 let verticalOffset: CGFloat = 0.0
let avatarSize: CGFloat = 40.0 let avatarSize: CGFloat = 40.0
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 25.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 12.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 25.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (statusLayout, statusApply) = makeStatusLayout(TextNodeLayoutArguments(attributedString: statusAttributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftInset - 8.0 - rightInset - 30.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let insets = UIEdgeInsets() let insets = UIEdgeInsets()
@ -622,11 +622,16 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
animationNode = VoiceChatMicrophoneNode() animationNode = VoiceChatMicrophoneNode()
strongSelf.animationNode = animationNode strongSelf.animationNode = animationNode
strongSelf.actionButtonNode.addSubnode(animationNode) strongSelf.actionButtonNode.addSubnode(animationNode)
if let _ = strongSelf.iconNode {
animationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
animationNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
}
} }
animationNode.update(state: VoiceChatMicrophoneNode.State(muted: muted, color: color), animated: true) animationNode.update(state: VoiceChatMicrophoneNode.State(muted: muted, color: color), animated: true)
strongSelf.actionButtonNode.isUserInteractionEnabled = false strongSelf.actionButtonNode.isUserInteractionEnabled = false
} else if let animationNode = strongSelf.animationNode { } else if let animationNode = strongSelf.animationNode {
strongSelf.animationNode = nil strongSelf.animationNode = nil
animationNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
animationNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false, completion: { [weak animationNode] _ in animationNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false, completion: { [weak animationNode] _ in
animationNode?.removeFromSupernode() animationNode?.removeFromSupernode()
}) })
@ -641,6 +646,11 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
iconNode.contentMode = .center iconNode.contentMode = .center
strongSelf.iconNode = iconNode strongSelf.iconNode = iconNode
strongSelf.actionButtonNode.addSubnode(iconNode) strongSelf.actionButtonNode.addSubnode(iconNode)
if let _ = strongSelf.animationNode {
iconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
iconNode.layer.animateScale(from: 0.001, to: 1.0, duration: 0.2)
}
} }
if invited { if invited {
@ -651,6 +661,7 @@ public class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode {
strongSelf.actionButtonNode.isUserInteractionEnabled = !invited strongSelf.actionButtonNode.isUserInteractionEnabled = !invited
} else if let iconNode = strongSelf.iconNode { } else if let iconNode = strongSelf.iconNode {
strongSelf.iconNode = nil strongSelf.iconNode = nil
iconNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
iconNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false, completion: { [weak iconNode] _ in iconNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false, completion: { [weak iconNode] _ in
iconNode?.removeFromSupernode() iconNode?.removeFromSupernode()
}) })

View File

@ -496,37 +496,35 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
break break
} }
} }
case let .groupPhoneCall(callId, accessHash, duration): case let .groupPhoneCall(callId, accessHash, nil), let .inviteToGroupPhoneCall(callId, accessHash, _):
let peerId = message.id.peerId let peerId = message.id.peerId
if duration == nil { let callResult = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: callId, accessHash: accessHash), endCurrentIfAny: false, sourcePanel: nil)
let callResult = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: callId, accessHash: accessHash), endCurrentIfAny: false, sourcePanel: nil) if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if currentPeerId == peerId {
if currentPeerId == peerId { strongSelf.context.sharedContext.navigateToCurrentCall(sourcePanel: nil)
strongSelf.context.sharedContext.navigateToCurrentCall(sourcePanel: nil) } else {
} else { let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let _ = (strongSelf.context.account.postbox.transaction { transaction -> (Peer?, Peer?) in
let _ = (strongSelf.context.account.postbox.transaction { transaction -> (Peer?, Peer?) in return (transaction.getPeer(peerId), currentPeerId.flatMap(transaction.getPeer))
return (transaction.getPeer(peerId), currentPeerId.flatMap(transaction.getPeer))
}
|> deliverOnMainQueue).start(next: { [weak self] peer, current in
guard let strongSelf = self else {
return
}
guard let peer = peer else {
return
}
if let current = current {
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
if let strongSelf = self {
let _ = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: callId, accessHash: accessHash), endCurrentIfAny: true, sourcePanel: nil)
}
})]), in: .window(.root))
} else {
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_ExternalCallInProgressMessage, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
})]), in: .window(.root))
}
})
} }
|> deliverOnMainQueue).start(next: { [weak self] peer, current in
guard let strongSelf = self else {
return
}
guard let peer = peer else {
return
}
if let current = current {
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
if let strongSelf = self {
let _ = strongSelf.context.sharedContext.callManager?.joinGroupCall(context: strongSelf.context, peerId: peerId, initialCall: CachedChannelData.ActiveCall(id: callId, accessHash: accessHash), endCurrentIfAny: true, sourcePanel: nil)
}
})]), in: .window(.root))
} else {
strongSelf.present(textAlertController(context: strongSelf.context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_ExternalCallInProgressMessage, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
})]), in: .window(.root))
}
})
} }
} }
break break