227 lines
8.9 KiB
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()),
|
|
]
|
|
)
|
|
);
|
|
}
|
|
}
|