diff --git a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift index 3303f67f9f..20cb05e3d0 100644 --- a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift @@ -162,7 +162,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { private var currentCallState: PresentationCallState? private var currentGroupCallState: PresentationGroupCallSummaryState? private var currentIsMuted = true - private var currentIsConnecting = true + private var currentIsConnected = true public override init() { self.backgroundNode = CallStatusBarBackgroundNode() @@ -234,6 +234,15 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { strongSelf.currentPeer = view.peers[view.peerId] strongSelf.currentGroupCallState = state strongSelf.currentIsMuted = isMuted + + let currentIsConnected: Bool + if let state = state, case .connected = state.callState.networkState { + currentIsConnected = true + } else { + currentIsConnected = false + } + strongSelf.currentIsConnected = currentIsConnected + strongSelf.update() } })) @@ -292,7 +301,7 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { self.titleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing, y: verticalOrigin + floor((contentHeight - titleSize.height) / 2.0)), size: titleSize) self.subtitleNode.frame = CGRect(origin: CGPoint(x: horizontalOrigin + animationSize + iconSpacing + titleSize.width + spacing, y: verticalOrigin + floor((contentHeight - subtitleSize.height) / 2.0)), size: subtitleSize) - self.backgroundNode.speaking = !self.currentIsMuted + self.backgroundNode.speaking = self.currentIsConnected && !self.currentIsMuted self.backgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + 18.0)) } } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift index ff7490efdc..43d4dca681 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift @@ -338,6 +338,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskBlobView = VoiceBlobView(frame: CGRect(origin: CGPoint(x: (areaSize.width - blobSize.width) / 2.0, y: (areaSize.height - blobSize.height) / 2.0), size: blobSize), maxLevel: 2.0, mediumBlobRange: (0.69, 0.87), bigBlobRange: (0.71, 1.0)) self.maskBlobView.setColor(white) + self.maskBlobView.isHidden = true var updateInHierarchy: ((Bool) -> Void)? self.hierarchyTrackingNode = HierarchyTrackingNode({ value in @@ -450,6 +451,8 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { private func setupProgressAnimations() { if let _ = self.maskProgressLayer.animation(forKey: "progressRotation") { } else { + self.maskProgressLayer.isHidden = false + let animation = CABasicAnimation(keyPath: "transform.rotation.z") animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) animation.duration = 1.0 @@ -535,7 +538,110 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.foregroundGradientLayer.colors = targetColors self.foregroundGradientLayer.animate(from: initialColors as AnyObject, to: targetColors as AnyObject, keyPath: "colors", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.3) } + + private func playConnectionDisappearanceAnimation() { + let initialRotation: CGFloat = CGFloat((self.maskProgressLayer.value(forKeyPath: "presentationLayer.transform.rotation.z") as? NSNumber)?.floatValue ?? 0.0) + let initialStrokeEnd: CGFloat = CGFloat((self.maskProgressLayer.value(forKeyPath: "presentationLayer.strokeEnd") as? NSNumber)?.floatValue ?? 1.0) + self.maskProgressLayer.removeAnimation(forKey: "progressGrowth") + self.maskProgressLayer.removeAnimation(forKey: "progressRotation") + + let duration: Double = (1.0 - Double(initialStrokeEnd)) * 0.6 + + let growthAnimation = CABasicAnimation(keyPath: "strokeEnd") + growthAnimation.fromValue = initialStrokeEnd + growthAnimation.toValue = 0.0 + growthAnimation.duration = duration + growthAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + + let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation.z") + rotateAnimation.fromValue = initialRotation + rotateAnimation.toValue = initialRotation + CGFloat.pi * 2 + rotateAnimation.isAdditive = true + rotateAnimation.duration = duration + rotateAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + + let groupAnimation = CAAnimationGroup() + groupAnimation.animations = [growthAnimation, rotateAnimation] + groupAnimation.duration = duration + + CATransaction.setCompletionBlock { + CATransaction.begin() + CATransaction.setDisableActions(true) + self.maskProgressLayer.isHidden = true + self.maskProgressLayer.removeAllAnimations() + CATransaction.commit() + } + + self.maskProgressLayer.add(groupAnimation, forKey: "progressDisappearance") + CATransaction.commit() + } + + private func playBlobsDisappearanceAnimation() { + self.foregroundCircleLayer.isHidden = false + + self.updateGlowAndGradientAnimations(active: nil, previousActive: nil) + + self.maskBlobView.startAnimating() + self.maskBlobView.layer.animateScale(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak self] _ in + self?.maskBlobView.isHidden = true + self?.maskBlobView.stopAnimating() + self?.maskBlobView.layer.removeAllAnimations() + }) + + CATransaction.begin() + let growthAnimation = CABasicAnimation(keyPath: "transform.scale") + growthAnimation.fromValue = 0.0 + growthAnimation.toValue = 1.0 + growthAnimation.duration = 0.15 + growthAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) + + CATransaction.setCompletionBlock { + CATransaction.begin() + CATransaction.setDisableActions(true) + self.maskGradientLayer.isHidden = true + self.maskCircleLayer.isHidden = true + self.foregroundCircleLayer.isHidden = true + CATransaction.commit() + } + + self.foregroundCircleLayer.add(growthAnimation, forKey: "insideGrowth") + CATransaction.commit() + } + + private func playBlobsAppearanceAnimation(active: Bool) { + CATransaction.begin() + CATransaction.setDisableActions(true) + self.foregroundCircleLayer.isHidden = false + self.maskCircleLayer.isHidden = false + self.maskProgressLayer.isHidden = true + self.maskGradientLayer.isHidden = false + CATransaction.commit() + + self.updateGlowAndGradientAnimations(active: active, previousActive: nil) + + self.maskBlobView.isHidden = false + self.maskBlobView.startAnimating() + self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45) + + CATransaction.begin() + let shrinkAnimation = CABasicAnimation(keyPath: "transform.scale") + shrinkAnimation.fromValue = 1.0 + shrinkAnimation.toValue = 0.0 + shrinkAnimation.duration = 0.15 + shrinkAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + + CATransaction.setCompletionBlock { + CATransaction.begin() + CATransaction.setDisableActions(true) + self.foregroundCircleLayer.isHidden = true + CATransaction.commit() + } + + self.foregroundCircleLayer.add(shrinkAnimation, forKey: "insideShrink") + CATransaction.commit() + } + private func playConnectionAnimation(active: Bool, completion: @escaping () -> Void) { CATransaction.begin() let initialRotation: CGFloat = CGFloat((self.maskProgressLayer.value(forKeyPath: "presentationLayer.transform.rotation.z") as? NSNumber)?.floatValue ?? 0.0) @@ -576,6 +682,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.updateGlowAndGradientAnimations(active: active, previousActive: nil) + self.maskBlobView.isHidden = false self.maskBlobView.startAnimating() self.maskBlobView.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.45) @@ -624,21 +731,34 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { if transition == .connecting { self.playConnectionAnimation(active: newActive) { [weak self] in self?.isActive = newActive - self?.transition = nil } } else if transition == .disabled { + self.playBlobsAppearanceAnimation(active: newActive) self.transition = nil + self.isActive = newActive + self.updatedActive?(true) } else if case let .blob(previousActive) = transition { updateGlowAndGradientAnimations(active: newActive, previousActive: previousActive) self.transition = nil self.isActive = newActive } + self.transition = nil } else { self.maskBlobView.startAnimating() } case .disabled: + self.updatedActive?(true) self.isActive = false self.updateGlowScale(nil) + + if let transition = self.transition { + if case .connecting = transition { + playConnectionDisappearanceAnimation() + } else if case .blob = transition { + playBlobsDisappearanceAnimation() + } + self.transition = nil + } break } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index c988fb4c89..8d59289a3b 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -5279,12 +5279,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let peer = peer as? TelegramChannel, case .broadcast = peer.info, let contextController = contextController { - contextController?.dismiss(completion: { + contextController.dismiss(completion: { pinAction(true, false) }) } else if let peer = peer as? TelegramUser, let contextController = contextController { if peer.id == strongSelf.context.account.peerId { - contextController?.dismiss(completion: { + contextController.dismiss(completion: { pinAction(true, true) }) } else {