feat: add school authentication entry with guarded import

This commit is contained in:
Codex
2026-10-12 23:50:52 +08:00
parent 8a98d49d12
commit ffd3920c0d
8 changed files with 717 additions and 4 deletions
+52 -4
View File
@@ -5,24 +5,36 @@ import 'app_theme.dart';
import '../widgets/glass_dock.dart';
import '../features/timetable/timetable_page.dart';
import '../features/profile/profile_page.dart';
import '../features/school/school_session.dart';
class HepanApp extends StatelessWidget {
const HepanApp({super.key, required this.controller, this.schoolBuilder});
const HepanApp({
super.key,
required this.controller,
this.schoolBuilder,
this.school,
});
final AppController controller;
final Widget Function()? schoolBuilder;
final SchoolSession? school;
@override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
title: '河畔Everyday',
theme: hepanTheme(),
home: _Shell(controller: controller, schoolBuilder: schoolBuilder),
home: _Shell(
controller: controller,
schoolBuilder: schoolBuilder,
school: school,
),
);
}
class _Shell extends StatefulWidget {
const _Shell({required this.controller, this.schoolBuilder});
const _Shell({required this.controller, this.schoolBuilder, this.school});
final AppController controller;
final Widget Function()? schoolBuilder;
final SchoolSession? school;
@override
State<_Shell> createState() => _ShellState();
}
@@ -71,9 +83,41 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
}
}
Future<void> _logout() async {
final choice = await showDialog<int>(
context: context,
builder: (context) => AlertDialog(
title: const Text('退出学校登录'),
content: const Text('已导入的课表是否保留在手机中?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, 0),
child: const Text('取消'),
),
TextButton(
onPressed: () => Navigator.pop(context, 1),
child: const Text('保留课表'),
),
TextButton(
onPressed: () => Navigator.pop(context, 2),
child: const Text('清除课表'),
),
],
),
);
if (choice == null || choice == 0) return;
await widget.school?.logout();
if (choice == 2) {
await widget.controller.clearCourses();
}
}
@override
Widget build(BuildContext context) => AnimatedBuilder(
animation: widget.controller,
animation: Listenable.merge([
widget.controller,
if (widget.school != null) widget.school!,
]),
builder: (context, _) => Scaffold(
body: Container(
decoration: const BoxDecoration(
@@ -118,6 +162,10 @@ class _ShellState extends State<_Shell> with WidgetsBindingObserver {
ProfilePage(
controller: widget.controller,
onLogin: _school,
authStatus: widget.school?.statusLabel ?? '未登录',
onLogout: widget.school?.hasOpened == true
? _logout
: null,
),
],
),