feat: add two-tab timetable UI and glass dock

This commit is contained in:
Codex
2026-10-12 23:33:33 +08:00
parent 808af007a2
commit 8a98d49d12
17 changed files with 1912 additions and 9 deletions
+14 -5
View File
@@ -2,7 +2,6 @@ import 'package:flutter/foundation.dart';
import '../domain/app_snapshot.dart';
import '../domain/app_settings.dart';
import '../domain/course.dart';
import '../data/snapshot_store.dart';
import '../data/json_schedule_import.dart';
import '../services/notification_service.dart';
@@ -29,6 +28,9 @@ class AppController extends ChangeNotifier {
isDemo ? _demoSettings! : snapshot.settings;
Future<void> _run(Future<void> Function() operation) {
final next = _queue.then((_) async {
if (storageReady) {
lastError = null;
}
try {
await operation();
} catch (error) {
@@ -84,14 +86,16 @@ class AppController extends ChangeNotifier {
isDemo = false;
});
Future<void> updateSettings(AppSettings value) => _run(() async {
if (![5, 10, 15, 30, 60].contains(value.reminderMinutes))
if (![5, 10, 15, 30, 60].contains(value.reminderMinutes)) {
throw ArgumentError('提醒时间无效');
}
await _save(snapshot.copyWith(settings: value));
if (isDemo)
if (isDemo) {
_demoSettings = _demoSettings!.copyWith(
colorMode: value.colorMode,
singleColorArgb: value.singleColorArgb,
);
}
await _reconcile();
});
Future<void> applyImport(
@@ -101,8 +105,9 @@ class AppController extends ChangeNotifier {
if (draft.courses.isEmpty && (!draft.explicitlyEmpty || !confirmedEmpty)) {
throw const FormatException('未检测到课程,已有课表保持不变');
}
if (draft.courses.map((c) => c.id).toSet().length != draft.courses.length)
if (draft.courses.map((c) => c.id).toSet().length != draft.courses.length) {
throw const FormatException('课程标识重复');
}
if (draft.source == CourseSource.demo) {
_demo = draft.courses;
isDemo = true;
@@ -117,8 +122,9 @@ class AppController extends ChangeNotifier {
);
return;
}
if (draft.courses.any((c) => c.source != draft.source))
if (draft.courses.any((c) => c.source != draft.source)) {
throw const FormatException('课程来源不一致');
}
await _save(
snapshot.copyWith(
courses: draft.courses,
@@ -195,6 +201,9 @@ class AppController extends ChangeNotifier {
});
Future<void> refreshServices() => _run(_reconcile);
Future<void> _reconcile() async {
if (!storageReady) {
return;
}
final settings = snapshot.settings;
final occurrences = settings.semester == null
? <CourseOccurrence>[]