forked from firka/firka
firka: add grade summary bar with dropdown under subjects chart
This commit is contained in:
@@ -4,6 +4,29 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:firka/ui/theme/style.dart';
|
import 'package:firka/ui/theme/style.dart';
|
||||||
import 'package:firka/ui/components/grade_helpers.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 {
|
class GradeWidget extends StatelessWidget {
|
||||||
final Grade grade;
|
final Grade grade;
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,21 @@ Color getGradeColor(double grade) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(int total, List<int> countsByGrade) getGradeDistribution(List<Grade> 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<Grade> {
|
extension GradeListExtension on List<Grade> {
|
||||||
double getAverageBySubject(Subject subject) {
|
double getAverageBySubject(Subject subject) {
|
||||||
var weightTotal = 0.00;
|
var weightTotal = 0.00;
|
||||||
|
|||||||
@@ -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/firka_card.dart';
|
||||||
import 'package:firka/ui/components/grade_helpers.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_chart.dart';
|
||||||
|
import 'package:firka/ui/phone/widgets/grade_summary_bar.dart';
|
||||||
import 'package:firka/ui/shared/grade_small_card.dart';
|
import 'package:firka/ui/shared/grade_small_card.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@@ -242,7 +243,12 @@ class _HomeGradesScreen extends FirkaState<HomeGradesScreen> {
|
|||||||
ChartInteractionScope.of(context).value = false,
|
ChartInteractionScope.of(context).value = false,
|
||||||
child: GradeChart(grades: grades?.response ?? []),
|
child: GradeChart(grades: grades?.response ?? []),
|
||||||
),
|
),
|
||||||
// ...gradeCards,
|
SizedBox(height: 2),
|
||||||
|
GradeSummaryBar(
|
||||||
|
grades: grades?.response ?? [],
|
||||||
|
l10n: widget.data.l10n,
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView(
|
child: ListView(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
115
firka/lib/ui/phone/widgets/grade_summary_bar.dart
Normal file
115
firka/lib/ui/phone/widgets/grade_summary_bar.dart
Normal file
@@ -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<Grade> grades;
|
||||||
|
final AppLocalizations l10n;
|
||||||
|
|
||||||
|
const GradeSummaryBar({super.key, required this.grades, required this.l10n});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<GradeSummaryBar> createState() => _GradeSummaryBarState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GradeSummaryBarState extends State<GradeSummaryBar> {
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user