diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index bafa506ffb..12694353fe 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -747,6 +747,7 @@ public final class VoiceChatController: ViewController { private var currentNormalButtonColor: UIColor? private var currentActiveButtonColor: UIColor? + private var mainEntry: VoiceChatPeerEntry? private var currentEntries: [ListEntry] = [] private var currentFullscreenEntries: [ListEntry] = [] @@ -1840,7 +1841,7 @@ public final class VoiceChatController: ViewController { } else if strongSelf.peerIdToEndpoint.count > 0 { for entry in strongSelf.currentFullscreenEntries { if case let .peer(peerEntry, _) = entry { - if let videoEndpointId = peerEntry.effectiveVideoEndpointId { + if let _ = peerEntry.effectiveVideoEndpointId { maxLevelWithVideo = (peerEntry.peer.id, 0.0) break } @@ -4162,11 +4163,11 @@ public final class VoiceChatController: ViewController { }) } - private func updateMembers() { - self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set()) + private func updateMembers(maybeUpdateVideo: Bool = true) { + self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set(), maybeUpdateVideo: maybeUpdateVideo) } - private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set, updatePinnedPeer: Bool = true) { + private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set, maybeUpdateVideo: Bool = true) { var disableAnimation = false if self.currentCallMembers?.1 != callMembers.1 { disableAnimation = true @@ -4193,6 +4194,7 @@ public final class VoiceChatController: ViewController { var entryByPeerId: [PeerId: VoiceChatPeerEntry] = [:] var latestWideVideo: String? = nil + var mainEntry: VoiceChatPeerEntry? for member in callMembers.0 { if processedPeerIds.contains(member.peer.id) { continue @@ -4270,7 +4272,7 @@ public final class VoiceChatController: ViewController { isLandscape: self.isLandscape ) if peerEntry.active { - self.mainStageNode.update(peerEntry: peerEntry, pinned: self.currentForcedSpeaker != nil) + mainEntry = peerEntry } entryByPeerId[peerEntry.peer.id] = peerEntry @@ -4392,6 +4394,19 @@ public final class VoiceChatController: ViewController { return } + let previousMainEntry = self.mainEntry + self.mainEntry = mainEntry + if let mainEntry = mainEntry { + self.mainStageNode.update(peerEntry: mainEntry, pinned: self.currentForcedSpeaker != nil) + + if let previousMainEntry = previousMainEntry, maybeUpdateVideo { + if previousMainEntry.effectiveVideoEndpointId != mainEntry.effectiveVideoEndpointId { + self.updateMainVideo(waitForFullSize: true, entries: fullscreenEntries, force: true) + return + } + } + } + self.updateRequestedVideoChannels() self.endpointToPeerId = endpointIdToPeerId @@ -4557,13 +4572,13 @@ public final class VoiceChatController: ViewController { } } - private func updateMainVideo(waitForFullSize: Bool, updateMembers: Bool = true, force: Bool = false, completion: (() -> Void)? = nil) { + private func updateMainVideo(waitForFullSize: Bool, entries: [ListEntry]? = nil, updateMembers: Bool = true, force: Bool = false, completion: (() -> Void)? = nil) { let effectiveMainSpeaker = self.currentForcedSpeaker ?? self.currentDominantSpeaker.flatMap { ($0.0, $0.1) } guard effectiveMainSpeaker?.0 != self.effectiveSpeaker?.0 || effectiveMainSpeaker?.1 != self.effectiveSpeaker?.1 || force else { return } - let currentEntries = self.currentFullscreenEntries + let currentEntries = entries ?? self.currentFullscreenEntries var effectiveSpeaker: (PeerId, String?)? = nil var anySpeakerWithVideo: (PeerId, String?)? = nil var anySpeaker: PeerId? = nil @@ -4600,7 +4615,7 @@ public final class VoiceChatController: ViewController { self.effectiveSpeaker = effectiveSpeaker if updateMembers { - self.updateMembers() + self.updateMembers(maybeUpdateVideo: false) } self.mainStageNode.update(peer: effectiveSpeaker, waitForFullSize: waitForFullSize, completion: { completion?() diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift b/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift index c6c9febcf8..ef08688d71 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatMainStageNode.swift @@ -284,10 +284,13 @@ final class VoiceChatMainStageNode: ASDisplayNode { } private var animatingIn = false private var animatingOut = false + private var appeared = false + func animateTransitionIn(from sourceNode: ASDisplayNode, transition: ContainedViewLayoutTransition) { guard let sourceNode = sourceNode as? VoiceChatTileItemNode, let _ = sourceNode.item, let (_, sideInset, bottomInset, isLandscape) = self.validLayout else { return } + self.appeared = true let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) alphaTransition.updateAlpha(node: self.backgroundNode, alpha: 1.0) @@ -327,6 +330,8 @@ final class VoiceChatMainStageNode: ASDisplayNode { return } + self.appeared = false + let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) alphaTransition.updateAlpha(node: self.backgroundNode, alpha: 0.0) alphaTransition.updateAlpha(node: self.topFadeNode, alpha: 0.0) @@ -543,14 +548,13 @@ final class VoiceChatMainStageNode: ASDisplayNode { self.audioLevelNode.startAnimating(immediately: true) if let getAudioLevel = self.getAudioLevel, previousPeerEntry?.peer.id != peerEntry.peer.id { + self.audioLevelNode.isHidden = self.currentPeer?.1 != nil self.audioLevelDisposable.set((getAudioLevel(peerEntry.peer.id) |> deliverOnMainQueue).start(next: { [weak self] value in guard let strongSelf = self else { return } - - strongSelf.audioLevelNode.isHidden = strongSelf.currentPeer?.1 != nil - + let level = min(1.5, max(0.0, CGFloat(value))) strongSelf.audioLevelNode.updateLevel(CGFloat(value)) @@ -590,7 +594,14 @@ final class VoiceChatMainStageNode: ASDisplayNode { if let (_, endpointId) = peer { if endpointId != previousPeer?.1 { if let endpointId = endpointId { - self.setAvatarHidden(true) + var delayTransition = false + if previousPeer?.0 == peer?.0 && self.appeared { + delayTransition = true + } + + if !delayTransition { + self.setAvatarHidden(true) + } self.call.makeIncomingVideoView(endpointId: endpointId, completion: { [weak self] videoView in Queue.mainQueue().async { @@ -630,6 +641,9 @@ final class VoiceChatMainStageNode: ASDisplayNode { strongSelf.currentVideoNode = videoNode strongSelf.insertSubnode(videoNode, aboveSubnode: strongSelf.backgroundNode) + if delayTransition { + videoNode.alpha = 0.0 + } if waitForFullSize { strongSelf.videoReadyDisposable.set((videoNode.ready |> filter { $0 } @@ -643,8 +657,23 @@ final class VoiceChatMainStageNode: ASDisplayNode { strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, transition: .immediate) } } - if let previousVideoNode = previousVideoNode { - previousVideoNode.removeFromSupernode() + + if delayTransition { + if let videoNode = strongSelf.currentVideoNode { + videoNode.alpha = 1.0 + videoNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, completion: { [weak self] _ in + if let strongSelf = self { + strongSelf.setAvatarHidden(true) + if let previousVideoNode = previousVideoNode { + previousVideoNode.removeFromSupernode() + } + } + }) + } + } else { + if let previousVideoNode = previousVideoNode { + previousVideoNode.removeFromSupernode() + } } } })) @@ -664,9 +693,17 @@ final class VoiceChatMainStageNode: ASDisplayNode { }) } else { self.setAvatarHidden(false) - if let currentVideoNode = self.currentVideoNode { - currentVideoNode.removeFromSupernode() - self.currentVideoNode = nil + if self.appeared { + if let currentVideoNode = self.currentVideoNode { + currentVideoNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak currentVideoNode] _ in + currentVideoNode?.removeFromSupernode() + }) + } + } else { + if let currentVideoNode = self.currentVideoNode { + currentVideoNode.removeFromSupernode() + self.currentVideoNode = nil + } } } } else {