mirror of
https://github.com/yattee/yattee.git
synced 2026-05-12 18:35:05 +00:00
Fix tvOS MPV Options focus and Add/Edit sheet layout
Wrap pushed view in TVSidebarDetailContainer, list custom options first so focus engages on a row, mark default options focusable so the list scrolls. Replace toolbar-based Add/Edit sheets with padded VStacks and inline confirm buttons. Cache customMPVOptions in @Observable backing storage so writes refresh the list immediately.
This commit is contained in:
@@ -16,6 +16,7 @@ extension SettingsManager {
|
||||
/// NOT synced to iCloud - local-only storage.
|
||||
var customMPVOptions: [String: String] {
|
||||
get {
|
||||
if let cached = _customMPVOptions { return cached }
|
||||
guard let data = localDefaults.data(forKey: "customMPVOptions"),
|
||||
let options = try? JSONDecoder().decode([String: String].self, from: data) else {
|
||||
return [:]
|
||||
@@ -23,6 +24,7 @@ extension SettingsManager {
|
||||
return options
|
||||
}
|
||||
set {
|
||||
_customMPVOptions = newValue
|
||||
if let data = try? JSONEncoder().encode(newValue) {
|
||||
localDefaults.set(data, forKey: "customMPVOptions")
|
||||
}
|
||||
|
||||
@@ -117,6 +117,9 @@ final class SettingsManager {
|
||||
// Top Shelf (tvOS)
|
||||
var _topShelfSections: [TopShelfSection]?
|
||||
|
||||
// Custom MPV options (local-only)
|
||||
var _customMPVOptions: [String: String]?
|
||||
|
||||
// Tab bar settings (compact size class only - iOS)
|
||||
var _tabBarItemOrder: [TabBarItem]?
|
||||
var _tabBarItemVisibility: [TabBarItem: Bool]?
|
||||
|
||||
@@ -212,7 +212,12 @@ struct AdvancedSettingsView: View {
|
||||
|
||||
#if os(tvOS)
|
||||
NavigationLink {
|
||||
MPVOptionsSettingsView()
|
||||
TVSidebarDetailContainer(
|
||||
systemImage: "slider.horizontal.3",
|
||||
title: String(localized: "settings.advanced.mpv.options")
|
||||
) {
|
||||
MPVOptionsSettingsView()
|
||||
}
|
||||
} label: {
|
||||
Label(String(localized: "settings.advanced.mpv.options"), systemImage: "slider.horizontal.3")
|
||||
}
|
||||
|
||||
@@ -16,12 +16,21 @@ struct MPVOptionsSettingsView: View {
|
||||
var body: some View {
|
||||
SettingsFormContainer {
|
||||
if let settings = appEnvironment?.settingsManager {
|
||||
#if os(tvOS)
|
||||
CustomOptionsSection(
|
||||
settings: settings,
|
||||
showingAddSheet: $showingAddSheet,
|
||||
editingOption: $editingOption
|
||||
)
|
||||
DefaultOptionsSection()
|
||||
#else
|
||||
DefaultOptionsSection()
|
||||
CustomOptionsSection(
|
||||
settings: settings,
|
||||
showingAddSheet: $showingAddSheet,
|
||||
editingOption: $editingOption
|
||||
)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.navigationTitle(String(localized: "settings.mpvOptions.title"))
|
||||
@@ -69,6 +78,7 @@ private struct DefaultOptionsSection: View {
|
||||
Text(option.value)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.focusable()
|
||||
}
|
||||
}
|
||||
#else
|
||||
@@ -263,6 +273,44 @@ private struct AddMPVOptionSheet: View {
|
||||
}
|
||||
.padding(20)
|
||||
.frame(minWidth: 420)
|
||||
#elseif os(tvOS)
|
||||
VStack(spacing: 30) {
|
||||
Text(String(localized: "settings.mpvOptions.addOption.title"))
|
||||
.font(.title2)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
VStack(spacing: 20) {
|
||||
TextField(
|
||||
String(localized: "settings.mpvOptions.optionName"),
|
||||
text: $optionName
|
||||
)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
|
||||
TextField(
|
||||
String(localized: "settings.mpvOptions.optionValue"),
|
||||
text: $optionValue
|
||||
)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
}
|
||||
|
||||
Button {
|
||||
save()
|
||||
} label: {
|
||||
Text(String(localized: "common.add"))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.disabled(!canSave)
|
||||
|
||||
Text(String(localized: "settings.mpvOptions.addOption.footer"))
|
||||
.font(.callout)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.padding(60)
|
||||
.frame(maxWidth: 900)
|
||||
#else
|
||||
NavigationStack {
|
||||
Form {
|
||||
@@ -400,6 +448,59 @@ private struct EditMPVOptionSheet: View {
|
||||
.onAppear {
|
||||
optionValue = initialValue
|
||||
}
|
||||
#elseif os(tvOS)
|
||||
VStack(spacing: 30) {
|
||||
Text(String(localized: "settings.mpvOptions.editOption.title"))
|
||||
.font(.title2)
|
||||
.fontWeight(.semibold)
|
||||
|
||||
VStack(spacing: 20) {
|
||||
HStack {
|
||||
Text(String(localized: "settings.mpvOptions.optionName"))
|
||||
Spacer()
|
||||
Text(originalName)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.padding(.horizontal, 24)
|
||||
|
||||
TextField(
|
||||
String(localized: "settings.mpvOptions.optionValue"),
|
||||
text: $optionValue
|
||||
)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
}
|
||||
|
||||
Button {
|
||||
save()
|
||||
} label: {
|
||||
Text(String(localized: "common.save"))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.disabled(!canSave)
|
||||
|
||||
Button(role: .destructive) {
|
||||
showingDeleteConfirmation = true
|
||||
} label: {
|
||||
Label(String(localized: "settings.mpvOptions.deleteOption"), systemImage: "trash")
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.padding(60)
|
||||
.frame(maxWidth: 900)
|
||||
.confirmationDialog(
|
||||
String(localized: "settings.mpvOptions.deleteOption.confirmation"),
|
||||
isPresented: $showingDeleteConfirmation,
|
||||
titleVisibility: .visible
|
||||
) {
|
||||
Button(String(localized: "common.delete"), role: .destructive) {
|
||||
delete()
|
||||
}
|
||||
Button(String(localized: "common.cancel"), role: .cancel) {}
|
||||
}
|
||||
.onAppear {
|
||||
optionValue = initialValue
|
||||
}
|
||||
#else
|
||||
NavigationStack {
|
||||
Form {
|
||||
|
||||
Reference in New Issue
Block a user