import SwiftUI import UIKit struct ReaderInteractivePopEnabler: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> Controller { Controller() } func updateUIViewController(_ uiViewController: Controller, context: Context) { uiViewController.enableInteractivePopIfAvailable() } static func dismantleUIViewController(_ uiViewController: Controller, coordinator: Void) { uiViewController.restoreInteractivePopDelegate() } final class Controller: UIViewController { private weak var popGesture: UIGestureRecognizer? private var previousDelegate: (any UIGestureRecognizerDelegate)? private var releasedDelegate = false override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) enableInteractivePopIfAvailable() } func enableInteractivePopIfAvailable() { guard let navigationController, navigationController.viewControllers.count > 1, let gesture = navigationController.interactivePopGestureRecognizer else { return } if gesture.delegate != nil { previousDelegate = gesture.delegate gesture.delegate = nil releasedDelegate = true } gesture.isEnabled = true popGesture = gesture } func restoreInteractivePopDelegate() { guard releasedDelegate, let popGesture, popGesture.delegate == nil else { return } popGesture.delegate = previousDelegate previousDelegate = nil releasedDelegate = false } } } struct ReaderMenuDismissShape: Shape { var leadingExclusion: CGFloat = 24 func path(in rect: CGRect) -> Path { Path(CGRect( x: min(max(leadingExclusion, 0), rect.width), y: 0, width: max(rect.width - leadingExclusion, 0), height: rect.height )) } } @MainActor enum ReaderScreenOrientation { static private(set) var supportedOrientations: UIInterfaceOrientationMask = .allButUpsideDown static func apply(_ value: String) { let mask: UIInterfaceOrientationMask = switch value { case "1": .portrait case "2": .landscape case "3": .all case "4": .portraitUpsideDown case "5": .landscapeLeft default: .allButUpsideDown } supportedOrientations = mask guard let scene = UIApplication.shared.connectedScenes .compactMap({ $0 as? UIWindowScene }) .first(where: { $0.activationState == .foregroundActive }) else { return } if #available(iOS 16.0, *) { scene.requestGeometryUpdate(.iOS(interfaceOrientations: mask)) { _ in } scene.windows.first?.rootViewController?.setNeedsUpdateOfSupportedInterfaceOrientations() } else { UIViewController.attemptRotationToDeviceOrientation() } } static func restoreApplicationDefault() { apply("0") } }