import UIKit /// Debug-only automation (`--demo-settings-flip`) that replays the user /// gesture sequence suspected of producing stale page tables: open the /// settings panel, change the line height, close the panel, flip pages — /// with several timing variants aimed at the preview-repagination and /// in-flight chapter build races. Combine with /// `--demo-pagination-validate` to detect any resulting metric mismatch. enum RDEPUBSettingsFlipAutomation { static let isEnabled = ProcessInfo.processInfo.arguments.contains("--demo-settings-flip") private(set) static var hasStarted = false static func startIfNeeded(controller: RDEPUBReaderController) { guard isEnabled, !hasStarted else { return } hasStarted = true print("[SETTINGS-FLIP] scheduled") // Pass 1 starts while progressive pagination of the freshly opened // book is still running, so prefetch builds are in flight. run(after: 2.0) { [weak controller] in guard let controller else { return } pass(controller: controller, index: 1, lineHeight: 1.8, changeToCloseDelay: 1.2) { pass(controller: controller, index: 2, lineHeight: 1.6, changeToCloseDelay: 0.05) { pass(controller: controller, index: 3, lineHeight: 1.8, changeToCloseDelay: 0.3) { print("[SETTINGS-FLIP] finished all passes") } } } } } /// One panel round-trip: present → change line height → close after /// `changeToCloseDelay` → flip pages forward and back. private static func pass( controller: RDEPUBReaderController, index: Int, lineHeight: CGFloat, changeToCloseDelay: TimeInterval, completion: @escaping () -> Void ) { print("[SETTINGS-FLIP] pass \(index) present panel") controller.presentSettings() run(after: 0.7) { [weak controller] in guard let controller else { return } print("[SETTINGS-FLIP] pass \(index) set lineHeightMultiple=\(lineHeight)") controller.updateConfiguration { $0.lineHeightMultiple = lineHeight } run(after: changeToCloseDelay) { [weak controller] in guard let controller else { return } print("[SETTINGS-FLIP] pass \(index) close panel") controller.dismiss(animated: true) { [weak controller] in controller?.runtime.settingsPanelDidDisappear() run(after: 1.0) { [weak controller] in guard let controller else { return } flipPages(controller: controller, index: index, completion: completion) } } } } } private static func flipPages( controller: RDEPUBReaderController, index: Int, completion: @escaping () -> Void ) { let startPage = controller.readerView.currentPage + 1 let offsets = [1, 2, 3, 2, 1, 0] print("[SETTINGS-FLIP] pass \(index) flip pages from \(startPage)") for (step, offset) in offsets.enumerated() { run(after: 0.6 * Double(step + 1)) { [weak controller] in _ = controller?.go(toPageNumber: startPage + offset, animated: false) } } run(after: 0.6 * Double(offsets.count + 1) + 0.5, block: completion) } private static func run(after delay: TimeInterval, block: @escaping () -> Void) { DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: block) } }