feat(gamification): integrate gamification into app — badge celebration overlay, history stats+badges tabs
This commit is contained in:
parent
58dde35cc9
commit
40fd63e748
@ -7,20 +7,34 @@ import WidgetKit
|
|||||||
struct ChronoMindApp: App {
|
struct ChronoMindApp: App {
|
||||||
@StateObject private var timerStore = TimerStore()
|
@StateObject private var timerStore = TimerStore()
|
||||||
@StateObject private var notificationManager = CMNotificationManager.shared
|
@StateObject private var notificationManager = CMNotificationManager.shared
|
||||||
|
@StateObject private var gamification = GamificationStore.shared
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
ZStack {
|
||||||
.environmentObject(timerStore)
|
ContentView()
|
||||||
.environmentObject(notificationManager)
|
.environmentObject(timerStore)
|
||||||
.preferredColorScheme(.dark)
|
.environmentObject(notificationManager)
|
||||||
.task {
|
.environmentObject(gamification)
|
||||||
notificationManager.registerCategories()
|
.preferredColorScheme(.dark)
|
||||||
await notificationManager.requestPermission()
|
.task {
|
||||||
}
|
notificationManager.registerCategories()
|
||||||
.onReceive(NotificationCenter.default.publisher(for: .chronoMindTimersDidChange)) { _ in
|
await notificationManager.requestPermission()
|
||||||
WidgetCenter.shared.reloadAllTimelines()
|
}
|
||||||
|
.onReceive(NotificationCenter.default.publisher(for: .chronoMindTimersDidChange)) { _ in
|
||||||
|
WidgetCenter.shared.reloadAllTimelines()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Badge celebration overlay
|
||||||
|
if let badge = gamification.newBadge {
|
||||||
|
BadgeCelebrationOverlay(badge: badge) {
|
||||||
|
gamification.clearNewBadge()
|
||||||
|
}
|
||||||
|
.transition(.opacity)
|
||||||
|
.zIndex(100)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.animation(.easeInOut, value: gamification.newBadge != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ struct HistoryView: View {
|
|||||||
enum HistorySegment: String, CaseIterable {
|
enum HistorySegment: String, CaseIterable {
|
||||||
case recent = "Recent"
|
case recent = "Recent"
|
||||||
case stats = "Stats"
|
case stats = "Stats"
|
||||||
|
case badges = "Badges"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var completedTimers: [CMTimer] {
|
private var completedTimers: [CMTimer] {
|
||||||
@ -39,6 +40,8 @@ struct HistoryView: View {
|
|||||||
recentList
|
recentList
|
||||||
case .stats:
|
case .stats:
|
||||||
statsView
|
statsView
|
||||||
|
case .badges:
|
||||||
|
badgesView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,6 +90,20 @@ struct HistoryView: View {
|
|||||||
private var statsView: some View {
|
private var statsView: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack(spacing: CMSpacing.lg) {
|
VStack(spacing: CMSpacing.lg) {
|
||||||
|
// Streak card
|
||||||
|
StreakCard()
|
||||||
|
|
||||||
|
// Focus score
|
||||||
|
let focusScore = GamificationEngine.calculateFocusScore(timers: store.timers)
|
||||||
|
FocusScoreCard(score: focusScore)
|
||||||
|
|
||||||
|
// Weekly summary card (shareable)
|
||||||
|
let summary = GamificationEngine.generateWeeklySummary(
|
||||||
|
timers: store.timers,
|
||||||
|
streak: GamificationStore.shared.streak
|
||||||
|
)
|
||||||
|
WeeklySummaryCard(summary: summary)
|
||||||
|
|
||||||
// Summary cards
|
// Summary cards
|
||||||
let allTimers = store.timers
|
let allTimers = store.timers
|
||||||
let completed = allTimers.filter { $0.state == .completed }.count
|
let completed = allTimers.filter { $0.state == .completed }.count
|
||||||
@ -166,6 +183,22 @@ struct HistoryView: View {
|
|||||||
.padding(.bottom, CMSpacing.xxl)
|
.padding(.bottom, CMSpacing.xxl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Badges View
|
||||||
|
|
||||||
|
private var badgesView: some View {
|
||||||
|
ScrollView {
|
||||||
|
VStack(spacing: CMSpacing.lg) {
|
||||||
|
// Streak card (compact)
|
||||||
|
StreakCard()
|
||||||
|
|
||||||
|
// Badge grid
|
||||||
|
BadgeGridView()
|
||||||
|
}
|
||||||
|
.padding(.horizontal, CMSpacing.lg)
|
||||||
|
.padding(.bottom, CMSpacing.xxl)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Stat Card
|
// MARK: - Stat Card
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user