-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #164 from PSDTools/gpa
GPA Calculation
- Loading branch information
Showing
8 changed files
with
262 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters