reworked home screen widgets to mirror the in-app timetable, hidden below android 12

This commit is contained in:
2026-09-27 14:07:52 +02:00
parent 2aed3d104c
commit 2ca9feb49a
44 changed files with 2401 additions and 1245 deletions
+46 -14
View File
@@ -1,4 +1,5 @@
import 'dart:developer';
import 'dart:ui';
import '../api/marianumconnect/queries/timetable_get_holidays/timetable_get_holidays_response.dart';
import '../api/marianumconnect/queries/timetable_get_rooms/timetable_get_rooms_response.dart';
@@ -9,11 +10,13 @@ import '../api/mhsl/custom_timetable_event/custom_timetable_event.dart';
import '../api/mhsl/custom_timetable_event/get/get_custom_timetable_event_response.dart';
import '../extensions/date_time.dart';
import '../utils/recurrence_occurrences.dart';
import '../view/pages/timetable/data/lesson_color.dart';
import '../view/pages/timetable/data/lesson_labels.dart';
import '../view/pages/timetable/data/lesson_merger.dart';
import '../view/pages/timetable/data/lesson_period_schedule.dart';
import '../view/pages/timetable/data/lesson_status.dart';
import '../view/pages/timetable/data/lesson_type_label.dart';
import '../view/pages/timetable/data/subject_color_palette.dart';
import 'widget_data.dart';
class WidgetDataMapper {
@@ -322,22 +325,26 @@ class WidgetDataMapper {
}) {
final start = lesson.startDateTime;
final end = lesson.endDateTime;
final status = _mapStatus(
LessonStatusClassifier.classify(lesson, start, end, now),
);
final subjectShortRaw = lesson.subjects.firstOrNull?.trim() ?? '';
// Webuntis sometimes ships subject-less entries (Wandertag etc.). Prefer
// their free text, else "Event" so the tile isn't just a dash.
// Gleiche Einstufung wie TimetableAppointmentFactory, damit Aufsicht,
// Prüfung & Co. im Widget dieselbe Farbe tragen wie in der App.
final lessonStatus = LessonStatusClassifier.classify(
lesson,
start,
end,
now,
isEvent: subjectShortRaw.isEmpty && lesson.lessonType == 'LESSON',
isDuty: lesson.lessonType != 'LESSON',
);
final subjectShort = subjectShortRaw.isEmpty
? LessonTypeLabel.entryText(lesson) ?? LessonTypeLabel.fallback
? LessonTypeLabel.forEntry(lesson)
: subjectShortRaw;
String? subjectLong;
if (subjects != null && subjectShortRaw.isNotEmpty) {
subjectLong = subjects.result
.where((s) => s.shortName == subjectShortRaw)
.firstOrNull
?.longName;
}
final subject = subjects == null || subjectShortRaw.isEmpty
? null
: subjects.result
.where((s) => s.shortName == subjectShortRaw)
.firstOrNull;
final subjectLong = subject?.longName;
final roomShort = lesson.rooms.firstOrNull;
var roomName = roomShort;
if (rooms != null && roomShort != null) {
@@ -365,10 +372,29 @@ class WidgetDataMapper {
room: roomName,
teacher: teacherName,
originalTeacher: originalTeacher,
status: status,
status: _mapStatus(lessonStatus),
color: _hex(_lessonColor(lessonStatus, subject?.color)),
);
}
/// Das Widget kennt keine Zeitzustände: laufende Stunden bekommen dieselbe
/// Farbe wie reguläre, sonst würde die Hervorhebung zwischen zwei
/// Aktualisierungen veralten.
static Color _lessonColor(LessonStatus status, String? subjectColor) {
final isRegular =
status == LessonStatus.regular ||
status == LessonStatus.ongoing ||
status == LessonStatus.past;
if (!isRegular) return LessonColor.forStatus(status);
return SubjectColorPalette.colorFromName(subjectColor) ??
LessonColor.regular;
}
static String _hex(Color color) {
final rgb = color.toARGB32() & 0xFFFFFF;
return '#${rgb.toRadixString(16).padLeft(6, '0').toUpperCase()}';
}
static WidgetLessonStatus _mapStatus(LessonStatus status) {
switch (status) {
case LessonStatus.cancelled:
@@ -480,6 +506,12 @@ class WidgetDataMapper {
subjectLong: title.isEmpty ? null : title,
status: WidgetLessonStatus.event,
customColor: event.color,
color: _hex(
SubjectColorPalette.colorFromName(event.color) ??
SubjectColorPalette.displayOf(
SubjectColorPalette.defaultColor,
).color,
),
);
final isAllDay = duration == Duration.zero && _isMidnight(event.startDate);