Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 48 additions & 42 deletions packages/ap_common_flutter_ui/lib/src/scaffold/score_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ class ScoreScaffold extends StatefulWidget {
this.finalScoreBuilder,
this.customHint,
this.isShowSearchButton = false,
this.showPRCard,
this.bottom,
this.customStateHint,
this.semesterPickerController,
this.semesterPickerUiConfig,
});

/// Creates a [ScoreScaffold] from a [DataState<ScoreData>].
Expand All @@ -53,8 +55,10 @@ class ScoreScaffold extends StatefulWidget {
this.middleScoreBuilder,
this.finalScoreBuilder,
this.isShowSearchButton = false,
this.showPRCard = true,
this.bottom,
this.semesterPickerController,
this.semesterPickerUiConfig,
}) : state = dataState.when(
loading: () => ScoreState.loading,
loaded: (_, __) => ScoreState.finish,
Expand Down Expand Up @@ -87,6 +91,7 @@ class ScoreScaffold extends StatefulWidget {
final Widget Function(int index)? finalScoreBuilder;

final bool isShowSearchButton;
final bool? showPRCard;

final String? customHint;

Expand All @@ -95,6 +100,9 @@ class ScoreScaffold extends StatefulWidget {
/// Optional controller for the semester picker.
final SemesterPickerController? semesterPickerController;

/// Optional UI config for the semester picker.
final SemesterUIConfig? semesterPickerUiConfig;

@override
ScoreScaffoldState createState() => ScoreScaffoldState();
}
Expand Down Expand Up @@ -139,36 +147,33 @@ class ScoreScaffoldState extends State<ScoreScaffold> {
return Scaffold(
backgroundColor: colorScheme.surface,
appBar: AppBar(
centerTitle: false,
titleSpacing: 0,
title: Row(
children: <Widget>[
Flexible(
child: Text(
widget.title ?? context.ap.score,
overflow: TextOverflow.ellipsis,
),
),
if (widget.itemPicker != null) ...<Widget>[
const SizedBox(width: 12),
widget.itemPicker!,
],
if (widget.semesterData != null &&
widget.itemPicker == null) ...<Widget>[
const SizedBox(width: 12),
SemesterPicker(
semesterData: widget.semesterData!,
currentIndex: widget.semesterData!.currentIndex,
onSelect: (Semester semester, int index) {
widget.onSelect?.call(index);
},
featureTag: 'score',
controller: widget.semesterPickerController,
),
],
],
title: Text(
widget.title ?? context.ap.score,
overflow: TextOverflow.ellipsis,
),
bottom: widget.bottom as PreferredSizeWidget?,
actions: const <Widget>[],
actions: <Widget>[
if (widget.itemPicker != null) ...<Widget>[
widget.itemPicker!,
const SizedBox(width: 12),
],
if (widget.semesterData != null &&
widget.itemPicker == null) ...<Widget>[
SemesterPicker(
semesterData: widget.semesterData!,
currentIndex: widget.semesterData!.currentIndex,
onSelect: (Semester semester, int index) {
widget.onSelect?.call(index);
},
featureTag: 'score',
controller: widget.semesterPickerController,
uiConfig: widget.semesterPickerUiConfig,
),
const SizedBox(width: 12),
],
],
),
floatingActionButton: AnimatedScale(
scale: _showFab ? 1.0 : 0.0,
Expand Down Expand Up @@ -332,6 +337,7 @@ class ScoreScaffoldState extends State<ScoreScaffold> {
finalScoreBuilder: widget.finalScoreBuilder,
isAnalysisView: isLandscape || _isAnalysisView,
scrollController: _scrollController,
showPRCard: widget.showPRCard,
);
}
}
Expand Down Expand Up @@ -435,6 +441,7 @@ class ScoreContent extends StatefulWidget {
this.finalScoreBuilder,
required this.isAnalysisView,
this.scrollController,
this.showPRCard,
});

final ScoreData? scoreData;
Expand All @@ -446,6 +453,7 @@ class ScoreContent extends StatefulWidget {
final Widget Function(int index)? finalScoreBuilder;
final bool isAnalysisView;
final ScrollController? scrollController;
final bool? showPRCard;

@override
_ScoreContentState createState() => _ScoreContentState();
Expand All @@ -461,6 +469,7 @@ class _ScoreContentState extends State<ScoreContent> {
scoreData: widget.scoreData!,
onRefresh: widget.onRefresh,
controller: widget.scrollController,
showPRCard: widget.showPRCard,
);
} else {
return _ScoreListTab(
Expand Down Expand Up @@ -646,8 +655,7 @@ class _ScoreListTab extends StatelessWidget {
Color scoreColor,
) {
final String raw = _effectiveScoreStr(score) ?? '-';
final bool isNumeric =
scoreData.scoreType == ScoreType.numeric;
final bool isNumeric = scoreData.scoreType == ScoreType.numeric;

if (scoreValue == null) {
// Cannot parse at all — show raw string
Expand Down Expand Up @@ -748,11 +756,13 @@ class _ScoreAnalysisTab extends StatelessWidget {
required this.scoreData,
this.onRefresh,
this.controller,
this.showPRCard,
});

final ScoreData scoreData;
final VoidCallback? onRefresh;
final ScrollController? controller;
final bool? showPRCard;

@override
Widget build(BuildContext context) {
Expand All @@ -769,8 +779,10 @@ class _ScoreAnalysisTab extends StatelessWidget {
children: <Widget>[
_buildMainSummaryCard(colorScheme, context.ap, analysis),
const SizedBox(height: 16),
ScorePRCard(analysis: analysis),
const SizedBox(height: 16),
if (showPRCard != false) ...<Widget>[
ScorePRCard(analysis: analysis),
const SizedBox(height: 16),
],
ScoreGPACard(analysis: analysis),
const SizedBox(height: 16),
ScoreStatisticsCard(analysis: analysis),
Expand Down Expand Up @@ -956,14 +968,12 @@ class ScoreAnalysis {
late List<double> _gradePoints;
late int _totalSubjects;

bool get isGradePoint =>
scoreData.scoreType == ScoreType.gradePoint;
bool get isGradePoint => scoreData.scoreType == ScoreType.gradePoint;

/// Whether a numeric score value is considered passing.
bool isPassing(double scoreValue) {
if (isGradePoint) {
return scoreToGradePoint(scoreValue) >=
scoreData.passingGradePoint;
return scoreToGradePoint(scoreValue) >= scoreData.passingGradePoint;
}
return scoreValue >= scoreData.passingScore;
}
Expand Down Expand Up @@ -1087,9 +1097,7 @@ class ScoreAnalysis {
_ScoreListTab._effectiveScoreStr(score),
);
final double? unit = double.tryParse(score.units);
if (scoreValue != null &&
isPassing(scoreValue) &&
unit != null) {
if (scoreValue != null && isPassing(scoreValue) && unit != null) {
credits += unit;
}
}
Expand All @@ -1101,12 +1109,10 @@ class ScoreAnalysis {
/// Returns the effective score string for a [Score], preferring
/// [Score.semesterScore] and falling back to [Score.finalScore].
static String? effectiveScoreStr(Score score) {
if (score.semesterScore != null &&
score.semesterScore!.isNotEmpty) {
if (score.semesterScore != null && score.semesterScore!.isNotEmpty) {
return score.semesterScore;
}
if (score.finalScore != null &&
score.finalScore!.isNotEmpty) {
if (score.finalScore != null && score.finalScore!.isNotEmpty) {
return score.finalScore;
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -776,16 +776,20 @@ class ScoreGPACard extends StatelessWidget {
for (final Score score in analysis.scoreData.scores) {
final String? raw = ScoreAnalysis.effectiveScoreStr(score);
final double? value = ScoreAnalysis.parseScore(raw);
if (value == null) continue;
entries.add(_GradeEntry(
title: score.title,
score: value,
grade: isGradePoint
? (raw ?? '')
: ScoreAnalysis.scoreToGradeLetter(value),
gradePoint: ScoreAnalysis.scoreToGradePoint(value),
credits: double.tryParse(score.units) ?? 0,
),);
final bool isInvalid = value == null;
entries.add(
_GradeEntry(
title: score.title,
score: value ?? 0,
grade: isInvalid
? '-'
: (isGradePoint
? (raw ?? '')
: ScoreAnalysis.scoreToGradeLetter(value)),
gradePoint: isInvalid ? 0.0 : ScoreAnalysis.scoreToGradePoint(value),
credits: double.tryParse(score.units) ?? 0,
),
);
}

if (entries.isEmpty) return const SizedBox.shrink();
Expand Down Expand Up @@ -825,7 +829,7 @@ class ScoreGPACard extends StatelessWidget {
),
),
SizedBox(
width: 40,
width: 50,
child: Text(
context.ap.gradePoint,
style: TextStyle(
Expand Down Expand Up @@ -871,9 +875,9 @@ class ScoreGPACard extends StatelessWidget {
),
),
SizedBox(
width: 40,
width: 50,
child: Text(
e.gradePoint.toStringAsFixed(1),
e.grade != '-' ? e.gradePoint.toStringAsFixed(1) : '-',
style: TextStyle(
fontSize: 13,
color: colorScheme.onSurface,
Expand Down
Loading