fix: some restructuring
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// Topic.swift
|
// QuizQuestion.swift
|
||||||
// QuizApp
|
// QuizApp
|
||||||
//
|
//
|
||||||
// Created by Paul on 03.08.25.
|
// Created by Paul on 03.08.25.
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class ViewModel: ObservableObject {
|
|||||||
isQuizFinished = false
|
isQuizFinished = false
|
||||||
answeredCount = 0
|
answeredCount = 0
|
||||||
selectedAnswers = Array(repeating: nil, count: questions.count)
|
selectedAnswers = Array(repeating: nil, count: questions.count)
|
||||||
|
print(selectedAnswers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -74,4 +75,24 @@ class ViewModel: ObservableObject {
|
|||||||
score += 1
|
score += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pointsForEstimation(
|
||||||
|
guess: Double,
|
||||||
|
correct: Double,
|
||||||
|
minValue: Double,
|
||||||
|
maxValue: Double,
|
||||||
|
maxPoints: Int = 3,
|
||||||
|
thresholdPercent: Double = 0.3
|
||||||
|
) -> Int {
|
||||||
|
let span = maxValue - minValue
|
||||||
|
guard span > 0 else { return 0 }
|
||||||
|
|
||||||
|
let absError = abs(guess - correct)
|
||||||
|
let relError = absError / span
|
||||||
|
|
||||||
|
if relError >= thresholdPercent { return 0 }
|
||||||
|
|
||||||
|
let ratio = 1.0 - (relError / thresholdPercent)
|
||||||
|
return max(0, Int(round(Double(maxPoints) * ratio)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,36 +72,33 @@ struct CategorySelectionView: View {
|
|||||||
// Liste der Kategorien
|
// Liste der Kategorien
|
||||||
VStack(spacing: 12) {
|
VStack(spacing: 12) {
|
||||||
ForEach(viewModel.availableCategories, id: \.self) { category in
|
ForEach(viewModel.availableCategories, id: \.self) { category in
|
||||||
NavigationLink(destination: ContentView(viewModel: viewModel)
|
NavigationLink(destination: ContentView(viewModel: viewModel, category: category)) {
|
||||||
.onAppear {
|
HStack {
|
||||||
viewModel.loadQuestions(for: category)
|
Image(systemName: "play.circle.fill")
|
||||||
}) {
|
.foregroundColor(.blue)
|
||||||
HStack {
|
.font(.title2)
|
||||||
Image(systemName: "play.circle.fill")
|
|
||||||
.foregroundColor(.blue)
|
|
||||||
.font(.title2)
|
|
||||||
|
|
||||||
Text(category)
|
Text(category)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.foregroundColor(.primary)
|
.foregroundColor(.primary)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
Image(systemName: "chevron.right")
|
Image(systemName: "chevron.right")
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
.background(
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.fill(Color(.systemGray6))
|
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 12)
|
|
||||||
.stroke(Color(.systemGray4), lineWidth: 1)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.buttonStyle(PlainButtonStyle())
|
.padding()
|
||||||
|
.background(
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.fill(Color(.systemGray6))
|
||||||
|
.overlay(
|
||||||
|
RoundedRectangle(cornerRadius: 12)
|
||||||
|
.stroke(Color(.systemGray4), lineWidth: 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
@@ -161,3 +158,7 @@ struct CategorySelectionView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
CategorySelectionView()
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ struct ContentView: View {
|
|||||||
@AppStorage("globalScore") var score: Int = 0
|
@AppStorage("globalScore") var score: Int = 0
|
||||||
@Environment(\.dismiss) var dismiss
|
@Environment(\.dismiss) var dismiss
|
||||||
|
|
||||||
|
let category: String
|
||||||
|
|
||||||
@State private var selectedAnswerIndex: Int? = nil
|
@State private var selectedAnswerIndex: Int? = nil
|
||||||
@State private var isAnswered = false
|
@State private var isAnswered = false
|
||||||
@State private var showExitAlert = false
|
@State private var showExitAlert = false
|
||||||
@@ -48,7 +50,7 @@ struct ContentView: View {
|
|||||||
score: viewModel.score,
|
score: viewModel.score,
|
||||||
currentIndex: viewModel.currentQuestionIndex,
|
currentIndex: viewModel.currentQuestionIndex,
|
||||||
total: viewModel.questions.count,
|
total: viewModel.questions.count,
|
||||||
colorForStep: { idx in colorForAnswer(at: idx) } // nutzt deine bestehende Funktion
|
colorForStep: { idx in colorForAnswer(at: idx) }
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(frage.question)
|
Text(frage.question)
|
||||||
@@ -66,6 +68,7 @@ struct ContentView: View {
|
|||||||
maxValue: maxV,
|
maxValue: maxV,
|
||||||
correctValue: correctV,
|
correctValue: correctV,
|
||||||
unit: frage.unit ?? "",
|
unit: frage.unit ?? "",
|
||||||
|
viewModel: viewModel,
|
||||||
value: $estimationValue,
|
value: $estimationValue,
|
||||||
submitted: $estimationSubmitted,
|
submitted: $estimationSubmitted,
|
||||||
gainedPoints: $estimationPoints
|
gainedPoints: $estimationPoints
|
||||||
@@ -123,9 +126,15 @@ struct ContentView: View {
|
|||||||
Text("Fragen werden geladen...")
|
Text("Fragen werden geladen...")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.navigationBarBackButtonHidden(!viewModel.isQuizFinished) // Button verstecken bei aktivem Quiz
|
.onAppear {
|
||||||
|
// Fragen für die Kategorie
|
||||||
|
if viewModel.selectedCategory != category {
|
||||||
|
viewModel.loadQuestions(for: category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationBarBackButtonHidden(!viewModel.isQuizFinished)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
if !viewModel.isQuizFinished { // Custom Button nur bei aktivem Quiz
|
if !viewModel.isQuizFinished {
|
||||||
ToolbarItem(placement: .navigationBarLeading) {
|
ToolbarItem(placement: .navigationBarLeading) {
|
||||||
Button("Abbrechen") {
|
Button("Abbrechen") {
|
||||||
showExitAlert = true
|
showExitAlert = true
|
||||||
@@ -167,7 +176,7 @@ struct ContentView: View {
|
|||||||
viewModel.selectedAnswers = Array(repeating: nil, count: viewModel.questions.count)
|
viewModel.selectedAnswers = Array(repeating: nil, count: viewModel.questions.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
func colorForAnswer(at index: Int) -> Color {
|
private func colorForAnswer(at index: Int) -> Color {
|
||||||
if index == viewModel.currentQuestionIndex,
|
if index == viewModel.currentQuestionIndex,
|
||||||
viewModel.selectedAnswers[index] == nil {
|
viewModel.selectedAnswers[index] == nil {
|
||||||
return Color.blue // aktuelle Frage
|
return Color.blue // aktuelle Frage
|
||||||
@@ -213,17 +222,6 @@ struct ContentView: View {
|
|||||||
|
|
||||||
print("Score gespeichert: \(playerName) - \(viewModel.score) Punkte")
|
print("Score gespeichert: \(playerName) - \(viewModel.score) Punkte")
|
||||||
}
|
}
|
||||||
|
|
||||||
private func pointsForEstimation(guess: Double, correct: Double, minValue: Double, maxValue: Double, maxPoints: Int = 3, thresholdPercent: Double = 0.3) -> Int {
|
|
||||||
let span = maxValue - minValue
|
|
||||||
guard span > 0 else { return 0 }
|
|
||||||
let absError = abs(guess - correct)
|
|
||||||
let relError = absError / span
|
|
||||||
if relError >= thresholdPercent { return 0 }
|
|
||||||
let ratio = 1.0 - (relError / thresholdPercent)
|
|
||||||
return max(0, Int(round(Double(maxPoints) * ratio)))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
//
|
//
|
||||||
// Created by Paul on 08.08.25.
|
// Created by Paul on 08.08.25.
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct EstimationQuestionView: View {
|
struct EstimationQuestionView: View {
|
||||||
@@ -12,6 +11,7 @@ struct EstimationQuestionView: View {
|
|||||||
let maxValue: Double
|
let maxValue: Double
|
||||||
let correctValue: Double
|
let correctValue: Double
|
||||||
let unit: String
|
let unit: String
|
||||||
|
let viewModel: ViewModel
|
||||||
|
|
||||||
@Binding var value: Double
|
@Binding var value: Double
|
||||||
@Binding var submitted: Bool
|
@Binding var submitted: Bool
|
||||||
@@ -45,7 +45,7 @@ struct EstimationQuestionView: View {
|
|||||||
|
|
||||||
if !submitted {
|
if !submitted {
|
||||||
Button {
|
Button {
|
||||||
gainedPoints = pointsForEstimation(
|
gainedPoints = viewModel.pointsForEstimation(
|
||||||
guess: value,
|
guess: value,
|
||||||
correct: correctValue,
|
correct: correctValue,
|
||||||
minValue: minValue,
|
minValue: minValue,
|
||||||
@@ -80,20 +80,3 @@ struct EstimationQuestionView: View {
|
|||||||
.padding(.horizontal)
|
.padding(.horizontal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func pointsForEstimation(
|
|
||||||
guess: Double,
|
|
||||||
correct: Double,
|
|
||||||
minValue: Double,
|
|
||||||
maxValue: Double,
|
|
||||||
maxPoints: Int = 3,
|
|
||||||
thresholdPercent: Double = 0.3
|
|
||||||
) -> Int {
|
|
||||||
let span = maxValue - minValue
|
|
||||||
guard span > 0 else { return 0 }
|
|
||||||
let absError = abs(guess - correct)
|
|
||||||
let relError = absError / span
|
|
||||||
if relError >= thresholdPercent { return 0 }
|
|
||||||
let ratio = 1.0 - (relError / thresholdPercent)
|
|
||||||
return max(0, Int(round(Double(maxPoints) * ratio)))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ struct QuizHeader: View {
|
|||||||
Text("Punkte: \(score)")
|
Text("Punkte: \(score)")
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
|
|
||||||
|
// Fortschrittsbalken
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
ForEach(0..<total, id: \.self) { idx in
|
ForEach(0..<total, id: \.self) { idx in
|
||||||
Rectangle()
|
Rectangle()
|
||||||
|
|||||||
Reference in New Issue
Block a user