feat: integrate undergraduate school workflows and period twelve
This commit is contained in:
+100
-12
@@ -15,6 +15,9 @@ import '../features/timetable/timetable_page.dart';
|
||||
import '../features/profile/profile_page.dart';
|
||||
import '../features/school/school_session.dart';
|
||||
import '../features/school/school_selection_page.dart';
|
||||
import '../features/school/undergraduate/session.dart';
|
||||
import '../features/school/undergraduate/exam_query_picker.dart';
|
||||
import '../domain/undergraduate_exam_query.dart';
|
||||
|
||||
class HepanApp extends StatelessWidget {
|
||||
const HepanApp({
|
||||
@@ -22,12 +25,16 @@ class HepanApp extends StatelessWidget {
|
||||
required this.controller,
|
||||
this.schoolBuilder,
|
||||
this.school,
|
||||
this.undergraduate,
|
||||
this.undergraduateBuilder,
|
||||
this.notificationSelection,
|
||||
this.feedbackSender,
|
||||
});
|
||||
final AppController controller;
|
||||
final Widget Function()? schoolBuilder;
|
||||
final SchoolSession? school;
|
||||
final UndergraduateSession? undergraduate;
|
||||
final Widget Function()? undergraduateBuilder;
|
||||
final ValueNotifier<String?>? notificationSelection;
|
||||
final FeedbackSender? feedbackSender;
|
||||
@override
|
||||
@@ -42,6 +49,8 @@ class HepanApp extends StatelessWidget {
|
||||
controller: controller,
|
||||
schoolBuilder: schoolBuilder,
|
||||
school: school,
|
||||
undergraduate: undergraduate,
|
||||
undergraduateBuilder: undergraduateBuilder,
|
||||
notificationSelection: notificationSelection,
|
||||
feedbackSender: feedbackSender ?? configuredFeedbackSender(),
|
||||
),
|
||||
@@ -53,12 +62,16 @@ class _Shell extends StatefulWidget {
|
||||
required this.controller,
|
||||
this.schoolBuilder,
|
||||
this.school,
|
||||
this.undergraduate,
|
||||
this.undergraduateBuilder,
|
||||
this.notificationSelection,
|
||||
required this.feedbackSender,
|
||||
});
|
||||
final AppController controller;
|
||||
final Widget Function()? schoolBuilder;
|
||||
final SchoolSession? school;
|
||||
final UndergraduateSession? undergraduate;
|
||||
final Widget Function()? undergraduateBuilder;
|
||||
final ValueNotifier<String?>? notificationSelection;
|
||||
final FeedbackSender feedbackSender;
|
||||
@override
|
||||
@@ -68,11 +81,13 @@ class _Shell extends StatefulWidget {
|
||||
class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
int _tab = 0;
|
||||
bool _openingSchool = false;
|
||||
SupportedSchool? _selectedSchool;
|
||||
// Earlier imports all belong to UESTC graduate; reuse their existing term
|
||||
// and session without requiring students to choose again on every refresh.
|
||||
SupportedSchool? get _knownSchool =>
|
||||
_selectedSchool ??
|
||||
widget.controller.snapshot.selectedSchool ??
|
||||
(widget.undergraduate?.canLogout == true
|
||||
? SupportedSchool.uestcUndergraduate
|
||||
: null) ??
|
||||
(widget.controller.snapshot.schoolTerm != null ||
|
||||
widget.school?.canLogout == true
|
||||
? SupportedSchool.uestcGraduate
|
||||
@@ -149,14 +164,15 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
),
|
||||
);
|
||||
if (!mounted || selected == null) return;
|
||||
setState(() => _selectedSchool = selected);
|
||||
final saved = await widget.controller.selectSchool(selected);
|
||||
if (!mounted || !saved) return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
// The only current connector is the existing UESTC graduate workflow.
|
||||
// A new catalog option must provide its own connector here.
|
||||
switch (selected) {
|
||||
case SupportedSchool.uestcGraduate:
|
||||
await _openSchool(exams: exams, chooseTerm: chooseTerm);
|
||||
case SupportedSchool.uestcUndergraduate:
|
||||
await _openUndergraduate(exams: exams, chooseTerm: chooseTerm);
|
||||
}
|
||||
} finally {
|
||||
_openingSchool = false;
|
||||
@@ -168,14 +184,17 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
bool chooseTerm = false,
|
||||
}) async {
|
||||
if (widget.schoolBuilder != null) {
|
||||
final term = widget.controller.snapshot.schoolTerm;
|
||||
final savedTerm = widget.controller.snapshot.schoolTerm;
|
||||
final term = savedTerm?.school == SupportedSchool.uestcGraduate
|
||||
? savedTerm
|
||||
: null;
|
||||
if (exams) {
|
||||
widget.school?.openExams(
|
||||
await widget.school?.openExams(
|
||||
term: term,
|
||||
chooseTerm: chooseTerm || term == null,
|
||||
);
|
||||
} else {
|
||||
widget.school?.openTimetable(
|
||||
await widget.school?.openTimetable(
|
||||
term: term,
|
||||
chooseTerm: chooseTerm || term == null,
|
||||
);
|
||||
@@ -201,6 +220,51 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _openUndergraduate({
|
||||
required bool exams,
|
||||
required bool chooseTerm,
|
||||
}) async {
|
||||
final session = widget.undergraduate, builder = widget.undergraduateBuilder;
|
||||
if (session == null || builder == null) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('学校连接'),
|
||||
content: const Text('本科连接暂未准备好,请重试。'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('知道了'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (exams) {
|
||||
var query = UndergraduateExamQuery.fromSchedule(
|
||||
widget.controller.snapshot.examSchedule,
|
||||
);
|
||||
if (query == null || chooseTerm) {
|
||||
query = await showUndergraduateExamQueryPicker(
|
||||
context,
|
||||
initial: query,
|
||||
now: widget.controller.clock(),
|
||||
);
|
||||
if (!mounted || query == null) return;
|
||||
}
|
||||
await session.openExams(query);
|
||||
} else {
|
||||
await session.openTimetable();
|
||||
}
|
||||
if (!mounted) return;
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<void>(builder: (_) => builder()),
|
||||
);
|
||||
session.setReadingActive(false);
|
||||
}
|
||||
|
||||
Future<void> _logout() async {
|
||||
final choice = await showDialog<int>(
|
||||
context: context,
|
||||
@@ -224,7 +288,17 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
),
|
||||
);
|
||||
if (choice == null || choice == 0) return;
|
||||
await widget.school?.logout();
|
||||
if (_knownSchool == SupportedSchool.uestcUndergraduate &&
|
||||
widget.undergraduate?.canLogout == true) {
|
||||
await widget.undergraduate!.logout();
|
||||
widget.school?.invalidateAuthentication();
|
||||
} else if (widget.school?.canLogout == true) {
|
||||
await widget.school!.logout();
|
||||
widget.undergraduate?.invalidateAuthentication();
|
||||
} else if (widget.undergraduate?.canLogout == true) {
|
||||
await widget.undergraduate!.logout();
|
||||
widget.school?.invalidateAuthentication();
|
||||
}
|
||||
if (choice == 2) {
|
||||
await widget.controller.clearCourses();
|
||||
await widget.controller.clearExams();
|
||||
@@ -261,6 +335,7 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
animation: Listenable.merge([
|
||||
widget.controller,
|
||||
if (widget.school != null) widget.school!,
|
||||
if (widget.undergraduate != null) widget.undergraduate!,
|
||||
]),
|
||||
builder: (context, _) => Scaffold(
|
||||
body: Container(
|
||||
@@ -316,6 +391,11 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
onSync: () {
|
||||
_school(exams: true);
|
||||
},
|
||||
onQueryOptions:
|
||||
_knownSchool ==
|
||||
SupportedSchool.uestcUndergraduate
|
||||
? () => _school(exams: true, chooseTerm: true)
|
||||
: null,
|
||||
),
|
||||
ProfilePage(
|
||||
controller: widget.controller,
|
||||
@@ -323,11 +403,19 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
|
||||
onLogin: () => _school(selectSchool: true),
|
||||
schoolName: _knownSchool?.label,
|
||||
onUpdateTerm: () => _school(chooseTerm: true),
|
||||
authStatus: widget.school?.statusLabel ?? '未登录',
|
||||
logoutLabel: widget.school?.logoutFailed == true
|
||||
authStatus:
|
||||
_knownSchool ==
|
||||
SupportedSchool.uestcUndergraduate
|
||||
? widget.undergraduate?.statusLabel ?? '未登录'
|
||||
: widget.school?.statusLabel ?? '未登录',
|
||||
logoutLabel:
|
||||
widget.school?.logoutFailed == true ||
|
||||
widget.undergraduate?.logoutFailed == true
|
||||
? '重试退出学校登录'
|
||||
: '退出学校登录',
|
||||
onLogout: widget.school?.canLogout == true
|
||||
onLogout:
|
||||
widget.school?.canLogout == true ||
|
||||
widget.undergraduate?.canLogout == true
|
||||
? _logout
|
||||
: null,
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user