placeholders removidos e todos os dados reais colocados, com conquistas e tudo
This commit is contained in:
@@ -3,13 +3,75 @@ import 'package:flutter/material.dart';
|
||||
import '../../../../core/theme/app_theme_extension.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import '../../../../core/services/auth_service.dart';
|
||||
import '../../../../core/services/gamification_service.dart';
|
||||
import '../../../../core/models/user_stats.dart';
|
||||
import '../../../../core/models/achievement.dart';
|
||||
|
||||
/// Profile section with user info and achievements
|
||||
class ProfileSectionWidget extends StatelessWidget {
|
||||
class ProfileSectionWidget extends StatefulWidget {
|
||||
const ProfileSectionWidget({super.key});
|
||||
|
||||
@override
|
||||
State<ProfileSectionWidget> createState() => _ProfileSectionWidgetState();
|
||||
}
|
||||
|
||||
class _ProfileSectionWidgetState extends State<ProfileSectionWidget> {
|
||||
UserStats? _userStats;
|
||||
List<Achievement> _recentAchievements = [];
|
||||
bool _loading = true;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadUserData();
|
||||
}
|
||||
|
||||
Future<void> _loadUserData() async {
|
||||
try {
|
||||
final user = AuthService.currentUser;
|
||||
if (user != null) {
|
||||
final results = await Future.wait([
|
||||
GamificationService.getUserStats(user.uid),
|
||||
GamificationService.getAvailableAchievements(),
|
||||
]);
|
||||
|
||||
final stats = results[0] as UserStats?;
|
||||
final achievements = results[1] as List<Achievement>;
|
||||
|
||||
// Obter conquistas desbloqueadas recentemente
|
||||
final unlockedAchievementIds = stats?.unlockedAchievements
|
||||
.map((ua) => ua.achievementId)
|
||||
.toSet() ?? {};
|
||||
|
||||
final recentUnlocked = achievements
|
||||
.where((a) => unlockedAchievementIds.contains(a.id))
|
||||
.take(4)
|
||||
.toList();
|
||||
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_userStats = stats;
|
||||
_recentAchievements = recentUnlocked;
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error loading user data: $e');
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_loading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
final user = AuthService.currentUser;
|
||||
final userName = user?.displayName ?? 'Estudante';
|
||||
final userEmail = user?.email ?? '';
|
||||
@@ -124,36 +186,55 @@ class ProfileSectionWidget extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
// Achievement Badges
|
||||
Row(
|
||||
children: [
|
||||
_buildAchievementBadge(
|
||||
icon: Icons.local_fire_department,
|
||||
label: '7 dias',
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildAchievementBadge(
|
||||
icon: Icons.school,
|
||||
label: '3 conceitos',
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildAchievementBadge(
|
||||
icon: Icons.speed,
|
||||
label: 'Rápido',
|
||||
color: Theme.of(
|
||||
// Achievement List (Teacher-style design)
|
||||
if (_recentAchievements.isNotEmpty) ...[
|
||||
..._recentAchievements.map((achievement) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _buildAchievementItem(
|
||||
context,
|
||||
).colorScheme.primary.withOpacity(0.8),
|
||||
achievement.name,
|
||||
achievement.points,
|
||||
_getRarityColor(achievement.rarity),
|
||||
_getIconData(achievement.icon),
|
||||
),
|
||||
);
|
||||
}),
|
||||
] else ...[
|
||||
// Streak item
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _buildAchievementItem(
|
||||
context,
|
||||
'${_userStats?.currentStreak ?? 0} dias seguidos',
|
||||
(_userStats?.currentStreak ?? 0) * 5,
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
Icons.local_fire_department,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildAchievementBadge(
|
||||
icon: Icons.star,
|
||||
label: '100%',
|
||||
color: Theme.of(context).colorScheme.tertiary,
|
||||
),
|
||||
// Concepts item
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _buildAchievementItem(
|
||||
context,
|
||||
'${_userStats?.masteredConcepts.length ?? 0} conceitos dominados',
|
||||
(_userStats?.masteredConcepts.length ?? 0) * 10,
|
||||
Theme.of(context).colorScheme.primary,
|
||||
Icons.school,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (_userStats != null && _userStats!.totalStudyTime > 0)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: _buildAchievementItem(
|
||||
context,
|
||||
'${(_userStats!.totalStudyTime / 60).toStringAsFixed(1)}h estudadas',
|
||||
(_userStats!.totalStudyTime ~/ 60) * 3,
|
||||
Theme.of(context).colorScheme.tertiary,
|
||||
Icons.schedule,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Recent Activity Summary
|
||||
@@ -183,7 +264,7 @@ class ProfileSectionWidget extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Ótimo progresso!',
|
||||
_getProgressMessage(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontSize: 14,
|
||||
@@ -192,7 +273,7 @@ class ProfileSectionWidget extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
'Você está 15% acima da média esta semana',
|
||||
_getProgressComparison(),
|
||||
style: TextStyle(
|
||||
color: Theme.of(
|
||||
context,
|
||||
@@ -217,32 +298,103 @@ class ProfileSectionWidget extends StatelessWidget {
|
||||
.then(delay: const Duration(milliseconds: 400));
|
||||
}
|
||||
|
||||
Widget _buildAchievementBadge({
|
||||
required IconData icon,
|
||||
required String label,
|
||||
required Color color,
|
||||
}) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: color.withOpacity(0.3), width: 1),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Icon(icon, color: color, size: 16),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
label,
|
||||
Widget _buildAchievementItem(
|
||||
BuildContext context,
|
||||
String name,
|
||||
int points,
|
||||
Color color,
|
||||
IconData icon,
|
||||
) {
|
||||
return Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: Center(
|
||||
child: Icon(icon, color: color, size: 16),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
name,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
'$points pts',
|
||||
style: TextStyle(
|
||||
color: color,
|
||||
fontSize: 10,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
IconData _getIconData(String iconName) {
|
||||
switch (iconName) {
|
||||
case 'emoji_events': return Icons.emoji_events;
|
||||
case 'school': return Icons.school;
|
||||
case 'local_fire_department': return Icons.local_fire_department;
|
||||
case 'schedule': return Icons.schedule;
|
||||
case 'trending_up': return Icons.trending_up;
|
||||
case 'military_tech': return Icons.military_tech;
|
||||
case 'workspace_premium': return Icons.workspace_premium;
|
||||
case 'psychology': return Icons.psychology;
|
||||
case 'lightbulb': return Icons.lightbulb;
|
||||
case 'star': return Icons.star;
|
||||
case 'speed': return Icons.speed;
|
||||
default: return Icons.star;
|
||||
}
|
||||
}
|
||||
|
||||
Color _getRarityColor(String rarity) {
|
||||
switch (rarity) {
|
||||
case 'common': return Colors.grey;
|
||||
case 'rare': return Colors.blue;
|
||||
case 'epic': return Colors.purple;
|
||||
case 'legendary': return Colors.orange;
|
||||
default: return Colors.grey;
|
||||
}
|
||||
}
|
||||
|
||||
String _getProgressMessage() {
|
||||
if (_userStats == null) return 'Continue estudando!';
|
||||
|
||||
final streak = _userStats!.currentStreak;
|
||||
final studyTime = _userStats!.totalStudyTime;
|
||||
|
||||
if (streak >= 7) return 'Incrível streak! 🔥';
|
||||
if (studyTime >= 300) return 'Dedicação exemplar! 📚';
|
||||
if (streak >= 3) return 'Bom progresso! 📈';
|
||||
return 'Continue estudando! 💪';
|
||||
}
|
||||
|
||||
String _getProgressComparison() {
|
||||
if (_userStats == null) return 'Comece sua jornada de estudos';
|
||||
|
||||
final weeklyTime = _userStats!.weeklyStudyTime;
|
||||
final concepts = _userStats!.masteredConcepts.length;
|
||||
|
||||
if (weeklyTime >= 180) return 'Você está 15% acima da média esta semana';
|
||||
if (concepts >= 3) return 'Domine $concepts conceitos esta semana';
|
||||
if (weeklyTime >= 60) return 'Bom tempo de estudo esta semana';
|
||||
return 'Continue assim para subir no ranking!';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user