mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '693cae73f244111b4e210fcc33765d9b1f9f6c82'
This commit is contained in:
commit
3bff235303
@ -1051,14 +1051,15 @@ public extension ContainedViewLayoutTransition {
|
||||
#if os(iOS)
|
||||
|
||||
public extension ContainedViewLayoutTransition {
|
||||
func animateView(_ f: @escaping () -> Void) {
|
||||
func animateView(_ f: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) {
|
||||
switch self {
|
||||
case .immediate:
|
||||
f()
|
||||
completion?(true)
|
||||
case let .animated(duration, curve):
|
||||
UIView.animate(withDuration: duration, delay: 0.0, options: curve.viewAnimationOptions, animations: {
|
||||
f()
|
||||
}, completion: nil)
|
||||
}, completion: completion)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -500,6 +500,8 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
|
||||
var notifyGlobalOverlayControllersUpdated = false
|
||||
|
||||
var additionalSideInsets = UIEdgeInsets()
|
||||
|
||||
var modalStyleOverlayTransitionFactor: CGFloat = 0.0
|
||||
var previousGlobalOverlayContainer: NavigationOverlayContainer?
|
||||
for i in (0 ..< self.globalOverlayContainers.count).reversed() {
|
||||
@ -527,6 +529,9 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
notifyGlobalOverlayControllersUpdated = true
|
||||
}
|
||||
|
||||
let controllerAdditionalSideInsets = overlayContainer.controller.additionalSideInsets
|
||||
additionalSideInsets = UIEdgeInsets(top: 0.0, left: max(additionalSideInsets.left, controllerAdditionalSideInsets.left), bottom: 0.0, right: max(additionalSideInsets.right, controllerAdditionalSideInsets.right))
|
||||
|
||||
if overlayContainer.supernode != nil {
|
||||
previousGlobalOverlayContainer = overlayContainer
|
||||
let controllerStatusBarStyle = overlayContainer.controller.statusBar.statusBarStyle
|
||||
@ -546,7 +551,6 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
}
|
||||
|
||||
var additionalSideInsets = UIEdgeInsets()
|
||||
var previousOverlayContainer: NavigationOverlayContainer?
|
||||
for i in (0 ..< self.overlayContainers.count).reversed() {
|
||||
let overlayContainer = self.overlayContainers[i]
|
||||
|
@ -47,15 +47,13 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
||||
|
||||
var pressing: Bool = false {
|
||||
didSet {
|
||||
var pressing = self.pressing
|
||||
var snap = false
|
||||
if let (_, _, _, _, _, _, _, snapValue) = self.currentParams, snapValue {
|
||||
pressing = false
|
||||
snap = true
|
||||
if let (_, _, _, _, _, _, _, snapValue) = self.currentParams {
|
||||
snap = snapValue
|
||||
}
|
||||
if pressing {
|
||||
if self.pressing {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring)
|
||||
transition.updateTransformScale(node: self.iconNode, scale: 0.9)
|
||||
transition.updateTransformScale(node: self.iconNode, scale: snap ? 0.5 : 0.9)
|
||||
} else {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring)
|
||||
transition.updateTransformScale(node: self.iconNode, scale: snap ? 0.5 : 1.0)
|
||||
@ -80,18 +78,15 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
||||
self.containerNode.addSubnode(self.backgroundNode)
|
||||
self.containerNode.addSubnode(self.iconNode)
|
||||
|
||||
self.highligthedChanged = { [weak self] highlighted in
|
||||
self.highligthedChanged = { [weak self] pressing in
|
||||
if let strongSelf = self {
|
||||
var highlighted = highlighted
|
||||
var snap = false
|
||||
if let (_, _, _, _, _, _, _, snapValue) = strongSelf.currentParams, snapValue {
|
||||
highlighted = false
|
||||
snap = true
|
||||
if let (_, _, _, _, _, _, _, snapValue) = strongSelf.currentParams {
|
||||
snap = snapValue
|
||||
}
|
||||
|
||||
if highlighted {
|
||||
if pressing {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring)
|
||||
transition.updateTransformScale(node: strongSelf.iconNode, scale: 0.9)
|
||||
transition.updateTransformScale(node: strongSelf.iconNode, scale: snap ? 0.5 : 0.9)
|
||||
} else if !strongSelf.pressing {
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring)
|
||||
transition.updateTransformScale(node: strongSelf.iconNode, scale: snap ? 0.5 : 1.0)
|
||||
@ -173,7 +168,7 @@ final class VoiceChatActionButton: HighlightTrackingButtonNode {
|
||||
|
||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
||||
if snap {
|
||||
transition.updateTransformScale(node: self.backgroundNode, scale: active ? 0.75 : 0.5)
|
||||
transition.updateTransformScale(node: self.backgroundNode, scale: self.pressing ? 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)
|
||||
@ -909,8 +904,8 @@ private final class VoiceBlobView: UIView {
|
||||
pointsCount: 8,
|
||||
minRandomness: 1,
|
||||
maxRandomness: 1,
|
||||
minSpeed: 0.85,
|
||||
maxSpeed: 7,
|
||||
minSpeed: 0.9,
|
||||
maxSpeed: 4.0,
|
||||
minScale: mediumBlobRange.min,
|
||||
maxScale: mediumBlobRange.max
|
||||
)
|
||||
@ -918,8 +913,8 @@ private final class VoiceBlobView: UIView {
|
||||
pointsCount: 8,
|
||||
minRandomness: 1,
|
||||
maxRandomness: 1,
|
||||
minSpeed: 0.85,
|
||||
maxSpeed: 7,
|
||||
minSpeed: 1.0,
|
||||
maxSpeed: 4.4,
|
||||
minScale: bigBlobRange.min,
|
||||
maxScale: bigBlobRange.max
|
||||
)
|
||||
|
@ -460,6 +460,7 @@ public final class VoiceChatController: ViewController {
|
||||
self.dimNode.backgroundColor = dimColor
|
||||
|
||||
self.contentContainer = ASDisplayNode()
|
||||
self.contentContainer.isHidden = true
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.backgroundColor = secondaryPanelBackgroundColor
|
||||
@ -1600,7 +1601,7 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
|
||||
func animateIn() {
|
||||
guard let (layout, _) = self.validLayout else {
|
||||
guard let (layout, navigationHeight) = self.validLayout else {
|
||||
return
|
||||
}
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||
@ -1609,13 +1610,23 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
let initialBounds = self.contentContainer.bounds
|
||||
self.contentContainer.bounds = initialBounds.offsetBy(dx: 0.0, dy: -(layout.size.height - topPanelFrame.minY))
|
||||
transition.animateView {
|
||||
self.contentContainer.isHidden = false
|
||||
transition.animateView({
|
||||
self.contentContainer.view.bounds = initialBounds
|
||||
}
|
||||
}, completion: { _ in
|
||||
self.bottomPanelNode.addSubnode(self.actionButton)
|
||||
self.containerLayoutUpdated(layout, navigationHeight:navigationHeight, transition: .immediate)
|
||||
|
||||
self.controller?.currentOverlayController?.dismiss()
|
||||
self.controller?.currentOverlayController = nil
|
||||
})
|
||||
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
|
||||
func animateOut(completion: (() -> Void)?) {
|
||||
guard let (layout, _) = self.validLayout else {
|
||||
return
|
||||
}
|
||||
var offsetCompleted = false
|
||||
let internalCompletion: () -> Void = { [weak self] in
|
||||
if offsetCompleted {
|
||||
@ -1631,7 +1642,9 @@ public final class VoiceChatController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
self.contentContainer.layer.animateBoundsOriginYAdditive(from: self.contentContainer.bounds.origin.y, to: -self.contentContainer.bounds.size.height, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
||||
let topPanelFrame = self.topPanelNode.view.convert(self.topPanelNode.bounds, to: self.view)
|
||||
|
||||
self.contentContainer.layer.animateBoundsOriginYAdditive(from: self.contentContainer.bounds.origin.y, to: -(layout.size.height - topPanelFrame.minY), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
||||
offsetCompleted = true
|
||||
internalCompletion()
|
||||
})
|
||||
@ -1862,6 +1875,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private var didAppearOnce: Bool = false
|
||||
private var isDismissed: Bool = false
|
||||
private var isDisconnected: Bool = false
|
||||
|
||||
private var controllerNode: Node {
|
||||
return self.displayNode as! Node
|
||||
@ -1869,7 +1883,7 @@ public final class VoiceChatController: ViewController {
|
||||
|
||||
private let idleTimerExtensionDisposable = MetaDisposable()
|
||||
|
||||
private var currentOverlayController: VoiceChatOverlayController?
|
||||
private weak var currentOverlayController: VoiceChatOverlayController?
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
@ -1943,39 +1957,41 @@ public final class VoiceChatController: ViewController {
|
||||
self.idleTimerExtensionDisposable.set(nil)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.didAppearOnce = false
|
||||
self.isDismissed = true
|
||||
self.detachActionButton()
|
||||
self.onViewDidDisappear?()
|
||||
}
|
||||
}
|
||||
|
||||
public func dismiss(closing: Bool) {
|
||||
if closing {
|
||||
self.dismiss()
|
||||
if !closing {
|
||||
self.detachActionButton()
|
||||
} else {
|
||||
let overlayController = VoiceChatOverlayController(actionButton: self.controllerNode.actionButton)
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
navigationController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false)
|
||||
self.isDisconnected = true
|
||||
}
|
||||
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
private func detachActionButton() {
|
||||
guard self.currentOverlayController == nil && !self.isDisconnected else {
|
||||
return
|
||||
}
|
||||
|
||||
let overlayController = VoiceChatOverlayController(actionButton: self.controllerNode.actionButton)
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
navigationController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false)
|
||||
}
|
||||
|
||||
self.currentOverlayController = overlayController
|
||||
|
||||
self.reclaimActionButton = { [weak self, weak overlayController] in
|
||||
if let strongSelf = self {
|
||||
let actionButton = strongSelf.controllerNode.actionButton
|
||||
overlayController?.animateOut(reclaim: true, completion: {})
|
||||
strongSelf.reclaimActionButton = nil
|
||||
}
|
||||
self.sharedContext.presentGlobalController(overlayController, nil)
|
||||
|
||||
self.currentOverlayController = overlayController
|
||||
|
||||
self.reclaimActionButton = { [weak self, weak overlayController] in
|
||||
if let strongSelf = self {
|
||||
let actionButton = strongSelf.controllerNode.actionButton
|
||||
overlayController?.animateOut(reclaim: true, completion: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.controllerNode.bottomPanelNode.addSubnode(actionButton)
|
||||
if let validLayout = strongSelf.validLayout {
|
||||
strongSelf.containerLayoutUpdated(validLayout, transition: .immediate)
|
||||
}
|
||||
}
|
||||
})
|
||||
strongSelf.currentOverlayController = nil
|
||||
strongSelf.reclaimActionButton = nil
|
||||
}
|
||||
}
|
||||
|
||||
self.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ import AppBundle
|
||||
import ContextUI
|
||||
import PresentationDataUtils
|
||||
|
||||
final class VoiceChatOverlayController: ViewController {
|
||||
public final class VoiceChatOverlayController: ViewController {
|
||||
private final class Node: ViewControllerTracingNode, UIGestureRecognizerDelegate {
|
||||
private weak var controller: VoiceChatOverlayController?
|
||||
|
||||
@ -24,6 +24,41 @@ final class VoiceChatOverlayController: ViewController {
|
||||
init(controller: VoiceChatOverlayController) {
|
||||
self.controller = controller
|
||||
}
|
||||
|
||||
private var isButtonHidden = false
|
||||
func update(hidden: Bool, slide: Bool, animated: Bool) {
|
||||
guard let actionButton = self.controller?.actionButton, actionButton.supernode === self else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.isButtonHidden == hidden {
|
||||
return
|
||||
}
|
||||
self.isButtonHidden = hidden
|
||||
|
||||
if animated {
|
||||
if hidden {
|
||||
if slide {
|
||||
|
||||
} 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
|
||||
actionButton?.isHidden = true
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if slide {
|
||||
|
||||
} else {
|
||||
actionButton.layer.removeAllAnimations()
|
||||
actionButton.isHidden = false
|
||||
actionButton.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func animateIn(from: CGRect) {
|
||||
guard let actionButton = self.controller?.actionButton else {
|
||||
@ -53,7 +88,7 @@ final class VoiceChatOverlayController: ViewController {
|
||||
keyframes.append(NSValue(cgPoint: CGPoint(x: x, y: y)))
|
||||
}
|
||||
|
||||
actionButton.layer.animateKeyframes(values: keyframes, duration: 0.3, keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, completion: { [weak self] _ in
|
||||
actionButton.layer.animateKeyframes(values: keyframes, duration: 0.2, keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, completion: { _ in
|
||||
})
|
||||
}
|
||||
|
||||
@ -88,9 +123,8 @@ 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: { [weak self] _ in
|
||||
actionButton.layer.animateKeyframes(values: keyframes, duration: 0.4, keyPath: "position", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, completion: { _ in
|
||||
completion()
|
||||
self?.controller?.dismiss()
|
||||
})
|
||||
} else {
|
||||
actionButton.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak self, weak actionButton] _ in
|
||||
@ -101,11 +135,14 @@ final class VoiceChatOverlayController: ViewController {
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let actionButton = self.controller?.actionButton, actionButton.supernode === self, actionButton.frame.contains(point) {
|
||||
return actionButton.hitTest(self.view.convert(point, to: actionButton.view), with: event)
|
||||
} else {
|
||||
return nil
|
||||
if let actionButton = self.controller?.actionButton, actionButton.supernode === self {
|
||||
let actionButtonSize = CGSize(width: 84.0, height: 84.0)
|
||||
let actionButtonFrame = CGRect(origin: CGPoint(x: actionButton.position.x - actionButtonSize.width / 2.0, y: actionButton.position.y - actionButtonSize.height / 2.0), size: actionButtonSize)
|
||||
if actionButtonFrame.contains(point) {
|
||||
return actionButton.hitTest(self.view.convert(point, to: actionButton.view), with: event)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
@ -141,6 +178,10 @@ final class VoiceChatOverlayController: ViewController {
|
||||
self.additionalSideInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 75.0)
|
||||
}
|
||||
|
||||
deinit {
|
||||
print("")
|
||||
}
|
||||
|
||||
required init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
@ -150,7 +191,7 @@ final class VoiceChatOverlayController: ViewController {
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
override func dismiss(completion: (() -> Void)? = nil) {
|
||||
public override func dismiss(completion: (() -> Void)? = nil) {
|
||||
super.dismiss(completion: completion)
|
||||
self.presentingViewController?.dismiss(animated: false, completion: nil)
|
||||
completion?()
|
||||
@ -160,6 +201,10 @@ final class VoiceChatOverlayController: ViewController {
|
||||
self.controllerNode.animateOut(reclaim: reclaim, completion: completion)
|
||||
}
|
||||
|
||||
public func update(hidden: Bool, slide: Bool, animated: Bool) {
|
||||
self.controllerNode.update(hidden: hidden, slide: slide, animated: animated)
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
|
@ -666,8 +666,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}, sendMessagesWithSignals: { [weak self] signals, _, _ in
|
||||
if let strongSelf = self {
|
||||
strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in })
|
||||
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
||||
if canEditMessage(context: strongSelf.context, limitsConfiguration: strongSelf.context.currentLimitsConfiguration.with { $0 }, message: message) {
|
||||
strongSelf.interfaceInteraction?.setupEditMessage(messageId, { _ in })
|
||||
strongSelf.editMessageMediaWithLegacySignals(signals!)
|
||||
} else {
|
||||
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: false)
|
||||
}
|
||||
}
|
||||
}, present: { [weak self] c, a in
|
||||
self?.present(c, in: .window(.root), with: a)
|
||||
@ -7052,6 +7056,24 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if saveInterfaceState {
|
||||
self.saveInterfaceState(includeScrollState: false)
|
||||
}
|
||||
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
var voiceChatOverlayController: VoiceChatOverlayController?
|
||||
for controller in navigationController.globalOverlayControllers {
|
||||
if let controller = controller as? VoiceChatOverlayController {
|
||||
voiceChatOverlayController = controller
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if let controller = voiceChatOverlayController {
|
||||
if self.presentationInterfaceState.inputMode == .text && 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateItemNodesSelectionStates(animated: Bool) {
|
||||
|
@ -634,7 +634,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
|> deliverOnMainQueue).start(next: { [weak self] call in
|
||||
if let strongSelf = self {
|
||||
if call !== strongSelf.groupCallController?.call {
|
||||
strongSelf.groupCallController?.dismiss()
|
||||
strongSelf.groupCallController?.dismiss(closing: true)
|
||||
strongSelf.groupCallController = nil
|
||||
strongSelf.hasOngoingCall.set(false)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user