import 'dart:async'; import 'package:bottom_sheet/bottom_sheet.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:jiffy/jiffy.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; import 'package:provider/provider.dart'; import 'package:rrule/rrule.dart'; import 'package:syncfusion_flutter_calendar/calendar.dart'; import '../../../api/mhsl/customTimetableEvent/customTimetableEvent.dart'; import '../../../api/mhsl/customTimetableEvent/remove/removeCustomTimetableEvent.dart'; import '../../../api/mhsl/customTimetableEvent/remove/removeCustomTimetableEventParams.dart'; import '../../../api/webuntis/queries/getRooms/getRoomsResponse.dart'; import '../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart'; import '../../../api/webuntis/queries/getTimetable/getTimetableResponse.dart'; import '../../../model/timetable/timetableProps.dart'; import '../../../widget/centeredLeading.dart'; import '../../../widget/confirmDialog.dart'; import '../../../widget/debug/debugTile.dart'; import '../../../widget/unimplementedDialog.dart'; import '../more/roomplan/roomplan.dart'; import 'arbitraryAppointment.dart'; import 'customTimetableEventEditDialog.dart'; class AppointmentDetails { static String _getEventPrefix(String? code) { if(code == 'cancelled') return 'Entfällt: '; if(code == 'irregular') return 'Änderung: '; return code ?? ''; } static void show(BuildContext context, TimetableProps webuntisData, Appointment appointment) { (appointment.id as ArbitraryAppointment).handlers( (webuntis) => _webuntis(context, webuntisData, appointment, webuntis), (customData) => _custom(context, webuntisData, customData) ); } static void _bottomSheet( BuildContext context, Widget Function(BuildContext context) header, SliverChildListDelegate Function(BuildContext context) body ) { showStickyFlexibleBottomSheet( minHeight: 0, initHeight: 0.4, maxHeight: 0.7, anchors: [0, 0.4, 0.7], isSafeArea: true, maxHeaderHeight: 100, context: context, headerBuilder: (context, bottomSheetOffset) => header(context), bodyBuilder: (context, bottomSheetOffset) => body(context) ); } static void _webuntis(BuildContext context, TimetableProps webuntisData, Appointment appointment, GetTimetableResponseObject timetableData) { GetSubjectsResponseObject subject; GetRoomsResponseObject room; try { subject = webuntisData.getSubjectsResponse.result.firstWhere((subject) => subject.id == timetableData.su[0].id); } catch(e) { subject = GetSubjectsResponseObject(0, '?', 'Unbekannt', '?', true); } try { room = webuntisData.getRoomsResponse.result.firstWhere((room) => room.id == timetableData.ro[0].id); } catch(e) { room = GetRoomsResponseObject(0, '?', 'Unbekannt', true, '?'); } _bottomSheet( context, (context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text("${_getEventPrefix(timetableData.code)}${subject.alternateName}", textAlign: TextAlign.center, style: const TextStyle(fontSize: 25), overflow: TextOverflow.ellipsis), Text(subject.longName), Text("${Jiffy.parseFromDateTime(appointment.startTime).format(pattern: "HH:mm")} - ${Jiffy.parseFromDateTime(appointment.endTime).format(pattern: "HH:mm")}", style: const TextStyle(fontSize: 15)), ], ), ); }, (context) { return SliverChildListDelegate( [ const Divider(), ListTile( leading: const Icon(Icons.notifications_active), title: Text("Status: ${timetableData.code != null ? "Geändert" : "Regulär"}"), ), ListTile( leading: const Icon(Icons.room), title: Text('Raum: ${room.name} (${room.longName})'), trailing: IconButton( icon: const Icon(Icons.house_outlined), onPressed: () { pushScreen(context, withNavBar: false, screen: const Roomplan()); }, ), ), ListTile( leading: const Icon(Icons.person), title: timetableData.te.isNotEmpty ? Text("Lehrkraft: ${timetableData.te[0].name} ${timetableData.te[0].longname.isNotEmpty ? "(${timetableData.te[0].longname})" : ""}") : const Text('?'), trailing: Visibility( visible: !kReleaseMode, child: IconButton( icon: const Icon(Icons.textsms_outlined), onPressed: () { UnimplementedDialog.show(context); }, ), ), ), ListTile( leading: const Icon(Icons.abc), title: Text('Typ: ${timetableData.activityType}'), ), ListTile( leading: const Icon(Icons.people), title: Text("Klasse(n): ${timetableData.kl.map((e) => e.name).join(", ")}"), ), DebugTile(context).jsonData(timetableData.toJson()), ], ); } ); } static Completer deleteCustomEvent(BuildContext context, CustomTimetableEvent appointment) { Completer future = Completer(); ConfirmDialog( title: 'Termin löschen', content: "Der ${appointment.rrule.isEmpty ? "Termin" : "Serientermin"} wird unwiederruflich gelöscht.", confirmButton: 'Löschen', onConfirm: () { RemoveCustomTimetableEvent( RemoveCustomTimetableEventParams( appointment.id ) ).run().then((value) { Provider.of(context, listen: false).run(renew: true); future.complete(); }); }, ).asDialog(context); return future; } static void _custom(BuildContext context, TimetableProps webuntisData, CustomTimetableEvent appointment) { _bottomSheet( context, (context) { return Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Text(appointment.title, style: const TextStyle(fontSize: 25, overflow: TextOverflow.ellipsis)), Text("${Jiffy.parseFromDateTime(appointment.startDate).format(pattern: "HH:mm")} - ${Jiffy.parseFromDateTime(appointment.endDate).format(pattern: "HH:mm")}", style: const TextStyle(fontSize: 15)), ], ), ); }, (context) { return SliverChildListDelegate( [ const Divider(), Center( child: Wrap( children: [ TextButton.icon( onPressed: () { Navigator.of(context).pop(); showDialog( context: context, builder: (context) => CustomTimetableEventEditDialog(existingEvent: appointment), ); }, label: const Text('Bearbeiten'), icon: const Icon(Icons.edit_outlined), ), TextButton.icon( onPressed: () { deleteCustomEvent(context, appointment).future.then((value) => Navigator.of(context).pop()); }, label: const Text('Löschen'), icon: const Icon(Icons.delete_outline), ), ], ), ), const Divider(), ListTile( leading: const Icon(Icons.info_outline), title: Text(appointment.description.isEmpty ? 'Keine Beschreibung' : appointment.description), ), ListTile( leading: const CenteredLeading(Icon(Icons.repeat_outlined)), title: Text("Serie: ${appointment.rrule.isNotEmpty ? "Wiederholend" : "Einmailg"}"), subtitle: FutureBuilder( future: RruleL10nEn.create(), builder: (context, snapshot) { if(appointment.rrule.isEmpty) return const Text('Keine weiteren vorkomnisse'); if(snapshot.data == null) return const Text('...'); RecurrenceRule rrule = RecurrenceRule.fromString(appointment.rrule); if(!rrule.canFullyConvertToText) return const Text('Keine genauere Angabe möglich.'); return Text(rrule.toText(l10n: snapshot.data!)); }, ) ), DebugTile(context).child( ListTile( leading: const CenteredLeading(Icon(Icons.rule)), title: const Text('RRule'), subtitle: Text(appointment.rrule.isEmpty ? 'Keine' : appointment.rrule), ) ), DebugTile(context).jsonData(appointment.toJson()), ] ); } ); } }