updated timetable UI with event status and enhanced appointment tile rendering

This commit is contained in:
2026-05-06 22:53:24 +02:00
parent 95ef29fb09
commit b8cac73e74
5 changed files with 163 additions and 23 deletions
@@ -8,12 +8,15 @@ class LessonColor {
static const Color cancelled = Color(0xff000000);
static const Color irregular = Color(0xff8F19B3);
static const Color teacherChanged = Color(0xFF29639B);
static const Color event = Color(0xff2E7D32);
static const Color parseFallback = Color(0xff404040);
static Color forStatus(LessonStatus status) {
switch (status) {
case LessonStatus.cancelled:
return cancelled;
case LessonStatus.event:
return event;
case LessonStatus.irregular:
return irregular;
case LessonStatus.teacherChanged:
@@ -2,6 +2,7 @@ import '../../../../api/webuntis/queries/get_timetable/get_timetable_response.da
enum LessonStatus {
cancelled,
event,
irregular,
teacherChanged,
past,
@@ -10,8 +11,15 @@ enum LessonStatus {
}
class LessonStatusClassifier {
static LessonStatus classify(GetTimetableResponseObject lesson, DateTime startTime, DateTime endTime, DateTime now) {
static LessonStatus classify(
GetTimetableResponseObject lesson,
DateTime startTime,
DateTime endTime,
DateTime now, {
bool isEvent = false,
}) {
if (lesson.code == 'cancelled') return LessonStatus.cancelled;
if (isEvent) return LessonStatus.event;
if (lesson.code == 'irregular' || (lesson.te.isNotEmpty && lesson.te.first.id == 0)) return LessonStatus.irregular;
if (lesson.te.any((t) => t.orgname != null)) return LessonStatus.teacherChanged;
if (endTime.isBefore(now)) return LessonStatus.past;
@@ -42,13 +42,20 @@ class TimetableAppointmentFactory {
try {
final startTime = WebuntisTime.parse(lesson.date, lesson.startTime);
final endTime = WebuntisTime.parse(lesson.date, lesson.endTime);
final status = LessonStatusClassifier.classify(lesson, startTime, endTime, now);
final subject = subjects.result.firstWhereOrNull((s) => s.id == lesson.su.firstOrNull?.id);
final status = LessonStatusClassifier.classify(
lesson,
startTime,
endTime,
now,
isEvent: subject == null,
);
return Appointment(
id: WebuntisAppointment(lesson),
startTime: startTime,
endTime: endTime,
subject: _subjectName(lesson),
subject: _subjectName(lesson, subject),
location: _locationLabel(lesson),
notes: lesson.activityType,
color: LessonColor.forStatus(status),
@@ -77,7 +84,10 @@ class TimetableAppointmentFactory {
? DateTime(event.startDate.year, event.startDate.month, event.startDate.day, 23, 59)
: event.endDate,
isAllDay: allDay,
location: _collapseWhitespace(event.description),
// Preserve user-entered newlines in descriptions; the tile soft-wraps to
// fill the available height. For lessons we still collapse whitespace
// so room/teacher stay on one line each.
location: event.description.trim().isEmpty ? null : event.description.trim(),
subject: _collapseWhitespace(event.title) ?? event.title,
recurrenceRule: event.rrule,
color: TimetableColors.getColorFromString(event.color ?? TimetableColors.defaultColor.name),
@@ -104,8 +114,7 @@ class TimetableAppointmentFactory {
e.second == 0;
}
String _subjectName(GetTimetableResponseObject lesson) {
final subject = subjects.result.firstWhereOrNull((s) => s.id == lesson.su.firstOrNull?.id);
String _subjectName(GetTimetableResponseObject lesson, GetSubjectsResponseObject? subject) {
if (subject == null) return 'Event';
final name = switch (settings.timetableNameMode) {
TimetableNameMode.name => subject.name,