152 lines
4.8 KiB
Dart
152 lines
4.8 KiB
Dart
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
|
|
/// Model para estatísticas do usuário (aluno)
|
|
class UserStats {
|
|
final String userId;
|
|
final int currentStreak;
|
|
final int longestStreak;
|
|
final int totalStudyTime; // em minutos
|
|
final DateTime? lastActivityDate;
|
|
final int weeklyStudyTime; // minutos esta semana
|
|
final int monthlyStudyTime; // minutos este mês
|
|
final int completedQuizzes; // total de quizzes completos
|
|
final List<MasteredConcept> masteredConcepts;
|
|
final List<UnlockedAchievement> unlockedAchievements;
|
|
|
|
const UserStats({
|
|
required this.userId,
|
|
required this.currentStreak,
|
|
required this.longestStreak,
|
|
required this.totalStudyTime,
|
|
required this.weeklyStudyTime,
|
|
required this.monthlyStudyTime,
|
|
required this.completedQuizzes,
|
|
required this.masteredConcepts,
|
|
required this.unlockedAchievements,
|
|
this.lastActivityDate,
|
|
});
|
|
|
|
factory UserStats.fromFirestore(Map<String, dynamic> data, String userId) {
|
|
return UserStats(
|
|
userId: userId,
|
|
currentStreak: data['currentStreak'] ?? 0,
|
|
longestStreak: data['longestStreak'] ?? 0,
|
|
totalStudyTime: data['totalStudyTime'] ?? 0,
|
|
lastActivityDate: (data['lastActivityDate'] as Timestamp?)?.toDate(),
|
|
weeklyStudyTime: data['weeklyStudyTime'] ?? 0,
|
|
monthlyStudyTime: data['monthlyStudyTime'] ?? 0,
|
|
completedQuizzes: data['completedQuizzes'] ?? 0,
|
|
masteredConcepts: (data['masteredConcepts'] as List<dynamic>?)
|
|
?.map((c) => MasteredConcept.fromFirestore(c))
|
|
.toList() ??
|
|
[],
|
|
unlockedAchievements: (data['unlockedAchievements'] as List<dynamic>?)
|
|
?.map((a) => UnlockedAchievement.fromFirestore(a))
|
|
.toList() ??
|
|
[],
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toFirestore() {
|
|
final data = {
|
|
'currentStreak': currentStreak,
|
|
'longestStreak': longestStreak,
|
|
'totalStudyTime': totalStudyTime,
|
|
'weeklyStudyTime': weeklyStudyTime,
|
|
'monthlyStudyTime': monthlyStudyTime,
|
|
'completedQuizzes': completedQuizzes,
|
|
'masteredConcepts': masteredConcepts.map((c) => c.toFirestore()).toList(),
|
|
'unlockedAchievements': unlockedAchievements.map((a) => a.toFirestore()).toList(),
|
|
};
|
|
|
|
if (lastActivityDate != null) {
|
|
data['lastActivityDate'] = Timestamp.fromDate(lastActivityDate!);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
UserStats copyWith({
|
|
int? currentStreak,
|
|
int? longestStreak,
|
|
int? totalStudyTime,
|
|
DateTime? lastActivityDate,
|
|
int? weeklyStudyTime,
|
|
int? monthlyStudyTime,
|
|
int? completedQuizzes,
|
|
List<MasteredConcept>? masteredConcepts,
|
|
List<UnlockedAchievement>? unlockedAchievements,
|
|
}) {
|
|
return UserStats(
|
|
userId: userId,
|
|
currentStreak: currentStreak ?? this.currentStreak,
|
|
longestStreak: longestStreak ?? this.longestStreak,
|
|
totalStudyTime: totalStudyTime ?? this.totalStudyTime,
|
|
lastActivityDate: lastActivityDate ?? this.lastActivityDate,
|
|
weeklyStudyTime: weeklyStudyTime ?? this.weeklyStudyTime,
|
|
monthlyStudyTime: monthlyStudyTime ?? this.monthlyStudyTime,
|
|
completedQuizzes: completedQuizzes ?? this.completedQuizzes,
|
|
masteredConcepts: masteredConcepts ?? this.masteredConcepts,
|
|
unlockedAchievements: unlockedAchievements ?? this.unlockedAchievements,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Conceito dominado pelo aluno
|
|
class MasteredConcept {
|
|
final String conceptName;
|
|
final DateTime masteredAt;
|
|
final int masteryLevel; // 0-100
|
|
|
|
const MasteredConcept({
|
|
required this.conceptName,
|
|
required this.masteredAt,
|
|
required this.masteryLevel,
|
|
});
|
|
|
|
factory MasteredConcept.fromFirestore(Map<String, dynamic> data) {
|
|
return MasteredConcept(
|
|
conceptName: data['conceptName'] ?? '',
|
|
masteredAt: (data['masteredAt'] as Timestamp?)?.toDate() ?? DateTime.now(),
|
|
masteryLevel: data['masteryLevel'] ?? 0,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toFirestore() {
|
|
return {
|
|
'conceptName': conceptName,
|
|
'masteredAt': Timestamp.fromDate(masteredAt),
|
|
'masteryLevel': masteryLevel,
|
|
};
|
|
}
|
|
}
|
|
|
|
/// Conquista desbloqueada pelo aluno
|
|
class UnlockedAchievement {
|
|
final String achievementId;
|
|
final DateTime unlockedAt;
|
|
final Map<String, dynamic> metadata;
|
|
|
|
const UnlockedAchievement({
|
|
required this.achievementId,
|
|
required this.unlockedAt,
|
|
required this.metadata,
|
|
});
|
|
|
|
factory UnlockedAchievement.fromFirestore(Map<String, dynamic> data) {
|
|
return UnlockedAchievement(
|
|
achievementId: data['achievementId'] ?? '',
|
|
unlockedAt: (data['unlockedAt'] as Timestamp?)?.toDate() ?? DateTime.now(),
|
|
metadata: data['metadata'] ?? {},
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toFirestore() {
|
|
return {
|
|
'achievementId': achievementId,
|
|
'unlockedAt': Timestamp.fromDate(unlockedAt),
|
|
'metadata': metadata,
|
|
};
|
|
}
|
|
}
|