feat: select school terms and smooth refractive Dock motion

This commit is contained in:
Codex
2026-10-13 19:08:36 +08:00
parent 3e2d8864af
commit 50fcc70e8e
33 changed files with 1245 additions and 94 deletions
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../../app/app_controller.dart';
import '../../domain/school_term.dart';
import 'school_session.dart';
class SchoolAuthPage extends StatefulWidget {
@@ -18,6 +19,7 @@ class SchoolAuthPage extends StatefulWidget {
class _SchoolAuthPageState extends State<SchoolAuthPage> {
bool _saving = false;
SchoolTerm? _termChoice;
@override
void initState() {
super.initState();
@@ -36,7 +38,9 @@ class _SchoolAuthPageState extends State<SchoolAuthPage> {
final courses = s.pendingDraft, exams = s.pendingExams;
final generation = s.pageGeneration;
final route = ModalRoute.of(context);
if (_saving || (courses == null && exams == null)) return;
if (s.needsTermSelection || _saving || (courses == null && exams == null)) {
return;
}
_saving = true;
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (!mounted) {
@@ -102,7 +106,9 @@ class _SchoolAuthPageState extends State<SchoolAuthPage> {
),
IconButton(
tooltip: '读取当前页面',
onPressed: _saving ? null : s.readCurrentPage,
onPressed: _saving || s.needsTermSelection
? null
: s.readCurrentPage,
icon: const Icon(Icons.sync_rounded),
),
],
@@ -123,7 +129,9 @@ class _SchoolAuthPageState extends State<SchoolAuthPage> {
child: Stack(
children: [
WebViewWidget(controller: s.web),
if (s.finding || _saving)
if (s.needsTermSelection)
Positioned.fill(child: _termPicker(s)),
if (!s.needsTermSelection && (s.finding || _saving))
Positioned.fill(
child: ColoredBox(
color: const Color(0xFFF5F9FE),
@@ -152,4 +160,62 @@ class _SchoolAuthPageState extends State<SchoolAuthPage> {
),
);
}
Widget _termPicker(SchoolSession session) {
final choices = session.termChoices;
final preferred =
_termChoice ??
session.selectedTerm ??
widget.controller.snapshot.schoolTerm ??
choices.first;
final selected = choices.contains(preferred) ? preferred : choices.first;
return Material(
color: const Color(0xFFF5F9FE),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(20, 16, 20, 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'选择学校学期',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700),
),
const SizedBox(height: 8),
Text(session.requestingExams ? '将读取这个学期的考试安排。' : '将读取这个学期的课程表。'),
const SizedBox(height: 12),
Expanded(
child: ListView.builder(
itemCount: choices.length,
itemBuilder: (context, index) {
final term = choices[index];
final isSelected = term == selected;
return ListTile(
title: Text(term.label),
selected: isSelected,
leading: Icon(
isSelected
? Icons.radio_button_checked
: Icons.radio_button_off,
),
onTap: () => setState(() => _termChoice = term),
);
},
),
),
const SizedBox(height: 12),
FilledButton(
onPressed: () => session.selectTerm(selected),
child: const Text('导入所选学期'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('取消'),
),
],
),
),
),
);
}
}