Skip to content

Commit

Permalink
Add charts to subjects
Browse files Browse the repository at this point in the history
  • Loading branch information
FauconSpartiate committed Mar 18, 2024
1 parent 2c94e81 commit a9a86df
Show file tree
Hide file tree
Showing 9 changed files with 639 additions and 61 deletions.
30 changes: 30 additions & 0 deletions lib/calculations/manager.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Flutter imports:
import "package:flutter/material.dart";

// Package imports:
import "package:collection/collection.dart";

// Project imports:
import "package:graded/calculations/subject.dart";
import "package:graded/calculations/term.dart";
Expand Down Expand Up @@ -161,6 +164,33 @@ class Manager {
return yearOverview;
}

//TODO make more use of this function
static List<Subject> getSubjectAcrossTerms(Subject subject) {
final List<Subject> result = [];

for (final term in getCurrentYear().terms) {
final Subject? s = getSubjectInTerm(subject, term);
if (s == null) continue;
result.add(s);
}
return result;
}

static Subject? getSubjectInTerm(Subject? subject, Term term) {
if (subject == null) return null;

final Subject? result = term.subjects.firstWhereOrNull((s) => s.name == subject.name);

if (result != null) return result;

for (final s in term.subjects) {
final Subject? child = s.children.firstWhereOrNull((c) => c.name == subject.name);
if (child != null) return child;
}

throw ArgumentError("Subject not found in term");
}

Map<String, dynamic> toJson() => {
"years": years,
};
Expand Down
7 changes: 6 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "package:device_info_plus/device_info_plus.dart";
import "package:dynamic_color/dynamic_color.dart";
import "package:flutter_displaymode/flutter_displaymode.dart";
import "package:flutter_localizations/flutter_localizations.dart";
import "package:intl/date_symbol_data_local.dart";
import "package:provider/provider.dart";

// Project imports:
Expand Down Expand Up @@ -89,8 +90,11 @@ class _AppContainerState extends State<AppContainer> {
supportedLocales: TranslationsClass.delegate.supportedLocales,
localeResolutionCallback: (deviceLocale, supportedLocales) {
if (supportedLocales.map((e) => e.languageCode).contains(deviceLocale?.languageCode)) {
initializeDateFormatting(deviceLocale?.languageCode);
return deviceLocale;
}

initializeDateFormatting("en_GB");
return const Locale("en", "GB");
},
locale: provider.locale,
Expand Down Expand Up @@ -128,6 +132,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
final CreationType type = (settings.arguments as CreationType?) ?? CreationType.edit;
route = SubjectEditRoute(creationType: type);
case "/subject":
case "/chart":
if (settings.arguments == null) {
throw ArgumentError("No arguments passed to route");
}
Expand All @@ -136,7 +141,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
final Subject subject = arguments[1]!;

route = RouteWidget(
routeType: RouteType.subject,
routeType: settings.name == "/subject" ? RouteType.subject : RouteType.chart,
title: subject.name,
arguments: arguments,
);
Expand Down
144 changes: 144 additions & 0 deletions lib/ui/routes/chart_route.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Dart imports:
import "dart:math";

// Flutter imports:
import "package:flutter/material.dart";

// Package imports:
import "package:sliver_tools/sliver_tools.dart";

// Project imports:
import "package:graded/calculations/manager.dart";
import "package:graded/calculations/subject.dart";
import "package:graded/calculations/term.dart";
import "package:graded/localization/translations.dart";
import "package:graded/ui/utilities/chart_utilities.dart";
import "package:graded/ui/widgets/charts.dart";
import "package:graded/ui/widgets/custom_safe_area.dart";
import "package:graded/ui/widgets/list_widgets.dart";

class ChartRoute extends StatefulWidget {
const ChartRoute({
super.key,
required this.term,
required this.subject,
this.parent,
});

final Term term;
final Subject subject;
final Subject? parent;

@override
State<ChartRoute> createState() => _ChartRouteState();
}

class _ChartRouteState extends State<ChartRoute> {
final ScrollController scrollController = ScrollController();

void rebuild() {
setState(() {});
}

void refreshYearOverview() {
Manager.refreshYearOverview();
rebuild();
}

@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: Builder(
builder: (context) {
return CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
),
CustomSliverSafeArea(
top: false,
maintainBottomViewPadding: true,
sliver: MultiSliver(
children: [
SliverToBoxAdapter(
child: ResultRow(
result: widget.subject.getResult(),
preciseResult: widget.subject.getResult(precise: true),
leading: Text(
translations.yearly_average,
overflow: TextOverflow.fade,
softWrap: false,
style: Theme.of(context).textTheme.titleLarge,
),
),
),
const SliverPadding(padding: EdgeInsets.only(top: 8)),
SliverToBoxAdapter(
child: StandardLineChart(
title: translations.average_over_time,
spots: getSubjectResultSpots(
subject: widget.subject,
),
maxY: max(getHighestAverage(subject: widget.subject), getCurrentYear().maxGrade),
maxX: getCurrentYear().termCount - 1,
xLabelInterval: 1,
getBottomTitleWidget: getTermBottomWidgets,
getLeftTitleWidget: getLeftTitleWidgets,
showRollingAverage: true,
),
),
const SliverPadding(
padding: EdgeInsets.symmetric(vertical: 12),
sliver: SliverToBoxAdapter(
child: Divider(),
),
),
SliverToBoxAdapter(
child: Builder(
builder: (context) {
final spots = getSubjectTestSpots(
subject: widget.subject,
);

double lowestX = spots[0].x;
final DateTime lowestDate = DateTime.fromMillisecondsSinceEpoch(lowestX.toInt());
if (lowestDate.month >= 9) {
lowestX = DateTime(lowestDate.year, 9).millisecondsSinceEpoch.toDouble();
} else {
lowestX = DateTime(lowestDate.year - 1, 9).millisecondsSinceEpoch.toDouble();
}

double highestX = spots[0].x;
final DateTime highestDate = DateTime.fromMillisecondsSinceEpoch(highestX.toInt());
if (highestDate.month >= 9) {
highestX = DateTime(highestDate.year + 1, 9).millisecondsSinceEpoch.toDouble();
} else {
highestX = DateTime(highestDate.year, 9).millisecondsSinceEpoch.toDouble();
}

return StandardLineChart(
title: translations.testOther,
spots: spots,
minX: lowestX,
maxX: highestX,
maxY: max(getHighestTest(subject: widget.subject), getCurrentYear().maxGrade),
xGridInterval: 2629746000, // 1 month
xLabelInterval: Duration.millisecondsPerDay,
getBottomTitleWidget: getDateBottomWidgets,
getLeftTitleWidget: getLeftTitleWidgets,
showRollingAverage: true,
);
},
),
),
],
),
),
],
);
},
),
);
}
}
66 changes: 41 additions & 25 deletions lib/ui/routes/main_route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import "package:graded/calculations/subject.dart";
import "package:graded/calculations/term.dart";
import "package:graded/localization/translations.dart";
import "package:graded/misc/enums.dart";
import "package:graded/ui/routes/chart_route.dart";
import "package:graded/ui/routes/home_route.dart";
import "package:graded/ui/routes/subject_route.dart";
import "package:graded/ui/utilities/haptics.dart";
Expand All @@ -20,6 +21,7 @@ import "package:graded/ui/widgets/popup_menus.dart";
enum RouteType {
home,
subject,
chart,
}

