controller Navigation improvements

This commit is contained in:
True Zhuanjia
2026-08-21 22:08:41 +08:00
parent 089515443d
commit 3c36964b5c
+97 -11
View File
@@ -315,6 +315,8 @@ final class ControllerNavigator: NSObject {
static var settingsReadTipSuppressNextRelease = false
static var navigationTimer: SafeTimer?
private static let navigationInitialRepeatDelay: TimeInterval = 0.23
private static let navigationContinuousRepeatInterval: TimeInterval = 0.177
private static let controllerDrivenUIKitAnimationWakeToken = ControllerDrivenUIKitAnimationWakeToken()
@objc static weak var controllerNavigationHighlightedView: UIView?
private static let installAlertControllerNavigationHook: Void = {
@@ -520,19 +522,27 @@ final class ControllerNavigator: NSObject {
*/
private static func navigateContinuously(forward: Bool) {
navigationTimer?.clean()
navigationTimer = SafeTimer(interval: 0.23) {
uiNavigationDelegate?.navigateByController(forward: forward)
}
navigationTimer?.restart()
navigationTimer?.clean()
uiNavigationDelegate?.navigateByController(forward: forward)
navigationTimer = SafeTimer(
interval: navigationContinuousRepeatInterval,
delay: navigationInitialRepeatDelay
) {
uiNavigationDelegate?.navigateByController(forward: forward)
}
navigationTimer?.restart(minimumRunCount: 0)
}
private static func navigateContinuously(downward: Bool) {
navigationTimer?.clean()
navigationTimer = SafeTimer(interval: 0.23) {
uiNavigationDelegate?.navigateByController(downward: downward)
}
navigationTimer?.restart()
navigationTimer?.clean()
uiNavigationDelegate?.navigateByController(downward: downward)
navigationTimer = SafeTimer(
interval: navigationContinuousRepeatInterval,
delay: navigationInitialRepeatDelay
) {
uiNavigationDelegate?.navigateByController(downward: downward)
}
navigationTimer?.restart(minimumRunCount: 0)
}
@objc static func start() {
@@ -1227,6 +1237,12 @@ extension SettingsViewController: ControllerUINavigationDelegate {
highlightControllerNavigationView(target)
return
}
if let identifer = identifer,
let target = nearestSelectableControllerNavigationTarget(to: identifer, selectableTargets: selectableTargets) {
highlightControllerNavigationView(target)
return
}
highlightControllerNavigationView(selectableTargets[0])
}
@@ -1249,6 +1265,14 @@ extension SettingsViewController: ControllerUINavigationDelegate {
highlightControllerNavigationView(target)
return
}
if let highlightedView = ControllerNavigator.controllerNavigationHighlightedView,
!isControllerNavigationSectionHeader(highlightedView),
let highlightedIdentifier = controllerNavigationPersistenceIdentifier(for: highlightedView),
let target = nearestSelectableControllerNavigationTarget(to: highlightedIdentifier, selectableTargets: selectableTargets) {
highlightControllerNavigationView(target)
return
}
highlightControllerNavigationView(selectableTargets[0])
}
@@ -1269,6 +1293,31 @@ extension SettingsViewController: ControllerUINavigationDelegate {
return true
}
}
private func nearestSelectableControllerNavigationTarget(to identifier: String, selectableTargets: [UIView]) -> UIView? {
let orderedTargets = controllerNavigationTargetsIncludingUnavailable()
guard let persistedIndex = orderedTargets.firstIndex(where: {
controllerNavigationPersistenceIdentifier(for: $0) == identifier
}) else {
return nil
}
for distance in 1..<orderedTargets.count {
let forwardIndex = persistedIndex + distance
if forwardIndex < orderedTargets.count,
let target = selectableTargets.first(where: { $0 === orderedTargets[forwardIndex] }) {
return target
}
let backwardIndex = persistedIndex - distance
if backwardIndex >= 0,
let target = selectableTargets.first(where: { $0 === orderedTargets[backwardIndex] }) {
return target
}
}
return nil
}
func controllerNavigationPersistenceIdentifier(for view: UIView) -> String? {
if currentSettingsMenuMode == .FavoriteSettings || currentSettingsMenuMode == .RemoveSettingItem,
@@ -1569,6 +1618,44 @@ extension SettingsViewController: ControllerUINavigationDelegate {
return targets
}
private func controllerNavigationTargetsIncludingUnavailable() -> [UIView] {
guard let parentStack = parentStack else { return [] }
if currentSettingsMenuMode == .FavoriteSettings || currentSettingsMenuMode == .RemoveSettingItem {
return parentStack.arrangedSubviews.compactMap { $0 as? UIStackView }
}
var targets: [UIView] = []
for arrangedSubview in parentStack.arrangedSubviews {
guard let sectionView = arrangedSubview as? MenuSectionView else { continue }
if let headerView = sectionView.headerView {
targets.append(headerView)
}
guard !shouldSkipControllerNavigationSection(sectionView) else { continue }
guard let rootStackView = sectionView.rootStackView else { continue }
for arrangedRootSubview in rootStackView.arrangedSubviews {
guard let stackView = arrangedRootSubview as? UIStackView else { continue }
targets.append(contentsOf: deepestControllerNavigationStacks(from: stackView))
}
}
return targets
}
private func deepestControllerNavigationStacks(from stackView: UIStackView) -> [UIStackView] {
let childStackViews = stackView.arrangedSubviews.compactMap { $0 as? UIStackView }
guard !childStackViews.isEmpty else {
return [stackView]
}
return childStackViews.flatMap {
deepestControllerNavigationStacks(from: $0)
}
}
private func shouldSkipControllerNavigationSection(_ sectionView: MenuSectionView) -> Bool {
guard let identifier = sectionView.identifier else {
@@ -1604,7 +1691,6 @@ extension SettingsViewController: ControllerUINavigationDelegate {
if skippingDisabledStacks, hasDisabledArrangedSubview(in: stackView) {
return []
}
return [stackView]
}