import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hive/hive.dart'; part 'gamification.freezed.dart'; part 'gamification.g.dart'; @HiveType(typeId: 8) @freezed class GamificationStats with _$GamificationStats { const factory GamificationStats({ @HiveField(0) @Default(0) int totalPoints, @HiveField(1) @Default(0) int currentStreak, @HiveField(2) @Default(0) int longestStreak, @HiveField(3) @Default(1) int level, @HiveField(4) @Default([]) List unlockedBadges, @HiveField(5) @Default({}) Map categoryStreaks, @HiveField(6) @Default(0) int routinesCompletedToday, @HiveField(7) @Default(0) int totalRoutinesCompleted, @HiveField(8) @Default(0) int perfectDays, @HiveField(9) required DateTime lastUpdated, }) = _GamificationStats; factory GamificationStats.fromJson(Map json) = _$$GamificationStatsImplFromJson; } @HiveType(typeId: 9) class Badge extends HiveObject { @HiveField(0) final String id; @HiveField(1) final String name; @HiveField(2) final String description; @HiveField(3) final String icon; @HiveField(4) final int pointsRequired; @HiveField(5) final BadgeCategory category; Badge({ required this.id, required this.name, required this.description, required this.icon, required this.pointsRequired, required this.category, }); } @HiveType(typeId: 10) enum BadgeCategory { @HiveField(0) streak, @HiveField(1) completion, @HiveField(2) category, @HiveField(3) special, } // Predefined badges class Badges { static final List all = [ // Streak badges Badge( id: 'streak_3', name: 'Getting Started', description: '3 day streak', icon: '🔥', pointsRequired: 0, category: BadgeCategory.streak, ), Badge( id: 'streak_7', name: 'Week Warrior', description: '7 day streak', icon: '🔥🔥', pointsRequired: 0, category: BadgeCategory.streak, ), Badge( id: 'streak_30', name: 'Monthly Master', description: '30 day streak', icon: '📅', pointsRequired: 0, category: BadgeCategory.streak, ), Badge( id: 'streak_100', name: 'Centurion', description: '100 day streak', icon: '💯', pointsRequired: 0, category: BadgeCategory.streak, ), // Completion badges Badge( id: 'first_routine', name: 'First Step', description: 'Complete your first routine', icon: '👟', pointsRequired: 0, category: BadgeCategory.completion, ), Badge( id: 'routines_10', name: 'Getting Consistent', description: 'Complete 10 routines', icon: '⭐', pointsRequired: 0, category: BadgeCategory.completion, ), Badge( id: 'routines_100', name: 'Century Club', description: 'Complete 100 routines', icon: '🏆', pointsRequired: 0, category: BadgeCategory.completion, ), Badge( id: 'perfect_week', name: 'Perfect Week', description: 'Complete all routines for 7 days', icon: '🌟', pointsRequired: 0, category: BadgeCategory.completion, ), // Category badges Badge( id: 'hydration_master', name: 'Hydration Hero', description: 'Hit water goal 7 days in a row', icon: '💧', pointsRequired: 0, category: BadgeCategory.category, ), Badge( id: 'medication_reliable', name: 'Reliable', description: 'Take medication on time for 14 days', icon: '💊', pointsRequired: 0, category: BadgeCategory.category, ), Badge( id: 'sleep_schedule', name: 'Sleep Master', description: 'Maintain sleep schedule for 7 days', icon: '😴', pointsRequired: 0, category: BadgeCategory.category, ), // Special badges Badge( id: 'early_bird', name: 'Early Bird', description: 'Complete morning routine before 8 AM', icon: '🐦', pointsRequired: 0, category: BadgeCategory.special, ), Badge( id: 'night_owl', name: 'Night Owl', description: 'Complete evening routine after 9 PM', icon: '🦉', pointsRequired: 0, category: BadgeCategory.special, ), ]; } // Level calculation class LevelCalculator { static int calculateLevel(int totalPoints) { // Exponential level curve // Level 1: 0 points // Level 2: 100 points // Level 3: 250 points // Level 4: 450 points // etc. if (totalPoints < 100) return 1; if (totalPoints < 250) return 2; if (totalPoints < 450) return 3; if (totalPoints < 700) return 4; if (totalPoints < 1000) return 5; // Beyond level 5: every 500 points return 5 + ((totalPoints - 1000) ~/ 500); } static int pointsToNextLevel(int currentLevel, int totalPoints) { final nextLevelThreshold = _levelThreshold(currentLevel + 1); return nextLevelThreshold - totalPoints; } static double progressToNextLevel(int currentLevel, int totalPoints) { final currentThreshold = _levelThreshold(currentLevel); final nextThreshold = _levelThreshold(currentLevel + 1); final progress = totalPoints - currentThreshold; final needed = nextThreshold - currentThreshold; return (progress / needed).clamp(0.0, 1.0); } static int _levelThreshold(int level) { switch (level) { case 1: return 0; case 2: return 100; case 3: return 250; case 4: return 450; case 5: return 700; default: return 1000 + ((level - 6) * 500); } } } class BadgeChecker { static List checkUnlockedBadges( GamificationStats stats, List alreadyUnlocked, ) { final newlyUnlocked = []; for (final badge in Badges.all) { if (alreadyUnlocked.contains(badge.id)) continue; if (_meetsCriteria(badge, stats)) { newlyUnlocked.add(badge); } } return newlyUnlocked; } static bool _meetsCriteria(Badge badge, GamificationStats stats) { switch (badge.id) { case 'streak_3': return stats.currentStreak >= 3; case 'streak_7': return stats.currentStreak >= 7; case 'streak_30': return stats.currentStreak >= 30; case 'streak_100': return stats.currentStreak >= 100; case 'routines_10': return stats.totalRoutinesCompleted >= 10; case 'routines_100': return stats.totalRoutinesCompleted >= 100; case 'perfect_week': return stats.perfectDays >= 7; default: return false; } } }