mirror of
https://github.com/FBukovina/Atoll.git
synced 2026-10-27 15:14:33 +00:00
Merge PR #117 (feature/settings) into revamp/essentials for testing & iteration
This commit is contained in:
commit
4090100c2a
3 changed files with 104 additions and 25 deletions
|
|
@ -10629,10 +10629,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Left button" : {
|
|
||||||
"comment" : "A label for a picker that lets the user select a control for the left button on a media player.",
|
|
||||||
"isCommentAutoGenerated" : true
|
|
||||||
},
|
|
||||||
"License key" : {
|
"License key" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"fr" : {
|
"fr" : {
|
||||||
|
|
@ -15730,10 +15726,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Right button" : {
|
|
||||||
"comment" : "A label for the right button in the media controls picker.",
|
|
||||||
"isCommentAutoGenerated" : true
|
|
||||||
},
|
|
||||||
"Rotation:" : {
|
"Rotation:" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"fr" : {
|
"fr" : {
|
||||||
|
|
|
||||||
|
|
@ -908,16 +908,7 @@ struct Media: View {
|
||||||
}
|
}
|
||||||
.disabled(!showShuffleAndRepeat)
|
.disabled(!showShuffleAndRepeat)
|
||||||
if showShuffleAndRepeat {
|
if showShuffleAndRepeat {
|
||||||
Picker("Left button", selection: $musicAuxLeftControl) {
|
mediaControlsGrid
|
||||||
ForEach(MusicAuxiliaryControl.allCases) { control in
|
|
||||||
Text(control.displayName).tag(control)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Picker("Right button", selection: $musicAuxRightControl) {
|
|
||||||
ForEach(MusicAuxiliaryControl.allCases) { control in
|
|
||||||
Text(control.displayName).tag(control)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("Media controls")
|
Text("Media controls")
|
||||||
|
|
@ -1034,6 +1025,102 @@ struct Media: View {
|
||||||
.navigationTitle("Media")
|
.navigationTitle("Media")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var mediaControlsGrid: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 20) {
|
||||||
|
mediaControlsRow(title: "Left button", selection: $musicAuxLeftControl, otherSelection: musicAuxRightControl)
|
||||||
|
mediaControlsRow(title: "Right button", selection: $musicAuxRightControl, otherSelection: musicAuxLeftControl)
|
||||||
|
}
|
||||||
|
.padding(.vertical, 12)
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 16) {
|
||||||
|
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: 80, height: 60)
|
||||||
|
.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: 100)
|
||||||
|
.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
|
// Only show controller options that are available on this macOS version
|
||||||
private var availableMediaControllers: [MediaControllerType] {
|
private var availableMediaControllers: [MediaControllerType] {
|
||||||
if MusicManager.shared.isNowPlayingDeprecated {
|
if MusicManager.shared.isNowPlayingDeprecated {
|
||||||
|
|
@ -2486,34 +2573,34 @@ struct TimerSettings: View {
|
||||||
let nextIndex = timerPresets.count + 1
|
let nextIndex = timerPresets.count + 1
|
||||||
let defaultColor = Defaults[.accentColor]
|
let defaultColor = Defaults[.accentColor]
|
||||||
let newPreset = TimerPreset(name: "Preset \(nextIndex)", duration: 5 * 60, color: defaultColor)
|
let newPreset = TimerPreset(name: "Preset \(nextIndex)", duration: 5 * 60, color: defaultColor)
|
||||||
_ = withAnimation(.smooth) {
|
withAnimation(.smooth) {
|
||||||
timerPresets.append(newPreset)
|
timerPresets.append(newPreset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func movePresetUp(_ index: Int) {
|
private func movePresetUp(_ index: Int) {
|
||||||
guard index > timerPresets.startIndex else { return }
|
guard index > timerPresets.startIndex else { return }
|
||||||
_ = withAnimation(.smooth) {
|
withAnimation(.smooth) {
|
||||||
timerPresets.swapAt(index, index - 1)
|
timerPresets.swapAt(index, index - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func movePresetDown(_ index: Int) {
|
private func movePresetDown(_ index: Int) {
|
||||||
guard index < timerPresets.index(before: timerPresets.endIndex) else { return }
|
guard index < timerPresets.index(before: timerPresets.endIndex) else { return }
|
||||||
_ = withAnimation(.smooth) {
|
withAnimation(.smooth) {
|
||||||
timerPresets.swapAt(index, index + 1)
|
timerPresets.swapAt(index, index + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removePreset(_ index: Int) {
|
private func removePreset(_ index: Int) {
|
||||||
guard timerPresets.indices.contains(index) else { return }
|
guard timerPresets.indices.contains(index) else { return }
|
||||||
_ = withAnimation(.smooth) {
|
withAnimation(.smooth) {
|
||||||
timerPresets.remove(at: index)
|
timerPresets.remove(at: index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func resetPresets() {
|
private func resetPresets() {
|
||||||
_ = withAnimation(.smooth) {
|
withAnimation(.smooth) {
|
||||||
timerPresets = TimerPreset.defaultPresets
|
timerPresets = TimerPreset.defaultPresets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2766,7 +2853,7 @@ struct StatsSettings: View {
|
||||||
|
|
||||||
Section {
|
Section {
|
||||||
Defaults.Toggle("CPU Usage", key: .showCpuGraph)
|
Defaults.Toggle("CPU Usage", key: .showCpuGraph)
|
||||||
Defaults.Toggle("Memory Usage", key: .showMemoryGraph)
|
Defaults.Toggle("Memory Usage", key: .showMemoryGraph)
|
||||||
Defaults.Toggle("GPU Usage", key: .showGpuGraph)
|
Defaults.Toggle("GPU Usage", key: .showGpuGraph)
|
||||||
Defaults.Toggle("Network Activity", key: .showNetworkGraph)
|
Defaults.Toggle("Network Activity", key: .showNetworkGraph)
|
||||||
Defaults.Toggle("Disk I/O", key: .showDiskGraph)
|
Defaults.Toggle("Disk I/O", key: .showDiskGraph)
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ enum MusicAuxiliaryControl: String, CaseIterable, Identifiable, Defaults.Seriali
|
||||||
case .repeatMode:
|
case .repeatMode:
|
||||||
return "repeat"
|
return "repeat"
|
||||||
case .mediaOutput:
|
case .mediaOutput:
|
||||||
return "speaker.wave.2"
|
return "laptopcomputer"
|
||||||
case .lyrics:
|
case .lyrics:
|
||||||
return "quote.bubble"
|
return "quote.bubble"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue