refactor: extract category logic into CategorySelectionViewModel

This commit is contained in:
2025-08-24 20:38:55 +02:00
parent bde826f5c1
commit c8f634a2ee
4 changed files with 50 additions and 46 deletions

View File

@@ -1,7 +1,44 @@
//
// CategorySelectionViewModel..swift
// CategorySelectionViewModel.swift
// QuizApp
//
// Created by Paul Nowotka on 23.08.25.
// Created by Paul on 23.08.25.
//
import Foundation
class CategorySelectionViewModel: ObservableObject {
private var allQuestionsByCategory: [String: [QuizQuestion]] = [:]
var availableCategories: [String] {
return Array(allQuestionsByCategory.keys).sorted()
}
init() {
loadQuestions()
}
private func loadQuestions() {
guard let url = Bundle.main.url(forResource: "questions", withExtension: "json") else {
print("questions.json nicht gefunden")
return
}
do {
let data = try Data(contentsOf: url)
allQuestionsByCategory = try JSONDecoder().decode([String: [QuizQuestion]].self, from: data)
print("Fragen für Kategorienauswahl geladen")
} catch {
print("Fehler beim Laden der Kategorien: \(error)")
}
}
func highscore(for category: String) -> Int {
let dict = UserDefaults.standard.dictionary(forKey: "categoryHighscores") as? [String: Int] ?? [:]
return dict[category] ?? 0
}
func questions(for category: String) -> [QuizQuestion] {
return allQuestionsByCategory[category] ?? []
}
}

View File

@@ -9,7 +9,6 @@ import Foundation
class ViewModel: ObservableObject {
private var allQuestionsByCategory: [String: [QuizQuestion]] = [:]
@Published var questions: [QuizQuestion] = []
@Published var selectedCategory: String? = nil
@Published var currentQuestionIndex: Int = 0
@@ -36,27 +35,6 @@ class ViewModel: ObservableObject {
return questions[currentQuestionIndex]
}
var availableCategories: [String] {
return Array(allQuestionsByCategory.keys).sorted()
}
init() {
guard let url = Bundle.main.url(forResource: "questions", withExtension: "json") else {
questions = []
return
}
do {
let data = try Data(contentsOf: url)
allQuestionsByCategory = try JSONDecoder().decode([String: [QuizQuestion]].self, from: data)
print("Fragen geladen")
} catch {
print("Fehler beim Laden des Inhalts: \(error)")
allQuestionsByCategory = [:]
}
}
func loadNextQuestion() {
if currentQuestionIndex + 1 < questions.count {
currentQuestionIndex += 1
@@ -65,18 +43,17 @@ class ViewModel: ObservableObject {
}
}
func loadQuestions(for category: String) {
func loadQuestions(questions: [QuizQuestion], for category: String) {
selectedCategory = category
questions = allQuestionsByCategory[category] ?? []
self.questions = questions
currentQuestionIndex = 0
score = 0
isQuizFinished = false
answeredCount = 0
selectedAnswers = Array(repeating: nil, count: questions.count)
print(selectedAnswers)
print("Fragen für Quiz geladen: \(questions.count) Fragen")
}
func incrementScore(selectedIndex: Int) {
if let correct = currentQuestion?.correctAnswer, selectedIndex == correct {
score += 1
@@ -86,8 +63,7 @@ class ViewModel: ObservableObject {
func pointsForEstimation(
guess: Double,
correct: Double,
maxPoints: Int = 1,
maxPoints: Int = 1
) -> Int {
let absError = abs(guess - correct) // Absolute Abweichung
let relError = absError / abs(correct) // Relative Abweichung
@@ -99,11 +75,6 @@ class ViewModel: ObservableObject {
}
}
func highscore(for category: String) -> Int {
let dict = UserDefaults.standard.dictionary(forKey: "categoryHighscores") as? [String: Int] ?? [:]
return dict[category] ?? 0
}
@discardableResult
func updateHighscoreIfNeeded() -> Bool {
guard let category = selectedCategory else { return false }
@@ -116,8 +87,4 @@ class ViewModel: ObservableObject {
}
return false
}
func allHighscores() -> [String: Int] {
UserDefaults.standard.dictionary(forKey: "categoryHighscores") as? [String: Int] ?? [:]
}
}

View File

@@ -8,10 +8,9 @@
import SwiftUI
struct CategorySelectionView: View {
@StateObject private var viewModel = ViewModel()
@StateObject private var categoryViewModel = CategorySelectionViewModel()
@AppStorage("globalScore") var globalScore: Int = 0
var body: some View {
NavigationStack {
VStack(spacing: 24) {
@@ -67,8 +66,8 @@ struct CategorySelectionView: View {
// Liste der Kategorien
VStack(spacing: 12) {
ForEach(viewModel.availableCategories, id: \.self) { category in
NavigationLink(destination: QuizView(viewModel: viewModel, category: category)) {
ForEach(categoryViewModel.availableCategories, id: \.self) { category in
NavigationLink(destination: QuizView(questions: categoryViewModel.questions(for: category), category: category)) {
HStack {
Image(systemName: "play.circle.fill")
.foregroundColor(.blue)
@@ -78,7 +77,7 @@ struct CategorySelectionView: View {
Text(category)
.font(.headline)
.foregroundColor(.primary)
Text("Highscore: \(viewModel.highscore(for: category))")
Text("Highscore: \(categoryViewModel.highscore(for: category))")
.font(.caption)
.foregroundColor(.secondary)
}

View File

@@ -10,10 +10,11 @@ import AudioToolbox
struct QuizView: View {
@ObservedObject var viewModel = ViewModel()
@StateObject var viewModel = ViewModel()
@AppStorage("globalScore") var score: Int = 0
@Environment(\.dismiss) var dismiss
let questions: [QuizQuestion] // Neue Property
let category: String
var body: some View {
@@ -119,7 +120,7 @@ struct QuizView: View {
}
}
.onAppear {
viewModel.loadQuestions(for: category)
viewModel.loadQuestions(questions: questions, for: category)
}
.navigationBarBackButtonHidden(!viewModel.isQuizFinished)
.toolbar {