diff --git a/submodules/TelegramCallsUI/Sources/Components/AnimatedCounterView.swift b/submodules/TelegramCallsUI/Sources/Components/AnimatedCounterView.swift index 7074143ed9..e57fa01fb3 100644 --- a/submodules/TelegramCallsUI/Sources/Components/AnimatedCounterView.swift +++ b/submodules/TelegramCallsUI/Sources/Components/AnimatedCounterView.swift @@ -252,7 +252,7 @@ class AnimatedCountLabel: UILabel { let currentChars = chars.map { $0.attributedText ?? .init() } - let maxAnimationDuration: TimeInterval = 0.5 + let maxAnimationDuration: TimeInterval = 1.2 var numberOfChanges = abs(newChars.count - currentChars.count) for index in 0.. 0 { containerView.frame = .init(x: self.bounds.midX - countWidth / 2, y: 0, width: countWidth, height: self.bounds.height) didBegin = true } @@ -389,32 +391,49 @@ class AnimatedCountLabel: UILabel { // layer.add(animation, forKey: "opacity") // // + let beginTimeOffset: CFTimeInterval = /*beginTime == .zero ? 0 :*/ /*CFTimeInterval(DispatchTime.now().uptimeNanoseconds / 1000000000)*/ layer.convertTime(CACurrentMediaTime(), to: nil) + let opacityInAnimation = CABasicAnimation(keyPath: "opacity") opacityInAnimation.fromValue = 1 opacityInAnimation.toValue = 0 - opacityInAnimation.duration = duration - opacityInAnimation.beginTime = CACurrentMediaTime() + beginTime - layer.add(opacityInAnimation, forKey: "opacity") +// opacityInAnimation.duration = duration +// opacityInAnimation.beginTime = beginTimeOffset + beginTime +// opacityInAnimation.completion = { _ in +// layer.removeFromSuperlayer() +// } +// layer.add(opacityInAnimation, forKey: "opacity") - Timer.scheduledTimer(withTimeInterval: duration + beginTime, repeats: false) { timer in - DispatchQueue.main.async { // After(deadline: .now() + duration + beginTime) { - layer.removeFromSuperlayer() - } - } +// let timer = Timer.scheduledTimer(withTimeInterval: duration + beginTime, repeats: false) { timer in + DispatchQueue.main.asyncAfter(deadline: .now() + duration * 0.95 + beginTime) { +// DispatchQueue.main.async { +// layer.backgroundColor = UIColor.red.withAlphaComponent(0.3).cgColor +// } +// DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + layer.removeFromSuperlayer() +// } +// timer.invalidate() + } +// RunLoop.current.add(timer, forMode: .common) let scaleOutAnimation = CABasicAnimation(keyPath: "transform.scale") scaleOutAnimation.fromValue = 1 // layer.presentation()?.value(forKey: "transform.scale") ?? 1 - scaleOutAnimation.toValue = 0.1 - scaleOutAnimation.duration = duration - scaleOutAnimation.beginTime = CACurrentMediaTime() + beginTime - layer.add(scaleOutAnimation, forKey: "scaleout") + scaleOutAnimation.toValue = 0.0 +// scaleOutAnimation.duration = duration +// scaleOutAnimation.beginTime = beginTimeOffset + beginTime +// layer.add(scaleOutAnimation, forKey: "scaleout") let translate = CABasicAnimation(keyPath: "transform.translation") translate.fromValue = CGPoint.zero translate.toValue = CGPoint(x: 0, y: -layer.bounds.height * 0.3)// -layer.bounds.height + 3.0) - translate.duration = duration - translate.beginTime = CACurrentMediaTime() + beginTime - layer.add(translate, forKey: "translate") +// translate.duration = duration +// translate.beginTime = beginTimeOffset + beginTime +// layer.add(translate, forKey: "translate") + + let group = CAAnimationGroup() + group.animations = [opacityInAnimation, scaleOutAnimation, translate] + group.duration = duration + group.beginTime = beginTimeOffset + beginTime + layer.add(group, forKey: "out") } func animateIn(for newLayer: CALayer, duration: CFTimeInterval, beginTime: CFTimeInterval) { @@ -442,7 +461,7 @@ class AnimatedCountLabel: UILabel { let animation = CAKeyframeAnimation() animation.keyPath = "position.y" - animation.values = [18, -6, 0] + animation.values = [20, -6, 0] animation.keyTimes = [0, 0.64, 1] animation.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut) animation.duration = duration / 0.64 diff --git a/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift b/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift index 53769805f8..e567888e80 100644 --- a/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift +++ b/submodules/TelegramCallsUI/Sources/Components/MediaStreamComponent.swift @@ -1760,7 +1760,7 @@ public final class _MediaStreamComponentController: ViewControllerComponentConta // self.view.layer.cornerCurve = .continuous // } - self.view.layer.animatePosition(from: self.view.center, to: CGPoint(x: self.view.center.x, y: self.view.bounds.maxY + self.view.bounds.height / 2), duration: 1.3, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in + self.view.layer.animatePosition(from: self.view.center, to: CGPoint(x: self.view.center.x, y: self.view.bounds.maxY + self.view.bounds.height / 2), duration: 0.4, /*timingFunction: kCAMediaTimingFunctionSpring, */completion: { _ in }) // self.view.layer.animateScale(from: 1.0, to: 0.001, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring) // } diff --git a/submodules/TelegramCallsUI/Sources/Components/MediaStreamVideoComponent.swift b/submodules/TelegramCallsUI/Sources/Components/MediaStreamVideoComponent.swift index e3b84da552..6566f3c2e8 100644 --- a/submodules/TelegramCallsUI/Sources/Components/MediaStreamVideoComponent.swift +++ b/submodules/TelegramCallsUI/Sources/Components/MediaStreamVideoComponent.swift @@ -151,12 +151,27 @@ final class _MediaStreamVideoComponent: Component { let borderShimmer = StandaloneShimmerEffect() let shimmerOverlayLayer = CALayer() let shimmerBorderLayer = CALayer() + let placeholderView = UIImageView() func update(component: _MediaStreamVideoComponent, availableSize: CGSize, state: State, transition: Transition) -> CGSize { self.state = state + if component.videoLoading && placeholderView.superview == nil { + addSubview(placeholderView) + } + placeholderView.alpha = 0.7 +// placeholderView.image = lastFrame[component.call.peerId.id.description] + if let frame = lastFrame[component.call.peerId.id.description] { + placeholderView.addSubview(frame) + frame.frame = placeholderView.bounds + placeholderView.backgroundColor = .green + } else { + placeholderView.subviews.forEach { $0.removeFromSuperview() } + placeholderView.backgroundColor = .red + } + placeholderView.backgroundColor = .red if component.videoLoading { if loadingBlurView.superview == nil { - addSubview(loadingBlurView) +// addSubview(loadingBlurView) } if shimmerOverlayLayer.superlayer == nil { loadingBlurView.layer.addSublayer(shimmerOverlayLayer) @@ -201,6 +216,7 @@ final class _MediaStreamVideoComponent: Component { if let videoView = self.videoRenderingContext.makeView(input: input, blur: false, forceSampleBufferDisplayLayer: true) { self.videoView = videoView + self.placeholderView.removeFromSuperview() self.addSubview(videoView) videoView.alpha = 0 UIView.animate(withDuration: 0.3) { @@ -313,6 +329,12 @@ final class _MediaStreamVideoComponent: Component { } if let videoView = self.videoView { + // TODO: REMOVE FROM HERE and move to call end (or at least to background) +// if let presentation = videoView.snapshotView(afterScreenUpdates: false) { + if videoView.bounds.size.width > 0, let snapshot = videoView.snapshotView(afterScreenUpdates: false) ?? videoView.snapshotView(afterScreenUpdates: true) { + lastFrame[component.call.peerId.id.description] = snapshot// ()! + } +// } var aspect = videoView.getAspect() // saveAspect(aspect) if component.isFullscreen { @@ -379,6 +401,10 @@ final class _MediaStreamVideoComponent: Component { loadingBlurView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - videoSize.width) / 2.0), y: floor((availableSize.height - videoSize.height) / 2.0)), size: videoSize) loadingBlurView.layer.cornerRadius = 10 + placeholderView.frame = loadingBlurView.frame + placeholderView.layer.cornerRadius = 10 + placeholderView.clipsToBounds = true + shimmerOverlayLayer.frame = loadingBlurView.bounds shimmerBorderLayer.frame = loadingBlurView.bounds shimmerBorderLayer.mask?.frame = loadingBlurView.bounds @@ -478,10 +504,26 @@ final class _MediaStreamVideoComponent: Component { } func pictureInPictureControllerWillStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - self.videoView?.alpha = 0 - } - UIView.animate(withDuration: 0.3) { [self] in + // Fading to make + let presentation = self.videoView!.snapshotView(afterScreenUpdates: false)! // (self.videoView?.layer.presentation())! + self.addSubview(presentation) + presentation.frame = self.videoView!.frame +// let image = UIGraphicsImageRenderer(size: presentation.bounds.size).image { context in +// presentation.render(in: context.cgContext) +// } +// print(image) + self.videoView?.alpha = 0 +// self.videoView?.alpha = 0.5 +// presentation.animateAlpha(from: 1, to: 0, duration: 0.1, completion: { _ in presentation.removeFromSuperlayer() }) + UIView.animate(withDuration: 0.1, animations: { + presentation.alpha = 0 + }, completion: { _ in + presentation.removeFromSuperview() + }) +// DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { +// presentation.removeFromSuperlayer() +// } + UIView.animate(withDuration: 0.1) { [self] in videoBlurView?.alpha = 0 } // TODO: make safe @@ -533,3 +575,25 @@ final class _MediaStreamVideoComponent: Component { return view.update(component: self, availableSize: availableSize, state: state, transition: transition) } } + +// TODO: move to appropriate place +var lastFrame: [String: UIView] = [:] + +extension UIView { + func snapshot() -> UIImage? { + UIGraphicsBeginImageContextWithOptions(bounds.size, true, UIScreen.main.scale) + + guard let currentContext = UIGraphicsGetCurrentContext() else { + UIGraphicsEndImageContext() + return nil + } + + layer.render(in: currentContext) + + let image = UIGraphicsGetImageFromCurrentImageContext() + + UIGraphicsEndImageContext() + + return image + } +}