74 lines
2.5 KiB
Swift
74 lines
2.5 KiB
Swift
import SwiftUI
|
||
|
||
// MARK: - RatingDotPicker
|
||
// 5-Punkt-Skala (-2 bis +2). Keine Zahlen sichtbar – nur Farb-Dots und Pol-Labels.
|
||
// Wert nil bedeutet: noch keine Auswahl getroffen.
|
||
|
||
struct RatingDotPicker: View {
|
||
@Binding var value: Int? // nil = unbewertet, -2...+2 sonst
|
||
let negativePole: String
|
||
let positivePole: String
|
||
|
||
private let dotValues = [-2, -1, 0, 1, 2]
|
||
|
||
private func color(for dot: Int) -> Color {
|
||
switch dot {
|
||
case -2: return .red
|
||
case -1: return .orange
|
||
case 0: return Color(.systemGray3)
|
||
case 1: return Color(red: 0.5, green: 0.8, blue: 0.3)
|
||
case 2: return .green
|
||
default: return .gray
|
||
}
|
||
}
|
||
|
||
var body: some View {
|
||
VStack(spacing: 12) {
|
||
HStack(spacing: 16) {
|
||
ForEach(dotValues, id: \.self) { dot in
|
||
Button {
|
||
let impact = UIImpactFeedbackGenerator(style: .light)
|
||
impact.impactOccurred()
|
||
if value == dot {
|
||
value = nil // Zweites Tippen hebt Auswahl auf
|
||
} else {
|
||
value = dot
|
||
}
|
||
} label: {
|
||
Circle()
|
||
.fill(value == dot ? color(for: dot) : Color(.systemGray5))
|
||
.frame(width: 44, height: 44)
|
||
.overlay(
|
||
Circle()
|
||
.strokeBorder(value == dot ? color(for: dot) : Color(.systemGray4), lineWidth: 1.5)
|
||
)
|
||
.scaleEffect(value == dot ? 1.15 : 1.0)
|
||
.animation(.spring(response: 0.3, dampingFraction: 0.6), value: value)
|
||
}
|
||
.buttonStyle(.plain)
|
||
}
|
||
}
|
||
|
||
HStack {
|
||
Text(LocalizedStringKey(negativePole))
|
||
.font(.caption)
|
||
.foregroundStyle(.secondary)
|
||
Spacer()
|
||
Text(LocalizedStringKey(positivePole))
|
||
.font(.caption)
|
||
.foregroundStyle(.secondary)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
#Preview {
|
||
@Previewable @State var val: Int? = nil
|
||
VStack(spacing: 32) {
|
||
RatingDotPicker(value: $val, negativePole: "Unwohl", positivePole: "Sehr wohl")
|
||
Text(val.map { "Wert: \($0)" } ?? "Keine Auswahl")
|
||
.font(.caption)
|
||
}
|
||
.padding()
|
||
}
|