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 settingsReadTipSuppressNextRelease = false
static var navigationTimer: SafeTimer? static var navigationTimer: SafeTimer?
private static let navigationInitialRepeatDelay: TimeInterval = 0.23
private static let navigationContinuousRepeatInterval: TimeInterval = 0.177
private static let controllerDrivenUIKitAnimationWakeToken = ControllerDrivenUIKitAnimationWakeToken() private static let controllerDrivenUIKitAnimationWakeToken = ControllerDrivenUIKitAnimationWakeToken()
@objc static weak var controllerNavigationHighlightedView: UIView? @objc static weak var controllerNavigationHighlightedView: UIView?
private static let installAlertControllerNavigationHook: Void = { private static let installAlertControllerNavigationHook: Void = {
@@ -520,19 +522,27 @@ final class ControllerNavigator: NSObject {
*/ */
private static func navigateContinuously(forward: Bool) { private static func navigateContinuously(forward: Bool) {
navigationTimer?.clean() navigationTimer?.clean()
navigationTimer = SafeTimer(interval: 0.23) { uiNavigationDelegate?.navigateByController(forward: forward)
uiNavigationDelegate?.navigateByController(forward: forward) navigationTimer = SafeTimer(
} interval: navigationContinuousRepeatInterval,
navigationTimer?.restart() delay: navigationInitialRepeatDelay
) {
uiNavigationDelegate?.navigateByController(forward: forward)
}
navigationTimer?.restart(minimumRunCount: 0)
} }
private static func navigateContinuously(downward: Bool) { private static func navigateContinuously(downward: Bool) {
navigationTimer?.clean() navigationTimer?.clean()
navigationTimer = SafeTimer(interval: 0.23) { uiNavigationDelegate?.navigateByController(downward: downward)
uiNavigationDelegate?.navigateByController(downward: downward) navigationTimer = SafeTimer(
} interval: navigationContinuousRepeatInterval,
navigationTimer?.restart() delay: navigationInitialRepeatDelay
) {
uiNavigationDelegate?.navigateByController(downward: downward)
}
navigationTimer?.restart(minimumRunCount: 0)
} }
@objc static func start() { @objc static func start() {
@@ -1227,6 +1237,12 @@ extension SettingsViewController: ControllerUINavigationDelegate {
highlightControllerNavigationView(target) highlightControllerNavigationView(target)
return return
} }
if let identifer = identifer,
let target = nearestSelectableControllerNavigationTarget(to: identifer, selectableTargets: selectableTargets) {
highlightControllerNavigationView(target)
return
}
highlightControllerNavigationView(selectableTargets[0]) highlightControllerNavigationView(selectableTargets[0])
} }
@@ -1249,6 +1265,14 @@ extension SettingsViewController: ControllerUINavigationDelegate {
highlightControllerNavigationView(target) highlightControllerNavigationView(target)
return 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]) highlightControllerNavigationView(selectableTargets[0])
} }
@@ -1269,6 +1293,31 @@ extension SettingsViewController: ControllerUINavigationDelegate {
return true 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? { func controllerNavigationPersistenceIdentifier(for view: UIView) -> String? {
if currentSettingsMenuMode == .FavoriteSettings || currentSettingsMenuMode == .RemoveSettingItem, if currentSettingsMenuMode == .FavoriteSettings || currentSettingsMenuMode == .RemoveSettingItem,
@@ -1569,6 +1618,44 @@ extension SettingsViewController: ControllerUINavigationDelegate {
return targets 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 { private func shouldSkipControllerNavigationSection(_ sectionView: MenuSectionView) -> Bool {
guard let identifier = sectionView.identifier else { guard let identifier = sectionView.identifier else {
@@ -1604,7 +1691,6 @@ extension SettingsViewController: ControllerUINavigationDelegate {
if skippingDisabledStacks, hasDisabledArrangedSubview(in: stackView) { if skippingDisabledStacks, hasDisabledArrangedSubview(in: stackView) {
return [] return []
} }
return [stackView] return [stackView]
} }