replaced generic "Event" label with substitution or lesson text
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import '../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
import '../../../../api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
||||||
|
import 'lesson_labels.dart';
|
||||||
|
|
||||||
/// Derives a human-readable title from the Marianum-Connect `lessonType` for
|
/// Derives a human-readable title from the Marianum-Connect `lessonType` for
|
||||||
/// lessons that have no subject of their own (Aufsicht, Sprechstunde, …).
|
/// lessons that have no subject of their own (Aufsicht, Sprechstunde, …).
|
||||||
@@ -10,10 +11,20 @@ class LessonTypeLabel {
|
|||||||
|
|
||||||
static String forEntry(McTimetableEntry lesson) {
|
static String forEntry(McTimetableEntry lesson) {
|
||||||
final base = baseLabel(lesson.lessonType);
|
final base = baseLabel(lesson.lessonType);
|
||||||
|
if (base == fallback) {
|
||||||
|
final text = entryText(lesson);
|
||||||
|
if (text != null) return text;
|
||||||
|
}
|
||||||
final room = (lesson.rooms.firstOrNull ?? '').trim();
|
final room = (lesson.rooms.firstOrNull ?? '').trim();
|
||||||
return room.isEmpty ? base : '$room $base';
|
return room.isEmpty ? base : '$room $base';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Webuntis-Freitext eines fachlosen Eintrags („Klassenfahrt 8a“), der
|
||||||
|
/// aussagekräftiger ist als das generische „Event“.
|
||||||
|
static String? entryText(McTimetableEntry lesson) =>
|
||||||
|
collapseWhitespace(lesson.substitutionText) ??
|
||||||
|
collapseWhitespace(lesson.lessonText);
|
||||||
|
|
||||||
/// Returns just the type wording without the room — useful when the caller
|
/// Returns just the type wording without the room — useful when the caller
|
||||||
/// renders the room separately (e.g. as a subtitle line).
|
/// renders the room separately (e.g. as a subtitle line).
|
||||||
static String baseLabel(String lessonType) {
|
static String baseLabel(String lessonType) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import '../../../../state/app/modules/timetable/bloc/timetable_bloc.dart';
|
|||||||
import '../../../../state/app/modules/timetable/bloc/timetable_state.dart';
|
import '../../../../state/app/modules/timetable/bloc/timetable_state.dart';
|
||||||
import '../../../../widget/debug/debug_tile.dart';
|
import '../../../../widget/debug/debug_tile.dart';
|
||||||
import '../../../../widget/details_bottom_sheet.dart';
|
import '../../../../widget/details_bottom_sheet.dart';
|
||||||
|
import '../data/lesson_labels.dart';
|
||||||
import '../data/lesson_type_label.dart';
|
import '../data/lesson_type_label.dart';
|
||||||
import '../subject_colors/subject_color_picker.dart';
|
import '../subject_colors/subject_color_picker.dart';
|
||||||
|
|
||||||
@@ -226,10 +227,13 @@ class LessonSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<Widget> _optionalTextTiles(McTimetableEntry lesson) {
|
static List<Widget> _optionalTextTiles(McTimetableEntry lesson) {
|
||||||
|
final sameText =
|
||||||
|
collapseWhitespace(lesson.lessonText) ==
|
||||||
|
collapseWhitespace(lesson.substitutionText);
|
||||||
return <Widget?>[
|
return <Widget?>[
|
||||||
_textTile(Icons.info_outline, 'Info', lesson.infoText),
|
_textTile(Icons.info_outline, 'Info', lesson.infoText),
|
||||||
_textTile(Icons.swap_horiz, 'Vertretungstext', lesson.substitutionText),
|
_textTile(Icons.swap_horiz, 'Vertretungstext', lesson.substitutionText),
|
||||||
_textTile(Icons.subject, 'Stundentext', lesson.lessonText),
|
if (!sameText) _textTile(Icons.subject, 'Stundentext', lesson.lessonText),
|
||||||
_textTile(
|
_textTile(
|
||||||
Icons.category_outlined,
|
Icons.category_outlined,
|
||||||
'Stundentyp',
|
'Stundentyp',
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import '../view/pages/timetable/data/lesson_labels.dart';
|
|||||||
import '../view/pages/timetable/data/lesson_merger.dart';
|
import '../view/pages/timetable/data/lesson_merger.dart';
|
||||||
import '../view/pages/timetable/data/lesson_period_schedule.dart';
|
import '../view/pages/timetable/data/lesson_period_schedule.dart';
|
||||||
import '../view/pages/timetable/data/lesson_status.dart';
|
import '../view/pages/timetable/data/lesson_status.dart';
|
||||||
|
import '../view/pages/timetable/data/lesson_type_label.dart';
|
||||||
import 'widget_data.dart';
|
import 'widget_data.dart';
|
||||||
|
|
||||||
class WidgetDataMapper {
|
class WidgetDataMapper {
|
||||||
@@ -326,9 +327,11 @@ class WidgetDataMapper {
|
|||||||
LessonStatusClassifier.classify(lesson, start, end, now),
|
LessonStatusClassifier.classify(lesson, start, end, now),
|
||||||
);
|
);
|
||||||
final subjectShortRaw = lesson.subjects.firstOrNull?.trim() ?? '';
|
final subjectShortRaw = lesson.subjects.firstOrNull?.trim() ?? '';
|
||||||
// Webuntis sometimes ships subject-less entries (Wandertag etc.). Fall
|
// Webuntis sometimes ships subject-less entries (Wandertag etc.). Prefer
|
||||||
// back to "Event" so the tile isn't just a dash.
|
// their free text, else "Event" so the tile isn't just a dash.
|
||||||
final subjectShort = subjectShortRaw.isEmpty ? 'Event' : subjectShortRaw;
|
final subjectShort = subjectShortRaw.isEmpty
|
||||||
|
? LessonTypeLabel.entryText(lesson) ?? LessonTypeLabel.fallback
|
||||||
|
: subjectShortRaw;
|
||||||
String? subjectLong;
|
String? subjectLong;
|
||||||
if (subjects != null && subjectShortRaw.isNotEmpty) {
|
if (subjects != null && subjectShortRaw.isNotEmpty) {
|
||||||
subjectLong = subjects.result
|
subjectLong = subjects.result
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:marianum_mobile/api/marianumconnect/queries/timetable_get_week/timetable_get_week_response.dart';
|
||||||
|
import 'package:marianum_mobile/view/pages/timetable/data/lesson_type_label.dart';
|
||||||
|
|
||||||
|
McTimetableEntry _entry({
|
||||||
|
String lessonType = 'LESSON',
|
||||||
|
String? substitutionText,
|
||||||
|
String? lessonText,
|
||||||
|
}) => McTimetableEntry(
|
||||||
|
id: 1,
|
||||||
|
date: DateTime(2026, 5, 4),
|
||||||
|
startTime: DateTime(1970, 1, 1, 8),
|
||||||
|
endTime: DateTime(1970, 1, 1, 15),
|
||||||
|
subjects: const [],
|
||||||
|
teachers: const [],
|
||||||
|
rooms: const ['A101'],
|
||||||
|
classNames: const ['8a'],
|
||||||
|
lessonType: lessonType,
|
||||||
|
status: 'REGULAR',
|
||||||
|
substitutionText: substitutionText,
|
||||||
|
lessonText: lessonText,
|
||||||
|
infoText: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('LessonTypeLabel.forEntry', () {
|
||||||
|
test('prefers the substitution text', () {
|
||||||
|
expect(
|
||||||
|
LessonTypeLabel.forEntry(
|
||||||
|
_entry(substitutionText: 'Klassenfahrt 8a', lessonText: 'Anderes'),
|
||||||
|
),
|
||||||
|
'Klassenfahrt 8a',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('falls back to the lesson text', () {
|
||||||
|
expect(
|
||||||
|
LessonTypeLabel.forEntry(_entry(lessonText: ' Wandertag\n8a ')),
|
||||||
|
'Wandertag 8a',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('falls back to "Event" with room when no text is set', () {
|
||||||
|
expect(
|
||||||
|
LessonTypeLabel.forEntry(_entry(substitutionText: ' ')),
|
||||||
|
'A101 Event',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('keeps known lesson types over free text', () {
|
||||||
|
expect(
|
||||||
|
LessonTypeLabel.forEntry(
|
||||||
|
_entry(lessonType: 'BREAK_SUPERVISION', lessonText: 'Hof'),
|
||||||
|
),
|
||||||
|
'A101 Aufsicht',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user