Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin
2020-08-07 21:09:36 +03:00
21 changed files with 3845 additions and 3778 deletions

View File

@@ -302,12 +302,16 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
private let imageNode: TransformImageNode
private let dimNode: ASImageNode
private var candidateIncomingVideoNodeValue: CallVideoNode?
private var incomingVideoNodeValue: CallVideoNode?
private var incomingVideoViewRequested: Bool = false
private var candidateOutgoingVideoNodeValue: CallVideoNode?
private var outgoingVideoNodeValue: CallVideoNode?
private var outgoingVideoViewRequested: Bool = false
private var removedMinimizedVideoNodeValue: CallVideoNode?
private var removedExpandedVideoNodeValue: CallVideoNode?
private var isRequestingVideo: Bool = false
private var animateRequestedVideoOnce: Bool = false
@@ -354,7 +358,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
var beginAudioOuputSelection: ((Bool) -> Void)?
var acceptCall: (() -> Void)?
var endCall: (() -> Void)?
var setIsVideoPaused: ((Bool) -> Void)?
var back: (() -> Void)?
var presentCallRating: ((CallId) -> Void)?
var callEnded: ((Bool) -> Void)?
@@ -447,6 +450,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
self.containerNode.addSubnode(self.statusNode)
self.containerNode.addSubnode(self.videoPausedNode)
self.containerNode.addSubnode(self.buttonsNode)
self.containerNode.addSubnode(self.toastNode)
self.containerNode.addSubnode(self.keyButtonNode)
self.containerNode.addSubnode(self.backButtonArrowNode)
self.containerNode.addSubnode(self.backButtonNode)
@@ -465,12 +469,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}
switch callState.state {
case .active, .connecting, .reconnecting:
switch callState.videoState {
case .incomingRequested:
strongSelf.call.acceptVideo()
default:
strongSelf.endCall?()
}
strongSelf.endCall?()
case .requesting:
strongSelf.endCall?()
case .ringing:
@@ -493,32 +492,20 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if strongSelf.outgoingVideoNodeValue == nil {
let proceed = {
switch callState.videoState {
case .possible:
case .inactive:
strongSelf.isRequestingVideo = true
strongSelf.updateButtonsMode()
default:
break
}
switch callState.videoState {
case .incomingRequested:
strongSelf.call.acceptVideo()
default:
strongSelf.call.requestVideo()
}
strongSelf.call.requestVideo()
}
strongSelf.present?(textAlertController(sharedContext: strongSelf.sharedContext, title: nil, text: strongSelf.presentationData.strings.Call_CameraConfirmationText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Call_CameraConfirmationConfirm, action: {
proceed()
})]))
} else {
strongSelf.isVideoPaused = !strongSelf.isVideoPaused
strongSelf.outgoingVideoNodeValue?.updateIsBlurred(isBlurred: strongSelf.isVideoPaused)
strongSelf.buttonsNode.isCameraPaused = strongSelf.isVideoPaused
strongSelf.setIsVideoPaused?(strongSelf.isVideoPaused)
if let (layout, navigationBarHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
}
strongSelf.call.disableVideo()
}
default:
break
@@ -526,9 +513,10 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}
self.buttonsNode.rotateCamera = { [weak self] in
guard let strongSelf = self else {
guard let strongSelf = self, !strongSelf.areUserActionsDisabledNow() else {
return
}
strongSelf.disableActionsUntilTimestamp = CACurrentMediaTime() + 1.0
if let outgoingVideoNode = strongSelf.outgoingVideoNodeValue, let (layout, _) = strongSelf.validLayout {
outgoingVideoNode.flip(withBackground: outgoingVideoNode.frame.width == layout.size.width)
}
@@ -543,6 +531,14 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
self.keyButtonNode.addTarget(self, action: #selector(self.keyPressed), forControlEvents: .touchUpInside)
self.backButtonNode.addTarget(self, action: #selector(self.backPressed), forControlEvents: .touchUpInside)
if !shouldStayHiddenUntilConnection && call.isVideo && call.isOutgoing {
self.containerNode.alpha = 0.0
Queue.mainQueue().after(1.0, { [weak self] in
self?.containerNode.alpha = 1.0
self?.animateIn()
})
}
}
func displayCameraTooltip() {
@@ -616,7 +612,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}
private func setupAudioOutputs() {
if self.outgoingVideoNodeValue != nil || self.candidateOutgoingVideoNodeValue != nil {
if self.outgoingVideoNodeValue != nil || self.incomingVideoNodeValue != nil || self.candidateOutgoingVideoNodeValue != nil || self.candidateIncomingVideoNodeValue != nil {
if let audioOutputState = self.audioOutputState, let currentOutput = audioOutputState.currentOutput {
switch currentOutput {
case .headphones:
@@ -636,21 +632,39 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
let statusValue: CallControllerStatusValue
var statusReception: Int32?
switch callState.videoState {
case .active, .incomingRequested(true):
switch callState.remoteVideoState {
case .active, .paused:
if !self.incomingVideoViewRequested {
self.incomingVideoViewRequested = true
let delayUntilInitialized = true
self.call.makeIncomingVideoView(completion: { [weak self] incomingVideoView in
guard let strongSelf = self else {
return
}
if let incomingVideoView = incomingVideoView {
let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, assumeReadyAfterTimeout: false, isReadyUpdated: {
guard let strongSelf = self else {
incomingVideoView.view.backgroundColor = .black
incomingVideoView.view.clipsToBounds = true
let applyNode: () -> Void = {
guard let strongSelf = self, let incomingVideoNode = strongSelf.candidateIncomingVideoNodeValue else {
return
}
if let (layout, navigationBarHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.5, curve: .spring))
strongSelf.candidateIncomingVideoNodeValue = nil
strongSelf.incomingVideoNodeValue = incomingVideoNode
if let expandedVideoNode = strongSelf.expandedVideoNode {
strongSelf.minimizedVideoNode = expandedVideoNode
}
strongSelf.expandedVideoNode = incomingVideoNode
strongSelf.containerNode.insertSubnode(incomingVideoNode, belowSubnode: strongSelf.dimNode)
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
}
let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, assumeReadyAfterTimeout: false, isReadyUpdated: {
if delayUntilInitialized {
Queue.mainQueue().after(0.1, {
applyNode()
})
}
}, orientationUpdated: {
guard let strongSelf = self else {
@@ -661,21 +675,38 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}
}, isFlippedUpdated: { _ in
})
strongSelf.incomingVideoNodeValue = incomingVideoNode
strongSelf.expandedVideoNode = incomingVideoNode
strongSelf.containerNode.insertSubnode(incomingVideoNode, belowSubnode: strongSelf.dimNode)
if let (layout, navigationBarHeight) = strongSelf.validLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.5, curve: .spring))
strongSelf.candidateIncomingVideoNodeValue = incomingVideoNode
strongSelf.setupAudioOutputs()
if !delayUntilInitialized {
applyNode()
}
}
})
}
default:
break
case .inactive:
self.candidateIncomingVideoNodeValue = nil
if let incomingVideoNodeValue = self.incomingVideoNodeValue {
if self.minimizedVideoNode == incomingVideoNodeValue {
self.minimizedVideoNode = nil
self.removedMinimizedVideoNodeValue = incomingVideoNodeValue
}
if self.expandedVideoNode == incomingVideoNodeValue {
self.expandedVideoNode = nil
self.removedExpandedVideoNodeValue = incomingVideoNodeValue
if let minimizedVideoNode = self.minimizedVideoNode {
self.expandedVideoNode = minimizedVideoNode
self.minimizedVideoNode = nil
}
}
self.incomingVideoNodeValue = nil
self.incomingVideoViewRequested = false
}
}
switch callState.videoState {
case .active, .outgoingRequested, .incomingRequested(false):
case .active, .paused:
if !self.outgoingVideoViewRequested {
self.outgoingVideoViewRequested = true
let delayUntilInitialized = self.isRequestingVideo
@@ -700,10 +731,11 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}
strongSelf.outgoingVideoNodeValue = outgoingVideoNode
strongSelf.minimizedVideoNode = outgoingVideoNode
if let expandedVideoNode = strongSelf.expandedVideoNode {
strongSelf.minimizedVideoNode = outgoingVideoNode
strongSelf.containerNode.insertSubnode(outgoingVideoNode, aboveSubnode: expandedVideoNode)
} else {
strongSelf.expandedVideoNode = outgoingVideoNode
strongSelf.containerNode.insertSubnode(outgoingVideoNode, belowSubnode: strongSelf.dimNode)
}
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
@@ -750,12 +782,28 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if !delayUntilInitialized {
applyNode()
}
strongSelf.setupAudioOutputs()
}
})
}
default:
break
case .notAvailable, .inactive:
self.candidateOutgoingVideoNodeValue = nil
if let outgoingVideoNodeValue = self.outgoingVideoNodeValue {
if self.minimizedVideoNode == outgoingVideoNodeValue {
self.minimizedVideoNode = nil
self.removedMinimizedVideoNodeValue = outgoingVideoNodeValue
}
if self.expandedVideoNode == self.outgoingVideoNodeValue {
self.expandedVideoNode = nil
self.removedExpandedVideoNodeValue = outgoingVideoNodeValue
if let minimizedVideoNode = self.minimizedVideoNode {
self.expandedVideoNode = minimizedVideoNode
self.minimizedVideoNode = nil
}
}
self.outgoingVideoNodeValue = nil
self.outgoingVideoViewRequested = false
}
}
if let incomingVideoNode = self.incomingVideoNodeValue {
@@ -765,7 +813,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
default:
let isActive: Bool
switch callState.remoteVideoState {
case .inactive:
case .inactive, .paused:
isActive = false
case .active:
isActive = true
@@ -842,25 +890,16 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
}
switch callState.videoState {
case .notAvailable, .active, .possible, .outgoingRequested:
statusValue = .timer({ value in
if isReconnecting {
return strings.Call_StatusConnecting
} else {
return value
}
}, timestamp)
statusReception = reception
case .incomingRequested:
var text: String
text = self.presentationData.strings.Call_IncomingVideoCall
if !self.statusNode.subtitle.isEmpty {
text += "\n\(self.statusNode.subtitle)"
statusValue = .timer({ value in
if isReconnecting {
return strings.Call_StatusConnecting
} else {
return value
}
statusValue = .text(string: text, displayLogo: false)
/*case .outgoingRequested:
statusValue = .text(string: self.presentationData.strings.Call_StatusRequesting, displayLogo: false)*/
}, timestamp)
if case .active = callState.state {
statusReception = reception
}
}
if self.shouldStayHiddenUntilConnection {
@@ -900,7 +939,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if self.incomingVideoViewRequested && !self.outgoingVideoViewRequested && !self.displayedCameraTooltip {
self.displayedCameraTooltip = true
Queue.mainQueue().after(1.0) {
Queue.mainQueue().after(2.0) {
self.displayCameraTooltip()
}
}
@@ -937,6 +976,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
self.dimNode.backgroundColor = color
self.dimNode.image = image
}
self.statusNode.isHidden = !visible
}
}
@@ -950,7 +990,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
var mode: CallControllerButtonsSpeakerMode = .none
var hasAudioRouteMenu: Bool = false
if let (availableOutputs, maybeCurrentOutput) = self.audioOutputState, let currentOutput = maybeCurrentOutput {
hasAudioRouteMenu = availableOutputs.count >= 2
hasAudioRouteMenu = availableOutputs.count > 2
switch currentOutput {
case .builtin:
mode = .builtin
@@ -972,29 +1012,16 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
mode = .none
}
}
let mappedVideoState: CallControllerButtonsMode.VideoState
var mappedVideoState = CallControllerButtonsMode.VideoState(isAvailable: false, isCameraActive: self.outgoingVideoNodeValue != nil, canChangeStatus: false, hasVideo: self.outgoingVideoNodeValue != nil || self.incomingVideoNodeValue != nil, isInitializingCamera: self.isRequestingVideo)
switch callState.videoState {
case .notAvailable:
mappedVideoState = .notAvailable
case .possible:
var isEnabled = false
switch callState.state {
case .active:
isEnabled = true
default:
break
}
mappedVideoState = .possible(isEnabled: isEnabled, isInitializing: false)
case .outgoingRequested:
if self.outgoingVideoNodeValue != nil {
mappedVideoState = .outgoingRequested(isInitializing: self.isRequestingVideo)
} else {
mappedVideoState = .possible(isEnabled: true, isInitializing: self.isRequestingVideo)
}
case let .incomingRequested(sendsVideo):
mappedVideoState = .incomingRequested(sendsVideo: sendsVideo)
case .active:
mappedVideoState = .active
break
case .inactive:
mappedVideoState.isAvailable = true
mappedVideoState.canChangeStatus = true
case .active, .paused:
mappedVideoState.isAvailable = true
mappedVideoState.canChangeStatus = true
}
switch callState.state {
@@ -1021,17 +1048,19 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
}
func animateIn() {
var bounds = self.bounds
bounds.origin = CGPoint()
self.bounds = bounds
self.layer.removeAnimation(forKey: "bounds")
self.statusBar.layer.removeAnimation(forKey: "opacity")
self.containerNode.layer.removeAnimation(forKey: "opacity")
self.containerNode.layer.removeAnimation(forKey: "scale")
self.statusBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
if !self.shouldStayHiddenUntilConnection {
self.containerNode.layer.animateScale(from: 1.04, to: 1.0, duration: 0.3)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
if !self.containerNode.alpha.isZero {
var bounds = self.bounds
bounds.origin = CGPoint()
self.bounds = bounds
self.layer.removeAnimation(forKey: "bounds")
self.statusBar.layer.removeAnimation(forKey: "opacity")
self.containerNode.layer.removeAnimation(forKey: "opacity")
self.containerNode.layer.removeAnimation(forKey: "scale")
self.statusBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
if !self.shouldStayHiddenUntilConnection {
self.containerNode.layer.animateScale(from: 1.04, to: 1.0, duration: 0.3)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
}
}
@@ -1063,6 +1092,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
uiDisplayTransition *= 1.0 - self.pictureInPictureTransitionFraction
let buttonsHeight: CGFloat = self.buttonsNode.bounds.height
let toastHeight: CGFloat = self.toastNode.bounds.height
var fullInsets = layout.insets(options: .statusBar)
@@ -1072,7 +1102,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
cleanInsets.right = 20.0
fullInsets.top += 44.0 + 8.0
fullInsets.bottom = buttonsHeight + 27.0
fullInsets.bottom = buttonsHeight + toastHeight + 27.0
fullInsets.left = 20.0
fullInsets.right = 20.0
@@ -1225,7 +1255,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
let videoPausedSize = self.videoPausedNode.updateLayout(CGSize(width: layout.size.width - 16.0, height: 100.0))
transition.updateFrame(node: self.videoPausedNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - videoPausedSize.width) / 2.0), y: floor((layout.size.height - videoPausedSize.height) / 2.0)), size: videoPausedSize))
transition.updateFrame(node: self.toastNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY), size: CGSize(width: layout.size.width, height: buttonsHeight)))
transition.updateFrame(node: self.toastNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY - toastHeight), size: CGSize(width: layout.size.width, height: toastHeight)))
transition.updateFrame(node: self.buttonsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY), size: CGSize(width: layout.size.width, height: buttonsHeight)))
transition.updateAlpha(node: self.buttonsNode, alpha: overlayAlpha)
@@ -1233,15 +1263,66 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
let previewVideoFrame = self.calculatePreviewVideoRect(layout: layout, navigationHeight: navigationBarHeight)
if let removedMinimizedVideoNodeValue = self.removedMinimizedVideoNodeValue {
self.removedMinimizedVideoNodeValue = nil
if transition.isAnimated {
removedMinimizedVideoNodeValue.layer.animateScale(from: 1.0, to: 0.1, duration: 0.3, removeOnCompletion: false)
removedMinimizedVideoNodeValue.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak removedMinimizedVideoNodeValue] _ in
removedMinimizedVideoNodeValue?.removeFromSupernode()
})
} else {
removedMinimizedVideoNodeValue.removeFromSupernode()
}
}
if let expandedVideoNode = self.expandedVideoNode {
var expandedVideoTransition = transition
if expandedVideoNode.frame.isEmpty || self.disableAnimationForExpandedVideoOnce {
expandedVideoTransition = .immediate
self.disableAnimationForExpandedVideoOnce = false
}
expandedVideoTransition.updateFrame(node: expandedVideoNode, frame: fullscreenVideoFrame)
if let removedExpandedVideoNodeValue = self.removedExpandedVideoNodeValue {
self.removedExpandedVideoNodeValue = nil
expandedVideoTransition.updateFrame(node: expandedVideoNode, frame: fullscreenVideoFrame, completion: { [weak removedExpandedVideoNodeValue] _ in
removedExpandedVideoNodeValue?.removeFromSupernode()
})
} else {
expandedVideoTransition.updateFrame(node: expandedVideoNode, frame: fullscreenVideoFrame)
}
expandedVideoNode.updateLayout(size: expandedVideoNode.frame.size, cornerRadius: 0.0, transition: expandedVideoTransition)
if self.animateRequestedVideoOnce {
self.animateRequestedVideoOnce = false
if expandedVideoNode === self.outgoingVideoNodeValue {
let videoButtonFrame = self.buttonsNode.videoButtonFrame().flatMap { frame -> CGRect in
return self.buttonsNode.view.convert(frame, to: self.view)
}
if let previousVideoButtonFrame = previousVideoButtonFrame, let videoButtonFrame = videoButtonFrame {
expandedVideoNode.animateRadialMask(from: previousVideoButtonFrame, to: videoButtonFrame)
}
}
}
} else {
if let removedExpandedVideoNodeValue = self.removedExpandedVideoNodeValue {
self.removedExpandedVideoNodeValue = nil
if transition.isAnimated {
removedExpandedVideoNodeValue.layer.animateScale(from: 1.0, to: 0.1, duration: 0.3, removeOnCompletion: false)
removedExpandedVideoNodeValue.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak removedExpandedVideoNodeValue] _ in
removedExpandedVideoNodeValue?.removeFromSupernode()
})
} else {
removedExpandedVideoNodeValue.removeFromSupernode()
}
}
}
if let minimizedVideoNode = self.minimizedVideoNode {
var minimizedVideoTransition = transition
var didAppear = false
@@ -1249,38 +1330,24 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
minimizedVideoTransition = .immediate
didAppear = true
}
if let expandedVideoNode = self.expandedVideoNode, expandedVideoNode.isReady {
if self.minimizedVideoDraggingPosition == nil {
if let animationForExpandedVideoSnapshotView = self.animationForExpandedVideoSnapshotView {
self.containerNode.view.addSubview(animationForExpandedVideoSnapshotView)
transition.updateAlpha(layer: animationForExpandedVideoSnapshotView.layer, alpha: 0.0, completion: { [weak animationForExpandedVideoSnapshotView] _ in
animationForExpandedVideoSnapshotView?.removeFromSuperview()
})
transition.updateTransformScale(layer: animationForExpandedVideoSnapshotView.layer, scale: previewVideoFrame.width / fullscreenVideoFrame.width)
transition.updatePosition(layer: animationForExpandedVideoSnapshotView.layer, position: CGPoint(x: previewVideoFrame.minX + previewVideoFrame.center.x / fullscreenVideoFrame.width * previewVideoFrame.width, y: previewVideoFrame.minY + previewVideoFrame.center.y / fullscreenVideoFrame.height * previewVideoFrame.height))
self.animationForExpandedVideoSnapshotView = nil
}
minimizedVideoTransition.updateFrame(node: minimizedVideoNode, frame: previewVideoFrame)
minimizedVideoNode.updateLayout(size: minimizedVideoNode.frame.size, cornerRadius: interpolate(from: 14.0, to: 24.0, value: self.pictureInPictureTransitionFraction), transition: minimizedVideoTransition)
if transition.isAnimated && didAppear {
minimizedVideoNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
}
}
} else {
minimizedVideoNode.frame = fullscreenVideoFrame
minimizedVideoNode.updateLayout(size: layout.size, cornerRadius: 0.0, transition: minimizedVideoTransition)
if self.animateRequestedVideoOnce {
self.animateRequestedVideoOnce = false
let videoButtonFrame = self.buttonsNode.videoButtonFrame().flatMap { frame -> CGRect in
return self.buttonsNode.view.convert(frame, to: self.view)
}
if self.minimizedVideoDraggingPosition == nil {
if let animationForExpandedVideoSnapshotView = self.animationForExpandedVideoSnapshotView {
self.containerNode.view.addSubview(animationForExpandedVideoSnapshotView)
transition.updateAlpha(layer: animationForExpandedVideoSnapshotView.layer, alpha: 0.0, completion: { [weak animationForExpandedVideoSnapshotView] _ in
animationForExpandedVideoSnapshotView?.removeFromSuperview()
})
transition.updateTransformScale(layer: animationForExpandedVideoSnapshotView.layer, scale: previewVideoFrame.width / fullscreenVideoFrame.width)
if let previousVideoButtonFrame = previousVideoButtonFrame, let videoButtonFrame = videoButtonFrame {
minimizedVideoNode.animateRadialMask(from: previousVideoButtonFrame, to: videoButtonFrame)
}
transition.updatePosition(layer: animationForExpandedVideoSnapshotView.layer, position: CGPoint(x: previewVideoFrame.minX + previewVideoFrame.center.x / fullscreenVideoFrame.width * previewVideoFrame.width, y: previewVideoFrame.minY + previewVideoFrame.center.y / fullscreenVideoFrame.height * previewVideoFrame.height))
self.animationForExpandedVideoSnapshotView = nil
}
minimizedVideoTransition.updateFrame(node: minimizedVideoNode, frame: previewVideoFrame)
minimizedVideoNode.updateLayout(size: previewVideoFrame.size, cornerRadius: interpolate(from: 14.0, to: 24.0, value: self.pictureInPictureTransitionFraction), transition: minimizedVideoTransition)
if transition.isAnimated && didAppear {
minimizedVideoNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
}
}
self.animationForExpandedVideoSnapshotView = nil
}