general: foregroundColor -> foregroundStyle (will change in future)
This commit is contained in:
@@ -10,15 +10,15 @@ import SwiftUI
|
||||
struct EyeTrackingCalibrationView: View {
|
||||
@StateObject private var calibrationManager = CalibrationManager.shared
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
|
||||
@State private var countdownValue = 3
|
||||
@State private var isCountingDown = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
// Full-screen black background
|
||||
Color.black.ignoresSafeArea()
|
||||
|
||||
|
||||
if calibrationManager.isCalibrating {
|
||||
calibrationContentView
|
||||
} else {
|
||||
@@ -27,51 +27,55 @@ struct EyeTrackingCalibrationView: View {
|
||||
}
|
||||
.frame(minWidth: 800, minHeight: 600)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Introduction Screen
|
||||
|
||||
|
||||
private var introductionScreenView: some View {
|
||||
VStack(spacing: 30) {
|
||||
Image(systemName: "eye.circle.fill")
|
||||
.font(.system(size: 80))
|
||||
.foregroundColor(.blue)
|
||||
|
||||
.foregroundStyle(.blue)
|
||||
|
||||
Text("Eye Tracking Calibration")
|
||||
.font(.largeTitle)
|
||||
.foregroundStyle(.white)
|
||||
.fontWeight(.bold)
|
||||
|
||||
|
||||
Text("This calibration will help improve eye tracking accuracy.")
|
||||
.font(.title3)
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundColor(.secondary)
|
||||
|
||||
.foregroundStyle(.gray)
|
||||
|
||||
VStack(alignment: .leading, spacing: 15) {
|
||||
InstructionRow(icon: "1.circle.fill", text: "Look at each target on the screen")
|
||||
InstructionRow(icon: "2.circle.fill", text: "Keep your head still, only move your eyes")
|
||||
InstructionRow(
|
||||
icon: "2.circle.fill", text: "Keep your head still, only move your eyes")
|
||||
InstructionRow(icon: "3.circle.fill", text: "Follow the countdown at each position")
|
||||
InstructionRow(icon: "4.circle.fill", text: "Takes about 30-45 seconds")
|
||||
}
|
||||
.padding(.vertical, 20)
|
||||
|
||||
|
||||
if calibrationManager.calibrationData.isComplete {
|
||||
VStack(spacing: 10) {
|
||||
Text("Last calibration:")
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundStyle(.gray)
|
||||
Text(calibrationManager.getCalibrationSummary())
|
||||
.font(.caption)
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundColor(.secondary)
|
||||
.foregroundStyle(.gray)
|
||||
}
|
||||
.padding(.vertical)
|
||||
}
|
||||
|
||||
|
||||
HStack(spacing: 20) {
|
||||
Button("Cancel") {
|
||||
dismiss()
|
||||
}
|
||||
.foregroundStyle(.white)
|
||||
.buttonStyle(.plain)
|
||||
.keyboardShortcut(.escape, modifiers: [])
|
||||
|
||||
|
||||
Button("Start Calibration") {
|
||||
startCalibration()
|
||||
}
|
||||
@@ -83,9 +87,9 @@ struct EyeTrackingCalibrationView: View {
|
||||
.padding(60)
|
||||
.frame(maxWidth: 600)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Calibration Content
|
||||
|
||||
|
||||
private var calibrationContentView: some View {
|
||||
ZStack {
|
||||
// Progress indicator at top
|
||||
@@ -93,12 +97,12 @@ struct EyeTrackingCalibrationView: View {
|
||||
progressBar
|
||||
Spacer()
|
||||
}
|
||||
|
||||
|
||||
// Calibration target
|
||||
if let step = calibrationManager.currentStep {
|
||||
calibrationTarget(for: step)
|
||||
}
|
||||
|
||||
|
||||
// Skip button at bottom
|
||||
VStack {
|
||||
Spacer()
|
||||
@@ -106,19 +110,19 @@ struct EyeTrackingCalibrationView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Progress Bar
|
||||
|
||||
|
||||
private var progressBar: some View {
|
||||
VStack(spacing: 10) {
|
||||
HStack {
|
||||
Text("Calibrating...")
|
||||
.foregroundColor(.white)
|
||||
.foregroundStyle(.white)
|
||||
Spacer()
|
||||
Text(calibrationManager.progressText)
|
||||
.foregroundColor(.white.opacity(0.7))
|
||||
.foregroundStyle(.white.opacity(0.7))
|
||||
}
|
||||
|
||||
|
||||
ProgressView(value: calibrationManager.progress)
|
||||
.progressViewStyle(.linear)
|
||||
.tint(.blue)
|
||||
@@ -126,13 +130,13 @@ struct EyeTrackingCalibrationView: View {
|
||||
.padding()
|
||||
.background(Color.black.opacity(0.5))
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Calibration Target
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
private func calibrationTarget(for step: CalibrationStep) -> some View {
|
||||
let position = targetPosition(for: step)
|
||||
|
||||
|
||||
VStack(spacing: 20) {
|
||||
// Target circle with countdown
|
||||
ZStack {
|
||||
@@ -141,29 +145,31 @@ struct EyeTrackingCalibrationView: View {
|
||||
.stroke(Color.blue.opacity(0.3), lineWidth: 3)
|
||||
.frame(width: 100, height: 100)
|
||||
.scaleEffect(isCountingDown ? 1.2 : 1.0)
|
||||
.animation(.easeInOut(duration: 0.6).repeatForever(autoreverses: true), value: isCountingDown)
|
||||
|
||||
.animation(
|
||||
.easeInOut(duration: 0.6).repeatForever(autoreverses: true),
|
||||
value: isCountingDown)
|
||||
|
||||
// Inner circle
|
||||
Circle()
|
||||
.fill(Color.blue)
|
||||
.frame(width: 60, height: 60)
|
||||
|
||||
|
||||
// Countdown number or checkmark
|
||||
if isCountingDown && countdownValue > 0 {
|
||||
Text("\(countdownValue)")
|
||||
.font(.system(size: 36, weight: .bold))
|
||||
.foregroundColor(.white)
|
||||
.foregroundStyle(.white)
|
||||
} else if calibrationManager.samplesCollected > 0 {
|
||||
Image(systemName: "checkmark")
|
||||
.font(.system(size: 30, weight: .bold))
|
||||
.foregroundColor(.white)
|
||||
.foregroundStyle(.white)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Instruction text
|
||||
Text(step.instructionText)
|
||||
.font(.title2)
|
||||
.foregroundColor(.white)
|
||||
.foregroundStyle(.white)
|
||||
.padding(.horizontal, 40)
|
||||
.padding(.vertical, 15)
|
||||
.background(Color.black.opacity(0.7))
|
||||
@@ -174,15 +180,15 @@ struct EyeTrackingCalibrationView: View {
|
||||
startStepCountdown()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Skip Button
|
||||
|
||||
|
||||
private var skipButton: some View {
|
||||
Button {
|
||||
calibrationManager.skipStep()
|
||||
} label: {
|
||||
Text("Skip this position")
|
||||
.foregroundColor(.white)
|
||||
.foregroundStyle(.white)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 10)
|
||||
.background(Color.white.opacity(0.2))
|
||||
@@ -190,17 +196,17 @@ struct EyeTrackingCalibrationView: View {
|
||||
}
|
||||
.padding(.bottom, 40)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
|
||||
private func startCalibration() {
|
||||
calibrationManager.startCalibration()
|
||||
}
|
||||
|
||||
|
||||
private func startStepCountdown() {
|
||||
countdownValue = 3
|
||||
isCountingDown = true
|
||||
|
||||
|
||||
// Countdown 3, 2, 1
|
||||
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
|
||||
if countdownValue > 0 {
|
||||
@@ -211,16 +217,16 @@ struct EyeTrackingCalibrationView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func targetPosition(for step: CalibrationStep) -> CGPoint {
|
||||
let screenBounds = NSScreen.main?.frame ?? CGRect(x: 0, y: 0, width: 1920, height: 1080)
|
||||
let width = screenBounds.width
|
||||
let height = screenBounds.height
|
||||
|
||||
|
||||
let centerX = width / 2
|
||||
let centerY = height / 2
|
||||
let margin: CGFloat = 150
|
||||
|
||||
|
||||
switch step {
|
||||
case .center:
|
||||
return CGPoint(x: centerX, y: centerY)
|
||||
@@ -253,15 +259,16 @@ struct EyeTrackingCalibrationView: View {
|
||||
struct InstructionRow: View {
|
||||
let icon: String
|
||||
let text: String
|
||||
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 15) {
|
||||
Image(systemName: icon)
|
||||
.font(.title2)
|
||||
.foregroundColor(.blue)
|
||||
.foregroundStyle(.blue)
|
||||
.frame(width: 30)
|
||||
|
||||
|
||||
Text(text)
|
||||
.foregroundStyle(.white)
|
||||
.font(.body)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user