Video Chat Improvements

This commit is contained in:
Ilya Laktyushin 2021-05-23 16:12:43 +04:00
parent b64860e116
commit 6fc89c71a5
2 changed files with 69 additions and 17 deletions

View File

@ -747,6 +747,7 @@ public final class VoiceChatController: ViewController {
private var currentNormalButtonColor: UIColor? private var currentNormalButtonColor: UIColor?
private var currentActiveButtonColor: UIColor? private var currentActiveButtonColor: UIColor?
private var mainEntry: VoiceChatPeerEntry?
private var currentEntries: [ListEntry] = [] private var currentEntries: [ListEntry] = []
private var currentFullscreenEntries: [ListEntry] = [] private var currentFullscreenEntries: [ListEntry] = []
@ -1840,7 +1841,7 @@ public final class VoiceChatController: ViewController {
} else if strongSelf.peerIdToEndpoint.count > 0 { } else if strongSelf.peerIdToEndpoint.count > 0 {
for entry in strongSelf.currentFullscreenEntries { for entry in strongSelf.currentFullscreenEntries {
if case let .peer(peerEntry, _) = entry { if case let .peer(peerEntry, _) = entry {
if let videoEndpointId = peerEntry.effectiveVideoEndpointId { if let _ = peerEntry.effectiveVideoEndpointId {
maxLevelWithVideo = (peerEntry.peer.id, 0.0) maxLevelWithVideo = (peerEntry.peer.id, 0.0)
break break
} }
@ -4162,11 +4163,11 @@ public final class VoiceChatController: ViewController {
}) })
} }
private func updateMembers() { private func updateMembers(maybeUpdateVideo: Bool = true) {
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set()) 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<PeerId>, updatePinnedPeer: Bool = true) { private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set<PeerId>, maybeUpdateVideo: Bool = true) {
var disableAnimation = false var disableAnimation = false
if self.currentCallMembers?.1 != callMembers.1 { if self.currentCallMembers?.1 != callMembers.1 {
disableAnimation = true disableAnimation = true
@ -4193,6 +4194,7 @@ public final class VoiceChatController: ViewController {
var entryByPeerId: [PeerId: VoiceChatPeerEntry] = [:] var entryByPeerId: [PeerId: VoiceChatPeerEntry] = [:]
var latestWideVideo: String? = nil var latestWideVideo: String? = nil
var mainEntry: VoiceChatPeerEntry?
for member in callMembers.0 { for member in callMembers.0 {
if processedPeerIds.contains(member.peer.id) { if processedPeerIds.contains(member.peer.id) {
continue continue
@ -4270,7 +4272,7 @@ public final class VoiceChatController: ViewController {
isLandscape: self.isLandscape isLandscape: self.isLandscape
) )
if peerEntry.active { if peerEntry.active {
self.mainStageNode.update(peerEntry: peerEntry, pinned: self.currentForcedSpeaker != nil) mainEntry = peerEntry
} }
entryByPeerId[peerEntry.peer.id] = peerEntry entryByPeerId[peerEntry.peer.id] = peerEntry
@ -4392,6 +4394,19 @@ public final class VoiceChatController: ViewController {
return 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.updateRequestedVideoChannels()
self.endpointToPeerId = endpointIdToPeerId 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) } let effectiveMainSpeaker = self.currentForcedSpeaker ?? self.currentDominantSpeaker.flatMap { ($0.0, $0.1) }
guard effectiveMainSpeaker?.0 != self.effectiveSpeaker?.0 || effectiveMainSpeaker?.1 != self.effectiveSpeaker?.1 || force else { guard effectiveMainSpeaker?.0 != self.effectiveSpeaker?.0 || effectiveMainSpeaker?.1 != self.effectiveSpeaker?.1 || force else {
return return
} }
let currentEntries = self.currentFullscreenEntries let currentEntries = entries ?? self.currentFullscreenEntries
var effectiveSpeaker: (PeerId, String?)? = nil var effectiveSpeaker: (PeerId, String?)? = nil
var anySpeakerWithVideo: (PeerId, String?)? = nil var anySpeakerWithVideo: (PeerId, String?)? = nil
var anySpeaker: PeerId? = nil var anySpeaker: PeerId? = nil
@ -4600,7 +4615,7 @@ public final class VoiceChatController: ViewController {
self.effectiveSpeaker = effectiveSpeaker self.effectiveSpeaker = effectiveSpeaker
if updateMembers { if updateMembers {
self.updateMembers() self.updateMembers(maybeUpdateVideo: false)
} }
self.mainStageNode.update(peer: effectiveSpeaker, waitForFullSize: waitForFullSize, completion: { self.mainStageNode.update(peer: effectiveSpeaker, waitForFullSize: waitForFullSize, completion: {
completion?() completion?()

View File

@ -284,10 +284,13 @@ final class VoiceChatMainStageNode: ASDisplayNode {
} }
private var animatingIn = false private var animatingIn = false
private var animatingOut = false private var animatingOut = false
private var appeared = false
func animateTransitionIn(from sourceNode: ASDisplayNode, transition: ContainedViewLayoutTransition) { func animateTransitionIn(from sourceNode: ASDisplayNode, transition: ContainedViewLayoutTransition) {
guard let sourceNode = sourceNode as? VoiceChatTileItemNode, let _ = sourceNode.item, let (_, sideInset, bottomInset, isLandscape) = self.validLayout else { guard let sourceNode = sourceNode as? VoiceChatTileItemNode, let _ = sourceNode.item, let (_, sideInset, bottomInset, isLandscape) = self.validLayout else {
return return
} }
self.appeared = true
let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
alphaTransition.updateAlpha(node: self.backgroundNode, alpha: 1.0) alphaTransition.updateAlpha(node: self.backgroundNode, alpha: 1.0)
@ -327,6 +330,8 @@ final class VoiceChatMainStageNode: ASDisplayNode {
return return
} }
self.appeared = false
let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut) let alphaTransition = ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut)
alphaTransition.updateAlpha(node: self.backgroundNode, alpha: 0.0) alphaTransition.updateAlpha(node: self.backgroundNode, alpha: 0.0)
alphaTransition.updateAlpha(node: self.topFadeNode, alpha: 0.0) alphaTransition.updateAlpha(node: self.topFadeNode, alpha: 0.0)
@ -543,14 +548,13 @@ final class VoiceChatMainStageNode: ASDisplayNode {
self.audioLevelNode.startAnimating(immediately: true) self.audioLevelNode.startAnimating(immediately: true)
if let getAudioLevel = self.getAudioLevel, previousPeerEntry?.peer.id != peerEntry.peer.id { 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) self.audioLevelDisposable.set((getAudioLevel(peerEntry.peer.id)
|> deliverOnMainQueue).start(next: { [weak self] value in |> deliverOnMainQueue).start(next: { [weak self] value in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
strongSelf.audioLevelNode.isHidden = strongSelf.currentPeer?.1 != nil
let level = min(1.5, max(0.0, CGFloat(value))) let level = min(1.5, max(0.0, CGFloat(value)))
strongSelf.audioLevelNode.updateLevel(CGFloat(value)) strongSelf.audioLevelNode.updateLevel(CGFloat(value))
@ -590,7 +594,14 @@ final class VoiceChatMainStageNode: ASDisplayNode {
if let (_, endpointId) = peer { if let (_, endpointId) = peer {
if endpointId != previousPeer?.1 { if endpointId != previousPeer?.1 {
if let endpointId = endpointId { if let endpointId = endpointId {
var delayTransition = false
if previousPeer?.0 == peer?.0 && self.appeared {
delayTransition = true
}
if !delayTransition {
self.setAvatarHidden(true) self.setAvatarHidden(true)
}
self.call.makeIncomingVideoView(endpointId: endpointId, completion: { [weak self] videoView in self.call.makeIncomingVideoView(endpointId: endpointId, completion: { [weak self] videoView in
Queue.mainQueue().async { Queue.mainQueue().async {
@ -630,6 +641,9 @@ final class VoiceChatMainStageNode: ASDisplayNode {
strongSelf.currentVideoNode = videoNode strongSelf.currentVideoNode = videoNode
strongSelf.insertSubnode(videoNode, aboveSubnode: strongSelf.backgroundNode) strongSelf.insertSubnode(videoNode, aboveSubnode: strongSelf.backgroundNode)
if delayTransition {
videoNode.alpha = 0.0
}
if waitForFullSize { if waitForFullSize {
strongSelf.videoReadyDisposable.set((videoNode.ready strongSelf.videoReadyDisposable.set((videoNode.ready
|> filter { $0 } |> filter { $0 }
@ -643,10 +657,25 @@ final class VoiceChatMainStageNode: ASDisplayNode {
strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, transition: .immediate) strongSelf.update(size: size, sideInset: sideInset, bottomInset: bottomInset, isLandscape: isLandscape, transition: .immediate)
} }
} }
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 { if let previousVideoNode = previousVideoNode {
previousVideoNode.removeFromSupernode() previousVideoNode.removeFromSupernode()
} }
} }
})
}
} else {
if let previousVideoNode = previousVideoNode {
previousVideoNode.removeFromSupernode()
}
}
}
})) }))
} else { } else {
if let (size, sideInset, bottomInset, isLandscape) = strongSelf.validLayout { if let (size, sideInset, bottomInset, isLandscape) = strongSelf.validLayout {
@ -664,11 +693,19 @@ final class VoiceChatMainStageNode: ASDisplayNode {
}) })
} else { } else {
self.setAvatarHidden(false) self.setAvatarHidden(false)
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 { if let currentVideoNode = self.currentVideoNode {
currentVideoNode.removeFromSupernode() currentVideoNode.removeFromSupernode()
self.currentVideoNode = nil self.currentVideoNode = nil
} }
} }
}
} else { } else {
self.setAvatarHidden(endpointId != nil) self.setAvatarHidden(endpointId != nil)
completion?() completion?()