Client/lib/view/pages/timetable/appointmentDetails.dart

227 lines
8.9 KiB
Dart

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) => 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) => 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) {
var 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<TimetableProps>(context, listen: false).run(renew: true);
future.complete();
});
},
).asDialog(context);
return future;
}
static void _custom(BuildContext context, TimetableProps webuntisData, CustomTimetableEvent appointment) {
_bottomSheet(
context,
(context) => 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) => 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('...');
var 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()),
]
)
);
}
}