import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; import '../../../../api/webuntis/queries/get_timetable/get_timetable_response.dart'; import '../../../../api/webuntis/services/lesson_resolver.dart'; import '../../../../extensions/date_time.dart'; import '../../../../extensions/text.dart'; import '../../../../routing/app_routes.dart'; import '../../../../state/app/modules/timetable/bloc/timetable_bloc.dart'; import '../../../../state/app/modules/timetable/bloc/timetable_state.dart'; import '../../../../widget/debug/debug_tile.dart'; import '../../../../widget/details_bottom_sheet.dart'; import '../../../../widget/unimplemented_dialog.dart'; class WebuntisLessonSheet { static void show(BuildContext context, TimetableBloc bloc, Appointment appointment, GetTimetableResponseObject lesson) { final state = bloc.state.data; if (state == null) return; final headerSubject = LessonResolver.resolveSubject(state, lesson.su.firstOrNull?.id); final headerTitle = firstNonEmpty([headerSubject.alternateName, headerSubject.name, headerSubject.longName, '?']); final headerLongName = headerSubject.longName.isNotEmpty && headerSubject.longName != headerTitle ? headerSubject.longName : ''; final timeRange = appointment.startTime.timeRangeTo(appointment.endTime); showDetailsBottomSheet( context, header: ListTile( leading: Icon(LessonFormatter.iconForCode(lesson.code), size: 32), title: Text( '${LessonFormatter.codePrefix(lesson.code)}$headerTitle', style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text(headerLongName.isNotEmpty ? '$timeRange\n$headerLongName' : timeRange), isThreeLine: headerLongName.isNotEmpty, ), children: (_) => [ ListTile( leading: const Icon(Icons.notifications_active), title: Text('Status: ${LessonFormatter.statusLabel(lesson.code)}'), ), if (lesson.su.length > 1) _listTile( icon: Icons.book_outlined, label: 'Fächer', entries: lesson.su.map((s) { final resolved = LessonResolver.resolveSubject(state, s.id); return LessonFormatter.formatLine( firstNonEmpty([resolved.name, s.name, '?']), longname: firstNonEmpty([resolved.longName, s.longname, '']), ); }).toList(), ), _roomTile(context, state, lesson), _teacherTile(context, lesson), if ((lesson.activityType ?? '').trim().isNotEmpty) ListTile( leading: const Icon(Icons.abc), title: Text('Typ: ${lesson.activityType}'), ), if (lesson.kl.isNotEmpty) _listTile( icon: Icons.people, label: lesson.kl.length == 1 ? 'Klasse' : 'Klassen', entries: lesson.kl .map((k) => LessonFormatter.formatLine( k.name.isNotEmpty ? k.name : '?', longname: k.longname, )) .toList(), ), ..._optionalTextTiles(lesson), DebugTile(context).jsonData(lesson.toJson()), ], ); } static Widget _roomTile(BuildContext context, TimetableState state, GetTimetableResponseObject lesson) { final trailing = IconButton( icon: const Icon(Icons.house_outlined), onPressed: () => AppRoutes.openRoomplan(context), ); if (lesson.ro.isEmpty) { return ListTile( leading: const Icon(Icons.room), title: const Text('Raum: ?'), trailing: trailing, ); } final entries = lesson.ro.map((r) { final resolved = LessonResolver.resolveRoom(state, r.id); final name = firstNonEmpty([resolved.name, r.name, '?']); final longname = firstNonEmpty([resolved.longName, r.longname, '']); final building = resolved.building.trim(); return LessonFormatter.formatLine( name, longname: longname, extra: (building.isNotEmpty && building != '?') ? building : null, ); }).toList(); return _listTile( icon: Icons.room, label: lesson.ro.length == 1 ? 'Raum' : 'Räume', entries: entries, trailing: trailing, ); } static Widget _teacherTile(BuildContext context, GetTimetableResponseObject lesson) { final trailing = Visibility( visible: !kReleaseMode, child: IconButton( icon: const Icon(Icons.textsms_outlined), onPressed: () => UnimplementedDialog.show(context), ), ); if (lesson.te.isEmpty) { return ListTile( leading: const Icon(Icons.person), title: const Text('Lehrkraft: ?'), trailing: trailing, ); } final entries = lesson.te.map((t) { final base = LessonFormatter.formatLine( t.name.isNotEmpty ? t.name : '?', longname: t.longname, ); final orgname = (t.orgname ?? '').trim(); return orgname.isEmpty ? base : '$base · ehemals $orgname'; }).toList(); return _listTile( icon: Icons.person, label: lesson.te.length == 1 ? 'Lehrkraft' : 'Lehrkräfte', entries: entries, trailing: trailing, ); } static Widget _listTile({ required IconData icon, required String label, required List entries, Widget? trailing, }) { if (entries.length == 1) { return ListTile( leading: Icon(icon), title: Text('$label: ${entries.first}'), trailing: trailing, ); } return ListTile( leading: Icon(icon), title: Text(label), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: entries.map(Text.new).toList(), ), trailing: trailing, ); } static List _optionalTextTiles(GetTimetableResponseObject lesson) { return [ _textTile(Icons.info_outline, 'Info', lesson.info), _textTile(Icons.swap_horiz, 'Vertretungstext', lesson.substText), _textTile(Icons.subject, 'Stundentext', lesson.lstext), _textTile(Icons.category_outlined, 'Stundentyp', lesson.lstype), _textTile(Icons.flag_outlined, 'Statusmerkmale', lesson.statflags), _textTile(Icons.school_outlined, 'Lerngruppe', lesson.sg), _textTile(Icons.bookmark_outline, 'Buchungshinweis', lesson.bkRemark), _textTile(Icons.notes, 'Buchungstext', lesson.bkText), ].whereType().toList(); } static Widget? _textTile(IconData icon, String label, String? value) { final text = (value ?? '').trim(); if (text.isEmpty || text == '-') return null; return ListTile( leading: Icon(icon), title: Text(label), subtitle: Text(text), ); } }