mirror of
https://github.com/yattee/yattee.git
synced 2026-05-13 10:55:03 +00:00
Make Playback and Subtitles settings feel native on macOS
Add shared SettingsFormContainer/SettingsFormSection helpers that mirror the Sources screen styling (uppercase subheadline headers, divider- bracketed cards, ScrollView + LazyVStack) on macOS while keeping the standard Form/Section layout on iOS and tvOS. Convert PlaybackSettingsView and SubtitlesSettingsView to the new helpers, wrap the macOS Settings detail pane in a NavigationStack so NavigationLink pushes (Subtitles Appearance) render in the detail column, fold the macOS-only Player Mode + Auto-resize player controls into the Behavior section, and drop the unused queue footer.
This commit is contained in:
135
Yattee/Views/Settings/MacOSSettings.swift
Normal file
135
Yattee/Views/Settings/MacOSSettings.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
//
|
||||
// MacOSSettings.swift
|
||||
// Yattee
|
||||
//
|
||||
// Shared helpers that make Settings screens feel native on macOS while
|
||||
// keeping the iOS/tvOS Form-based layout unchanged.
|
||||
//
|
||||
// The reference implementation these helpers mirror is SourcesListView.swift:
|
||||
// uppercase subheadline section headers, divider-bracketed cards (no rounded
|
||||
// background), and a ScrollView + LazyVStack container instead of Form.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
/// Root container for a macOS-native settings screen.
|
||||
///
|
||||
/// - On macOS: renders a `ScrollView` + `LazyVStack` so sections can use
|
||||
/// custom dividers and typography instead of Form's grouped cards.
|
||||
/// - On iOS/tvOS: renders a standard `Form` (unchanged from the iOS layout).
|
||||
struct SettingsFormContainer<Content: View>: View {
|
||||
@ViewBuilder let content: () -> Content
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
ScrollView {
|
||||
LazyVStack(alignment: .leading, spacing: 0) {
|
||||
content()
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
#else
|
||||
Form {
|
||||
content()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// A settings section with header and optional footer.
|
||||
///
|
||||
/// - On macOS: renders an uppercase `.subheadline` header, a top divider,
|
||||
/// content with consistent padding, a bottom divider, and an optional
|
||||
/// caption-sized footer.
|
||||
/// - On iOS/tvOS: renders a standard `Section { } header: { } footer: { }`.
|
||||
struct SettingsFormSection<Content: View>: View {
|
||||
let header: LocalizedStringKey?
|
||||
let footer: LocalizedStringKey?
|
||||
@ViewBuilder let content: () -> Content
|
||||
|
||||
init(
|
||||
_ header: LocalizedStringKey? = nil,
|
||||
footer: LocalizedStringKey? = nil,
|
||||
@ViewBuilder content: @escaping () -> Content
|
||||
) {
|
||||
self.header = header
|
||||
self.footer = footer
|
||||
self.content = content
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
macOSSection
|
||||
#else
|
||||
platformSection
|
||||
#endif
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
private var macOSSection: some View {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
if let header {
|
||||
Text(header)
|
||||
.font(.subheadline)
|
||||
.textCase(.uppercase)
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.top, 12)
|
||||
.padding(.bottom, 4)
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
content()
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 10)
|
||||
|
||||
Divider()
|
||||
|
||||
if let footer {
|
||||
Text(footer)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.top, 6)
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 12)
|
||||
}
|
||||
#else
|
||||
@ViewBuilder
|
||||
private var platformSection: some View {
|
||||
if let header, let footer {
|
||||
Section {
|
||||
content()
|
||||
} header: {
|
||||
Text(header)
|
||||
} footer: {
|
||||
Text(footer)
|
||||
}
|
||||
} else if let header {
|
||||
Section {
|
||||
content()
|
||||
} header: {
|
||||
Text(header)
|
||||
}
|
||||
} else if let footer {
|
||||
Section {
|
||||
content()
|
||||
} footer: {
|
||||
Text(footer)
|
||||
}
|
||||
} else {
|
||||
Section {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user