feat(reports): remove Access/Equity tags, add Data on Enrollment comparison table with JHS/SHS separation and remarks

This commit is contained in:
ssbg04 committed 2026-08-31 21:31:05 +08:00
1 parent da5f5a7b54
commit 36bd41dea2
2 files changed
+433 -114

No files matched your search

+3 -3
View File
@@ -457,14 +457,14 @@ Files backup/restore - mirror mode or zip -->
- table dropdowns only status have dropdown, other convert to icon click to change the sorting order --> - table dropdowns only status have dropdown, other convert to icon click to change the sorting order -->
# REPORT SCREEN # REPORT SCREEN
- Compliance & analytics -> "Students per year" section -> add inactive status - deped transparency board -> remove the access and equity -> change the enrollment by sex & year to data on enrollment which compares the previous year students count and active year students count, difference, and remarks if increasing or decreasing, separate the jhs and shs
- Compliance & analytics -> fix the layout for windows app it has overflow
- Compliance & analytics -> remove the storage chip
--- ---
# DONT DO # DONT DO
- make the admin side that resets user password send into their email the link to reset password add expiration time -> then push notif the admin that successful or not that email link, if not successful or the time has expired send notif to admin, if successfull push notif the user and admin
- teacher no assigned section theme color - teacher no assigned section theme color
- bug in bulk add student enrollment - bug in bulk add student enrollment
@@ -127,22 +127,14 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
], ],
), ),
const SizedBox(height: 8), if (academicYears.isNotEmpty) ...[
Wrap( const SizedBox(height: 8),
spacing: 8, _buildYearSelector(
runSpacing: 6, context,
crossAxisAlignment: WrapCrossAlignment.center, academicYears: academicYears,
children: [ selectedYearId: selectedYearId,
_buildThemeChip('ACCESS', Colors.amber), ),
_buildThemeChip('EQUITY', Colors.lightBlueAccent), ],
if (academicYears.isNotEmpty)
_buildYearSelector(
context,
academicYears: academicYears,
selectedYearId: selectedYearId,
),
],
),
] else ...[ ] else ...[
Row( Row(
children: [ children: [
@@ -163,9 +155,6 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
), ),
), ),
_buildThemeChip('ACCESS', Colors.amber),
const SizedBox(width: 8),
_buildThemeChip('EQUITY', Colors.lightBlueAccent),
if (academicYears.isNotEmpty) ...[ if (academicYears.isNotEmpty) ...[
const SizedBox(width: 12), const SizedBox(width: 12),
_buildYearSelector( _buildYearSelector(
@@ -234,11 +223,11 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// ── Section 1: ACCESS — Enrollment ────────────────────────── // ── Section 1: Data on Enrollment ───────────────────────────
_buildSectionHeader( _buildSectionHeader(
context, context,
icon: Icons.bar_chart, icon: Icons.bar_chart,
label: '1. ACCESS — Enrollment by Sex & Year', label: '1. Data on Enrollment',
color: AppColors.primaryGreen, color: AppColors.primaryGreen,
), ),
const SizedBox(height: AppSizes.p16), const SizedBox(height: AppSizes.p16),
@@ -253,11 +242,11 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
const SizedBox(height: AppSizes.p24), const SizedBox(height: AppSizes.p24),
// ── Section 2: ACCESS — Dropouts & Transferees ─────────────── // ── Section 2: Dropouts & Transferees ────────────────────────
_buildSectionHeader( _buildSectionHeader(
context, context,
icon: Icons.trending_down, icon: Icons.trending_down,
label: '2. ACCESS — Dropouts & Transferees', label: '2. Dropouts & Transferees',
color: Colors.redAccent, color: Colors.redAccent,
), ),
const SizedBox(height: AppSizes.p16), const SizedBox(height: AppSizes.p16),
@@ -272,11 +261,11 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
const SizedBox(height: AppSizes.p24), const SizedBox(height: AppSizes.p24),
// ── Section 3: EQUITY — 4Ps Beneficiaries ──────────────────── // ── Section 3: 4Ps Beneficiaries ─────────────────────────────
_buildSectionHeader( _buildSectionHeader(
context, context,
icon: Icons.family_restroom, icon: Icons.family_restroom,
label: '3. EQUITY — 4Ps Beneficiaries', label: '3. 4Ps Beneficiaries',
color: Colors.deepPurple, color: Colors.deepPurple,
), ),
const SizedBox(height: AppSizes.p16), const SizedBox(height: AppSizes.p16),
@@ -367,24 +356,143 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
// ── Shared Helpers ───────────────────────────────────────────────────────── // ── Shared Helpers ─────────────────────────────────────────────────────────
static Widget _buildThemeChip(String label, Color color) { static Widget _buildDifferenceCell(int? diff, {required bool hasPreviousYear, required bool isDark}) {
return Container( if (!hasPreviousYear || diff == null) {
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), return Text(
decoration: BoxDecoration( '—',
color: color, style: TextStyle(
borderRadius: BorderRadius.circular(20), fontWeight: FontWeight.w600,
), color: isDark ? AppColors.darkTextMuted : Colors.grey,
child: Text(
label,
style: const TextStyle(
color: Colors.black87,
fontSize: 11,
fontWeight: FontWeight.bold,
), ),
);
}
final String text = diff > 0 ? '+$diff' : '$diff';
final Color color = diff > 0
? (isDark ? const Color(0xFF81C784) : const Color(0xFF2E7D32))
: (diff < 0
? (isDark ? const Color(0xFFE57373) : const Color(0xFFC62828))
: (isDark ? AppColors.darkTextSecondary : AppColors.textSecondary));
return Text(
text,
style: TextStyle(
fontWeight: FontWeight.bold,
color: color,
), ),
); );
} }
static Widget _buildRemarkBadge(int? diff, {required bool hasPreviousYear, required bool isDark}) {
if (!hasPreviousYear || diff == null) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: isDark ? AppColors.darkSurface2 : Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isDark ? AppColors.darkBorder : Colors.grey.shade300,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.remove, size: 12, color: isDark ? AppColors.darkTextMuted : Colors.grey.shade600),
const SizedBox(width: 4),
Text(
'Baseline',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: isDark ? AppColors.darkTextSecondary : Colors.grey.shade700,
),
),
],
),
);
}
if (diff > 0) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF1B3828) : const Color(0xFFE8F5E9),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isDark ? const Color(0xFF2E7D32) : const Color(0xFFA5D6A7),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.trending_up, size: 13, color: isDark ? const Color(0xFF81C784) : const Color(0xFF2E7D32)),
const SizedBox(width: 4),
Text(
'Increasing',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: isDark ? const Color(0xFF81C784) : const Color(0xFF2E7D32),
),
),
],
),
);
} else if (diff < 0) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: isDark ? const Color(0xFF3E1F1F) : const Color(0xFFFFEBEE),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isDark ? const Color(0xFFC62828) : const Color(0xFFEF9A9A),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.trending_down, size: 13, color: isDark ? const Color(0xFFE57373) : const Color(0xFFC62828)),
const SizedBox(width: 4),
Text(
'Decreasing',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: isDark ? const Color(0xFFE57373) : const Color(0xFFC62828),
),
),
],
),
);
} else {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: isDark ? AppColors.darkSurface2 : const Color(0xFFF1F5F9),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isDark ? AppColors.darkBorder : const Color(0xFFCBD5E1),
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.trending_flat, size: 13, color: isDark ? AppColors.darkTextSecondary : const Color(0xFF64748B)),
const SizedBox(width: 4),
Text(
'Maintained',
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.bold,
color: isDark ? AppColors.darkTextSecondary : const Color(0xFF64748B),
),
),
],
),
);
}
}
static Widget _buildSectionHeader( static Widget _buildSectionHeader(
BuildContext context, { BuildContext context, {
required IconData icon, required IconData icon,
@@ -480,7 +588,7 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
); );
} }
// ── Section 1: Enrollment ───────────────────────────────────────────────── // ── Section 1: Data on Enrollment ─────────────────────────────────────────
Widget _buildEnrollmentSection( Widget _buildEnrollmentSection(
BuildContext context, BuildContext context,
@@ -491,6 +599,7 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
} }
final isDark = Theme.of(context).brightness == Brightness.dark; final isDark = Theme.of(context).brightness == Brightness.dark;
final latestYear = years.last; final latestYear = years.last;
final previousYear = years.length > 1 ? years[years.length - 2] : null;
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -523,7 +632,9 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
runSpacing: 8, runSpacing: 8,
children: [ children: [
Text( Text(
'Enrollment Summary (SY ${latestYear.yearRange})', previousYear != null
? 'Data on Enrollment (SY ${previousYear.yearRange} vs. SY ${latestYear.yearRange})'
: 'Data on Enrollment (SY ${latestYear.yearRange})',
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -531,7 +642,7 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
), ),
Text( Text(
'Overall Total: ${latestYear.enrollment.overallTotal.total}', 'Active SY Total: ${latestYear.enrollment.overallTotal.total}',
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: AppColors.primaryGreen, color: AppColors.primaryGreen,
@@ -540,7 +651,12 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
], ],
), ),
const SizedBox(height: AppSizes.p12), const SizedBox(height: AppSizes.p12),
_buildEnrollmentTable(context, latestYear.enrollment, isDark: isDark), _buildEnrollmentComparisonTable(
context,
latestYear: latestYear,
previousYear: previousYear,
isDark: isDark,
),
], ],
); );
} }
@@ -779,11 +895,16 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
); );
} }
Widget _buildEnrollmentTable( Widget _buildEnrollmentComparisonTable(
BuildContext context, BuildContext context, {
YearlyEnrollmentSummary summary, { required YearlyTransparencyItem latestYear,
required YearlyTransparencyItem? previousYear,
required bool isDark, required bool isDark,
}) { }) {
final hasPrev = previousYear != null;
final prevLabel = hasPrev ? 'SY ${previousYear.yearRange}' : 'Previous SY';
final currentLabel = 'SY ${latestYear.yearRange}';
Widget tableWidget = Container( Widget tableWidget = Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border.all( border: Border.all(
@@ -793,10 +914,11 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
child: Table( child: Table(
columnWidths: const { columnWidths: const {
0: FlexColumnWidth(2.5), 0: FlexColumnWidth(2.4),
1: FlexColumnWidth(1), 1: FlexColumnWidth(1.2),
2: FlexColumnWidth(1), 2: FlexColumnWidth(1.2),
3: FlexColumnWidth(1), 3: FlexColumnWidth(1.1),
4: FlexColumnWidth(1.4),
}, },
border: TableBorder.symmetric( border: TableBorder.symmetric(
inside: BorderSide( inside: BorderSide(
@@ -806,7 +928,7 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
), ),
), ),
children: [ children: [
// Header // Header Row
TableRow( TableRow(
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.primaryGreen.withValues(alpha: 0.1), color: AppColors.primaryGreen.withValues(alpha: 0.1),
@@ -814,38 +936,50 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
top: Radius.circular(AppSizes.radiusMedium), top: Radius.circular(AppSizes.radiusMedium),
), ),
), ),
children: const [ children: [
Padding( const Padding(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Text( child: Text(
'Key Stage / Grade Level', 'Key Stage / Grade Level',
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
), ),
), ),
Padding( Padding(
padding: EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
'Male', prevLabel,
style: TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
textAlign: TextAlign.center,
), ),
), ),
Padding( Padding(
padding: EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
'Female', currentLabel,
style: TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
textAlign: TextAlign.center,
), ),
), ),
Padding( const Padding(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Text( child: Text(
'Total', 'Difference',
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
textAlign: TextAlign.center,
),
),
const Padding(
padding: EdgeInsets.all(10),
child: Text(
'Remarks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
textAlign: TextAlign.center,
), ),
), ),
], ],
), ),
// Key Stage 3 Header
// ── Key Stage 3 Header ──
TableRow( TableRow(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDark color: isDark
@@ -866,34 +1000,73 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
SizedBox.shrink(), SizedBox.shrink(),
SizedBox.shrink(), SizedBox.shrink(),
SizedBox.shrink(), SizedBox.shrink(),
SizedBox.shrink(),
], ],
), ),
// JHS Grades
...summary.grades.where((g) => g.gradeLevel <= 10).map((g) { // JHS Grades 7-10
...[7, 8, 9, 10].map((grade) {
final curr = latestYear.enrollment.grades.firstWhere(
(g) => g.gradeLevel == grade,
orElse: () => GradeEnrollmentBreakdown(
gradeLevel: grade,
male: 0,
female: 0,
total: 0,
),
).total;
final prev = hasPrev
? previousYear.enrollment.grades.firstWhere(
(g) => g.gradeLevel == grade,
orElse: () => GradeEnrollmentBreakdown(
gradeLevel: grade,
male: 0,
female: 0,
total: 0,
),
).total
: null;
final diff = hasPrev ? (curr - (prev ?? 0)) : null;
return TableRow( return TableRow(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text('Grade ${g.gradeLevel}'), child: Text('Grade $grade'),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(g.male.toString()),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(g.female.toString()),
), ),
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
g.total.toString(), hasPrev ? '$prev' : '—',
style: const TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
'$curr',
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: _buildDifferenceCell(diff, hasPreviousYear: hasPrev, isDark: isDark),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
child: Center(
child: _buildRemarkBadge(diff, hasPreviousYear: hasPrev, isDark: isDark),
), ),
), ),
], ],
); );
}), }),
// JHS Subtotal Row // JHS Subtotal Row
TableRow( TableRow(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -903,37 +1076,59 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
const Padding( const Padding(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Text( child: Text(
'Key Stage 3 Total', 'Key Stage 3 (JHS) Total',
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
summary.jhsTotal.male.toString(), hasPrev ? '${previousYear.enrollment.jhsTotal.total}' : '—',
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
summary.jhsTotal.female.toString(), '${latestYear.enrollment.jhsTotal.total}',
style: const TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
summary.jhsTotal.total.toString(),
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: AppColors.primaryGreen, color: AppColors.primaryGreen,
), ),
), ),
), ),
Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: _buildDifferenceCell(
hasPrev
? (latestYear.enrollment.jhsTotal.total -
previousYear.enrollment.jhsTotal.total)
: null,
hasPreviousYear: hasPrev,
isDark: isDark,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
child: Center(
child: _buildRemarkBadge(
hasPrev
? (latestYear.enrollment.jhsTotal.total -
previousYear.enrollment.jhsTotal.total)
: null,
hasPreviousYear: hasPrev,
isDark: isDark,
),
),
),
], ],
), ),
// Key Stage 4 Header
// ── Key Stage 4 Header ──
TableRow( TableRow(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isDark color: isDark
@@ -954,34 +1149,73 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
SizedBox.shrink(), SizedBox.shrink(),
SizedBox.shrink(), SizedBox.shrink(),
SizedBox.shrink(), SizedBox.shrink(),
SizedBox.shrink(),
], ],
), ),
// SHS Grades
...summary.grades.where((g) => g.gradeLevel > 10).map((g) { // SHS Grades 11-12
...[11, 12].map((grade) {
final curr = latestYear.enrollment.grades.firstWhere(
(g) => g.gradeLevel == grade,
orElse: () => GradeEnrollmentBreakdown(
gradeLevel: grade,
male: 0,
female: 0,
total: 0,
),
).total;
final prev = hasPrev
? previousYear.enrollment.grades.firstWhere(
(g) => g.gradeLevel == grade,
orElse: () => GradeEnrollmentBreakdown(
gradeLevel: grade,
male: 0,
female: 0,
total: 0,
),
).total
: null;
final diff = hasPrev ? (curr - (prev ?? 0)) : null;
return TableRow( return TableRow(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text('Grade ${g.gradeLevel}'), child: Text('Grade $grade'),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(g.male.toString()),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(g.female.toString()),
), ),
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
g.total.toString(), hasPrev ? '$prev' : '—',
style: const TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
'$curr',
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: _buildDifferenceCell(diff, hasPreviousYear: hasPrev, isDark: isDark),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
child: Center(
child: _buildRemarkBadge(diff, hasPreviousYear: hasPrev, isDark: isDark),
), ),
), ),
], ],
); );
}), }),
// SHS Subtotal Row // SHS Subtotal Row
TableRow( TableRow(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -991,41 +1225,126 @@ class _TransparencyBoardContentState extends ConsumerState<_TransparencyBoardCon
const Padding( const Padding(
padding: EdgeInsets.all(10), padding: EdgeInsets.all(10),
child: Text( child: Text(
'Key Stage 4 Total', 'Key Stage 4 (SHS) Total',
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
summary.shsTotal.male.toString(), hasPrev ? '${previousYear.enrollment.shsTotal.total}' : '—',
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
), ),
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: Text( child: Text(
summary.shsTotal.female.toString(), '${latestYear.enrollment.shsTotal.total}',
style: const TextStyle(fontWeight: FontWeight.bold), textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
summary.shsTotal.total.toString(),
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: AppColors.primaryGreen, color: AppColors.primaryGreen,
), ),
), ),
), ),
Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: _buildDifferenceCell(
hasPrev
? (latestYear.enrollment.shsTotal.total -
previousYear.enrollment.shsTotal.total)
: null,
hasPreviousYear: hasPrev,
isDark: isDark,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
child: Center(
child: _buildRemarkBadge(
hasPrev
? (latestYear.enrollment.shsTotal.total -
previousYear.enrollment.shsTotal.total)
: null,
hasPreviousYear: hasPrev,
isDark: isDark,
),
),
),
],
),
// ── Overall Total Row ──
TableRow(
decoration: BoxDecoration(
color: AppColors.primaryGreen.withValues(alpha: 0.12),
),
children: [
const Padding(
padding: EdgeInsets.all(10),
child: Text(
'Overall Total (JHS + SHS)',
style: TextStyle(
fontWeight: FontWeight.bold,
color: AppColors.primaryGreen,
),
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
hasPrev ? '${previousYear.enrollment.overallTotal.total}' : '—',
textAlign: TextAlign.center,
style: const TextStyle(fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Text(
'${latestYear.enrollment.overallTotal.total}',
textAlign: TextAlign.center,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: AppColors.primaryGreen,
),
),
),
Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: _buildDifferenceCell(
hasPrev
? (latestYear.enrollment.overallTotal.total -
previousYear.enrollment.overallTotal.total)
: null,
hasPreviousYear: hasPrev,
isDark: isDark,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 8),
child: Center(
child: _buildRemarkBadge(
hasPrev
? (latestYear.enrollment.overallTotal.total -
previousYear.enrollment.overallTotal.total)
: null,
hasPreviousYear: hasPrev,
isDark: isDark,
),
),
),
], ],
), ),
], ],
), ),
); );
return _responsiveTable(child: tableWidget, minWidth: 580); return _responsiveTable(child: tableWidget, minWidth: 620);
} }
// ── Section 2: Dropouts & Transferees ────────────────────────────────────── // ── Section 2: Dropouts & Transferees ──────────────────────────────────────