Skip to content

Commit

Permalink
Merge pull request #164 from PSDTools/gpa
Browse files Browse the repository at this point in the history
GPA Calculation
  • Loading branch information
lishaduck committed Sep 13, 2023
2 parents a99d1d7 + b64df2d commit 59de5d8
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 13 deletions.
11 changes: 8 additions & 3 deletions lib/app/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "../features/auth/domain/auth_domain.dart";
import "../features/auth/presentation/auth_page/auth_page.dart";
import "../features/dashboard/presentation/dashboard_page/dashboard_page.dart";
import "../features/dashboard/presentation/wrapper_page/wrapper_page.dart";
import "../features/gpa_calculator/presentation/gpa_page.dart";
import "../features/pirate_coins/presentation/pirate_coins_page/pirate_coins_page.dart";
import "../features/pirate_coins/presentation/stats_page/stats_page.dart";

Expand Down Expand Up @@ -47,15 +48,19 @@ class AppRouter extends _$AppRouter {
),
AutoRoute(
page: DashboardRoute.page,
path: "dashboard",
path: "",
title: (context, route) => "Dashboard",
),
AutoRoute(
page: StatsRoute.page,
path: "stats",
title: (context, route) => "Stats",
),
RedirectRoute(path: "*", redirectTo: "dashboard"),
AutoRoute(
page: GpaRoute.page,
path: "gpa-calculator",
title: (context, route) => "GPA Calculator",
),
],
title: (context, data) => "Pirate Code",
),
Expand All @@ -65,6 +70,6 @@ class AppRouter extends _$AppRouter {
title: (context, data) => "Login",
initial: true,
),
RedirectRoute(path: "/*", redirectTo: "/dashboard"),
RedirectRoute(path: "/*", redirectTo: "/"),
];
}
12 changes: 6 additions & 6 deletions lib/features/dashboard/domain/dashboard_domain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ List<Applet> applets(AppletsRef ref) {
color: const Color.fromARGB(255, 122, 194, 129),
location: const PirateCoinsRoute(),
),
// Applet(
// image: appletsFolder.gpaCalculator,
// color: const Color.fromARGB(255, 242, 184, 184),
// name: "GPA Calculator",
// location: const GpaCalculatorRoute(),
// ),
Applet(
image: appletsFolder.gpaCalculator,
color: const Color.fromARGB(255, 242, 184, 184),
name: "GPA Calculator",
location: const GpaRoute(),
),
// Applet(
// image: appletsFolder.phsMap,
// color: const Color.fromARGB(255, 178, 254, 186),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "package:auto_route/auto_route.dart";
import "package:flutter/material.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";

import "../../../pirate_coins/domain/coins_domain.dart";
import "../../domain/dashboard_domain.dart";
import "../../domain/dashboard_model.dart";

Expand Down Expand Up @@ -116,7 +117,7 @@ class _NotificationBar extends StatelessWidget {
}

