112 lines
3.5 KiB
Dart
112 lines
3.5 KiB
Dart
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<List<String>> checkAchievementsAsync(UserProgress progress) async {
|
|
List<String> 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<AchievementConfig, double> getAllAchievementsWithProgress(
|
|
UserProgress progress,
|
|
) {
|
|
final result = <AchievementConfig, double>{};
|
|
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<String> getNewlyUnlockedAchievements(
|
|
UserProgress progress,
|
|
Set<String> previouslyUnlocked,
|
|
) {
|
|
final currentlyUnlocked = progress.unlockedAchievements.keys.toSet();
|
|
return currentlyUnlocked.difference(previouslyUnlocked).toList();
|
|
}
|
|
}
|