fix: recover authenticated undergraduate full pages with session guards

This commit is contained in:
Codex
2026-10-15 16:39:27 +08:00
parent 83b0c7e177
commit 79d268fd5e
22 changed files with 1418 additions and 13 deletions
@@ -13,9 +13,14 @@ import 'timetable_adapter.dart';
import 'exam_adapter.dart';
import '../school_browser.dart';
import '../school_browser_diagnostics.dart';
import '../school_full_page_recovery.dart';
class UndergraduateSession extends ChangeNotifier {
UndergraduateSession({this.configureBrowser = configureSchoolBrowser});
UndergraduateSession({
this.configureBrowser = configureSchoolBrowser,
SchoolFullPageRecovery? pageRecovery,
}) : _pageRecovery = pageRecovery ?? SchoolFullPageRecovery();
final SchoolFullPageRecovery _pageRecovery;
final SchoolBrowserConfigurator configureBrowser;
Future<SchoolBrowserInfo>? _browserReady;
String? browserVersion;
@@ -28,6 +33,7 @@ class UndergraduateSession extends ChangeNotifier {
_connected = false,
_loading = false,
_manualCapture = false,
_recoveringPage = false,
_failed = false,
_complete = false;
bool hasOpened = false, awaitingAuthentication = false, logoutFailed = false;
@@ -44,7 +50,8 @@ class UndergraduateSession extends ChangeNotifier {
int get pageGeneration => _generation;
bool get requestingExams => query != null;
bool get canLogout => hasOpened || logoutFailed;
bool get busy => _loading || _manualCapture || _itemTimeout != null;
bool get busy =>
_loading || _manualCapture || _recoveringPage || _itemTimeout != null;
String get statusLabel => logoutFailed
? '退出未完成'
: _failed
@@ -70,6 +77,8 @@ class UndergraduateSession extends ChangeNotifier {
void _reset() {
_generation++;
_pageRecovery.reset();
_recoveringPage = false;
_cancelTimers();
_parts.clear();
_index = 0;
@@ -123,6 +132,7 @@ class UndergraduateSession extends ChangeNotifier {
return NavigationDecision.navigate;
},
onPageStarted: (url) {
_pageRecovery.invalidateDocument();
DiagnosticLog.instance.navigation('undergraduate', 'started', url);
// Within a batch, type-to-type loads retain their generation. Once
// published, any new document invalidates the deferred save result.
@@ -130,6 +140,7 @@ class UndergraduateSession extends ChangeNotifier {
_reset();
}
_document++;
_recoveringPage = false;
_poll?.cancel();
_probeKey = null;
pendingDraft = null;
@@ -350,6 +361,37 @@ class UndergraduateSession extends ChangeNotifier {
}
_connected = true;
awaitingAuthentication = false;
final recovery = await _pageRecovery.tryRestore(
web,
uri,
authenticated: true,
documentKey: '$g:$d',
isCurrent: () => _valid(g) && d == _document,
onStarted: () {
_recoveringPage = true;
message = '已登录,正在恢复完整教务页面…';
_emit();
},
);
if (!_valid(g) || d != _document) return;
_recoveringPage = false;
if (recovery == FullPageRecoveryResult.restored) {
_loading = true;
message = '完整页面已恢复,正在检查…';
_schedulePoll(g, d, url);
_emit();
return;
}
if (recovery == FullPageRecoveryResult.cancelled) {
message = '页面已变化,请等待加载完成或重新认证。';
_emit();
return;
}
if (recovery == FullPageRecoveryResult.failed) {
message = '已登录,但完整教务页面暂未恢复,请重新认证后重试。';
_emit();
return;
}
if (!requestingExams) {
message = manualMessage;
_emit();
@@ -438,7 +480,9 @@ class UndergraduateSession extends ChangeNotifier {
}
Future<void> readCurrentTimetable() async {
if (requestingExams || _manualCapture || !_active) return;
if (requestingExams || _manualCapture || _recoveringPage || !_active) {
return;
}
final g = _generation, d = _document;
_manualCapture = true;
_emit();
@@ -535,6 +579,7 @@ class UndergraduateSession extends ChangeNotifier {
_disposed = true;
_active = false;
_generation++;
_pageRecovery.reset();
_cancelTimers();
super.dispose();
}