feat: persist timetable and validate confirmed imports
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
import '../domain/course.dart';
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
class ImportDraft {
|
||||
const ImportDraft({
|
||||
required this.courses,
|
||||
required this.explicitlyEmpty,
|
||||
required this.source,
|
||||
required this.parserVersion,
|
||||
});
|
||||
final List<Course> courses;
|
||||
final bool explicitlyEmpty;
|
||||
final CourseSource source;
|
||||
final String parserVersion;
|
||||
}
|
||||
|
||||
class JsonScheduleImport {
|
||||
static ImportDraft parse(String text) {
|
||||
try {
|
||||
if (utf8.encode(text).length > 2 * 1024 * 1024)
|
||||
throw const FormatException('文件不能超过 2 MB');
|
||||
final json = jsonDecode(text);
|
||||
if (json is! Map ||
|
||||
json['schemaVersion'] != 1 ||
|
||||
json['courses'] is! List ||
|
||||
(json['isDemo'] != null && json['isDemo'] is! bool) ||
|
||||
(json['explicitlyEmpty'] != null &&
|
||||
json['explicitlyEmpty'] is! bool)) {
|
||||
throw const FormatException('请选择版本 1 的课表 JSON 文件');
|
||||
}
|
||||
final source = json['isDemo'] == true
|
||||
? CourseSource.demo
|
||||
: CourseSource.file;
|
||||
final courses = (json['courses'] as List)
|
||||
.map(
|
||||
(c) => Course.fromJson(
|
||||
Map<String, dynamic>.from(c as Map),
|
||||
source: source,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
if (courses.map((c) => c.id).toSet().length != courses.length)
|
||||
throw const FormatException('课程标识重复');
|
||||
return ImportDraft(
|
||||
courses: List.unmodifiable(courses),
|
||||
explicitlyEmpty: json['explicitlyEmpty'] == true,
|
||||
source: source,
|
||||
parserVersion: 'json-v1',
|
||||
);
|
||||
} on FormatException {
|
||||
rethrow;
|
||||
} catch (_) {
|
||||
throw const FormatException('课表文件格式无效');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user