migrated timetable integration from WebUntis to the MarianumConnect API, implementing a Dio-based client with bearer token authentication, background session validation, and auto-refresh logic.
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../errors/marianumconnect_error.dart';
|
||||
import '../../marianumconnect_api.dart';
|
||||
import '../../marianumconnect_endpoint.dart';
|
||||
import 'timetable_get_week_response.dart';
|
||||
|
||||
class TimetableGetWeek {
|
||||
final Dio _dio;
|
||||
|
||||
TimetableGetWeek({Dio? dio}) : _dio = dio ?? MarianumConnectApi.dio();
|
||||
|
||||
Future<TimetableGetWeekResponse> run({
|
||||
required DateTime from,
|
||||
required DateTime until,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _dio.get<Map<String, dynamic>>(
|
||||
MarianumConnectEndpoint.resolve('timetable/me'),
|
||||
queryParameters: {
|
||||
'from': _format(from),
|
||||
'until': _format(until),
|
||||
},
|
||||
);
|
||||
return TimetableGetWeekResponse.fromJson(response.data!);
|
||||
} on DioException catch (e) {
|
||||
throw mapMarianumConnectError(e);
|
||||
}
|
||||
}
|
||||
|
||||
String _format(DateTime d) =>
|
||||
'${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}';
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import '../../../api_response.dart';
|
||||
|
||||
part 'timetable_get_week_response.g.dart';
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class McTimetableTeacher {
|
||||
final String shortName;
|
||||
final String displayName;
|
||||
final String? originalShortName;
|
||||
final String? originalDisplayName;
|
||||
|
||||
McTimetableTeacher({
|
||||
required this.shortName,
|
||||
required this.displayName,
|
||||
this.originalShortName,
|
||||
this.originalDisplayName,
|
||||
});
|
||||
|
||||
factory McTimetableTeacher.fromJson(Map<String, dynamic> json) =>
|
||||
_$McTimetableTeacherFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$McTimetableTeacherToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class McTimetableEntry {
|
||||
final int id;
|
||||
|
||||
@JsonKey(fromJson: _dateFromJson, toJson: _dateToJson)
|
||||
final DateTime date;
|
||||
|
||||
@JsonKey(fromJson: _timeFromJson, toJson: _timeToJson)
|
||||
final DateTime startTime;
|
||||
|
||||
@JsonKey(fromJson: _timeFromJson, toJson: _timeToJson)
|
||||
final DateTime endTime;
|
||||
|
||||
final List<String> subjects;
|
||||
final List<McTimetableTeacher> teachers;
|
||||
final List<String> rooms;
|
||||
final List<String> classNames;
|
||||
final String lessonType;
|
||||
final String status;
|
||||
final String? substitutionText;
|
||||
final String? lessonText;
|
||||
final String? infoText;
|
||||
|
||||
McTimetableEntry({
|
||||
required this.id,
|
||||
required this.date,
|
||||
required this.startTime,
|
||||
required this.endTime,
|
||||
required this.subjects,
|
||||
required this.teachers,
|
||||
required this.rooms,
|
||||
required this.classNames,
|
||||
required this.lessonType,
|
||||
required this.status,
|
||||
required this.substitutionText,
|
||||
required this.lessonText,
|
||||
required this.infoText,
|
||||
});
|
||||
|
||||
factory McTimetableEntry.fromJson(Map<String, dynamic> json) =>
|
||||
_$McTimetableEntryFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$McTimetableEntryToJson(this);
|
||||
|
||||
/// Combines the calendar date with the hour/minute portion of [startTime]
|
||||
/// (which carries a 1970 placeholder date) into a real DateTime.
|
||||
DateTime get startDateTime =>
|
||||
DateTime(date.year, date.month, date.day, startTime.hour, startTime.minute);
|
||||
|
||||
DateTime get endDateTime =>
|
||||
DateTime(date.year, date.month, date.day, endTime.hour, endTime.minute);
|
||||
|
||||
static DateTime _dateFromJson(String raw) => DateTime.parse(raw);
|
||||
static String _dateToJson(DateTime d) =>
|
||||
'${d.year.toString().padLeft(4, '0')}-${d.month.toString().padLeft(2, '0')}-${d.day.toString().padLeft(2, '0')}';
|
||||
|
||||
// Backend sends ISO_LOCAL_TIME (e.g. "08:00:00" or "08:00"). Parsed via a
|
||||
// fixed-date prefix so we get a real DateTime out of it; only hour/minute
|
||||
// are meaningful for rendering.
|
||||
static DateTime _timeFromJson(String raw) => DateTime.parse('1970-01-01T$raw');
|
||||
static String _timeToJson(DateTime t) =>
|
||||
'${t.hour.toString().padLeft(2, '0')}:${t.minute.toString().padLeft(2, '0')}:${t.second.toString().padLeft(2, '0')}';
|
||||
}
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class TimetableGetWeekResponse extends ApiResponse {
|
||||
@JsonKey(fromJson: McTimetableEntry._dateFromJson, toJson: McTimetableEntry._dateToJson)
|
||||
final DateTime from;
|
||||
|
||||
@JsonKey(fromJson: McTimetableEntry._dateFromJson, toJson: McTimetableEntry._dateToJson)
|
||||
final DateTime until;
|
||||
|
||||
final List<McTimetableEntry> entries;
|
||||
|
||||
TimetableGetWeekResponse({
|
||||
required this.from,
|
||||
required this.until,
|
||||
required this.entries,
|
||||
});
|
||||
|
||||
factory TimetableGetWeekResponse.fromJson(Map<String, dynamic> json) =>
|
||||
_$TimetableGetWeekResponseFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$TimetableGetWeekResponseToJson(this);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'timetable_get_week_response.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
McTimetableTeacher _$McTimetableTeacherFromJson(Map<String, dynamic> json) =>
|
||||
McTimetableTeacher(
|
||||
shortName: json['shortName'] as String,
|
||||
displayName: json['displayName'] as String,
|
||||
originalShortName: json['originalShortName'] as String?,
|
||||
originalDisplayName: json['originalDisplayName'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$McTimetableTeacherToJson(McTimetableTeacher instance) =>
|
||||
<String, dynamic>{
|
||||
'shortName': instance.shortName,
|
||||
'displayName': instance.displayName,
|
||||
'originalShortName': instance.originalShortName,
|
||||
'originalDisplayName': instance.originalDisplayName,
|
||||
};
|
||||
|
||||
McTimetableEntry _$McTimetableEntryFromJson(Map<String, dynamic> json) =>
|
||||
McTimetableEntry(
|
||||
id: (json['id'] as num).toInt(),
|
||||
date: McTimetableEntry._dateFromJson(json['date'] as String),
|
||||
startTime: McTimetableEntry._timeFromJson(json['startTime'] as String),
|
||||
endTime: McTimetableEntry._timeFromJson(json['endTime'] as String),
|
||||
subjects: (json['subjects'] as List<dynamic>)
|
||||
.map((e) => e as String)
|
||||
.toList(),
|
||||
teachers: (json['teachers'] as List<dynamic>)
|
||||
.map((e) => McTimetableTeacher.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
rooms: (json['rooms'] as List<dynamic>).map((e) => e as String).toList(),
|
||||
classNames: (json['classNames'] as List<dynamic>)
|
||||
.map((e) => e as String)
|
||||
.toList(),
|
||||
lessonType: json['lessonType'] as String,
|
||||
status: json['status'] as String,
|
||||
substitutionText: json['substitutionText'] as String?,
|
||||
lessonText: json['lessonText'] as String?,
|
||||
infoText: json['infoText'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$McTimetableEntryToJson(McTimetableEntry instance) =>
|
||||
<String, dynamic>{
|
||||
'id': instance.id,
|
||||
'date': McTimetableEntry._dateToJson(instance.date),
|
||||
'startTime': McTimetableEntry._timeToJson(instance.startTime),
|
||||
'endTime': McTimetableEntry._timeToJson(instance.endTime),
|
||||
'subjects': instance.subjects,
|
||||
'teachers': instance.teachers.map((e) => e.toJson()).toList(),
|
||||
'rooms': instance.rooms,
|
||||
'classNames': instance.classNames,
|
||||
'lessonType': instance.lessonType,
|
||||
'status': instance.status,
|
||||
'substitutionText': instance.substitutionText,
|
||||
'lessonText': instance.lessonText,
|
||||
'infoText': instance.infoText,
|
||||
};
|
||||
|
||||
TimetableGetWeekResponse _$TimetableGetWeekResponseFromJson(
|
||||
Map<String, dynamic> json,
|
||||
) =>
|
||||
TimetableGetWeekResponse(
|
||||
from: McTimetableEntry._dateFromJson(json['from'] as String),
|
||||
until: McTimetableEntry._dateFromJson(json['until'] as String),
|
||||
entries: (json['entries'] as List<dynamic>)
|
||||
.map((e) => McTimetableEntry.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
)
|
||||
..headers = (json['headers'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$TimetableGetWeekResponseToJson(
|
||||
TimetableGetWeekResponse instance,
|
||||
) => <String, dynamic>{
|
||||
'headers': ?instance.headers,
|
||||
'from': McTimetableEntry._dateToJson(instance.from),
|
||||
'until': McTimetableEntry._dateToJson(instance.until),
|
||||
'entries': instance.entries.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
Reference in New Issue
Block a user