From c0999b7a6df7af371ce7b1abb5419c168e393950 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 2 Feb 2024 23:07:57 +0800 Subject: [PATCH 01/31] Refactor: Migrate course related JSON --- lib/src/connector/course_connector.dart | 108 +++++++ lib/src/connector/ischool_plus_connector.dart | 12 +- lib/src/model/coursetable/course.dart | 84 ++++++ lib/src/model/coursetable/course.g.dart | 46 +++ lib/src/model/coursetable/course_period.dart | 18 ++ .../model/coursetable/course_period.g.dart | 18 ++ lib/src/model/coursetable/course_table.dart | 29 ++ lib/src/model/coursetable/course_table.g.dart | 24 ++ lib/src/model/coursetable/user.dart | 23 ++ lib/src/model/coursetable/user.g.dart | 19 ++ lib/src/model/json_init.dart | 14 +- lib/src/model/setting/setting_json.dart | 8 +- lib/src/model/setting/setting_json.g.dart | 2 +- lib/src/store/local_storage.dart | 52 ++-- lib/src/task/course/course_table_task.dart | 58 ++-- .../iplus/iplus_course_announcement_task.dart | 2 +- .../task/iplus/iplus_course_file_task.dart | 2 +- .../iplus_get_course_subscribe_task.dart | 4 +- lib/ui/other/route_utils.dart | 14 +- .../coursedetail/course_detail_page.dart | 15 +- .../coursedetail/screen/course_info_page.dart | 37 +-- .../iplus_announcement_detail_page.dart | 10 +- .../ischoolplus/iplus_announcement_page.dart | 10 +- .../screen/ischoolplus/iplus_file_page.dart | 12 +- .../coursetable/course_table_control.dart | 66 ++--- .../pages/coursetable/course_table_page.dart | 271 +++++++++--------- .../pages/videoplayer/class_video_player.dart | 8 +- 27 files changed, 663 insertions(+), 303 deletions(-) create mode 100644 lib/src/model/coursetable/course.dart create mode 100644 lib/src/model/coursetable/course.g.dart create mode 100644 lib/src/model/coursetable/course_period.dart create mode 100644 lib/src/model/coursetable/course_period.g.dart create mode 100644 lib/src/model/coursetable/course_table.dart create mode 100644 lib/src/model/coursetable/course_table.g.dart create mode 100644 lib/src/model/coursetable/user.dart create mode 100644 lib/src/model/coursetable/user.g.dart diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index aa92a42d..3454080c 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -8,6 +8,8 @@ import 'package:flutter_app/src/connector/ntut_connector.dart'; import 'package:flutter_app/src/model/course/course_class_json.dart'; import 'package:flutter_app/src/model/course/course_main_extra_json.dart'; import 'package:flutter_app/src/model/course/course_score_json.dart'; +import 'package:flutter_app/src/model/coursetable/course.dart'; +import 'package:flutter_app/src/model/coursetable/user.dart'; import 'package:flutter_app/src/model/course/course_syllabus_json.dart'; import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:html/dom.dart'; @@ -64,6 +66,112 @@ class CourseConnector { } } + static Future> getEnglishCourses(String studentId, int year, int semester) async { + ConnectorParameter parameter = ConnectorParameter(_postCourseENUrl); + Map data = { + "code": studentId, + "format": "-2", + "year": year.toString(), + "sem": semester.toString(), + }; + parameter.charsetName = 'utf-8'; + parameter.data = data; + String result = await Connector.getDataByGet(parameter); + + Document tagNode = parse(result); + List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); + List courses = []; + + for(int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++){ + var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); + courses.add(Course( + id: courseRowData[0].text, + name: courseRowData[1].text, + stage: courseRowData[2].text, + credit: courseRowData[3].text, + periodCount: courseRowData[4].text, + category: "", + teacher: courseRowData[5].text, + className: courseRowData[6].text, + periodSlots: courseRowData.sublist(7, 14).map((data) => data.text).toList(), + classroom: courseRowData[14].text, + applyStatus: courseRowData[15].text, + language: courseRowData[16].text, + syllabusLink: "", + note: courseRowData[17].text + )); + } + + return courses; + } + + static Future getUserInfo(String studentId, int year, int semester) async { + ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + Map data = { + "code": studentId, + "format": "-2", + "year": year.toString(), + "sem": semester.toString(), + }; + parameter.charsetName = 'utf-8'; + parameter.data = data; + String result = await Connector.getDataByGet(parameter); + + Document tagNode = parse(result); + String courseTableHead = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr").first.text; + List matches = RegExp(r".+?:(.+?)\s").allMatches(courseTableHead).toList(); + + return User( + id: studentId, + name: matches[1].group(1), + className: matches[2].group(1) + ); + } + + static Future> getChineseCourses(String studentId, int year, int semester) async { + try { + ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + Map data = { + "code": studentId, + "format": "-2", + "year": year.toString(), + "sem": semester.toString(), + }; + parameter.charsetName = 'utf-8'; + parameter.data = data; + String result = await Connector.getDataByGet(parameter); + Document tagNode = parse(result); + List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); + List courses = []; + + for (int rowIndex = 2; rowIndex < courseRows.length - 1; rowIndex++) { + var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); + var syllabusNode = courseRowData[18].getElementsByTagName("a"); + courses.add(Course( + id: courseRowData[0].text, + name: courseRowData[1].text, + stage: courseRowData[2].text, + credit: courseRowData[3].text, + periodCount: courseRowData[4].text, + category: courseRowData[5].text, + teacher: courseRowData[6].text, + className: courseRowData[7].text, + periodSlots: courseRowData.sublist(8, 15).map((data) => data.text).toList(), + classroom: courseRowData[15].text, + applyStatus: courseRowData[16].text, + language: courseRowData[17].text, + syllabusLink: syllabusNode.isEmpty ? "" : _postCourseCNUrl + syllabusNode.first.attributes["href"], + note: courseRowData[19].text + )); + } + + return courses; + } catch (e, stack){ + Log.eWithStack(e.toString(), stack); + return null; + } + } + static Future getCourseENName(String url) async { try { ConnectorParameter parameter; diff --git a/lib/src/connector/ischool_plus_connector.dart b/lib/src/connector/ischool_plus_connector.dart index 4086ccb1..10ae2531 100644 --- a/lib/src/connector/ischool_plus_connector.dart +++ b/lib/src/connector/ischool_plus_connector.dart @@ -112,7 +112,7 @@ class ISchoolPlusConnector { } } - static Future>> getCourseFile(String courseId) async { + static Future>> getCourseFile(int courseId) async { ConnectorParameter parameter; String result; html.Document tagNode; @@ -263,7 +263,7 @@ class ISchoolPlusConnector { static String bid; - static Future>> getCourseAnnouncement(String courseId) async { + static Future>> getCourseAnnouncement(int courseId) async { String result; var value = ReturnWithStatus>(); try { @@ -460,7 +460,7 @@ class ISchoolPlusConnector { String result; try { parameter = ConnectorParameter("https://istudy.ntut.edu.tw/forum/subscribe.php"); - parameter.data = {"bid": bid}; + parameter.data = {"bid": bid.toString()}; await Connector.getDataByPost(parameter); result = await Connector.getDataByPost(parameter); tagNode = html.parse(result); @@ -471,7 +471,7 @@ class ISchoolPlusConnector { } } - static Future getBid(String courseId) async { + static Future getBid() async { /* ConnectorParameter parameter; html.Document tagNode; @@ -492,7 +492,7 @@ class ISchoolPlusConnector { return bid; } - static Future _selectCourse(String courseId) async { + static Future _selectCourse(int courseId) async { ConnectorParameter parameter; html.Document tagNode; html.Element node; @@ -508,7 +508,7 @@ class ISchoolPlusConnector { for (int i = 1; i < nodes.length; i++) { node = nodes[i]; String name = node.text.split("_").last; - if (name == courseId) { + if (name == courseId.toString()) { courseValue = node.attributes["value"]; break; } diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart new file mode 100644 index 00000000..af6a465b --- /dev/null +++ b/lib/src/model/coursetable/course.dart @@ -0,0 +1,84 @@ +import 'package:flutter_app/src/model/coursetable/course_period.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import '../json_init.dart'; + +part 'course.g.dart'; + +@JsonSerializable() +class Course { + late int id; + String name; + late int stage; + late double credit; + late int periodCount; + String category; + String teacher; + String className; + late List periodSlots; + late List coursePeriods; + String classroom; + String applyStatus; + String language; + String syllabusLink; + String note; + + Course({ + required String id, + required this.name, + required String stage, + required String credit, + required String periodCount, + required this.category, + required this.teacher, + required this.className, + required this.periodSlots, + required this.classroom, + required this.applyStatus, + required this.language, + required this.syllabusLink, + required this.note + }) { + this.id = JsonInit.intInit(id); + name = JsonInit.stringInit(name); + this.stage = JsonInit.intInit(stage); + this.credit = JsonInit.doubleInit(credit); + this.periodCount = JsonInit.intInit(periodCount); + category = JsonInit.stringInit(category); + teacher = JsonInit.stringInit(teacher); + periodSlots = JsonInit.listInit(periodSlots); + coursePeriods = _convertPeriodSlotsToCoursePeriods(periodSlots); + classroom = JsonInit.stringInit(classroom); + applyStatus = JsonInit.stringInit(applyStatus); + language = JsonInit.stringInit(language); + syllabusLink = JsonInit.stringInit(syllabusLink); + note = JsonInit.stringInit(note); + } + + bool isEmpty() => id == 0; + + static List _convertPeriodSlotsToCoursePeriods(List periodSlots){ + List coursePeriods = []; + for(int weekday = 1; weekday <= 7; weekday++){ + String weekdaySlot = periodSlots[weekday % 7]; + if(_isNullOrEmpty(weekdaySlot)){ + continue; + } + List periods = weekdaySlot.split(RegExp(r"\s")); + for(String period in periods) { + coursePeriods.add(CoursePeriod( + weekday: weekday, + period: period + )); + } + } + return coursePeriods; + } + + static bool _isNullOrEmpty(String? text){ + return text == null || text.replaceAll(RegExp(r"\s"), "").isEmpty; + } + + factory Course.fromJson(Map json) => _$CourseFromJson(json); + Map toJson() => _$CourseToJson(this); +} \ No newline at end of file diff --git a/lib/src/model/coursetable/course.g.dart b/lib/src/model/coursetable/course.g.dart new file mode 100644 index 00000000..6acb2adc --- /dev/null +++ b/lib/src/model/coursetable/course.g.dart @@ -0,0 +1,46 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'course.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Course _$CourseFromJson(Map json) => Course( + id: json['id'] as String, + name: json['name'] as String, + stage: json['stage'] as String, + credit: json['credit'] as String, + periodCount: json['periodCount'] as String, + category: json['category'] as String, + teacher: json['teacher'] as String, + className: json['className'] as String, + periodSlots: (json['periodSlots'] as List) + .map((e) => e as String) + .toList(), + classroom: json['classroom'] as String, + applyStatus: json['applyStatus'] as String, + language: json['language'] as String, + syllabusLink: json['syllabusLink'] as String, + note: json['note'] as String, + )..coursePeriods = (json['coursePeriods'] as List) + .map((e) => CoursePeriod.fromJson(e as Map)) + .toList(); + +Map _$CourseToJson(Course instance) => { + 'id': instance.id, + 'name': instance.name, + 'stage': instance.stage, + 'credit': instance.credit, + 'periodCount': instance.periodCount, + 'category': instance.category, + 'teacher': instance.teacher, + 'className': instance.className, + 'periodSlots': instance.periodSlots, + 'coursePeriods': instance.coursePeriods, + 'classroom': instance.classroom, + 'applyStatus': instance.applyStatus, + 'language': instance.language, + 'syllabusLink': instance.syllabusLink, + 'note': instance.note, + }; diff --git a/lib/src/model/coursetable/course_period.dart b/lib/src/model/coursetable/course_period.dart new file mode 100644 index 00000000..a479ce60 --- /dev/null +++ b/lib/src/model/coursetable/course_period.dart @@ -0,0 +1,18 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'course_period.g.dart'; + +@JsonSerializable() +class CoursePeriod { + int weekday; + String period; + + CoursePeriod({required this.weekday, required this.period}){ + weekday = weekday; + period = period; + } + + factory CoursePeriod.fromJson(Map json) => _$CoursePeriodFromJson(json); + + Map toJson() => _$CoursePeriodToJson(this); +} \ No newline at end of file diff --git a/lib/src/model/coursetable/course_period.g.dart b/lib/src/model/coursetable/course_period.g.dart new file mode 100644 index 00000000..207e6d02 --- /dev/null +++ b/lib/src/model/coursetable/course_period.g.dart @@ -0,0 +1,18 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'course_period.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CoursePeriod _$CoursePeriodFromJson(Map json) => CoursePeriod( + weekday: json['weekday'] as int, + period: json['period'] as String, + ); + +Map _$CoursePeriodToJson(CoursePeriod instance) => + { + 'weekday': instance.weekday, + 'period': instance.period, + }; diff --git a/lib/src/model/coursetable/course_table.dart b/lib/src/model/coursetable/course_table.dart new file mode 100644 index 00000000..61e58fa8 --- /dev/null +++ b/lib/src/model/coursetable/course_table.dart @@ -0,0 +1,29 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'course.dart'; +import 'user.dart'; + +part 'course_table.g.dart'; + +@JsonSerializable() +class CourseTable { + int year; + int semester; + List courses; + User user; + + CourseTable({ + required this.year, + required this.semester, + required this.courses, + required this.user + }){ + year = year; + semester = semester; + courses = courses; + user = user; + } + + factory CourseTable.fromJson(Map json) => _$CourseTableFromJson(json); + Map toJson() => _$CourseTableToJson(this); +} \ No newline at end of file diff --git a/lib/src/model/coursetable/course_table.g.dart b/lib/src/model/coursetable/course_table.g.dart new file mode 100644 index 00000000..26b8a1a2 --- /dev/null +++ b/lib/src/model/coursetable/course_table.g.dart @@ -0,0 +1,24 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'course_table.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +CourseTable _$CourseTableFromJson(Map json) => CourseTable( + year: json['year'] as int, + semester: json['semester'] as int, + courses: (json['courses'] as List) + .map((e) => Course.fromJson(e as Map)) + .toList(), + user: User.fromJson(json['user'] as Map), + ); + +Map _$CourseTableToJson(CourseTable instance) => + { + 'year': instance.year, + 'semester': instance.semester, + 'courses': instance.courses, + 'user': instance.user, + }; diff --git a/lib/src/model/coursetable/user.dart b/lib/src/model/coursetable/user.dart new file mode 100644 index 00000000..b4429c94 --- /dev/null +++ b/lib/src/model/coursetable/user.dart @@ -0,0 +1,23 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'user.g.dart'; + +@JsonSerializable() +class User { + String id; + String name; + String className; + + User({ + required this.id, + required this.name, + required this.className + }){ + id = id; + name = name; + className = className; + } + + factory User.fromJson(Map json) => _$UserFromJson(json); + Map toJson() => _$UserToJson(this); +} \ No newline at end of file diff --git a/lib/src/model/coursetable/user.g.dart b/lib/src/model/coursetable/user.g.dart new file mode 100644 index 00000000..4942c5c0 --- /dev/null +++ b/lib/src/model/coursetable/user.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +User _$UserFromJson(Map json) => User( + id: json['id'] as String, + name: json['name'] as String, + className: json['className'] as String, + ); + +Map _$UserToJson(User instance) => { + 'id': instance.id, + 'name': instance.name, + 'className': instance.className, + }; diff --git a/lib/src/model/json_init.dart b/lib/src/model/json_init.dart index 321f9f99..aa46bf45 100644 --- a/lib/src/model/json_init.dart +++ b/lib/src/model/json_init.dart @@ -1,11 +1,17 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 class JsonInit { + static int intInit(String value){ + return value.isEmpty ? int.parse(value) : 0; + } + + static double doubleInit(String value){ + return value.isEmpty ? double.parse(value) : 0.00; + } + static String stringInit(String value) { return value ?? ""; } - static List listInit(List value) { - return value ?? [] as List; + static List listInit(List value){ + return value ?? []; } } diff --git a/lib/src/model/setting/setting_json.dart b/lib/src/model/setting/setting_json.dart index 326cc6bd..e373ea31 100644 --- a/lib/src/model/setting/setting_json.dart +++ b/lib/src/model/setting/setting_json.dart @@ -5,6 +5,8 @@ import 'package:flutter_app/src/model/json_init.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:sprintf/sprintf.dart'; +import '../coursetable/course_table.dart'; + part 'setting_json.g.dart'; @JsonSerializable() @@ -37,14 +39,14 @@ class SettingJson { @JsonSerializable() class CourseSettingJson { - CourseTableJson info; + CourseTable info; CourseSettingJson({this.info}) { - info = info ?? CourseTableJson(); + info = info; } bool get isEmpty { - return info.isEmpty; + return info.courses.isEmpty; } @override diff --git a/lib/src/model/setting/setting_json.g.dart b/lib/src/model/setting/setting_json.g.dart index 7717c429..7e85dad9 100644 --- a/lib/src/model/setting/setting_json.g.dart +++ b/lib/src/model/setting/setting_json.g.dart @@ -26,7 +26,7 @@ Map _$SettingJsonToJson(SettingJson instance) => json) { return CourseSettingJson( - info: json['info'] == null ? null : CourseTableJson.fromJson(json['info'] as Map), + info: json['info'] == null ? null : CourseTable.fromJson(json['info'] as Map), ); } diff --git a/lib/src/store/local_storage.dart b/lib/src/store/local_storage.dart index 400230a2..6cda5f21 100644 --- a/lib/src/store/local_storage.dart +++ b/lib/src/store/local_storage.dart @@ -12,9 +12,12 @@ import 'package:flutter_app/src/model/userdata/user_data_json.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:get/get.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:tat_core/tat_core.dart'; +import 'package:tat_core/core/zuvio/domain/login_credential.dart'; +import 'package:tat_core/core/zuvio/domain/user_info.dart'; import '../model/course/course_class_json.dart'; +import "../model/coursetable/course.dart"; +import '../model/coursetable/course_table.dart'; class LocalStorage { LocalStorage._(); @@ -37,7 +40,7 @@ class LocalStorage { final _zUserInfoKey = 'ZUserInfoKey'; final _zLoginCredentialKey = 'ZLoginCredentialKey'; final _firstRun = {}; - final _courseTableList = []; + final _courseTableList = []; final _httpClientInterceptors = []; @@ -112,52 +115,57 @@ class LocalStorage { _courseTableList.clear(); if (readJsonList != null) { for (final readJson in readJsonList) { - _courseTableList.add(CourseTableJson.fromJson(json.decode(readJson))); + _courseTableList.add(CourseTable.fromJson(json.decode(readJson))); } } } - String getCourseNameByCourseId(String courseId) { - for (final courseDetail in _courseTableList) { - final name = courseDetail.getCourseNameByCourseId(courseId); - if (name != null) { - return name; + String getCourseNameByCourseId(int courseId) { + for (final courseTable in _courseTableList) { + var course = courseTable.courses.firstWhere((course) => course.id == courseId, orElse: () => null); + if (course != null) { + return course.name; } } return null; } - void removeCourseTable(CourseTableJson addCourseTable) { + void removeCourseTable(CourseTable courseTable) { _courseTableList.removeWhere( - (courseTable) => - courseTable.courseSemester == addCourseTable.courseSemester && - courseTable.studentId == addCourseTable.studentId, + (value) => + value.semester == courseTable.semester && value.year == courseTable.year && + value.user.id == courseTable.user.id, ); } - void addCourseTable(CourseTableJson addCourseTable) { - removeCourseTable(addCourseTable); - _courseTableList.add(addCourseTable); + void addCourseTable(CourseTable courseTable) { + removeCourseTable(courseTable); + _courseTableList.add(courseTable); } - List getCourseTableList() { + List getCourseTableList() { _courseTableList.sort((a, b) { - if (a.studentId == b.studentId) { - return b.courseSemester.toString().compareTo(a.courseSemester.toString()); + if (a.user.id == b.user.id) { + if(a.year == b.year) { + return b.semester.compareTo(a.semester); + } + return a.year.compareTo(b.year); } - return a.studentId.compareTo(b.studentId); + return a.user.id.compareTo(b.user.id); }); return _courseTableList; } - CourseTableJson getCourseTable(String studentId, SemesterJson courseSemester) { - if (courseSemester == null || studentId == null || studentId.isEmpty) { + CourseTable getCourseTable(String studentId, int year, int semester) { + if (studentId == null || studentId.isEmpty) { return null; } return _courseTableList.firstWhereOrNull( - (courseTable) => courseTable.courseSemester == courseSemester && courseTable.studentId == studentId, + (courseTable) => courseTable.semester == semester && + courseTable.year == year && + courseTable.user.id == studentId, ); } diff --git a/lib/src/task/course/course_table_task.dart b/lib/src/task/course/course_table_task.dart index b0293c5f..b3c30796 100644 --- a/lib/src/task/course/course_table_task.dart +++ b/lib/src/task/course/course_table_task.dart @@ -7,61 +7,45 @@ import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; import 'package:flutter_app/src/util/language_util.dart'; +import '../../model/coursetable/course.dart'; +import '../../model/coursetable/course_table.dart'; import '../task.dart'; import 'course_system_task.dart'; -class CourseTableTask extends CourseSystemTask { +class CourseTableTask extends CourseSystemTask { final String studentId; - final SemesterJson semester; + final int year; + final int semester; - CourseTableTask(this.studentId, this.semester) : super("CourseTableTask"); + CourseTableTask(this.studentId, this.year, this.semester) : super("CourseTableTask"); @override Future execute() async { final status = await super.execute(); if (status == TaskStatus.success) { - super.onStart(R.current.getCourse); - CourseMainInfo? value; - if (studentId.length == 5) { - value = await CourseConnector.getTWTeacherCourseMainInfoList(studentId, semester); - } else { + super.onStart(R.current.getCourse); + List? courses; + var userInfo = await CourseConnector.getUserInfo(studentId, year, semester); + // TODO: Handle Teacher Situation. if (LanguageUtil.getLangIndex() == LangEnum.zh) { - value = await CourseConnector.getTWCourseMainInfoList(studentId, semester); + courses = await CourseConnector.getEnglishCourses(studentId, year, semester); } else { - value = await CourseConnector.getENCourseMainInfoList(studentId, semester) as CourseMainInfo?; + courses = await CourseConnector.getChineseCourses(studentId, year, semester); } - } - super.onEnd(); - if (value != null) { - final courseTable = CourseTableJson(); - courseTable.courseSemester = semester; - courseTable.studentId = studentId; - courseTable.studentName = value.studentName; + super.onEnd(); + final courseTable = CourseTable( + year: year, + semester: semester, + courses: courses, + user: userInfo + ); + LocalStorage.instance.addCourseTable(courseTable); + await LocalStorage.instance.saveCourseTableList(); - for (final courseMainInfo in value.json) { - final courseInfo = CourseInfoJson(); - bool add = false; - for (int i = 0; i < 7; i++) { - final day = Day.values[i]; - final time = courseMainInfo.course.time[day]; - courseInfo.main = courseMainInfo; - add |= courseTable.setCourseDetailByTimeString(day, time, courseInfo); - } - if (!add) { - courseTable.setCourseDetailByTime(Day.UnKnown, SectionNumber.T_UnKnown, courseInfo); - } - } - if (studentId == LocalStorage.instance.getAccount()) { - //只儲存自己的課表 - LocalStorage.instance.addCourseTable(courseTable); - await LocalStorage.instance.saveCourseTableList(); - } result = courseTable; return TaskStatus.success; } else { return super.onError(R.current.getCourseError); } - } - return status; } } diff --git a/lib/src/task/iplus/iplus_course_announcement_task.dart b/lib/src/task/iplus/iplus_course_announcement_task.dart index 5457432d..74d8fe87 100644 --- a/lib/src/task/iplus/iplus_course_announcement_task.dart +++ b/lib/src/task/iplus/iplus_course_announcement_task.dart @@ -10,7 +10,7 @@ import '../task.dart'; import 'iplus_system_task.dart'; class IPlusCourseAnnouncementTask extends IPlusSystemTask> { - final String id; + final int id; IPlusCourseAnnouncementTask(this.id) : super("IPlusCourseAnnouncementTask"); diff --git a/lib/src/task/iplus/iplus_course_file_task.dart b/lib/src/task/iplus/iplus_course_file_task.dart index 533ab2a6..07bd94c0 100644 --- a/lib/src/task/iplus/iplus_course_file_task.dart +++ b/lib/src/task/iplus/iplus_course_file_task.dart @@ -10,7 +10,7 @@ import '../task.dart'; import 'iplus_system_task.dart'; class IPlusCourseFileTask extends IPlusSystemTask> { - final String id; + final int id; IPlusCourseFileTask(this.id) : super("IPlusCourseFileTask"); diff --git a/lib/src/task/iplus/iplus_get_course_subscribe_task.dart b/lib/src/task/iplus/iplus_get_course_subscribe_task.dart index 8ae95517..f7944739 100644 --- a/lib/src/task/iplus/iplus_get_course_subscribe_task.dart +++ b/lib/src/task/iplus/iplus_get_course_subscribe_task.dart @@ -6,7 +6,7 @@ import 'package:flutter_app/src/task/iplus/iplus_system_task.dart'; import 'package:flutter_app/src/task/task.dart'; class IPlusGetCourseSubscribeTask extends IPlusSystemTask> { - final String id; + final int id; IPlusGetCourseSubscribeTask(this.id) : super("IPlusGetCourseSubscribeTask"); @@ -15,7 +15,7 @@ class IPlusGetCourseSubscribeTask extends IPlusSystemTask> final status = await super.execute(); if (status == TaskStatus.success) { super.onStart(R.current.searchSubscribe); - final courseBid = await ISchoolPlusConnector.getBid(id); + final courseBid = await ISchoolPlusConnector.getBid(); final openNotifications = await ISchoolPlusConnector.getCourseSubscribe(courseBid); super.onEnd(); result = { diff --git a/lib/ui/other/route_utils.dart b/lib/ui/other/route_utils.dart index a7bba903..1dfc23f2 100644 --- a/lib/ui/other/route_utils.dart +++ b/lib/ui/other/route_utils.dart @@ -24,6 +24,8 @@ import 'package:flutter_app/ui/screen/login_screen.dart'; import 'package:flutter_app/ui/screen/main_screen.dart'; import 'package:get/get.dart'; +import '../../src/model/coursetable/course.dart'; + class RouteUtils { static Transition transition = (Platform.isAndroid) ? Transition.downToUp : Transition.cupertino; @@ -67,9 +69,9 @@ class RouteUtils { ); } - static Future? toISchoolPage(String studentId, CourseInfoJson courseInfo) { + static Future? toISchoolPage(String studentId, Course course) { return Get.to( - () => ISchoolPage(studentId, courseInfo), + () => ISchoolPage(studentId, course), transition: transition, ); } @@ -122,15 +124,15 @@ class RouteUtils { DioConnector.instance.getAlice(navigatorKey: Get.key).showInspector(); } - static Future? toIPlusAnnouncementDetailPage(CourseInfoJson courseInfo, Map detail) { + static Future? toIPlusAnnouncementDetailPage(Course course, Map detail) { return Get.to( - () => IPlusAnnouncementDetailPage(courseInfo, detail), + () => IPlusAnnouncementDetailPage(course, detail), transition: transition, ); } - static Future? toVideoPlayer(String url, CourseInfoJson courseInfo, String name) => Get.to( - () => ClassVideoPlayer(url, courseInfo, name), + static Future? toVideoPlayer(String url, Course course, String name) => Get.to( + () => ClassVideoPlayer(url, course, name), transition: transition, ); diff --git a/lib/ui/pages/coursedetail/course_detail_page.dart b/lib/ui/pages/coursedetail/course_detail_page.dart index 794c6240..f0b8fe55 100644 --- a/lib/ui/pages/coursedetail/course_detail_page.dart +++ b/lib/ui/pages/coursedetail/course_detail_page.dart @@ -13,11 +13,13 @@ import 'package:flutter_app/ui/pages/coursedetail/tab_page.dart'; import 'package:get/get.dart'; import 'package:provider/provider.dart'; +import '../../../src/model/coursetable/course.dart'; + class ISchoolPage extends StatefulWidget { - final CourseInfoJson courseInfo; + final Course course; final String studentId; - const ISchoolPage(this.studentId, this.courseInfo, {Key key}) : super(key: key); + const ISchoolPage(this.studentId, this.course, {Key key}) : super(key: key); @override State createState() => _ISchoolPageState(); @@ -33,12 +35,12 @@ class _ISchoolPageState extends State with SingleTickerProviderStat void initState() { super.initState(); tabPageList = TabPageList(); - tabPageList.add(TabPage(R.current.course, Icons.info, CourseInfoPage(widget.studentId, widget.courseInfo))); + tabPageList.add(TabPage(R.current.course, Icons.info, CourseInfoPage(widget.studentId, widget.course))); if (widget.studentId == LocalStorage.instance.getAccount()) { tabPageList.add(TabPage( - R.current.announcement, Icons.announcement, IPlusAnnouncementPage(widget.studentId, widget.courseInfo))); + R.current.announcement, Icons.announcement, IPlusAnnouncementPage(widget.studentId, widget.course))); tabPageList.add( - TabPage(R.current.fileAndVideo, Icons.file_download, IPlusFilePage(widget.studentId, widget.courseInfo))); + TabPage(R.current.fileAndVideo, Icons.file_download, IPlusFilePage(widget.studentId, widget.course))); } _tabController = TabController(vsync: this, length: tabPageList.length); @@ -63,8 +65,7 @@ class _ISchoolPageState extends State with SingleTickerProviderStat } Widget tabPageView() { - CourseMainJson course = widget.courseInfo.main.course; - + Course course = widget.course; return DefaultTabController( length: tabPageList.length, child: Scaffold( diff --git a/lib/ui/pages/coursedetail/screen/course_info_page.dart b/lib/ui/pages/coursedetail/screen/course_info_page.dart index 6ff49c14..32fdc625 100644 --- a/lib/ui/pages/coursedetail/screen/course_info_page.dart +++ b/lib/ui/pages/coursedetail/screen/course_info_page.dart @@ -14,11 +14,13 @@ import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:get/get.dart'; import 'package:sprintf/sprintf.dart'; +import '../../../../src/model/coursetable/course.dart'; + class CourseInfoPage extends StatefulWidget { - final CourseInfoJson courseInfo; + final Course course; final String studentId; - const CourseInfoPage(this.studentId, this.courseInfo, {Key key}) : super(key: key); + const CourseInfoPage(this.studentId, this.course, {Key key}) : super(key: key); final int courseInfoWithAlpha = 0x44; @@ -27,8 +29,7 @@ class CourseInfoPage extends StatefulWidget { } class _CourseInfoPageState extends State with AutomaticKeepAliveClientMixin { - CourseMainInfoJson courseMainInfo; - CourseExtraInfoJson courseExtraInfo; + Course course; bool isLoading = true; final List courseData = []; final List listItem = []; @@ -58,32 +59,24 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive } void _addTask() async { - courseMainInfo = widget.courseInfo.main; - final courseId = courseMainInfo.course.id; - final taskFlow = TaskFlow(); - final task = CourseExtraInfoTask(courseId); - taskFlow.addTask(task); - if (await taskFlow.start()) { - courseExtraInfo = task.result; - } - widget.courseInfo.extra = courseExtraInfo; - courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.courseId, courseMainInfo.course.id]))); - courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.courseName, courseMainInfo.course.name]))); - courseData.add(_buildCourseInfo(sprintf("%s: %s ", [R.current.credit, courseMainInfo.course.credits]))); - courseData.add(_buildCourseInfo(sprintf("%s: %s ", [R.current.category, courseExtraInfo.course.category]))); + course = widget.course; + courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.courseId, course.id]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.courseName, course.name]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s ", [R.current.credit, course.credit]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s ", [R.current.category, course.category]))); courseData.add( _buildCourseInfoWithButton( - sprintf("%s: %s", [R.current.instructor, courseMainInfo.getTeacherName()]), + sprintf("%s: %s", [R.current.instructor, course.teacher]), R.current.syllabus, - courseMainInfo.course.scheduleHref, + course.syllabusLink, ), ); - courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.startClass, courseMainInfo.getOpenClassName()]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.startClass, course.className]))); courseData.add(_buildMultiButtonInfo( sprintf("%s: ", [R.current.classroom]), R.current.classroomUse, - courseMainInfo.getClassroomNameList(), - courseMainInfo.getClassroomHrefList(), + [], + [], )); listItem.removeRange(0, listItem.length); diff --git a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart index 243617c2..e5430c16 100644 --- a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart +++ b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart @@ -13,11 +13,13 @@ import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart import 'package:get/get.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../../../../../src/model/coursetable/course.dart'; + class IPlusAnnouncementDetailPage extends StatefulWidget { final Map data; - final CourseInfoJson courseInfo; + final Course course; - const IPlusAnnouncementDetailPage(this.courseInfo, this.data, {Key key}) : super(key: key); + const IPlusAnnouncementDetailPage(this.course, this.data, {Key key}) : super(key: key); @override State createState() => _IPlusAnnouncementDetailPage(); @@ -50,7 +52,7 @@ class _IPlusAnnouncementDetailPage extends State { leading: BackButton( onPressed: () => Get.back(), ), - title: Text(widget.courseInfo.main.course.name), + title: Text(widget.course.name), actions: [ PopupMenuButton( onSelected: (result) { @@ -191,7 +193,7 @@ class _IPlusAnnouncementDetailPage extends State { } void _downloadFile(String url, String name) async { - String courseName = widget.courseInfo.main.course.name; + String courseName = widget.course.name; await FileDownload.download(url, courseName, name); } diff --git a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart index 41264bbf..a147b490 100644 --- a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart +++ b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart @@ -12,11 +12,13 @@ import 'package:flutter_app/src/task/iplus/iplus_course_announcement_task.dart'; import 'package:flutter_app/src/task/task_flow.dart'; import 'package:flutter_app/ui/other/route_utils.dart'; +import '../../../../../src/model/coursetable/course.dart'; + class IPlusAnnouncementPage extends StatefulWidget { - final CourseInfoJson courseInfo; + final Course course; final String studentId; - const IPlusAnnouncementPage(this.studentId, this.courseInfo, {Key key}) : super(key: key); + const IPlusAnnouncementPage(this.studentId, this.course, {Key key}) : super(key: key); @override State createState() => _IPlusAnnouncementPage(); @@ -41,7 +43,7 @@ class _IPlusAnnouncementPage extends State with Automatic void _addTask() async { //第一次 - String courseId = widget.courseInfo.main.course.id; + int courseId = widget.course.id; TaskFlow taskFlow = TaskFlow(); var task = IPlusCourseAnnouncementTask(courseId); var getTask = IPlusGetCourseSubscribeTask(courseId); @@ -67,7 +69,7 @@ class _IPlusAnnouncementPage extends State with Automatic if (await taskFlow.start()) { detail = task.result; } - RouteUtils.toIPlusAnnouncementDetailPage(widget.courseInfo, detail); + RouteUtils.toIPlusAnnouncementDetailPage(widget.course, detail); } @override diff --git a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart index b066f2dd..2b7d625c 100644 --- a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart +++ b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart @@ -20,13 +20,15 @@ import 'package:flutter_app/ui/other/route_utils.dart'; import 'package:sprintf/sprintf.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../../../../../src/model/coursetable/course.dart'; + class IPlusFilePage extends StatefulWidget { - final CourseInfoJson courseInfo; + final Course course; final String studentId; const IPlusFilePage( this.studentId, - this.courseInfo, { + this.course, { super.key, }); @@ -71,7 +73,7 @@ class _IPlusFilePage extends State with AutomaticKeepAliveClientM void _addTask() async { await Future.delayed(const Duration(microseconds: 500)); - final courseId = widget.courseInfo.main.course.id; + final courseId = widget.course.id; final taskFlow = TaskFlow(); final task = IPlusCourseFileTask(courseId); @@ -230,7 +232,7 @@ class _IPlusFilePage extends State with AutomaticKeepAliveClientM Future _downloadOneFile(int index, [showToast = true]) async { final courseFile = courseFileList[index]; final fileType = courseFile.fileType[0]; - final dirName = widget.courseInfo.main.course.name; + final dirName = widget.course.name; String url = ""; String referer = ""; @@ -266,7 +268,7 @@ class _IPlusFilePage extends State with AutomaticKeepAliveClientM errorDialogParameter.dialogType = DialogType.info; errorDialogParameter.okButtonText = R.current.sure; errorDialogParameter.onOkButtonClicked = - () => RouteUtils.toVideoPlayer(urlParse.toString(), widget.courseInfo, courseFile.name); + () => RouteUtils.toVideoPlayer(urlParse.toString(), widget.course, courseFile.name); MsgDialog(errorDialogParameter).show(); } else { await FileDownload.download(url, dirName, courseFile.name, referer); diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index bb60f4f7..4442368a 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -5,6 +5,9 @@ import 'package:flutter_app/src/config/app_colors.dart'; import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; +import '../../../src/model/coursetable/course.dart'; +import '../../../src/model/coursetable/course_table.dart'; + class CourseTableControl { bool isHideSaturday = false; bool isHideSunday = false; @@ -14,7 +17,7 @@ class CourseTableControl { bool isHideB = false; bool isHideC = false; bool isHideD = false; - CourseTableJson courseTable; + CourseTable courseTable; List dayStringList = [ R.current.Monday, R.current.Tuesday, @@ -47,16 +50,16 @@ class CourseTableControl { static int sectionLength = 14; Map colorMap; - void set(CourseTableJson value) { + void set(CourseTable value) { courseTable = value; - isHideSaturday = !courseTable.isDayInCourseTable(Day.Saturday); - isHideSunday = !courseTable.isDayInCourseTable(Day.Sunday); - isHideUnKnown = !courseTable.isDayInCourseTable(Day.UnKnown); - isHideN = !courseTable.isSectionNumberInCourseTable(SectionNumber.T_N); - isHideA = (!courseTable.isSectionNumberInCourseTable(SectionNumber.T_A)); - isHideB = (!courseTable.isSectionNumberInCourseTable(SectionNumber.T_B)); - isHideC = (!courseTable.isSectionNumberInCourseTable(SectionNumber.T_C)); - isHideD = (!courseTable.isSectionNumberInCourseTable(SectionNumber.T_D)); + isHideSaturday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 6)); + isHideSunday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 7)); + isHideUnKnown = true; + isHideN = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "N")); + isHideA = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "A")); + isHideB = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "B")); + isHideC = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "C")); + isHideD = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "D")); isHideA &= (isHideB & isHideC & isHideD); isHideB &= (isHideC & isHideD); isHideC &= isHideD; @@ -74,29 +77,23 @@ class CourseTableControl { return intList; } - CourseInfoJson getCourseInfo(int intDay, int intNumber) { - final day = Day.values[intDay]; - final number = SectionNumber.values[intNumber]; - - if (courseTable == null) { - return null; - } - - return courseTable?.courseInfoMap[day][number]; + Course getCourse(int weekday, String period) { + return courseTable.courses.firstWhere((course) => + course.coursePeriods.any((coursePeriod) => + coursePeriod.period == period && coursePeriod.weekday == weekday + ) + ); } - Color getCourseInfoColor(int intDay, int intNumber) { - final courseInfo = getCourseInfo(intDay, intNumber); - + Color getCourseInfoColor(int weekday, String period) { + Course course = getCourse(weekday, period); if (colorMap == null) { return Colors.white; } for (final key in colorMap.keys) { - if (courseInfo != null) { - if (key == courseInfo.main.course.id) { - return colorMap[key]; - } + if (key == course.id.toString()) { + return colorMap[key]; } } @@ -105,7 +102,7 @@ class CourseTableControl { void _initColorList() { colorMap = {}; - List courseInfoList = courseTable.getCourseIdList(); + List courseInfoList = courseTable.courses.map((course) => course.id.toString()).toList(); int colorCount = courseInfoList.length; colorCount = (colorCount == 0) ? 1 : colorCount; @@ -116,17 +113,12 @@ class CourseTableControl { } } - List get getSectionIntList { - List intList = []; - for (int i = 0; i < sectionLength; i++) { - if (isHideN && i == 4) continue; - if (isHideA && i == 10) continue; - if (isHideB && i == 11) continue; - if (isHideC && i == 12) continue; - if (isHideD && i == 13) continue; - intList.add(i); + List get getSectionList { + List list = []; + for(Course course in courseTable.courses){ + list.addAll(course.coursePeriods.map((coursePeriod) => coursePeriod.period).toList()); } - return intList; + return list.toSet().toList(); } String getDayString(int day) { diff --git a/lib/ui/pages/coursetable/course_table_page.dart b/lib/ui/pages/coursetable/course_table_page.dart index b9f382dc..457c9cd9 100644 --- a/lib/ui/pages/coursetable/course_table_page.dart +++ b/lib/ui/pages/coursetable/course_table_page.dart @@ -29,6 +29,9 @@ import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sprintf/sprintf.dart'; +import '../../../src/model/coursetable/course.dart'; +import '../../../src/model/coursetable/course_table.dart'; + class CourseTablePage extends StatefulWidget { const CourseTablePage({Key key}) : super(key: key); @@ -41,7 +44,7 @@ class _CourseTablePageState extends State { final FocusNode _studentFocus = FocusNode(); final GlobalKey _key = GlobalKey(); bool isLoading = true; - CourseTableJson courseTableData; + CourseTable courseTableData; static double dayHeight = 25; static double studentIdHeight = 40; static double courseHeight = 60; @@ -59,83 +62,83 @@ class _CourseTablePageState extends State { Future.microtask(() => _loadLocalSettings()); } - void getCourseNotice() async { - setState(() { - loadCourseNotice = false; - }); - if (!LocalStorage.instance.getOtherSetting().checkIPlusNew) { - return; - } - if (!LocalStorage.instance.getFirstUse(LocalStorage.courseNotice, timeOut: 15 * 60)) { - return; - } - if (LocalStorage.instance.getAccount() != LocalStorage.instance.getCourseSetting().info.studentId) { - //只有顯示自己的課表時才會檢查新公告 - return; - } - setState(() { - loadCourseNotice = true; - }); - - TaskFlow taskFlow = TaskFlow(); - var task = IPlusSubscribeNoticeTask(); - task.openLoadingDialog = false; - taskFlow.addTask(task); - if (await taskFlow.start()) { - List v = task.result; - List value = []; - v = v ?? []; - for (int i = 0; i < v.length; i++) { - String courseName = v[i]; - CourseInfoJson courseInfo = courseTableData.getCourseInfoByCourseName(courseName); - if (courseInfo != null) { - value.add(courseName); - } - } - if (value != null && value.isNotEmpty) { - Get.dialog( - AlertDialog( - title: Text(R.current.findNewMessage), - content: SizedBox( - width: double.minPositive, - child: ListView.builder( - itemCount: value.length, - shrinkWrap: true, //使清單最小化 - itemBuilder: (BuildContext context, int index) { - return TextButton( - child: Text(value[index]), - onPressed: () { - String courseName = value[index]; - CourseInfoJson courseInfo = courseTableData.getCourseInfoByCourseName(courseName); - if (courseInfo != null) { - _showCourseDetail(courseInfo); - } else { - MyToast.show(R.current.noSupport); - Get.back(); - } - }, - ); - }, - ), - ), - actions: [ - TextButton( - child: Text(R.current.sure), - onPressed: () { - Get.back(); - }, - ), - ], - ), - barrierDismissible: true, - ); - } - } - LocalStorage.instance.setAlreadyUse(LocalStorage.courseNotice); - setState(() { - loadCourseNotice = false; - }); - } + // void getCourseNotice() async { + // setState(() { + // loadCourseNotice = false; + // }); + // if (!LocalStorage.instance.getOtherSetting().checkIPlusNew) { + // return; + // } + // if (!LocalStorage.instance.getFirstUse(LocalStorage.courseNotice, timeOut: 15 * 60)) { + // return; + // } + // if (LocalStorage.instance.getAccount() != LocalStorage.instance.getCourseSetting().info.user.id) { + // //只有顯示自己的課表時才會檢查新公告 + // return; + // } + // setState(() { + // loadCourseNotice = true; + // }); + // + // TaskFlow taskFlow = TaskFlow(); + // var task = IPlusSubscribeNoticeTask(); + // task.openLoadingDialog = false; + // taskFlow.addTask(task); + // if (await taskFlow.start()) { + // List v = task.result; + // List value = []; + // v = v ?? []; + // for (int i = 0; i < v.length; i++) { + // String courseName = v[i]; + // CourseInfoJson courseInfo = courseTableData.getCourseInfoByCourseName(courseName); + // if (courseInfo != null) { + // value.add(courseName); + // } + // } + // if (value != null && value.isNotEmpty) { + // Get.dialog( + // AlertDialog( + // title: Text(R.current.findNewMessage), + // content: SizedBox( + // width: double.minPositive, + // child: ListView.builder( + // itemCount: value.length, + // shrinkWrap: true, //使清單最小化 + // itemBuilder: (BuildContext context, int index) { + // return TextButton( + // child: Text(value[index]), + // onPressed: () { + // String courseName = value[index]; + // CourseInfoJson courseInfo = courseTableData.getCourseInfoByCourseName(courseName); + // if (courseInfo != null) { + // _showCourseDetail(courseInfo); + // } else { + // MyToast.show(R.current.noSupport); + // Get.back(); + // } + // }, + // ); + // }, + // ), + // ), + // actions: [ + // TextButton( + // child: Text(R.current.sure), + // onPressed: () { + // Get.back(); + // }, + // ), + // ], + // ), + // barrierDismissible: true, + // ); + // } + // } + // LocalStorage.instance.setAlreadyUse(LocalStorage.courseNotice); + // setState(() { + // loadCourseNotice = false; + // }); + // } @override void setState(fn) { @@ -154,8 +157,8 @@ class _CourseTablePageState extends State { final renderObject = _key.currentContext.findRenderObject(); courseHeight = (renderObject.semanticBounds.size.height - studentIdHeight - dayHeight) / showCourseTableNum; final courseTable = LocalStorage.instance.getCourseSetting().info; - if (courseTable == null || courseTable.isEmpty) { - _getCourseTable(studentId: courseTable.studentId, semesterSetting: courseTable.courseSemester); + if (courseTable == null || courseTable.courses.isEmpty) { + _getCourseTable(studentId: courseTable.user.id, year: courseTable.year, semester: courseTable.semester); } else { _showCourseTable(courseTable); } @@ -170,32 +173,22 @@ class _CourseTablePageState extends State { } } - void _getCourseTable({SemesterJson semesterSetting, String studentId, bool refresh = false}) async { + void _getCourseTable({int year, int semester, String studentId, bool refresh = false}) async { await Future.delayed(const Duration(microseconds: 100)); //等待頁面刷新 UserDataJson userData = LocalStorage.instance.getUserData(); studentId = studentId?.trim() ?? ''; studentId = (studentId.isEmpty ? null : studentId) ?? userData.account; - if (courseTableData?.studentId != studentId) { + if (courseTableData.user.id != studentId) { LocalStorage.instance.clearSemesterJsonList(); //需重設因為更換了studentId } - SemesterJson semesterJson; - if (semesterSetting == null || semesterSetting.semester.isEmpty || semesterSetting.year.isEmpty) { - await _getSemesterList(studentId); - semesterJson = LocalStorage.instance.getSemesterJsonItem(0); - } else { - semesterJson = semesterSetting; - } - if (semesterJson == null) { - return; - } - CourseTableJson courseTable; + CourseTable courseTable; if (!refresh) { - courseTable = LocalStorage.instance.getCourseTable(studentId, semesterSetting); //去取找是否已經暫存 + courseTable = LocalStorage.instance.getCourseTable(studentId, year, semester); //去取找是否已經暫存 } if (courseTable == null) { TaskFlow taskFlow = TaskFlow(); - var task = CourseTableTask(studentId, semesterJson); + var task = CourseTableTask(studentId, year, semester); taskFlow.addTask(task); if (await taskFlow.start()) { courseTable = task.result; @@ -209,13 +202,13 @@ class _CourseTablePageState extends State { } } - Widget _getSemesterItem(SemesterJson semester) { - final semesterString = "${semester.year}-${semester.semester}"; + Widget _getSemesterItem(int year, int semester) { + final semesterString = "$year-$semester"; return TextButton( child: Text(semesterString), onPressed: () { Get.back(); - _getCourseTable(semesterSetting: semester, studentId: _studentIdControl.text); //取得課表 + _getCourseTable(year: year, semester: semester, studentId: _studentIdControl.text); //取得課表 }, ); } @@ -244,7 +237,7 @@ class _CourseTablePageState extends State { child: ListView.builder( itemCount: semesterList?.length ?? 0, shrinkWrap: true, - itemBuilder: (context, index) => _getSemesterItem(semesterList[index]), + itemBuilder: (context, index) => _getSemesterItem(int.parse(semesterList[index].year), int.parse(semesterList[index].semester)), ), ), ), @@ -255,7 +248,7 @@ class _CourseTablePageState extends State { _onPopupMenuSelect(int value) { switch (value) { case 0: - final credit = courseTableData?.getTotalCredit()?.toString(); + final credit = courseTableData?.courses?.map((course) => course.credit)?.toList()?.reduce((value, element) => value + element); if (credit != null) { MyToast.show(sprintf("%s:%s", [R.current.credit, credit])); } @@ -281,7 +274,7 @@ class _CourseTablePageState extends State { } void _loadFavorite() async { - List value = LocalStorage.instance.getCourseTableList(); + List value = LocalStorage.instance.getCourseTableList(); if (value.isEmpty) { MyToast.show(R.current.noAnyFavorite); return; @@ -319,11 +312,11 @@ class _CourseTablePageState extends State { child: SizedBox( height: 50, child: TextButton( - child: Text(sprintf("%s %s %s-%s", [ - value[index].studentId, - value[index].studentName, - value[index].courseSemester.year, - value[index].courseSemester.semester + child: Text(sprintf("%s %s %d-%d", [ + value[index].user.id, + value[index].user.name, + value[index].year, + value[index].semester ])), onPressed: () { LocalStorage.instance.getCourseSetting().info = value[index]; //儲存課表 @@ -350,8 +343,9 @@ class _CourseTablePageState extends State { @override Widget build(BuildContext context) { - final semesterSetting = courseTableData?.courseSemester ?? SemesterJson(); - final semesterString = "${semesterSetting.year}-${semesterSetting.semester}"; + final year = courseTableData == null ? 0 : courseTableData.year; + final semester = courseTableData == null ? 0 : courseTableData.semester; + final semesterString = "$year-$semester"; return Scaffold( resizeToAvoidBottomInset: false, @@ -368,7 +362,7 @@ class _CourseTablePageState extends State { ), ) : const SizedBox.shrink(), - (!isLoading && LocalStorage.instance.getAccount() != courseTableData?.studentId) + (!isLoading && LocalStorage.instance.getAccount() != courseTableData.user.id) ? Padding( padding: const EdgeInsets.only( right: 20, @@ -388,7 +382,8 @@ class _CourseTablePageState extends State { ), child: InkWell( onTap: () => _getCourseTable( - semesterSetting: courseTableData?.courseSemester, + year: year, + semester: semester, studentId: _studentIdControl.text, refresh: true, ), @@ -500,7 +495,7 @@ class _CourseTablePageState extends State { ) : Column( children: List.generate( - 1 + courseTableControl.getSectionIntList.length, + 1 + courseTableControl.getSectionList.length, (index) { final widget = (index == 0) ? _buildDay() : _buildCourseTable(index - 1); return AnimationConfiguration.staggeredList( @@ -544,7 +539,7 @@ class _CourseTablePageState extends State { } Widget _buildCourseTable(int index) { - final section = courseTableControl.getSectionIntList[index]; + final section = courseTableControl.getSectionList[index]; final color = index % 2 == 1 ? Theme.of(context).colorScheme.surface : Theme.of(context).colorScheme.surfaceVariant.withAlpha(courseTableWithAlpha); @@ -554,7 +549,7 @@ class _CourseTablePageState extends State { width: sectionWidth, alignment: Alignment.center, child: Text( - courseTableControl.getSectionString(section), + section, textAlign: TextAlign.center, ), ), @@ -563,11 +558,11 @@ class _CourseTablePageState extends State { final isDarkMode = Get.isDarkMode; for (final day in courseTableControl.getDayIntList) { - final courseInfo = courseTableControl.getCourseInfo(day, section) ?? CourseInfoJson(); + final course = courseTableControl.getCourse(day, section); final color = courseTableControl.getCourseInfoColor(day, section); widgetList.add( Expanded( - child: (courseInfo.isEmpty) + child: (course.isEmpty()) ? const SizedBox.shrink() : Card( elevation: 0, @@ -582,7 +577,7 @@ class _CourseTablePageState extends State { child: InkWell( borderRadius: const BorderRadius.all(Radius.circular(5)), highlightColor: isDarkMode ? Colors.white : Colors.black12, - onTap: () => showCourseDetailDialog(section, courseInfo), + onTap: () => showCourseDetailDialog(section, course), child: Stack( children: [ Align( @@ -590,7 +585,7 @@ class _CourseTablePageState extends State { child: Padding( padding: const EdgeInsets.all(2), child: AutoSizeText( - courseInfo.main.course.name, + course.name, style: const TextStyle( color: Colors.black, fontSize: 14, @@ -622,12 +617,11 @@ class _CourseTablePageState extends State { } //顯示課程對話框 - void showCourseDetailDialog(int section, CourseInfoJson courseInfo) { + void showCourseDetailDialog(String section, Course course) { _unFocusStudentInput(); - final course = courseInfo.main.course; - final classroomName = courseInfo.main.getClassroomName(); - final teacherName = courseInfo.main.getTeacherName(); - final studentId = LocalStorage.instance.getCourseSetting().info.studentId; + final classroomName = course.classroom; + final teacherName = course.teacher; + final studentId = LocalStorage.instance.getCourseSetting().info.user.id; setState(() { _studentIdControl.text = studentId; }); @@ -642,20 +636,20 @@ class _CourseTablePageState extends State { GestureDetector( child: Text(sprintf("%s : %s", [R.current.courseId, course.id])), onLongPress: () async { - course.id = await _showEditDialog(course.id); + course.id = int.parse(await _showEditDialog(course.id.toString())); await LocalStorage.instance.saveOtherSetting(); setState(() {}); }, ), - Text(sprintf("%s : %s", [R.current.time, courseTableControl.getTimeString(section)])), + Text(sprintf("%s : %s", [R.current.time, section])), Text(sprintf("%s : %s", [R.current.location, classroomName])), Text(sprintf("%s : %s", [R.current.instructor, teacherName])), ], ), - actions: courseInfo.main.course.id.isNotEmpty + actions: !course.isEmpty() ? [ TextButton.icon( - onPressed: () => _showCourseDetail(courseInfo), + onPressed: () => _showCourseDetail(course), icon: const Icon(Icons.add_outlined), label: Text(R.current.details), ), @@ -702,17 +696,18 @@ class _CourseTablePageState extends State { return v ?? value; } - void _showCourseDetail(CourseInfoJson courseInfo) { - final course = courseInfo.main.course; + void _showCourseDetail(Course course) { Get.back(); - final studentId = LocalStorage.instance.getCourseSetting().info.studentId; - if (course.id.isEmpty) { + final studentId = LocalStorage.instance.getCourseSetting().info.user.id; + if (course.isEmpty()) { MyToast.show(course.name + R.current.noSupport); } else { - RouteUtils.toISchoolPage(studentId, courseInfo).then((value) { + RouteUtils.toISchoolPage(studentId, course).then((value) { if (value != null) { - final semesterSetting = LocalStorage.instance.getCourseSetting().info.courseSemester; - _getCourseTable(semesterSetting: semesterSetting, studentId: value); + final courseTable = LocalStorage.instance.getCourseSetting().info; + final year = courseTable.year; + final semester = courseTable.semester; + _getCourseTable(year: year, semester: semester, studentId: value); } }); } @@ -723,13 +718,13 @@ class _CourseTablePageState extends State { _studentFocus.unfocus(); } - void _showCourseTable(CourseTableJson courseTable) async { + void _showCourseTable(CourseTable courseTable) async { if (courseTable == null) { return; } - getCourseNotice(); //查詢訂閱的課程是否有公告 + // getCourseNotice(); //查詢訂閱的課程是否有公告 courseTableData = courseTable; - _studentIdControl.text = courseTable.studentId; + _studentIdControl.text = courseTable.user.id; _unFocusStudentInput(); setState(() { isLoading = true; @@ -739,7 +734,7 @@ class _CourseTablePageState extends State { setState(() { isLoading = false; }); - favorite = (LocalStorage.instance.getCourseTable(courseTable.studentId, courseTable.courseSemester) != null); + favorite = (LocalStorage.instance.getCourseTable(courseTable.user.id, courseTable.year, courseTable.semester) != null); if (favorite) { LocalStorage.instance.addCourseTable(courseTableData); } @@ -755,7 +750,7 @@ class _CourseTablePageState extends State { final directory = await getApplicationSupportDirectory(); final path = directory.path; - setState(() => courseHeight = height / courseTableControl.getSectionIntList.length); + setState(() => courseHeight = height / courseTableControl.getSectionList.length); await Future.delayed(const Duration(milliseconds: 100)); setState(() => isLoading = true); diff --git a/lib/ui/pages/videoplayer/class_video_player.dart b/lib/ui/pages/videoplayer/class_video_player.dart index d38ebe29..7ab83c56 100644 --- a/lib/ui/pages/videoplayer/class_video_player.dart +++ b/lib/ui/pages/videoplayer/class_video_player.dart @@ -20,16 +20,18 @@ import 'package:html/parser.dart'; import 'package:path/path.dart' as path; import 'package:video_player/video_player.dart'; +import '../../../src/model/coursetable/course.dart'; + class ClassVideoPlayer extends StatefulWidget { const ClassVideoPlayer( this.videoUrl, - this.courseInfo, + this.course, this.name, { super.key, }); final String videoUrl; - final CourseInfoJson courseInfo; + final Course course; final String name; @override @@ -192,7 +194,7 @@ class _VideoPlayer extends State { return; } - final courseName = widget.courseInfo.main.course.name; + final courseName = widget.course.name; final saveName = "${widget.name}_${_selectedVideoInfo.name}.mp4"; final subDir = (LanguageUtil.getLangIndex() == LangEnum.zh) ? "上課錄影" : "video"; final dirName = path.join(courseName, subDir); From 540eca7744d33f74310c696b02e70a128334c725 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 2 Feb 2024 23:37:55 +0800 Subject: [PATCH 02/31] Fix: Loading semester list when year and semester not exists. --- lib/ui/pages/coursetable/course_table_page.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/ui/pages/coursetable/course_table_page.dart b/lib/ui/pages/coursetable/course_table_page.dart index 457c9cd9..8fb744a5 100644 --- a/lib/ui/pages/coursetable/course_table_page.dart +++ b/lib/ui/pages/coursetable/course_table_page.dart @@ -182,6 +182,13 @@ class _CourseTablePageState extends State { LocalStorage.instance.clearSemesterJsonList(); //需重設因為更換了studentId } + if(year == 0 && semester == 0){ + await _getSemesterList(studentId); + SemesterJson semesterJson = LocalStorage.instance.getSemesterJsonItem(0); + year = int.parse(semesterJson.year); + semester = int.parse(semesterJson.semester); + } + CourseTable courseTable; if (!refresh) { courseTable = LocalStorage.instance.getCourseTable(studentId, year, semester); //去取找是否已經暫存 From 488dc963f19d151d534b5d056df597e2e1285ee9 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Sun, 4 Feb 2024 23:25:52 +0800 Subject: [PATCH 03/31] Refactor: course_connector.dart --- lib/src/connector/course_connector.dart | 315 ++---------------- lib/src/model/coursetable/course.dart | 69 ++-- lib/src/model/coursetable/course.g.dart | 45 ++- lib/src/model/json_init.dart | 4 +- lib/src/task/course/course_table_task.dart | 4 +- .../coursedetail/screen/course_info_page.dart | 257 +++++++++++++- .../coursetable/course_table_control.dart | 53 ++- .../pages/coursetable/course_table_page.dart | 250 +++++++------- 8 files changed, 508 insertions(+), 489 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index 3454080c..529d79b2 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -85,20 +85,20 @@ class CourseConnector { for(int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++){ var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); courses.add(Course( - id: courseRowData[0].text, + idString: courseRowData[0].text, name: courseRowData[1].text, - stage: courseRowData[2].text, - credit: courseRowData[3].text, - periodCount: courseRowData[4].text, + stageString: "", + creditString: courseRowData[2].text, + periodCountString: courseRowData[3].text, category: "", - teacher: courseRowData[5].text, - className: courseRowData[6].text, - periodSlots: courseRowData.sublist(7, 14).map((data) => data.text).toList(), - classroom: courseRowData[14].text, - applyStatus: courseRowData[15].text, - language: courseRowData[16].text, + teacherString: courseRowData[4].innerHtml.replaceAll("
", "\n"), + classNameString: courseRowData[5].text, + periodSlots: courseRowData.sublist(6, 13).map((data) => data.text).toList(), + classroomString: courseRowData[13].text, + applyStatus: courseRowData[14].text, + language: courseRowData[15].text, syllabusLink: "", - note: courseRowData[17].text + note: courseRowData[16].text )); } @@ -148,16 +148,16 @@ class CourseConnector { var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); var syllabusNode = courseRowData[18].getElementsByTagName("a"); courses.add(Course( - id: courseRowData[0].text, + idString: courseRowData[0].text, name: courseRowData[1].text, - stage: courseRowData[2].text, - credit: courseRowData[3].text, - periodCount: courseRowData[4].text, + stageString: courseRowData[2].text, + creditString: courseRowData[3].text, + periodCountString: courseRowData[4].text, category: courseRowData[5].text, - teacher: courseRowData[6].text, - className: courseRowData[7].text, + teacherString: courseRowData[6].text, + classNameString: courseRowData[7].text, periodSlots: courseRowData.sublist(8, 15).map((data) => data.text).toList(), - classroom: courseRowData[15].text, + classroomString: courseRowData[15].text, applyStatus: courseRowData[16].text, language: courseRowData[17].text, syllabusLink: syllabusNode.isEmpty ? "" : _postCourseCNUrl + syllabusNode.first.attributes["href"], @@ -181,7 +181,9 @@ class CourseConnector { parameter.charsetName = 'big5'; String result = await Connector.getDataByGet(parameter); tagNode = parse(result); - node = tagNode.getElementsByTagName("table").first; + node = tagNode + .getElementsByTagName("table") + .first; node = node.getElementsByTagName("tr")[1]; return node.getElementsByTagName("td")[2].text.replaceAll(RegExp(r"\n"), ""); } catch (e, stack) { @@ -190,89 +192,6 @@ class CourseConnector { } } - static Future getCourseExtraInfo(String courseId) async { - try { - ConnectorParameter parameter; - Document tagNode; - Element node; - List courseNodes, nodes, classExtraInfoNodes; - Map data = { - "code": courseId, - "format": "-1", - }; - parameter = ConnectorParameter(_postCourseCNUrl); - parameter.data = data; - String result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - courseNodes = tagNode.getElementsByTagName("table"); - - CourseExtraInfoJson courseExtraInfo = CourseExtraInfoJson(); - - //取得學期資料 - nodes = courseNodes[0].getElementsByTagName("td"); - SemesterJson semester = SemesterJson(); - - // Previously, the title string of the first course table was stored separately in its `` element, - // but it currently stores all the information in a row, - // e.g. "學號:110310144  姓名:xxx  班級:電機三甲    112 學年度 第 1 學期 上課時間表" - // so the RegExp is used to filter out only the number parts - final titleString = nodes[0].text; - final RegExp studentSemesterDetailFilter = RegExp(r'\b[\dA-Z]+\b'); - final Iterable studentSemesterDetailMatches = studentSemesterDetailFilter.allMatches(titleString); - // "studentSemesterDetails" should consist of three numerical values - // ex: [110310144, 112, 1] - final List studentSemesterDetails = studentSemesterDetailMatches.map((match) => match.group(0)).toList(); - if (studentSemesterDetails.isEmpty) { - throw RangeError("[TAT] course_connector.dart: studentSemesterDetails list is empty"); - } - if (studentSemesterDetails.length < 3) { - throw RangeError("[TAT] course_connector.dart: studentSemesterDetails list has range less than 3"); - } - semester.year = studentSemesterDetails[1]; - semester.semester = studentSemesterDetails[2]; - - courseExtraInfo.courseSemester = semester; - - CourseExtraJson courseExtra = CourseExtraJson(); - - nodes = courseNodes[1].getElementsByTagName("tr"); - final List courseIds = nodes.skip(2).map((node) => node.getElementsByTagName("td")[0].text).toList(); - final courseIdPosition = courseIds.indexWhere((element) => element.contains(courseId)); - if (courseIdPosition == -1) { - throw StateError('[TAT] course_connector.dart: CourseId not found: $courseId'); - } else { - node = nodes[courseIdPosition + 2]; - } - classExtraInfoNodes = node.getElementsByTagName("td"); - courseExtra.id = strQ2B(classExtraInfoNodes[0].text).replaceAll(RegExp(r"\s"), ""); - courseExtra.name = classExtraInfoNodes[1].getElementsByTagName("a")[0].text; - courseExtra.openClass = classExtraInfoNodes[7].getElementsByTagName("a")[0].text; - - // if the courseExtraInfo.herf (課程大綱連結) is empty, - // the category of the course will be set to ▲ (校訂專業必修) as default - if (classExtraInfoNodes[18].text.trim() != "" && - classExtraInfoNodes[18].getElementsByTagName("a")[0].attributes.containsKey("href")) { - courseExtra.href = _courseCNHost + classExtraInfoNodes[18].getElementsByTagName("a")[0].attributes["href"]; - parameter = ConnectorParameter(courseExtra.href); - result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - nodes = tagNode.getElementsByTagName("tr"); - courseExtra.category = nodes[1].getElementsByTagName("td")[6].text; - } else { - courseExtra.category = constCourseType[4]; - } - - courseExtra.selectNumber = "s?"; - courseExtra.withdrawNumber = "w?"; - - courseExtraInfo.course = courseExtra; - return courseExtraInfo; - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - return null; - } - } - static Future getCourseCategory(String courseId) async { try { Map data = { @@ -355,198 +274,6 @@ class CourseConnector { return String.fromCharCodes(newString); } - static Future getENCourseMainInfoList(String studentId, SemesterJson semester) async { - var info = CourseMainInfo(); - try { - ConnectorParameter parameter; - Document tagNode; - List courseNodes, nodesOne, nodes; - List dayEnum = [Day.Sunday, Day.Monday, Day.Tuesday, Day.Wednesday, Day.Thursday, Day.Friday, Day.Saturday]; - Map data = { - "code": studentId, - "format": "-2", - "year": semester.year, - "sem": semester.semester, - }; - parameter = ConnectorParameter(_postCourseENUrl); - parameter.data = data; - parameter.charsetName = 'utf-8'; - Response response = await Connector.getDataByPostResponse(parameter); - tagNode = parse(response.toString()); - nodes = tagNode.getElementsByTagName("table"); - courseNodes = nodes[1].getElementsByTagName("tr"); - String studentName; - try { - studentName = strQ2B(nodes[0].getElementsByTagName("td")[4].text).replaceAll(RegExp(r"[\n| ]"), ""); - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - studentName = ""; - } - info.studentName = studentName; - - List courseMainInfoList = []; - for (int i = 1; i < courseNodes.length - 1; i++) { - CourseMainInfoJson courseMainInfo = CourseMainInfoJson(); - CourseMainJson courseMain = CourseMainJson(); - nodesOne = courseNodes[i].getElementsByTagName("td"); - if (nodesOne[16].text.contains("Withdraw")) { - continue; - } - //取得課號 - courseMain.id = strQ2B(nodesOne[0].text).replaceAll(RegExp(r"[\n| ]"), ""); - //取的課程名稱/課程連結 - nodes = nodesOne[1].getElementsByTagName("a"); //確定是否有連結 - if (nodes.isNotEmpty) { - courseMain.name = nodes[0].text; - } else { - courseMain.name = nodesOne[1].text; - } - courseMain.credits = nodesOne[2].text.replaceAll("\n", ""); //學分 - courseMain.hours = nodesOne[3].text.replaceAll("\n", ""); //時數 - - //時間 - for (int j = 0; j < 7; j++) { - Day day = dayEnum[j]; //要做變換網站是從星期日開始 - String time = nodesOne[j + 6].text; - time = strQ2B(time); - courseMain.time[day] = time; - } - - courseMainInfo.course = courseMain; - - int length; - //取得老師名稱 - length = nodesOne[4].innerHtml.split("
").length; - for (String name in nodesOne[4].innerHtml.split("
")) { - TeacherJson teacher = TeacherJson(); - teacher.name = name.replaceAll("\n", ""); - courseMainInfo.teacher.add(teacher); - } - - //取得教室名稱 - length = nodesOne[13].innerHtml.split("
").length; - for (String name in nodesOne[13].innerHtml.split("
").getRange(0, length - 1)) { - ClassroomJson classroom = ClassroomJson(); - classroom.name = name.replaceAll("\n", ""); - courseMainInfo.classroom.add(classroom); - } - - //取得開設教室名稱 - for (Element node in nodesOne[5].getElementsByTagName("a")) { - ClassJson classInfo = ClassJson(); - classInfo.name = node.text; - classInfo.href = _courseCNHost + node.attributes["href"]; - courseMainInfo.openClass.add(classInfo); - } - courseMainInfoList.add(courseMainInfo); - } - info.json = courseMainInfoList; - return info; - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - return null; - } - } - - static Future getTWCourseMainInfoList(String studentId, SemesterJson semester) async { - var info = CourseMainInfo(); - try { - ConnectorParameter parameter; - Document tagNode; - Element node; - List courseNodes, nodesOne, nodes; - List dayEnum = [Day.Sunday, Day.Monday, Day.Tuesday, Day.Wednesday, Day.Thursday, Day.Friday, Day.Saturday]; - Map data = { - "code": studentId, - "format": "-2", - "year": semester.year, - "sem": semester.semester, - }; - parameter = ConnectorParameter(_postCourseCNUrl); - parameter.data = data; - Response response = await Connector.getDataByPostResponse(parameter); - tagNode = parse(response.toString()); - node = tagNode.getElementsByTagName("table")[1]; - courseNodes = node.getElementsByTagName("tr"); - String studentName; - try { - studentName = RegExp(r"姓名:([\u4E00-\u9FA5]+)").firstMatch(courseNodes[0].text).group(1); - } catch (e) { - studentName = ""; - } - info.studentName = studentName; - List courseMainInfoList = []; - for (int i = 2; i < courseNodes.length - 1; i++) { - CourseMainInfoJson courseMainInfo = CourseMainInfoJson(); - CourseMainJson courseMain = CourseMainJson(); - - nodesOne = courseNodes[i].getElementsByTagName("td"); - if (nodesOne[16].text.contains("撤選")) { - continue; - } - //取得課號 - courseMain.id = strQ2B(nodesOne[0].text).replaceAll(RegExp(r"\s"), ""); - - //取的課程名稱/課程連結 - nodes = nodesOne[1].getElementsByTagName("a"); //確定是否有連結 - if (nodes.isNotEmpty) { - courseMain.name = nodes[0].text; - } else { - courseMain.name = nodesOne[1].text; - } - courseMain.stage = nodesOne[2].text.replaceAll("\n", ""); //階段 - courseMain.credits = nodesOne[3].text.replaceAll("\n", ""); //學分 - courseMain.hours = nodesOne[4].text.replaceAll("\n", ""); //時數 - courseMain.note = nodesOne[19].text.replaceAll("\n", ""); //備註 - if (nodesOne[18].getElementsByTagName("a").isNotEmpty) { - courseMain.scheduleHref = - _courseCNHost + nodesOne[18].getElementsByTagName("a")[0].attributes["href"]; //教學進度大綱 - } - - //時間 - for (int j = 0; j < 7; j++) { - Day day = dayEnum[j]; //要做變換網站是從星期日開始 - String time = nodesOne[j + 8].text; - time = strQ2B(time); - courseMain.time[day] = time; - } - - courseMainInfo.course = courseMain; - - //取得老師名稱 - for (Element node in nodesOne[6].getElementsByTagName("a")) { - TeacherJson teacher = TeacherJson(); - teacher.name = node.text; - teacher.href = _courseCNHost + node.attributes["href"]; - courseMainInfo.teacher.add(teacher); - } - - //取得教室名稱 - for (Element node in nodesOne[15].getElementsByTagName("a")) { - ClassroomJson classroom = ClassroomJson(); - classroom.name = node.text; - classroom.href = _courseCNHost + node.attributes["href"]; - courseMainInfo.classroom.add(classroom); - } - - //取得開設教室名稱 - for (Element node in nodesOne[7].getElementsByTagName("a")) { - ClassJson classInfo = ClassJson(); - classInfo.name = node.text; - classInfo.href = _courseCNHost + node.attributes["href"]; - courseMainInfo.openClass.add(classInfo); - } - - courseMainInfoList.add(courseMainInfo); - } - info.json = courseMainInfoList; - return info; - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - return null; - } - } - static Future getTWTeacherCourseMainInfoList(String studentId, SemesterJson semester) async { var info = CourseMainInfo(); try { diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index af6a465b..fea8b647 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -7,52 +7,73 @@ part 'course.g.dart'; @JsonSerializable() class Course { + String idString; late int id; + String name; - late int stage; + + String stageString; + late double stage; + + String creditString; late double credit; + + String periodCountString; late int periodCount; + String category; - String teacher; - String className; - late List periodSlots; + + String teacherString; + late List teachers; + + String classNameString; + late List classNames; + + List periodSlots; late List coursePeriods; - String classroom; + + String classroomString; + late List classrooms; + String applyStatus; String language; String syllabusLink; String note; Course({ - required String id, + required this.idString, required this.name, - required String stage, - required String credit, - required String periodCount, + required this.stageString, + required this.creditString, + required this.periodCountString, required this.category, - required this.teacher, - required this.className, + required this.teacherString, + required this.classNameString, required this.periodSlots, - required this.classroom, + required this.classroomString, required this.applyStatus, required this.language, required this.syllabusLink, required this.note }) { - this.id = JsonInit.intInit(id); - name = JsonInit.stringInit(name); - this.stage = JsonInit.intInit(stage); - this.credit = JsonInit.doubleInit(credit); - this.periodCount = JsonInit.intInit(periodCount); - category = JsonInit.stringInit(category); - teacher = JsonInit.stringInit(teacher); + id = JsonInit.intInit(idString); + name = JsonInit.stringInit(name).trim(); + stage = JsonInit.doubleInit(stageString); + credit = JsonInit.doubleInit(creditString); + periodCount = JsonInit.intInit(periodCountString); + category = JsonInit.stringInit(category).trim(); + teacherString = JsonInit.stringInit(teacherString).trim(); + teachers = teacherString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); periodSlots = JsonInit.listInit(periodSlots); coursePeriods = _convertPeriodSlotsToCoursePeriods(periodSlots); - classroom = JsonInit.stringInit(classroom); - applyStatus = JsonInit.stringInit(applyStatus); - language = JsonInit.stringInit(language); - syllabusLink = JsonInit.stringInit(syllabusLink); - note = JsonInit.stringInit(note); + classroomString = JsonInit.stringInit(classroomString).trim(); + classrooms = classroomString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); + classNameString = JsonInit.stringInit(classNameString).trim(); + classNames = classNameString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); + applyStatus = JsonInit.stringInit(applyStatus).trim(); + language = JsonInit.stringInit(language).trim(); + syllabusLink = JsonInit.stringInit(syllabusLink).trim(); + note = JsonInit.stringInit(note).trim(); } bool isEmpty() => id == 0; diff --git a/lib/src/model/coursetable/course.g.dart b/lib/src/model/coursetable/course.g.dart index 6acb2adc..181ee043 100644 --- a/lib/src/model/coursetable/course.g.dart +++ b/lib/src/model/coursetable/course.g.dart @@ -7,38 +7,57 @@ part of 'course.dart'; // ************************************************************************** Course _$CourseFromJson(Map json) => Course( - id: json['id'] as String, + idString: json['idString'] as String, name: json['name'] as String, - stage: json['stage'] as String, - credit: json['credit'] as String, - periodCount: json['periodCount'] as String, + stageString: json['stageString'] as String, + creditString: json['creditString'] as String, + periodCountString: json['periodCountString'] as String, category: json['category'] as String, - teacher: json['teacher'] as String, - className: json['className'] as String, + teacherString: json['teacherString'] as String, + classNameString: json['classNameString'] as String, periodSlots: (json['periodSlots'] as List) .map((e) => e as String) .toList(), - classroom: json['classroom'] as String, + classroomString: json['classroomString'] as String, applyStatus: json['applyStatus'] as String, language: json['language'] as String, syllabusLink: json['syllabusLink'] as String, note: json['note'] as String, - )..coursePeriods = (json['coursePeriods'] as List) - .map((e) => CoursePeriod.fromJson(e as Map)) - .toList(); + ) + ..id = json['id'] as int + ..stage = (json['stage'] as num).toDouble() + ..credit = (json['credit'] as num).toDouble() + ..periodCount = json['periodCount'] as int + ..teachers = + (json['teachers'] as List).map((e) => e as String).toList() + ..classNames = + (json['classNames'] as List).map((e) => e as String).toList() + ..coursePeriods = (json['coursePeriods'] as List) + .map((e) => CoursePeriod.fromJson(e as Map)) + .toList() + ..classrooms = (json['classrooms'] as List) + .map((e) => e as String) + .toList(); Map _$CourseToJson(Course instance) => { + 'idString': instance.idString, 'id': instance.id, 'name': instance.name, + 'stageString': instance.stageString, 'stage': instance.stage, + 'creditString': instance.creditString, 'credit': instance.credit, + 'periodCountString': instance.periodCountString, 'periodCount': instance.periodCount, 'category': instance.category, - 'teacher': instance.teacher, - 'className': instance.className, + 'teacherString': instance.teacherString, + 'teachers': instance.teachers, + 'classNameString': instance.classNameString, + 'classNames': instance.classNames, 'periodSlots': instance.periodSlots, 'coursePeriods': instance.coursePeriods, - 'classroom': instance.classroom, + 'classroomString': instance.classroomString, + 'classrooms': instance.classrooms, 'applyStatus': instance.applyStatus, 'language': instance.language, 'syllabusLink': instance.syllabusLink, diff --git a/lib/src/model/json_init.dart b/lib/src/model/json_init.dart index aa46bf45..8e36b70f 100644 --- a/lib/src/model/json_init.dart +++ b/lib/src/model/json_init.dart @@ -1,10 +1,10 @@ class JsonInit { static int intInit(String value){ - return value.isEmpty ? int.parse(value) : 0; + return value.replaceAll(RegExp(r"\s"), "").isNotEmpty ? int.parse(value) : 0; } static double doubleInit(String value){ - return value.isEmpty ? double.parse(value) : 0.00; + return value.replaceAll(RegExp(r"\s"), "").isNotEmpty ? double.parse(value) : 0.00; } static String stringInit(String value) { diff --git a/lib/src/task/course/course_table_task.dart b/lib/src/task/course/course_table_task.dart index b3c30796..aff5e6c4 100644 --- a/lib/src/task/course/course_table_task.dart +++ b/lib/src/task/course/course_table_task.dart @@ -28,9 +28,9 @@ class CourseTableTask extends CourseSystemTask { var userInfo = await CourseConnector.getUserInfo(studentId, year, semester); // TODO: Handle Teacher Situation. if (LanguageUtil.getLangIndex() == LangEnum.zh) { - courses = await CourseConnector.getEnglishCourses(studentId, year, semester); - } else { courses = await CourseConnector.getChineseCourses(studentId, year, semester); + } else { + courses = await CourseConnector.getEnglishCourses(studentId, year, semester); } super.onEnd(); final courseTable = CourseTable( diff --git a/lib/ui/pages/coursedetail/screen/course_info_page.dart b/lib/ui/pages/coursedetail/screen/course_info_page.dart index 32fdc625..cb5bc7eb 100644 --- a/lib/ui/pages/coursedetail/screen/course_info_page.dart +++ b/lib/ui/pages/coursedetail/screen/course_info_page.dart @@ -1,14 +1,8 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 import 'dart:async'; import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_app/src/model/course/course_main_extra_json.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; -import 'package:flutter_app/src/task/course/course_extra_info_task.dart'; -import 'package:flutter_app/src/task/task_flow.dart'; import 'package:flutter_app/ui/other/route_utils.dart'; import 'package:flutter_staggered_animations/flutter_staggered_animations.dart'; import 'package:get/get.dart'; @@ -20,7 +14,7 @@ class CourseInfoPage extends StatefulWidget { final Course course; final String studentId; - const CourseInfoPage(this.studentId, this.course, {Key key}) : super(key: key); + const CourseInfoPage(this.studentId, this.course, {required Key key}) : super(key: key); final int courseInfoWithAlpha = 0x44; @@ -29,7 +23,7 @@ class CourseInfoPage extends StatefulWidget { } class _CourseInfoPageState extends State with AutomaticKeepAliveClientMixin { - Course course; + late Course course; bool isLoading = true; final List courseData = []; final List listItem = []; @@ -62,27 +56,29 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive course = widget.course; courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.courseId, course.id]))); courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.courseName, course.name]))); - courseData.add(_buildCourseInfo(sprintf("%s: %s ", [R.current.credit, course.credit]))); - courseData.add(_buildCourseInfo(sprintf("%s: %s ", [R.current.category, course.category]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.credit, course.credit]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.category, course.category]))); courseData.add( _buildCourseInfoWithButton( - sprintf("%s: %s", [R.current.instructor, course.teacher]), + sprintf("%04s: %s", [R.current.instructor, course.teachers.join(" ")]), R.current.syllabus, course.syllabusLink, ), ); - courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.startClass, course.className]))); + courseData.add(_buildCourseInfo(sprintf("%s: %s", [R.current.startClass, course.classNames.join(" ")]))); courseData.add(_buildMultiButtonInfo( sprintf("%s: ", [R.current.classroom]), R.current.classroomUse, - [], - [], + course.classrooms, + course.classrooms, )); listItem.removeRange(0, listItem.length); listItem.add(_buildInfoTitle(R.current.courseData)); listItem.addAll(courseData); - + // listItem.add(_buildCourseCard(course)); + // listItem.add(_buildInfoTitle("課程修課資訊")); + // listItem.add(_buildCourseApplyCard(course)); isLoading = false; setState(() {}); } @@ -133,6 +129,230 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive ); } + Widget _buildCourseApplyCard(Course course) { + return SizedBox( + height: MediaQuery + .of(context) + .size + .width * 0.35, + child: Row( + children: [ + Expanded( + flex: 5, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.blueAccent + ), + padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(2), + child: const Text( + "修課人數", + style: TextStyle(fontSize: 14) + ) + ), + Expanded( + child: Center( + child: Text( + "150", + style: const TextStyle(fontSize: 36) + ) + ) + ) + ] + ) + ) + ), + Container(padding: const EdgeInsets.all(10)), + Expanded( + flex: 5, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.grey + ), + padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(2), + child: const Text( + "撤選人數", + style: TextStyle(fontSize: 14) + ) + ), + Expanded( + child: Center( + child: Text( + "5", + style: const TextStyle(fontSize: 36) + ) + ) + ) + ] + ) + ) + ) + ] + ) + ); + } + + Widget _buildCourseCard(Course course) { + return SizedBox( + height: MediaQuery + .of(context) + .size + .width * 0.65, + child: Row( + children: [ + Expanded( + flex: 8, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.yellow[900] + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FractionallySizedBox( + child: Container( + padding: const EdgeInsets.all(10), + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.id.toString(), + style: const TextStyle(fontSize: 16) + ) + ), + ), + FractionallySizedBox( + child: Container( + padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), + alignment: const Align(alignment: Alignment.centerLeft).alignment, + child: Container( + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text(course.name, style: const TextStyle(fontSize: 18)), + ) + ), + ), + FractionallySizedBox( + child: Container( + padding: const EdgeInsets.all(10), + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Column( + children: [ + Container( + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.classNames.join(" "), + style: const TextStyle(fontSize: 14), + ) + ), + Container( + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.teachers.join(" "), + style: const TextStyle(fontSize: 14), + ) + ), + Container( + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.classrooms.join(" "), + style: const TextStyle(fontSize: 14), + ) + ) + ], + ) + ) + ) + ], + ) + ) + ), + Container(padding: const EdgeInsets.all(10)), + Expanded( + flex: 3, + child: Column( + children: [ + Expanded( + flex: 5, + child: Container( + alignment: const Align(alignment: Alignment.topCenter).alignment, + padding: const EdgeInsets.all(10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.deepOrange + ), + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(10), + child: const Text( + "類別", + style: TextStyle(fontSize: 14) + ) + ), + Container( + padding: const EdgeInsets.all(10), + child: Center( + child: Text( + course.category == "選" ? "選修" : "必修", + style: const TextStyle(fontSize: 18) + ) + ) + ) + ] + ) + ) + ), + Container( + padding: const EdgeInsets.all(10) + ), + Expanded( + flex: 5, + child: Container( + padding: const EdgeInsets.all(10), + alignment: const Align(alignment: Alignment.topCenter).alignment, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.deepOrangeAccent + ), + child: Column( + children: [ + Container( + padding: const EdgeInsets.all(10), + child: const Text( + "學分數", + style: TextStyle(fontSize: 14) + ) + ), + Container( + padding: const EdgeInsets.all(10), + child: Center( + child: Text( + course.credit.toString(), + style: const TextStyle(fontSize: 18) + ) + ) + ) + ] + ) + ), + ) + ] + ), + ) + ] + ) + ); + } + Widget _buildCourseInfo(String text) { TextStyle textStyle = const TextStyle(fontSize: 18); return Container( @@ -140,7 +360,8 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive child: Row( children: [ const Icon(Icons.details), - Expanded( + Container( + alignment: const Align(alignment: Alignment.topCenter).alignment, child: Text( text, style: textStyle, @@ -190,7 +411,7 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive Widget _buildInfoTitle(String title) { TextStyle textStyle = const TextStyle(fontSize: 24); return Container( - padding: const EdgeInsets.only(top: 5, bottom: 5), + padding: const EdgeInsets.only(top: 20, bottom: 20), child: Row( children: [ Text( @@ -202,7 +423,7 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive ); } - Widget _buildMultiButtonInfo(String title, String buttonText, List textList, List urlList) { + Widget _buildMultiButtonInfo(String title, String buttonText, List textList, List urlList) { const textStyle = TextStyle(fontSize: 18); final classroomItemList = []; diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index 4442368a..f1152844 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -2,6 +2,7 @@ // @dart=2.10 import 'package:flutter/material.dart'; import 'package:flutter_app/src/config/app_colors.dart'; +import 'package:flutter_app/src/model/coursetable/course_period.dart'; import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; @@ -19,13 +20,13 @@ class CourseTableControl { bool isHideD = false; CourseTable courseTable; List dayStringList = [ + R.current.Sunday, R.current.Monday, R.current.Tuesday, R.current.Wednesday, R.current.Thursday, R.current.Friday, R.current.Saturday, - R.current.Sunday, R.current.UnKnown ]; List timeList = [ @@ -53,8 +54,8 @@ class CourseTableControl { void set(CourseTable value) { courseTable = value; isHideSaturday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 6)); - isHideSunday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 7)); - isHideUnKnown = true; + isHideSunday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 0)); + isHideUnKnown = !courseTable.courses.any((course) => course.coursePeriods.isEmpty); isHideN = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "N")); isHideA = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "A")); isHideB = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "B")); @@ -69,28 +70,35 @@ class CourseTableControl { List get getDayIntList { List intList = []; for (int i = 0; i < dayLength; i++) { - if (isHideSaturday && i == 5) continue; - if (isHideSunday && i == 6) continue; + if (isHideSaturday && i == 6) continue; + if (isHideSunday && i == 0) continue; if (isHideUnKnown && i == 7) continue; intList.add(i); } return intList; } - Course getCourse(int weekday, String period) { + Course getCourse(int weekday, int period) { + if(weekday == 7){ + return getUnknownCourse(period); + } return courseTable.courses.firstWhere((course) => course.coursePeriods.any((coursePeriod) => - coursePeriod.period == period && coursePeriod.weekday == weekday - ) + coursePeriod.period == getSectionString(period) && coursePeriod.weekday == weekday + ), orElse: () => null ); } - Color getCourseInfoColor(int weekday, String period) { + Color getCourseInfoColor(int weekday, int period) { Course course = getCourse(weekday, period); if (colorMap == null) { return Colors.white; } + if (course == null){ + return Colors.white; + } + for (final key in colorMap.keys) { if (key == course.id.toString()) { return colorMap[key]; @@ -113,14 +121,27 @@ class CourseTableControl { } } - List get getSectionList { - List list = []; + List get getCoursePeriodList { + List list = []; for(Course course in courseTable.courses){ - list.addAll(course.coursePeriods.map((coursePeriod) => coursePeriod.period).toList()); + list.addAll(course.coursePeriods.map((coursePeriod) => coursePeriod).toList()); } return list.toSet().toList(); } + List get getSectionIntList { + List intList = []; + for (int i = 0; i < sectionLength; i++) { + if (isHideN && i == 4) continue; + if (isHideA && i == 10) continue; + if (isHideB && i == 11) continue; + if (isHideC && i == 12) continue; + if (isHideD && i == 13) continue; + intList.add(i); + } + return intList; + } + String getDayString(int day) { return dayStringList[day]; } @@ -132,4 +153,12 @@ class CourseTableControl { String getSectionString(int section) { return sectionStringList[section]; } + + Course getUnknownCourse(int period){ + int index = period; + if(index >= courseTable.courses.where((course) => course.coursePeriods.isEmpty).length){ + return null; + } + return courseTable.courses.where((course) => course.coursePeriods.isEmpty).toList()[index]; + } } diff --git a/lib/ui/pages/coursetable/course_table_page.dart b/lib/ui/pages/coursetable/course_table_page.dart index 8fb744a5..fa8a27ca 100644 --- a/lib/ui/pages/coursetable/course_table_page.dart +++ b/lib/ui/pages/coursetable/course_table_page.dart @@ -11,7 +11,6 @@ import 'package:flutter/services.dart'; import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/config/app_config.dart'; import 'package:flutter_app/src/model/course/course_class_json.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/model/userdata/user_data_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; @@ -62,83 +61,86 @@ class _CourseTablePageState extends State { Future.microtask(() => _loadLocalSettings()); } - // void getCourseNotice() async { - // setState(() { - // loadCourseNotice = false; - // }); - // if (!LocalStorage.instance.getOtherSetting().checkIPlusNew) { - // return; - // } - // if (!LocalStorage.instance.getFirstUse(LocalStorage.courseNotice, timeOut: 15 * 60)) { - // return; - // } - // if (LocalStorage.instance.getAccount() != LocalStorage.instance.getCourseSetting().info.user.id) { - // //只有顯示自己的課表時才會檢查新公告 - // return; - // } - // setState(() { - // loadCourseNotice = true; - // }); - // - // TaskFlow taskFlow = TaskFlow(); - // var task = IPlusSubscribeNoticeTask(); - // task.openLoadingDialog = false; - // taskFlow.addTask(task); - // if (await taskFlow.start()) { - // List v = task.result; - // List value = []; - // v = v ?? []; - // for (int i = 0; i < v.length; i++) { - // String courseName = v[i]; - // CourseInfoJson courseInfo = courseTableData.getCourseInfoByCourseName(courseName); - // if (courseInfo != null) { - // value.add(courseName); - // } - // } - // if (value != null && value.isNotEmpty) { - // Get.dialog( - // AlertDialog( - // title: Text(R.current.findNewMessage), - // content: SizedBox( - // width: double.minPositive, - // child: ListView.builder( - // itemCount: value.length, - // shrinkWrap: true, //使清單最小化 - // itemBuilder: (BuildContext context, int index) { - // return TextButton( - // child: Text(value[index]), - // onPressed: () { - // String courseName = value[index]; - // CourseInfoJson courseInfo = courseTableData.getCourseInfoByCourseName(courseName); - // if (courseInfo != null) { - // _showCourseDetail(courseInfo); - // } else { - // MyToast.show(R.current.noSupport); - // Get.back(); - // } - // }, - // ); - // }, - // ), - // ), - // actions: [ - // TextButton( - // child: Text(R.current.sure), - // onPressed: () { - // Get.back(); - // }, - // ), - // ], - // ), - // barrierDismissible: true, - // ); - // } - // } - // LocalStorage.instance.setAlreadyUse(LocalStorage.courseNotice); - // setState(() { - // loadCourseNotice = false; - // }); - // } + void getCourseNotice() async { + setState(() { + loadCourseNotice = false; + }); + if (!LocalStorage.instance.getOtherSetting().checkIPlusNew) { + return; + } + if (!LocalStorage.instance.getFirstUse(LocalStorage.courseNotice, timeOut: 15 * 60)) { + return; + } + if (LocalStorage.instance.getAccount() != LocalStorage.instance.getCourseSetting().info.user.id) { + //只有顯示自己的課表時才會檢查新公告 + return; + } + setState(() { + loadCourseNotice = true; + }); + + TaskFlow taskFlow = TaskFlow(); + var task = IPlusSubscribeNoticeTask(); + task.openLoadingDialog = false; + taskFlow.addTask(task); + if (await taskFlow.start()) { + List v = task.result; + List value = []; + v = v ?? []; + for (int i = 0; i < v.length; i++) { + String courseName = v[i]; + Course course = courseTableData.courses.firstWhere((course) => course.name == courseName, orElse: () => null); + if (course != null) { + value.add(courseName); + } + } + if (value != null && value.isNotEmpty) { + Get.dialog( + AlertDialog( + title: Text(R.current.findNewMessage), + content: SizedBox( + width: double.minPositive, + child: ListView.builder( + itemCount: value.length, + shrinkWrap: true, //使清單最小化 + itemBuilder: (BuildContext context, int index) { + return TextButton( + child: Text(value[index]), + onPressed: () { + String courseName = value[index]; + Course courseInfo = courseTableData.courses.firstWhere((course) => + course.name == courseName, + orElse: () => null + ); + if (courseInfo != null) { + _showCourseDetail(courseInfo); + } else { + MyToast.show(R.current.noSupport); + Get.back(); + } + }, + ); + }, + ), + ), + actions: [ + TextButton( + child: Text(R.current.sure), + onPressed: () { + Get.back(); + }, + ), + ], + ), + barrierDismissible: true, + ); + } + } + LocalStorage.instance.setAlreadyUse(LocalStorage.courseNotice); + setState(() { + loadCourseNotice = false; + }); + } @override void setState(fn) { @@ -158,7 +160,7 @@ class _CourseTablePageState extends State { courseHeight = (renderObject.semanticBounds.size.height - studentIdHeight - dayHeight) / showCourseTableNum; final courseTable = LocalStorage.instance.getCourseSetting().info; if (courseTable == null || courseTable.courses.isEmpty) { - _getCourseTable(studentId: courseTable.user.id, year: courseTable.year, semester: courseTable.semester); + _getCourseTable(studentId: "", year: 0, semester: 0); } else { _showCourseTable(courseTable); } @@ -178,7 +180,7 @@ class _CourseTablePageState extends State { UserDataJson userData = LocalStorage.instance.getUserData(); studentId = studentId?.trim() ?? ''; studentId = (studentId.isEmpty ? null : studentId) ?? userData.account; - if (courseTableData.user.id != studentId) { + if (userData.account != studentId) { LocalStorage.instance.clearSemesterJsonList(); //需重設因為更換了studentId } @@ -502,7 +504,7 @@ class _CourseTablePageState extends State { ) : Column( children: List.generate( - 1 + courseTableControl.getSectionList.length, + 1 + courseTableControl.getSectionIntList.length, (index) { final widget = (index == 0) ? _buildDay() : _buildCourseTable(index - 1); return AnimationConfiguration.staggeredList( @@ -546,7 +548,7 @@ class _CourseTablePageState extends State { } Widget _buildCourseTable(int index) { - final section = courseTableControl.getSectionList[index]; + final section = courseTableControl.getSectionIntList[index]; final color = index % 2 == 1 ? Theme.of(context).colorScheme.surface : Theme.of(context).colorScheme.surfaceVariant.withAlpha(courseTableWithAlpha); @@ -556,7 +558,7 @@ class _CourseTablePageState extends State { width: sectionWidth, alignment: Alignment.center, child: Text( - section, + courseTableControl.getSectionString(section), textAlign: TextAlign.center, ), ), @@ -566,50 +568,50 @@ class _CourseTablePageState extends State { for (final day in courseTableControl.getDayIntList) { final course = courseTableControl.getCourse(day, section); - final color = courseTableControl.getCourseInfoColor(day, section); + final courseInfoColor = courseTableControl.getCourseInfoColor(day, section); widgetList.add( Expanded( - child: (course.isEmpty()) + child: (course == null) ? const SizedBox.shrink() : Card( - elevation: 0, - margin: const EdgeInsets.all(2), - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(5)), - color: color, - ), - child: Material( - color: Colors.transparent, - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(5)), - highlightColor: isDarkMode ? Colors.white : Colors.black12, - onTap: () => showCourseDetailDialog(section, course), - child: Stack( - children: [ - Align( - alignment: Alignment.center, - child: Padding( - padding: const EdgeInsets.all(2), - child: AutoSizeText( - course.name, - style: const TextStyle( - color: Colors.black, - fontSize: 14, - overflow: TextOverflow.ellipsis, - ), - minFontSize: 6, - maxLines: 3, - textAlign: TextAlign.center, - ), - ), + elevation: 0, + margin: const EdgeInsets.all(2), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(5)), + color: courseInfoColor, + ), + child: Material( + color: Colors.transparent, + child: InkWell( + borderRadius: const BorderRadius.all(Radius.circular(5)), + highlightColor: isDarkMode ? Colors.white : Colors.black12, + onTap: () => showCourseDetailDialog(courseTableControl.getTimeString(section), course), + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.all(2), + child: AutoSizeText( + course.name, + style: const TextStyle( + color: Colors.black, + fontSize: 14, + overflow: TextOverflow.ellipsis, ), - ], + minFontSize: 6, + maxLines: 3, + textAlign: TextAlign.center, + ), ), ), - ), + ], ), ), + ), + ), + ), ), ); } @@ -624,10 +626,10 @@ class _CourseTablePageState extends State { } //顯示課程對話框 - void showCourseDetailDialog(String section, Course course) { + void showCourseDetailDialog(String timePeriod, Course course) { _unFocusStudentInput(); - final classroomName = course.classroom; - final teacherName = course.teacher; + final classroomName = course.classrooms.join(" "); + final teacherName = course.teachers.join(" "); final studentId = LocalStorage.instance.getCourseSetting().info.user.id; setState(() { _studentIdControl.text = studentId; @@ -648,7 +650,7 @@ class _CourseTablePageState extends State { setState(() {}); }, ), - Text(sprintf("%s : %s", [R.current.time, section])), + Text(sprintf("%s : %s", [R.current.time, timePeriod])), Text(sprintf("%s : %s", [R.current.location, classroomName])), Text(sprintf("%s : %s", [R.current.instructor, teacherName])), ], @@ -729,7 +731,7 @@ class _CourseTablePageState extends State { if (courseTable == null) { return; } - // getCourseNotice(); //查詢訂閱的課程是否有公告 + getCourseNotice(); //查詢訂閱的課程是否有公告 courseTableData = courseTable; _studentIdControl.text = courseTable.user.id; _unFocusStudentInput(); @@ -757,7 +759,7 @@ class _CourseTablePageState extends State { final directory = await getApplicationSupportDirectory(); final path = directory.path; - setState(() => courseHeight = height / courseTableControl.getSectionList.length); + setState(() => courseHeight = height / courseTableControl.getSectionIntList.length); await Future.delayed(const Duration(milliseconds: 100)); setState(() => isLoading = true); From 8fda4322e0be8b94771247b8d82b2283551d81bb Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Thu, 8 Feb 2024 23:23:56 +0800 Subject: [PATCH 04/31] Refactor: course_connector.dart --- ios/Podfile.lock | 2 +- lib/generated/intl/messages_all.dart | 14 +- lib/generated/intl/messages_en.dart | 4 +- lib/generated/intl/messages_zh_TW.dart | 4 +- lib/src/connector/course_connector.dart | 500 +++++++++++---------- lib/src/model/coursetable/user.dart | 2 + lib/src/task/course/course_table_task.dart | 7 +- 7 files changed, 270 insertions(+), 263 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e40e0765..30d96142 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -384,7 +384,7 @@ SPEC CHECKSUMS: FirebaseCoreExtension: 2dbc745b337eb99d2026a7a309ae037bd873f45e FirebaseCoreInternal: 26233f705cc4531236818a07ac84d20c333e505a FirebaseCrashlytics: a83f26fb922a3fe181eb738fb4dcf0c92bba6455 - FirebaseFirestore: 58d92e3cc19fd1c93e279d466aaf148ce6dbf635 + FirebaseFirestore: 9a14eef134fd586d8200f4dfa0ee3cb093a05d8f FirebaseInstallations: b822f91a61f7d1ba763e5ccc9d4f2e6f2ed3b3ee FirebaseMessaging: 0c0ae1eb722ef0c07f7801e5ded8dccd1357d6d4 FirebaseRemoteConfig: 64b6ada098c649304114a817effd7e5f87229b11 diff --git a/lib/generated/intl/messages_all.dart b/lib/generated/intl/messages_all.dart index 1771ed2d..c65333cc 100644 --- a/lib/generated/intl/messages_all.dart +++ b/lib/generated/intl/messages_all.dart @@ -19,10 +19,10 @@ import 'package:intl/src/intl_helpers.dart'; import 'messages_en.dart' as messages_en; import 'messages_zh_TW.dart' as messages_zh_tw; -typedef Future LibraryLoader(); +typedef LibraryLoader = Future Function(); Map _deferredLibraries = { - 'en': () => new SynchronousFuture(null), - 'zh_TW': () => new SynchronousFuture(null), + 'en': () => SynchronousFuture(null), + 'zh_TW': () => SynchronousFuture(null), }; MessageLookupByLibrary? _findExact(String localeName) { @@ -41,13 +41,13 @@ Future initializeMessages(String localeName) { var availableLocale = Intl.verifiedLocale(localeName, (locale) => _deferredLibraries[locale] != null, onFailure: (_) => null); if (availableLocale == null) { - return new SynchronousFuture(false); + return SynchronousFuture(false); } var lib = _deferredLibraries[availableLocale]; - lib == null ? new SynchronousFuture(false) : lib(); - initializeInternalMessageLookup(() => new CompositeMessageLookup()); + lib == null ? SynchronousFuture(false) : lib(); + initializeInternalMessageLookup(() => CompositeMessageLookup()); messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); - return new SynchronousFuture(true); + return SynchronousFuture(true); } bool _messagesExistFor(String locale) { diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart index b57a618d..4c49f218 100644 --- a/lib/generated/intl/messages_en.dart +++ b/lib/generated/intl/messages_en.dart @@ -13,9 +13,9 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; -final messages = new MessageLookup(); +final messages = MessageLookup(); -typedef String MessageIfAbsent(String messageStr, List args); +typedef MessageIfAbsent = String Function(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'en'; diff --git a/lib/generated/intl/messages_zh_TW.dart b/lib/generated/intl/messages_zh_TW.dart index c6d61bf8..c2085ef7 100644 --- a/lib/generated/intl/messages_zh_TW.dart +++ b/lib/generated/intl/messages_zh_TW.dart @@ -13,9 +13,9 @@ import 'package:intl/intl.dart'; import 'package:intl/message_lookup_by_library.dart'; -final messages = new MessageLookup(); +final messages = MessageLookup(); -typedef String MessageIfAbsent(String messageStr, List args); +typedef MessageIfAbsent = String Function(String messageStr, List args); class MessageLookup extends MessageLookupByLibrary { String get localeName => 'zh_TW'; diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index 529d79b2..a0b10a7a 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -1,5 +1,3 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 import 'package:dio/dio.dart'; import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/connector/core/connector.dart'; @@ -15,12 +13,9 @@ import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; -enum CourseConnectorStatus { loginSuccess, loginFail, unknownError } +import '../util/must.dart'; -class CourseMainInfo { - List json; - String studentName; -} +enum CourseConnectorStatus { loginSuccess, loginFail, unknownError } class CourseConnector { static const _ssoLoginUrl = "${NTUTConnector.host}ssoIndex.do"; @@ -33,32 +28,12 @@ class CourseConnector { static const String _creditUrl = "${_courseCNHost}Cprog.jsp"; static Future login() async { - String result; try { - ConnectorParameter parameter; - Document tagNode; - List nodes; - Map data = { - "apUrl": "https://aps.ntut.edu.tw/course/tw/courseSID.jsp", - "apOu": "aa_0010-", - "sso": "true", - "datetime1": DateTime.now().millisecondsSinceEpoch.toString() - }; - parameter = ConnectorParameter(_ssoLoginUrl); - parameter.data = data; - result = await Connector.getDataByGet(parameter); - tagNode = parse(result); - nodes = tagNode.getElementsByTagName("input"); - data = {}; - for (Element node in nodes) { - String name = node.attributes['name']; - String value = node.attributes['value']; - data[name] = value; - } - String jumpUrl = tagNode.getElementsByTagName("form")[0].attributes["action"]; - parameter = ConnectorParameter(jumpUrl); - parameter.data = data; - await Connector.getDataByPostResponse(parameter); + Document tagNode = await _getSSORedirectNodesInLoginPhase(); + await _tryToSSOLoginOrThrowException( + _getSSOLoginJumpUrl(tagNode), + _getSSOLoginPayload(tagNode) + ); return CourseConnectorStatus.loginSuccess; } catch (e, stack) { Log.eWithStack(e.toString(), stack); @@ -106,6 +81,48 @@ class CourseConnector { } static Future getUserInfo(String studentId, int year, int semester) async { + try { + ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + Map data = { + "code": studentId, + "format": "-2", + "year": year.toString(), + "sem": semester.toString(), + }; + parameter.charsetName = 'utf-8'; + parameter.data = data; + String result = await Connector.getDataByGet(parameter); + + Document tagNode = parse(result); + String courseTableHead = tagNode.getElementsByTagName("table")[1] + .getElementsByTagName("tr") + .first + .text; + List matches = RegExp(r".+?:(.+?)\s").allMatches(courseTableHead).toList(); + + String? name = matches[1].group(1); + String? className = matches[2].group(1); + + if (name == null) { + throw Exception("getUserInfo: Cannot Fetch the user info (null name)."); + } + + if (className == null) { + throw Exception("getUserInfo: Cannot Fetch the user info (null className)."); + } + + return User( + id: studentId, + name: name, + className: className + ); + } catch (e, stack) { + Log.eWithStack(e.toString(), stack); + return User.origin(); + } + } + + static Future> getChineseCourses(String studentId, int year, int semester) async { ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); Map data = { "code": studentId, @@ -116,63 +133,119 @@ class CourseConnector { parameter.charsetName = 'utf-8'; parameter.data = data; String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); - String courseTableHead = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr").first.text; - List matches = RegExp(r".+?:(.+?)\s").allMatches(courseTableHead).toList(); - - return User( - id: studentId, - name: matches[1].group(1), - className: matches[2].group(1) - ); + List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); + List courses = []; + + for (int rowIndex = 2; rowIndex < courseRows.length - 1; rowIndex++) { + var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); + var syllabusNode = courseRowData[18].getElementsByTagName("a"); + var syllabusLinkHref = syllabusNode.isEmpty ? null : syllabusNode.first.attributes["href"]; + courses.add(Course( + idString: courseRowData[0].text, + name: courseRowData[1].text, + stageString: courseRowData[2].text, + creditString: courseRowData[3].text, + periodCountString: courseRowData[4].text, + category: courseRowData[5].text, + teacherString: courseRowData[6].text, + classNameString: courseRowData[7].text, + periodSlots: courseRowData.sublist(8, 15).map((data) => data.text).toList(), + classroomString: courseRowData[15].text, + applyStatus: courseRowData[16].text, + language: courseRowData[17].text, + syllabusLink: syllabusLinkHref == null ? "" : _postCourseCNUrl + syllabusLinkHref, + note: courseRowData[19].text + )); + } + + return courses; } - static Future> getChineseCourses(String studentId, int year, int semester) async { + static Future getCourseExtraInfo(String courseId) async { try { - ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + ConnectorParameter parameter; + Document tagNode; + Element node; + List courseNodes, nodes, classExtraInfoNodes; Map data = { - "code": studentId, - "format": "-2", - "year": year.toString(), - "sem": semester.toString(), + "code": courseId, + "format": "-1", }; - parameter.charsetName = 'utf-8'; + parameter = ConnectorParameter(_postCourseCNUrl); parameter.data = data; - String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); - List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); - List courses = []; - - for (int rowIndex = 2; rowIndex < courseRows.length - 1; rowIndex++) { - var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); - var syllabusNode = courseRowData[18].getElementsByTagName("a"); - courses.add(Course( - idString: courseRowData[0].text, - name: courseRowData[1].text, - stageString: courseRowData[2].text, - creditString: courseRowData[3].text, - periodCountString: courseRowData[4].text, - category: courseRowData[5].text, - teacherString: courseRowData[6].text, - classNameString: courseRowData[7].text, - periodSlots: courseRowData.sublist(8, 15).map((data) => data.text).toList(), - classroomString: courseRowData[15].text, - applyStatus: courseRowData[16].text, - language: courseRowData[17].text, - syllabusLink: syllabusNode.isEmpty ? "" : _postCourseCNUrl + syllabusNode.first.attributes["href"], - note: courseRowData[19].text - )); + String result = await Connector.getDataByPost(parameter); + tagNode = parse(result); + courseNodes = tagNode.getElementsByTagName("table"); + + CourseExtraInfoJson courseExtraInfo = CourseExtraInfoJson(); + + //取得學期資料 + nodes = courseNodes[0].getElementsByTagName("td"); + SemesterJson semester = SemesterJson(); + + // Previously, the title string of the first course table was stored separately in its `` element, + // but it currently stores all the information in a row, + // e.g. "學號:110310144  姓名:xxx  班級:電機三甲    112 學年度 第 1 學期 上課時間表" + // so the RegExp is used to filter out only the number parts + final titleString = nodes[0].text; + final RegExp studentSemesterDetailFilter = RegExp(r'\b[\dA-Z]+\b'); + final Iterable studentSemesterDetailMatches = studentSemesterDetailFilter.allMatches(titleString); + // "studentSemesterDetails" should consist of three numerical values + // ex: [110310144, 112, 1] + final List studentSemesterDetails = studentSemesterDetailMatches.map((match) => match.group(0)).toList(); + if (studentSemesterDetails.isEmpty) { + throw RangeError("[TAT] course_connector.dart: studentSemesterDetails list is empty"); + } + if (studentSemesterDetails.length < 3) { + throw RangeError("[TAT] course_connector.dart: studentSemesterDetails list has range less than 3"); + } + semester.year = studentSemesterDetails[1]; + semester.semester = studentSemesterDetails[2]; + + courseExtraInfo.courseSemester = semester; + + CourseExtraJson courseExtra = CourseExtraJson(); + + nodes = courseNodes[1].getElementsByTagName("tr"); + final List courseIds = nodes.skip(2).map((node) => node.getElementsByTagName("td")[0].text).toList(); + final courseIdPosition = courseIds.indexWhere((element) => element.contains(courseId)); + if (courseIdPosition == -1) { + throw StateError('[TAT] course_connector.dart: CourseId not found: $courseId'); + } else { + node = nodes[courseIdPosition + 2]; + } + classExtraInfoNodes = node.getElementsByTagName("td"); + courseExtra.id = strQ2B(classExtraInfoNodes[0].text).replaceAll(RegExp(r"\s"), ""); + courseExtra.name = classExtraInfoNodes[1].getElementsByTagName("a")[0].text; + courseExtra.openClass = classExtraInfoNodes[7].getElementsByTagName("a")[0].text; + + // if the courseExtraInfo.herf (課程大綱連結) is empty, + // the category of the course will be set to ▲ (校訂專業必修) as default + if (classExtraInfoNodes[18].text.trim() != "" && + classExtraInfoNodes[18].getElementsByTagName("a")[0].attributes.containsKey("href")) { + courseExtra.href = _courseCNHost + classExtraInfoNodes[18].getElementsByTagName("a")[0].attributes["href"]!; + parameter = ConnectorParameter(courseExtra.href); + result = await Connector.getDataByPost(parameter); + tagNode = parse(result); + nodes = tagNode.getElementsByTagName("tr"); + courseExtra.category = nodes[1].getElementsByTagName("td")[6].text; + } else { + courseExtra.category = constCourseType[4]; } - return courses; - } catch (e, stack){ + courseExtra.selectNumber = "s?"; + courseExtra.withdrawNumber = "w?"; + + courseExtraInfo.course = courseExtra; + return courseExtraInfo; + } catch (e, stack) { Log.eWithStack(e.toString(), stack); return null; } } - static Future getCourseENName(String url) async { + static Future getCourseENName(String url) async { try { ConnectorParameter parameter; Document tagNode; @@ -229,21 +302,17 @@ class CourseConnector { static Future> getCourseSemester(String studentId) async { try { - ConnectorParameter parameter; - Document tagNode; - Element node; - List nodes; - - Map data = { + ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + parameter.data = { "code": studentId, "format": "-3", }; - parameter = ConnectorParameter(_postCourseCNUrl); - parameter.data = data; Response response = await Connector.getDataByPostResponse(parameter); - tagNode = parse(response.toString()); - node = tagNode.getElementsByTagName("table")[0]; - nodes = node.getElementsByTagName("tr"); + Document tagNode = parse(response.toString()); + + Element node = tagNode.getElementsByTagName("table")[0]; + List nodes = node.getElementsByTagName("tr"); + List semesterJsonList = []; for (int i = 1; i < nodes.length; i++) { node = nodes[i]; @@ -274,166 +343,23 @@ class CourseConnector { return String.fromCharCodes(newString); } - static Future getTWTeacherCourseMainInfoList(String studentId, SemesterJson semester) async { - var info = CourseMainInfo(); - try { - ConnectorParameter parameter; - Document tagNode; - Element node; - List courseNodes, nodesOne, nodes; - List dayEnum = [Day.Sunday, Day.Monday, Day.Tuesday, Day.Wednesday, Day.Thursday, Day.Friday, Day.Saturday]; - Map data = { - "code": studentId, - "format": "-3", - "year": semester.year, - "sem": semester.semester, - }; - parameter = ConnectorParameter(_postTeacherCourseCNUrl); - parameter.data = data; - parameter.charsetName = 'big5'; - Response response = await Connector.getDataByPostResponse(parameter); - tagNode = parse(response.toString()); - node = tagNode.getElementsByTagName("table")[0]; - courseNodes = node.getElementsByTagName("tr"); - String studentName; - try { - studentName = courseNodes[0].text.replaceAll("  ", " ").split(" ")[2]; - } catch (e) { - studentName = ""; - } - info.studentName = studentName; - List courseMainInfoList = []; - for (int i = 2; i < courseNodes.length - 1; i++) { - CourseMainInfoJson courseMainInfo = CourseMainInfoJson(); - CourseMainJson courseMain = CourseMainJson(); - - nodesOne = courseNodes[i].getElementsByTagName("td"); - if (nodesOne[16].text.contains("撤選")) { - continue; - } - //取得課號 - nodes = nodesOne[0].getElementsByTagName("a"); //確定是否有課號 - if (nodes.isNotEmpty) { - courseMain.id = nodes[0].text; - courseMain.href = _courseCNHost + nodes[0].attributes["href"]; - } - //取的課程名稱/課程連結 - nodes = nodesOne[1].getElementsByTagName("a"); //確定是否有連結 - if (nodes.isNotEmpty) { - courseMain.name = nodes[0].text; - } else { - courseMain.name = nodesOne[1].text; - } - courseMain.stage = nodesOne[2].text.replaceAll("\n", ""); //階段 - courseMain.credits = nodesOne[3].text.replaceAll("\n", ""); //學分 - courseMain.hours = nodesOne[4].text.replaceAll("\n", ""); //時數 - courseMain.note = nodesOne[20].text.replaceAll("\n", ""); //備註 - if (nodesOne[19].getElementsByTagName("a").isNotEmpty) { - courseMain.scheduleHref = - _courseCNHost + nodesOne[19].getElementsByTagName("a")[0].attributes["href"]; //教學進度大綱 - } - - //時間 - for (int j = 0; j < 7; j++) { - Day day = dayEnum[j]; //要做變換網站是從星期日開始 - String time = nodesOne[j + 8].text; - time = strQ2B(time); - courseMain.time[day] = time; - } - - courseMainInfo.course = courseMain; - - //取得老師名稱 - TeacherJson teacher = TeacherJson(); - teacher.name = ""; - teacher.href = ""; - courseMainInfo.teacher.add(teacher); - - //取得教室名稱 - for (Element node in nodesOne[15].getElementsByTagName("a")) { - ClassroomJson classroom = ClassroomJson(); - classroom.name = node.text; - classroom.href = _courseCNHost + node.attributes["href"]; - courseMainInfo.classroom.add(classroom); - } + static Future getGraduation(String year, String department) async { + ConnectorParameter parameter = ConnectorParameter("https://aps.ntut.edu.tw/course/tw/Cprog.jsp"); + parameter.data = {"format": "-3", "year": year, "matric": "7"}; + String result = await Connector.getDataByGet(parameter); + Document tagNode = parse(result); - //取得開設教室名稱 - for (Element node in nodesOne[7].getElementsByTagName("a")) { - ClassJson classInfo = ClassJson(); - classInfo.name = node.text; - classInfo.href = _courseCNHost + node.attributes["href"]; - courseMainInfo.openClass.add(classInfo); - } + Element node = tagNode.getElementsByTagName("tbody").first; + List nodes = node.getElementsByTagName("tr"); + String redirectHypertextRef = nodes.firstWhere((node) => + node.text.contains(department) + ).getElementsByTagName("a").first.attributes["href"]!; - courseMainInfoList.add(courseMainInfo); - } - info.json = courseMainInfoList; - return info; - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - return null; - } + Map graduationMap = await _getGraduationCreditMap(redirectHypertextRef); + return graduationMap; } - static Future getGraduation(String year, String department) async { - ConnectorParameter parameter; - String result; - Document tagNode; - Element node; - List nodes; - RegExp exp; - RegExpMatch matches; - Map graduationMap = {}; - try { - parameter = ConnectorParameter("https://aps.ntut.edu.tw/course/tw/Cprog.jsp"); - parameter.data = {"format": "-3", "year": year, "matric": "7"}; - result = await Connector.getDataByGet(parameter); - tagNode = parse(result); - node = tagNode.getElementsByTagName("tbody").first; - nodes = node.getElementsByTagName("tr"); - String href; - for (int i = 1; i < nodes.length; i++) { - node = nodes[i]; - node = node.getElementsByTagName("a").first; - if (node.text.contains(department)) { - href = node.attributes["href"]; - break; - } - } - href = "https://aps.ntut.edu.tw/course/tw/$href"; - parameter = ConnectorParameter(href); - result = await Connector.getDataByGet(parameter); - - exp = RegExp(r"最低畢業學分:?(\d+)學分"); - matches = exp.firstMatch(result); - graduationMap["lowCredit"] = int.parse(matches.group(1)); - - exp = RegExp(r"共同必修:?(\d+)學分"); - matches = exp.firstMatch(result); - graduationMap["△"] = int.parse(matches.group(1)); - - exp = RegExp(r"專業必修:?(\d+)學分"); - matches = exp.firstMatch(result); - graduationMap["▲"] = int.parse(matches.group(1)); - - exp = RegExp(r"專業選修:?(\d+)學分"); - matches = exp.firstMatch(result); - graduationMap["★"] = int.parse(matches.group(1)); - - /* - exp = RegExp("通識博雅課程應修滿(\d+)學分"); - matches = exp.firstMatch(result); - exp = RegExp("跨系所專業選修(\d+)學分為畢業學分"); - matches = exp.firstMatch(result); - */ - return graduationMap; - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - return null; - } - } - - static Future> getYearList() async { + static Future?> getYearList() async { ConnectorParameter parameter; String result; Document tagNode; @@ -462,7 +388,7 @@ class CourseConnector { name 名稱 code 參數 */ - static Future> getDivisionList(String year) async { + static Future?> getDivisionList(String year) async { ConnectorParameter parameter; String result; Document tagNode; @@ -477,7 +403,9 @@ class CourseConnector { nodes = tagNode.getElementsByTagName("a"); for (int i = 0; i < nodes.length; i++) { node = nodes[i]; - Map code = Uri.parse(node.attributes["href"]).queryParameters; + var href = node.attributes["href"]; + Must.notNullOrEmpty(href, "href"); + Map code = Uri.parse(href!).queryParameters; resultList.add({"name": node.text, "code": code}); } return resultList; @@ -492,7 +420,7 @@ class CourseConnector { name 名稱 code 參數 */ - static Future> getDepartmentList(Map code) async { + static Future>?> getDepartmentList(Map code) async { ConnectorParameter parameter; String result; Document tagNode; @@ -508,7 +436,9 @@ class CourseConnector { nodes = node.getElementsByTagName("a"); for (int i = 0; i < nodes.length; i++) { node = nodes[i]; - Map code = Uri.parse(node.attributes["href"]).queryParameters; + var href = node.attributes["href"]; + Must.notNullOrEmpty(href, "href"); + Map code = Uri.parse(href!).queryParameters; String name = node.text.replaceAll(RegExp("[ |s]"), ""); resultList.add({"name": name, "code": code}); } @@ -523,7 +453,7 @@ class CourseConnector { Map Key minGraduationCredits */ - static Future getCreditInfo(Map code, String select) async { + static Future getCreditInfo(Map code, String select) async { ConnectorParameter parameter; String result; Document tagNode; @@ -599,4 +529,80 @@ class CourseConnector { return null; } } + + static Future _getSSORedirectNodesInLoginPhase() async { + ConnectorParameter parameter = ConnectorParameter(_ssoLoginUrl); + Map data = { + "apUrl": "https://aps.ntut.edu.tw/course/tw/courseSID.jsp", + "apOu": "aa_0010-", + "sso": "true", + "datetime1": DateTime.now().millisecondsSinceEpoch.toString() + }; + parameter.data = data; + String result = await Connector.getDataByGet(parameter); + + Document tagNode = parse(result); + return tagNode; + } + + static Map _getSSOLoginPayload(Document ssoRedirectTagNode){ + Map data = {}; + List nodes = ssoRedirectTagNode.getElementsByTagName("input"); + + for (Element node in nodes) { + String? name = node.attributes['name']; + String? value = node.attributes['value']; + if (name == null || value == null) { + throw Exception("Cannot fetch name or value."); + } + data[name] = value; + } + + return data; + } + + static String _getSSOLoginJumpUrl(Document ssoRedirectTagNode) { + String? jumpUrl = ssoRedirectTagNode + .getElementsByTagName("form")[0] + .attributes["action"]; + + if (jumpUrl == null) { + throw Exception("Cannot fetch jumpUrl."); + } + + return jumpUrl; + } + + static Future _tryToSSOLoginOrThrowException(String jumpUrl, Map payload) async { + ConnectorParameter parameter = ConnectorParameter(jumpUrl); + parameter.data = payload; + await Connector.getDataByPostResponse(parameter); + } + + static Future> _getGraduationCreditMap(String href) async { + ConnectorParameter parameter = ConnectorParameter(href); + String result = await Connector.getDataByGet(parameter); + Map graduationMap = {}; + + graduationMap["lowCredit"] = _getGraduationCredit(result, RegExp(r"最低畢業學分:?(\d+)學分")); + graduationMap["△"] = _getGraduationCredit(result, RegExp(r"共同必修:?(\d+)學分")); + graduationMap["▲"] = _getGraduationCredit(result, RegExp(r"專業必修:?(\d+)學分")); + graduationMap["★"] = _getGraduationCredit(result, RegExp(r"專業選修:?(\d+)學分")); + + return graduationMap; + } + + static int _getGraduationCredit(String content, RegExp exp) { + RegExpMatch? matches = exp.firstMatch(content); + if (matches == null) { + return 0; + } + + String? creditText = matches.group(1); + if (creditText == null) { + return 0; + } + + return int.parse(creditText); + } } diff --git a/lib/src/model/coursetable/user.dart b/lib/src/model/coursetable/user.dart index b4429c94..a2438088 100644 --- a/lib/src/model/coursetable/user.dart +++ b/lib/src/model/coursetable/user.dart @@ -8,6 +8,8 @@ class User { String name; String className; + User.origin() : id = "", name = "", className = ""; + User({ required this.id, required this.name, diff --git a/lib/src/task/course/course_table_task.dart b/lib/src/task/course/course_table_task.dart index aff5e6c4..e2d58fb0 100644 --- a/lib/src/task/course/course_table_task.dart +++ b/lib/src/task/course/course_table_task.dart @@ -1,14 +1,13 @@ // ignore_for_file: import_of_legacy_library_into_null_safe import 'package:flutter_app/src/connector/course_connector.dart'; -import 'package:flutter_app/src/model/course/course_class_json.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; import 'package:flutter_app/src/util/language_util.dart'; import '../../model/coursetable/course.dart'; import '../../model/coursetable/course_table.dart'; +import '../../model/coursetable/user.dart'; import '../task.dart'; import 'course_system_task.dart'; @@ -24,8 +23,8 @@ class CourseTableTask extends CourseSystemTask { final status = await super.execute(); if (status == TaskStatus.success) { super.onStart(R.current.getCourse); - List? courses; - var userInfo = await CourseConnector.getUserInfo(studentId, year, semester); + List courses; + User userInfo = await CourseConnector.getUserInfo(studentId, year, semester); // TODO: Handle Teacher Situation. if (LanguageUtil.getLangIndex() == LangEnum.zh) { courses = await CourseConnector.getChineseCourses(studentId, year, semester); From 22a870b54aad7bf6f49822188494b810201c1b2b Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 9 Feb 2024 02:00:20 +0800 Subject: [PATCH 05/31] Migrate: Remove redundant json --- lib/src/connector/course_connector.dart | 88 +------ lib/src/model/course/course_class_json.dart | 209 +--------------- lib/src/model/course/course_class_json.g.dart | 151 +----------- .../model/course/course_main_extra_json.dart | 105 -------- .../course/course_main_extra_json.g.dart | 48 ---- .../model/coursetable/course_table_json.dart | 227 ------------------ .../coursetable/course_table_json.g.dart | 105 -------- lib/src/model/setting/setting_json.dart | 1 - lib/src/store/local_storage.dart | 1 - .../task/course/course_extra_info_task.dart | 33 --- lib/ui/other/route_utils.dart | 1 - .../coursedetail/course_detail_page.dart | 1 - .../iplus_announcement_detail_page.dart | 1 - .../ischoolplus/iplus_announcement_page.dart | 1 - .../screen/ischoolplus/iplus_file_page.dart | 1 - .../coursetable/course_table_control.dart | 1 - .../pages/videoplayer/class_video_player.dart | 1 - 17 files changed, 3 insertions(+), 972 deletions(-) delete mode 100644 lib/src/model/course/course_main_extra_json.dart delete mode 100644 lib/src/model/course/course_main_extra_json.g.dart delete mode 100644 lib/src/model/coursetable/course_table_json.dart delete mode 100644 lib/src/model/coursetable/course_table_json.g.dart delete mode 100644 lib/src/task/course/course_extra_info_task.dart diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index a0b10a7a..183e83fa 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -4,12 +4,10 @@ import 'package:flutter_app/src/connector/core/connector.dart'; import 'package:flutter_app/src/connector/core/connector_parameter.dart'; import 'package:flutter_app/src/connector/ntut_connector.dart'; import 'package:flutter_app/src/model/course/course_class_json.dart'; -import 'package:flutter_app/src/model/course/course_main_extra_json.dart'; import 'package:flutter_app/src/model/course/course_score_json.dart'; import 'package:flutter_app/src/model/coursetable/course.dart'; import 'package:flutter_app/src/model/coursetable/user.dart'; import 'package:flutter_app/src/model/course/course_syllabus_json.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; @@ -23,7 +21,6 @@ class CourseConnector { static const String _courseENHost = "https://aps.ntut.edu.tw/course/en/"; static const String _postCourseCNUrl = "${_courseCNHost}Select.jsp"; static const String _getSyllabusCNUrl = "${_courseCNHost}ShowSyllabus.jsp"; - static const String _postTeacherCourseCNUrl = "${_courseCNHost}Teach.jsp"; static const String _postCourseENUrl = "${_courseENHost}Select.jsp"; static const String _creditUrl = "${_courseCNHost}Cprog.jsp"; @@ -162,89 +159,6 @@ class CourseConnector { return courses; } - static Future getCourseExtraInfo(String courseId) async { - try { - ConnectorParameter parameter; - Document tagNode; - Element node; - List courseNodes, nodes, classExtraInfoNodes; - Map data = { - "code": courseId, - "format": "-1", - }; - parameter = ConnectorParameter(_postCourseCNUrl); - parameter.data = data; - String result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - courseNodes = tagNode.getElementsByTagName("table"); - - CourseExtraInfoJson courseExtraInfo = CourseExtraInfoJson(); - - //取得學期資料 - nodes = courseNodes[0].getElementsByTagName("td"); - SemesterJson semester = SemesterJson(); - - // Previously, the title string of the first course table was stored separately in its `` element, - // but it currently stores all the information in a row, - // e.g. "學號:110310144  姓名:xxx  班級:電機三甲    112 學年度 第 1 學期 上課時間表" - // so the RegExp is used to filter out only the number parts - final titleString = nodes[0].text; - final RegExp studentSemesterDetailFilter = RegExp(r'\b[\dA-Z]+\b'); - final Iterable studentSemesterDetailMatches = studentSemesterDetailFilter.allMatches(titleString); - // "studentSemesterDetails" should consist of three numerical values - // ex: [110310144, 112, 1] - final List studentSemesterDetails = studentSemesterDetailMatches.map((match) => match.group(0)).toList(); - if (studentSemesterDetails.isEmpty) { - throw RangeError("[TAT] course_connector.dart: studentSemesterDetails list is empty"); - } - if (studentSemesterDetails.length < 3) { - throw RangeError("[TAT] course_connector.dart: studentSemesterDetails list has range less than 3"); - } - semester.year = studentSemesterDetails[1]; - semester.semester = studentSemesterDetails[2]; - - courseExtraInfo.courseSemester = semester; - - CourseExtraJson courseExtra = CourseExtraJson(); - - nodes = courseNodes[1].getElementsByTagName("tr"); - final List courseIds = nodes.skip(2).map((node) => node.getElementsByTagName("td")[0].text).toList(); - final courseIdPosition = courseIds.indexWhere((element) => element.contains(courseId)); - if (courseIdPosition == -1) { - throw StateError('[TAT] course_connector.dart: CourseId not found: $courseId'); - } else { - node = nodes[courseIdPosition + 2]; - } - classExtraInfoNodes = node.getElementsByTagName("td"); - courseExtra.id = strQ2B(classExtraInfoNodes[0].text).replaceAll(RegExp(r"\s"), ""); - courseExtra.name = classExtraInfoNodes[1].getElementsByTagName("a")[0].text; - courseExtra.openClass = classExtraInfoNodes[7].getElementsByTagName("a")[0].text; - - // if the courseExtraInfo.herf (課程大綱連結) is empty, - // the category of the course will be set to ▲ (校訂專業必修) as default - if (classExtraInfoNodes[18].text.trim() != "" && - classExtraInfoNodes[18].getElementsByTagName("a")[0].attributes.containsKey("href")) { - courseExtra.href = _courseCNHost + classExtraInfoNodes[18].getElementsByTagName("a")[0].attributes["href"]!; - parameter = ConnectorParameter(courseExtra.href); - result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - nodes = tagNode.getElementsByTagName("tr"); - courseExtra.category = nodes[1].getElementsByTagName("td")[6].text; - } else { - courseExtra.category = constCourseType[4]; - } - - courseExtra.selectNumber = "s?"; - courseExtra.withdrawNumber = "w?"; - - courseExtraInfo.course = courseExtra; - return courseExtraInfo; - } catch (e, stack) { - Log.eWithStack(e.toString(), stack); - return null; - } - } - static Future getCourseENName(String url) async { try { ConnectorParameter parameter; @@ -300,7 +214,7 @@ class CourseConnector { } } - static Future> getCourseSemester(String studentId) async { + static Future?> getCourseSemester(String studentId) async { try { ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); parameter.data = { diff --git a/lib/src/model/course/course_class_json.dart b/lib/src/model/course/course_class_json.dart index c3d36435..a0de1e09 100644 --- a/lib/src/model/course/course_class_json.dart +++ b/lib/src/model/course/course_class_json.dart @@ -1,6 +1,5 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/model/json_init.dart'; import 'package:flutter_app/src/util/language_util.dart'; import 'package:json_annotation/json_annotation.dart'; @@ -8,168 +7,6 @@ import 'package:sprintf/sprintf.dart'; part 'course_class_json.g.dart'; -@JsonSerializable() -class CourseMainJson { - String name; - String id; - String href; - String note; //備註 - String stage; //階段 - String credits; //學分 - String hours; //時數 - String scheduleHref; // 教學進度大綱 - Map time; //時間 - - CourseMainJson( - {this.name, this.href, this.id, this.credits, this.hours, this.stage, this.note, this.time, this.scheduleHref}) { - name = JsonInit.stringInit(name); - id = JsonInit.stringInit(id); - href = JsonInit.stringInit(href); - note = JsonInit.stringInit(note); - stage = JsonInit.stringInit(stage); - credits = JsonInit.stringInit(credits); - hours = JsonInit.stringInit(hours); - scheduleHref = JsonInit.stringInit(scheduleHref); - time = time ?? {}; - } - - bool get isEmpty { - return name.isEmpty && - href.isEmpty && - note.isEmpty && - stage.isEmpty && - credits.isEmpty && - hours.isEmpty && - scheduleHref.isEmpty; - } - - @override - String toString() { - return sprintf( - "name :%s \nid :%s \nhref :%s \nstage :%s \ncredits :%s \nhours :%s \nscheduleHref :%s \nnote :%s \n", - [name, id, href, stage, credits, hours, scheduleHref, note]); - } - - factory CourseMainJson.fromJson(Map json) => _$CourseMainJsonFromJson(json); - - Map toJson() => _$CourseMainJsonToJson(this); -} - -@JsonSerializable() -class CourseExtraJson { - String id; - String name; - String href; //課程名稱用於取得英文 - String category; //類別 (必修...) - String selectNumber; //選課人數 - String withdrawNumber; //徹選人數 - String openClass; //開課班級(計算學分用) - - CourseExtraJson({this.name, this.category, this.selectNumber, this.withdrawNumber, this.href}) { - id = JsonInit.stringInit(id); - name = JsonInit.stringInit(name); - href = JsonInit.stringInit(href); - category = JsonInit.stringInit(category); - selectNumber = JsonInit.stringInit(selectNumber); - withdrawNumber = JsonInit.stringInit(withdrawNumber); - openClass = JsonInit.stringInit(openClass); - } - - bool get isEmpty { - return id.isEmpty && - name.isEmpty && - category.isEmpty && - selectNumber.isEmpty && - withdrawNumber.isEmpty && - openClass.isEmpty; - } - - @override - String toString() { - return sprintf( - "id :%s \nname :%s \ncategory :%s \nselectNumber :%s \nwithdrawNumber :%s \nopenClass :%s \n", - [id, name, category, selectNumber, withdrawNumber, openClass]); - } - - factory CourseExtraJson.fromJson(Map json) => _$CourseExtraJsonFromJson(json); - - Map toJson() => _$CourseExtraJsonToJson(this); -} - -@JsonSerializable() -class ClassJson { - String name; - String href; - - ClassJson({this.name, this.href}) { - name = JsonInit.stringInit(name); - href = JsonInit.stringInit(href); - } - - bool get isEmpty { - return name.isEmpty && href.isEmpty; - } - - @override - String toString() { - return sprintf("name : %s \n" "href : %s \n", [name, href]); - } - - factory ClassJson.fromJson(Map json) => _$ClassJsonFromJson(json); - - Map toJson() => _$ClassJsonToJson(this); -} - -@JsonSerializable() -class ClassroomJson { - String name; - String href; - bool mainUse; - - ClassroomJson({this.name, this.href, this.mainUse}) { - name = JsonInit.stringInit(name); - href = JsonInit.stringInit(href); - mainUse = mainUse ?? false; - } - - bool get isEmpty { - return name.isEmpty && href.isEmpty; - } - - @override - String toString() { - return sprintf("name : %s \nhref : %s \nmainUse : %s \n", [name, href, mainUse.toString()]); - } - - factory ClassroomJson.fromJson(Map json) => _$ClassroomJsonFromJson(json); - - Map toJson() => _$ClassroomJsonToJson(this); -} - -@JsonSerializable() -class TeacherJson { - String name; - String href; - - TeacherJson({this.name, this.href}) { - name = JsonInit.stringInit(name); - href = JsonInit.stringInit(href); - } - - bool get isEmpty { - return name.isEmpty && href.isEmpty; - } - - @override - String toString() { - return sprintf("name : %s \n" "href : %s \n", [name, href]); - } - - factory TeacherJson.fromJson(Map json) => _$TeacherJsonFromJson(json); - - Map toJson() => _$TeacherJsonToJson(this); -} - @JsonSerializable() class SemesterJson { String year; @@ -207,48 +44,4 @@ class SemesterJson { @override int get hashCode => Object.hashAll([semester.hashCode, year.hashCode]); -} - -@JsonSerializable() -class ClassmateJson { - String className; //電子一甲 - String studentEnglishName; - String studentName; - String studentId; - String href; - bool isSelect; //是否撤選 - - ClassmateJson({this.className, this.studentEnglishName, this.studentName, this.studentId, this.isSelect, this.href}) { - className = JsonInit.stringInit(className); - studentEnglishName = JsonInit.stringInit(studentEnglishName); - studentName = JsonInit.stringInit(studentName); - studentId = JsonInit.stringInit(studentId); - href = JsonInit.stringInit(href); - isSelect = isSelect ?? false; - } - - bool get isEmpty { - return className.isEmpty && studentEnglishName.isEmpty && studentName.isEmpty && studentId.isEmpty && href.isEmpty; - } - - @override - String toString() { - return sprintf( - "className : %s \nstudentEnglishName : %s \nstudentName : %s \nstudentId : %s \nhref : %s \nisSelect : %s \n", - [className, studentEnglishName, studentName, studentId, href, isSelect.toString()]); - } - - String getName() { - String name; - if (LanguageUtil.getLangIndex() == LangEnum.en) { - name = studentEnglishName; - } - name = name ?? studentName; - name = (name.contains(RegExp(r"\w"))) ? name : studentName; - return name; - } - - factory ClassmateJson.fromJson(Map json) => _$ClassmateJsonFromJson(json); - - Map toJson() => _$ClassmateJsonToJson(this); -} +} \ No newline at end of file diff --git a/lib/src/model/course/course_class_json.g.dart b/lib/src/model/course/course_class_json.g.dart index 8536047d..043ce4a3 100644 --- a/lib/src/model/course/course_class_json.g.dart +++ b/lib/src/model/course/course_class_json.g.dart @@ -8,135 +8,6 @@ part of 'course_class_json.dart'; // JsonSerializableGenerator // ************************************************************************** -CourseMainJson _$CourseMainJsonFromJson(Map json) { - return CourseMainJson( - name: json['name'] as String, - href: json['href'] as String, - id: json['id'] as String, - credits: json['credits'] as String, - hours: json['hours'] as String, - stage: json['stage'] as String, - note: json['note'] as String, - time: (json['time'] as Map)?.map( - (k, e) => MapEntry(_$enumDecodeNullable(_$DayEnumMap, k), e as String), - ), - scheduleHref: json['scheduleHref'] as String, - ); -} - -Map _$CourseMainJsonToJson(CourseMainJson instance) => { - 'name': instance.name, - 'id': instance.id, - 'href': instance.href, - 'note': instance.note, - 'stage': instance.stage, - 'credits': instance.credits, - 'hours': instance.hours, - 'scheduleHref': instance.scheduleHref, - 'time': instance.time?.map((k, e) => MapEntry(_$DayEnumMap[k], e)), - }; - -T _$enumDecode( - Map enumValues, - dynamic source, { - T unknownValue, -}) { - if (source == null) { - throw ArgumentError('A value must be provided. Supported values: ' - '${enumValues.values.join(', ')}'); - } - - final value = enumValues.entries.singleWhere((e) => e.value == source, orElse: () => null)?.key; - - if (value == null && unknownValue == null) { - throw ArgumentError('`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}'); - } - return value ?? unknownValue; -} - -T _$enumDecodeNullable( - Map enumValues, - dynamic source, { - T unknownValue, -}) { - if (source == null) { - return null; - } - return _$enumDecode(enumValues, source, unknownValue: unknownValue); -} - -const _$DayEnumMap = { - Day.Monday: 'Monday', - Day.Tuesday: 'Tuesday', - Day.Wednesday: 'Wednesday', - Day.Thursday: 'Thursday', - Day.Friday: 'Friday', - Day.Saturday: 'Saturday', - Day.Sunday: 'Sunday', - Day.UnKnown: 'UnKnown', -}; - -CourseExtraJson _$CourseExtraJsonFromJson(Map json) { - return CourseExtraJson( - name: json['name'] as String, - category: json['category'] as String, - selectNumber: json['selectNumber'] as String, - withdrawNumber: json['withdrawNumber'] as String, - href: json['href'] as String, - ) - ..id = json['id'] as String - ..openClass = json['openClass'] as String; -} - -Map _$CourseExtraJsonToJson(CourseExtraJson instance) => { - 'id': instance.id, - 'name': instance.name, - 'href': instance.href, - 'category': instance.category, - 'selectNumber': instance.selectNumber, - 'withdrawNumber': instance.withdrawNumber, - 'openClass': instance.openClass, - }; - -ClassJson _$ClassJsonFromJson(Map json) { - return ClassJson( - name: json['name'] as String, - href: json['href'] as String, - ); -} - -Map _$ClassJsonToJson(ClassJson instance) => { - 'name': instance.name, - 'href': instance.href, - }; - -ClassroomJson _$ClassroomJsonFromJson(Map json) { - return ClassroomJson( - name: json['name'] as String, - href: json['href'] as String, - mainUse: json['mainUse'] as bool, - ); -} - -Map _$ClassroomJsonToJson(ClassroomJson instance) => { - 'name': instance.name, - 'href': instance.href, - 'mainUse': instance.mainUse, - }; - -TeacherJson _$TeacherJsonFromJson(Map json) { - return TeacherJson( - name: json['name'] as String, - href: json['href'] as String, - ); -} - -Map _$TeacherJsonToJson(TeacherJson instance) => { - 'name': instance.name, - 'href': instance.href, - }; - SemesterJson _$SemesterJsonFromJson(Map json) { return SemesterJson( year: json['year'] as String, @@ -147,24 +18,4 @@ SemesterJson _$SemesterJsonFromJson(Map json) { Map _$SemesterJsonToJson(SemesterJson instance) => { 'year': instance.year, 'semester': instance.semester, - }; - -ClassmateJson _$ClassmateJsonFromJson(Map json) { - return ClassmateJson( - className: json['className'] as String, - studentEnglishName: json['studentEnglishName'] as String, - studentName: json['studentName'] as String, - studentId: json['studentId'] as String, - isSelect: json['isSelect'] as bool, - href: json['href'] as String, - ); -} - -Map _$ClassmateJsonToJson(ClassmateJson instance) => { - 'className': instance.className, - 'studentEnglishName': instance.studentEnglishName, - 'studentName': instance.studentName, - 'studentId': instance.studentId, - 'href': instance.href, - 'isSelect': instance.isSelect, - }; + }; \ No newline at end of file diff --git a/lib/src/model/course/course_main_extra_json.dart b/lib/src/model/course/course_main_extra_json.dart deleted file mode 100644 index b2782736..00000000 --- a/lib/src/model/course/course_main_extra_json.dart +++ /dev/null @@ -1,105 +0,0 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 -import 'package:flutter_app/src/model/course/course_class_json.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:sprintf/sprintf.dart'; - -part 'course_main_extra_json.g.dart'; - -@JsonSerializable() -class CourseExtraInfoJson { - //點入課程使用 - SemesterJson courseSemester; - CourseExtraJson course; - List classmate; //修課同學 - - CourseExtraInfoJson({this.courseSemester, this.course, this.classmate}) { - classmate = classmate ?? []; - courseSemester = courseSemester ?? SemesterJson(); - course = course ?? CourseExtraJson(); - } - - bool get isEmpty { - return classmate.isEmpty && courseSemester.isEmpty && course.isEmpty; - } - - @override - String toString() { - return sprintf( - "---------courseSemester-------- \n%s \n---------course-------- \n%s \n---------classmateList-------- \n%s \n", - [courseSemester.toString(), course.toString(), classmate.toString()]); - } - - factory CourseExtraInfoJson.fromJson(Map json) => _$CourseExtraInfoJsonFromJson(json); - - Map toJson() => _$CourseExtraInfoJsonToJson(this); -} - -@JsonSerializable() -class CourseMainInfoJson { - CourseMainJson course; - List teacher; //開課老師 - List classroom; //使用教室 - List openClass; //開課班級 - CourseMainInfoJson({this.course, this.teacher, this.classroom, this.openClass}) { - course = course ?? CourseMainJson(); - teacher = teacher ?? []; - classroom = classroom ?? []; - openClass = openClass ?? []; - } - - String getOpenClassName() { - String name = ""; - for (ClassJson value in openClass) { - name += '${value.name} '; - } - return name; - } - - String getTeacherName() { - String name = ""; - for (TeacherJson value in teacher) { - name += '${value.name} '; - } - return name; - } - - String getClassroomName() { - String name = ""; - for (ClassroomJson value in classroom) { - name += '${value.name} '; - } - return name; - } - - List getClassroomNameList() { - List name = []; - for (ClassroomJson value in classroom) { - name.add(value.name); - } - return name; - } - - List getClassroomHrefList() { - List href = []; - for (ClassroomJson value in classroom) { - href.add(value.href); - } - return href; - } - - bool get isEmpty { - return course.isEmpty && teacher.isEmpty && classroom.isEmpty && openClass.isEmpty; - } - - @override - String toString() { - return sprintf( - "---------course-------- \n%s \n---------teacherList-------- \n%s \n---------classroomList-------- \n%s \n---------openClassList-------- \n%s \n", - [course.toString(), teacher.toString(), classroom.toString(), openClass.toString()]); - } - - factory CourseMainInfoJson.fromJson(Map json) => _$CourseMainInfoJsonFromJson(json); - - Map toJson() => _$CourseMainInfoJsonToJson(this); -} diff --git a/lib/src/model/course/course_main_extra_json.g.dart b/lib/src/model/course/course_main_extra_json.g.dart deleted file mode 100644 index ca62cafd..00000000 --- a/lib/src/model/course/course_main_extra_json.g.dart +++ /dev/null @@ -1,48 +0,0 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'course_main_extra_json.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -CourseExtraInfoJson _$CourseExtraInfoJsonFromJson(Map json) { - return CourseExtraInfoJson( - courseSemester: - json['courseSemester'] == null ? null : SemesterJson.fromJson(json['courseSemester'] as Map), - course: json['course'] == null ? null : CourseExtraJson.fromJson(json['course'] as Map), - classmate: (json['classmate'] as List) - ?.map((e) => e == null ? null : ClassmateJson.fromJson(e as Map)) - ?.toList(), - ); -} - -Map _$CourseExtraInfoJsonToJson(CourseExtraInfoJson instance) => { - 'courseSemester': instance.courseSemester, - 'course': instance.course, - 'classmate': instance.classmate, - }; - -CourseMainInfoJson _$CourseMainInfoJsonFromJson(Map json) { - return CourseMainInfoJson( - course: json['course'] == null ? null : CourseMainJson.fromJson(json['course'] as Map), - teacher: (json['teacher'] as List) - ?.map((e) => e == null ? null : TeacherJson.fromJson(e as Map)) - ?.toList(), - classroom: (json['classroom'] as List) - ?.map((e) => e == null ? null : ClassroomJson.fromJson(e as Map)) - ?.toList(), - openClass: (json['openClass'] as List) - ?.map((e) => e == null ? null : ClassJson.fromJson(e as Map)) - ?.toList(), - ); -} - -Map _$CourseMainInfoJsonToJson(CourseMainInfoJson instance) => { - 'course': instance.course, - 'teacher': instance.teacher, - 'classroom': instance.classroom, - 'openClass': instance.openClass, - }; diff --git a/lib/src/model/coursetable/course_table_json.dart b/lib/src/model/coursetable/course_table_json.dart deleted file mode 100644 index 33333d2c..00000000 --- a/lib/src/model/coursetable/course_table_json.dart +++ /dev/null @@ -1,227 +0,0 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 -import 'package:flutter_app/src/model/course/course_class_json.dart'; -import 'package:flutter_app/src/model/course/course_main_extra_json.dart'; -import 'package:flutter_app/src/model/json_init.dart'; -import 'package:json_annotation/json_annotation.dart'; -import 'package:sprintf/sprintf.dart'; - -part 'course_table_json.g.dart'; - -// ignore: constant_identifier_names -enum Day { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, UnKnown } - -// ignore: constant_identifier_names -enum SectionNumber { T_1, T_2, T_3, T_4, T_N, T_5, T_6, T_7, T_8, T_9, T_A, T_B, T_C, T_D, T_UnKnown } - -@JsonSerializable() -class CourseTableJson { - SemesterJson courseSemester; //課程學期資料 - String studentId; - String studentName; - Map> courseInfoMap; - - CourseTableJson({this.courseSemester, this.courseInfoMap, this.studentId, this.studentName}) { - studentId = JsonInit.stringInit(studentId); - studentName = JsonInit.stringInit(studentName); - courseSemester = courseSemester ?? SemesterJson(); - if (courseInfoMap != null) { - courseInfoMap = courseInfoMap; - } else { - courseInfoMap = {}; - for (Day value in Day.values) { - courseInfoMap[value] = {}; - } - } - } - - int getTotalCredit() { - int credit = 0; - final List courseIdList = getCourseIdList(); - for (final courseId in courseIdList) { - credit += getCreditByCourseId(courseId); - } - return credit; - } - - int getCreditByCourseId(String courseId) { - for (Day day in Day.values) { - for (SectionNumber number in SectionNumber.values) { - CourseInfoJson courseDetail = courseInfoMap[day][number]; - if (courseDetail != null) { - if (courseDetail.main.course.id == courseId) { - String creditString = courseDetail.main.course.credits; - try { - return double.parse(creditString).toInt(); - } catch (e) { - return 0; - } - } - } - } - } - return 0; - } - - bool isDayInCourseTable(Day day) { - bool pass = false; - for (SectionNumber number in SectionNumber.values) { - if (courseInfoMap[day][number] != null) { - pass = true; - break; - } - } - return pass; - } - - bool isSectionNumberInCourseTable(SectionNumber number) { - bool pass = false; - for (Day day in Day.values) { - if (courseInfoMap[day].containsKey(number)) { - pass = true; - break; - } - } - return pass; - } - - factory CourseTableJson.fromJson(Map json) => _$CourseTableJsonFromJson(json); - - Map toJson() => _$CourseTableJsonToJson(this); - - @override - String toString() { - String courseInfoString = ""; - for (Day day in Day.values) { - for (SectionNumber number in SectionNumber.values) { - courseInfoString += "$day $number\n"; - courseInfoString += "${courseInfoMap[day][number]}\n"; - } - } - return sprintf("studentId :%s \n ---------courseSemester-------- \n%s \n---------courseInfo-------- \n%s \n", - [studentId, courseSemester.toString(), courseInfoString]); - } - - bool get isEmpty { - return studentId.isEmpty && courseSemester.isEmpty; - } - - CourseInfoJson getCourseDetailByTime(Day day, SectionNumber sectionNumber) { - return courseInfoMap[day][sectionNumber]; - } - - void setCourseDetailByTime(Day day, SectionNumber sectionNumber, CourseInfoJson courseInfo) { - if (day == Day.UnKnown) { - for (SectionNumber value in SectionNumber.values) { - if (courseInfo.main.course.id.isEmpty) { - continue; - } - if (!courseInfoMap[day].containsKey(value)) { - courseInfoMap[day][value] = courseInfo; - //Log.d( day.toString() + value.toString() + courseInfo.toString() ); - break; - } - } - } - /* else if (courseInfoMap[day].containsKey(sectionNumber)) { - throw Exception("衝堂"); - } */ - else { - courseInfoMap[day][sectionNumber] = courseInfo; - } - } - - bool setCourseDetailByTimeString(Day day, String sectionNumber, CourseInfoJson courseInfo) { - bool add = false; - for (SectionNumber value in SectionNumber.values) { - String time = value.toString().split("_")[1]; - if (sectionNumber.contains(time)) { - setCourseDetailByTime(day, value, courseInfo); - add = true; - } - } - return add; - } - - List getCourseIdList() { - List courseIdList = []; - for (Day day in Day.values) { - for (SectionNumber number in SectionNumber.values) { - CourseInfoJson courseInfo = courseInfoMap[day][number]; - if (courseInfo != null) { - String id = courseInfo.main.course.id; - if (!courseIdList.contains(id)) { - courseIdList.add(id); - } - } - } - } - return courseIdList; - } - - String getCourseNameByCourseId(String courseId) { - for (Day day in Day.values) { - for (SectionNumber number in SectionNumber.values) { - CourseInfoJson courseDetail = courseInfoMap[day][number]; - if (courseDetail != null) { - if (courseDetail.main.course.id == courseId) { - return courseDetail.main.course.name; - } - } - } - } - return null; - } - - CourseInfoJson getCourseInfoByCourseName(String courseName) { - for (Day day in Day.values) { - for (SectionNumber number in SectionNumber.values) { - CourseInfoJson courseDetail = courseInfoMap[day][number]; - if (courseDetail != null) { - if (courseDetail.main.course.name == courseName) { - return courseDetail; - } - } - } - } - return null; - } -} - -@JsonSerializable() -class CourseInfoJson { - CourseMainInfoJson main; - CourseExtraInfoJson extra; - - CourseInfoJson({this.main, this.extra}) { - main = main ?? CourseMainInfoJson(); - extra = extra ?? CourseExtraInfoJson(); - } - - bool get isEmpty { - return main.isEmpty && extra.isEmpty; - } - -/* - @override - bool operator ==(dynamic o) { - if( isEmpty || o.isEmpty || !(o is CourseInfoJson) ){ - return false; - }else{ - return ( main.course.id == o.main.course.id ); - } - } - - int get hashCode => hash2(main.hashCode, extra.hashCode); -*/ - - @override - String toString() { - return sprintf( - "---------main-------- \n%s \n" "---------extra-------- \n%s \n", [main.toString(), extra.toString()]); - } - - factory CourseInfoJson.fromJson(Map json) => _$CourseInfoJsonFromJson(json); - - Map toJson() => _$CourseInfoJsonToJson(this); -} diff --git a/lib/src/model/coursetable/course_table_json.g.dart b/lib/src/model/coursetable/course_table_json.g.dart deleted file mode 100644 index 3ca2e74f..00000000 --- a/lib/src/model/coursetable/course_table_json.g.dart +++ /dev/null @@ -1,105 +0,0 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'course_table_json.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -CourseTableJson _$CourseTableJsonFromJson(Map json) { - return CourseTableJson( - courseSemester: - json['courseSemester'] == null ? null : SemesterJson.fromJson(json['courseSemester'] as Map), - courseInfoMap: (json['courseInfoMap'] as Map)?.map( - (k, e) => MapEntry( - _$enumDecodeNullable(_$DayEnumMap, k), - (e as Map)?.map( - (k, e) => MapEntry(_$enumDecodeNullable(_$SectionNumberEnumMap, k), - e == null ? null : CourseInfoJson.fromJson(e as Map)), - )), - ), - studentId: json['studentId'] as String, - studentName: json['studentName'] as String, - ); -} - -Map _$CourseTableJsonToJson(CourseTableJson instance) => { - 'courseSemester': instance.courseSemester, - 'studentId': instance.studentId, - 'studentName': instance.studentName, - 'courseInfoMap': instance.courseInfoMap - ?.map((k, e) => MapEntry(_$DayEnumMap[k], e?.map((k, e) => MapEntry(_$SectionNumberEnumMap[k], e)))), - }; - -T _$enumDecode( - Map enumValues, - dynamic source, { - T unknownValue, -}) { - if (source == null) { - throw ArgumentError('A value must be provided. Supported values: ' - '${enumValues.values.join(', ')}'); - } - - final value = enumValues.entries.singleWhere((e) => e.value == source, orElse: () => null)?.key; - - if (value == null && unknownValue == null) { - throw ArgumentError('`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}'); - } - return value ?? unknownValue; -} - -T _$enumDecodeNullable( - Map enumValues, - dynamic source, { - T unknownValue, -}) { - if (source == null) { - return null; - } - return _$enumDecode(enumValues, source, unknownValue: unknownValue); -} - -const _$SectionNumberEnumMap = { - SectionNumber.T_1: 'T_1', - SectionNumber.T_2: 'T_2', - SectionNumber.T_3: 'T_3', - SectionNumber.T_4: 'T_4', - SectionNumber.T_N: 'T_N', - SectionNumber.T_5: 'T_5', - SectionNumber.T_6: 'T_6', - SectionNumber.T_7: 'T_7', - SectionNumber.T_8: 'T_8', - SectionNumber.T_9: 'T_9', - SectionNumber.T_A: 'T_A', - SectionNumber.T_B: 'T_B', - SectionNumber.T_C: 'T_C', - SectionNumber.T_D: 'T_D', - SectionNumber.T_UnKnown: 'T_UnKnown', -}; - -const _$DayEnumMap = { - Day.Monday: 'Monday', - Day.Tuesday: 'Tuesday', - Day.Wednesday: 'Wednesday', - Day.Thursday: 'Thursday', - Day.Friday: 'Friday', - Day.Saturday: 'Saturday', - Day.Sunday: 'Sunday', - Day.UnKnown: 'UnKnown', -}; - -CourseInfoJson _$CourseInfoJsonFromJson(Map json) { - return CourseInfoJson( - main: json['main'] == null ? null : CourseMainInfoJson.fromJson(json['main'] as Map), - extra: json['extra'] == null ? null : CourseExtraInfoJson.fromJson(json['extra'] as Map), - ); -} - -Map _$CourseInfoJsonToJson(CourseInfoJson instance) => { - 'main': instance.main, - 'extra': instance.extra, - }; diff --git a/lib/src/model/setting/setting_json.dart b/lib/src/model/setting/setting_json.dart index e373ea31..2a01eadd 100644 --- a/lib/src/model/setting/setting_json.dart +++ b/lib/src/model/setting/setting_json.dart @@ -1,6 +1,5 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/model/json_init.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:sprintf/sprintf.dart'; diff --git a/lib/src/store/local_storage.dart b/lib/src/store/local_storage.dart index 6cda5f21..f0901691 100644 --- a/lib/src/store/local_storage.dart +++ b/lib/src/store/local_storage.dart @@ -6,7 +6,6 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter_app/src/connector/core/dio_connector.dart'; import 'package:flutter_app/src/model/course/course_score_json.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/model/setting/setting_json.dart'; import 'package:flutter_app/src/model/userdata/user_data_json.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; diff --git a/lib/src/task/course/course_extra_info_task.dart b/lib/src/task/course/course_extra_info_task.dart deleted file mode 100644 index bec7e763..00000000 --- a/lib/src/task/course/course_extra_info_task.dart +++ /dev/null @@ -1,33 +0,0 @@ -// ignore_for_file: import_of_legacy_library_into_null_safe - -import 'package:flutter_app/src/connector/course_connector.dart'; -import 'package:flutter_app/src/model/course/course_main_extra_json.dart'; -import 'package:flutter_app/src/r.dart'; - -import '../task.dart'; -import 'course_system_task.dart'; - -class CourseExtraInfoTask extends CourseSystemTask { - final String id; - - CourseExtraInfoTask(this.id) : super("CourseExtraInfoTask"); - - @override - Future execute() async { - final status = await super.execute(); - - if (status == TaskStatus.success) { - super.onStart(R.current.getCourseDetail); - final value = await CourseConnector.getCourseExtraInfo(id) as CourseExtraInfoJson?; - super.onEnd(); - - if (value != null) { - result = value; - return TaskStatus.success; - } else { - return await super.onError(R.current.getCourseDetailError); - } - } - return status; - } -} diff --git a/lib/ui/other/route_utils.dart b/lib/ui/other/route_utils.dart index 1dfc23f2..b3aa9595 100644 --- a/lib/ui/other/route_utils.dart +++ b/lib/ui/other/route_utils.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/src/connector/core/dio_connector.dart'; import 'package:flutter_app/src/controllers/zuvio_auth_controller.dart'; import 'package:flutter_app/src/controllers/zuvio_auto_roll_call_schedule_controller.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/ui/pages/coursedetail/course_detail_page.dart'; import 'package:flutter_app/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart'; import 'package:flutter_app/ui/pages/fileviewer/file_viewer_page.dart'; diff --git a/lib/ui/pages/coursedetail/course_detail_page.dart b/lib/ui/pages/coursedetail/course_detail_page.dart index f0b8fe55..37a6b428 100644 --- a/lib/ui/pages/coursedetail/course_detail_page.dart +++ b/lib/ui/pages/coursedetail/course_detail_page.dart @@ -2,7 +2,6 @@ // @dart=2.10 import 'package:flutter/material.dart'; import 'package:flutter_app/src/model/course/course_class_json.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/providers/app_provider.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; diff --git a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart index e5430c16..df08559c 100644 --- a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart +++ b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_detail_page.dart @@ -4,7 +4,6 @@ import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/file/file_download.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/util/html_utils.dart'; import 'package:flutter_app/ui/other/list_view_animator.dart'; diff --git a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart index a147b490..540c66bb 100644 --- a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart +++ b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_announcement_page.dart @@ -1,7 +1,6 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 import 'package:flutter/material.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/model/ischoolplus/ischool_plus_announcement_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; diff --git a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart index 2b7d625c..eb2d194f 100644 --- a/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart +++ b/lib/ui/pages/coursedetail/screen/ischoolplus/iplus_file_page.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/src/connector/ischool_plus_connector.dart'; import 'package:flutter_app/src/file/file_download.dart'; import 'package:flutter_app/src/file/file_store.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/model/ischoolplus/course_file_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index f1152844..e7018c62 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/src/config/app_colors.dart'; import 'package:flutter_app/src/model/coursetable/course_period.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; import '../../../src/model/coursetable/course.dart'; diff --git a/lib/ui/pages/videoplayer/class_video_player.dart b/lib/ui/pages/videoplayer/class_video_player.dart index 7ab83c56..e268c3f4 100644 --- a/lib/ui/pages/videoplayer/class_video_player.dart +++ b/lib/ui/pages/videoplayer/class_video_player.dart @@ -8,7 +8,6 @@ import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/connector/core/connector.dart'; import 'package:flutter_app/src/connector/core/connector_parameter.dart'; import 'package:flutter_app/src/file/file_download.dart'; -import 'package:flutter_app/src/model/coursetable/course_table_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; import 'package:flutter_app/src/util/language_util.dart'; From 0d2b1c034e1341d1787404aa3fd6d6a44ee46a68 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 9 Feb 2024 02:02:18 +0800 Subject: [PATCH 06/31] Rename: course_syllabus and course_semester --- lib/src/connector/course_connector.dart | 4 ++-- lib/src/connector/score_connector.dart | 2 +- lib/src/model/course/course_score_json.dart | 2 +- .../course/{course_class_json.dart => course_semester.dart} | 2 +- .../{course_class_json.g.dart => course_semester.g.dart} | 2 +- .../{course_syllabus_json.dart => course_syllabus.dart} | 0 lib/src/store/local_storage.dart | 2 +- lib/src/task/course/course_category_task.dart | 2 +- lib/src/task/course/course_semester_task.dart | 2 +- lib/ui/pages/coursedetail/course_detail_page.dart | 2 +- lib/ui/pages/coursetable/course_table_page.dart | 2 +- lib/ui/pages/score/score_page.dart | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) rename lib/src/model/course/{course_class_json.dart => course_semester.dart} (97%) rename lib/src/model/course/{course_class_json.g.dart => course_semester.g.dart} (94%) rename lib/src/model/course/{course_syllabus_json.dart => course_syllabus.dart} (100%) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index 183e83fa..a5e61488 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -3,11 +3,11 @@ import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/connector/core/connector.dart'; import 'package:flutter_app/src/connector/core/connector_parameter.dart'; import 'package:flutter_app/src/connector/ntut_connector.dart'; -import 'package:flutter_app/src/model/course/course_class_json.dart'; +import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/model/course/course_score_json.dart'; import 'package:flutter_app/src/model/coursetable/course.dart'; import 'package:flutter_app/src/model/coursetable/user.dart'; -import 'package:flutter_app/src/model/course/course_syllabus_json.dart'; +import 'package:flutter_app/src/model/course/course_syllabus.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; diff --git a/lib/src/connector/score_connector.dart b/lib/src/connector/score_connector.dart index 9e0c08d1..ba8e6505 100644 --- a/lib/src/connector/score_connector.dart +++ b/lib/src/connector/score_connector.dart @@ -2,7 +2,7 @@ // @dart=2.10 import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/connector/ntut_connector.dart'; -import 'package:flutter_app/src/model/course/course_class_json.dart'; +import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/model/course/course_score_json.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; diff --git a/lib/src/model/course/course_score_json.dart b/lib/src/model/course/course_score_json.dart index d7aeac04..368460d8 100644 --- a/lib/src/model/course/course_score_json.dart +++ b/lib/src/model/course/course_score_json.dart @@ -1,6 +1,6 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 -import 'package:flutter_app/src/model/course/course_class_json.dart'; +import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/model/json_init.dart'; import 'package:flutter_app/src/util/language_util.dart'; import 'package:json_annotation/json_annotation.dart'; diff --git a/lib/src/model/course/course_class_json.dart b/lib/src/model/course/course_semester.dart similarity index 97% rename from lib/src/model/course/course_class_json.dart rename to lib/src/model/course/course_semester.dart index a0de1e09..25c644dd 100644 --- a/lib/src/model/course/course_class_json.dart +++ b/lib/src/model/course/course_semester.dart @@ -5,7 +5,7 @@ import 'package:flutter_app/src/util/language_util.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:sprintf/sprintf.dart'; -part 'course_class_json.g.dart'; +part 'course_semester.g.dart'; @JsonSerializable() class SemesterJson { diff --git a/lib/src/model/course/course_class_json.g.dart b/lib/src/model/course/course_semester.g.dart similarity index 94% rename from lib/src/model/course/course_class_json.g.dart rename to lib/src/model/course/course_semester.g.dart index 043ce4a3..c15c9f1e 100644 --- a/lib/src/model/course/course_class_json.g.dart +++ b/lib/src/model/course/course_semester.g.dart @@ -2,7 +2,7 @@ // @dart=2.10 // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'course_class_json.dart'; +part of 'course_semester.dart'; // ************************************************************************** // JsonSerializableGenerator diff --git a/lib/src/model/course/course_syllabus_json.dart b/lib/src/model/course/course_syllabus.dart similarity index 100% rename from lib/src/model/course/course_syllabus_json.dart rename to lib/src/model/course/course_syllabus.dart diff --git a/lib/src/store/local_storage.dart b/lib/src/store/local_storage.dart index f0901691..ddb8cf73 100644 --- a/lib/src/store/local_storage.dart +++ b/lib/src/store/local_storage.dart @@ -14,7 +14,7 @@ import 'package:shared_preferences/shared_preferences.dart'; import 'package:tat_core/core/zuvio/domain/login_credential.dart'; import 'package:tat_core/core/zuvio/domain/user_info.dart'; -import '../model/course/course_class_json.dart'; +import '../model/course/course_semester.dart'; import "../model/coursetable/course.dart"; import '../model/coursetable/course_table.dart'; diff --git a/lib/src/task/course/course_category_task.dart b/lib/src/task/course/course_category_task.dart index fe4eea3b..f78b6a34 100644 --- a/lib/src/task/course/course_category_task.dart +++ b/lib/src/task/course/course_category_task.dart @@ -1,7 +1,7 @@ // ignore_for_file: import_of_legacy_library_into_null_safe import 'package:flutter_app/src/connector/course_connector.dart'; -import 'package:flutter_app/src/model/course/course_syllabus_json.dart'; +import 'package:flutter_app/src/model/course/course_syllabus.dart'; import 'package:flutter_app/src/r.dart'; import '../task.dart'; diff --git a/lib/src/task/course/course_semester_task.dart b/lib/src/task/course/course_semester_task.dart index fada03bb..59977eae 100644 --- a/lib/src/task/course/course_semester_task.dart +++ b/lib/src/task/course/course_semester_task.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/src/connector/course_connector.dart'; -import 'package:flutter_app/src/model/course/course_class_json.dart'; +import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/r.dart'; import 'package:get/get.dart'; import 'package:numberpicker/numberpicker.dart'; diff --git a/lib/ui/pages/coursedetail/course_detail_page.dart b/lib/ui/pages/coursedetail/course_detail_page.dart index 37a6b428..e243bcb8 100644 --- a/lib/ui/pages/coursedetail/course_detail_page.dart +++ b/lib/ui/pages/coursedetail/course_detail_page.dart @@ -1,7 +1,7 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 import 'package:flutter/material.dart'; -import 'package:flutter_app/src/model/course/course_class_json.dart'; +import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/providers/app_provider.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; diff --git a/lib/ui/pages/coursetable/course_table_page.dart b/lib/ui/pages/coursetable/course_table_page.dart index fa8a27ca..52b7e954 100644 --- a/lib/ui/pages/coursetable/course_table_page.dart +++ b/lib/ui/pages/coursetable/course_table_page.dart @@ -10,7 +10,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/config/app_config.dart'; -import 'package:flutter_app/src/model/course/course_class_json.dart'; +import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/model/userdata/user_data_json.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; diff --git a/lib/ui/pages/score/score_page.dart b/lib/ui/pages/score/score_page.dart index f19441cd..cf511602 100644 --- a/lib/ui/pages/score/score_page.dart +++ b/lib/ui/pages/score/score_page.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/config/app_colors.dart'; import 'package:flutter_app/src/model/course/course_score_json.dart'; -import 'package:flutter_app/src/model/course/course_syllabus_json.dart'; +import 'package:flutter_app/src/model/course/course_syllabus.dart'; import 'package:flutter_app/src/providers/app_provider.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; From f10d45086c57438460cf1bdcbafa42b2f5c8a0a4 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 9 Feb 2024 18:27:19 +0800 Subject: [PATCH 07/31] Migrate: Remove must.dart --- lib/src/connector/course_connector.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index a5e61488..b98b6734 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -11,8 +11,6 @@ import 'package:flutter_app/src/model/course/course_syllabus.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart'; -import '../util/must.dart'; - enum CourseConnectorStatus { loginSuccess, loginFail, unknownError } class CourseConnector { @@ -318,8 +316,10 @@ class CourseConnector { for (int i = 0; i < nodes.length; i++) { node = nodes[i]; var href = node.attributes["href"]; - Must.notNullOrEmpty(href, "href"); - Map code = Uri.parse(href!).queryParameters; + if(href == null || href.isEmpty){ + throw Exception("getDivisionList: href is null or empty."); + } + Map code = Uri.parse(href).queryParameters; resultList.add({"name": node.text, "code": code}); } return resultList; @@ -351,7 +351,9 @@ class CourseConnector { for (int i = 0; i < nodes.length; i++) { node = nodes[i]; var href = node.attributes["href"]; - Must.notNullOrEmpty(href, "href"); + if(href == null || href.isEmpty){ + throw Exception("getDepartmentList: href is null or empty."); + } Map code = Uri.parse(href!).queryParameters; String name = node.text.replaceAll(RegExp("[ |s]"), ""); resultList.add({"name": name, "code": code}); From 27770d7371fd2cd00a26f80f0c22a1135987891f Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 9 Feb 2024 18:28:21 +0800 Subject: [PATCH 08/31] Chore: format --- lib/src/connector/course_connector.dart | 49 +-- lib/src/model/course/course_semester.dart | 2 +- lib/src/model/course/course_semester.g.dart | 2 +- lib/src/model/coursetable/course.dart | 50 ++- lib/src/model/coursetable/course.g.dart | 19 +- lib/src/model/coursetable/course_period.dart | 4 +- .../model/coursetable/course_period.g.dart | 3 +- lib/src/model/coursetable/course_table.dart | 9 +- lib/src/model/coursetable/course_table.g.dart | 7 +- lib/src/model/coursetable/user.dart | 13 +- lib/src/model/json_init.dart | 6 +- lib/src/store/local_storage.dart | 9 +- lib/src/task/course/course_table_task.dart | 39 +-- .../coursedetail/course_detail_page.dart | 6 +- .../coursedetail/screen/course_info_page.dart | 316 ++++++------------ .../coursetable/course_table_control.dart | 40 ++- .../pages/coursetable/course_table_page.dart | 93 +++--- 17 files changed, 263 insertions(+), 404 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index b98b6734..cf1c63c1 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -25,10 +25,7 @@ class CourseConnector { static Future login() async { try { Document tagNode = await _getSSORedirectNodesInLoginPhase(); - await _tryToSSOLoginOrThrowException( - _getSSOLoginJumpUrl(tagNode), - _getSSOLoginPayload(tagNode) - ); + await _tryToSSOLoginOrThrowException(_getSSOLoginJumpUrl(tagNode), _getSSOLoginPayload(tagNode)); return CourseConnectorStatus.loginSuccess; } catch (e, stack) { Log.eWithStack(e.toString(), stack); @@ -52,7 +49,7 @@ class CourseConnector { List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); List courses = []; - for(int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++){ + for (int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++) { var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); courses.add(Course( idString: courseRowData[0].text, @@ -68,8 +65,7 @@ class CourseConnector { applyStatus: courseRowData[14].text, language: courseRowData[15].text, syllabusLink: "", - note: courseRowData[16].text - )); + note: courseRowData[16].text)); } return courses; @@ -89,10 +85,7 @@ class CourseConnector { String result = await Connector.getDataByGet(parameter); Document tagNode = parse(result); - String courseTableHead = tagNode.getElementsByTagName("table")[1] - .getElementsByTagName("tr") - .first - .text; + String courseTableHead = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr").first.text; List matches = RegExp(r".+?:(.+?)\s").allMatches(courseTableHead).toList(); String? name = matches[1].group(1); @@ -106,11 +99,7 @@ class CourseConnector { throw Exception("getUserInfo: Cannot Fetch the user info (null className)."); } - return User( - id: studentId, - name: name, - className: className - ); + return User(id: studentId, name: name, className: className); } catch (e, stack) { Log.eWithStack(e.toString(), stack); return User.origin(); @@ -150,8 +139,7 @@ class CourseConnector { applyStatus: courseRowData[16].text, language: courseRowData[17].text, syllabusLink: syllabusLinkHref == null ? "" : _postCourseCNUrl + syllabusLinkHref, - note: courseRowData[19].text - )); + note: courseRowData[19].text)); } return courses; @@ -166,9 +154,7 @@ class CourseConnector { parameter.charsetName = 'big5'; String result = await Connector.getDataByGet(parameter); tagNode = parse(result); - node = tagNode - .getElementsByTagName("table") - .first; + node = tagNode.getElementsByTagName("table").first; node = node.getElementsByTagName("tr")[1]; return node.getElementsByTagName("td")[2].text.replaceAll(RegExp(r"\n"), ""); } catch (e, stack) { @@ -263,9 +249,8 @@ class CourseConnector { Element node = tagNode.getElementsByTagName("tbody").first; List nodes = node.getElementsByTagName("tr"); - String redirectHypertextRef = nodes.firstWhere((node) => - node.text.contains(department) - ).getElementsByTagName("a").first.attributes["href"]!; + String redirectHypertextRef = + nodes.firstWhere((node) => node.text.contains(department)).getElementsByTagName("a").first.attributes["href"]!; Map graduationMap = await _getGraduationCreditMap(redirectHypertextRef); return graduationMap; @@ -316,7 +301,7 @@ class CourseConnector { for (int i = 0; i < nodes.length; i++) { node = nodes[i]; var href = node.attributes["href"]; - if(href == null || href.isEmpty){ + if (href == null || href.isEmpty) { throw Exception("getDivisionList: href is null or empty."); } Map code = Uri.parse(href).queryParameters; @@ -351,7 +336,7 @@ class CourseConnector { for (int i = 0; i < nodes.length; i++) { node = nodes[i]; var href = node.attributes["href"]; - if(href == null || href.isEmpty){ + if (href == null || href.isEmpty) { throw Exception("getDepartmentList: href is null or empty."); } Map code = Uri.parse(href!).queryParameters; @@ -461,7 +446,7 @@ class CourseConnector { return tagNode; } - static Map _getSSOLoginPayload(Document ssoRedirectTagNode){ + static Map _getSSOLoginPayload(Document ssoRedirectTagNode) { Map data = {}; List nodes = ssoRedirectTagNode.getElementsByTagName("input"); @@ -478,9 +463,7 @@ class CourseConnector { } static String _getSSOLoginJumpUrl(Document ssoRedirectTagNode) { - String? jumpUrl = ssoRedirectTagNode - .getElementsByTagName("form")[0] - .attributes["action"]; + String? jumpUrl = ssoRedirectTagNode.getElementsByTagName("form")[0].attributes["action"]; if (jumpUrl == null) { throw Exception("Cannot fetch jumpUrl."); @@ -490,9 +473,9 @@ class CourseConnector { } static Future _tryToSSOLoginOrThrowException(String jumpUrl, Map payload) async { - ConnectorParameter parameter = ConnectorParameter(jumpUrl); - parameter.data = payload; - await Connector.getDataByPostResponse(parameter); + ConnectorParameter parameter = ConnectorParameter(jumpUrl); + parameter.data = payload; + await Connector.getDataByPostResponse(parameter); } static Future> _getGraduationCreditMap(String href) async { diff --git a/lib/src/model/course/course_semester.dart b/lib/src/model/course/course_semester.dart index 25c644dd..92ad7c82 100644 --- a/lib/src/model/course/course_semester.dart +++ b/lib/src/model/course/course_semester.dart @@ -44,4 +44,4 @@ class SemesterJson { @override int get hashCode => Object.hashAll([semester.hashCode, year.hashCode]); -} \ No newline at end of file +} diff --git a/lib/src/model/course/course_semester.g.dart b/lib/src/model/course/course_semester.g.dart index c15c9f1e..0ce4adde 100644 --- a/lib/src/model/course/course_semester.g.dart +++ b/lib/src/model/course/course_semester.g.dart @@ -18,4 +18,4 @@ SemesterJson _$SemesterJsonFromJson(Map json) { Map _$SemesterJsonToJson(SemesterJson instance) => { 'year': instance.year, 'semester': instance.semester, - }; \ No newline at end of file + }; diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index fea8b647..8cb28b68 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -40,22 +40,21 @@ class Course { String syllabusLink; String note; - Course({ - required this.idString, - required this.name, - required this.stageString, - required this.creditString, - required this.periodCountString, - required this.category, - required this.teacherString, - required this.classNameString, - required this.periodSlots, - required this.classroomString, - required this.applyStatus, - required this.language, - required this.syllabusLink, - required this.note - }) { + Course( + {required this.idString, + required this.name, + required this.stageString, + required this.creditString, + required this.periodCountString, + required this.category, + required this.teacherString, + required this.classNameString, + required this.periodSlots, + required this.classroomString, + required this.applyStatus, + required this.language, + required this.syllabusLink, + required this.note}) { id = JsonInit.intInit(idString); name = JsonInit.stringInit(name).trim(); stage = JsonInit.doubleInit(stageString); @@ -65,7 +64,7 @@ class Course { teacherString = JsonInit.stringInit(teacherString).trim(); teachers = teacherString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); periodSlots = JsonInit.listInit(periodSlots); - coursePeriods = _convertPeriodSlotsToCoursePeriods(periodSlots); + coursePeriods = _convertPeriodSlotsToCoursePeriods(periodSlots); classroomString = JsonInit.stringInit(classroomString).trim(); classrooms = classroomString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); classNameString = JsonInit.stringInit(classNameString).trim(); @@ -78,28 +77,25 @@ class Course { bool isEmpty() => id == 0; - static List _convertPeriodSlotsToCoursePeriods(List periodSlots){ + static List _convertPeriodSlotsToCoursePeriods(List periodSlots) { List coursePeriods = []; - for(int weekday = 1; weekday <= 7; weekday++){ + for (int weekday = 1; weekday <= 7; weekday++) { String weekdaySlot = periodSlots[weekday % 7]; - if(_isNullOrEmpty(weekdaySlot)){ + if (_isNullOrEmpty(weekdaySlot)) { continue; } List periods = weekdaySlot.split(RegExp(r"\s")); - for(String period in periods) { - coursePeriods.add(CoursePeriod( - weekday: weekday, - period: period - )); + for (String period in periods) { + coursePeriods.add(CoursePeriod(weekday: weekday, period: period)); } } return coursePeriods; } - static bool _isNullOrEmpty(String? text){ + static bool _isNullOrEmpty(String? text) { return text == null || text.replaceAll(RegExp(r"\s"), "").isEmpty; } factory Course.fromJson(Map json) => _$CourseFromJson(json); Map toJson() => _$CourseToJson(this); -} \ No newline at end of file +} diff --git a/lib/src/model/coursetable/course.g.dart b/lib/src/model/coursetable/course.g.dart index 181ee043..d7afc123 100644 --- a/lib/src/model/coursetable/course.g.dart +++ b/lib/src/model/coursetable/course.g.dart @@ -15,9 +15,7 @@ Course _$CourseFromJson(Map json) => Course( category: json['category'] as String, teacherString: json['teacherString'] as String, classNameString: json['classNameString'] as String, - periodSlots: (json['periodSlots'] as List) - .map((e) => e as String) - .toList(), + periodSlots: (json['periodSlots'] as List).map((e) => e as String).toList(), classroomString: json['classroomString'] as String, applyStatus: json['applyStatus'] as String, language: json['language'] as String, @@ -28,16 +26,11 @@ Course _$CourseFromJson(Map json) => Course( ..stage = (json['stage'] as num).toDouble() ..credit = (json['credit'] as num).toDouble() ..periodCount = json['periodCount'] as int - ..teachers = - (json['teachers'] as List).map((e) => e as String).toList() - ..classNames = - (json['classNames'] as List).map((e) => e as String).toList() - ..coursePeriods = (json['coursePeriods'] as List) - .map((e) => CoursePeriod.fromJson(e as Map)) - .toList() - ..classrooms = (json['classrooms'] as List) - .map((e) => e as String) - .toList(); + ..teachers = (json['teachers'] as List).map((e) => e as String).toList() + ..classNames = (json['classNames'] as List).map((e) => e as String).toList() + ..coursePeriods = + (json['coursePeriods'] as List).map((e) => CoursePeriod.fromJson(e as Map)).toList() + ..classrooms = (json['classrooms'] as List).map((e) => e as String).toList(); Map _$CourseToJson(Course instance) => { 'idString': instance.idString, diff --git a/lib/src/model/coursetable/course_period.dart b/lib/src/model/coursetable/course_period.dart index a479ce60..89dd8d1f 100644 --- a/lib/src/model/coursetable/course_period.dart +++ b/lib/src/model/coursetable/course_period.dart @@ -7,7 +7,7 @@ class CoursePeriod { int weekday; String period; - CoursePeriod({required this.weekday, required this.period}){ + CoursePeriod({required this.weekday, required this.period}) { weekday = weekday; period = period; } @@ -15,4 +15,4 @@ class CoursePeriod { factory CoursePeriod.fromJson(Map json) => _$CoursePeriodFromJson(json); Map toJson() => _$CoursePeriodToJson(this); -} \ No newline at end of file +} diff --git a/lib/src/model/coursetable/course_period.g.dart b/lib/src/model/coursetable/course_period.g.dart index 207e6d02..b27a009a 100644 --- a/lib/src/model/coursetable/course_period.g.dart +++ b/lib/src/model/coursetable/course_period.g.dart @@ -11,8 +11,7 @@ CoursePeriod _$CoursePeriodFromJson(Map json) => CoursePeriod( period: json['period'] as String, ); -Map _$CoursePeriodToJson(CoursePeriod instance) => - { +Map _$CoursePeriodToJson(CoursePeriod instance) => { 'weekday': instance.weekday, 'period': instance.period, }; diff --git a/lib/src/model/coursetable/course_table.dart b/lib/src/model/coursetable/course_table.dart index 61e58fa8..ccfb5b96 100644 --- a/lib/src/model/coursetable/course_table.dart +++ b/lib/src/model/coursetable/course_table.dart @@ -12,12 +12,7 @@ class CourseTable { List courses; User user; - CourseTable({ - required this.year, - required this.semester, - required this.courses, - required this.user - }){ + CourseTable({required this.year, required this.semester, required this.courses, required this.user}) { year = year; semester = semester; courses = courses; @@ -26,4 +21,4 @@ class CourseTable { factory CourseTable.fromJson(Map json) => _$CourseTableFromJson(json); Map toJson() => _$CourseTableToJson(this); -} \ No newline at end of file +} diff --git a/lib/src/model/coursetable/course_table.g.dart b/lib/src/model/coursetable/course_table.g.dart index 26b8a1a2..865d58d5 100644 --- a/lib/src/model/coursetable/course_table.g.dart +++ b/lib/src/model/coursetable/course_table.g.dart @@ -9,14 +9,11 @@ part of 'course_table.dart'; CourseTable _$CourseTableFromJson(Map json) => CourseTable( year: json['year'] as int, semester: json['semester'] as int, - courses: (json['courses'] as List) - .map((e) => Course.fromJson(e as Map)) - .toList(), + courses: (json['courses'] as List).map((e) => Course.fromJson(e as Map)).toList(), user: User.fromJson(json['user'] as Map), ); -Map _$CourseTableToJson(CourseTable instance) => - { +Map _$CourseTableToJson(CourseTable instance) => { 'year': instance.year, 'semester': instance.semester, 'courses': instance.courses, diff --git a/lib/src/model/coursetable/user.dart b/lib/src/model/coursetable/user.dart index a2438088..6fc16e6d 100644 --- a/lib/src/model/coursetable/user.dart +++ b/lib/src/model/coursetable/user.dart @@ -8,13 +8,12 @@ class User { String name; String className; - User.origin() : id = "", name = "", className = ""; + User.origin() + : id = "", + name = "", + className = ""; - User({ - required this.id, - required this.name, - required this.className - }){ + User({required this.id, required this.name, required this.className}) { id = id; name = name; className = className; @@ -22,4 +21,4 @@ class User { factory User.fromJson(Map json) => _$UserFromJson(json); Map toJson() => _$UserToJson(this); -} \ No newline at end of file +} diff --git a/lib/src/model/json_init.dart b/lib/src/model/json_init.dart index 8e36b70f..924bc501 100644 --- a/lib/src/model/json_init.dart +++ b/lib/src/model/json_init.dart @@ -1,9 +1,9 @@ class JsonInit { - static int intInit(String value){ + static int intInit(String value) { return value.replaceAll(RegExp(r"\s"), "").isNotEmpty ? int.parse(value) : 0; } - static double doubleInit(String value){ + static double doubleInit(String value) { return value.replaceAll(RegExp(r"\s"), "").isNotEmpty ? double.parse(value) : 0.00; } @@ -11,7 +11,7 @@ class JsonInit { return value ?? ""; } - static List listInit(List value){ + static List listInit(List value) { return value ?? []; } } diff --git a/lib/src/store/local_storage.dart b/lib/src/store/local_storage.dart index ddb8cf73..cedbb698 100644 --- a/lib/src/store/local_storage.dart +++ b/lib/src/store/local_storage.dart @@ -133,7 +133,8 @@ class LocalStorage { void removeCourseTable(CourseTable courseTable) { _courseTableList.removeWhere( (value) => - value.semester == courseTable.semester && value.year == courseTable.year && + value.semester == courseTable.semester && + value.year == courseTable.year && value.user.id == courseTable.user.id, ); } @@ -146,7 +147,7 @@ class LocalStorage { List getCourseTableList() { _courseTableList.sort((a, b) { if (a.user.id == b.user.id) { - if(a.year == b.year) { + if (a.year == b.year) { return b.semester.compareTo(a.semester); } return a.year.compareTo(b.year); @@ -162,9 +163,7 @@ class LocalStorage { } return _courseTableList.firstWhereOrNull( - (courseTable) => courseTable.semester == semester && - courseTable.year == year && - courseTable.user.id == studentId, + (courseTable) => courseTable.semester == semester && courseTable.year == year && courseTable.user.id == studentId, ); } diff --git a/lib/src/task/course/course_table_task.dart b/lib/src/task/course/course_table_task.dart index e2d58fb0..057678f8 100644 --- a/lib/src/task/course/course_table_task.dart +++ b/lib/src/task/course/course_table_task.dart @@ -22,29 +22,24 @@ class CourseTableTask extends CourseSystemTask { Future execute() async { final status = await super.execute(); if (status == TaskStatus.success) { - super.onStart(R.current.getCourse); - List courses; - User userInfo = await CourseConnector.getUserInfo(studentId, year, semester); - // TODO: Handle Teacher Situation. - if (LanguageUtil.getLangIndex() == LangEnum.zh) { - courses = await CourseConnector.getChineseCourses(studentId, year, semester); - } else { - courses = await CourseConnector.getEnglishCourses(studentId, year, semester); - } - super.onEnd(); - final courseTable = CourseTable( - year: year, - semester: semester, - courses: courses, - user: userInfo - ); - LocalStorage.instance.addCourseTable(courseTable); - await LocalStorage.instance.saveCourseTableList(); - - result = courseTable; - return TaskStatus.success; + super.onStart(R.current.getCourse); + List courses; + User userInfo = await CourseConnector.getUserInfo(studentId, year, semester); + // TODO: Handle Teacher Situation. + if (LanguageUtil.getLangIndex() == LangEnum.zh) { + courses = await CourseConnector.getChineseCourses(studentId, year, semester); } else { - return super.onError(R.current.getCourseError); + courses = await CourseConnector.getEnglishCourses(studentId, year, semester); } + super.onEnd(); + final courseTable = CourseTable(year: year, semester: semester, courses: courses, user: userInfo); + LocalStorage.instance.addCourseTable(courseTable); + await LocalStorage.instance.saveCourseTableList(); + + result = courseTable; + return TaskStatus.success; + } else { + return super.onError(R.current.getCourseError); + } } } diff --git a/lib/ui/pages/coursedetail/course_detail_page.dart b/lib/ui/pages/coursedetail/course_detail_page.dart index e243bcb8..b70896c5 100644 --- a/lib/ui/pages/coursedetail/course_detail_page.dart +++ b/lib/ui/pages/coursedetail/course_detail_page.dart @@ -36,10 +36,10 @@ class _ISchoolPageState extends State with SingleTickerProviderStat tabPageList = TabPageList(); tabPageList.add(TabPage(R.current.course, Icons.info, CourseInfoPage(widget.studentId, widget.course))); if (widget.studentId == LocalStorage.instance.getAccount()) { - tabPageList.add(TabPage( - R.current.announcement, Icons.announcement, IPlusAnnouncementPage(widget.studentId, widget.course))); tabPageList.add( - TabPage(R.current.fileAndVideo, Icons.file_download, IPlusFilePage(widget.studentId, widget.course))); + TabPage(R.current.announcement, Icons.announcement, IPlusAnnouncementPage(widget.studentId, widget.course))); + tabPageList + .add(TabPage(R.current.fileAndVideo, Icons.file_download, IPlusFilePage(widget.studentId, widget.course))); } _tabController = TabController(vsync: this, length: tabPageList.length); diff --git a/lib/ui/pages/coursedetail/screen/course_info_page.dart b/lib/ui/pages/coursedetail/screen/course_info_page.dart index cb5bc7eb..acd00807 100644 --- a/lib/ui/pages/coursedetail/screen/course_info_page.dart +++ b/lib/ui/pages/coursedetail/screen/course_info_page.dart @@ -131,226 +131,124 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive Widget _buildCourseApplyCard(Course course) { return SizedBox( - height: MediaQuery - .of(context) - .size - .width * 0.35, - child: Row( - children: [ - Expanded( - flex: 5, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.blueAccent - ), - padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), - child: Column( - children: [ - Container( - padding: const EdgeInsets.all(2), - child: const Text( - "修課人數", - style: TextStyle(fontSize: 14) - ) - ), - Expanded( - child: Center( - child: Text( - "150", - style: const TextStyle(fontSize: 36) - ) - ) - ) - ] - ) - ) - ), - Container(padding: const EdgeInsets.all(10)), - Expanded( - flex: 5, - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.grey - ), - padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), - child: Column( - children: [ - Container( - padding: const EdgeInsets.all(2), - child: const Text( - "撤選人數", - style: TextStyle(fontSize: 14) - ) - ), - Expanded( - child: Center( - child: Text( - "5", - style: const TextStyle(fontSize: 36) - ) - ) - ) - ] - ) - ) - ) - ] - ) - ); + height: MediaQuery.of(context).size.width * 0.35, + child: Row(children: [ + Expanded( + flex: 5, + child: Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.blueAccent), + padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(2), child: const Text("修課人數", style: TextStyle(fontSize: 14))), + Expanded(child: Center(child: Text("150", style: const TextStyle(fontSize: 36)))) + ]))), + Container(padding: const EdgeInsets.all(10)), + Expanded( + flex: 5, + child: Container( + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.grey), + padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(2), child: const Text("撤選人數", style: TextStyle(fontSize: 14))), + Expanded(child: Center(child: Text("5", style: const TextStyle(fontSize: 36)))) + ]))) + ])); } Widget _buildCourseCard(Course course) { return SizedBox( - height: MediaQuery - .of(context) - .size - .width * 0.65, - child: Row( - children: [ - Expanded( - flex: 8, - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.yellow[900] + height: MediaQuery.of(context).size.width * 0.65, + child: Row(children: [ + Expanded( + flex: 8, + child: Container( + padding: const EdgeInsets.all(10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.yellow[900]), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FractionallySizedBox( + child: Container( + padding: const EdgeInsets.all(10), + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text(course.id.toString(), style: const TextStyle(fontSize: 16))), ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FractionallySizedBox( - child: Container( - padding: const EdgeInsets.all(10), - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.id.toString(), - style: const TextStyle(fontSize: 16) - ) - ), - ), - FractionallySizedBox( + FractionallySizedBox( + child: Container( + padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), + alignment: const Align(alignment: Alignment.centerLeft).alignment, child: Container( - padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), - alignment: const Align(alignment: Alignment.centerLeft).alignment, - child: Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text(course.name, style: const TextStyle(fontSize: 18)), - ) - ), - ), - FractionallySizedBox( - child: Container( - padding: const EdgeInsets.all(10), - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Column( - children: [ - Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.classNames.join(" "), - style: const TextStyle(fontSize: 14), - ) - ), - Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.teachers.join(" "), - style: const TextStyle(fontSize: 14), - ) - ), - Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.classrooms.join(" "), - style: const TextStyle(fontSize: 14), - ) - ) - ], - ) - ) - ) - ], - ) - ) - ), - Container(padding: const EdgeInsets.all(10)), - Expanded( - flex: 3, - child: Column( - children: [ - Expanded( - flex: 5, + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text(course.name, style: const TextStyle(fontSize: 18)), + )), + ), + FractionallySizedBox( child: Container( - alignment: const Align(alignment: Alignment.topCenter).alignment, padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.deepOrange - ), + alignment: const Align(alignment: Alignment.topLeft).alignment, child: Column( - children: [ - Container( - padding: const EdgeInsets.all(10), - child: const Text( - "類別", - style: TextStyle(fontSize: 14) - ) - ), - Container( - padding: const EdgeInsets.all(10), - child: Center( - child: Text( - course.category == "選" ? "選修" : "必修", - style: const TextStyle(fontSize: 18) - ) - ) - ) - ] - ) - ) - ), - Container( - padding: const EdgeInsets.all(10) - ), - Expanded( - flex: 5, - child: Container( - padding: const EdgeInsets.all(10), - alignment: const Align(alignment: Alignment.topCenter).alignment, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.deepOrangeAccent - ), - child: Column( - children: [ + children: [ Container( - padding: const EdgeInsets.all(10), - child: const Text( - "學分數", - style: TextStyle(fontSize: 14) - ) - ), + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.classNames.join(" "), + style: const TextStyle(fontSize: 14), + )), Container( - padding: const EdgeInsets.all(10), - child: Center( - child: Text( - course.credit.toString(), - style: const TextStyle(fontSize: 18) - ) - ) - ) - ] - ) - ), - ) - ] - ), + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.teachers.join(" "), + style: const TextStyle(fontSize: 14), + )), + Container( + alignment: const Align(alignment: Alignment.topLeft).alignment, + child: Text( + course.classrooms.join(" "), + style: const TextStyle(fontSize: 14), + )) + ], + ))) + ], + ))), + Container(padding: const EdgeInsets.all(10)), + Expanded( + flex: 3, + child: Column(children: [ + Expanded( + flex: 5, + child: Container( + alignment: const Align(alignment: Alignment.topCenter).alignment, + padding: const EdgeInsets.all(10), + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.deepOrange), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), child: const Text("類別", style: TextStyle(fontSize: 14))), + Container( + padding: const EdgeInsets.all(10), + child: Center( + child: + Text(course.category == "選" ? "選修" : "必修", style: const TextStyle(fontSize: 18)))) + ]))), + Container(padding: const EdgeInsets.all(10)), + Expanded( + flex: 5, + child: Container( + padding: const EdgeInsets.all(10), + alignment: const Align(alignment: Alignment.topCenter).alignment, + decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.deepOrangeAccent), + child: Column(children: [ + Container( + padding: const EdgeInsets.all(10), child: const Text("學分數", style: TextStyle(fontSize: 14))), + Container( + padding: const EdgeInsets.all(10), + child: Center(child: Text(course.credit.toString(), style: const TextStyle(fontSize: 18)))) + ])), ) - ] - ) - ); + ]), + ) + ])); } Widget _buildCourseInfo(String text) { @@ -423,7 +321,7 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive ); } - Widget _buildMultiButtonInfo(String title, String buttonText, List textList, List urlList) { + Widget _buildMultiButtonInfo(String title, String buttonText, List textList, List urlList) { const textStyle = TextStyle(fontSize: 18); final classroomItemList = []; diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index e7018c62..d9ed8dd0 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -52,14 +52,21 @@ class CourseTableControl { void set(CourseTable value) { courseTable = value; - isHideSaturday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 6)); - isHideSunday = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 0)); + isHideSaturday = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 6)); + isHideSunday = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 0)); isHideUnKnown = !courseTable.courses.any((course) => course.coursePeriods.isEmpty); - isHideN = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "N")); - isHideA = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "A")); - isHideB = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "B")); - isHideC = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "C")); - isHideD = !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "D")); + isHideN = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "N")); + isHideA = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "A")); + isHideB = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "B")); + isHideC = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "C")); + isHideD = + !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "D")); isHideA &= (isHideB & isHideC & isHideD); isHideB &= (isHideC & isHideD); isHideC &= isHideD; @@ -78,14 +85,13 @@ class CourseTableControl { } Course getCourse(int weekday, int period) { - if(weekday == 7){ + if (weekday == 7) { return getUnknownCourse(period); } - return courseTable.courses.firstWhere((course) => - course.coursePeriods.any((coursePeriod) => - coursePeriod.period == getSectionString(period) && coursePeriod.weekday == weekday - ), orElse: () => null - ); + return courseTable.courses.firstWhere( + (course) => course.coursePeriods + .any((coursePeriod) => coursePeriod.period == getSectionString(period) && coursePeriod.weekday == weekday), + orElse: () => null); } Color getCourseInfoColor(int weekday, int period) { @@ -94,7 +100,7 @@ class CourseTableControl { return Colors.white; } - if (course == null){ + if (course == null) { return Colors.white; } @@ -122,7 +128,7 @@ class CourseTableControl { List get getCoursePeriodList { List list = []; - for(Course course in courseTable.courses){ + for (Course course in courseTable.courses) { list.addAll(course.coursePeriods.map((coursePeriod) => coursePeriod).toList()); } return list.toSet().toList(); @@ -153,9 +159,9 @@ class CourseTableControl { return sectionStringList[section]; } - Course getUnknownCourse(int period){ + Course getUnknownCourse(int period) { int index = period; - if(index >= courseTable.courses.where((course) => course.coursePeriods.isEmpty).length){ + if (index >= courseTable.courses.where((course) => course.coursePeriods.isEmpty).length) { return null; } return courseTable.courses.where((course) => course.coursePeriods.isEmpty).toList()[index]; diff --git a/lib/ui/pages/coursetable/course_table_page.dart b/lib/ui/pages/coursetable/course_table_page.dart index 52b7e954..c6dceb85 100644 --- a/lib/ui/pages/coursetable/course_table_page.dart +++ b/lib/ui/pages/coursetable/course_table_page.dart @@ -108,10 +108,8 @@ class _CourseTablePageState extends State { child: Text(value[index]), onPressed: () { String courseName = value[index]; - Course courseInfo = courseTableData.courses.firstWhere((course) => - course.name == courseName, - orElse: () => null - ); + Course courseInfo = + courseTableData.courses.firstWhere((course) => course.name == courseName, orElse: () => null); if (courseInfo != null) { _showCourseDetail(courseInfo); } else { @@ -184,7 +182,7 @@ class _CourseTablePageState extends State { LocalStorage.instance.clearSemesterJsonList(); //需重設因為更換了studentId } - if(year == 0 && semester == 0){ + if (year == 0 && semester == 0) { await _getSemesterList(studentId); SemesterJson semesterJson = LocalStorage.instance.getSemesterJsonItem(0); year = int.parse(semesterJson.year); @@ -246,7 +244,8 @@ class _CourseTablePageState extends State { child: ListView.builder( itemCount: semesterList?.length ?? 0, shrinkWrap: true, - itemBuilder: (context, index) => _getSemesterItem(int.parse(semesterList[index].year), int.parse(semesterList[index].semester)), + itemBuilder: (context, index) => + _getSemesterItem(int.parse(semesterList[index].year), int.parse(semesterList[index].semester)), ), ), ), @@ -257,7 +256,10 @@ class _CourseTablePageState extends State { _onPopupMenuSelect(int value) { switch (value) { case 0: - final credit = courseTableData?.courses?.map((course) => course.credit)?.toList()?.reduce((value, element) => value + element); + final credit = courseTableData?.courses + ?.map((course) => course.credit) + ?.toList() + ?.reduce((value, element) => value + element); if (credit != null) { MyToast.show(sprintf("%s:%s", [R.current.credit, credit])); } @@ -321,12 +323,8 @@ class _CourseTablePageState extends State { child: SizedBox( height: 50, child: TextButton( - child: Text(sprintf("%s %s %d-%d", [ - value[index].user.id, - value[index].user.name, - value[index].year, - value[index].semester - ])), + child: Text(sprintf("%s %s %d-%d", + [value[index].user.id, value[index].user.name, value[index].year, value[index].semester])), onPressed: () { LocalStorage.instance.getCourseSetting().info = value[index]; //儲存課表 LocalStorage.instance.saveCourseSetting(); @@ -574,44 +572,44 @@ class _CourseTablePageState extends State { child: (course == null) ? const SizedBox.shrink() : Card( - elevation: 0, - margin: const EdgeInsets.all(2), - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(5)), - color: courseInfoColor, - ), - child: Material( - color: Colors.transparent, - child: InkWell( - borderRadius: const BorderRadius.all(Radius.circular(5)), - highlightColor: isDarkMode ? Colors.white : Colors.black12, - onTap: () => showCourseDetailDialog(courseTableControl.getTimeString(section), course), - child: Stack( - children: [ - Align( - alignment: Alignment.center, - child: Padding( - padding: const EdgeInsets.all(2), - child: AutoSizeText( - course.name, - style: const TextStyle( - color: Colors.black, - fontSize: 14, - overflow: TextOverflow.ellipsis, + elevation: 0, + margin: const EdgeInsets.all(2), + child: Container( + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(5)), + color: courseInfoColor, + ), + child: Material( + color: Colors.transparent, + child: InkWell( + borderRadius: const BorderRadius.all(Radius.circular(5)), + highlightColor: isDarkMode ? Colors.white : Colors.black12, + onTap: () => showCourseDetailDialog(courseTableControl.getTimeString(section), course), + child: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Padding( + padding: const EdgeInsets.all(2), + child: AutoSizeText( + course.name, + style: const TextStyle( + color: Colors.black, + fontSize: 14, + overflow: TextOverflow.ellipsis, + ), + minFontSize: 6, + maxLines: 3, + textAlign: TextAlign.center, + ), + ), ), - minFontSize: 6, - maxLines: 3, - textAlign: TextAlign.center, - ), + ], ), ), - ], + ), ), ), - ), - ), - ), ), ); } @@ -743,7 +741,8 @@ class _CourseTablePageState extends State { setState(() { isLoading = false; }); - favorite = (LocalStorage.instance.getCourseTable(courseTable.user.id, courseTable.year, courseTable.semester) != null); + favorite = + (LocalStorage.instance.getCourseTable(courseTable.user.id, courseTable.year, courseTable.semester) != null); if (favorite) { LocalStorage.instance.addCourseTable(courseTableData); } From a1471a1b53d9ca91211f4f77ecc3734e91e7995b Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 9 Feb 2024 18:39:26 +0800 Subject: [PATCH 09/31] Chore: fix the issues from analyzer --- lib/src/connector/course_connector.dart | 4 +- lib/src/model/course/course_semester.dart | 1 - lib/src/model/json_init.dart | 4 +- lib/src/store/local_storage.dart | 1 - .../task/course/course_credit_info_task.dart | 2 +- .../task/course/course_department_task.dart | 2 +- lib/src/task/course/course_division_task.dart | 2 +- lib/src/task/course/course_semester_task.dart | 2 +- .../coursedetail/course_detail_page.dart | 3 +- .../coursedetail/screen/course_info_page.dart | 122 ------------------ 10 files changed, 10 insertions(+), 133 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index cf1c63c1..eb58e01e 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -1,3 +1,5 @@ +// ignore_for_file: import_of_legacy_library_into_null_safe + import 'package:dio/dio.dart'; import 'package:flutter_app/debug/log/log.dart'; import 'package:flutter_app/src/connector/core/connector.dart'; @@ -339,7 +341,7 @@ class CourseConnector { if (href == null || href.isEmpty) { throw Exception("getDepartmentList: href is null or empty."); } - Map code = Uri.parse(href!).queryParameters; + Map code = Uri.parse(href).queryParameters; String name = node.text.replaceAll(RegExp("[ |s]"), ""); resultList.add({"name": name, "code": code}); } diff --git a/lib/src/model/course/course_semester.dart b/lib/src/model/course/course_semester.dart index 92ad7c82..df29eafc 100644 --- a/lib/src/model/course/course_semester.dart +++ b/lib/src/model/course/course_semester.dart @@ -1,7 +1,6 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 import 'package:flutter_app/src/model/json_init.dart'; -import 'package:flutter_app/src/util/language_util.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:sprintf/sprintf.dart'; diff --git a/lib/src/model/json_init.dart b/lib/src/model/json_init.dart index 924bc501..459d6cd2 100644 --- a/lib/src/model/json_init.dart +++ b/lib/src/model/json_init.dart @@ -7,11 +7,11 @@ class JsonInit { return value.replaceAll(RegExp(r"\s"), "").isNotEmpty ? double.parse(value) : 0.00; } - static String stringInit(String value) { + static String stringInit(String? value) { return value ?? ""; } - static List listInit(List value) { + static List listInit(List? value) { return value ?? []; } } diff --git a/lib/src/store/local_storage.dart b/lib/src/store/local_storage.dart index cedbb698..1f078dbc 100644 --- a/lib/src/store/local_storage.dart +++ b/lib/src/store/local_storage.dart @@ -15,7 +15,6 @@ import 'package:tat_core/core/zuvio/domain/login_credential.dart'; import 'package:tat_core/core/zuvio/domain/user_info.dart'; import '../model/course/course_semester.dart'; -import "../model/coursetable/course.dart"; import '../model/coursetable/course_table.dart'; class LocalStorage { diff --git a/lib/src/task/course/course_credit_info_task.dart b/lib/src/task/course/course_credit_info_task.dart index 4132a68b..b93ccc12 100644 --- a/lib/src/task/course/course_credit_info_task.dart +++ b/lib/src/task/course/course_credit_info_task.dart @@ -18,7 +18,7 @@ class CourseCreditInfoTask extends CourseSystemTask { final status = await super.execute(); if (status == TaskStatus.success) { super.onStart(R.current.searchingCreditInfo); - final value = await CourseConnector.getCreditInfo(code, creditName) as GraduationInformationJson?; + final value = await CourseConnector.getCreditInfo(code, creditName); super.onEnd(); if (value != null) { diff --git a/lib/src/task/course/course_department_task.dart b/lib/src/task/course/course_department_task.dart index d9b03cc4..21d5fd43 100644 --- a/lib/src/task/course/course_department_task.dart +++ b/lib/src/task/course/course_department_task.dart @@ -16,7 +16,7 @@ class CourseDepartmentTask extends CourseSystemTask> { final status = await super.execute(); if (status == TaskStatus.success) { super.onStart(R.current.searchingDepartment); - final value = await CourseConnector.getDepartmentList(code) as List>?; + final value = await CourseConnector.getDepartmentList(code); super.onEnd(); if (value != null) { diff --git a/lib/src/task/course/course_division_task.dart b/lib/src/task/course/course_division_task.dart index d7926ea2..7edf67b5 100644 --- a/lib/src/task/course/course_division_task.dart +++ b/lib/src/task/course/course_division_task.dart @@ -16,7 +16,7 @@ class CourseDivisionTask extends CourseSystemTask> { final status = await super.execute(); if (status == TaskStatus.success) { super.onStart(R.current.searchingDivision); - final value = await CourseConnector.getDivisionList(year) as List>?; + final value = await CourseConnector.getDivisionList(year); super.onEnd(); if (value != null) { diff --git a/lib/src/task/course/course_semester_task.dart b/lib/src/task/course/course_semester_task.dart index 59977eae..e41ca007 100644 --- a/lib/src/task/course/course_semester_task.dart +++ b/lib/src/task/course/course_semester_task.dart @@ -25,7 +25,7 @@ class CourseSemesterTask extends CourseSystemTask> { value = await _selectSemesterDialog(); } else { super.onStart(R.current.getCourseSemester); - value = await CourseConnector.getCourseSemester(id) as List?; + value = await CourseConnector.getCourseSemester(id); super.onEnd(); } diff --git a/lib/ui/pages/coursedetail/course_detail_page.dart b/lib/ui/pages/coursedetail/course_detail_page.dart index b70896c5..400a146c 100644 --- a/lib/ui/pages/coursedetail/course_detail_page.dart +++ b/lib/ui/pages/coursedetail/course_detail_page.dart @@ -1,7 +1,6 @@ // TODO: remove sdk version selector after migrating to null-safety. // @dart=2.10 import 'package:flutter/material.dart'; -import 'package:flutter_app/src/model/course/course_semester.dart'; import 'package:flutter_app/src/providers/app_provider.dart'; import 'package:flutter_app/src/r.dart'; import 'package:flutter_app/src/store/local_storage.dart'; @@ -34,7 +33,7 @@ class _ISchoolPageState extends State with SingleTickerProviderStat void initState() { super.initState(); tabPageList = TabPageList(); - tabPageList.add(TabPage(R.current.course, Icons.info, CourseInfoPage(widget.studentId, widget.course))); + tabPageList.add(TabPage(R.current.course, Icons.info, CourseInfoPage(widget.studentId, widget.course, key: null,))); if (widget.studentId == LocalStorage.instance.getAccount()) { tabPageList.add( TabPage(R.current.announcement, Icons.announcement, IPlusAnnouncementPage(widget.studentId, widget.course))); diff --git a/lib/ui/pages/coursedetail/screen/course_info_page.dart b/lib/ui/pages/coursedetail/screen/course_info_page.dart index acd00807..6a74f998 100644 --- a/lib/ui/pages/coursedetail/screen/course_info_page.dart +++ b/lib/ui/pages/coursedetail/screen/course_info_page.dart @@ -129,128 +129,6 @@ class _CourseInfoPageState extends State with AutomaticKeepAlive ); } - Widget _buildCourseApplyCard(Course course) { - return SizedBox( - height: MediaQuery.of(context).size.width * 0.35, - child: Row(children: [ - Expanded( - flex: 5, - child: Container( - decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.blueAccent), - padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), - child: Column(children: [ - Container( - padding: const EdgeInsets.all(2), child: const Text("修課人數", style: TextStyle(fontSize: 14))), - Expanded(child: Center(child: Text("150", style: const TextStyle(fontSize: 36)))) - ]))), - Container(padding: const EdgeInsets.all(10)), - Expanded( - flex: 5, - child: Container( - decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.grey), - padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), - child: Column(children: [ - Container( - padding: const EdgeInsets.all(2), child: const Text("撤選人數", style: TextStyle(fontSize: 14))), - Expanded(child: Center(child: Text("5", style: const TextStyle(fontSize: 36)))) - ]))) - ])); - } - - Widget _buildCourseCard(Course course) { - return SizedBox( - height: MediaQuery.of(context).size.width * 0.65, - child: Row(children: [ - Expanded( - flex: 8, - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.yellow[900]), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - FractionallySizedBox( - child: Container( - padding: const EdgeInsets.all(10), - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text(course.id.toString(), style: const TextStyle(fontSize: 16))), - ), - FractionallySizedBox( - child: Container( - padding: const EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 20), - alignment: const Align(alignment: Alignment.centerLeft).alignment, - child: Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text(course.name, style: const TextStyle(fontSize: 18)), - )), - ), - FractionallySizedBox( - child: Container( - padding: const EdgeInsets.all(10), - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Column( - children: [ - Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.classNames.join(" "), - style: const TextStyle(fontSize: 14), - )), - Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.teachers.join(" "), - style: const TextStyle(fontSize: 14), - )), - Container( - alignment: const Align(alignment: Alignment.topLeft).alignment, - child: Text( - course.classrooms.join(" "), - style: const TextStyle(fontSize: 14), - )) - ], - ))) - ], - ))), - Container(padding: const EdgeInsets.all(10)), - Expanded( - flex: 3, - child: Column(children: [ - Expanded( - flex: 5, - child: Container( - alignment: const Align(alignment: Alignment.topCenter).alignment, - padding: const EdgeInsets.all(10), - decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.deepOrange), - child: Column(children: [ - Container( - padding: const EdgeInsets.all(10), child: const Text("類別", style: TextStyle(fontSize: 14))), - Container( - padding: const EdgeInsets.all(10), - child: Center( - child: - Text(course.category == "選" ? "選修" : "必修", style: const TextStyle(fontSize: 18)))) - ]))), - Container(padding: const EdgeInsets.all(10)), - Expanded( - flex: 5, - child: Container( - padding: const EdgeInsets.all(10), - alignment: const Align(alignment: Alignment.topCenter).alignment, - decoration: BoxDecoration(borderRadius: BorderRadius.circular(10), color: Colors.deepOrangeAccent), - child: Column(children: [ - Container( - padding: const EdgeInsets.all(10), child: const Text("學分數", style: TextStyle(fontSize: 14))), - Container( - padding: const EdgeInsets.all(10), - child: Center(child: Text(course.credit.toString(), style: const TextStyle(fontSize: 18)))) - ])), - ) - ]), - ) - ])); - } - Widget _buildCourseInfo(String text) { TextStyle textStyle = const TextStyle(fontSize: 18); return Container( From c0d8d0a309bb6ac5c6152def31c3fd6aafda68ce Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Fri, 9 Feb 2024 18:47:26 +0800 Subject: [PATCH 10/31] Chore: format --- lib/ui/pages/coursedetail/course_detail_page.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/ui/pages/coursedetail/course_detail_page.dart b/lib/ui/pages/coursedetail/course_detail_page.dart index 400a146c..f187dfd1 100644 --- a/lib/ui/pages/coursedetail/course_detail_page.dart +++ b/lib/ui/pages/coursedetail/course_detail_page.dart @@ -33,7 +33,14 @@ class _ISchoolPageState extends State with SingleTickerProviderStat void initState() { super.initState(); tabPageList = TabPageList(); - tabPageList.add(TabPage(R.current.course, Icons.info, CourseInfoPage(widget.studentId, widget.course, key: null,))); + tabPageList.add(TabPage( + R.current.course, + Icons.info, + CourseInfoPage( + widget.studentId, + widget.course, + key: null, + ))); if (widget.studentId == LocalStorage.instance.getAccount()) { tabPageList.add( TabPage(R.current.announcement, Icons.announcement, IPlusAnnouncementPage(widget.studentId, widget.course))); From 4aa139031f4a13785ed568dc410c7479967338dd Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:28:12 +0800 Subject: [PATCH 11/31] Implement: Use EEquatableMixin to instead of operator overloading --- lib/src/model/course/course_semester.dart | 24 ++++++--------------- lib/src/model/course/course_semester.g.dart | 2 -- pubspec.lock | 2 +- pubspec.yaml | 1 + 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/lib/src/model/course/course_semester.dart b/lib/src/model/course/course_semester.dart index df29eafc..2b682d9e 100644 --- a/lib/src/model/course/course_semester.dart +++ b/lib/src/model/course/course_semester.dart @@ -1,5 +1,4 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 +import 'package:equatable/equatable.dart'; import 'package:flutter_app/src/model/json_init.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:sprintf/sprintf.dart'; @@ -7,11 +6,11 @@ import 'package:sprintf/sprintf.dart'; part 'course_semester.g.dart'; @JsonSerializable() -class SemesterJson { +class SemesterJson with EquatableMixin { String year; String semester; - SemesterJson({this.year, this.semester}) { + SemesterJson({required this.year, required this.semester}) { year = JsonInit.stringInit(year); semester = JsonInit.stringInit(semester); } @@ -30,17 +29,8 @@ class SemesterJson { } @override - bool operator ==(dynamic other) { - if (other is! SemesterJson) { - return false; - } - - final isSemesterSame = int.tryParse(other.semester) == int.tryParse(semester); - final isYearSame = int.tryParse(other.year) == int.tryParse(year); - - return isSemesterSame && isYearSame; - } - - @override - int get hashCode => Object.hashAll([semester.hashCode, year.hashCode]); + List get props => [ + year, + semester + ]; } diff --git a/lib/src/model/course/course_semester.g.dart b/lib/src/model/course/course_semester.g.dart index 0ce4adde..39b0ed83 100644 --- a/lib/src/model/course/course_semester.g.dart +++ b/lib/src/model/course/course_semester.g.dart @@ -1,5 +1,3 @@ -// TODO: remove sdk version selector after migrating to null-safety. -// @dart=2.10 // GENERATED CODE - DO NOT MODIFY BY HAND part of 'course_semester.dart'; diff --git a/pubspec.lock b/pubspec.lock index 934aa762..b3361db7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -426,7 +426,7 @@ packages: source: hosted version: "2.1.17" equatable: - dependency: transitive + dependency: "direct main" description: name: equatable sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 diff --git a/pubspec.yaml b/pubspec.yaml index 801df6c1..98b7efc1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -91,6 +91,7 @@ dependencies: uuid: ^4.1.0 intl_utils: ^2.8.5 flutter_native_splash: ^2.2.19 # restricted by path 1.8.2 + equatable: ^2.0.5 dependency_overrides: From 65d8bc82f4f92d472963f1ac38cc2218b30df232 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:31:03 +0800 Subject: [PATCH 12/31] Implement: use final when the value won't modify --- lib/src/connector/course_connector.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index eb58e01e..9b62647c 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -337,7 +337,7 @@ class CourseConnector { nodes = node.getElementsByTagName("a"); for (int i = 0; i < nodes.length; i++) { node = nodes[i]; - var href = node.attributes["href"]; + final href = node.attributes["href"]; if (href == null || href.isEmpty) { throw Exception("getDepartmentList: href is null or empty."); } From 4ae3cdea4db69c80285802dc9e5911bebf05a4bc Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:32:24 +0800 Subject: [PATCH 13/31] Implement: use final when the value won't modify --- lib/src/model/coursetable/course_period.g.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/src/model/coursetable/course_period.g.dart b/lib/src/model/coursetable/course_period.g.dart index b27a009a..207e6d02 100644 --- a/lib/src/model/coursetable/course_period.g.dart +++ b/lib/src/model/coursetable/course_period.g.dart @@ -11,7 +11,8 @@ CoursePeriod _$CoursePeriodFromJson(Map json) => CoursePeriod( period: json['period'] as String, ); -Map _$CoursePeriodToJson(CoursePeriod instance) => { +Map _$CoursePeriodToJson(CoursePeriod instance) => + { 'weekday': instance.weekday, 'period': instance.period, }; From 7ca37d3fc00bf965558318870be34150fd06fb63 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:33:38 +0800 Subject: [PATCH 14/31] Implement: use final when the value won't modify --- lib/src/connector/course_connector.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index 9b62647c..da16b157 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -52,7 +52,7 @@ class CourseConnector { List courses = []; for (int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++) { - var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); + final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); courses.add(Course( idString: courseRowData[0].text, name: courseRowData[1].text, @@ -124,9 +124,9 @@ class CourseConnector { List courses = []; for (int rowIndex = 2; rowIndex < courseRows.length - 1; rowIndex++) { - var courseRowData = courseRows[rowIndex].getElementsByTagName("td"); - var syllabusNode = courseRowData[18].getElementsByTagName("a"); - var syllabusLinkHref = syllabusNode.isEmpty ? null : syllabusNode.first.attributes["href"]; + final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); + final syllabusNode = courseRowData[18].getElementsByTagName("a"); + final syllabusLinkHref = syllabusNode.isEmpty ? null : syllabusNode.first.attributes["href"]; courses.add(Course( idString: courseRowData[0].text, name: courseRowData[1].text, @@ -175,11 +175,11 @@ class CourseConnector { String result = await Connector.getDataByGet(parameter); Document tagNode = parse(result); - var tables = tagNode.getElementsByTagName("table"); - var trs = tables[0].getElementsByTagName("tr"); - var syllabusRow = trs[1].getElementsByTagName("td"); + final tables = tagNode.getElementsByTagName("table"); + final trs = tables[0].getElementsByTagName("tr"); + final syllabusRow = trs[1].getElementsByTagName("td"); - var model = CourseSyllabusJson( + final model = CourseSyllabusJson( yearSemester: syllabusRow[0].text, courseId: syllabusRow[1].text, courseName: syllabusRow[2].text, @@ -302,7 +302,7 @@ class CourseConnector { nodes = tagNode.getElementsByTagName("a"); for (int i = 0; i < nodes.length; i++) { node = nodes[i]; - var href = node.attributes["href"]; + final href = node.attributes["href"]; if (href == null || href.isEmpty) { throw Exception("getDivisionList: href is null or empty."); } From 24d296a0c29c686fd363ca0b5098da7e202ef579 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:35:31 +0800 Subject: [PATCH 15/31] Implement: use final when the value won't modify --- lib/src/store/local_storage.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/store/local_storage.dart b/lib/src/store/local_storage.dart index 1f078dbc..bd60bccb 100644 --- a/lib/src/store/local_storage.dart +++ b/lib/src/store/local_storage.dart @@ -120,7 +120,7 @@ class LocalStorage { String getCourseNameByCourseId(int courseId) { for (final courseTable in _courseTableList) { - var course = courseTable.courses.firstWhere((course) => course.id == courseId, orElse: () => null); + final course = courseTable.courses.firstWhere((course) => course.id == courseId, orElse: () => null); if (course != null) { return course.name; } From 530cea05507e0be7982942b63b28120f71dd223c Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:33:38 +0800 Subject: [PATCH 16/31] Chore: Change required key to nullable key --- lib/ui/pages/coursedetail/screen/course_info_page.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ui/pages/coursedetail/screen/course_info_page.dart b/lib/ui/pages/coursedetail/screen/course_info_page.dart index 6a74f998..c17d923e 100644 --- a/lib/ui/pages/coursedetail/screen/course_info_page.dart +++ b/lib/ui/pages/coursedetail/screen/course_info_page.dart @@ -14,7 +14,7 @@ class CourseInfoPage extends StatefulWidget { final Course course; final String studentId; - const CourseInfoPage(this.studentId, this.course, {required Key key}) : super(key: key); + const CourseInfoPage(this.studentId, this.course, {Key? key}) : super(key: key); final int courseInfoWithAlpha = 0x44; From 1eea804f7aefa4dfb2e59c36ebc704bab40ed432 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:43:09 +0800 Subject: [PATCH 17/31] Chore: Simply the unique process with Set data structure --- lib/ui/pages/coursetable/course_table_control.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index d9ed8dd0..b49b97ed 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -127,11 +127,11 @@ class CourseTableControl { } List get getCoursePeriodList { - List list = []; + final Set list = {}; for (Course course in courseTable.courses) { list.addAll(course.coursePeriods.map((coursePeriod) => coursePeriod).toList()); } - return list.toSet().toList(); + return list.toList(); } List get getSectionIntList { From 29e7c9ba1715981797d7f9d756b30c73d76d0b3f Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:44:44 +0800 Subject: [PATCH 18/31] Chore: Simply the unique process with addAll function --- lib/ui/pages/coursetable/course_table_control.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index b49b97ed..26f6301d 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -127,11 +127,11 @@ class CourseTableControl { } List get getCoursePeriodList { - final Set list = {}; + final Set coursePeriodSet = {}; for (Course course in courseTable.courses) { - list.addAll(course.coursePeriods.map((coursePeriod) => coursePeriod).toList()); + coursePeriodSet.addAll(course.coursePeriods); } - return list.toList(); + return coursePeriodSet.toList(); } List get getSectionIntList { From df623de6969ab13148220f550ce1d5aafbe4024b Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:47:51 +0800 Subject: [PATCH 19/31] Chore: Simply getUnknownCourse when reuse complex method chains --- lib/ui/pages/coursetable/course_table_control.dart | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index 26f6301d..cc02333c 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -160,10 +160,7 @@ class CourseTableControl { } Course getUnknownCourse(int period) { - int index = period; - if (index >= courseTable.courses.where((course) => course.coursePeriods.isEmpty).length) { - return null; - } - return courseTable.courses.where((course) => course.coursePeriods.isEmpty).toList()[index]; + final nonPeriodCourses = courseTable.courses.where((course) => course.coursePeriods.isEmpty); + return period >= nonPeriodCourses.length ? null : nonPeriodCourses.elementAt(period); } } From b4b19a33f1e9bff451f913fcd014cfa04748ef2a Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 16:51:14 +0800 Subject: [PATCH 20/31] Chore: Add comma after the final things in a series of long parameters --- lib/src/model/coursetable/course.dart | 37 +++++++++++++++------------ 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index 8cb28b68..ac85a241 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -40,21 +40,21 @@ class Course { String syllabusLink; String note; - Course( - {required this.idString, - required this.name, - required this.stageString, - required this.creditString, - required this.periodCountString, - required this.category, - required this.teacherString, - required this.classNameString, - required this.periodSlots, - required this.classroomString, - required this.applyStatus, - required this.language, - required this.syllabusLink, - required this.note}) { + Course({required this.idString, + required this.name, + required this.stageString, + required this.creditString, + required this.periodCountString, + required this.category, + required this.teacherString, + required this.classNameString, + required this.periodSlots, + required this.classroomString, + required this.applyStatus, + required this.language, + required this.syllabusLink, + required this.note, + }) { id = JsonInit.intInit(idString); name = JsonInit.stringInit(name).trim(); stage = JsonInit.doubleInit(stageString); @@ -93,9 +93,12 @@ class Course { } static bool _isNullOrEmpty(String? text) { - return text == null || text.replaceAll(RegExp(r"\s"), "").isEmpty; + return text == null || text + .replaceAll(RegExp(r"\s"), "") + .isEmpty; } factory Course.fromJson(Map json) => _$CourseFromJson(json); + Map toJson() => _$CourseToJson(this); -} +} \ No newline at end of file From 4dc5e4602419e8db5981bd7e38d18111c980697f Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 17:20:10 +0800 Subject: [PATCH 21/31] Chore: Optimize huge function chain when Pre-build member --- lib/src/model/coursetable/course_table.dart | 10 +++++++++ .../coursetable/course_table_control.dart | 22 ++++++------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/src/model/coursetable/course_table.dart b/lib/src/model/coursetable/course_table.dart index ccfb5b96..7ebf3195 100644 --- a/lib/src/model/coursetable/course_table.dart +++ b/lib/src/model/coursetable/course_table.dart @@ -11,14 +11,24 @@ class CourseTable { int semester; List courses; User user; + late final Set weekdays = {}; + late final Set periods = {}; CourseTable({required this.year, required this.semester, required this.courses, required this.user}) { year = year; semester = semester; courses = courses; user = user; + weekdays.addAll(courses.map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.weekday)) + .expand((element) => element)); + periods.addAll(courses.map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.period)) + .expand((element) => element)); } + bool isPeriodInCourseTable(String period) => periods.contains(period); + + bool isWeekdayInCourseTable(int weekday) => weekdays.contains(weekday); + factory CourseTable.fromJson(Map json) => _$CourseTableFromJson(json); Map toJson() => _$CourseTableToJson(this); } diff --git a/lib/ui/pages/coursetable/course_table_control.dart b/lib/ui/pages/coursetable/course_table_control.dart index cc02333c..53347384 100644 --- a/lib/ui/pages/coursetable/course_table_control.dart +++ b/lib/ui/pages/coursetable/course_table_control.dart @@ -52,21 +52,13 @@ class CourseTableControl { void set(CourseTable value) { courseTable = value; - isHideSaturday = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 6)); - isHideSunday = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.weekday == 0)); - isHideUnKnown = !courseTable.courses.any((course) => course.coursePeriods.isEmpty); - isHideN = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "N")); - isHideA = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "A")); - isHideB = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "B")); - isHideC = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "C")); - isHideD = - !courseTable.courses.any((course) => course.coursePeriods.any((coursePeriod) => coursePeriod.period == "D")); + isHideSaturday = !courseTable.isWeekdayInCourseTable(6); + isHideSunday = !courseTable.isWeekdayInCourseTable(0); + isHideN = !courseTable.isPeriodInCourseTable("N"); + isHideA = !courseTable.isPeriodInCourseTable("A"); + isHideB = !courseTable.isPeriodInCourseTable("B"); + isHideC = !courseTable.isPeriodInCourseTable("C"); + isHideD = !courseTable.isPeriodInCourseTable("D"); isHideA &= (isHideB & isHideC & isHideD); isHideB &= (isHideC & isHideD); isHideC &= isHideD; From 54e8d4428728b93acd8c94309ae4de9411de5532 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 17:21:43 +0800 Subject: [PATCH 22/31] Chore: Run format --- lib/src/model/course/course_semester.dart | 5 +---- lib/src/model/coursetable/course.dart | 13 ++++++------- lib/src/model/coursetable/course_period.g.dart | 3 +-- lib/src/model/coursetable/course_table.dart | 6 ++++-- 4 files changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/src/model/course/course_semester.dart b/lib/src/model/course/course_semester.dart index 2b682d9e..708d634d 100644 --- a/lib/src/model/course/course_semester.dart +++ b/lib/src/model/course/course_semester.dart @@ -29,8 +29,5 @@ class SemesterJson with EquatableMixin { } @override - List get props => [ - year, - semester - ]; + List get props => [year, semester]; } diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index ac85a241..28e2883f 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -40,7 +40,8 @@ class Course { String syllabusLink; String note; - Course({required this.idString, + Course({ + required this.idString, required this.name, required this.stageString, required this.creditString, @@ -77,7 +78,7 @@ class Course { bool isEmpty() => id == 0; - static List _convertPeriodSlotsToCoursePeriods(List periodSlots) { + List _convertPeriodSlotsToCoursePeriods(List periodSlots) { List coursePeriods = []; for (int weekday = 1; weekday <= 7; weekday++) { String weekdaySlot = periodSlots[weekday % 7]; @@ -92,13 +93,11 @@ class Course { return coursePeriods; } - static bool _isNullOrEmpty(String? text) { - return text == null || text - .replaceAll(RegExp(r"\s"), "") - .isEmpty; + bool _isNullOrEmpty(String? text) { + return text == null || text.replaceAll(RegExp(r"\s"), "").isEmpty; } factory Course.fromJson(Map json) => _$CourseFromJson(json); Map toJson() => _$CourseToJson(this); -} \ No newline at end of file +} diff --git a/lib/src/model/coursetable/course_period.g.dart b/lib/src/model/coursetable/course_period.g.dart index 207e6d02..b27a009a 100644 --- a/lib/src/model/coursetable/course_period.g.dart +++ b/lib/src/model/coursetable/course_period.g.dart @@ -11,8 +11,7 @@ CoursePeriod _$CoursePeriodFromJson(Map json) => CoursePeriod( period: json['period'] as String, ); -Map _$CoursePeriodToJson(CoursePeriod instance) => - { +Map _$CoursePeriodToJson(CoursePeriod instance) => { 'weekday': instance.weekday, 'period': instance.period, }; diff --git a/lib/src/model/coursetable/course_table.dart b/lib/src/model/coursetable/course_table.dart index 7ebf3195..54168867 100644 --- a/lib/src/model/coursetable/course_table.dart +++ b/lib/src/model/coursetable/course_table.dart @@ -19,9 +19,11 @@ class CourseTable { semester = semester; courses = courses; user = user; - weekdays.addAll(courses.map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.weekday)) + weekdays.addAll(courses + .map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.weekday)) .expand((element) => element)); - periods.addAll(courses.map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.period)) + periods.addAll(courses + .map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.period)) .expand((element) => element)); } From dfcf8494dcaad452cbba02f9ae0ed1ca60c5a6b9 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 17:36:36 +0800 Subject: [PATCH 23/31] Chore: Optimize the implementation by add a value-mapping constructor --- lib/src/connector/course_connector.dart | 4 +- lib/src/model/course/course_semester.g.dart | 13 ++--- lib/src/model/coursetable/course.dart | 55 +++++++++---------- lib/src/model/coursetable/course.g.dart | 42 ++++++-------- lib/src/model/coursetable/course_table.g.dart | 7 ++- 5 files changed, 54 insertions(+), 67 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index da16b157..f5543ae8 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -53,7 +53,7 @@ class CourseConnector { for (int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++) { final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); - courses.add(Course( + courses.add(Course.parseNodeString( idString: courseRowData[0].text, name: courseRowData[1].text, stageString: "", @@ -127,7 +127,7 @@ class CourseConnector { final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); final syllabusNode = courseRowData[18].getElementsByTagName("a"); final syllabusLinkHref = syllabusNode.isEmpty ? null : syllabusNode.first.attributes["href"]; - courses.add(Course( + courses.add(Course.parseNodeString( idString: courseRowData[0].text, name: courseRowData[1].text, stageString: courseRowData[2].text, diff --git a/lib/src/model/course/course_semester.g.dart b/lib/src/model/course/course_semester.g.dart index 39b0ed83..b6e51b73 100644 --- a/lib/src/model/course/course_semester.g.dart +++ b/lib/src/model/course/course_semester.g.dart @@ -6,14 +6,13 @@ part of 'course_semester.dart'; // JsonSerializableGenerator // ************************************************************************** -SemesterJson _$SemesterJsonFromJson(Map json) { - return SemesterJson( - year: json['year'] as String, - semester: json['semester'] as String, - ); -} +SemesterJson _$SemesterJsonFromJson(Map json) => SemesterJson( + year: json['year'] as String, + semester: json['semester'] as String, + ); -Map _$SemesterJsonToJson(SemesterJson instance) => { +Map _$SemesterJsonToJson(SemesterJson instance) => + { 'year': instance.year, 'semester': instance.semester, }; diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index 28e2883f..3df2a450 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -7,50 +7,49 @@ part 'course.g.dart'; @JsonSerializable() class Course { - String idString; late int id; - String name; - - String stageString; late double stage; - - String creditString; late double credit; - - String periodCountString; late int periodCount; - String category; - - String teacherString; late List teachers; - - String classNameString; late List classNames; - - List periodSlots; late List coursePeriods; - - String classroomString; late List classrooms; - String applyStatus; String language; String syllabusLink; String note; Course({ - required this.idString, + required this.id, + required this.name, + required this.stage, + required this.credit, + required this.periodCount, + required this.category, + required this.teachers, + required this.classNames, + required this.coursePeriods, + required this.classrooms, + required this.applyStatus, + required this.language, + required this.syllabusLink, + required this.note + }); + + Course.parseNodeString({ + required String idString, required this.name, - required this.stageString, - required this.creditString, - required this.periodCountString, + required String stageString, + required String creditString, + required String periodCountString, required this.category, - required this.teacherString, - required this.classNameString, - required this.periodSlots, - required this.classroomString, + required String teacherString, + required String classNameString, + required List periodSlots, + required String classroomString, required this.applyStatus, required this.language, required this.syllabusLink, @@ -62,13 +61,9 @@ class Course { credit = JsonInit.doubleInit(creditString); periodCount = JsonInit.intInit(periodCountString); category = JsonInit.stringInit(category).trim(); - teacherString = JsonInit.stringInit(teacherString).trim(); teachers = teacherString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); - periodSlots = JsonInit.listInit(periodSlots); coursePeriods = _convertPeriodSlotsToCoursePeriods(periodSlots); - classroomString = JsonInit.stringInit(classroomString).trim(); classrooms = classroomString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); - classNameString = JsonInit.stringInit(classNameString).trim(); classNames = classNameString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); applyStatus = JsonInit.stringInit(applyStatus).trim(); language = JsonInit.stringInit(language).trim(); diff --git a/lib/src/model/coursetable/course.g.dart b/lib/src/model/coursetable/course.g.dart index d7afc123..1b5a6748 100644 --- a/lib/src/model/coursetable/course.g.dart +++ b/lib/src/model/coursetable/course.g.dart @@ -7,49 +7,39 @@ part of 'course.dart'; // ************************************************************************** Course _$CourseFromJson(Map json) => Course( - idString: json['idString'] as String, + id: json['id'] as int, name: json['name'] as String, - stageString: json['stageString'] as String, - creditString: json['creditString'] as String, - periodCountString: json['periodCountString'] as String, + stage: (json['stage'] as num).toDouble(), + credit: (json['credit'] as num).toDouble(), + periodCount: json['periodCount'] as int, category: json['category'] as String, - teacherString: json['teacherString'] as String, - classNameString: json['classNameString'] as String, - periodSlots: (json['periodSlots'] as List).map((e) => e as String).toList(), - classroomString: json['classroomString'] as String, + teachers: + (json['teachers'] as List).map((e) => e as String).toList(), + classNames: (json['classNames'] as List) + .map((e) => e as String) + .toList(), + coursePeriods: (json['coursePeriods'] as List) + .map((e) => CoursePeriod.fromJson(e as Map)) + .toList(), + classrooms: (json['classrooms'] as List) + .map((e) => e as String) + .toList(), applyStatus: json['applyStatus'] as String, language: json['language'] as String, syllabusLink: json['syllabusLink'] as String, note: json['note'] as String, - ) - ..id = json['id'] as int - ..stage = (json['stage'] as num).toDouble() - ..credit = (json['credit'] as num).toDouble() - ..periodCount = json['periodCount'] as int - ..teachers = (json['teachers'] as List).map((e) => e as String).toList() - ..classNames = (json['classNames'] as List).map((e) => e as String).toList() - ..coursePeriods = - (json['coursePeriods'] as List).map((e) => CoursePeriod.fromJson(e as Map)).toList() - ..classrooms = (json['classrooms'] as List).map((e) => e as String).toList(); + ); Map _$CourseToJson(Course instance) => { - 'idString': instance.idString, 'id': instance.id, 'name': instance.name, - 'stageString': instance.stageString, 'stage': instance.stage, - 'creditString': instance.creditString, 'credit': instance.credit, - 'periodCountString': instance.periodCountString, 'periodCount': instance.periodCount, 'category': instance.category, - 'teacherString': instance.teacherString, 'teachers': instance.teachers, - 'classNameString': instance.classNameString, 'classNames': instance.classNames, - 'periodSlots': instance.periodSlots, 'coursePeriods': instance.coursePeriods, - 'classroomString': instance.classroomString, 'classrooms': instance.classrooms, 'applyStatus': instance.applyStatus, 'language': instance.language, diff --git a/lib/src/model/coursetable/course_table.g.dart b/lib/src/model/coursetable/course_table.g.dart index 865d58d5..26b8a1a2 100644 --- a/lib/src/model/coursetable/course_table.g.dart +++ b/lib/src/model/coursetable/course_table.g.dart @@ -9,11 +9,14 @@ part of 'course_table.dart'; CourseTable _$CourseTableFromJson(Map json) => CourseTable( year: json['year'] as int, semester: json['semester'] as int, - courses: (json['courses'] as List).map((e) => Course.fromJson(e as Map)).toList(), + courses: (json['courses'] as List) + .map((e) => Course.fromJson(e as Map)) + .toList(), user: User.fromJson(json['user'] as Map), ); -Map _$CourseTableToJson(CourseTable instance) => { +Map _$CourseTableToJson(CourseTable instance) => + { 'year': instance.year, 'semester': instance.semester, 'courses': instance.courses, From 8ee64bb09b40c812130e261f7cc7619b5f90f51b Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 17:37:02 +0800 Subject: [PATCH 24/31] Chore: Run format --- lib/src/model/course/course_semester.g.dart | 3 +- lib/src/model/coursetable/course.dart | 31 +++++++++---------- lib/src/model/coursetable/course.g.dart | 11 ++----- lib/src/model/coursetable/course_table.g.dart | 7 ++--- 4 files changed, 21 insertions(+), 31 deletions(-) diff --git a/lib/src/model/course/course_semester.g.dart b/lib/src/model/course/course_semester.g.dart index b6e51b73..b09ab650 100644 --- a/lib/src/model/course/course_semester.g.dart +++ b/lib/src/model/course/course_semester.g.dart @@ -11,8 +11,7 @@ SemesterJson _$SemesterJsonFromJson(Map json) => SemesterJson( semester: json['semester'] as String, ); -Map _$SemesterJsonToJson(SemesterJson instance) => - { +Map _$SemesterJsonToJson(SemesterJson instance) => { 'year': instance.year, 'semester': instance.semester, }; diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index 3df2a450..1d88c242 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -22,22 +22,21 @@ class Course { String syllabusLink; String note; - Course({ - required this.id, - required this.name, - required this.stage, - required this.credit, - required this.periodCount, - required this.category, - required this.teachers, - required this.classNames, - required this.coursePeriods, - required this.classrooms, - required this.applyStatus, - required this.language, - required this.syllabusLink, - required this.note - }); + Course( + {required this.id, + required this.name, + required this.stage, + required this.credit, + required this.periodCount, + required this.category, + required this.teachers, + required this.classNames, + required this.coursePeriods, + required this.classrooms, + required this.applyStatus, + required this.language, + required this.syllabusLink, + required this.note}); Course.parseNodeString({ required String idString, diff --git a/lib/src/model/coursetable/course.g.dart b/lib/src/model/coursetable/course.g.dart index 1b5a6748..b97e54e2 100644 --- a/lib/src/model/coursetable/course.g.dart +++ b/lib/src/model/coursetable/course.g.dart @@ -13,17 +13,12 @@ Course _$CourseFromJson(Map json) => Course( credit: (json['credit'] as num).toDouble(), periodCount: json['periodCount'] as int, category: json['category'] as String, - teachers: - (json['teachers'] as List).map((e) => e as String).toList(), - classNames: (json['classNames'] as List) - .map((e) => e as String) - .toList(), + teachers: (json['teachers'] as List).map((e) => e as String).toList(), + classNames: (json['classNames'] as List).map((e) => e as String).toList(), coursePeriods: (json['coursePeriods'] as List) .map((e) => CoursePeriod.fromJson(e as Map)) .toList(), - classrooms: (json['classrooms'] as List) - .map((e) => e as String) - .toList(), + classrooms: (json['classrooms'] as List).map((e) => e as String).toList(), applyStatus: json['applyStatus'] as String, language: json['language'] as String, syllabusLink: json['syllabusLink'] as String, diff --git a/lib/src/model/coursetable/course_table.g.dart b/lib/src/model/coursetable/course_table.g.dart index 26b8a1a2..865d58d5 100644 --- a/lib/src/model/coursetable/course_table.g.dart +++ b/lib/src/model/coursetable/course_table.g.dart @@ -9,14 +9,11 @@ part of 'course_table.dart'; CourseTable _$CourseTableFromJson(Map json) => CourseTable( year: json['year'] as int, semester: json['semester'] as int, - courses: (json['courses'] as List) - .map((e) => Course.fromJson(e as Map)) - .toList(), + courses: (json['courses'] as List).map((e) => Course.fromJson(e as Map)).toList(), user: User.fromJson(json['user'] as Map), ); -Map _$CourseTableToJson(CourseTable instance) => - { +Map _$CourseTableToJson(CourseTable instance) => { 'year': instance.year, 'semester': instance.semester, 'courses': instance.courses, From f9909682c33537469d90ba5b7ab1c2483b00bad0 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Mon, 12 Feb 2024 17:46:01 +0800 Subject: [PATCH 25/31] Chore: Add origin constructor & passed analyze & format it --- lib/src/connector/score_connector.dart | 4 ++-- lib/src/model/course/course_score_json.dart | 2 +- lib/src/model/course/course_semester.dart | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/src/connector/score_connector.dart b/lib/src/connector/score_connector.dart index ba8e6505..9c6f338a 100644 --- a/lib/src/connector/score_connector.dart +++ b/lib/src/connector/score_connector.dart @@ -97,7 +97,7 @@ class ScoreConnector { SemesterCourseScoreJson courseScore = SemesterCourseScoreJson(); - SemesterJson semester = SemesterJson(); + SemesterJson semester = SemesterJson.origin(); semester.year = h3Node.text.split(" ")[0]; semester.semester = h3Node.text.split(" ")[3]; courseScore.semester = semester; @@ -152,7 +152,7 @@ class ScoreConnector { .where((row) => row.getElementsByTagName("td").length >= 7) .toList(growable: false); for (int i = 0; i < (rankNodes.length / 3).floor(); i++) { - SemesterJson semester = SemesterJson(); + SemesterJson semester = SemesterJson.origin(); String semesterString = rankNodes[i * 3 + 2].getElementsByTagName("td")[0].innerHtml.split("
").first; semester.year = semesterString.split(" ")[0]; semester.semester = semesterString.split(" ").reversed.toList()[0]; diff --git a/lib/src/model/course/course_score_json.dart b/lib/src/model/course/course_score_json.dart index 368460d8..ec8081d5 100644 --- a/lib/src/model/course/course_score_json.dart +++ b/lib/src/model/course/course_score_json.dart @@ -248,7 +248,7 @@ class SemesterCourseScoreJson { now = now ?? RankJson(); history = history ?? RankJson(); courseScoreList = courseScoreList ?? []; - semester = semester ?? SemesterJson(); + semester = semester ?? SemesterJson.origin(); averageScore = averageScore ?? 0; performanceScore = performanceScore ?? 0; totalCredit = totalCredit ?? 0; diff --git a/lib/src/model/course/course_semester.dart b/lib/src/model/course/course_semester.dart index 708d634d..df33d2ff 100644 --- a/lib/src/model/course/course_semester.dart +++ b/lib/src/model/course/course_semester.dart @@ -10,6 +10,10 @@ class SemesterJson with EquatableMixin { String year; String semester; + SemesterJson.origin() + : year = "0", + semester = "0"; + SemesterJson({required this.year, required this.semester}) { year = JsonInit.stringInit(year); semester = JsonInit.stringInit(semester); From fb295cdedfc6a591a9a366c70d4ea23b182a82b5 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Tue, 13 Feb 2024 00:39:42 +0800 Subject: [PATCH 26/31] Chore: Add final --- lib/src/connector/course_connector.dart | 68 ++++++++++++------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index f5543ae8..d2e0d3c8 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -36,8 +36,8 @@ class CourseConnector { } static Future> getEnglishCourses(String studentId, int year, int semester) async { - ConnectorParameter parameter = ConnectorParameter(_postCourseENUrl); - Map data = { + final ConnectorParameter parameter = ConnectorParameter(_postCourseENUrl); + final Map data = { "code": studentId, "format": "-2", "year": year.toString(), @@ -45,11 +45,11 @@ class CourseConnector { }; parameter.charsetName = 'utf-8'; parameter.data = data; - String result = await Connector.getDataByGet(parameter); + final String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); - List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); - List courses = []; + final Document tagNode = parse(result); + final List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); + final List courses = []; for (int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++) { final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); @@ -75,8 +75,8 @@ class CourseConnector { static Future getUserInfo(String studentId, int year, int semester) async { try { - ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); - Map data = { + final ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + final Map data = { "code": studentId, "format": "-2", "year": year.toString(), @@ -84,14 +84,14 @@ class CourseConnector { }; parameter.charsetName = 'utf-8'; parameter.data = data; - String result = await Connector.getDataByGet(parameter); + final String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); - String courseTableHead = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr").first.text; - List matches = RegExp(r".+?:(.+?)\s").allMatches(courseTableHead).toList(); + final Document tagNode = parse(result); + final String courseTableHead = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr").first.text; + final List matches = RegExp(r".+?:(.+?)\s").allMatches(courseTableHead).toList(); - String? name = matches[1].group(1); - String? className = matches[2].group(1); + final String? name = matches[1].group(1); + final String? className = matches[2].group(1); if (name == null) { throw Exception("getUserInfo: Cannot Fetch the user info (null name)."); @@ -109,8 +109,8 @@ class CourseConnector { } static Future> getChineseCourses(String studentId, int year, int semester) async { - ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); - Map data = { + final ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + final Map data = { "code": studentId, "format": "-2", "year": year.toString(), @@ -118,10 +118,10 @@ class CourseConnector { }; parameter.charsetName = 'utf-8'; parameter.data = data; - String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); - List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); - List courses = []; + final String result = await Connector.getDataByGet(parameter); + final Document tagNode = parse(result); + final List courseRows = tagNode.getElementsByTagName("table")[1].getElementsByTagName("tr"); + final List courses = []; for (int rowIndex = 2; rowIndex < courseRows.length - 1; rowIndex++) { final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); @@ -434,27 +434,27 @@ class CourseConnector { } static Future _getSSORedirectNodesInLoginPhase() async { - ConnectorParameter parameter = ConnectorParameter(_ssoLoginUrl); - Map data = { + final ConnectorParameter parameter = ConnectorParameter(_ssoLoginUrl); + final Map data = { "apUrl": "https://aps.ntut.edu.tw/course/tw/courseSID.jsp", "apOu": "aa_0010-", "sso": "true", "datetime1": DateTime.now().millisecondsSinceEpoch.toString() }; parameter.data = data; - String result = await Connector.getDataByGet(parameter); + final String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); + final Document tagNode = parse(result); return tagNode; } static Map _getSSOLoginPayload(Document ssoRedirectTagNode) { - Map data = {}; - List nodes = ssoRedirectTagNode.getElementsByTagName("input"); + final Map data = {}; + final List nodes = ssoRedirectTagNode.getElementsByTagName("input"); for (Element node in nodes) { - String? name = node.attributes['name']; - String? value = node.attributes['value']; + final String? name = node.attributes['name']; + final String? value = node.attributes['value']; if (name == null || value == null) { throw Exception("Cannot fetch name or value."); } @@ -475,15 +475,15 @@ class CourseConnector { } static Future _tryToSSOLoginOrThrowException(String jumpUrl, Map payload) async { - ConnectorParameter parameter = ConnectorParameter(jumpUrl); + final ConnectorParameter parameter = ConnectorParameter(jumpUrl); parameter.data = payload; await Connector.getDataByPostResponse(parameter); } static Future> _getGraduationCreditMap(String href) async { - ConnectorParameter parameter = ConnectorParameter(href); - String result = await Connector.getDataByGet(parameter); - Map graduationMap = {}; + final ConnectorParameter parameter = ConnectorParameter(href); + final String result = await Connector.getDataByGet(parameter); + final Map graduationMap = {}; graduationMap["lowCredit"] = _getGraduationCredit(result, RegExp(r"最低畢業學分:?(\d+)學分")); graduationMap["△"] = _getGraduationCredit(result, RegExp(r"共同必修:?(\d+)學分")); @@ -494,12 +494,12 @@ class CourseConnector { } static int _getGraduationCredit(String content, RegExp exp) { - RegExpMatch? matches = exp.firstMatch(content); + final RegExpMatch? matches = exp.firstMatch(content); if (matches == null) { return 0; } - String? creditText = matches.group(1); + final String? creditText = matches.group(1); if (creditText == null) { return 0; } From 03b73c2d279cae0fa3b39de5594f713bcea66f73 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Tue, 13 Feb 2024 00:49:14 +0800 Subject: [PATCH 27/31] Chore: Add final & adding trailing commas --- lib/src/connector/course_connector.dart | 126 +++++++++++------------- 1 file changed, 58 insertions(+), 68 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index d2e0d3c8..6ad7a6ef 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -141,7 +141,7 @@ class CourseConnector { applyStatus: courseRowData[16].text, language: courseRowData[17].text, syllabusLink: syllabusLinkHref == null ? "" : _postCourseCNUrl + syllabusLinkHref, - note: courseRowData[19].text)); + note: courseRowData[19].text,),); } return courses; @@ -149,16 +149,16 @@ class CourseConnector { static Future getCourseENName(String url) async { try { - ConnectorParameter parameter; - Document tagNode; - Element node; - parameter = ConnectorParameter(url); + final ConnectorParameter parameter = ConnectorParameter(url); parameter.charsetName = 'big5'; - String result = await Connector.getDataByGet(parameter); - tagNode = parse(result); - node = tagNode.getElementsByTagName("table").first; - node = node.getElementsByTagName("tr")[1]; - return node.getElementsByTagName("td")[2].text.replaceAll(RegExp(r"\n"), ""); + final String result = await Connector.getDataByGet(parameter); + + final Document tagNode = parse(result); + final Element node = tagNode.getElementsByTagName("table").first + .getElementsByTagName("tr")[1] + .getElementsByTagName("td")[2]; + + return node.text.replaceAll(RegExp(r"\n"), ""); } catch (e, stack) { Log.eWithStack(e.toString(), stack); return null; @@ -191,7 +191,7 @@ class CourseConnector { className: syllabusRow[8].text, applyStudentCount: syllabusRow[9].text, withdrawStudentCount: syllabusRow[10].text, - note: syllabusRow[11].text); + note: syllabusRow[11].text,); return model; } catch (e, stack) { @@ -202,23 +202,22 @@ class CourseConnector { static Future?> getCourseSemester(String studentId) async { try { - ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); + final ConnectorParameter parameter = ConnectorParameter(_postCourseCNUrl); parameter.data = { "code": studentId, "format": "-3", }; - Response response = await Connector.getDataByPostResponse(parameter); - Document tagNode = parse(response.toString()); + final Response response = await Connector.getDataByPostResponse(parameter); + final Document tagNode = parse(response.toString()); - Element node = tagNode.getElementsByTagName("table")[0]; - List nodes = node.getElementsByTagName("tr"); + final Element node = tagNode.getElementsByTagName("table")[0]; + final List nodes = node.getElementsByTagName("tr"); - List semesterJsonList = []; + final List semesterJsonList = []; for (int i = 1; i < nodes.length; i++) { - node = nodes[i]; - String year, semester; - year = node.getElementsByTagName("a")[0].text.split(" ")[0]; - semester = node.getElementsByTagName("a")[0].text.split(" ")[2]; + final Element semesterNode = nodes[i]; + final String year = semesterNode.getElementsByTagName("a")[0].text.split(" ")[0]; + final String semester = semesterNode.getElementsByTagName("a")[0].text.split(" ")[2]; semesterJsonList.add(SemesterJson(year: year, semester: semester)); } return semesterJsonList; @@ -229,7 +228,7 @@ class CourseConnector { } static String strQ2B(String input) { - List newString = []; + final List newString = []; for (int c in input.codeUnits) { if (c == 12288) { c = 32; @@ -244,35 +243,30 @@ class CourseConnector { } static Future getGraduation(String year, String department) async { - ConnectorParameter parameter = ConnectorParameter("https://aps.ntut.edu.tw/course/tw/Cprog.jsp"); + final ConnectorParameter parameter = ConnectorParameter("https://aps.ntut.edu.tw/course/tw/Cprog.jsp"); parameter.data = {"format": "-3", "year": year, "matric": "7"}; - String result = await Connector.getDataByGet(parameter); - Document tagNode = parse(result); + final String result = await Connector.getDataByGet(parameter); + final Document tagNode = parse(result); - Element node = tagNode.getElementsByTagName("tbody").first; - List nodes = node.getElementsByTagName("tr"); - String redirectHypertextRef = + final Element node = tagNode.getElementsByTagName("tbody").first; + final List nodes = node.getElementsByTagName("tr"); + final String redirectHypertextRef = nodes.firstWhere((node) => node.text.contains(department)).getElementsByTagName("a").first.attributes["href"]!; - Map graduationMap = await _getGraduationCreditMap(redirectHypertextRef); + final Map graduationMap = await _getGraduationCreditMap(redirectHypertextRef); return graduationMap; } static Future?> getYearList() async { - ConnectorParameter parameter; - String result; - Document tagNode; - Element node; - List nodes; - List resultList = []; try { - parameter = ConnectorParameter("https://aps.ntut.edu.tw/course/tw/Cprog.jsp"); + final ConnectorParameter parameter = ConnectorParameter("https://aps.ntut.edu.tw/course/tw/Cprog.jsp"); parameter.data = {"format": "-1"}; - result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - nodes = tagNode.getElementsByTagName("a"); + final String result = await Connector.getDataByPost(parameter); + final Document tagNode = parse(result); + final List nodes = tagNode.getElementsByTagName("a"); + final List resultList = []; for (int i = 0; i < nodes.length; i++) { - node = nodes[i]; + final Element node = nodes[i]; resultList.add(node.text); } return resultList; @@ -288,25 +282,23 @@ class CourseConnector { code 參數 */ static Future?> getDivisionList(String year) async { - ConnectorParameter parameter; - String result; - Document tagNode; - Element node; - List nodes; - List resultList = []; try { - parameter = ConnectorParameter(_creditUrl); + final ConnectorParameter parameter = ConnectorParameter(_creditUrl); parameter.data = {"format": "-2", "year": year}; - result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - nodes = tagNode.getElementsByTagName("a"); + final String result = await Connector.getDataByPost(parameter); + final Document tagNode = parse(result); + final List nodes = tagNode.getElementsByTagName("a"); + final List resultList = []; + for (int i = 0; i < nodes.length; i++) { - node = nodes[i]; + final Element node = nodes[i]; final href = node.attributes["href"]; if (href == null || href.isEmpty) { throw Exception("getDivisionList: href is null or empty."); } - Map code = Uri.parse(href).queryParameters; + final Map code = Uri + .parse(href) + .queryParameters; resultList.add({"name": node.text, "code": code}); } return resultList; @@ -322,27 +314,25 @@ class CourseConnector { code 參數 */ static Future>?> getDepartmentList(Map code) async { - ConnectorParameter parameter; - String result; - Document tagNode; - Element node; - List nodes; - List resultList = []; try { - parameter = ConnectorParameter(_creditUrl); - parameter.data = code; - result = await Connector.getDataByPost(parameter); - tagNode = parse(result); - node = tagNode.getElementsByTagName("table").first; - nodes = node.getElementsByTagName("a"); + final ConnectorParameter parameter = ConnectorParameter(_creditUrl); + final String result = await Connector.getDataByPost(parameter); + final Document tagNode = parse(result); + final List resultList = []; + final List nodes = tagNode + .getElementsByTagName("table") + .first + .getElementsByTagName("a"); for (int i = 0; i < nodes.length; i++) { - node = nodes[i]; + final Element node = nodes[i]; final href = node.attributes["href"]; if (href == null || href.isEmpty) { throw Exception("getDepartmentList: href is null or empty."); } - Map code = Uri.parse(href).queryParameters; - String name = node.text.replaceAll(RegExp("[ |s]"), ""); + final Map code = Uri + .parse(href) + .queryParameters; + final String name = node.text.replaceAll(RegExp("[ |s]"), ""); resultList.add({"name": name, "code": code}); } return resultList; @@ -465,7 +455,7 @@ class CourseConnector { } static String _getSSOLoginJumpUrl(Document ssoRedirectTagNode) { - String? jumpUrl = ssoRedirectTagNode.getElementsByTagName("form")[0].attributes["action"]; + final String? jumpUrl = ssoRedirectTagNode.getElementsByTagName("form")[0].attributes["action"]; if (jumpUrl == null) { throw Exception("Cannot fetch jumpUrl."); From 5ece6bf6c75775cb71fcdd9a03019d77f949b494 Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Tue, 13 Feb 2024 00:49:45 +0800 Subject: [PATCH 28/31] Chore: Format --- lib/src/connector/course_connector.dart | 50 ++++++++++++------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index 6ad7a6ef..3fff63c0 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -127,7 +127,8 @@ class CourseConnector { final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); final syllabusNode = courseRowData[18].getElementsByTagName("a"); final syllabusLinkHref = syllabusNode.isEmpty ? null : syllabusNode.first.attributes["href"]; - courses.add(Course.parseNodeString( + courses.add( + Course.parseNodeString( idString: courseRowData[0].text, name: courseRowData[1].text, stageString: courseRowData[2].text, @@ -141,7 +142,9 @@ class CourseConnector { applyStatus: courseRowData[16].text, language: courseRowData[17].text, syllabusLink: syllabusLinkHref == null ? "" : _postCourseCNUrl + syllabusLinkHref, - note: courseRowData[19].text,),); + note: courseRowData[19].text, + ), + ); } return courses; @@ -154,9 +157,8 @@ class CourseConnector { final String result = await Connector.getDataByGet(parameter); final Document tagNode = parse(result); - final Element node = tagNode.getElementsByTagName("table").first - .getElementsByTagName("tr")[1] - .getElementsByTagName("td")[2]; + final Element node = + tagNode.getElementsByTagName("table").first.getElementsByTagName("tr")[1].getElementsByTagName("td")[2]; return node.text.replaceAll(RegExp(r"\n"), ""); } catch (e, stack) { @@ -180,18 +182,19 @@ class CourseConnector { final syllabusRow = trs[1].getElementsByTagName("td"); final model = CourseSyllabusJson( - yearSemester: syllabusRow[0].text, - courseId: syllabusRow[1].text, - courseName: syllabusRow[2].text, - phase: syllabusRow[3].text, - credit: syllabusRow[4].text, - hour: syllabusRow[5].text, - category: syllabusRow[6].text, - teachers: syllabusRow[7].text, - className: syllabusRow[8].text, - applyStudentCount: syllabusRow[9].text, - withdrawStudentCount: syllabusRow[10].text, - note: syllabusRow[11].text,); + yearSemester: syllabusRow[0].text, + courseId: syllabusRow[1].text, + courseName: syllabusRow[2].text, + phase: syllabusRow[3].text, + credit: syllabusRow[4].text, + hour: syllabusRow[5].text, + category: syllabusRow[6].text, + teachers: syllabusRow[7].text, + className: syllabusRow[8].text, + applyStudentCount: syllabusRow[9].text, + withdrawStudentCount: syllabusRow[10].text, + note: syllabusRow[11].text, + ); return model; } catch (e, stack) { @@ -296,9 +299,7 @@ class CourseConnector { if (href == null || href.isEmpty) { throw Exception("getDivisionList: href is null or empty."); } - final Map code = Uri - .parse(href) - .queryParameters; + final Map code = Uri.parse(href).queryParameters; resultList.add({"name": node.text, "code": code}); } return resultList; @@ -319,19 +320,14 @@ class CourseConnector { final String result = await Connector.getDataByPost(parameter); final Document tagNode = parse(result); final List resultList = []; - final List nodes = tagNode - .getElementsByTagName("table") - .first - .getElementsByTagName("a"); + final List nodes = tagNode.getElementsByTagName("table").first.getElementsByTagName("a"); for (int i = 0; i < nodes.length; i++) { final Element node = nodes[i]; final href = node.attributes["href"]; if (href == null || href.isEmpty) { throw Exception("getDepartmentList: href is null or empty."); } - final Map code = Uri - .parse(href) - .queryParameters; + final Map code = Uri.parse(href).queryParameters; final String name = node.text.replaceAll(RegExp("[ |s]"), ""); resultList.add({"name": name, "code": code}); } From 1b5da584f1a08192d4abd6d3fd93cc56b22d432e Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Tue, 13 Feb 2024 00:51:29 +0800 Subject: [PATCH 29/31] Chore: Adding trailing commas --- lib/src/connector/course_connector.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/connector/course_connector.dart b/lib/src/connector/course_connector.dart index 3fff63c0..e3d735d5 100644 --- a/lib/src/connector/course_connector.dart +++ b/lib/src/connector/course_connector.dart @@ -53,7 +53,8 @@ class CourseConnector { for (int rowIndex = 1; rowIndex < courseRows.length - 1; rowIndex++) { final courseRowData = courseRows[rowIndex].getElementsByTagName("td"); - courses.add(Course.parseNodeString( + courses.add( + Course.parseNodeString( idString: courseRowData[0].text, name: courseRowData[1].text, stageString: "", @@ -67,7 +68,9 @@ class CourseConnector { applyStatus: courseRowData[14].text, language: courseRowData[15].text, syllabusLink: "", - note: courseRowData[16].text)); + note: courseRowData[16].text, + ), + ); } return courses; From e3f75f42ffb83bbc80de1aaa31ef8def2ba7530c Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Tue, 13 Feb 2024 00:57:29 +0800 Subject: [PATCH 30/31] Chore: Add final in data transfer object --- lib/src/model/coursetable/course.dart | 34 ++++++++------------ lib/src/model/coursetable/course_period.dart | 9 ++---- lib/src/model/coursetable/course_table.dart | 12 +++---- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/lib/src/model/coursetable/course.dart b/lib/src/model/coursetable/course.dart index 1d88c242..848779c0 100644 --- a/lib/src/model/coursetable/course.dart +++ b/lib/src/model/coursetable/course.dart @@ -7,20 +7,20 @@ part 'course.g.dart'; @JsonSerializable() class Course { - late int id; - String name; - late double stage; - late double credit; - late int periodCount; - String category; - late List teachers; - late List classNames; - late List coursePeriods; - late List classrooms; - String applyStatus; - String language; - String syllabusLink; - String note; + late final int id; + final String name; + late final double stage; + late final double credit; + late final int periodCount; + final String category; + late final List teachers; + late final List classNames; + late final List coursePeriods; + late final List classrooms; + final String applyStatus; + final String language; + final String syllabusLink; + final String note; Course( {required this.id, @@ -55,19 +55,13 @@ class Course { required this.note, }) { id = JsonInit.intInit(idString); - name = JsonInit.stringInit(name).trim(); stage = JsonInit.doubleInit(stageString); credit = JsonInit.doubleInit(creditString); periodCount = JsonInit.intInit(periodCountString); - category = JsonInit.stringInit(category).trim(); teachers = teacherString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); coursePeriods = _convertPeriodSlotsToCoursePeriods(periodSlots); classrooms = classroomString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); classNames = classNameString.split(RegExp(r"\n")).map((element) => element.trim()).toList(); - applyStatus = JsonInit.stringInit(applyStatus).trim(); - language = JsonInit.stringInit(language).trim(); - syllabusLink = JsonInit.stringInit(syllabusLink).trim(); - note = JsonInit.stringInit(note).trim(); } bool isEmpty() => id == 0; diff --git a/lib/src/model/coursetable/course_period.dart b/lib/src/model/coursetable/course_period.dart index 89dd8d1f..198fd374 100644 --- a/lib/src/model/coursetable/course_period.dart +++ b/lib/src/model/coursetable/course_period.dart @@ -4,13 +4,10 @@ part 'course_period.g.dart'; @JsonSerializable() class CoursePeriod { - int weekday; - String period; + final int weekday; + final String period; - CoursePeriod({required this.weekday, required this.period}) { - weekday = weekday; - period = period; - } + CoursePeriod({required this.weekday, required this.period}); factory CoursePeriod.fromJson(Map json) => _$CoursePeriodFromJson(json); diff --git a/lib/src/model/coursetable/course_table.dart b/lib/src/model/coursetable/course_table.dart index 54168867..797e8df8 100644 --- a/lib/src/model/coursetable/course_table.dart +++ b/lib/src/model/coursetable/course_table.dart @@ -7,18 +7,14 @@ part 'course_table.g.dart'; @JsonSerializable() class CourseTable { - int year; - int semester; - List courses; - User user; + final int year; + final int semester; + final List courses; + final User user; late final Set weekdays = {}; late final Set periods = {}; CourseTable({required this.year, required this.semester, required this.courses, required this.user}) { - year = year; - semester = semester; - courses = courses; - user = user; weekdays.addAll(courses .map((course) => course.coursePeriods.map((coursePeriod) => coursePeriod.weekday)) .expand((element) => element)); From 33f07fea544703bc3d1d2bf6831c82f5d65a3b1d Mon Sep 17 00:00:00 2001 From: ntut-xuan Date: Tue, 13 Feb 2024 01:01:27 +0800 Subject: [PATCH 31/31] Chore: Add final --- lib/src/model/coursetable/user.dart | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/src/model/coursetable/user.dart b/lib/src/model/coursetable/user.dart index 6fc16e6d..3fc5f68d 100644 --- a/lib/src/model/coursetable/user.dart +++ b/lib/src/model/coursetable/user.dart @@ -4,20 +4,16 @@ part 'user.g.dart'; @JsonSerializable() class User { - String id; - String name; - String className; + final String id; + final String name; + final String className; User.origin() : id = "", name = "", className = ""; - User({required this.id, required this.name, required this.className}) { - id = id; - name = name; - className = className; - } + User({required this.id, required this.name, required this.className}); factory User.fromJson(Map json) => _$UserFromJson(json); Map toJson() => _$UserToJson(this);