getCourseTable method

  1. @override
Future<List<ScheduleDto>> getCourseTable({
  1. required String username,
  2. required SemesterDto semester,
})
override

Fetches the course schedule table for a specific student and semester.

Returns a list of course offerings enrolled by the student, including:

  • Course details (name, credits, hours)
  • Schedule information (days, periods, classroom)
  • Teacher and class information
  • Enrollment status and remarks

The username should be a student ID, and semester should be obtained from getCourseSemesterList.

Throws an Exception if no courses are found for the given semester.

Implementation

@override
Future<List<ScheduleDto>> getCourseTable({
  required String username,
  required SemesterDto semester,
}) async {
  final queryParameters = {
    'format': '-2',
    'code': username,
    'year': semester.year,
    'sem': semester.term,
  };

  // Fetch Chinese and English pages in parallel
  final (zhResponse, enResponse) = await (
    _courseDio.get('tw/Select.jsp', queryParameters: queryParameters),
    _courseDio
        .get('en/Select.jsp', queryParameters: queryParameters)
        .then<Response?>((r) => r, onError: (_) => null),
  ).wait;

  final courses = _parseZhCourseTable(zhResponse.data);
  final englishNames = switch (enResponse) {
    final r? => _parseEnCourseTable(r.data),
    null => <_EnglishCourseNames>[],
  };

  // Merge English names into Chinese-parsed DTOs. Match by course number
  // for numbered courses; for numberless rows (e.g. 班週會) fall back to
  // positional matching among the numberless subset.
  final enByNumber = <String, _EnglishCourseNames>{
    for (final en in englishNames) ?en.number: en,
  };
  final enNumberless = englishNames.where((e) => e.number == null).toList();
  var numberlessIndex = 0;

  return courses.map((dto) {
    final en = dto.number != null
        ? enByNumber[dto.number]
        : enNumberless.elementAtOrNull(numberlessIndex++);
    if (en == null) return dto;

    return (
      number: dto.number,
      course: (
        id: dto.course?.id,
        nameZh: dto.course?.nameZh,
        nameEn: en.courseName,
      ),
      phase: dto.phase,
      credits: dto.credits,
      hours: dto.hours,
      type: dto.type,
      teacher: (
        id: dto.teacher?.id,
        nameZh: dto.teacher?.nameZh,
        nameEn: en.teacherName,
      ),
      classes: dto.classes
          ?.map(
            (c) => (
              id: c.id,
              nameZh: c.nameZh,
              nameEn: en.classes.firstWhereOrNull((e) => e.id == c.id)?.name,
            ),
          )
          .toList(),
      schedule: dto.schedule,
      status: dto.status,
      language: dto.language,
      syllabusId: dto.syllabusId,
      remarks: dto.remarks,
    );
  }).toList();
}