diff --git a/firka/lib/ui/components/grade.dart b/firka/lib/ui/components/grade.dart index c363b96..8458176 100644 --- a/firka/lib/ui/components/grade.dart +++ b/firka/lib/ui/components/grade.dart @@ -4,6 +4,29 @@ import 'package:flutter/material.dart'; import 'package:firka/ui/theme/style.dart'; import 'package:firka/ui/components/grade_helpers.dart'; +class GradeIconWidget extends StatelessWidget { + final int gradeValue; + + const GradeIconWidget(this.gradeValue, {super.key}); + + @override + Widget build(BuildContext context) { + final gradeColor = getGradeColor(gradeValue.toDouble()); + return Card( + shape: const CircleBorder(), + shadowColor: Colors.transparent, + color: gradeColor.withAlpha(38), + child: Padding( + padding: const EdgeInsets.only(left: 8, right: 8), + child: Text( + gradeValue.toString(), + style: appStyle.fonts.H_H1.copyWith(fontSize: 24, color: gradeColor), + ), + ), + ); + } +} + class GradeWidget extends StatelessWidget { final Grade grade; diff --git a/firka/lib/ui/components/grade_helpers.dart b/firka/lib/ui/components/grade_helpers.dart index f211c6c..3c5f774 100644 --- a/firka/lib/ui/components/grade_helpers.dart +++ b/firka/lib/ui/components/grade_helpers.dart @@ -60,6 +60,21 @@ Color getGradeColor(double grade) { } } +(int total, List countsByGrade) getGradeDistribution(List grades) { + final filtered = grades + .where((g) => g.type.name != "felevi_jegy_ertekeles") + .toList(); + final counts = [0, 0, 0, 0, 0]; + for (final g in filtered) { + if (g.numericValue == null) continue; + final value = g.valueType.name == "Szazalekos" + ? percentageToGrade(g.numericValue!.round()) + : g.numericValue!.round().clamp(1, 5); + counts[value - 1]++; + } + return (filtered.length, counts); +} + extension GradeListExtension on List { double getAverageBySubject(Subject subject) { var weightTotal = 0.00; diff --git a/firka/lib/ui/phone/pages/home/home_grades.dart b/firka/lib/ui/phone/pages/home/home_grades.dart index d5e52a4..a349f38 100644 --- a/firka/lib/ui/phone/pages/home/home_grades.dart +++ b/firka/lib/ui/phone/pages/home/home_grades.dart @@ -5,6 +5,7 @@ import 'package:firka/routing/chart_interaction_scope.dart'; import 'package:firka/ui/components/firka_card.dart'; import 'package:firka/ui/components/grade_helpers.dart'; import 'package:firka/ui/phone/widgets/grade_chart.dart'; +import 'package:firka/ui/phone/widgets/grade_summary_bar.dart'; import 'package:firka/ui/shared/grade_small_card.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -242,7 +243,12 @@ class _HomeGradesScreen extends FirkaState { ChartInteractionScope.of(context).value = false, child: GradeChart(grades: grades?.response ?? []), ), - // ...gradeCards, + SizedBox(height: 2), + GradeSummaryBar( + grades: grades?.response ?? [], + l10n: widget.data.l10n, + ), + SizedBox(height: 12), Expanded( child: ListView( children: [ diff --git a/firka/lib/ui/phone/widgets/grade_summary_bar.dart b/firka/lib/ui/phone/widgets/grade_summary_bar.dart new file mode 100644 index 0000000..42c43ea --- /dev/null +++ b/firka/lib/ui/phone/widgets/grade_summary_bar.dart @@ -0,0 +1,115 @@ +import 'package:firka/api/model/grade.dart'; +import 'package:firka/ui/components/grade.dart'; +import 'package:firka/ui/components/grade_helpers.dart'; +import 'package:firka/ui/shared/firka_icon.dart'; +import 'package:flutter/material.dart'; +import 'package:majesticons_flutter/majesticons_flutter.dart'; + +import 'package:firka/l10n/app_localizations.dart'; +import 'package:firka/ui/theme/style.dart'; + +class GradeSummaryBar extends StatefulWidget { + final List grades; + final AppLocalizations l10n; + + const GradeSummaryBar({super.key, required this.grades, required this.l10n}); + + @override + State createState() => _GradeSummaryBarState(); +} + +class _GradeSummaryBarState extends State { + bool _expanded = false; + + @override + Widget build(BuildContext context) { + final (total, countsByGrade) = getGradeDistribution(widget.grades); + final gradeColors = [ + appStyle.colors.grade1, + appStyle.colors.grade2, + appStyle.colors.grade3, + appStyle.colors.grade4, + appStyle.colors.grade5, + ]; + final totalCounted = countsByGrade.reduce((a, b) => a + b); + + return Card( + shadowColor: Colors.transparent, + color: appStyle.colors.a15p, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + child: InkWell( + onTap: () => setState(() => _expanded = !_expanded), + borderRadius: BorderRadius.circular(16), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Text( + widget.l10n.gradesCount(total), + style: appStyle.fonts.B_16SB.apply( + color: appStyle.colors.textPrimary, + ), + ), + const SizedBox(width: 12), + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Row( + children: List.generate(5, (i) { + final flex = totalCounted > 0 ? countsByGrade[i] : 1; + return Expanded( + flex: flex, + child: Container(height: 10, color: gradeColors[i]), + ); + }), + ), + ), + ), + const SizedBox(width: 12), + FirkaIconWidget( + FirkaIconType.majesticons, + _expanded + ? Majesticon.chevronUpLine + : Majesticon.chevronDownLine, + color: appStyle.colors.textPrimary, + size: 24, + ), + ], + ), + if (_expanded) ...[ + const SizedBox(height: 12), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: List.generate(5, (i) { + final grade = i + 1; + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + width: 32, + height: 32, + child: FittedBox(child: GradeIconWidget(grade)), + ), + const SizedBox(width: 4), + Text( + countsByGrade[i].toString(), + style: appStyle.fonts.B_16SB.apply( + color: appStyle.colors.textPrimary, + ), + ), + ], + ); + }), + ), + ], + ], + ), + ), + ), + ); + } +}