diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 0000000..7e7e7f6 --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1 @@ +extensions: diff --git a/lib/view/pages/timetable/appointmentDetails.dart b/lib/view/pages/timetable/appointmentDetails.dart index 716ff58..17475da 100644 --- a/lib/view/pages/timetable/appointmentDetails.dart +++ b/lib/view/pages/timetable/appointmentDetails.dart @@ -1,4 +1,6 @@ +import 'dart:async'; + import 'package:bottom_sheet/bottom_sheet.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -135,6 +137,26 @@ class AppointmentDetails { ); } + 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, @@ -169,21 +191,7 @@ class AppointmentDetails { ), TextButton.icon( onPressed: () { - 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) { - Navigator.of(context).pop(); - Provider.of(context, listen: false).run(renew: true); - }); - }, - ).asDialog(context); + deleteCustomEvent(context, appointment).future.then((value) => Navigator.of(context).pop()); }, label: const Text("Löschen"), icon: const Icon(Icons.delete_outline), @@ -214,7 +222,7 @@ class AppointmentDetails { ListTile( leading: const CenteredLeading(Icon(Icons.rule)), title: const Text("RRule"), - subtitle: Text(appointment.rrule), + subtitle: Text(appointment.rrule.isEmpty ? "Keine" : appointment.rrule), ) ), DebugTile(context).jsonData(appointment.toJson()), diff --git a/lib/view/pages/timetable/customTimetableEventEditDialog.dart b/lib/view/pages/timetable/customTimetableEventEditDialog.dart index 9e36b70..f1b3791 100644 --- a/lib/view/pages/timetable/customTimetableEventEditDialog.dart +++ b/lib/view/pages/timetable/customTimetableEventEditDialog.dart @@ -108,7 +108,7 @@ class _AddCustomTimetableEventDialogState extends State createState() => _TimetableState(); } +enum CalendarActions { addEvent, viewEvents } + class _TimetableState extends State { CalendarController controller = CalendarController(); late Timer updateTimings; @@ -66,16 +69,45 @@ class _TimetableState extends State { controller.displayDate = DateTime.now().add(const Duration(days: 2)); } ), - IconButton( - icon: const Icon(Icons.add_outlined), - onPressed: () { - showDialog( - context: context, - builder: (context) => const CustomTimetableEventEditDialog(), - barrierDismissible: false, - ); + PopupMenuButton( + icon: const Icon(Icons.edit_calendar_outlined), + itemBuilder: (context) { + return CalendarActions.values.map( + (e) { + String title; + Icon icon; + switch(e) { + case CalendarActions.addEvent: + title = "Kalendereintrag hinzufügen"; + icon = const Icon(Icons.add); + case CalendarActions.viewEvents: + default: + title = "Kalendereinträge anzeigen"; + icon = const Icon(Icons.perm_contact_calendar_outlined); + } + return PopupMenuItem( + value: e, + child: ListTile( + title: Text(title), + leading: icon, + ) + ); + } + ).toList(); }, - ), + onSelected: (value) { + switch(value) { + case CalendarActions.addEvent: + showDialog( + context: context, + builder: (context) => const CustomTimetableEventEditDialog(), + barrierDismissible: false, + ); + case CalendarActions.viewEvents: + Navigator.of(context).push(MaterialPageRoute(builder: (context) => const ViewCustomTimetableEvents())); + } + }, + ) ], ), body: Consumer( diff --git a/lib/view/pages/timetable/viewCustomTimetableEvents.dart b/lib/view/pages/timetable/viewCustomTimetableEvents.dart new file mode 100644 index 0000000..2f961fb --- /dev/null +++ b/lib/view/pages/timetable/viewCustomTimetableEvents.dart @@ -0,0 +1,99 @@ +import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:provider/provider.dart'; + +import '../../../api/mhsl/customTimetableEvent/get/getCustomTimetableEventResponse.dart'; +import '../../../model/timetable/timetableProps.dart'; +import '../../../widget/centeredLeading.dart'; +import '../../../widget/loadingSpinner.dart'; +import '../../../widget/placeholderView.dart'; +import 'appointmentDetails.dart'; +import 'customTimetableEventEditDialog.dart'; + +class ViewCustomTimetableEvents extends StatefulWidget { + const ViewCustomTimetableEvents({super.key}); + + @override + State createState() => _ViewCustomTimetableEventsState(); +} + +class _ViewCustomTimetableEventsState extends State { + late Future events; + + @override + void initState() { + super.initState(); + } + + _openCreateDialog() { + showDialog( + context: context, + builder: (context) => const CustomTimetableEventEditDialog(), + barrierDismissible: false, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Eigene Termine"), + actions: [ + IconButton( + icon: const Icon(Icons.add), + onPressed: _openCreateDialog, + ) + ], + ), + body: Consumer(builder: (context, value, child) { + if(value.primaryLoading()) return const LoadingSpinner(); + + var listView = ListView( + children: value.getCustomTimetableEventResponse.events.map((e) { + return ListTile( + title: Text(e.title), + subtitle: Text("${e.rrule.isNotEmpty ? "wiederholdend, " : ""}beginnend ${Jiffy.parseFromDateTime(e.startDate).fromNow()}"), + leading: CenteredLeading(Icon(e.rrule.isEmpty ? Icons.event_outlined : Icons.event_repeat_outlined)), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: const Icon(Icons.edit_outlined), + onPressed: () { + showDialog(context: context, builder: (context) => CustomTimetableEventEditDialog(existingEvent: e)); + }, + ), + IconButton( + icon: const Icon(Icons.delete_outline), + onPressed: () { + AppointmentDetails.deleteCustomEvent(context, e); + }, + ) + ], + ), + ); + }).toList(), + ); + + var placeholder = PlaceholderView( + icon: Icons.calendar_today_outlined, + text: "Keine Einträge vorhanden", + button: TextButton( + onPressed: _openCreateDialog, + child: const Text("Termin erstellen"), + ), + ); + + return RefreshIndicator( + onRefresh: () { + Provider.of(context, listen: false).run(renew: true); + return Future.delayed(const Duration(seconds: 3)); + }, + child: value.getCustomTimetableEventResponse.events.isEmpty + ? placeholder + : listView + ); + }), + ); + } +}