Add OS metadata, preference hooks, and slider polish

This commit is contained in:
Micha
2025-11-19 18:15:33 +01:00
parent 4efe1a2324
commit d3f9126245
4 changed files with 104 additions and 60 deletions

View File

@@ -28,9 +28,10 @@ struct PreferencesView: View {
@State private var pingIntervalSlider: Double = 10
@State private var refreshIntervalSlider: Double = 60
@State private var selection: Tab = .monitor
@State private var hoveredTab: Tab?
private let minimumInterval: Double = 10
private let maximumPingInterval: Double = 600
private let maximumPingInterval: Double = 60
private let maximumRefreshInterval: Double = 600
var body: some View {
@@ -74,13 +75,20 @@ struct PreferencesView: View {
Spacer()
}
.padding(.vertical, 8)
.padding(.horizontal, 6)
.background(
RoundedRectangle(cornerRadius: 10, style: .continuous)
.fill(selection == tab ? Color.accentColor.opacity(0.25) : Color.clear)
)
.padding(.horizontal, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
.buttonStyle(.plain)
.focusable(false)
.contentShape(Capsule())
.background(
Capsule(style: .continuous)
.fill(backgroundColor(for: tab))
)
.foregroundColor(selection == tab ? .white : .primary)
.onHover { isHovering in
hoveredTab = isHovering ? tab : (hoveredTab == tab ? nil : hoveredTab)
}
}
Spacer()
@@ -127,6 +135,15 @@ struct PreferencesView: View {
storedRefreshInterval = Int(refreshIntervalSlider)
}
}
private func backgroundColor(for tab: Tab) -> Color {
if selection == tab {
return Color.accentColor
}
if hoveredTab == tab {
return Color.accentColor.opacity(0.2)
}
return Color.accentColor.opacity(0.08)
}
}
private struct MonitorPreferencesView: View {
@@ -141,56 +158,20 @@ private struct MonitorPreferencesView: View {
let refreshChanged: (Bool) -> Void
var body: some View {
VStack(alignment: .leading, spacing: 18) {
Group {
Text("Ping interval")
.font(.headline)
Slider(
value: $pingIntervalSlider,
in: minimumInterval...maximumPingInterval,
step: 5
) {
Text("Ping interval")
} minimumValueLabel: {
Text("\(Int(minimumInterval))s")
.font(.caption)
.foregroundColor(.secondary)
} maximumValueLabel: {
Text("\(Int(maximumPingInterval))s")
.font(.caption)
.foregroundColor(.secondary)
} onEditingChanged: { editing in
pingChanged(editing)
}
Text("Current: \(Int(pingIntervalSlider)) seconds")
.font(.caption)
.foregroundColor(.secondary)
}
VStack(alignment: .leading, spacing: 24) {
intervalSection(
title: "Ping interval",
value: $pingIntervalSlider,
range: minimumInterval...maximumPingInterval,
onEditingChanged: pingChanged
)
Group {
Text("Refresh interval")
.font(.headline)
Slider(
value: $refreshIntervalSlider,
in: minimumInterval...maximumRefreshInterval,
step: 5
) {
Text("Refresh interval")
} minimumValueLabel: {
Text("\(Int(minimumInterval))s")
.font(.caption)
.foregroundColor(.secondary)
} maximumValueLabel: {
Text("\(Int(maximumRefreshInterval))s")
.font(.caption)
.foregroundColor(.secondary)
} onEditingChanged: { editing in
refreshChanged(editing)
}
Text("Current: \(Int(refreshIntervalSlider)) seconds")
.font(.caption)
.foregroundColor(.secondary)
}
intervalSection(
title: "Refresh interval",
value: $refreshIntervalSlider,
range: minimumInterval...maximumRefreshInterval,
onEditingChanged: refreshChanged
)
Divider()
@@ -201,6 +182,42 @@ private struct MonitorPreferencesView: View {
}
.frame(maxWidth: .infinity, alignment: .leading)
}
private func intervalSection(
title: String,
value: Binding<Double>,
range: ClosedRange<Double>,
onEditingChanged: @escaping (Bool) -> Void
) -> some View {
VStack(alignment: .leading, spacing: 8) {
HStack {
Text(title)
.font(.headline)
Spacer()
Text("\(Int(value.wrappedValue)) seconds")
.font(.subheadline)
.foregroundColor(.secondary)
}
Slider(
value: value,
in: range,
step: 5
) {
Text(title)
} minimumValueLabel: {
Text("\(Int(range.lowerBound))s")
.font(.caption)
.foregroundColor(.secondary)
} maximumValueLabel: {
Text("\(Int(range.upperBound))s")
.font(.caption)
.foregroundColor(.secondary)
} onEditingChanged: { editing in
onEditingChanged(editing)
}
}
}
}
private struct NotificationsPreferencesView: View {