diff --git a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift index 9759fe6995..cfeef09cf5 100644 --- a/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift +++ b/submodules/TelegramCallsUI/Sources/CallStatusBarNode.swift @@ -236,6 +236,11 @@ public class CallStatusBarNodeImpl: CallStatusBarNode { if let strongSelf = self { strongSelf.currentPeer = view.peers[view.peerId] strongSelf.currentGroupCallState = state + + var isMuted = isMuted + if let state = state, let muteState = state.callState.muteState, !muteState.canUnmute { + isMuted = true + } strongSelf.currentIsMuted = isMuted let currentIsConnected: Bool diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift index 43ad99de0d..2b4b05fd01 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift @@ -45,18 +45,31 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode { } var activeDisposable = MetaDisposable() + var wasActiveWhenPressed = false var pressing: Bool = false { didSet { - var snap = false - if let (_, _, _, _, _, _, _, snapValue) = self.currentParams { - snap = snapValue + guard let (_, _, state, _, _, _, _, snap) = self.currentParams else { + return } if self.pressing { let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring) transition.updateTransformScale(node: self.iconNode, scale: snap ? 0.5 : 0.9) + + switch state { + case let .active(state): + switch state { + case .on: + self.wasActiveWhenPressed = true + default: + break + } + case .connecting: + break + } } else { let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring) transition.updateTransformScale(node: self.iconNode, scale: snap ? 0.5 : 1.0) + self.wasActiveWhenPressed = false } } } @@ -80,9 +93,8 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode { self.highligthedChanged = { [weak self] pressing in if let strongSelf = self { - var snap = false - if let (_, _, _, _, _, _, _, snapValue) = strongSelf.currentParams { - snap = snapValue + guard let (_, _, _, _, _, _, _, snap) = self.currentParams else { + return } if pressing { let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring) @@ -153,9 +165,22 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode { self.backgroundNode.bounds = CGRect(origin: CGPoint(), size: size) self.backgroundNode.position = CGPoint(x: size.width / 2.0, y: size.height / 2.0) + var active = false + switch state { + case let .active(state): + switch state { + case .on: + active = self.pressing && !self.wasActiveWhenPressed + default: + break + } + case .connecting: + break + } + let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate if snap { - transition.updateTransformScale(node: self.backgroundNode, scale: self.pressing ? 0.75 : 0.5) + transition.updateTransformScale(node: self.backgroundNode, scale: active ? 0.75 : 0.5) transition.updateTransformScale(node: self.iconNode, scale: 0.5) transition.updateAlpha(node: self.titleLabel, alpha: 0.0) transition.updateAlpha(node: self.subtitleLabel, alpha: 0.0) @@ -169,6 +194,8 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode { let iconSize = CGSize(width: 90.0, height: 90.0) self.iconNode.bounds = CGRect(origin: CGPoint(), size: iconSize) self.iconNode.position = CGPoint(x: size.width / 2.0, y: size.height / 2.0) + + self.wasActiveWhenPressed = false } func update(snap: Bool) { @@ -344,6 +371,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { private let backgroundCircleLayer = CAShapeLayer() private let foregroundCircleLayer = CAShapeLayer() + private let growingForegroundCircleLayer = CAShapeLayer() private let foregroundView = UIView() private let foregroundGradientLayer = CAGradientLayer() @@ -387,6 +415,11 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.foregroundCircleLayer.transform = CATransform3DMakeScale(0.0, 0.0, 1) self.foregroundCircleLayer.isHidden = true + self.growingForegroundCircleLayer.fillColor = greyColor.cgColor + self.growingForegroundCircleLayer.path = smallerCirclePath + self.growingForegroundCircleLayer.transform = CATransform3DMakeScale(1.0, 1.0, 1) + self.growingForegroundCircleLayer.isHidden = true + self.foregroundGradientLayer.type = .radial self.foregroundGradientLayer.colors = [lightBlue.cgColor, blue.cgColor] self.foregroundGradientLayer.startPoint = CGPoint(x: 1.0, y: 0.0) @@ -430,7 +463,8 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.view.addSubview(self.foregroundView) self.layer.addSublayer(self.foregroundCircleLayer) - + self.layer.addSublayer(self.growingForegroundCircleLayer) + self.foregroundView.mask = self.maskView self.foregroundView.layer.addSublayer(self.foregroundGradientLayer) @@ -529,7 +563,11 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { } } + var disableGlowAnimations = false func updateGlowScale(_ scale: CGFloat?) { + if self.disableGlowAnimations { + return + } if let scale = scale { self.maskGradientLayer.transform = CATransform3DMakeScale(0.89 + 0.11 * scale, 0.89 + 0.11 * scale, 1.0) } else { @@ -617,12 +655,19 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { CATransaction.commit() } + var animatingDisappearance = false private func playBlobsDisappearanceAnimation() { + if self.animatingDisappearance { + return + } + self.animatingDisappearance = true CATransaction.begin() CATransaction.setDisableActions(true) - self.foregroundCircleLayer.isHidden = false + self.growingForegroundCircleLayer.isHidden = false CATransaction.commit() + self.disableGlowAnimations = true + self.maskGradientLayer.removeAllAnimations() self.updateGlowAndGradientAnimations(active: nil, previousActive: nil) self.maskBlobView.startAnimating() @@ -643,14 +688,16 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { CATransaction.setCompletionBlock { CATransaction.begin() CATransaction.setDisableActions(true) + self.disableGlowAnimations = false self.maskGradientLayer.isHidden = true self.maskCircleLayer.isHidden = true - self.foregroundCircleLayer.isHidden = true - self.foregroundCircleLayer.removeAllAnimations() + self.growingForegroundCircleLayer.isHidden = true + self.growingForegroundCircleLayer.removeAllAnimations() + self.animatingDisappearance = false CATransaction.commit() } - self.foregroundCircleLayer.add(growthAnimation, forKey: "insideGrowth") + self.growingForegroundCircleLayer.add(growthAnimation, forKey: "insideGrowth") CATransaction.commit() } @@ -663,6 +710,8 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.maskGradientLayer.isHidden = false CATransaction.commit() + self.disableGlowAnimations = true + self.maskGradientLayer.removeAllAnimations() self.updateGlowAndGradientAnimations(active: active, previousActive: nil) self.maskBlobView.isHidden = false @@ -679,6 +728,7 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { CATransaction.setCompletionBlock { CATransaction.begin() CATransaction.setDisableActions(true) + self.disableGlowAnimations = false self.foregroundCircleLayer.isHidden = true CATransaction.commit() } @@ -818,8 +868,10 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { } self.backgroundCircleLayer.fillColor = targetColor self.foregroundCircleLayer.fillColor = targetColor + self.growingForegroundCircleLayer.fillColor = targetColor self.backgroundCircleLayer.animate(from: previousColor, to: targetColor, keyPath: "fillColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.3) self.foregroundCircleLayer.animate(from: previousColor, to: targetColor, keyPath: "fillColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.3) + self.growingForegroundCircleLayer.animate(from: previousColor, to: targetColor, keyPath: "fillColor", timingFunction: CAMediaTimingFunctionName.linear.rawValue, duration: 0.3) } func update(state: State, animated: Bool) { @@ -850,6 +902,8 @@ private final class VoiceChatActionButtonBackgroundNode: ASDisplayNode { self.backgroundCircleLayer.frame = circleFrame self.foregroundCircleLayer.position = center self.foregroundCircleLayer.bounds = CGRect(origin: CGPoint(), size: CGSize(width: circleFrame.width - progressLineWidth, height: circleFrame.height - progressLineWidth)) + self.growingForegroundCircleLayer.position = center + self.growingForegroundCircleLayer.bounds = self.foregroundCircleLayer.bounds self.maskCircleLayer.frame = circleFrame.insetBy(dx: -progressLineWidth / 2.0, dy: -progressLineWidth / 2.0) self.maskProgressLayer.frame = circleFrame.insetBy(dx: -3.0, dy: -3.0) self.foregroundView.frame = self.bounds diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 86fe81ef98..4f12f1dbeb 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1151,7 +1151,7 @@ public final class VoiceChatController: ViewController { private var pressTimer: SwiftSignalKit.Timer? private func startPressTimer() { self.pressTimer?.invalidate() - let pressTimer = SwiftSignalKit.Timer(timeout: 0.2, repeat: false, completion: { [weak self] in + let pressTimer = SwiftSignalKit.Timer(timeout: 0.185, repeat: false, completion: { [weak self] in self?.pressTimerFired() self?.pressTimer = nil }, queue: Queue.mainQueue()) @@ -1672,16 +1672,17 @@ public final class VoiceChatController: ViewController { self.enqueuedTransitions.remove(at: 0) var options = ListViewDeleteAndInsertOptions() - if transition.crossFade { - options.insert(.AnimateCrossfade) - } - if transition.animated { - options.insert(.AnimateInsertion) + if !isFirstTime { + if transition.crossFade { + options.insert(.AnimateCrossfade) + } + if transition.animated { + options.insert(.AnimateInsertion) + } } options.insert(.LowLatency) options.insert(.PreferSynchronousResourceLoading) - var scrollToItem: ListViewScrollToItem? if self.isFirstTime { self.isFirstTime = false diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift index b0a86ebfec..2352bfdbdf 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift @@ -14,6 +14,7 @@ import SyncCore import AppBundle import ContextUI import PresentationDataUtils +import TooltipUI public final class VoiceChatOverlayController: ViewController { private final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate { @@ -23,6 +24,10 @@ public final class VoiceChatOverlayController: ViewController { init(controller: VoiceChatOverlayController) { self.controller = controller + + super.init() + + self.clipsToBounds = true } private var isButtonHidden = false @@ -42,7 +47,7 @@ public final class VoiceChatOverlayController: ViewController { if hidden { if slide { self.isSlidOffscreen = true - transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint(x: 70.0, y: 0.0)) + transition.updateSublayerTransformOffset(layer: actionButton.layer, offset: CGPoint(x: 80.0 + 44.0, y: 0.0)) } else { actionButton.layer.removeAllAnimations() actionButton.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak actionButton] _ in @@ -104,7 +109,7 @@ public final class VoiceChatOverlayController: ViewController { if reclaim { let targetPosition = CGPoint(x: layout.size.width / 2.0, y: layout.size.height - layout.intrinsicInsets.bottom - 268.0 / 2.0) let sourcePoint = actionButton.position - let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0 - 20.0, y: sourcePoint.y + 10.0) + let midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0 - 60.0, y: sourcePoint.y + 10.0) let x1 = sourcePoint.x let y1 = sourcePoint.y @@ -127,7 +132,7 @@ public final class VoiceChatOverlayController: ViewController { actionButton.update(snap: false) actionButton.position = targetPosition - actionButton.layer.animateKeyframes(values: keyframes, duration: 0.4, keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, completion: { _ in + actionButton.layer.animateKeyframes(values: keyframes, duration: 0.34, keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, completion: { _ in completion() }) } else { @@ -192,17 +197,24 @@ public final class VoiceChatOverlayController: ViewController { self.disposable = (combineLatest(queue: Queue.mainQueue(), controllers, overlayControllers)).start(next: { [weak self] controllers, overlayControllers in if let strongSelf = self { var hasVoiceChatController = false + var overlayControllersCount = 0 for controller in controllers { if controller is VoiceChatController { hasVoiceChatController = true } } + for controller in overlayControllers { + if controller is TooltipController || controller is TooltipScreen || controller is AlertController { + } else { + overlayControllersCount += 1 + } + } var hidden = true if controllers.count == 1 || controllers.last is ChatController { hidden = false } - if overlayControllers.count > 0 { + if overlayControllersCount > 0 { hidden = true } if hasVoiceChatController { diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index df939562de..8419afeba2 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -5609,6 +5609,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G }) strongSelf.saveInterfaceState() + if let navigationController = strongSelf.navigationController as? NavigationController { + for controller in navigationController.globalOverlayControllers { + if controller is VoiceChatOverlayController { + return + } + } + } + var rect: CGRect? = strongSelf.chatDisplayNode.frameForInputPanelAccessoryButton(.silentPost(true)) if rect == nil { rect = strongSelf.chatDisplayNode.frameForInputPanelAccessoryButton(.silentPost(false)) @@ -7062,11 +7070,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let controller = voiceChatOverlayController { + var hidden = false if self.presentationInterfaceState.interfaceState.editMessage != nil || self.presentationInterfaceState.interfaceState.composeInputState.inputText.string.count > 0 { - controller.update(hidden: true, slide: false, animated: true) - } else { - controller.update(hidden: false, slide: false, animated: true) + hidden = true } + controller.update(hidden: hidden, slide: false, animated: true) } } } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 4ce5417319..96ae8425b0 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -1556,6 +1556,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { apparentNavigateButtonsFrame.origin.y += verticalOffset } + if layout.additionalInsets.right > 0.0 { + apparentNavigateButtonsFrame.origin.y -= 16.0 + } + let previousInputPanelBackgroundFrame = self.inputPanelBackgroundNode.frame transition.updateFrame(node: self.inputPanelBackgroundNode, frame: apparentInputBackgroundFrame) transition.updateFrame(node: self.inputPanelBackgroundSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: apparentInputBackgroundFrame.origin.y), size: CGSize(width: apparentInputBackgroundFrame.size.width, height: UIScreenPixel)))