diff --git a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift index cb4eff8305..a2f37daa0f 100644 --- a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift @@ -83,6 +83,15 @@ private class CallStatusBarBackgroundNode: ASDisplayNode { private let hierarchyTrackingNode: HierarchyTrackingNode private var isCurrentlyInHierarchy = true + + var animationsEnabled: Bool = false { + didSet { + self.updateAnimations() + if !self.animationsEnabled { + self.maskCurveView.disableCurves() + } + } + } override init() { self.foregroundView = UIView() @@ -137,42 +146,11 @@ private class CallStatusBarBackgroundNode: ASDisplayNode { CATransaction.commit() } - private func setupGradientAnimations() { - /*if let _ = self.foregroundGradientLayer.animation(forKey: "movement") { - } else { - let previousValue = self.foregroundGradientLayer.startPoint - let newValue: CGPoint - if self.maskCurveView.presentationAudioLevel > 0.1 { - newValue = CGPoint(x: CGFloat.random(in: 1.0 ..< 1.3), y: 0.5) - } else { - newValue = CGPoint(x: CGFloat.random(in: 0.85 ..< 1.2), y: 0.5) - } - self.foregroundGradientLayer.startPoint = newValue - - CATransaction.begin() - - let animation = CABasicAnimation(keyPath: "endPoint") - animation.duration = Double.random(in: 0.8 ..< 1.4) - animation.fromValue = previousValue - animation.toValue = newValue - - CATransaction.setCompletionBlock { [weak self] in - self?.setupGradientAnimations() - } - - self.foregroundGradientLayer.add(animation, forKey: "movement") - CATransaction.commit() - }*/ - } - func updateAnimations() { - if !isCurrentlyInHierarchy { + if !self.isCurrentlyInHierarchy || !self.animationsEnabled { self.foregroundGradientLayer.removeAllAnimations() self.maskCurveView.stopAnimating() - return - } - self.setupGradientAnimations() - if isCurrentlyInHierarchy { + } else { self.maskCurveView.startAnimating() } } @@ -182,6 +160,13 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { public enum Content { case call(SharedAccountContext, Account, PresentationCall) case groupCall(SharedAccountContext, Account, PresentationGroupCall) + + var sharedContext: SharedAccountContext { + switch self { + case let .call(sharedContext, _, _), let .groupCall(sharedContext, _, _): + return sharedContext + } + } } private let backgroundNode: CallStatusBarBackgroundNode @@ -252,6 +237,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { public func update(content: Content) { self.currentContent = content + self.backgroundNode.animationsEnabled = content.sharedContext.energyUsageSettings.fullTranslucency if self.isCurrentlyInHierarchy { self.update() } @@ -553,6 +539,7 @@ private final class VoiceCurveView: UIView { private let smallCurve: CurveView private let mediumCurve: CurveView private let bigCurve: CurveView + private var solidView: UIView? private let maxLevel: CGFloat @@ -604,11 +591,11 @@ private final class VoiceCurveView: UIView { super.init(frame: frame) - addSubview(bigCurve) - addSubview(mediumCurve) - addSubview(smallCurve) + self.addSubview(self.bigCurve) + self.addSubview(self.mediumCurve) + self.addSubview(self.smallCurve) - displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in + self.displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in guard let strongSelf = self else { return } strongSelf.presentationAudioLevel = strongSelf.presentationAudioLevel * 0.9 + strongSelf.audioLevel * 0.1 @@ -624,28 +611,33 @@ private final class VoiceCurveView: UIView { } public func setColor(_ color: UIColor) { - smallCurve.setColor(color.withAlphaComponent(1.0)) - mediumCurve.setColor(color.withAlphaComponent(0.55)) - bigCurve.setColor(color.withAlphaComponent(0.35)) + self.smallCurve.setColor(color.withAlphaComponent(1.0)) + self.mediumCurve.setColor(color.withAlphaComponent(0.55)) + self.bigCurve.setColor(color.withAlphaComponent(0.35)) } public func updateLevel(_ level: CGFloat) { - let normalizedLevel = min(1, max(level / maxLevel, 0)) + let normalizedLevel = min(1, max(level / self.maxLevel, 0)) - smallCurve.updateSpeedLevel(to: normalizedLevel) - mediumCurve.updateSpeedLevel(to: normalizedLevel) - bigCurve.updateSpeedLevel(to: normalizedLevel) + self.smallCurve.updateSpeedLevel(to: normalizedLevel) + self.mediumCurve.updateSpeedLevel(to: normalizedLevel) + self.bigCurve.updateSpeedLevel(to: normalizedLevel) - audioLevel = normalizedLevel + self.audioLevel = normalizedLevel } public func startAnimating() { - guard !isAnimating else { return } - isAnimating = true + guard !self.isAnimating else { return } + self.isAnimating = true - updateCurvesState() + if let solidView = self.solidView { + solidView.removeFromSuperview() + self.solidView = nil + } - displayLinkAnimator?.isPaused = false + self.updateCurvesState() + + self.displayLinkAnimator?.isPaused = false } public func stopAnimating() { @@ -653,36 +645,48 @@ private final class VoiceCurveView: UIView { } public func stopAnimating(duration: Double) { - guard isAnimating else { return } - isAnimating = false + guard self.isAnimating else { return } + self.isAnimating = false - updateCurvesState() + self.updateCurvesState() - displayLinkAnimator?.isPaused = true + self.displayLinkAnimator?.isPaused = true + } + + func disableCurves() { + self.smallCurve.isHidden = true + self.mediumCurve.isHidden = true + self.bigCurve.isHidden = true + + let view = UIView(frame: .zero) + view.backgroundColor = .white + self.addSubview(view) + self.solidView = view } private func updateCurvesState() { - if isAnimating { - if smallCurve.frame.size != .zero { - smallCurve.startAnimating() - mediumCurve.startAnimating() - bigCurve.startAnimating() + if self.isAnimating { + if self.smallCurve.frame.size != .zero { + self.smallCurve.startAnimating() + self.mediumCurve.startAnimating() + self.bigCurve.startAnimating() } } else { - smallCurve.stopAnimating() - mediumCurve.stopAnimating() - bigCurve.stopAnimating() + self.smallCurve.stopAnimating() + self.mediumCurve.stopAnimating() + self.bigCurve.stopAnimating() } } override public func layoutSubviews() { super.layoutSubviews() - smallCurve.frame = bounds - mediumCurve.frame = bounds - bigCurve.frame = bounds + self.smallCurve.frame = self.bounds + self.mediumCurve.frame = self.bounds + self.bigCurve.frame = self.bounds + self.solidView?.frame = CGRect(origin: .zero, size: CGSize(width: self.bounds.width, height: self.bounds.height - 18.0)) - updateCurvesState() + self.updateCurvesState() } } @@ -721,7 +725,6 @@ final class CurveView: UIView { return layer }() - override var frame: CGRect { didSet { if self.frame.size != oldValue.size { @@ -764,11 +767,7 @@ final class CurveView: UIView { } func updateSpeedLevel(to newSpeedLevel: CGFloat) { - speedLevel = max(speedLevel, newSpeedLevel) - -// if abs(lastSpeedLevel - newSpeedLevel) > 0.45 { -// animateToNewShape() -// } + self.speedLevel = max(self.speedLevel, newSpeedLevel) } func startAnimating() { diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift index b6b3160275..0ede7e5209 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift @@ -130,6 +130,12 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode { } } + var animationsEnabled: Bool = true { + didSet { + self.backgroundNode.animationsEnabled = self.animationsEnabled + } + } + init() { self.bottomNode = ASDisplayNode() self.bottomNode.isUserInteractionEnabled = false @@ -833,7 +839,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { } private func playMuteAnimation() { - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak self] _ in guard let strongSelf = self else { return @@ -862,7 +870,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskGradientLayer.removeAllAnimations() self.updateGlowAndGradientAnimations(type: .connecting, previousType: nil) - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak self] _ in guard let strongSelf = self else { return @@ -915,7 +925,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.updateGlowAndGradientAnimations(type: active ? .speaking : .active, previousType: nil) self.maskBlobView.isHidden = false - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45) } @@ -968,7 +980,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { if case .connecting = self.state { } else { self.maskBlobView.isHidden = false - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45) } @@ -1038,7 +1052,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskCircleLayer.animateSpring(from: previousPath as AnyObject, to: largerCirclePath as AnyObject, keyPath: "path", duration: 0.6, initialVelocity: 0.0, damping: 100.0) self.maskBlobView.isHidden = false - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.6, damping: 100.0) self.disableGlowAnimations = true @@ -1048,6 +1064,12 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { }) } + var animationsEnabled: Bool = true { + didSet { + self.updateAnimations() + } + } + var isActive = false func updateAnimations() { if !self.isCurrentlyInHierarchy { @@ -1058,7 +1080,13 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskBlobView.stopAnimating() return } - self.setupGradientAnimations() + + if !self.animationsEnabled { + self.foregroundGradientLayer.removeAllAnimations() + self.maskBlobView.stopAnimating() + } else { + self.setupGradientAnimations() + } switch self.state { case .connecting: @@ -1093,7 +1121,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { } self.transition = nil } else { - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } } case .disabled: self.updatedActive?(true) @@ -1118,7 +1148,9 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskProgressLayer.isHidden = true self.maskGradientLayer.isHidden = false self.maskBlobView.isHidden = false - self.maskBlobView.startAnimating() + if self.animationsEnabled { + self.maskBlobView.startAnimating() + } self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45) } } @@ -1287,12 +1319,12 @@ private final class VoiceBlobView: UIView { super.init(frame: frame) - addSubnode(hierarchyTrackingNode) + self.addSubnode(self.hierarchyTrackingNode) - addSubview(bigBlob) - addSubview(mediumBlob) + self.addSubview(self.bigBlob) + self.addSubview(self.mediumBlob) - displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in + self.displayLinkAnimator = ConstantDisplayLinkAnimator() { [weak self] in guard let strongSelf = self else { return } if !strongSelf.isCurrentlyInHierarchy { @@ -1317,29 +1349,29 @@ private final class VoiceBlobView: UIView { } public func setColor(_ color: UIColor) { - mediumBlob.setColor(color.withAlphaComponent(0.5)) - bigBlob.setColor(color.withAlphaComponent(0.21)) + self.mediumBlob.setColor(color.withAlphaComponent(0.5)) + self.bigBlob.setColor(color.withAlphaComponent(0.21)) } public func updateLevel(_ level: CGFloat, immediately: Bool) { let normalizedLevel = min(1, max(level / maxLevel, 0)) - mediumBlob.updateSpeedLevel(to: normalizedLevel) - bigBlob.updateSpeedLevel(to: normalizedLevel) + self.mediumBlob.updateSpeedLevel(to: normalizedLevel) + self.bigBlob.updateSpeedLevel(to: normalizedLevel) - audioLevel = normalizedLevel + self.audioLevel = normalizedLevel if immediately { - presentationAudioLevel = normalizedLevel + self.presentationAudioLevel = normalizedLevel } } public func startAnimating() { - guard !isAnimating else { return } - isAnimating = true + guard !self.isAnimating else { return } + self.isAnimating = true - updateBlobsState() + self.updateBlobsState() - displayLinkAnimator?.isPaused = false + self.displayLinkAnimator?.isPaused = false } public func stopAnimating() { @@ -1348,32 +1380,32 @@ private final class VoiceBlobView: UIView { public func stopAnimating(duration: Double) { guard isAnimating else { return } - isAnimating = false + self.isAnimating = false - updateBlobsState() + self.updateBlobsState() - displayLinkAnimator?.isPaused = true + self.displayLinkAnimator?.isPaused = true } private func updateBlobsState() { - if isAnimating { - if mediumBlob.frame.size != .zero { - mediumBlob.startAnimating() - bigBlob.startAnimating() + if self.isAnimating { + if self.mediumBlob.frame.size != .zero { + self.mediumBlob.startAnimating() + self.bigBlob.startAnimating() } } else { - mediumBlob.stopAnimating() - bigBlob.stopAnimating() + self.mediumBlob.stopAnimating() + self.bigBlob.stopAnimating() } } override public func layoutSubviews() { super.layoutSubviews() - mediumBlob.frame = bounds - bigBlob.frame = bounds + self.mediumBlob.frame = bounds + self.bigBlob.frame = bounds - updateBlobsState() + self.updateBlobsState() } } @@ -1451,10 +1483,6 @@ final class BlobView: UIView { func updateSpeedLevel(to newSpeedLevel: CGFloat) { self.speedLevel = max(self.speedLevel, newSpeedLevel) - -// if abs(lastSpeedLevel - newSpeedLevel) > 0.45 { -// animateToNewShape() -// } } func startAnimating() { @@ -1540,7 +1568,7 @@ final class BlobView: UIView { CATransaction.begin() CATransaction.setDisableActions(true) - shapeLayer.position = CGPoint(x: bounds.midX, y: bounds.midY) + self.shapeLayer.position = CGPoint(x: bounds.midX, y: bounds.midY) CATransaction.commit() } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 88a75ebdfe..11c04cf1d8 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1064,6 +1064,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController self.switchCameraButton.isUserInteractionEnabled = false self.leaveButton = CallControllerButtonItemNode() self.actionButton = VoiceChatActionButton() + self.actionButton.animationsEnabled = sharedContext.energyUsageSettings.fullTranslucency if self.isScheduling { self.cameraButton.alpha = 0.0