- Rename source module from RDReaderView to RDEpubReaderView - Move all source files from Sources/RDReaderView/ to Sources/RDEpubReaderView/ - Update podspec: RDReaderView.podspec -> RDEpubReaderView.podspec - Update Podfile, demo project, and CocoaPods config for new pod name - Delete old RDReaderView pod support files from ReadViewDemo/Pods - Add new RDEpubReaderView pod support files - Update documentation (API ref, architecture, UML, conventions, etc.) - Add FixedLayoutRotationTests - Update .gitignore: exclude .DS_Store, manual unpack backups, _ssoft-output
68 lines
2.6 KiB
Swift
68 lines
2.6 KiB
Swift
import UIKit
|
|
|
|
/// Device-level safe area lookup modeled after GKNavigationBarSwift.
|
|
/// Reads the real safe area from the key window so correct values are
|
|
/// available even before a view has been laid out in the hierarchy.
|
|
/// Must be called on the main thread.
|
|
public enum RDEPUBSafeArea {
|
|
|
|
/// Minimum text margins applied when the device safe area on an edge is
|
|
/// smaller (e.g. no notch / no home indicator). These are aesthetic
|
|
/// paddings, not approximations of the safe area itself.
|
|
public static let minimumVerticalTextMargin: CGFloat = 20
|
|
|
|
public static let minimumHorizontalTextMargin: CGFloat = 16
|
|
|
|
public static func keyWindow() -> UIWindow? {
|
|
let scenes = UIApplication.shared.connectedScenes
|
|
.compactMap { $0 as? UIWindowScene }
|
|
if let window = scenes
|
|
.filter({ $0.activationState == .foregroundActive })
|
|
.flatMap({ $0.windows })
|
|
.first(where: { $0.isKeyWindow }) {
|
|
return window
|
|
}
|
|
if let window = scenes
|
|
.flatMap({ $0.windows })
|
|
.first(where: { $0.isKeyWindow }) {
|
|
return window
|
|
}
|
|
return UIApplication.shared.delegate?.window ?? nil
|
|
}
|
|
|
|
public static func insets() -> UIEdgeInsets {
|
|
if let window = keyWindow() {
|
|
return window.safeAreaInsets
|
|
}
|
|
// No key window yet (early launch): create a detached window to read
|
|
// the device safe area, same fallback as GKNavigationBarSwift.
|
|
let window = UIWindow(frame: UIScreen.main.bounds)
|
|
if window.safeAreaInsets.bottom <= 0 {
|
|
window.rootViewController = UIViewController()
|
|
}
|
|
return window.safeAreaInsets
|
|
}
|
|
|
|
/// Prefers insets measured from a view already installed in the hierarchy;
|
|
/// falls back to the key-window insets when the view is not laid out yet
|
|
/// and reports .zero.
|
|
public static func resolve(_ measuredInsets: UIEdgeInsets?) -> UIEdgeInsets {
|
|
if let measuredInsets, measuredInsets != .zero {
|
|
return measuredInsets
|
|
}
|
|
return insets()
|
|
}
|
|
|
|
/// Default reflowable content insets derived from the live device safe
|
|
/// area instead of hard-coded heights.
|
|
public static func defaultReflowableContentInsets() -> UIEdgeInsets {
|
|
let safe = insets()
|
|
return UIEdgeInsets(
|
|
top: max(safe.top, minimumVerticalTextMargin),
|
|
left: max(safe.left, minimumHorizontalTextMargin),
|
|
bottom: max(safe.bottom, minimumVerticalTextMargin),
|
|
right: max(safe.right, minimumHorizontalTextMargin)
|
|
)
|
|
}
|
|
}
|