/// A button widget that navigates to a specified applet.
class _AppletButton extends StatelessWidget {
class _AppletButton extends ConsumerWidget {
/// Create a new instance of [_AppletButton].
const _AppletButton({
required this.buttonData,
Expand All @@ -129,16 +130,16 @@ class _AppletButton extends StatelessWidget {
final Applet buttonData;

@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
final imagePath = buttonData.image.path;
final backgroundColor = buttonData.color;
final title = buttonData.name;
final destination = buttonData.location;

return GestureDetector(
onTap: () async {
ref.read(currentStageProvider.notifier).reset();
// Handle button tap here to navigate to the specified destination.
// TODO(ParkerH27): Find out why this doesn't change the URL.
await context.router.push(destination);
},
child: Card(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class WrapperPage extends StatelessWidget {
PirateCoinsRoute(),
StatsRoute(), // TODO(lishaduck): Make this accessible.
DashboardRoute(),
GpaRoute(),
],
duration: const Duration(milliseconds: 200),
transitionBuilder: (context, child, animation) {
Expand Down Expand Up @@ -126,7 +127,7 @@ class _ExpandedWrapper extends ConsumerWidget {
child: Text(
"Pattonville Pirates",
style: GoogleFonts.mrDafoe(
color: const Color.fromARGB(255, 11, 70, 24),
color: const Color.fromARGB(255, 9, 56, 19),
shadows: [
Shadow(
color: theme.colorScheme.shadow.withOpacity(0.5),
Expand Down
21 changes: 21 additions & 0 deletions lib/features/gpa_calculator/domain/gpa_domain.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import "package:riverpod_annotation/riverpod_annotation.dart";

import "gpa_model.dart";

part "gpa_domain.g.dart";

/// Get the state for the GPA calculator.
@riverpod
class Gpa extends _$Gpa {
@override
Course build(int hour) {
return Course(hour: hour, grade: _defaultGrade);
}

final _defaultGrade = const LetterGrade.a();

/// Update the course's grade.
void updateGrade(LetterGrade? grade) {
state = state.copyWith(grade: grade ?? _defaultGrade);
}
}
116 changes: 116 additions & 0 deletions lib/features/gpa_calculator/domain/gpa_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import "package:freezed_annotation/freezed_annotation.dart";

part "gpa_model.freezed.dart";

/// A course.
@freezed
@immutable
sealed class Course with _$Course {
/// Create a new, immutable instance of [Course].
const factory Course({
/// The hour the course takes place.
required int hour,

// /// The name of the course.
// required String name,

/// The grade of the course.
required LetterGrade grade,
}) = _Course;
}

/// A grade.
sealed class LetterGrade {
/// An 'A'.
const factory LetterGrade.a({bool isHonors}) = _A;

/// A 'B'.
const factory LetterGrade.b({bool isHonors}) = _B;

/// A 'C'.
const factory LetterGrade.c({bool isHonors}) = _C;

/// A 'D'.
const factory LetterGrade.d({bool isHonors}) = _D;

/// An 'F'.
const factory LetterGrade.f({bool isHonors}) = _F;

/// The GPA value for the letter grade.
int get value;
}

/// An 'A'.
@freezed
@immutable
class _A with _$_A implements LetterGrade {
/// Create a new, immutable [LetterGrade.a].
const factory _A({
@Default(false) bool isHonors,
}) = __A;

const _A._();

@override
int get value => isHonors ? 5 : 4;
}

/// A 'B'.
@freezed
@immutable
class _B with _$_B implements LetterGrade {
/// Create a new, immutable [LetterGrade.b].
const factory _B({
@Default(false) bool isHonors,
}) = __B;

const _B._();

@override
int get value => isHonors ? 4 : 3;
}

/// A 'C'.
@freezed
@immutable
class _C with _$_C implements LetterGrade {
/// Create a new, immutable [LetterGrade.c].
const factory _C({
@Default(false) bool isHonors,
}) = __C;

const _C._();

@override
int get value => isHonors ? 3 : 2;
}

/// A 'D'.
@freezed
@immutable
class _D with _$_D implements LetterGrade {
/// Create a new, immutable [LetterGrade.d].
const factory _D({
@Default(false) bool isHonors,
}) = __D;

const _D._();

@override
int get value => 1;
}

/// An 'F'.
@freezed
@immutable
class _F with _$_F implements LetterGrade {
/// Create a new, immutable [LetterGrade.f].
const factory _F({
@Default(false) bool isHonors,
}) = __F;

const _F._();

@override
int get value => 0;
}
100 changes: 100 additions & 0 deletions lib/features/gpa_calculator/presentation/gpa_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/// The auth feature.
library;

import "package:auto_route/auto_route.dart";
import "package:flutter/material.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";

import "../domain/gpa_domain.dart";
import "../domain/gpa_model.dart";

/// The page located at `/login/`
@RoutePage()
class GpaPage extends ConsumerStatefulWidget {
/// Create a new instance of [GpaPage].
const GpaPage({super.key});

@override
ConsumerState<GpaPage> createState() => _GpaPageState();
}

class _GpaPageState extends ConsumerState<GpaPage> {
final _formKey = GlobalKey<FormState>();
final _hours = 7;

@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 300,
child: Form(
key: _formKey,
child: Column(
children: [
for (var hour = 0; hour < _hours; hour++)
Dropdown(
hour: hour,
),
],
),
),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState?.validate.call() ?? false) {
var total = 0;
for (var hour = 0; hour < _hours; hour++) {
final grade = ref.read(gpaProvider(hour)).grade;
total += grade.value;
}

final gpa = total / _hours;

// TODO(lishaduck): Add an extension on context.
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Calculated GPA: $gpa")),
);
}
},
child: const Text("Calculate GPA"),
),
],
),
);
}
}

/// Dropdown widget for picking your letter grade.
class Dropdown extends ConsumerStatefulWidget {
/// Create a new instance of [Dropdown].
const Dropdown({required this.hour, super.key});

/// The hour the course is taken.
final int hour;

@override
ConsumerState<Dropdown> createState() => _DropdownState();
}

class _DropdownState extends ConsumerState<Dropdown> {
@override
Widget build(BuildContext context) {
final value = ref.watch(gpaProvider(widget.hour));
final valueNotifier = ref.watch(gpaProvider(widget.hour).notifier);

return DropdownButtonFormField(
value: value.grade,
items: const [
DropdownMenuItem(value: LetterGrade.a(), child: Text("A")),
DropdownMenuItem(value: LetterGrade.b(), child: Text("B")),
DropdownMenuItem(value: LetterGrade.c(), child: Text("C")),
DropdownMenuItem(value: LetterGrade.d(), child: Text("D")),
DropdownMenuItem(value: LetterGrade.f(), child: Text("F")),
],
onChanged: valueNotifier.updateGrade,
);
}
}
5 changes: 5 additions & 0 deletions lib/features/pirate_coins/domain/coins_domain.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,9 @@ class CurrentStage extends _$CurrentStage {
void goToViewCoinsStage(int student) {
state = ViewCoinsStage(student: student);
}

/// Reset the stage back to the default.
void reset() {
state = const PickStudentStage();
}
}

0 comments on commit 59de5d8

Please sign in to comment.