ssap_app/node_modules/expo-dev-menu/ios/DevMenuWindow.swift

146 lines
3.6 KiB
Swift

// Copyright 2015-present 650 Industries. All rights reserved.
import UIKit
import React
#if os(tvOS)
protocol PresentationControllerDelegate: AnyObject {
}
#else
protocol PresentationControllerDelegate: UISheetPresentationControllerDelegate {
}
#endif
class DevMenuWindow: UIWindow, PresentationControllerDelegate {
private let manager: DevMenuManager
private let devMenuViewController: DevMenuViewController
private var isPresenting = false
private var isDismissing = false
required init(manager: DevMenuManager) {
self.manager = manager
self.devMenuViewController = DevMenuViewController(manager: manager)
super.init(frame: UIScreen.main.bounds)
self.rootViewController = UIViewController()
self.backgroundColor = UIColor(white: 0, alpha: 0.4)
#if os(tvOS)
self.windowLevel = .normal
#else
self.windowLevel = .statusBar
#endif
self.isHidden = true
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func becomeKey() {
super.becomeKey()
if !isPresenting && !isDismissing {
presentDevMenu()
}
}
private func presentDevMenu() {
guard !isPresenting && !isDismissing else {
return
}
guard let rootVC = self.rootViewController, rootVC.presentedViewController == nil else {
return
}
guard rootVC.isViewLoaded && rootVC.view.window != nil else {
return
}
isPresenting = true
#if os(tvOS)
devMenuViewController.modalPresentationStyle = .automatic
#else
devMenuViewController.modalPresentationStyle = .pageSheet
#endif
#if os(tvOS)
#else
if #available(iOS 15.0, *) {
if let sheet = devMenuViewController.sheetPresentationController {
if #available(iOS 16.0, *) {
sheet.detents = [
.custom(resolver: { context in
return context.maximumDetentValue * 0.6
}),
.large()
]
} else {
sheet.detents = [.medium(), .large()]
}
sheet.largestUndimmedDetentIdentifier = .large
sheet.prefersEdgeAttachedInCompactHeight = true
sheet.delegate = self
}
}
#endif
rootVC.present(devMenuViewController, animated: true) { [weak self] in
self?.isPresenting = false
}
}
func closeBottomSheet(_ completion: (() -> Void)? = nil) {
guard !isDismissing && !isPresenting else {
return
}
isDismissing = true
resetScrollPosition()
UIView.animate(withDuration: 0.3) {
self.backgroundColor = .clear
}
devMenuViewController.dismiss(animated: true) {
self.isDismissing = false
self.isHidden = true
self.backgroundColor = UIColor(white: 0, alpha: 0.4)
completion?()
}
}
private func resetScrollPosition() {
if let scrollView = findScrollView(in: devMenuViewController.view) {
scrollView.setContentOffset(.zero, animated: false)
}
}
private func findScrollView(in view: UIView) -> UIScrollView? {
if let scrollView = view as? UIScrollView {
return scrollView
}
for subview in view.subviews {
if let scrollView = findScrollView(in: subview) {
return scrollView
}
}
return nil
}
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let view = super.hitTest(point, with: event)
if view == self.rootViewController?.view && event?.type == .touches {
manager.hideMenu()
return self.rootViewController?.view
}
return view
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
manager.hideMenu()
}
}