mirror of
https://github.com/yattee/yattee.git
synced 2026-07-21 06:42:01 +00:00
Add glass background theme setting for macOS control bar
Rename the macOS "Control Bar Buttons" settings entry to "Control Bar" and add an Auto/Light/Dark glass background picker on that page. The choice is stored per-preset as GlobalLayoutSettings.controlBarTheme and forces the bar's glass color scheme via glassBackground(colorScheme:).
This commit is contained in:
@@ -1859,6 +1859,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"controls.theme.auto" : {
|
||||||
|
"extractionState" : "extracted_with_value",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "new",
|
||||||
|
"value" : "Auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"controls.theme.dark" : {
|
"controls.theme.dark" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@@ -13315,13 +13326,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings.playerControls.controlBarButtons" : {
|
"settings.playerControls.controlBar" : {
|
||||||
"extractionState" : "extracted_with_value",
|
"extractionState" : "extracted_with_value",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
"state" : "new",
|
"state" : "new",
|
||||||
"value" : "Control Bar Buttons"
|
"value" : "Control Bar"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13396,6 +13407,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"settings.playerControls.glassBackground" : {
|
||||||
|
"extractionState" : "extracted_with_value",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "new",
|
||||||
|
"value" : "Glass Background"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"settings.playerControls.import.error.emptyFile" : {
|
"settings.playerControls.import.error.emptyFile" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
|
|||||||
@@ -411,6 +411,9 @@ struct GlobalLayoutSettings: Codable, Hashable, Sendable {
|
|||||||
/// How volume is controlled during playback.
|
/// How volume is controlled during playback.
|
||||||
var volumeMode: VolumeMode
|
var volumeMode: VolumeMode
|
||||||
|
|
||||||
|
/// Forced appearance for the macOS control bar's glass background.
|
||||||
|
var controlBarTheme: ControlsTheme
|
||||||
|
|
||||||
/// Theme derived from style (for backwards compatibility).
|
/// Theme derived from style (for backwards compatibility).
|
||||||
var theme: ControlsTheme { style.theme }
|
var theme: ControlsTheme { style.theme }
|
||||||
|
|
||||||
@@ -433,6 +436,7 @@ struct GlobalLayoutSettings: Codable, Hashable, Sendable {
|
|||||||
case systemControlsMode
|
case systemControlsMode
|
||||||
case systemControlsSeekDuration
|
case systemControlsSeekDuration
|
||||||
case volumeMode
|
case volumeMode
|
||||||
|
case controlBarTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
@@ -445,6 +449,7 @@ struct GlobalLayoutSettings: Codable, Hashable, Sendable {
|
|||||||
systemControlsMode = try container.decodeIfPresent(SystemControlsMode.self, forKey: .systemControlsMode) ?? .seek
|
systemControlsMode = try container.decodeIfPresent(SystemControlsMode.self, forKey: .systemControlsMode) ?? .seek
|
||||||
systemControlsSeekDuration = try container.decodeIfPresent(SystemControlsSeekDuration.self, forKey: .systemControlsSeekDuration) ?? .tenSeconds
|
systemControlsSeekDuration = try container.decodeIfPresent(SystemControlsSeekDuration.self, forKey: .systemControlsSeekDuration) ?? .tenSeconds
|
||||||
volumeMode = try container.decodeIfPresent(VolumeMode.self, forKey: .volumeMode) ?? .mpv
|
volumeMode = try container.decodeIfPresent(VolumeMode.self, forKey: .volumeMode) ?? .mpv
|
||||||
|
controlBarTheme = try container.decodeIfPresent(ControlsTheme.self, forKey: .controlBarTheme) ?? .system
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(to encoder: Encoder) throws {
|
func encode(to encoder: Encoder) throws {
|
||||||
@@ -457,6 +462,7 @@ struct GlobalLayoutSettings: Codable, Hashable, Sendable {
|
|||||||
try container.encode(systemControlsMode, forKey: .systemControlsMode)
|
try container.encode(systemControlsMode, forKey: .systemControlsMode)
|
||||||
try container.encode(systemControlsSeekDuration, forKey: .systemControlsSeekDuration)
|
try container.encode(systemControlsSeekDuration, forKey: .systemControlsSeekDuration)
|
||||||
try container.encode(volumeMode, forKey: .volumeMode)
|
try container.encode(volumeMode, forKey: .volumeMode)
|
||||||
|
try container.encode(controlBarTheme, forKey: .controlBarTheme)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
@@ -469,7 +475,8 @@ struct GlobalLayoutSettings: Codable, Hashable, Sendable {
|
|||||||
controlsFadeOpacity: Double = 0.5,
|
controlsFadeOpacity: Double = 0.5,
|
||||||
systemControlsMode: SystemControlsMode = .seek,
|
systemControlsMode: SystemControlsMode = .seek,
|
||||||
systemControlsSeekDuration: SystemControlsSeekDuration = .tenSeconds,
|
systemControlsSeekDuration: SystemControlsSeekDuration = .tenSeconds,
|
||||||
volumeMode: VolumeMode = .mpv
|
volumeMode: VolumeMode = .mpv,
|
||||||
|
controlBarTheme: ControlsTheme = .system
|
||||||
) {
|
) {
|
||||||
self.style = style
|
self.style = style
|
||||||
self.buttonSize = buttonSize
|
self.buttonSize = buttonSize
|
||||||
@@ -478,6 +485,7 @@ struct GlobalLayoutSettings: Codable, Hashable, Sendable {
|
|||||||
self.systemControlsMode = systemControlsMode
|
self.systemControlsMode = systemControlsMode
|
||||||
self.systemControlsSeekDuration = systemControlsSeekDuration
|
self.systemControlsSeekDuration = systemControlsSeekDuration
|
||||||
self.volumeMode = volumeMode
|
self.volumeMode = volumeMode
|
||||||
|
self.controlBarTheme = controlBarTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Defaults
|
// MARK: - Defaults
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ struct MacOSControlBar: View {
|
|||||||
.padding(.horizontal, 16)
|
.padding(.horizontal, 16)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
.frame(maxWidth: 500)
|
.frame(maxWidth: 500)
|
||||||
.glassBackground(.regular, in: .rect(cornerRadius: 16))
|
.glassBackground(.regular, in: .rect(cornerRadius: 16), colorScheme: globalSettings.controlBarTheme.colorScheme)
|
||||||
.shadow(color: .black.opacity(0.3), radius: 8, y: 4)
|
.shadow(color: .black.opacity(0.3), radius: 8, y: 4)
|
||||||
// Seek preview overlay - positioned above the control bar
|
// Seek preview overlay - positioned above the control bar
|
||||||
.overlay(alignment: .bottom) {
|
.overlay(alignment: .bottom) {
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ private struct LayoutSectionsSection: View {
|
|||||||
HStack {
|
HStack {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
Label(
|
Label(
|
||||||
String(localized: "settings.playerControls.controlBarButtons", defaultValue: "Control Bar Buttons"),
|
String(localized: "settings.playerControls.controlBar", defaultValue: "Control Bar"),
|
||||||
systemImage: "rectangle.bottomthird.inset.filled"
|
systemImage: "rectangle.bottomthird.inset.filled"
|
||||||
)
|
)
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ struct SectionEditorView: View {
|
|||||||
// Local state for immediate UI updates
|
// Local state for immediate UI updates
|
||||||
@State private var buttons: [ControlButtonConfiguration] = []
|
@State private var buttons: [ControlButtonConfiguration] = []
|
||||||
@State private var availableTypes: [ControlButtonType] = []
|
@State private var availableTypes: [ControlButtonType] = []
|
||||||
|
@State private var controlBarTheme: ControlsTheme = .system
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
@@ -45,6 +46,29 @@ struct SectionEditorView: View {
|
|||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The macOS bar draws a glass capsule whose appearance can be forced.
|
||||||
|
#if os(macOS)
|
||||||
|
if sectionType == .bottom {
|
||||||
|
Section {
|
||||||
|
Picker(
|
||||||
|
String(localized: "settings.playerControls.glassBackground", defaultValue: "Glass Background"),
|
||||||
|
selection: $controlBarTheme
|
||||||
|
) {
|
||||||
|
ForEach(ControlsTheme.allCases, id: \.self) { theme in
|
||||||
|
Text(glassBackgroundLabel(for: theme)).tag(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disabled(!viewModel.canEditActivePreset)
|
||||||
|
.onChange(of: controlBarTheme) { _, newTheme in
|
||||||
|
guard newTheme != viewModel.currentLayout.globalSettings.controlBarTheme else { return }
|
||||||
|
viewModel.updateGlobalSettingsSync { $0.controlBarTheme = newTheme }
|
||||||
|
}
|
||||||
|
} header: {
|
||||||
|
Text(String(localized: "settings.playerControls.appearance"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Added buttons
|
// Added buttons
|
||||||
Section {
|
Section {
|
||||||
ForEach(buttons) { button in
|
ForEach(buttons) { button in
|
||||||
@@ -139,6 +163,7 @@ struct SectionEditorView: View {
|
|||||||
case .bottom:
|
case .bottom:
|
||||||
buttons = preset.layout.bottomSection.buttons
|
buttons = preset.layout.bottomSection.buttons
|
||||||
}
|
}
|
||||||
|
controlBarTheme = preset.layout.globalSettings.controlBarTheme
|
||||||
syncAvailableTypes()
|
syncAvailableTypes()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,12 +185,27 @@ struct SectionEditorView: View {
|
|||||||
viewModel.addButtonSync(buttonType, to: sectionType)
|
viewModel.addButtonSync(buttonType, to: sectionType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(macOS)
|
||||||
|
private func glassBackgroundLabel(for theme: ControlsTheme) -> String {
|
||||||
|
switch theme {
|
||||||
|
case .system:
|
||||||
|
return String(localized: "controls.theme.auto", defaultValue: "Auto")
|
||||||
|
case .light, .dark:
|
||||||
|
return theme.displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private var sectionTitle: String {
|
private var sectionTitle: String {
|
||||||
switch sectionType {
|
switch sectionType {
|
||||||
case .top:
|
case .top:
|
||||||
return String(localized: "settings.playerControls.topButtons")
|
return String(localized: "settings.playerControls.topButtons")
|
||||||
case .bottom:
|
case .bottom:
|
||||||
|
#if os(macOS)
|
||||||
|
return String(localized: "settings.playerControls.controlBar", defaultValue: "Control Bar")
|
||||||
|
#else
|
||||||
return String(localized: "settings.playerControls.bottomButtons")
|
return String(localized: "settings.playerControls.bottomButtons")
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user