mirror of
https://github.com/yattee/yattee.git
synced 2026-05-13 10:55:03 +00:00
Use menu-style pickers in tvOS settings
Introduce PlatformMenuPicker that wraps short-option pickers in LabeledContent + .pickerStyle(.menu) on tvOS so they render as a compact dropdown instead of pushing a full-screen option list. On iOS/macOS it falls through to a plain Picker, leaving rendering unchanged. Applied across Playback, Subtitles, Sidebar, Privacy, and Advanced settings. Long language lists in PlaybackSettingsView are left as push-style.
This commit is contained in:
@@ -99,7 +99,7 @@ struct AdvancedSettingsView: View {
|
||||
@ViewBuilder
|
||||
private func feedSection(settingsManager: SettingsManager) -> some View {
|
||||
Section {
|
||||
Picker(selection: Binding(
|
||||
PlatformMenuPicker(selection: Binding(
|
||||
get: { settingsManager.feedCacheValidityMinutes },
|
||||
set: { settingsManager.feedCacheValidityMinutes = $0 }
|
||||
)) {
|
||||
@@ -192,7 +192,7 @@ struct AdvancedSettingsView: View {
|
||||
private var mpvSection: some View {
|
||||
if let settingsManager = appEnvironment?.settingsManager {
|
||||
Section {
|
||||
Picker(selection: Binding(
|
||||
PlatformMenuPicker(selection: Binding(
|
||||
get: { settingsManager.mpvBufferSeconds },
|
||||
set: { settingsManager.mpvBufferSeconds = $0 }
|
||||
)) {
|
||||
|
||||
42
Yattee/Views/Settings/PlatformMenuPicker.swift
Normal file
42
Yattee/Views/Settings/PlatformMenuPicker.swift
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// PlatformMenuPicker.swift
|
||||
// Yattee
|
||||
//
|
||||
// A Picker wrapper that renders as a compact menu inside LabeledContent on tvOS,
|
||||
// and as a standard inline Picker on iOS/macOS. Use this for short option lists
|
||||
// in settings forms so tvOS shows a dropdown menu rather than pushing a sub-view.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct PlatformMenuPicker<Selection: Hashable, Label: View, Content: View>: View {
|
||||
@Binding var selection: Selection
|
||||
@ViewBuilder var content: () -> Content
|
||||
@ViewBuilder var label: () -> Label
|
||||
|
||||
var body: some View {
|
||||
#if os(tvOS)
|
||||
LabeledContent {
|
||||
Picker(selection: $selection, content: content) { EmptyView() }
|
||||
.pickerStyle(.menu)
|
||||
.labelsHidden()
|
||||
} label: {
|
||||
label()
|
||||
}
|
||||
#else
|
||||
Picker(selection: $selection, content: content, label: label)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
extension PlatformMenuPicker where Label == Text {
|
||||
init(
|
||||
_ titleKey: String,
|
||||
selection: Binding<Selection>,
|
||||
@ViewBuilder content: @escaping () -> Content
|
||||
) {
|
||||
self._selection = selection
|
||||
self.content = content
|
||||
self.label = { Text(titleKey) }
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ private struct QualitySection: View {
|
||||
|
||||
var body: some View {
|
||||
Section {
|
||||
Picker(
|
||||
PlatformMenuPicker(
|
||||
String(localized: "settings.playback.quality.preferred"),
|
||||
selection: $settings.preferredQuality
|
||||
) {
|
||||
@@ -241,7 +241,7 @@ private struct BehaviorSection: View {
|
||||
|
||||
var body: some View {
|
||||
Section(String(localized: "settings.playback.behavior.header")) {
|
||||
Picker(
|
||||
PlatformMenuPicker(
|
||||
String(localized: "settings.playback.resumeAction"),
|
||||
selection: $settings.resumeAction
|
||||
) {
|
||||
@@ -273,7 +273,7 @@ private struct QueueSection: View {
|
||||
)
|
||||
|
||||
#if os(tvOS)
|
||||
Picker(
|
||||
PlatformMenuPicker(
|
||||
String(localized: "settings.playback.queue.autoPlayCountdown"),
|
||||
selection: $settings.queueAutoPlayCountdown
|
||||
) {
|
||||
|
||||
@@ -54,7 +54,7 @@ struct PrivacySettingsView: View {
|
||||
isOn: Bindable(settingsManager).saveWatchHistory
|
||||
)
|
||||
|
||||
Picker(
|
||||
PlatformMenuPicker(
|
||||
String(localized: "settings.behavior.historyRetention"),
|
||||
selection: Binding(
|
||||
get: { settingsManager.historyRetentionDays },
|
||||
@@ -104,7 +104,7 @@ struct PrivacySettingsView: View {
|
||||
isOn: Bindable(settingsManager).saveRecentPlaylists
|
||||
)
|
||||
|
||||
Picker(
|
||||
PlatformMenuPicker(
|
||||
String(localized: "settings.behavior.searchHistoryLimit"),
|
||||
selection: Binding(
|
||||
get: { settingsManager.searchHistoryLimit },
|
||||
|
||||
@@ -153,7 +153,7 @@ struct SidebarSettingsView: View {
|
||||
|
||||
private var startupSection: some View {
|
||||
Section {
|
||||
Picker(String(localized: "settings.sidebar.startup.tab"), selection: startupTabBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.startup.tab"), selection: startupTabBinding) {
|
||||
ForEach(validStartupTabs) { item in
|
||||
Text(item.localizedTitle).tag(item)
|
||||
}
|
||||
@@ -288,7 +288,7 @@ struct SidebarSettingsView: View {
|
||||
}
|
||||
|
||||
// Source sort order
|
||||
Picker(String(localized: "settings.sidebar.sourceSort"), selection: sourceSortBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.sourceSort"), selection: sourceSortBinding) {
|
||||
ForEach(SidebarSourceSort.allCases) { sort in
|
||||
Text(sort.localizedTitle).tag(sort)
|
||||
}
|
||||
@@ -309,7 +309,7 @@ struct SidebarSettingsView: View {
|
||||
if sourcesLimitEnabledBinding.wrappedValue {
|
||||
#if os(tvOS)
|
||||
// tvOS uses Picker instead of Slider (Slider/Stepper unavailable)
|
||||
Picker(String(localized: "settings.sidebar.maxSources"), selection: maxSourcesBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.maxSources"), selection: maxSourcesBinding) {
|
||||
ForEach([5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100], id: \.self) { value in
|
||||
Text("\(value)").tag(value)
|
||||
}
|
||||
@@ -360,7 +360,7 @@ struct SidebarSettingsView: View {
|
||||
}
|
||||
|
||||
// Channel sort order
|
||||
Picker(String(localized: "settings.sidebar.channelSort"), selection: channelSortBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.channelSort"), selection: channelSortBinding) {
|
||||
ForEach(SidebarChannelSort.allCases.filter { $0 != .custom }) { sort in
|
||||
Text(sort.localizedTitle).tag(sort)
|
||||
}
|
||||
@@ -381,7 +381,7 @@ struct SidebarSettingsView: View {
|
||||
if channelsLimitEnabledBinding.wrappedValue {
|
||||
#if os(tvOS)
|
||||
// tvOS uses Picker instead of Slider (Slider/Stepper unavailable)
|
||||
Picker(String(localized: "settings.sidebar.maxChannels"), selection: maxChannelsBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.maxChannels"), selection: maxChannelsBinding) {
|
||||
ForEach([5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100], id: \.self) { value in
|
||||
Text("\(value)").tag(value)
|
||||
}
|
||||
@@ -432,7 +432,7 @@ struct SidebarSettingsView: View {
|
||||
}
|
||||
|
||||
// Playlist sort order
|
||||
Picker(String(localized: "settings.sidebar.playlistSort"), selection: playlistSortBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.playlistSort"), selection: playlistSortBinding) {
|
||||
ForEach(SidebarPlaylistSort.allCases) { sort in
|
||||
Text(sort.localizedTitle).tag(sort)
|
||||
}
|
||||
@@ -453,7 +453,7 @@ struct SidebarSettingsView: View {
|
||||
if playlistsLimitEnabledBinding.wrappedValue {
|
||||
#if os(tvOS)
|
||||
// tvOS uses Picker instead of Slider (Slider/Stepper unavailable)
|
||||
Picker(String(localized: "settings.sidebar.maxPlaylists"), selection: maxPlaylistsBinding) {
|
||||
PlatformMenuPicker(String(localized: "settings.sidebar.maxPlaylists"), selection: maxPlaylistsBinding) {
|
||||
ForEach([5, 10, 15, 20, 25, 30], id: \.self) { value in
|
||||
Text("\(value)").tag(value)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ struct SubtitlesSettingsView: View {
|
||||
|
||||
private var fontSection: some View {
|
||||
Section {
|
||||
Picker(
|
||||
PlatformMenuPicker(
|
||||
String(localized: "settings.subtitles.font"),
|
||||
selection: $settings.font
|
||||
) {
|
||||
@@ -49,7 +49,7 @@ struct SubtitlesSettingsView: View {
|
||||
|
||||
#if os(tvOS)
|
||||
// tvOS uses Picker instead of Slider (Slider unavailable)
|
||||
Picker(String(localized: "settings.subtitles.fontSize"), selection: $settings.fontSize) {
|
||||
PlatformMenuPicker(String(localized: "settings.subtitles.fontSize"), selection: $settings.fontSize) {
|
||||
ForEach([20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100], id: \.self) { size in
|
||||
Text("settings.subtitles.fontSize \(size)").tag(size)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user