refactored teacher display in lesson details to better handle substitutions and duplicates
This commit is contained in:
@@ -87,7 +87,7 @@ class LessonSheet {
|
|||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
_roomTile(context, lesson),
|
_roomTile(context, lesson),
|
||||||
_teacherTile(lesson),
|
_teacherTile(context, lesson),
|
||||||
if (lesson.classNames.isNotEmpty)
|
if (lesson.classNames.isNotEmpty)
|
||||||
_listTile(
|
_listTile(
|
||||||
icon: Icons.people,
|
icon: Icons.people,
|
||||||
@@ -127,7 +127,7 @@ class LessonSheet {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Widget _teacherTile(McTimetableEntry lesson) {
|
static Widget _teacherTile(BuildContext context, McTimetableEntry lesson) {
|
||||||
if (lesson.teachers.isEmpty) {
|
if (lesson.teachers.isEmpty) {
|
||||||
return const ListTile(
|
return const ListTile(
|
||||||
leading: Icon(Icons.person),
|
leading: Icon(Icons.person),
|
||||||
@@ -135,33 +135,32 @@ class LessonSheet {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final entries = lesson.teachers.map((t) {
|
// Webuntis liefert entfallende Lehrkräfte bei Vertretungen teils mehrfach —
|
||||||
final shortName = t.shortName.isEmpty ? '?' : t.shortName;
|
// über die Anzeigewerte deduplizieren.
|
||||||
final longName = t.displayName.trim();
|
final seen = <String>{};
|
||||||
final orgShort = (t.originalShortName ?? '').trim();
|
final teachers = <_TeacherDisplay>[];
|
||||||
final orgLong = (t.originalDisplayName ?? '').trim();
|
for (final t in lesson.teachers) {
|
||||||
|
final display = _TeacherDisplay.from(t);
|
||||||
|
if (seen.add(display.dedupKey)) teachers.add(display);
|
||||||
|
}
|
||||||
|
|
||||||
final subLines = <String>[];
|
final label = teachers.length == 1 ? 'Lehrkraft' : 'Lehrkräfte';
|
||||||
if (longName.isNotEmpty && longName != shortName) {
|
|
||||||
subLines.add(longName);
|
|
||||||
}
|
|
||||||
if (orgShort.isNotEmpty) {
|
|
||||||
final label = orgLong.isEmpty || orgLong == orgShort
|
|
||||||
? orgShort
|
|
||||||
: '$orgShort · $orgLong';
|
|
||||||
subLines.add('ehemals $label');
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
// Einzelne, reguläre Lehrkraft kompakt in der Titelzeile.
|
||||||
main: shortName,
|
if (teachers.length == 1 && teachers.first.isPlain) {
|
||||||
sub: subLines.isEmpty ? null : subLines.join('\n'),
|
return ListTile(
|
||||||
|
leading: const Icon(Icons.person),
|
||||||
|
title: Text('$label: ${teachers.first.after}'),
|
||||||
);
|
);
|
||||||
}).toList();
|
}
|
||||||
|
|
||||||
return _listTileWithSubs(
|
return ListTile(
|
||||||
icon: Icons.person,
|
leading: const Icon(Icons.person),
|
||||||
label: lesson.teachers.length == 1 ? 'Lehrkraft' : 'Lehrkräfte',
|
title: Text(label),
|
||||||
entries: entries,
|
subtitle: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [for (final t in teachers) t.buildRow(context)],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,3 +317,86 @@ class LessonSheet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Aufbereitete Darstellung einer einzelnen Lehrkraft aus einem
|
||||||
|
/// Webuntis-Element. Trennt die drei Fälle regulär / Vertretung / Entfall,
|
||||||
|
/// damit die Ansicht statt eines nackten `?` einen sprechenden Namen zeigt.
|
||||||
|
class _TeacherDisplay {
|
||||||
|
/// Ersetzte bzw. entfallende Lehrkraft — steht vorn und wird durchgestrichen.
|
||||||
|
/// Leer bei einer regulären Lehrkraft.
|
||||||
|
final String before;
|
||||||
|
|
||||||
|
/// Aktuelle Lehrkraft. Leer bei ersatzlosem Entfall.
|
||||||
|
final String after;
|
||||||
|
|
||||||
|
const _TeacherDisplay._({this.before = '', this.after = ''});
|
||||||
|
|
||||||
|
bool get isPlain => before.isEmpty;
|
||||||
|
|
||||||
|
String get dedupKey => '$before|$after';
|
||||||
|
|
||||||
|
factory _TeacherDisplay.from(McTimetableTeacher t) {
|
||||||
|
final current = _formatName(t.shortName, t.displayName);
|
||||||
|
final original = _formatName(
|
||||||
|
t.originalShortName ?? '',
|
||||||
|
t.originalDisplayName ?? '',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Kein (abweichendes) Original → reguläre Lehrkraft.
|
||||||
|
if (original.isEmpty || original == current) {
|
||||||
|
return _TeacherDisplay._(after: current.isEmpty ? '?' : current);
|
||||||
|
}
|
||||||
|
// Original vorhanden → ersetzte/entfallende Lehrkraft vorn, aktuelle
|
||||||
|
// Lehrkraft (falls vorhanden) als Ersatz dahinter.
|
||||||
|
return _TeacherDisplay._(before: original, after: current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Eine Bullet-Zeile je Lehrkraft: ersetzte Person durchgestrichen, bei
|
||||||
|
/// Ersatz ein Pfeil auf die neue Person. Bricht bei Bedarf sauber um.
|
||||||
|
Widget buildRow(BuildContext context) {
|
||||||
|
final muted = Theme.of(context).colorScheme.onSurfaceVariant;
|
||||||
|
final spans = <InlineSpan>[];
|
||||||
|
if (before.isNotEmpty) {
|
||||||
|
spans.add(
|
||||||
|
TextSpan(
|
||||||
|
text: before,
|
||||||
|
style: TextStyle(
|
||||||
|
decoration: TextDecoration.lineThrough,
|
||||||
|
color: muted,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (after.isNotEmpty) {
|
||||||
|
if (before.isNotEmpty) {
|
||||||
|
spans.add(TextSpan(text: ' → ', style: TextStyle(color: muted)));
|
||||||
|
}
|
||||||
|
spans.add(TextSpan(text: after));
|
||||||
|
}
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 2),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Text('• '),
|
||||||
|
Expanded(child: Text.rich(TextSpan(children: spans))),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Kombiniert Kurz- und Langname zu „Langname (Kurzname)“ und lässt leere
|
||||||
|
/// Teile weg. Liefert `''`, wenn beides leer ist.
|
||||||
|
static String _formatName(String short, String long) {
|
||||||
|
short = short.trim();
|
||||||
|
long = long.trim();
|
||||||
|
// Ein wörtliches „?“ zählt wie ein fehlender Wert.
|
||||||
|
if (short == '?') short = '';
|
||||||
|
if (long == '?') long = '';
|
||||||
|
if (long.isNotEmpty && short.isNotEmpty && long != short) {
|
||||||
|
return '$long ($short)';
|
||||||
|
}
|
||||||
|
if (long.isNotEmpty) return long;
|
||||||
|
return short;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user