145 lines
3.8 KiB
Dart
145 lines
3.8 KiB
Dart
import 'package:hive/hive.dart';
|
|
|
|
part 'user_progress.g.dart';
|
|
|
|
@HiveType(typeId: 1)
|
|
class UserProgress extends HiveObject {
|
|
@HiveField(0)
|
|
int totalPoints;
|
|
|
|
@HiveField(1)
|
|
int currentPoints;
|
|
|
|
@HiveField(2)
|
|
DateTime? lastCheckInDate;
|
|
|
|
@HiveField(3)
|
|
int consecutiveCheckIns;
|
|
|
|
@HiveField(4)
|
|
Map<String, DateTime> unlockedAchievements;
|
|
|
|
@HiveField(5)
|
|
int totalFocusMinutes;
|
|
|
|
@HiveField(6)
|
|
int totalDistractions;
|
|
|
|
@HiveField(7)
|
|
int totalSessions;
|
|
|
|
@HiveField(8)
|
|
List<DateTime> checkInHistory;
|
|
|
|
UserProgress({
|
|
this.totalPoints = 0,
|
|
this.currentPoints = 0,
|
|
this.lastCheckInDate,
|
|
this.consecutiveCheckIns = 0,
|
|
Map<String, DateTime>? unlockedAchievements,
|
|
this.totalFocusMinutes = 0,
|
|
this.totalDistractions = 0,
|
|
this.totalSessions = 0,
|
|
List<DateTime>? checkInHistory,
|
|
}) : unlockedAchievements = unlockedAchievements ?? {},
|
|
checkInHistory = checkInHistory ?? [];
|
|
|
|
/// Get current level based on total points
|
|
int get level {
|
|
return LevelSystem.getLevel(totalPoints);
|
|
}
|
|
|
|
/// Get progress to next level (0.0 - 1.0)
|
|
double get levelProgress {
|
|
return LevelSystem.getLevelProgress(totalPoints);
|
|
}
|
|
|
|
/// Get points needed to reach next level
|
|
int get pointsToNextLevel {
|
|
return LevelSystem.getPointsToNextLevel(totalPoints);
|
|
}
|
|
|
|
/// Check if checked in today
|
|
bool get hasCheckedInToday {
|
|
if (lastCheckInDate == null) return false;
|
|
final now = DateTime.now();
|
|
return lastCheckInDate!.year == now.year &&
|
|
lastCheckInDate!.month == now.month &&
|
|
lastCheckInDate!.day == now.day;
|
|
}
|
|
|
|
/// Get longest check-in streak from history
|
|
int get longestCheckInStreak {
|
|
if (checkInHistory.isEmpty) return 0;
|
|
|
|
int maxStreak = 1;
|
|
int currentStreak = 1;
|
|
|
|
// Sort dates
|
|
final sortedDates = List<DateTime>.from(checkInHistory)
|
|
..sort((a, b) => a.compareTo(b));
|
|
|
|
for (int i = 1; i < sortedDates.length; i++) {
|
|
final diff = sortedDates[i].difference(sortedDates[i - 1]).inDays;
|
|
if (diff == 1) {
|
|
currentStreak++;
|
|
maxStreak = currentStreak > maxStreak ? currentStreak : maxStreak;
|
|
} else {
|
|
currentStreak = 1;
|
|
}
|
|
}
|
|
|
|
return maxStreak;
|
|
}
|
|
}
|
|
|
|
/// Level system configuration
|
|
class LevelSystem {
|
|
static const List<int> levelThresholds = [
|
|
0, // Level 0 → 1: 0 points
|
|
50, // Level 1 → 2: 50 points
|
|
150, // Level 2 → 3: 150 points
|
|
300, // Level 3 → 4: 300 points
|
|
500, // Level 4 → 5: 500 points
|
|
800, // Level 5 → 6: 800 points
|
|
1200, // Level 6 → 7: 1200 points
|
|
1800, // Level 7 → 8: 1800 points
|
|
2500, // Level 8 → 9: 2500 points
|
|
3500, // Level 9 → 10: 3500 points
|
|
];
|
|
|
|
static int getLevel(int points) {
|
|
for (int i = levelThresholds.length - 1; i >= 0; i--) {
|
|
if (points >= levelThresholds[i]) {
|
|
return i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static double getLevelProgress(int points) {
|
|
int currentLevel = getLevel(points);
|
|
if (currentLevel >= levelThresholds.length - 1) return 1.0;
|
|
|
|
int currentThreshold = levelThresholds[currentLevel];
|
|
int nextThreshold = levelThresholds[currentLevel + 1];
|
|
|
|
return (points - currentThreshold) / (nextThreshold - currentThreshold);
|
|
}
|
|
|
|
static int getPointsToNextLevel(int points) {
|
|
int currentLevel = getLevel(points);
|
|
if (currentLevel >= levelThresholds.length - 1) return 0;
|
|
|
|
return levelThresholds[currentLevel + 1] - points;
|
|
}
|
|
|
|
static int getNextLevelThreshold(int points) {
|
|
int currentLevel = getLevel(points);
|
|
if (currentLevel >= levelThresholds.length - 1) {
|
|
return levelThresholds.last;
|
|
}
|
|
return levelThresholds[currentLevel + 1];
|
|
}
|
|
}
|