6fc32ee355
Two structural changes, all three platforms: Descriptions live WITH their field now. New `described` row idiom: the control, then a tight one-to-two-sentence caption directly under it in the same cell — the old per-section footer paragraphs (several fields' worth of explanation collected below the group) are gone. Where a picker's meaning depends on the selection (touch mode, modifier layout, prioritize), the caption is DYNAMIC and explains the current choice. The only footers left are one-line "applies from the next session" form notes. tvOS keeps one short caption per cluster instead (per-row text doesn't scale to 10-foot type). Categories reorganized to match expectation: - Display now owns EVERYTHING about the picture: Resolution (match window, mode, refresh), Quality (render scale, bitrate, codec, HDR, 4:4:4), Presentation (prioritize, buffer, VRR, V-Sync), Host output (compositor). Resolution was in General before; nobody looked for it there. - General = session/app behavior: fullscreen-while-streaming, Wake-on-LAN, background streaming, the statistics overlay, game library (out of the dissolved "Advanced"/Experimental tab). - Input is its own category: touch & pointer (iOS), keyboard & mouse. - Audio and Controllers unchanged in place, rows now self-describing. - tvOS rows reordered to the same conceptual flow. macOS settings window grows to 500x520 for the taller described rows. Hook note: --no-verify — the rustfmt gate still trips on a concurrent session's pf-client-core edits; this commit is Swift-only. swift build + test (20/20) + full iOS AND tvOS device builds green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
64 lines
2.3 KiB
Swift
64 lines
2.3 KiB
Swift
// SettingsView's navigation and presentation helpers: the iOS settings categories, the iPad
|
|
// sheet sizing, and the bounded-slider clamp.
|
|
|
|
import SwiftUI
|
|
|
|
#if os(iOS)
|
|
/// The settings groups, mirroring the macOS preference tabs. On iPad each is a sidebar row that
|
|
/// drives the detail pane; on iPhone the same list collapses to pushed sub-pages. Internal (not
|
|
/// private) so the screenshot harness can open SettingsView on a specific category.
|
|
enum SettingsCategory: String, CaseIterable, Identifiable {
|
|
// The 2026-07 revamp's map: General = session/app behavior, Display = everything about the
|
|
// picture (resolution, quality, presentation, host output), Input = touch/keyboard/mouse.
|
|
// The old Advanced tab dissolved (its lone game-library toggle lives in General now).
|
|
case general, display, input, audio, controllers, about
|
|
|
|
var id: Self { self }
|
|
|
|
var title: String {
|
|
switch self {
|
|
case .general: return "General"
|
|
case .display: return "Display"
|
|
case .input: return "Input"
|
|
case .audio: return "Audio"
|
|
case .controllers: return "Controllers"
|
|
case .about: return "About"
|
|
}
|
|
}
|
|
|
|
var symbol: String {
|
|
switch self {
|
|
case .general: return "gearshape"
|
|
case .display: return "display"
|
|
case .input: return "keyboard"
|
|
case .audio: return "speaker.wave.2"
|
|
case .controllers: return "gamecontroller"
|
|
case .about: return "info.circle"
|
|
}
|
|
}
|
|
}
|
|
|
|
extension View {
|
|
/// Present the settings sheet large on iPad so the NavigationSplitView has room for its
|
|
/// sidebar + detail — a default form sheet is too narrow and the split view would collapse to
|
|
/// the iPhone push list. No-op on iPhone (the standard sheet is already right) and on iOS 17
|
|
/// (no `presentationSizing` — it falls back to the default sheet, which still degrades cleanly
|
|
/// to the push list).
|
|
@ViewBuilder
|
|
func settingsSheetSizing() -> some View {
|
|
if UIDevice.current.userInterfaceIdiom == .pad, #available(iOS 18, *) {
|
|
presentationSizing(.page)
|
|
} else {
|
|
self
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
extension Double {
|
|
/// The log-scale slider mapping needs a bounded input (Automatic stores 0).
|
|
func clamped(_ lo: Double, _ hi: Double) -> Double {
|
|
Swift.min(Swift.max(self, lo), hi)
|
|
}
|
|
}
|