Add files via upload
This commit is contained in:
268
filcnaplo_desktop_ui/lib/pages/grades/grade_subject_view.dart
Normal file
268
filcnaplo_desktop_ui/lib/pages/grades/grade_subject_view.dart
Normal file
@@ -0,0 +1,268 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:animations/animations.dart';
|
||||
import 'package:filcnaplo/utils/format.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo/helpers/average_helper.dart';
|
||||
import 'package:filcnaplo/helpers/subject.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/subject.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/average_display.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/panel/panel.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/trend_display.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/widgets/cretification/certification_tile.dart';
|
||||
import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/widgets/grade/grade_viewable.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/hero_scrollview.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart';
|
||||
import 'package:filcnaplo_desktop_ui/pages/grades/grades_count.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/grades/graph.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/grades/subject_grades_container.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
|
||||
import 'package:flutter_feather_icons/flutter_feather_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'grades_page.i18n.dart';
|
||||
// import 'package:filcnaplo_premium/ui/mobile/goalplanner/new_goal.dart';
|
||||
|
||||
class GradeSubjectView extends StatefulWidget {
|
||||
const GradeSubjectView(this.subject, {Key? key, this.groupAverage = 0.0}) : super(key: key);
|
||||
|
||||
final Subject subject;
|
||||
final double groupAverage;
|
||||
|
||||
void push(BuildContext context, {bool root = false}) {
|
||||
Navigator.of(context, rootNavigator: root).push(CupertinoPageRoute(builder: (context) => this));
|
||||
}
|
||||
|
||||
@override
|
||||
State<GradeSubjectView> createState() => _GradeSubjectViewState();
|
||||
}
|
||||
|
||||
class _GradeSubjectViewState extends State<GradeSubjectView> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
// Controllers
|
||||
PersistentBottomSheetController? _sheetController;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
List<Widget> gradeTiles = [];
|
||||
|
||||
// Providers
|
||||
late GradeProvider gradeProvider;
|
||||
late GradeCalculatorProvider calculatorProvider;
|
||||
|
||||
late double average;
|
||||
late Widget gradeGraph;
|
||||
|
||||
bool gradeCalcMode = false;
|
||||
|
||||
List<Grade> getSubjectGrades(Subject subject) => !gradeCalcMode
|
||||
? gradeProvider.grades.where((e) => e.subject == subject).toList()
|
||||
: calculatorProvider.grades.where((e) => e.subject == subject).toList();
|
||||
|
||||
bool showGraph(List<Grade> subjectGrades) {
|
||||
if (gradeCalcMode) return true;
|
||||
|
||||
final gradeDates = subjectGrades.map((e) => e.date.millisecondsSinceEpoch);
|
||||
final maxGradeDate = gradeDates.fold(0, max);
|
||||
final minGradeDate = gradeDates.fold(0, min);
|
||||
if (maxGradeDate - minGradeDate < const Duration(days: 5).inMilliseconds) return false; // naplo/#78
|
||||
|
||||
return subjectGrades.where((e) => e.type == GradeType.midYear).length > 1;
|
||||
}
|
||||
|
||||
void buildTiles(List<Grade> subjectGrades) {
|
||||
List<Widget> tiles = [];
|
||||
|
||||
if (showGraph(subjectGrades)) {
|
||||
tiles.add(gradeGraph);
|
||||
} else {
|
||||
tiles.add(Container(height: 24.0));
|
||||
}
|
||||
|
||||
List<Widget> _gradeTiles = [];
|
||||
|
||||
if (!gradeCalcMode) {
|
||||
subjectGrades.sort((a, b) => -a.date.compareTo(b.date));
|
||||
for (var grade in subjectGrades) {
|
||||
if (grade.type == GradeType.midYear) {
|
||||
_gradeTiles.add(GradeViewable(grade));
|
||||
} else {
|
||||
_gradeTiles.add(CertificationTile(grade, padding: EdgeInsets.zero));
|
||||
}
|
||||
}
|
||||
} else if (subjectGrades.isNotEmpty) {
|
||||
subjectGrades.sort((a, b) => -a.date.compareTo(b.date));
|
||||
for (var grade in subjectGrades) {
|
||||
_gradeTiles.add(GradeTile(grade));
|
||||
}
|
||||
}
|
||||
tiles.add(
|
||||
PageTransitionSwitcher(
|
||||
transitionBuilder: (
|
||||
Widget child,
|
||||
Animation<double> primaryAnimation,
|
||||
Animation<double> secondaryAnimation,
|
||||
) {
|
||||
return SharedAxisTransition(
|
||||
animation: primaryAnimation,
|
||||
secondaryAnimation: secondaryAnimation,
|
||||
transitionType: SharedAxisTransitionType.vertical,
|
||||
child: child,
|
||||
fillColor: Colors.transparent,
|
||||
);
|
||||
},
|
||||
child: _gradeTiles.isNotEmpty
|
||||
? Panel(
|
||||
key: ValueKey(gradeCalcMode),
|
||||
title: Text(
|
||||
gradeCalcMode ? "Ghost Grades".i18n : "Grades".i18n,
|
||||
),
|
||||
child: Column(
|
||||
children: _gradeTiles,
|
||||
))
|
||||
: const SizedBox(),
|
||||
),
|
||||
);
|
||||
|
||||
tiles.add(Padding(padding: EdgeInsets.only(bottom: !gradeCalcMode ? 24.0 : 250.0)));
|
||||
gradeTiles = List.castFrom(tiles);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
gradeProvider = Provider.of<GradeProvider>(context);
|
||||
calculatorProvider = Provider.of<GradeCalculatorProvider>(context);
|
||||
|
||||
List<Grade> subjectGrades = getSubjectGrades(widget.subject).toList();
|
||||
average = AverageHelper.averageEvals(subjectGrades);
|
||||
final prevAvg = subjectGrades.isNotEmpty
|
||||
? AverageHelper.averageEvals(subjectGrades
|
||||
.where((e) => e.date.isBefore(subjectGrades.reduce((v, e) => e.date.isAfter(v.date) ? e : v).date.subtract(const Duration(days: 30))))
|
||||
.toList())
|
||||
: 0.0;
|
||||
|
||||
gradeGraph = Padding(
|
||||
padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
|
||||
child: Panel(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("annual_average".i18n),
|
||||
if (average != prevAvg) TrendDisplay(current: average, previous: prevAvg),
|
||||
],
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 12.0, right: 12.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: GradeGraph(subjectGrades, dayThreshold: 5, classAvg: widget.groupAverage)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: GradesCount(grades: subjectGrades),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (!gradeCalcMode) {
|
||||
buildTiles(subjectGrades);
|
||||
} else {
|
||||
List<Grade> ghostGrades = calculatorProvider.ghosts.where((e) => e.subject == widget.subject).toList();
|
||||
buildTiles(ghostGrades);
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
floatingActionButtonLocation: ExpandableFab.location,
|
||||
floatingActionButton: Visibility(
|
||||
visible: !gradeCalcMode && subjectGrades.where((e) => e.type == GradeType.midYear).isNotEmpty,
|
||||
child: ExpandableFab(
|
||||
type: ExpandableFabType.up,
|
||||
distance: 50,
|
||||
children: [
|
||||
FloatingActionButton.small(
|
||||
child: const Icon(FeatherIcons.plus),
|
||||
onPressed: () {
|
||||
gradeCalc(context);
|
||||
},
|
||||
),
|
||||
// FloatingActionButton.small(
|
||||
// child: const Icon(FeatherIcons.flag, size: 20.0),
|
||||
// onPressed: () {
|
||||
// Navigator.of(context).push(CupertinoPageRoute(builder: (context) => PremiumGoalplannerNewGoalScreen(subject: widget.subject)));
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () async {},
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
child: HeroScrollView(
|
||||
onClose: () {
|
||||
if (_sheetController != null && gradeCalcMode) {
|
||||
_sheetController!.close();
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
navBarItems: [
|
||||
const SizedBox(width: 6.0),
|
||||
if (widget.groupAverage != 0) Center(child: AverageDisplay(average: widget.groupAverage, border: true)),
|
||||
const SizedBox(width: 6.0),
|
||||
if (average != 0) Center(child: AverageDisplay(average: average)),
|
||||
const SizedBox(width: 12.0),
|
||||
],
|
||||
icon: SubjectIcon.resolveVariant(subject: widget.subject, context: context),
|
||||
scrollController: _scrollController,
|
||||
title: widget.subject.renamedTo ?? widget.subject.name.capital(),
|
||||
italic: widget.subject.isRenamed,
|
||||
child: SubjectGradesContainer(
|
||||
child: CupertinoScrollbar(
|
||||
child: ListView.builder(
|
||||
physics: const BouncingScrollPhysics(),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
shrinkWrap: true,
|
||||
itemBuilder: (context, index) => gradeTiles[index],
|
||||
itemCount: gradeTiles.length,
|
||||
),
|
||||
),
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
void gradeCalc(BuildContext context) {
|
||||
// Scroll to the top of the page
|
||||
_scrollController.animateTo(75, duration: const Duration(milliseconds: 500), curve: Curves.ease);
|
||||
|
||||
calculatorProvider.clear();
|
||||
calculatorProvider.addAllGrades(gradeProvider.grades);
|
||||
|
||||
_sheetController = _scaffoldKey.currentState?.showBottomSheet(
|
||||
(context) => RoundedBottomSheet(child: GradeCalculator(widget.subject), borderRadius: 14.0),
|
||||
backgroundColor: const Color(0x00000000),
|
||||
elevation: 12.0,
|
||||
);
|
||||
|
||||
// Hide the fab and grades
|
||||
setState(() {
|
||||
gradeCalcMode = true;
|
||||
});
|
||||
|
||||
_sheetController!.closed.then((value) {
|
||||
// Show fab and grades
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
gradeCalcMode = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
25
filcnaplo_desktop_ui/lib/pages/grades/grades_count.dart
Normal file
25
filcnaplo_desktop_ui/lib/pages/grades/grades_count.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:filcnaplo_desktop_ui/pages/grades/grades_count_item.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class GradesCount extends StatelessWidget {
|
||||
const GradesCount({Key? key, required this.grades}) : super(key: key);
|
||||
|
||||
final List<Grade> grades;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<int> gradesCount = List.generate(5, (int index) => grades.where((e) => e.value.value == index + 1).length);
|
||||
|
||||
return Container(
|
||||
width: 75,
|
||||
padding: const EdgeInsets.only(bottom: 6.0, top: 6.0, left: 12.0, right: 0.0),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: gradesCount.mapIndexed((index, e) => GradesCountItem(count: e, value: index + 1)).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
37
filcnaplo_desktop_ui/lib/pages/grades/grades_count_item.dart
Normal file
37
filcnaplo_desktop_ui/lib/pages/grades/grades_count_item.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:filcnaplo/ui/widgets/grade/grade_tile.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GradesCountItem extends StatelessWidget {
|
||||
const GradesCountItem({Key? key, required this.count, required this.value}) : super(key: key);
|
||||
|
||||
final int count;
|
||||
final int value;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 2.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text.rich(
|
||||
TextSpan(children: [
|
||||
TextSpan(
|
||||
text: count.toString(),
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const TextSpan(
|
||||
text: "x",
|
||||
style: TextStyle(fontSize: 13.0),
|
||||
),
|
||||
]),
|
||||
style: const TextStyle(fontSize: 15.0),
|
||||
),
|
||||
const SizedBox(width: 5.0),
|
||||
GradeValueWidget(GradeValue(value, "Value", "Value", 100), size: 19.0, fill: true, shadow: false),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
263
filcnaplo_desktop_ui/lib/pages/grades/grades_page.dart
Normal file
263
filcnaplo_desktop_ui/lib/pages/grades/grades_page.dart
Normal file
@@ -0,0 +1,263 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:filcnaplo/api/providers/update_provider.dart';
|
||||
import 'package:filcnaplo_kreta_api/providers/grade_provider.dart';
|
||||
import 'package:filcnaplo/api/providers/user_provider.dart';
|
||||
import 'package:filcnaplo/theme/colors/colors.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/grade.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/subject.dart';
|
||||
import 'package:filcnaplo_kreta_api/models/group_average.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/average_display.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/empty.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/panel/panel.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/widgets/statistics_tile.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/widgets/grade/grade_subject_tile.dart';
|
||||
import 'package:filcnaplo_mobile_ui/common/trend_display.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/grades/fail_warning.dart';
|
||||
import 'package:filcnaplo_desktop_ui/pages/grades/grades_count.dart';
|
||||
import 'package:filcnaplo_mobile_ui/pages/grades/graph.dart';
|
||||
import 'package:filcnaplo_desktop_ui/pages/grades/grade_subject_view.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:filcnaplo/helpers/average_helper.dart';
|
||||
import 'package:filcnaplo_premium/ui/mobile/grades/average_selector.dart';
|
||||
import 'grades_page.i18n.dart';
|
||||
|
||||
class GradesPage extends StatefulWidget {
|
||||
const GradesPage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_GradesPageState createState() => _GradesPageState();
|
||||
}
|
||||
|
||||
class _GradesPageState extends State<GradesPage> {
|
||||
late UserProvider user;
|
||||
late GradeProvider gradeProvider;
|
||||
late UpdateProvider updateProvider;
|
||||
late String firstName;
|
||||
late Widget yearlyGraph;
|
||||
List<Widget> subjectTiles = [];
|
||||
|
||||
int avgDropValue = 0;
|
||||
|
||||
List<Grade> getSubjectGrades(Subject subject, {int days = 0}) => gradeProvider.grades
|
||||
.where(
|
||||
(e) => e.subject == subject && e.type == GradeType.midYear && (days == 0 || e.date.isBefore(DateTime.now().subtract(Duration(days: days)))))
|
||||
.toList();
|
||||
|
||||
void generateTiles() {
|
||||
List<Subject> subjects = gradeProvider.grades.map((e) => e.subject).toSet().toList()..sort((a, b) => a.name.compareTo(b.name));
|
||||
List<Widget> tiles = [];
|
||||
|
||||
Map<Subject, double> subjectAvgs = {};
|
||||
|
||||
tiles.addAll(subjects.map((subject) {
|
||||
List<Grade> subjectGrades = getSubjectGrades(subject);
|
||||
|
||||
double avg = AverageHelper.averageEvals(subjectGrades);
|
||||
double averageBefore = 0.0;
|
||||
|
||||
if (avgDropValue != 0) {
|
||||
List<Grade> gradesBefore = getSubjectGrades(subject, days: avgDropValue);
|
||||
averageBefore = avgDropValue == 0 ? 0.0 : AverageHelper.averageEvals(gradesBefore);
|
||||
}
|
||||
var nullavg = GroupAverage(average: 0.0, subject: subject, uid: "0");
|
||||
double groupAverage = gradeProvider.groupAverages.firstWhere((e) => e.subject == subject, orElse: () => nullavg).average;
|
||||
|
||||
if (avg != 0) subjectAvgs[subject] = avg;
|
||||
|
||||
return GradeSubjectTile(
|
||||
subject,
|
||||
averageBefore: averageBefore,
|
||||
average: avg,
|
||||
groupAverage: avgDropValue == 0 ? groupAverage : 0.0,
|
||||
onTap: () {
|
||||
GradeSubjectView(subject, groupAverage: groupAverage).push(context, root: true);
|
||||
},
|
||||
);
|
||||
}));
|
||||
|
||||
if (tiles.isNotEmpty) {
|
||||
tiles.insert(0, yearlyGraph);
|
||||
tiles.insert(1, FailWarning(subjectAvgs: subjectAvgs));
|
||||
tiles.insert(2, PanelTitle(title: Text(avgDropValue == 0 ? "Subjects".i18n : "Subjects_changes".i18n)));
|
||||
tiles.insert(3, const PanelHeader(padding: EdgeInsets.only(top: 12.0)));
|
||||
tiles.add(const PanelFooter(padding: EdgeInsets.only(bottom: 12.0)));
|
||||
tiles.add(const Padding(padding: EdgeInsets.only(bottom: 24.0)));
|
||||
} else {
|
||||
tiles.insert(
|
||||
0,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 24.0),
|
||||
child: Empty(subtitle: "empty".i18n),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
double subjectAvg = subjectAvgs.isNotEmpty ? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) / subjectAvgs.length : 0.0;
|
||||
final double classAvg = gradeProvider.groupAverages.isNotEmpty
|
||||
? gradeProvider.groupAverages.map((e) => e.average).fold(0.0, (double a, double b) => a + b) / gradeProvider.groupAverages.length
|
||||
: 0.0;
|
||||
|
||||
if (subjectAvg > 0) {
|
||||
tiles.add(Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: StatisticsTile(
|
||||
fill: true,
|
||||
title: AutoSizeText(
|
||||
"subjectavg".i18n,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
value: subjectAvg,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 24.0),
|
||||
Expanded(
|
||||
child: StatisticsTile(
|
||||
outline: true,
|
||||
title: AutoSizeText(
|
||||
"classavg".i18n,
|
||||
textAlign: TextAlign.center,
|
||||
maxLines: 2,
|
||||
wrapWords: false,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
value: classAvg,
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
// padding
|
||||
tiles.add(const SizedBox(height: 32.0));
|
||||
|
||||
subjectTiles = List.castFrom(tiles);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
user = Provider.of<UserProvider>(context);
|
||||
gradeProvider = Provider.of<GradeProvider>(context);
|
||||
updateProvider = Provider.of<UpdateProvider>(context);
|
||||
|
||||
List<String> nameParts = user.displayName?.split(" ") ?? ["?"];
|
||||
firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
|
||||
|
||||
final double totalClassAvg = gradeProvider.groupAverages.isEmpty
|
||||
? 0.0
|
||||
: gradeProvider.groupAverages.map((e) => e.average).fold(0.0, (double a, double b) => a + b) / gradeProvider.groupAverages.length;
|
||||
|
||||
final now = gradeProvider.grades.isNotEmpty ? gradeProvider.grades.reduce((v, e) => e.date.isAfter(v.date) ? e : v).date : DateTime.now();
|
||||
|
||||
final currentStudentAvg = AverageHelper.averageEvals(gradeProvider.grades.where((e) => e.type == GradeType.midYear).toList());
|
||||
final prevStudentAvg = AverageHelper.averageEvals(gradeProvider.grades
|
||||
.where((e) => e.type == GradeType.midYear)
|
||||
.where((e) => e.date.isBefore(now.subtract(const Duration(days: 30))))
|
||||
.toList());
|
||||
|
||||
List<Grade> graphGrades = gradeProvider.grades
|
||||
.where((e) => e.type == GradeType.midYear && (avgDropValue == 0 || e.date.isAfter(DateTime.now().subtract(Duration(days: avgDropValue)))))
|
||||
.toList();
|
||||
|
||||
yearlyGraph = Padding(
|
||||
padding: const EdgeInsets.only(top: 12.0, bottom: 8.0),
|
||||
child: Panel(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
PremiumAverageSelector(
|
||||
value: avgDropValue,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
avgDropValue = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
// if (totalClassAvg >= 1.0) AverageDisplay(average: totalClassAvg, border: true),
|
||||
// const SizedBox(width: 4.0),
|
||||
TrendDisplay(previous: prevStudentAvg, current: currentStudentAvg),
|
||||
if (gradeProvider.grades.where((e) => e.type == GradeType.midYear).isNotEmpty) AverageDisplay(average: currentStudentAvg),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(top: 12.0, right: 12.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: GradeGraph(graphGrades, dayThreshold: 2, classAvg: totalClassAvg)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24.0),
|
||||
child: GradesCount(grades: graphGrades),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
generateTiles();
|
||||
|
||||
return Scaffold(
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.only(top: 9.0),
|
||||
child: NestedScrollView(
|
||||
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
|
||||
headerSliverBuilder: (context, _) => [
|
||||
SliverAppBar(
|
||||
centerTitle: false,
|
||||
pinned: true,
|
||||
floating: false,
|
||||
snap: false,
|
||||
automaticallyImplyLeading: false,
|
||||
surfaceTintColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(left: 8.0),
|
||||
child: Text(
|
||||
"Grades".i18n,
|
||||
style: TextStyle(color: AppColors.of(context).text, fontSize: 32.0, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
shadowColor: Theme.of(context).shadowColor,
|
||||
),
|
||||
],
|
||||
body: RefreshIndicator(
|
||||
onRefresh: () => gradeProvider.fetch(),
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const BouncingScrollPhysics(),
|
||||
itemCount: max(subjectTiles.length, 1),
|
||||
itemBuilder: (context, index) {
|
||||
if (subjectTiles.isNotEmpty) {
|
||||
EdgeInsetsGeometry panelPadding = const EdgeInsets.symmetric(horizontal: 24.0);
|
||||
|
||||
if (subjectTiles[index].runtimeType == GradeSubjectTile) {
|
||||
return Padding(
|
||||
padding: panelPadding,
|
||||
child: PanelBody(
|
||||
child: subjectTiles[index],
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
));
|
||||
} else {
|
||||
return Padding(padding: panelPadding, child: subjectTiles[index]);
|
||||
}
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
60
filcnaplo_desktop_ui/lib/pages/grades/grades_page.i18n.dart
Normal file
60
filcnaplo_desktop_ui/lib/pages/grades/grades_page.i18n.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:i18n_extension/i18n_extension.dart';
|
||||
|
||||
extension Localization on String {
|
||||
static final _t = Translations.byLocale("hu_hu") +
|
||||
{
|
||||
"en_en": {
|
||||
"Grades": "Grades",
|
||||
"Ghost Grades": "Grades",
|
||||
"Subjects": "Subjects",
|
||||
"Subjects_changes": "Subject Differences",
|
||||
"empty": "You don't have any subjects.",
|
||||
"annual_average": "Annual average",
|
||||
"3_months_average": "3 Monthly Average",
|
||||
"30_days_average": "Monthly Average",
|
||||
"14_days_average": "2 Weekly Average",
|
||||
"7_days_average": "Weekly Average",
|
||||
"subjectavg": "Subject Average",
|
||||
"classavg": "Class Average",
|
||||
"fail_warning": "Faliure warning",
|
||||
"fail_warning_description": "You are failing %d subject(s)",
|
||||
},
|
||||
"hu_hu": {
|
||||
"Grades": "Jegyek",
|
||||
"Ghost Grades": "Szellem jegyek",
|
||||
"Subjects": "Tantárgyak",
|
||||
"Subjects_changes": "Tantárgyi változások",
|
||||
"empty": "Még nincs egy tárgyad sem.",
|
||||
"annual_average": "Éves átlag",
|
||||
"3_months_average": "Háromhavi átlag",
|
||||
"30_days_average": "Havi átlag",
|
||||
"14_days_average": "Kétheti átlag",
|
||||
"7_days_average": "Heti átlag",
|
||||
"subjectavg": "Tantárgyi átlag",
|
||||
"classavg": "Osztályátlag",
|
||||
"fail_warning": "Bukás figyelmeztető",
|
||||
"fail_warning_description": "Bukásra állsz %d tantárgyból",
|
||||
},
|
||||
"de_de": {
|
||||
"Grades": "Noten",
|
||||
"Ghost Grades": "Geist Noten",
|
||||
"Subjects": "Fächer",
|
||||
"Subjects_changes": "Betreff Änderungen",
|
||||
"empty": "Sie haben keine Fächer.",
|
||||
"annual_average": "Jahresdurchschnitt",
|
||||
"3_months_average": "Drei-Monats-Durchschnitt",
|
||||
"30_days_average": "Monatsdurchschnitt",
|
||||
"14_days_average": "Vierzehntägiger Durchschnitt",
|
||||
"7_days_average": "Wöchentlicher Durchschnitt",
|
||||
"subjectavg": "Fächer Durchschnitt",
|
||||
"classavg": "Klassendurchschnitt",
|
||||
"fail_warning": "Ausfallwarnung",
|
||||
"fail_warning_description": "Sie werden in %d des Fachs durchfallen",
|
||||
},
|
||||
};
|
||||
|
||||
String get i18n => localize(this, _t);
|
||||
String fill(List<Object> params) => localizeFill(this, params);
|
||||
String plural(int value) => localizePlural(value, this, _t);
|
||||
String version(Object modifier) => localizeVersion(modifier, this, _t);
|
||||
}
|
||||
Reference in New Issue
Block a user