import '../models/user_progress.dart'; import '../models/achievement_config.dart'; /// Service for managing achievements class AchievementService { /// Check for newly unlocked achievements asynchronously /// Returns list of newly unlocked achievement IDs Future> checkAchievementsAsync(UserProgress progress) async { List newlyUnlocked = []; for (var achievement in AchievementConfig.all) { // Skip if already unlocked if (progress.unlockedAchievements.containsKey(achievement.id)) { continue; } // Check if requirement is met bool unlocked = false; switch (achievement.type) { case AchievementType.sessionCount: unlocked = progress.totalSessions >= achievement.requiredValue; break; case AchievementType.distractionCount: unlocked = progress.totalDistractions >= achievement.requiredValue; break; case AchievementType.totalMinutes: unlocked = progress.totalFocusMinutes >= achievement.requiredValue; break; case AchievementType.consecutiveDays: unlocked = progress.consecutiveCheckIns >= achievement.requiredValue; break; } if (unlocked) { // Mark as unlocked with timestamp progress.unlockedAchievements[achievement.id] = DateTime.now(); // Award bonus points progress.totalPoints += achievement.bonusPoints; progress.currentPoints += achievement.bonusPoints; newlyUnlocked.add(achievement.id); } } return newlyUnlocked; } /// Get progress towards a specific achievement (0.0 - 1.0) double getAchievementProgress( UserProgress progress, AchievementConfig achievement, ) { int currentValue = 0; switch (achievement.type) { case AchievementType.sessionCount: currentValue = progress.totalSessions; break; case AchievementType.distractionCount: currentValue = progress.totalDistractions; break; case AchievementType.totalMinutes: currentValue = progress.totalFocusMinutes; break; case AchievementType.consecutiveDays: currentValue = progress.consecutiveCheckIns; break; } return (currentValue / achievement.requiredValue).clamp(0.0, 1.0); } /// Get current value for achievement type int getAchievementCurrentValue( UserProgress progress, AchievementConfig achievement, ) { switch (achievement.type) { case AchievementType.sessionCount: return progress.totalSessions; case AchievementType.distractionCount: return progress.totalDistractions; case AchievementType.totalMinutes: return progress.totalFocusMinutes; case AchievementType.consecutiveDays: return progress.consecutiveCheckIns; } } /// Get all achievements with their current progress Map getAllAchievementsWithProgress( UserProgress progress, ) { final result = {}; for (var achievement in AchievementConfig.all) { result[achievement] = getAchievementProgress(progress, achievement); } return result; } /// Get newly unlocked achievements since last check /// This can be used to show notifications for achievements unlocked in background List getNewlyUnlockedAchievements( UserProgress progress, Set previouslyUnlocked, ) { final currentlyUnlocked = progress.unlockedAchievements.keys.toSet(); return currentlyUnlocked.difference(previouslyUnlocked).toList(); } }