Video Chat Improvements

This commit is contained in:
Ilya Laktyushin
2021-05-29 14:35:12 +04:00
parent 21632c6dc0
commit 29df2fd229
6 changed files with 136 additions and 52 deletions

View File

@@ -87,6 +87,8 @@ func decorationTopCornersImage(dark: Bool) -> UIImage? {
})?.stretchableImage(withLeftCapWidth: 25, topCapHeight: 32)
}
func decorationBottomCornersImage(dark: Bool) -> UIImage? {
return generateImage(CGSize(width: 50.0, height: 110.0), rotatedContext: { (size, context) in
let bounds = CGRect(origin: CGPoint(), size: size)
@@ -414,7 +416,7 @@ public final class VoiceChatController: ViewController {
}
}
func tileItem(context: AccountContext, presentationData: PresentationData, interaction: Interaction, videoEndpointId: String, videoReady: Bool) -> VoiceChatTileItem? {
func tileItem(context: AccountContext, presentationData: PresentationData, interaction: Interaction, videoEndpointId: String, videoReady: Bool, showAsPresentation: Bool) -> VoiceChatTileItem? {
guard case let .peer(peerEntry, _) = self else {
return nil
}
@@ -485,7 +487,7 @@ public final class VoiceChatController: ViewController {
text = .text(about, textIcon, .generic)
}
return VoiceChatTileItem(account: context.account, peer: peerEntry.peer, videoEndpointId: videoEndpointId, videoReady: videoReady, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, speaking: speaking, icon: icon, text: text, additionalText: additionalText, action: {
return VoiceChatTileItem(account: context.account, peer: peerEntry.peer, videoEndpointId: videoEndpointId, videoReady: videoReady, strings: presentationData.strings, nameDisplayOrder: presentationData.nameDisplayOrder, speaking: speaking, icon: showAsPresentation ? .presentation : icon, text: text, additionalText: additionalText, action: {
interaction.switchToPeer(peer.id, videoEndpointId, true)
}, contextAction: { node, gesture in
interaction.peerContextAction(peerEntry, node, gesture)
@@ -786,6 +788,7 @@ public final class VoiceChatController: ViewController {
private var animatingExpansion = false
private var animatingAppearance = false
private var animatingButtonsSwap = false
private var animatingMainStage = false
private var panGestureArguments: (topInset: CGFloat, offset: CGFloat)?
private var isPanning = false
@@ -865,8 +868,7 @@ public final class VoiceChatController: ViewController {
private var timeoutedEndpointIds = Set<String>()
private var readyVideoDisposables = DisposableDict<String>()
private var endpointToPeerId: [String: PeerId] = [:]
private var peerIdToEndpoint: [PeerId: String] = [:]
private var peerIdToEndpointId: [PeerId: String] = [:]
private var currentSpeakers: [PeerId] = []
private var currentDominantSpeaker: (PeerId, String?, Double)?
@@ -1114,7 +1116,7 @@ public final class VoiceChatController: ViewController {
}, switchToPeer: { [weak self] peerId, videoEndpointId, expand in
if let strongSelf = self {
if expand, let videoEndpointId = videoEndpointId {
strongSelf.currentDominantSpeaker = (peerId, videoEndpointId, CACurrentMediaTime())
strongSelf.currentDominantSpeaker = (peerId, videoEndpointId, CACurrentMediaTime() + 3.0)
strongSelf.updateDisplayMode(.fullscreen(controlsHidden: false))
} else {
strongSelf.currentForcedSpeaker = nil
@@ -1883,7 +1885,7 @@ public final class VoiceChatController: ViewController {
var maxLevelWithVideo: (PeerId, Float)?
for (peerId, source, level, hasSpeech) in levels {
let hasVideo = strongSelf.peerIdToEndpoint[peerId] != nil
let hasVideo = strongSelf.peerIdToEndpointId[peerId] != nil
if hasSpeech && source != 0 && hasVideo {
if let (_, currentLevel) = maxLevelWithVideo {
if currentLevel < level {
@@ -1898,7 +1900,7 @@ public final class VoiceChatController: ViewController {
if maxLevelWithVideo == nil {
if let (peerId, _, _) = strongSelf.currentDominantSpeaker {
maxLevelWithVideo = (peerId, 0.0)
} else if strongSelf.peerIdToEndpoint.count > 0 {
} else if strongSelf.peerIdToEndpointId.count > 0 {
for entry in strongSelf.currentFullscreenEntries {
if case let .peer(peerEntry, _) = entry {
if let _ = peerEntry.effectiveVideoEndpointId {
@@ -2111,7 +2113,7 @@ public final class VoiceChatController: ViewController {
}
self.mainStageNode.back = { [weak self] in
if let strongSelf = self {
if let strongSelf = self, !strongSelf.isPanning && !strongSelf.animatingExpansion && !strongSelf.mainStageNode.animating {
strongSelf.currentForcedSpeaker = nil
strongSelf.updateDisplayMode(.modal(isExpanded: true, isFilled: true), fromPan: true)
strongSelf.effectiveSpeaker = nil
@@ -3489,7 +3491,7 @@ public final class VoiceChatController: ViewController {
let listMaxY = listTopInset + listSize.height
let bottomOffset = min(0.0, bottomEdge - listMaxY) + layout.size.height - bottomPanelHeight
let bottomCornersFrame = CGRect(origin: CGPoint(x: sideInset + floorToScreenPixels((size.width - contentWidth) / 2.0), y: -50.0 + bottomOffset + bottomGradientHeight), size: CGSize(width: contentWidth - sideInset * 2.0, height: 50.0 + 40.0))
let bottomCornersFrame = CGRect(origin: CGPoint(x: sideInset + floorToScreenPixels((size.width - contentWidth) / 2.0), y: -50.0 + bottomOffset + bottomGradientHeight), size: CGSize(width: contentWidth - sideInset * 2.0, height: 50.0 + 60.0))
let previousBottomCornersFrame = self.bottomCornersNode.frame
if !bottomCornersFrame.equalTo(previousBottomCornersFrame) {
self.bottomCornersNode.frame = bottomCornersFrame
@@ -4362,11 +4364,11 @@ public final class VoiceChatController: ViewController {
})
}
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(maybeUpdateVideo: Bool = true, force: Bool = false) {
self.updateMembers(muteState: self.effectiveMuteState, callMembers: self.currentCallMembers ?? ([], nil), invitedPeers: self.currentInvitedPeers ?? [], speakingPeers: self.currentSpeakingPeers ?? Set(), maybeUpdateVideo: maybeUpdateVideo, force: force)
}
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set<PeerId>, maybeUpdateVideo: Bool = true) {
private func updateMembers(muteState: GroupCallParticipantsContext.Participant.MuteState?, callMembers: ([GroupCallParticipantsContext.Participant], String?), invitedPeers: [Peer], speakingPeers: Set<PeerId>, maybeUpdateVideo: Bool = true, force: Bool = false) {
var disableAnimation = false
if self.currentCallMembers?.1 != callMembers.1 {
disableAnimation = true
@@ -4384,7 +4386,7 @@ public final class VoiceChatController: ViewController {
var processedPeerIds = Set<PeerId>()
var processedFullscreenPeerIds = Set<PeerId>()
var endpointIdToPeerId: [String: PeerId] = [:]
var peerIdToCameraEndpointId: [PeerId: String] = [:]
var peerIdToEndpointId: [PeerId: String] = [:]
var requestedVideoChannels: [PresentationGroupCallRequestedVideo] = []
@@ -4446,10 +4448,7 @@ public final class VoiceChatController: ViewController {
}
if let videoEndpointId = member.videoEndpointId {
endpointIdToPeerId[videoEndpointId] = member.peer.id
}
if let presentationEndpointId = member.presentationEndpointId {
endpointIdToPeerId[presentationEndpointId] = member.peer.id
peerIdToCameraEndpointId[member.peer.id] = videoEndpointId
}
if let anyEndpointId = member.presentationEndpointId ?? member.videoEndpointId {
peerIdToEndpointId[member.peer.id] = anyEndpointId
@@ -4485,7 +4484,7 @@ public final class VoiceChatController: ViewController {
self.videoOrder.append(videoEndpointId)
}
}
if let tileItem = ListEntry.peer(peerEntry, 0).tileItem(context: self.context, presentationData: self.presentationData, interaction: interaction, videoEndpointId: videoEndpointId, videoReady: self.readyVideoEndpointIds.contains(videoEndpointId)) {
if let tileItem = ListEntry.peer(peerEntry, 0).tileItem(context: self.context, presentationData: self.presentationData, interaction: interaction, videoEndpointId: videoEndpointId, videoReady: self.readyVideoEndpointIds.contains(videoEndpointId), showAsPresentation: peerIdToCameraEndpointId[peerEntry.peer.id] != nil) {
isTile = true
tileByVideoEndpoint[videoEndpointId] = tileItem
}
@@ -4501,7 +4500,7 @@ public final class VoiceChatController: ViewController {
self.videoOrder.append(videoEndpointId)
}
}
if let tileItem = ListEntry.peer(peerEntry, 0).tileItem(context: self.context, presentationData: self.presentationData, interaction: interaction, videoEndpointId: videoEndpointId, videoReady: self.readyVideoEndpointIds.contains(videoEndpointId)) {
if let tileItem = ListEntry.peer(peerEntry, 0).tileItem(context: self.context, presentationData: self.presentationData, interaction: interaction, videoEndpointId: videoEndpointId, videoReady: self.readyVideoEndpointIds.contains(videoEndpointId), showAsPresentation: false) {
isTile = true
tileByVideoEndpoint[videoEndpointId] = tileItem
}
@@ -4597,7 +4596,7 @@ public final class VoiceChatController: ViewController {
self.requestedVideoChannels = requestedVideoChannels
guard self.didSetDataReady && !self.isPanning && !self.animatingExpansion else {
guard self.didSetDataReady && (force || (!self.isPanning && !self.animatingExpansion && !self.animatingMainStage)) else {
return
}
@@ -4619,8 +4618,7 @@ public final class VoiceChatController: ViewController {
self.updateRequestedVideoChannels()
self.endpointToPeerId = endpointIdToPeerId
self.peerIdToEndpoint = peerIdToEndpointId
self.peerIdToEndpointId = peerIdToEndpointId
if !tileItems.isEmpty {
entries.insert(.tiles(tileItems), at: 0)
@@ -4835,7 +4833,7 @@ public final class VoiceChatController: ViewController {
self.effectiveSpeaker = effectiveSpeaker
if updateMembers {
self.updateMembers(maybeUpdateVideo: false)
self.updateMembers(maybeUpdateVideo: false, force: force)
}
self.mainStageNode.update(peer: effectiveSpeaker, waitForFullSize: waitForFullSize, completion: {
completion?()
@@ -5010,6 +5008,7 @@ public final class VoiceChatController: ViewController {
self.panGestureArguments = nil
self.fullscreenListContainer.subnodeTransform = CATransform3DIdentity
if abs(translation.y) > 100.0 || abs(velocity.y) > 300.0 {
self.mainStageBackgroundNode.layer.removeAllAnimations()
self.currentForcedSpeaker = nil
self.updateDisplayMode(.modal(isExpanded: true, isFilled: true), fromPan: true)
self.effectiveSpeaker = nil
@@ -5551,7 +5550,7 @@ public final class VoiceChatController: ViewController {
}
private func updateDisplayMode(_ displayMode: DisplayMode, fromPan: Bool = false) {
guard !self.animatingExpansion && !self.mainStageNode.animating else {
guard !self.animatingExpansion && !self.animatingMainStage && !self.mainStageNode.animating else {
return
}
self.updateMembers()
@@ -5562,6 +5561,11 @@ public final class VoiceChatController: ViewController {
isFullscreen = true
}
if case .fullscreen = previousDisplayMode, case .fullscreen = displayMode {
} else {
self.animatingMainStage = true
}
let completion = {
self.displayMode = displayMode
self.updateDecorationsColors()
@@ -5585,8 +5589,6 @@ public final class VoiceChatController: ViewController {
}
}
self.animatingExpansion = true
let completion = {
let effectiveSpeakerPeerId = self.effectiveSpeaker?.0
@@ -5606,7 +5608,9 @@ public final class VoiceChatController: ViewController {
let transitionStartPosition = otherItemNode.view.convert(CGPoint(x: otherItemNode.frame.width / 2.0, y: otherItemNode.frame.height), to: self.fullscreenListContainer.view.superview)
self.fullscreenListContainer.layer.animatePosition(from: transitionStartPosition, to: self.fullscreenListContainer.position, duration: 0.55, timingFunction: kCAMediaTimingFunctionSpring)
self.mainStageNode.animateTransitionIn(from: otherItemNode, transition: transition)
self.mainStageNode.animateTransitionIn(from: otherItemNode, transition: transition, completion: { [weak self] in
self?.animatingMainStage = false
})
self.mainStageNode.alpha = 1.0
self.mainStageBackgroundNode.alpha = 1.0
@@ -5669,9 +5673,7 @@ public final class VoiceChatController: ViewController {
fullscreenItemNodes[String(item.peer.id.toInt64()) + "_" + (item.videoEndpointId ?? "")] = itemNode
}
}
self.animatingExpansion = true
let completion = {
let effectiveSpeakerPeerId = self.effectiveSpeaker?.0
var targetTileNode: VoiceChatTileItemNode?
@@ -5727,6 +5729,7 @@ public final class VoiceChatController: ViewController {
strongSelf.contentContainer.insertSubnode(strongSelf.mainStageContainerNode, belowSubnode: strongSelf.transitionContainerNode)
strongSelf.isPanning = false
strongSelf.animatingMainStage = false
})
self.listContainer.layer.animateScale(from: 0.86, to: 1.0, duration: 0.55, timingFunction: kCAMediaTimingFunctionSpring)
@@ -5757,8 +5760,6 @@ public final class VoiceChatController: ViewController {
completion()
}
} else if case .fullscreen = self.displayMode {
self.animatingExpansion = true
if let (layout, navigationHeight) = self.validLayout {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
self.containerLayoutUpdated(layout, navigationHeight: navigationHeight, transition: transition)