mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-28 07:34:32 +00:00
Remapping functionality
This commit is contained in:
parent
d451ea34fd
commit
96dde9d555
9 changed files with 687 additions and 399 deletions
|
|
@ -1360,13 +1360,9 @@ struct Media: View {
|
|||
@Default(.sneakPeekStyles) var sneakPeekStyles
|
||||
@Default(.enableMinimalisticUI) var enableMinimalisticUI
|
||||
@Default(.showShuffleAndRepeat) private var showShuffleAndRepeat
|
||||
@Default(.musicAuxLeftControl) private var musicAuxLeftControl
|
||||
@Default(.musicAuxRightControl) private var musicAuxRightControl
|
||||
@Default(.musicSkipBehavior) private var musicSkipBehavior
|
||||
@Default(.musicControlWindowEnabled) private var musicControlWindowEnabled
|
||||
@Default(.enableLockScreenMediaWidget) private var enableLockScreenMediaWidget
|
||||
@State private var previousLeftAuxControl: MusicAuxiliaryControl = Defaults[.musicAuxLeftControl]
|
||||
@State private var previousRightAuxControl: MusicAuxiliaryControl = Defaults[.musicAuxRightControl]
|
||||
|
||||
private func highlightID(_ title: String) -> String {
|
||||
SettingsTab.media.highlightID(for: title)
|
||||
|
|
@ -1408,16 +1404,21 @@ struct Media: View {
|
|||
Section {
|
||||
Defaults.Toggle(key: .showShuffleAndRepeat) {
|
||||
HStack {
|
||||
Text("Show shuffle and repeat buttons")
|
||||
Text("Enable customizable controls")
|
||||
customBadge(text: "Beta")
|
||||
}
|
||||
}
|
||||
Defaults.Toggle(key: .showMediaOutputControl) {
|
||||
Text("Show media output control in other layouts")
|
||||
Text("Allow media output control in layouts")
|
||||
}
|
||||
.disabled(!showShuffleAndRepeat)
|
||||
if showShuffleAndRepeat {
|
||||
mediaControlsGrid
|
||||
MusicSlotConfigurationView()
|
||||
} else {
|
||||
Text("Turn on customizable controls to rearrange media buttons.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.vertical, 4)
|
||||
}
|
||||
} header: {
|
||||
Text("Media controls")
|
||||
|
|
@ -1512,142 +1513,9 @@ struct Media: View {
|
|||
Defaults[.enableFullscreenMediaDetection] = hideNotchOption != .never
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
ensureAuxControlsUnique()
|
||||
previousLeftAuxControl = musicAuxLeftControl
|
||||
previousRightAuxControl = musicAuxRightControl
|
||||
}
|
||||
.onChange(of: musicAuxLeftControl) { newValue in
|
||||
if newValue == musicAuxRightControl {
|
||||
let fallback = MusicAuxiliaryControl.alternative(
|
||||
excluding: newValue,
|
||||
preferring: previousLeftAuxControl
|
||||
)
|
||||
if fallback != musicAuxRightControl {
|
||||
musicAuxRightControl = fallback
|
||||
}
|
||||
}
|
||||
|
||||
previousLeftAuxControl = newValue
|
||||
}
|
||||
.onChange(of: musicAuxRightControl) { newValue in
|
||||
if newValue == musicAuxLeftControl {
|
||||
let fallback = MusicAuxiliaryControl.alternative(
|
||||
excluding: newValue,
|
||||
preferring: previousRightAuxControl
|
||||
)
|
||||
if fallback != musicAuxLeftControl {
|
||||
musicAuxLeftControl = fallback
|
||||
}
|
||||
}
|
||||
|
||||
previousRightAuxControl = newValue
|
||||
}
|
||||
.onChange(of: showShuffleAndRepeat) { isEnabled in
|
||||
if isEnabled {
|
||||
ensureAuxControlsUnique()
|
||||
}
|
||||
}
|
||||
.navigationTitle("Media")
|
||||
}
|
||||
|
||||
private var mediaControlsGrid: some View {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
mediaControlsRow(title: "Left button", selection: $musicAuxLeftControl, otherSelection: musicAuxRightControl)
|
||||
mediaControlsRow(title: "Right button", selection: $musicAuxRightControl, otherSelection: musicAuxLeftControl)
|
||||
}
|
||||
.padding(.vertical, 12)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
private func mediaControlsRow(title: String, selection: Binding<MusicAuxiliaryControl>, otherSelection: MusicAuxiliaryControl) -> some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text(title)
|
||||
.font(.system(size: 13, weight: .semibold))
|
||||
.foregroundStyle(.white)
|
||||
|
||||
HStack(spacing: 12) {
|
||||
ForEach([MusicAuxiliaryControl.mediaOutput, MusicAuxiliaryControl.repeatMode, MusicAuxiliaryControl.lyrics, MusicAuxiliaryControl.shuffle], id: \.self) { control in
|
||||
MediaControlButton(
|
||||
control: control,
|
||||
isSelected: selection.wrappedValue == control,
|
||||
disabled: control == otherSelection
|
||||
) {
|
||||
selection.wrappedValue = control
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MediaControlButton: View {
|
||||
let control: MusicAuxiliaryControl
|
||||
let isSelected: Bool
|
||||
let disabled: Bool
|
||||
let action: () -> Void
|
||||
|
||||
@State private var isHovering = false
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 8) {
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(backgroundColor)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.strokeBorder(borderColor, lineWidth: isSelected ? 2 : 1)
|
||||
)
|
||||
|
||||
Image(systemName: control.symbolName)
|
||||
.font(.system(size: 22, weight: .medium))
|
||||
.foregroundStyle(iconColor)
|
||||
}
|
||||
.frame(width: 68, height: 52)
|
||||
.onHover { hovering in
|
||||
if !disabled {
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
isHovering = hovering
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Text(control.displayName)
|
||||
.font(.caption)
|
||||
.fontWeight(.medium)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(width: 80)
|
||||
.foregroundStyle(disabled ? .secondary : .primary)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
if !disabled {
|
||||
action()
|
||||
}
|
||||
}
|
||||
.opacity(disabled ? 0.5 : 1.0)
|
||||
}
|
||||
|
||||
private var backgroundColor: Color {
|
||||
if disabled { return Color(nsColor: .controlBackgroundColor) }
|
||||
if isSelected { return Color.accentColor.opacity(0.1) }
|
||||
if isHovering { return Color.primary.opacity(0.05) }
|
||||
return Color(nsColor: .controlBackgroundColor)
|
||||
}
|
||||
|
||||
private var borderColor: Color {
|
||||
if isSelected { return Color.accentColor }
|
||||
if isHovering { return Color.primary.opacity(0.1) }
|
||||
return Color.clear
|
||||
}
|
||||
|
||||
private var iconColor: Color {
|
||||
if disabled { return .secondary }
|
||||
if isSelected { return .accentColor }
|
||||
return .primary
|
||||
}
|
||||
}
|
||||
|
||||
// Only show controller options that are available on this macOS version
|
||||
private var availableMediaControllers: [MediaControllerType] {
|
||||
if MusicManager.shared.isNowPlayingDeprecated {
|
||||
|
|
@ -1656,15 +1524,6 @@ struct Media: View {
|
|||
return MediaControllerType.allCases
|
||||
}
|
||||
}
|
||||
|
||||
private func ensureAuxControlsUnique() {
|
||||
guard showShuffleAndRepeat, musicAuxLeftControl == musicAuxRightControl else { return }
|
||||
|
||||
let fallback = MusicAuxiliaryControl.alternative(excluding: musicAuxLeftControl)
|
||||
if fallback != musicAuxRightControl {
|
||||
musicAuxRightControl = fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CalendarSettings: View {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue