feat: replace Leaderboard with Highscore

This commit is contained in:
2025-08-11 19:08:28 +02:00
parent a7907d59b9
commit de8547749c
4 changed files with 48 additions and 114 deletions

View File

@@ -91,4 +91,26 @@ class ViewModel: ObservableObject {
return 0
}
}
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 }
var dict = UserDefaults.standard.dictionary(forKey: "categoryHighscores") as? [String: Int] ?? [:]
let oldScore = dict[category] ?? 0
if score > oldScore {
dict[category] = score
UserDefaults.standard.set(dict, forKey: "categoryHighscores")
return true
}
return false
}
func allHighscores() -> [String: Int] {
UserDefaults.standard.dictionary(forKey: "categoryHighscores") as? [String: Int] ?? [:]
}
}

View File

@@ -10,11 +10,7 @@ import SwiftUI
struct CategorySelectionView: View {
@StateObject private var viewModel = ViewModel()
@AppStorage("globalScore") var globalScore: Int = 0
@State private var boardData: [[String: Any]] = []
private func loadBoardData() {
boardData = UserDefaults.standard.array(forKey: "leaderboard") as? [[String: Any]] ?? []
}
var body: some View {
NavigationStack {
@@ -78,9 +74,14 @@ struct CategorySelectionView: View {
.foregroundColor(.blue)
.font(.title2)
Text(category)
.font(.headline)
.foregroundColor(.primary)
VStack(alignment: .leading, spacing: 4) {
Text(category)
.font(.headline)
.foregroundColor(.primary)
Text("Highscore: \(viewModel.highscore(for: category))")
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
@@ -103,58 +104,11 @@ struct CategorySelectionView: View {
}
.padding(.horizontal)
// Scoreboard
Text("Leaderboard")
.font(.title2)
.fontWeight(.semibold)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal)
if !boardData.isEmpty {
VStack(spacing: 8) {
ForEach(Array(boardData.prefix(5).enumerated()), id: \.offset) { index, scoreData in
HStack {
Text("\(index + 1).")
.font(.headline)
.foregroundColor(index < 3 ? .orange : .primary)
.frame(width: 25, alignment: .leading)
Text(scoreData["name"] as? String ?? "Unbekannt")
.font(.body)
.foregroundColor(.primary)
Spacer()
Text("\(scoreData["score"] as? Int ?? 0) Punkte")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.blue)
}
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(
RoundedRectangle(cornerRadius: 12)
.fill(Color(.systemGray6))
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(Color(.systemGray4), lineWidth: 1)
)
)
}
}
.padding(.horizontal)
} else {
Text("Keine Leadboard Daten...")
}
Spacer()
}
.background(Color.white)
.navigationBarHidden(true)
.navigationTitle("Quiz-Auswahl")
.onAppear {
loadBoardData()
}
}
}
}

View File

@@ -10,41 +10,36 @@ import SwiftUI
struct QuizFinishedView: View {
let score: Int
let total: Int
@Binding var playerName: String
let isNewHighscore: Bool
let onPlayAgain: () -> Void
let onBackToCategories: () -> Void
let onSaveScore: () -> Void
var body: some View {
VStack(spacing: 20) {
Text("🎉 Quiz beendet!")
.font(.title)
Text("Dein Ergebnis: \(score) von \(total) Punkten")
.font(.headline)
if isNewHighscore {
Text("🔥 Neuer Highscore!")
.font(.headline)
.foregroundColor(.orange)
}
Button("Nochmal spielen", action: onPlayAgain)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
Button("Zurück zur Kategorieauswahl", action: onBackToCategories)
.padding()
.background(Color.gray)
.foregroundColor(.white)
.cornerRadius(10)
TextField("Dein Name:", text: $playerName)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding(.horizontal)
Button("Score speichern", action: onSaveScore)
.padding()
.background(playerName.isEmpty ? Color.gray : Color.green)
.foregroundColor(.white)
.cornerRadius(10)
.disabled(playerName.isEmpty)
}
}
}

View File

@@ -19,8 +19,7 @@ struct QuizView: View {
@State private var selectedAnswerIndex: Int? = nil
@State private var isAnswered = false
@State private var showExitAlert = false
@State private var playerName: String = ""
@State private var scoreIsSaved = false
@State private var isNewHighscore = false
@State private var estimationValue: Double = 0
@State private var estimationSubmitted: Bool = false
@@ -32,17 +31,15 @@ struct QuizView: View {
QuizFinishedView(
score: viewModel.score,
total: viewModel.questions.count,
playerName: $playerName,
isNewHighscore: isNewHighscore,
onPlayAgain: { restartQuiz() },
onBackToCategories: { dismiss() },
onSaveScore: {
saveScore()
dismiss()
}
onBackToCategories: { dismiss() }
)
.onAppear {
AudioServicesPlaySystemSound(1322)
score += viewModel.score
// Highscore prüfen/setzen
isNewHighscore = viewModel.updateHighscoreIfNeeded()
}
.onDisappear {
viewModel.isQuizFinished = false
@@ -131,10 +128,7 @@ struct QuizView: View {
}
}
.onAppear {
// Fragen für die Kategorie
if viewModel.selectedCategory != category {
viewModel.loadQuestions(for: category)
}
viewModel.loadQuestions(for: category)
}
.navigationBarBackButtonHidden(!viewModel.isQuizFinished)
.toolbar {
@@ -206,37 +200,6 @@ struct QuizView: View {
}
}
}
private func saveScore() {
// Bestehende Scores laden
var savedScores = UserDefaults.standard.array(forKey: "leaderboard") as? [[String: Any]] ?? []
// Neuen Score hinzufügen
let newScore: [String: Any] = [
"name": playerName,
"score": viewModel.score,
"date": Date()
]
savedScores.append(newScore)
// Nach Score sortieren
savedScores.sort { score1, score2 in
let score1Value = score1["score"] as? Int ?? 0
let score2Value = score2["score"] as? Int ?? 0
return score1Value > score2Value
}
// Nur die besten 10 Scores behalten
if savedScores.count > 5 {
savedScores = Array(savedScores.prefix(10))
}
UserDefaults.standard.set(savedScores, forKey: "leaderboard")
scoreIsSaved = true
print("Score gespeichert: \(playerName) - \(viewModel.score) Punkte")
}
}
#Preview {