class RouteWidget extends StatefulWidget {
Expand Down Expand Up @@ -63,7 +65,7 @@ class RouteWidgetState extends State<RouteWidget> with TickerProviderStateMixin

tabController = TabController(
length: children.length,
initialIndex: Manager.currentTerm,
initialIndex: widget.routeType != RouteType.chart ? Manager.currentTerm : 0,
vsync: this,
)..addListener(() {
if (widget.routeType != RouteType.home) return;
Expand Down Expand Up @@ -234,33 +236,47 @@ class RouteWidgetState extends State<RouteWidget> with TickerProviderStateMixin

List<Widget> children = [];

if (widget.routeType == RouteType.home) {
children = List.generate(
tabCount,
(index) => HomePage(term: getTerm(index)),
);
} else {
if (widget.arguments == null) {
throw ArgumentError("No arguments passed to route");
}

final List<Subject?> arguments = widget.arguments! as List<Subject?>;
final Subject? parent = arguments[0];
final Subject subject = arguments[1]!;
switch (widget.routeType) {
case RouteType.home:
children = List.generate(
tabCount,
(index) => HomePage(term: getTerm(index)),
);

int tabCount = getCurrentYear().termCount;
if (getCurrentYear().validatedYear == 1) tabCount++;
if (tabCount > 1) tabCount++;
case RouteType.subject:
case RouteType.chart:
if (widget.arguments == null) {
throw ArgumentError("No arguments passed to route");
}

final List<Subject?> arguments = widget.arguments! as List<Subject?>;
final Subject? parent = arguments[0];
final Subject subject = arguments[1]!;

int tabCount = 1;
if (widget.routeType == RouteType.subject) {
tabCount = getCurrentYear().termCount;
if (getCurrentYear().validatedYear == 1) tabCount++;
if (tabCount > 1) tabCount++;
}

children = List.generate(tabCount, (index) {
Term term = getTerm(index);
if (widget.routeType == RouteType.chart) {
term = getYearOverview();
}

children = List.generate(tabCount, (index) {
final Term term = getTerm(index);
final Subject? newParent = parent != null ? term.subjects.firstWhere((element) => element.name == parent.name) : null;
final Subject newSubject = newParent != null
? newParent.children.firstWhere((element) => element.name == subject.name)
: term.subjects.firstWhere((element) => element.name == subject.name);
final Subject? newParent = parent != null ? Manager.getSubjectInTerm(parent, term) : null;
final Subject newSubject = newParent != null
? newParent.children.firstWhere((element) => element.name == subject.name)
: term.subjects.firstWhere((element) => element.name == subject.name);

return SubjectRoute(term: term, parent: newParent, subject: newSubject);
});
if (widget.routeType == RouteType.subject) {
return SubjectRoute(term: term, parent: newParent, subject: newSubject);
} else {
return ChartRoute(term: term, parent: newParent, subject: newSubject);
}
});
}

return children;
Expand Down
Loading

0 comments on commit a9a86df

Please sign in to comment.