fead: new leaderboard
This commit is contained in:
@@ -10,6 +10,11 @@ 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 {
|
||||
@@ -58,7 +63,7 @@ struct CategorySelectionView: View {
|
||||
.padding(.horizontal)
|
||||
|
||||
// Kategorien Header
|
||||
Text("Verfügbare Quiz")
|
||||
Text("Kategorien")
|
||||
.font(.title2)
|
||||
.fontWeight(.semibold)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -71,22 +76,64 @@ struct CategorySelectionView: View {
|
||||
.onAppear {
|
||||
viewModel.loadQuestions(for: category)
|
||||
}) {
|
||||
HStack {
|
||||
Image(systemName: "play.circle.fill")
|
||||
.foregroundColor(.blue)
|
||||
.font(.title2)
|
||||
HStack {
|
||||
Image(systemName: "play.circle.fill")
|
||||
.foregroundColor(.blue)
|
||||
.font(.title2)
|
||||
|
||||
Text(category)
|
||||
Text(category)
|
||||
.font(.headline)
|
||||
.foregroundColor(.primary)
|
||||
|
||||
Spacer()
|
||||
|
||||
Image(systemName: "chevron.right")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
}
|
||||
.padding()
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Color(.systemGray6))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Color(.systemGray4), lineWidth: 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
}
|
||||
.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()
|
||||
|
||||
Image(systemName: "chevron.right")
|
||||
.foregroundColor(.secondary)
|
||||
.font(.caption)
|
||||
Text("\(scoreData["score"] as? Int ?? 0) Punkte")
|
||||
.font(.body)
|
||||
.fontWeight(.medium)
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
.padding()
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 8)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Color(.systemGray6))
|
||||
@@ -94,18 +141,23 @@ struct CategorySelectionView: View {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Color(.systemGray4), lineWidth: 1)
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
}
|
||||
.padding(.horizontal)
|
||||
} else {
|
||||
Text("Keine Leadboard Daten...")
|
||||
}
|
||||
.padding(.horizontal)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.background(Color.white)
|
||||
.navigationBarHidden(true)
|
||||
.navigationTitle("Quiz-Auswahl")
|
||||
.onAppear {
|
||||
loadBoardData()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ struct ContentView: 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
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
@@ -38,11 +40,26 @@ struct ContentView: View {
|
||||
|
||||
Button("Zurück zur Kategorieauswahl") {
|
||||
dismiss()
|
||||
|
||||
}
|
||||
.padding()
|
||||
.background(Color.gray)
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(10)
|
||||
|
||||
TextField("Dein Name:", text: $playerName)
|
||||
.textFieldStyle(RoundedBorderTextFieldStyle())
|
||||
.padding(.horizontal)
|
||||
|
||||
Button("Score speichern") {
|
||||
saveScore()
|
||||
dismiss()
|
||||
}
|
||||
.padding()
|
||||
.background(playerName.isEmpty ? Color.gray : Color.green)
|
||||
.foregroundColor(.white)
|
||||
.cornerRadius(10)
|
||||
.disabled(playerName.isEmpty)
|
||||
}
|
||||
.onAppear {
|
||||
AudioServicesPlaySystemSound(1322)
|
||||
@@ -186,6 +203,37 @@ struct ContentView: View {
|
||||
let correct = viewModel.questions[index].correctAnswer
|
||||
return selected == correct ? .green : .red
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user