diff --git a/Display/NativeWindowHostView.swift b/Display/NativeWindowHostView.swift index 445e1c498b..1be378e317 100644 --- a/Display/NativeWindowHostView.swift +++ b/Display/NativeWindowHostView.swift @@ -76,6 +76,12 @@ private class WindowRootViewController: UIViewController { self.transitionToSize?(size, coordinator.transitionDuration) } } + + override func loadView() { + self.view = UIView() + self.view.isOpaque = false + self.view.backgroundColor = nil + } } private final class NativeWindow: UIWindow, WindowHost { @@ -210,14 +216,14 @@ private final class NativeWindow: UIWindow, WindowHost { } } -public func nativeWindowHostView() -> WindowHostView { +public func nativeWindowHostView() -> (UIWindow, WindowHostView) { let window = NativeWindow(frame: UIScreen.main.bounds) let rootViewController = WindowRootViewController() window.rootViewController = rootViewController rootViewController.viewWillAppear(false) + rootViewController.view.frame = CGRect(origin: CGPoint(), size: window.bounds.size) rootViewController.viewDidAppear(false) - rootViewController.view.isHidden = true let hostView = WindowHostView(view: window, isRotating: { return window.isRotating() @@ -283,13 +289,11 @@ public func nativeWindowHostView() -> WindowHostView { } rootViewController.presentController = { [weak hostView] controller, level, animated, completion in - if let strongSelf = hostView { - strongSelf.present?(LegacyPresentedController(legacyController: controller, presentation: .custom), level) - if let completion = completion { - completion() - } + if let hostView = hostView { + hostView.present?(LegacyPresentedController(legacyController: controller, presentation: .custom), level) + completion?() } } - return hostView + return (window, hostView) } diff --git a/Display/TabBarContollerNode.swift b/Display/TabBarContollerNode.swift index f4e5d3b420..b34cf744f6 100644 --- a/Display/TabBarContollerNode.swift +++ b/Display/TabBarContollerNode.swift @@ -14,7 +14,7 @@ final class TabBarControllerNode: ASDisplayNode { } } - init(theme: TabBarControllerTheme, itemSelected: @escaping (Int) -> Void) { + init(theme: TabBarControllerTheme, itemSelected: @escaping (Int, Bool) -> Void) { self.tabBarNode = TabBarNode(theme: theme, itemSelected: itemSelected) super.init() diff --git a/Display/TabBarController.swift b/Display/TabBarController.swift index d3770e25c8..d53db8f195 100644 --- a/Display/TabBarController.swift +++ b/Display/TabBarController.swift @@ -87,7 +87,7 @@ open class TabBarController: ViewController { private var debugTapCounter: (Double, Int) = (0.0, 0) override open func loadDisplayNode() { - self.displayNode = TabBarControllerNode(theme: self.theme, itemSelected: { [weak self] index in + self.displayNode = TabBarControllerNode(theme: self.theme, itemSelected: { [weak self] index, longTap in if let strongSelf = self { if strongSelf.selectedIndex == index { let timestamp = CACurrentMediaTime() @@ -110,11 +110,16 @@ open class TabBarController: ViewController { if let validLayout = strongSelf.validLayout { strongSelf.controllers[index].containerLayoutUpdated(validLayout.addedInsets(insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 49.0, right: 0.0)), transition: .immediate) } - strongSelf.pendingControllerDisposable.set((strongSelf.controllers[index].ready.get() |> deliverOnMainQueue).start(next: { _ in + strongSelf.pendingControllerDisposable.set((strongSelf.controllers[index].ready.get() + |> deliverOnMainQueue).start(next: { _ in if let strongSelf = self { if strongSelf.selectedIndex == index { if let controller = strongSelf.currentController { - controller.scrollToTopWithTabBar?() + if longTap { + controller.longTapWithTabBar?() + } else { + controller.scrollToTopWithTabBar?() + } } } else { strongSelf.selectedIndex = index diff --git a/Display/TabBarNode.swift b/Display/TabBarNode.swift index 463ed3e057..de3fcf85aa 100644 --- a/Display/TabBarNode.swift +++ b/Display/TabBarNode.swift @@ -167,7 +167,7 @@ class TabBarNode: ASDisplayNode { } } - private let itemSelected: (Int) -> Void + private let itemSelected: (Int, Bool) -> Void private var theme: TabBarControllerTheme private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat)? @@ -178,7 +178,7 @@ class TabBarNode: ASDisplayNode { let separatorNode: ASDisplayNode private var tabBarNodeContainers: [TabBarNodeContainer] = [] - init(theme: TabBarControllerTheme, itemSelected: @escaping (Int) -> Void) { + init(theme: TabBarControllerTheme, itemSelected: @escaping (Int, Bool) -> Void) { self.itemSelected = itemSelected self.theme = theme @@ -201,9 +201,9 @@ class TabBarNode: ASDisplayNode { super.didLoad() self.view.addGestureRecognizer(TabBarTapRecognizer(tap: { [weak self] point in - if let strongSelf = self { - strongSelf.tapped(at: point) - } + self?.tapped(at: point, longTap: false) + }, longTap: { [weak self] point in + self?.tapped(at: point, longTap: true) })) } @@ -364,7 +364,7 @@ class TabBarNode: ASDisplayNode { } } - private func tapped(at location: CGPoint) { + private func tapped(at location: CGPoint, longTap: Bool) { if let bottomInset = self.validLayout?.3 { if location.y > self.bounds.size.height - bottomInset { return @@ -384,7 +384,7 @@ class TabBarNode: ASDisplayNode { } if let closestNode = closestNode { - self.itemSelected(closestNode.0) + self.itemSelected(closestNode.0, longTap) } } } diff --git a/Display/TabBarTapRecognizer.swift b/Display/TabBarTapRecognizer.swift index 4cbe02b777..616ced31e5 100644 --- a/Display/TabBarTapRecognizer.swift +++ b/Display/TabBarTapRecognizer.swift @@ -1,13 +1,17 @@ import Foundation import UIKit +import SwiftSignalKit final class TabBarTapRecognizer: UIGestureRecognizer { private let tap: (CGPoint) -> Void + private let longTap: (CGPoint) -> Void private var initialLocation: CGPoint? + private var longTapTimer: SwiftSignalKit.Timer? - init(tap: @escaping (CGPoint) -> Void) { + init(tap: @escaping (CGPoint) -> Void, longTap: @escaping (CGPoint) -> Void) { self.tap = tap + self.longTap = longTap super.init(target: nil, action: nil) } @@ -16,6 +20,8 @@ final class TabBarTapRecognizer: UIGestureRecognizer { super.reset() self.initialLocation = nil + self.longTapTimer?.invalidate() + self.longTapTimer = nil } override func touchesBegan(_ touches: Set, with event: UIEvent) { @@ -23,6 +29,19 @@ final class TabBarTapRecognizer: UIGestureRecognizer { if self.initialLocation == nil { self.initialLocation = touches.first?.location(in: self.view) + let longTapTimer = SwiftSignalKit.Timer(timeout: 0.4, repeat: false, completion: { [weak self] in + guard let strongSelf = self else { + return + } + if let initialLocation = strongSelf.initialLocation { + strongSelf.initialLocation = nil + strongSelf.longTap(initialLocation) + strongSelf.state = .ended + } + }, queue: Queue.mainQueue()) + self.longTapTimer?.invalidate() + self.longTapTimer = longTapTimer + longTapTimer.start() } } @@ -31,6 +50,8 @@ final class TabBarTapRecognizer: UIGestureRecognizer { if let initialLocation = self.initialLocation { self.initialLocation = nil + self.longTapTimer?.invalidate() + self.longTapTimer = nil self.tap(initialLocation) self.state = .ended } @@ -43,6 +64,8 @@ final class TabBarTapRecognizer: UIGestureRecognizer { let deltaX = initialLocation.x - location.x let deltaY = initialLocation.y - location.y if deltaX * deltaX + deltaY * deltaY > 4.0 { + self.longTapTimer?.invalidate() + self.longTapTimer = nil self.initialLocation = nil self.state = .failed } @@ -53,6 +76,8 @@ final class TabBarTapRecognizer: UIGestureRecognizer { super.touchesCancelled(touches, with: event) self.initialLocation = nil + self.longTapTimer?.invalidate() + self.longTapTimer = nil self.state = .failed } } diff --git a/Display/ViewController.swift b/Display/ViewController.swift index c31a241ae0..962a37eb8b 100644 --- a/Display/ViewController.swift +++ b/Display/ViewController.swift @@ -151,6 +151,7 @@ open class ViewControllerPresentationArguments { } } public var scrollToTopWithTabBar: (() -> Void)? + public var longTapWithTabBar: (() -> Void)? public var attemptNavigation: (@escaping () -> Void) -> Bool = { _ in return true