Finalização de detalhes e pequenas adições em dashboards de alunos e professores
This commit is contained in:
@@ -23,6 +23,8 @@ class AnalyticsPage extends StatefulWidget {
|
||||
class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late TabController _tabController;
|
||||
final _classSearchController = TextEditingController();
|
||||
String _classSearchQuery = '';
|
||||
List<ClassStats> _classStats = [];
|
||||
bool _loading = true;
|
||||
String? _selectedClassId;
|
||||
@@ -38,6 +40,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
@override
|
||||
void dispose() {
|
||||
_tabController.dispose();
|
||||
_classSearchController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -46,7 +49,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
final user = AuthService.currentUser;
|
||||
if (user == null) return;
|
||||
|
||||
// Obter disciplinas do professor
|
||||
// Obter turmas do professor
|
||||
final classesSnapshot = await FirebaseFirestore.instance
|
||||
.collection('classes')
|
||||
.where('teacherId', isEqualTo: user.uid)
|
||||
@@ -85,7 +88,6 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final themeExtras = AppThemeExtras.of(context);
|
||||
final cs = Theme.of(context).colorScheme;
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
@@ -94,9 +96,9 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
context.go('/teacher-dashboard');
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: cs.surface,
|
||||
backgroundColor: Colors.transparent,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Container(
|
||||
body: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
@@ -106,6 +108,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
// Header
|
||||
@@ -137,7 +140,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Acompanhe o desempenho das disciplinas',
|
||||
'Acompanhe o desempenho das turmas',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.8),
|
||||
fontSize: 16,
|
||||
@@ -163,7 +166,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
indicatorColor: Colors.white,
|
||||
indicatorWeight: 2,
|
||||
tabs: const [
|
||||
Tab(text: 'Disciplinas'),
|
||||
Tab(text: 'Turmas'),
|
||||
Tab(text: 'Alunos'),
|
||||
],
|
||||
),
|
||||
@@ -205,7 +208,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Nenhuma disciplina encontrada',
|
||||
'Nenhuma turma encontrada',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.7),
|
||||
fontSize: 18,
|
||||
@@ -213,7 +216,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Crie disciplinas para ver as analytics aqui',
|
||||
'Crie turmas para ver as analytics aqui',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.5),
|
||||
fontSize: 14,
|
||||
@@ -224,47 +227,131 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
);
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Overview Cards
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildOverviewCard(
|
||||
'Total de Alunos',
|
||||
'${_classStats.fold(0, (sum, stats) => sum + stats.totalStudents)}',
|
||||
Icons.people,
|
||||
Colors.blue,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildOverviewCard(
|
||||
'Alunos Ativos',
|
||||
'${_classStats.fold(0, (sum, stats) => sum + stats.activeStudents)}',
|
||||
Icons.trending_up,
|
||||
Colors.green,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
final filtered = _classSearchQuery.isEmpty
|
||||
? _classStats
|
||||
: _classStats
|
||||
.where(
|
||||
(s) => s.className.toLowerCase().contains(_classSearchQuery),
|
||||
)
|
||||
.toList();
|
||||
|
||||
// Class Cards
|
||||
..._classStats.map(
|
||||
(stats) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: ClassAnalyticsCard(
|
||||
classStats: stats,
|
||||
onTap: () => _showClassStudents(stats),
|
||||
return CustomScrollView(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 0),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Column(
|
||||
children: [
|
||||
// Overview Cards
|
||||
Center(
|
||||
child: _buildOverviewCard(
|
||||
'Total de Alunos',
|
||||
'${_classStats.fold(0, (sum, s) => sum + s.totalStudents)}',
|
||||
Icons.people,
|
||||
Colors.blue,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
// Search bar
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 14,
|
||||
vertical: 10,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Colors.white.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.search,
|
||||
color: Colors.white.withValues(alpha: 0.7),
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Theme(
|
||||
data: ThemeData.dark().copyWith(
|
||||
textSelectionTheme: const TextSelectionThemeData(
|
||||
cursorColor: Colors.white,
|
||||
selectionColor: Colors.white24,
|
||||
selectionHandleColor: Colors.white,
|
||||
),
|
||||
),
|
||||
child: TextField(
|
||||
controller: _classSearchController,
|
||||
onChanged: (v) => setState(
|
||||
() => _classSearchQuery = v.trim().toLowerCase(),
|
||||
),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
),
|
||||
cursorColor: Colors.white,
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Pesquisar turma…',
|
||||
hintStyle: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.5),
|
||||
fontSize: 14,
|
||||
),
|
||||
border: InputBorder.none,
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (_classSearchQuery.isNotEmpty)
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_classSearchController.clear();
|
||||
setState(() => _classSearchQuery = '');
|
||||
},
|
||||
child: Icon(
|
||||
Icons.close,
|
||||
color: Colors.white.withValues(alpha: 0.7),
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (filtered.isEmpty)
|
||||
SliverFillRemaining(
|
||||
hasScrollBody: false,
|
||||
child: Center(
|
||||
child: Text(
|
||||
'Nenhuma turma encontrada',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.6),
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
|
||||
sliver: SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) => ClassAnalyticsCard(
|
||||
classStats: filtered[index],
|
||||
onTap: () => _showClassStudents(filtered[index]),
|
||||
),
|
||||
childCount: filtered.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -281,7 +368,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Seleciona uma disciplina',
|
||||
'Seleciona uma turma',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.7),
|
||||
fontSize: 18,
|
||||
@@ -289,7 +376,7 @@ class _AnalyticsPageState extends State<AnalyticsPage>
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Clica numa disciplina no separador "Disciplinas" para ver os alunos',
|
||||
'Clica numa turma no separador "Turmas" para ver os alunos',
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.5),
|
||||
fontSize: 14,
|
||||
|
||||
Reference in New Issue
Block a user