diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift index 4e2828b520..5da4fc7963 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatActionButton.swift @@ -217,11 +217,11 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode { transition.updateAlpha(node: self.subtitleLabel, alpha: 0.0) transition.updateAlpha(layer: self.backgroundNode.maskProgressLayer, alpha: 0.0) } else { - let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.35, curve: .easeInOut) : .immediate - transition.updateTransformScale(node: self.backgroundNode, scale: small ? 0.85 : 1.0, delay: 0.12) - transition.updateTransformScale(node: self.iconNode, scale: self.pressing ? 0.9 : 1.0, delay: 0.12) - transition.updateAlpha(node: self.titleLabel, alpha: 1.0, delay: 0.1) - transition.updateAlpha(node: self.subtitleLabel, alpha: 1.0, delay: 0.1) + let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate + transition.updateTransformScale(node: self.backgroundNode, scale: small ? 0.85 : 1.0, delay: 0.05) + transition.updateTransformScale(node: self.iconNode, scale: self.pressing ? 0.9 : 1.0, delay: 0.05) + transition.updateAlpha(node: self.titleLabel, alpha: 1.0, delay: 0.05) + transition.updateAlpha(node: self.subtitleLabel, alpha: 1.0, delay: 0.05) transition.updateAlpha(layer: self.backgroundNode.maskProgressLayer, alpha: 1.0) } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 878cac44fd..407ec95c26 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -1826,6 +1826,7 @@ public final class VoiceChatController: ViewController { } let topPanelFrame = self.topPanelNode.view.convert(self.topPanelNode.bounds, to: self.view) + let offset: CGFloat = self.contentContainer.bounds.minY self.contentContainer.layer.animateBoundsOriginYAdditive(from: self.contentContainer.bounds.origin.y, to: -(layout.size.height - topPanelFrame.minY) - 44.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in offsetCompleted = true @@ -2161,7 +2162,7 @@ public final class VoiceChatController: ViewController { self.panGestureArguments = nil var dismissing = false if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) { - self.controller?.dismiss(closing: false) + self.controller?.dismiss(closing: false, manual: true) dismissing = true } else if velocity.y < -300.0 || offset < topInset / 2.0 { self.isExpanded = true @@ -2342,8 +2343,11 @@ public final class VoiceChatController: ViewController { } } - public func dismiss(closing: Bool) { - if !closing { + private var dismissedManually: Bool = false + public func dismiss(closing: Bool, manual: Bool = false) { + if closing { + self.isDisconnected = true + } else { if let navigationController = self.navigationController as? NavigationController { let count = navigationController.viewControllers.count if count == 2 || navigationController.viewControllers[count - 2] is ChatController { @@ -2351,12 +2355,17 @@ public final class VoiceChatController: ViewController { } else if let chatController = navigationController.viewControllers[count - 2] as? ChatController, chatController.isSendButtonVisible { } else if let tabBarController = navigationController.viewControllers[count - 2] as? TabBarController, let chatListController = tabBarController.controllers[tabBarController.selectedIndex] as? ChatListController, chatListController.isSearchActive { } else { - self.detachActionButton() + if manual { + self.dismissedManually = true + Queue.mainQueue().after(0.05) { + self.detachActionButton() + } + } else { + self.detachActionButton() + } } } } - } else { - self.isDisconnected = true } self.dismiss() @@ -2367,12 +2376,13 @@ public final class VoiceChatController: ViewController { return } - let overlayController = VoiceChatOverlayController(actionButton: self.controllerNode.actionButton, audioOutputNode: self.controllerNode.audioOutputNode, leaveNode: self.controllerNode.leaveNode, navigationController: self.navigationController as? NavigationController) + let overlayController = VoiceChatOverlayController(actionButton: self.controllerNode.actionButton, audioOutputNode: self.controllerNode.audioOutputNode, leaveNode: self.controllerNode.leaveNode, navigationController: self.navigationController as? NavigationController, initiallyHidden: self.dismissedManually) if let navigationController = self.navigationController as? NavigationController { navigationController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false) } self.currentOverlayController = overlayController + self.dismissedManually = false self.reclaimActionButton = { [weak self, weak overlayController] in if let strongSelf = self { diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift index 71b75bbdb9..05446e94ea 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatOverlayController.swift @@ -204,51 +204,39 @@ public final class VoiceChatOverlayController: ViewController { completion(true) } else { self.animating = true + let sourcePoint = actionButton.position - var midPoint = CGPoint(x: (sourcePoint.x + targetPosition.x) / 2.0 - 30.0, y: (sourcePoint.y + targetPosition.y) / 2.0 + 30.0) - if sourcePoint.y < layout.size.height - 100.0 { - midPoint.x = (sourcePoint.x + targetPosition.x) / 2.0 + 30.0 - midPoint.y = (sourcePoint.y + targetPosition.y) / 2.0 + 40.0 - } - - let x1 = sourcePoint.x - let y1 = sourcePoint.y - let x2 = midPoint.x - let y2 = midPoint.y - let x3 = targetPosition.x - let y3 = targetPosition.y - - let a = (x3 * (y2 - y1) + x2 * (y1 - y3) + x1 * (y3 - y2)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let b = (x1 * x1 * (y2 - y3) + x3 * x3 * (y1 - y2) + x2 * x2 * (y3 - y1)) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - let c = (x2 * x2 * (x3 * y1 - x1 * y3) + x2 * (x1 * x1 * y3 - x3 * x3 * y1) + x1 * x3 * (x3 - x1) * y2) / ((x1 - x2) * (x1 - x3) * (x2 - x3)) - - var keyframes: [AnyObject] = [] - for i in 0 ..< 10 { - let k = CGFloat(i) / CGFloat(10 - 1) - let x = sourcePoint.x * (1.0 - k) + targetPosition.x * k - let y = a * x * x + b * x + c - keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y))) - } - + let transitionNode = ASDisplayNode() + transitionNode.position = sourcePoint + transitionNode.addSubnode(actionButton) + actionButton.position = CGPoint() + self.addSubnode(transitionNode) + if let leftButtonPosition = self.initialLeftButtonPosition, let rightButtonPosition = self.initialRightButtonPosition { let center = CGPoint(x: actionButton.frame.width / 2.0, y: actionButton.frame.height / 2.0) leftButton.isHidden = false - leftButton.layer.animatePosition(from: center, to: leftButtonPosition, duration: 0.28, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false) - rightButton.isHidden = false - rightButton.layer.animatePosition(from: center, to: rightButtonPosition, duration: 0.28, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false) - leftButton.layer.animateScale(from: 0.5, to: 1.0, duration: 0.28, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) - rightButton.layer.animateScale(from: 0.5, to: 1.0, duration: 0.28, delay: 0.05, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) + leftButton.layer.animatePosition(from: center, to: leftButtonPosition, duration: 0.26, delay: 0.07, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false) + rightButton.layer.animatePosition(from: center, to: rightButtonPosition, duration: 0.26, delay: 0.07, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, removeOnCompletion: false) + + leftButton.layer.animateScale(from: 0.55, to: 1.0, duration: 0.26, delay: 0.06, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) + rightButton.layer.animateScale(from: 0.55, to: 1.0, duration: 0.26, delay: 0.06, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) leftButton.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, delay: 0.05) rightButton.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, delay: 0.05) } actionButton.update(snap: false, animated: true) - actionButton.position = targetPosition - actionButton.layer.animateKeyframes(values: keyframes, duration: 0.5, keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, mediaTimingFunction: CAMediaTimingFunction(controlPoints: 0.5, 1.1 + Float(1.0 / 3.0), 1, 1), completion: { _ in + actionButton.position = CGPoint(x: targetPosition.x - sourcePoint.x, y: 80.0) + + let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) + transition.animateView { + transitionNode.position = CGPoint(x: transitionNode.position.x, y: targetPosition.y - 80.0) + } + + actionButton.layer.animatePosition(from: CGPoint(), to: actionButton.position, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, completion: { _ in self.animating = false completion(false) }) @@ -296,7 +284,17 @@ public final class VoiceChatOverlayController: ViewController { self.didAnimateIn = true actionButton.ignoreHierarchyChanges = true self.addSubnode(actionButton) + var hidden = false + if let initiallyHidden = self.controller?.initiallyHidden, initiallyHidden { + hidden = initiallyHidden + } + if hidden { + self.update(hidden: true, slide: true, animated: false) + } self.animateIn(from: convertedRect) + if hidden { + self.controller?.setupVisibilityUpdates() + } actionButton.ignoreHierarchyChanges = false } } @@ -315,33 +313,26 @@ public final class VoiceChatOverlayController: ViewController { private weak var parentNavigationController: NavigationController? private var currentParams: ([UIViewController], [UIViewController], VoiceChatActionButton.State)? + fileprivate var initiallyHidden: Bool - init(actionButton: VoiceChatActionButton, audioOutputNode: CallControllerButtonItemNode, leaveNode: CallControllerButtonItemNode, navigationController: NavigationController?) { + init(actionButton: VoiceChatActionButton, audioOutputNode: CallControllerButtonItemNode, leaveNode: CallControllerButtonItemNode, navigationController: NavigationController?, initiallyHidden: Bool) { self.actionButton = actionButton self.audioOutputNode = audioOutputNode self.leaveNode = leaveNode self.parentNavigationController = navigationController + self.initiallyHidden = initiallyHidden super.init(navigationBarPresentationData: nil) self.statusBar.statusBarStyle = .Ignore if case .active(.cantSpeak) = actionButton.stateValue { - } else { + } else if !initiallyHidden { self.additionalSideInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 75.0) } - if let navigationController = navigationController { - let controllers: Signal<[UIViewController], NoError> = .single([]) - |> then(navigationController.viewControllersSignal) - let overlayControllers: Signal<[UIViewController], NoError> = .single([]) - |> then(navigationController.overlayControllersSignal) - - self.disposable = (combineLatest(queue: Queue.mainQueue(), controllers, overlayControllers, actionButton.state)).start(next: { [weak self] controllers, overlayControllers, state in - if let strongSelf = self { - strongSelf.currentParams = (controllers, overlayControllers, state) - strongSelf.updateVisibility() - } - }) + + if !self.initiallyHidden { + self.setupVisibilityUpdates() } } @@ -358,6 +349,22 @@ public final class VoiceChatOverlayController: ViewController { self.displayNodeDidLoad() } + private func setupVisibilityUpdates() { + if let navigationController = self.parentNavigationController, let actionButton = self.actionButton { + let controllers: Signal<[UIViewController], NoError> = .single([]) + |> then(navigationController.viewControllersSignal) + let overlayControllers: Signal<[UIViewController], NoError> = .single([]) + |> then(navigationController.overlayControllersSignal) + + self.disposable = (combineLatest(queue: Queue.mainQueue(), controllers, overlayControllers, actionButton.state)).start(next: { [weak self] controllers, overlayControllers, state in + if let strongSelf = self { + strongSelf.currentParams = (controllers, overlayControllers, state) + strongSelf.updateVisibility() + } + }) + } + } + public override func dismiss(completion: (() -> Void)? = nil) { super.dismiss(completion: completion) self.presentingViewController?.dismiss(animated: false, completion: nil) @@ -389,6 +396,7 @@ public final class VoiceChatOverlayController: ViewController { var slide = true var hidden = true var animated = true + var animateInsets = true if controllers.count == 1 || controllers.last is ChatController { if let chatController = controllers.last as? ChatController { slide = false @@ -413,7 +421,8 @@ public final class VoiceChatOverlayController: ViewController { } if hasVoiceChatController { hidden = false - animated = false + animated = self.initiallyHidden + self.initiallyHidden = false } self.controllerNode.update(hidden: hidden, slide: slide, animated: animated)