diff --git a/.idea/libraries/Flutter_Plugins.xml b/.idea/libraries/Flutter_Plugins.xml
new file mode 100644
index 0000000..5480177
--- /dev/null
+++ b/.idea/libraries/Flutter_Plugins.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/data/timetable/timetableProps.dart b/lib/data/timetable/timetableProps.dart
index 73ad618..3704c98 100644
--- a/lib/data/timetable/timetableProps.dart
+++ b/lib/data/timetable/timetableProps.dart
@@ -14,7 +14,7 @@ import '../../api/webuntis/queries/getTimetable/getTimetableResponse.dart';
import '../../api/webuntis/webuntisError.dart';
extension DateTimeExtension on DateTime {
- DateTime next(int day) {
+ DateTime jumpToNextWeekDay(int day) {
return add(
Duration(
days: (day - weekday) % DateTime.daysPerWeek,
@@ -24,7 +24,7 @@ extension DateTimeExtension on DateTime {
}
class TimetableProps extends DataHolder {
- var _queryWeek = DateTime.now();
+ final _queryWeek = DateTime.now().add(const Duration(days: 2));
late DateTime startDate = getDate(_queryWeek.subtract(Duration(days: _queryWeek.weekday - 1)));
late DateTime endDate = getDate(_queryWeek.add(Duration(days: DateTime.daysPerWeek - _queryWeek.weekday)));
@@ -87,33 +87,18 @@ class TimetableProps extends DataHolder {
);
}
- void nearest() {
- _queryWeek = _queryWeek = DateTime.now();
- if(_queryWeek.weekday == DateTime.saturday || _queryWeek.weekday == DateTime.sunday) _queryWeek = _queryWeek.add(const Duration(days: 2));
- updateWeek();
- }
-
- void switchWeek({previous = false}) {
- if(previous) {
- _queryWeek = _queryWeek.subtract(const Duration(days: 7));
- } else {
- _queryWeek = _queryWeek.add(const Duration(days: 7));
- }
- updateWeek();
- }
-
DateTime getDate(DateTime d) => DateTime(d.year, d.month, d.day);
bool isWeekend(DateTime queryDate) {
return queryDate.weekday == DateTime.saturday || queryDate.weekday == DateTime.sunday;
}
- void updateWeek() {
+ void updateWeek(DateTime start, DateTime end) {
properties().forEach((element) => element = null);
error = null;
notifyListeners();
- startDate = getDate(_queryWeek.subtract(Duration(days: _queryWeek.weekday - 1)));
- endDate = getDate(_queryWeek.add(Duration(days: DateTime.daysPerWeek - _queryWeek.weekday)));
+ startDate = start.subtract(const Duration(days: 7));
+ endDate = end.add(const Duration(days: 7));
try {
run();
} on WebuntisError catch(e) {
diff --git a/lib/main.dart b/lib/main.dart
index d5f9382..82df1b4 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -8,6 +8,7 @@ import 'package:marianum_mobile/screen/login/login.dart';
import 'package:marianum_mobile/widget/errorView.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
import 'app.dart';
import 'data/chatList/chatListProps.dart';
@@ -71,6 +72,16 @@ class _MainState extends State {
return MaterialApp(
debugShowCheckedModeBanner: false,
+ localizationsDelegates: const [
+ ...GlobalMaterialLocalizations.delegates,
+ GlobalWidgetsLocalizations.delegate,
+ ],
+ supportedLocales: const [
+ Locale('de'),
+ Locale('en'),
+ ],
+ locale: const Locale('de'),
+
title: 'Marianum Fulda',
theme: ThemeData(
@@ -79,7 +90,7 @@ class _MainState extends State {
colorScheme: const ColorScheme(
brightness: Brightness.light,
surface: Colors.white,
- onSurface: Colors.white,
+ onSurface: Colors.black,
onSecondary: Colors.white,
onPrimary: Colors.white,
onError: marianumRed,
@@ -91,7 +102,7 @@ class _MainState extends State {
),
hintColor: marianumRed,
inputDecorationTheme: const InputDecorationTheme(
- border: UnderlineInputBorder(borderSide: BorderSide(color: marianumRed)),
+ border: UnderlineInputBorder(borderSide: BorderSide(color: marianumRed)),
),
appBarTheme: const AppBarTheme(
backgroundColor: marianumRed,
diff --git a/lib/screen/pages/timetable/appointmenetComponent.dart b/lib/screen/pages/timetable/appointmenetComponent.dart
new file mode 100644
index 0000000..d553934
--- /dev/null
+++ b/lib/screen/pages/timetable/appointmenetComponent.dart
@@ -0,0 +1,112 @@
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:syncfusion_flutter_calendar/calendar.dart';
+
+class AppointmentComponent extends StatefulWidget {
+ final CalendarAppointmentDetails details;
+ const AppointmentComponent({Key? key, required this.details}) : super(key: key);
+
+ @override
+ State createState() => _AppointmentComponentState();
+}
+
+class _AppointmentComponentState extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ final Appointment meeting = widget.details.appointments.first;
+ final appointmentHeight = widget.details.bounds.height;
+ double headerHeight = 50;
+ const double footerHeight = 5;
+ final double infoHeight = appointmentHeight - (headerHeight + footerHeight);
+ if(infoHeight < 0) headerHeight += infoHeight;
+
+ return Column(
+ children: [
+ Container(
+ padding: const EdgeInsets.all(3),
+ height: headerHeight,
+ alignment: Alignment.topLeft,
+ decoration: BoxDecoration(
+ shape: BoxShape.rectangle,
+ borderRadius: const BorderRadius.only(
+ topLeft: Radius.circular(5),
+ topRight: Radius.circular(5)),
+ color: meeting.color,
+ ),
+ child: SingleChildScrollView(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ FittedBox(
+ fit: BoxFit.fitWidth,
+ child: Text(
+ meeting.subject,
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 15,
+ fontWeight: FontWeight.w500,
+ ),
+ maxLines: 1,
+ softWrap: false,
+ ),
+ ),
+ FittedBox(
+ fit: BoxFit.fitWidth,
+ child: Text(
+ meeting.location ?? "?",
+ maxLines: 3,
+ overflow: TextOverflow.ellipsis,
+ softWrap: true,
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 10,
+ ),
+ ),
+ )
+ ],
+ )),
+ ),
+ Visibility(
+ visible: meeting.notes != null && infoHeight > 10,
+ replacement: Container(
+ color: meeting.color,
+ height: infoHeight,
+ ),
+ child: Container(
+ height: infoHeight,
+ padding: const EdgeInsets.fromLTRB(3, 5, 3, 2),
+ color: meeting.color.withOpacity(0.8),
+ alignment: Alignment.topLeft,
+ child: SingleChildScrollView(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ meeting.notes ?? "",
+ style: const TextStyle(
+ color: Colors.white,
+ fontSize: 10,
+ ),
+ )
+ ],
+ )),
+ ),
+ ),
+ Container(
+ height: footerHeight,
+ decoration: BoxDecoration(
+ shape: BoxShape.rectangle,
+ borderRadius: const BorderRadius.only(
+ bottomLeft: Radius.circular(5),
+ bottomRight: Radius.circular(5)),
+ color: meeting.color,
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/screen/pages/timetable/appointmentDetails.dart b/lib/screen/pages/timetable/appointmentDetails.dart
new file mode 100644
index 0000000..06261e6
--- /dev/null
+++ b/lib/screen/pages/timetable/appointmentDetails.dart
@@ -0,0 +1,90 @@
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:jiffy/jiffy.dart';
+import 'package:marianum_mobile/api/webuntis/queries/getTimetable/getTimetableResponse.dart';
+import 'package:marianum_mobile/data/timetable/timetableProps.dart';
+import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
+import 'package:syncfusion_flutter_calendar/calendar.dart';
+
+import '../../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
+import '../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart';
+import '../../settings/debug/jsonViewer.dart';
+import '../more/roomplan/roomplan.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) {
+ GetTimetableResponseObject timetableData = appointment.id as GetTimetableResponseObject;
+
+ //GetTimetableResponseObject timetableData = webuntisData.getTimetableResponse.result.firstWhere((element) => element.id == timetableObject.id);
+ GetSubjectsResponseObject subject = webuntisData.getSubjectsResponse.result.firstWhere((subject) => subject.id == timetableData.su[0]['id']);
+ GetRoomsResponseObject room = webuntisData.getRoomsResponse.result.firstWhere((room) => room.id == timetableData.ro[0]['id']);
+
+ showModalBottomSheet(context: context, builder: (context) => Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.symmetric(vertical: 30),
+ child: Center(
+ child: Column(
+ children: [
+ Icon(Icons.info, color: appointment.color),
+ const SizedBox(height: 10),
+ Text("${_getEventPrefix(timetableData.code)}${subject.alternateName} - (${subject.longName})", style: const TextStyle(fontSize: 30)),
+ Text("${Jiffy(appointment.startTime).format("HH:mm")} - ${Jiffy(appointment.endTime).format("HH:mm")}", style: const TextStyle(fontSize: 15)),
+ ],
+ ),
+ ),
+ ),
+
+ Expanded(
+ child: ListView(
+ children: [
+ 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}"),
+ trailing: IconButton(
+ icon: const Icon(Icons.house_outlined),
+ onPressed: () {
+ PersistentNavBarNavigator.pushNewScreen(context, withNavBar: false, screen: const Roomplan());
+ },
+ ),
+ ),
+ ListTile(
+ leading: const Icon(Icons.person),
+ title: Text("Lehrkraft: (${timetableData.te[0]['name']}) ${timetableData.te[0]['longname']}"),
+ trailing: IconButton(
+ icon: const Icon(Icons.textsms_outlined),
+ onPressed: () {
+ showDialog(context: context, builder: (context) => const AlertDialog(content: Text("Not implemented yet")));
+ },
+ ),
+ ),
+ 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(", ")}"),
+ ),
+ ListTile(
+ leading: const Icon(Icons.bug_report_outlined),
+ title: const Text("Webuntis Rohdaten zeigen"),
+ onTap: () => JsonViewer.asDialog(context, timetableData.toJson()),
+ )
+ ],
+ ),
+ )
+ ],
+ ));
+ }
+}
\ No newline at end of file
diff --git a/lib/screen/pages/timetable/timeRegionComponent.dart b/lib/screen/pages/timetable/timeRegionComponent.dart
new file mode 100644
index 0000000..cbbd007
--- /dev/null
+++ b/lib/screen/pages/timetable/timeRegionComponent.dart
@@ -0,0 +1,59 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:syncfusion_flutter_calendar/calendar.dart';
+
+class TimeRegionComponent extends StatefulWidget {
+ final TimeRegionDetails details;
+ const TimeRegionComponent({Key? key, required this.details}) : super(key: key);
+
+ @override
+ State createState() => _TimeRegionComponentState();
+}
+
+class _TimeRegionComponentState extends State {
+ @override
+ Widget build(BuildContext context) {
+ String text = widget.details.region.text!;
+ Color? color = widget.details.region.color;
+
+ if (text == 'centerIcon') {
+ return Container(
+ color: color,
+ alignment: Alignment.center,
+ child: Icon(
+ widget.details.region.iconData,
+ size: 17,
+ color: Theme.of(context).primaryColor,
+ ),
+ );
+ } else if(text.startsWith('holiday')) {
+ return Container(
+ color: color,
+ alignment: Alignment.center,
+ child: Column(
+ children: [
+ const SizedBox(height: 5),
+ const Icon(Icons.cake),
+ const Text("FREI"),
+ const SizedBox(height: 5),
+ RotatedBox(
+ quarterTurns: 1,
+ child: Text(
+ text.split(":").last,
+ maxLines: 1,
+ style: const TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 15,
+ decorationStyle: TextDecorationStyle.dashed,
+ letterSpacing: 2,
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ return const Placeholder();
+ }
+}
diff --git a/lib/screen/pages/timetable/timetable.dart b/lib/screen/pages/timetable/timetable.dart
index d8b5526..ba7faf9 100644
--- a/lib/screen/pages/timetable/timetable.dart
+++ b/lib/screen/pages/timetable/timetable.dart
@@ -1,10 +1,20 @@
+import 'dart:developer';
+
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
-import 'package:marianum_mobile/data/timetable/timetableProps.dart';
-import 'package:marianum_mobile/screen/pages/timetable/weekView.dart';
-import 'package:marianum_mobile/widget/errorView.dart';
+import 'package:marianum_mobile/screen/pages/timetable/appointmenetComponent.dart';
+import 'package:marianum_mobile/screen/pages/timetable/timeRegionComponent.dart';
+import 'package:marianum_mobile/screen/pages/timetable/timetableEvents.dart';
import 'package:provider/provider.dart';
+import 'package:syncfusion_flutter_calendar/calendar.dart';
+import '../../../api/webuntis/queries/getHolidays/getHolidaysResponse.dart';
+import '../../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
+import '../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart';
+import '../../../data/timetable/timetableProps.dart';
+import 'appointmentDetails.dart';
class Timetable extends StatefulWidget {
const Timetable({Key? key}) : super(key: key);
@@ -14,44 +24,209 @@ class Timetable extends StatefulWidget {
}
class _TimetableState extends State {
- bool draggable = true;
+ CalendarController controller = CalendarController();
+
+ double elementScale = 40;
+ double baseElementScale = 40;
@override
void initState() {
- super.initState();
-
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
- Provider.of(context, listen: false).nearest();
+ Provider.of(context, listen: false).run();
});
+
+ super.initState();
}
-
+
@override
Widget build(BuildContext context) {
- TimetableProps timetable = Provider.of(context, listen: false);
return Scaffold(
appBar: AppBar(
- title: const Text("Vertretungsplan"),
+ title: const Text("Stunden & Vertretungsplan"),
actions: [
- IconButton(onPressed: () => timetable.switchWeek(previous: true), icon: const Icon(Icons.chevron_left)),
- IconButton(onPressed: () => timetable.nearest(), icon: const Icon(Icons.home)),
- IconButton(onPressed: () => timetable.switchWeek(), icon: const Icon(Icons.chevron_right))
+ IconButton(
+ icon: const Icon(Icons.today),
+ onPressed: () {
+ controller.displayDate = DateTime.now().jumpToNextWeekDay(DateTime.monday);
+ //controller.displayDate = DateTime.now().add(Duration(days: 2));
+ //controller.selectedDate = DateTime.now();
+ }
+ ),
],
),
body: Consumer(
builder: (context, value, child) {
+ if(value.primaryLoading()) return const Placeholder();
+
+ GetHolidaysResponse holidays = value.getHolidaysResponse;
if(value.hasError) {
- return ErrorView(icon: Icons.error, text: value.error?.message ?? "Unbekannter Fehler");
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+ showDialog(context: context, builder: (context) {
+ return AlertDialog(
+ title: Text("Webuntis error"),
+ content: Text(value.error.toString()),
+ );
+ });
+ });
}
- if(value.primaryLoading()) {
- return const Center(child: CircularProgressIndicator());
- }
+ return GestureDetector(
+ onScaleStart: (details) => baseElementScale = elementScale,
+ onScaleUpdate: (details) {
+ setState(() {
+ elementScale = (baseElementScale * details.scale).clamp(40, 80);
+ });
+ },
+ onScaleEnd: (details) {
+ // TODO save scale for later
+ },
- return WeekView(value);
+ child: SfCalendar(
+ view: CalendarView.workWeek,
+ dataSource: _buildTableEvents(value),
+
+ controller: controller,
+
+ onViewChanged: (ViewChangedDetails details) {
+ log(details.visibleDates.toString());
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
+ Provider.of(context, listen: false).updateWeek(details.visibleDates.first, details.visibleDates.last);
+ });
+ },
+
+ onTap: (calendarTapDetails) {
+ if(calendarTapDetails.appointments == null) return;
+ Appointment tapped = calendarTapDetails.appointments!.first;
+ AppointmentDetails.show(context, value, tapped);
+ log(tapped.id.toString());
+ },
+
+ firstDayOfWeek: DateTime.monday,
+ specialRegions: _buildSpecialTimeRegions(holidays),
+ timeSlotViewSettings: TimeSlotViewSettings(
+ startHour: 07.5,
+ endHour: 16.5,
+ timeInterval: const Duration(minutes: 30),
+ timeFormat: "HH:mm",
+ dayFormat: "EE",
+ timeIntervalHeight: elementScale,
+ ),
+
+ timeRegionBuilder: (BuildContext context, TimeRegionDetails timeRegionDetails) => TimeRegionComponent(details: timeRegionDetails),
+ appointmentBuilder: (BuildContext context, CalendarAppointmentDetails details) => AppointmentComponent(details: details),
+
+ headerHeight: 0,
+ selectionDecoration: const BoxDecoration(),
+
+ allowAppointmentResize: false,
+ allowDragAndDrop: false,
+ allowViewNavigation: false,
+ ),
+ );
},
),
);
}
+
+ List _buildSpecialTimeRegions(GetHolidaysResponse holidays, ) {
+ DateTime lastMonday = DateTime.now().subtract(Duration(days: DateTime.now().weekday - 1));
+ DateTime firstBreak = lastMonday.copyWith(hour: 10, minute: 15);
+ DateTime secondBreak = lastMonday.copyWith(hour: 13, minute: 50);
+ DateTime beforeSchool = lastMonday.copyWith(hour: 7, minute: 30);
+
+ return [
+ ...holidays.result.map((e) {
+ return TimeRegion(
+ startTime: _parseWebuntisTimestamp(e.startDate, 755),
+ endTime: _parseWebuntisTimestamp(e.startDate, 1630),
+ text: 'holiday:${e.name}',
+ color: Theme.of(context).disabledColor.withAlpha(50),
+ iconData: Icons.holiday_village_outlined
+ );
+ }),
+
+ TimeRegion(
+ startTime: firstBreak,
+ endTime: firstBreak.add(const Duration(minutes: 20)),
+ recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5',
+ text: 'centerIcon',
+ color: Theme.of(context).primaryColor.withAlpha(50),
+ iconData: Icons.restaurant
+ ),
+ TimeRegion(
+ startTime: secondBreak,
+ endTime: secondBreak.add(const Duration(minutes: 15)),
+ recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5',
+ text: 'centerIcon',
+ color: Theme.of(context).primaryColor.withAlpha(50),
+ iconData: Icons.restaurant
+ ),
+ TimeRegion(
+ startTime: beforeSchool,
+ endTime: beforeSchool.add(const Duration(minutes: 25)),
+ recurrenceRule: 'FREQ=DAILY;INTERVAL=1;COUNT=5',
+ color: Theme.of(context).disabledColor.withAlpha(50),
+ text: "centerIcon",
+ ),
+ ];
+ }
+
+ TimetableEvents _buildTableEvents(TimetableProps data) {
+
+ List appointments = data.getTimetableResponse.result.map((element) {
+
+ GetRoomsResponse rooms = data.getRoomsResponse;
+ GetSubjectsResponse subjects = data.getSubjectsResponse;
+
+ try {
+ DateTime startTime = _parseWebuntisTimestamp(element.date, element.startTime);
+ DateTime endTime = _parseWebuntisTimestamp(element.date, element.endTime);
+ return Appointment(
+ id: element,
+ startTime: startTime,
+ endTime: endTime,
+ subject: subjects.result.firstWhere((subject) => subject.id == element.su[0]['id']).alternateName,
+ location: ""
+ "${rooms.result.firstWhere((room) => room.id == element.ro[0]['id']).name}"
+ "\n"
+ "${element.te.first['longname']}",
+ notes: element.activityType,
+ color: _getEventColor(element.code, startTime, endTime),
+ );
+ } on Error catch(e) {
+ log(e.toString());
+ return Appointment(
+ startTime: _parseWebuntisTimestamp(element.date, element.startTime),
+ endTime: _parseWebuntisTimestamp(element.date, element.endTime),
+ subject: "ERROR",
+ notes: element.info,
+ location: 'LOCATION',
+ color: Theme.of(context).primaryColor,
+ startTimeZone: '',
+ endTimeZone: '',
+ );
+ }
+ }).toList();
+
+ return TimetableEvents(appointments);
+ }
+
+ DateTime _parseWebuntisTimestamp(int date, int time) {
+ String timeString = time.toString().padLeft(4, '0');
+ return DateTime.parse('$date ${timeString.substring(0, 2)}:${timeString.substring(2, 4)}');
+ }
+
+ Color _getEventColor(String? code, DateTime startTime, DateTime endTime) {
+ int opacity = endTime.isBefore(DateTime.now()) ? 100 : 255;
+
+ if(code == "cancelled") return const Color(0xff000000).withAlpha(opacity);
+ if(code == "irregular") return const Color(0xff8F19B3).withAlpha(opacity);
+
+ if(endTime.isBefore(DateTime.now())) return Theme.of(context).primaryColor.withAlpha(opacity);
+ if(endTime.isAfter(DateTime.now()) && startTime.isBefore(DateTime.now())) return Theme.of(context).primaryColor.withRed(100);
+
+ return Theme.of(context).primaryColor;
+ }
}
diff --git a/lib/screen/pages/timetable/timetableEvents.dart b/lib/screen/pages/timetable/timetableEvents.dart
new file mode 100644
index 0000000..03510fa
--- /dev/null
+++ b/lib/screen/pages/timetable/timetableEvents.dart
@@ -0,0 +1,8 @@
+
+import 'package:syncfusion_flutter_calendar/calendar.dart';
+
+class TimetableEvents extends CalendarDataSource {
+ TimetableEvents(List source) {
+ appointments = source;
+ }
+}
\ No newline at end of file
diff --git a/lib/screen/pages/timetable/weekView.dart b/lib/screen/pages/timetable/weekView.dart
deleted file mode 100644
index 3816121..0000000
--- a/lib/screen/pages/timetable/weekView.dart
+++ /dev/null
@@ -1,272 +0,0 @@
-
-import 'package:flutter/cupertino.dart';
-import 'package:collection/collection.dart';
-import 'package:flutter/material.dart';
-import 'package:jiffy/jiffy.dart';
-import 'package:marianum_mobile/api/webuntis/queries/getHolidays/getHolidaysResponse.dart';
-import 'package:marianum_mobile/screen/pages/more/roomplan/roomplan.dart';
-import 'package:marianum_mobile/screen/settings/debug/jsonViewer.dart';
-import 'package:persistent_bottom_nav_bar/persistent_tab_view.dart';
-import 'package:timetable_view/timetable_view.dart';
-
-import '../../../api/webuntis/queries/getHolidays/getHolidays.dart';
-import '../../../api/webuntis/queries/getRooms/getRoomsResponse.dart';
-import '../../../api/webuntis/queries/getSubjects/getSubjectsResponse.dart';
-import '../../../api/webuntis/queries/getTimetable/getTimetableResponse.dart';
-import '../../../data/timetable/timetableProps.dart';
-
-extension DateHelpers on DateTime {
- bool isToday() {
- final now = DateTime.now();
- return now.day == day &&
- now.month == month &&
- now.year == year;
- }
-}
-
-class WeekView extends StatefulWidget {
- final TimetableProps value;
- const WeekView(this.value, {Key? key}) : super(key: key);
-
- @override
- State createState() => _WeekViewState();
-}
-
-class _WeekViewState extends State {
- @override
- Widget build(BuildContext context) {
- return TimetableView(
- laneEventsList: _buildLaneEvents(widget.value),
- onEventTap: (TableEvent event) {
-
- try {
- GetTimetableResponseObject timetableData = widget.value.getTimetableResponse.result.firstWhere((element) => element.id == event.eventId);
- GetSubjectsResponseObject subject = widget.value.getSubjectsResponse.result.firstWhere((subject) => subject.id == timetableData.su[0]['id']);
- GetRoomsResponseObject room = widget.value.getRoomsResponse.result.firstWhere((room) => room.id == timetableData.ro[0]['id']);
-
- showModalBottomSheet(context: context, builder: (context) => Column(
- children: [
- Padding(
- padding: const EdgeInsets.symmetric(vertical: 30),
- child: Center(
- child: Column(
- children: [
- Icon(Icons.info, color: event.backgroundColor),
- const SizedBox(height: 10),
- Text("${getEventPrefix(timetableData.code)}${subject.alternateName} - (${subject.longName})", style: const TextStyle(fontSize: 30)),
- Text("${Jiffy(event.startTime).format("HH:mm")} - ${Jiffy(event.endTime).format("HH:mm")}", style: const TextStyle(fontSize: 15)),
- ],
- ),
- ),
- ),
-
- Expanded(
- child: ListView(
- children: [
- 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}"),
- trailing: IconButton(
- icon: const Icon(Icons.house_outlined),
- onPressed: () {
- PersistentNavBarNavigator.pushNewScreen(context, withNavBar: false, screen: const Roomplan());
- },
- ),
- ),
- ListTile(
- leading: const Icon(Icons.person),
- title: Text("Lehrkraft: (${timetableData.te[0]['name']}) ${timetableData.te[0]['longname']}"),
- trailing: IconButton(
- icon: const Icon(Icons.textsms_outlined),
- onPressed: () {
- showDialog(context: context, builder: (context) => const AlertDialog(content: Text("Not implemented yet")));
- },
- ),
- ),
- 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(", ")}"),
- ),
- ListTile(
- leading: const Icon(Icons.bug_report_outlined),
- title: const Text("Webuntis Rohdaten zeigen"),
- onTap: () => JsonViewer.asDialog(context, timetableData.toJson()),
- )
- ],
- ),
- )
- ],
- ));
-
-
- } on StateError {
- return;
- }
- },
- timetableStyle: CustomTableStyle(context),
- onEmptySlotTap: (int laneIndex, TableEventTime start, TableEventTime end) => {
-
- },
- );
- }
-
- List _buildLaneEvents(TimetableProps data) {
- List laneEvents = List.empty(growable: true);
-
- if(data.primaryLoading()) throw UnimplementedError();
-
- GetTimetableResponse timetable = data.getTimetableResponse;
- GetRoomsResponse rooms = data.getRoomsResponse;
- GetSubjectsResponse subjects = data.getSubjectsResponse;
- GetHolidaysResponse holidays = data.getHolidaysResponse;
-
- List dayList = timetable.result.map((e) => e.date).toSet().toList();
- dayList.sort((a, b) => a-b);
-
- for(int i = 0; i <= data.endDate.difference(data.startDate).inDays; i++) {
- DateTime currentDay = data.startDate.copyWith().add(Duration(days: i));
-
- // Check Holiday Information
- GetHolidaysResponseObject? holidayInfo = GetHolidays.find(holidays, time: currentDay);
- if(holidayInfo != null) {
- laneEvents.add(
- LaneEvents(
- lane: getLane(currentDay),
- events: List.of([
- TableEvent(
- title: holidayInfo.name,
- eventId: holidayInfo.id,
- laneIndex: data.startDate.millisecondsSinceEpoch,
- startTime: parseTime(0800),
- endTime: parseTime(1500),
- padding: const EdgeInsets.all(5),
- backgroundColor: const Color(0xff3D62B3),
- location: "\n${holidayInfo.longName}",
- )
- ]),
- )
- );
- }
- }
-
- for (var day in dayList) {
- DateTime currentDay = DateTime.parse("$day");
- Lane currentLane = getLane(currentDay);
- //Every Day
-
- List events = List.generate(
- timetable.result.where((element) => element.date == day).length, (index) {
- GetTimetableResponseObject tableEvent = timetable.result.where((element) => element.date == day).elementAt(index);
- try {
- GetSubjectsResponseObject subject = subjects.result.firstWhere((subject) => subject.id == tableEvent.su[0]['id']);
-
- return TableEvent(
- title: "${getEventPrefix(tableEvent.code)}${subject.alternateName} (${subject.longName})",
- eventId: tableEvent.id,
- laneIndex: day,
- startTime: parseTime(tableEvent.startTime),
- endTime: parseTime(tableEvent.endTime),
- padding: const EdgeInsets.all(5),
- backgroundColor: getEventColor(
- tableEvent.code ?? "",
- currentDay.add(Duration(hours: parseTime(tableEvent.startTime).hour, minutes: parseTime(tableEvent.startTime).minute)),
- currentDay.add(Duration(hours: parseTime(tableEvent.endTime).hour, minutes: parseTime(tableEvent.endTime).minute)),
- ),
- location: "\n${rooms.result.firstWhereOrNull((room) => room.id == tableEvent.ro[0]['id'])?.name ?? "?"} - ${tableEvent.te[0]['longname']} (${tableEvent.te[0]['name']})",
- );
- } on Error {
- return TableEvent(title: "Unbekannt", eventId: index, laneIndex: day, startTime: parseTime(tableEvent.startTime), endTime: parseTime(tableEvent.endTime));
- }
- }
- );
-
- //Timepointer
- if(currentDay.isToday()) {
- events.add(TableEvent(
- title: "",
- eventId: 0,
- laneIndex: day,
- startTime: formatTime(DateTime.now()),
- endTime: formatTime(DateTime.now().add(const Duration(minutes: 3))),
- backgroundColor: Theme.of(context).disabledColor,
- ));
- }
-
- laneEvents.add(
- LaneEvents(
- lane: currentLane,
- events: events
- )
- );
- }
-
- return laneEvents;
- }
-
- Lane getLane(DateTime currentDay) {
- return Lane(
- backgroundColor: currentDay.isToday() ? Theme.of(context).dividerColor : Colors.white,
- laneIndex: currentDay.millisecondsSinceEpoch,
- name: "${Jiffy(currentDay.toString()).format("dd MMM")}\n${Jiffy(currentDay.toString()).format("EE")}",
- textStyle: TextStyle(
- color: Theme.of(context).primaryColor,
- fontWeight: FontWeight.bold,
- fontSize: 14
- )
- );
- }
-
- TableEventTime parseTime(int input) {
- String time = input.toString().length < 4 ? "0$input" : input.toString();
- return TableEventTime(hour: int.parse(time.substring(0, 2)), minute: int.parse(time.substring(2, 4)));
- }
-
- TableEventTime formatTime(DateTime input) {
- return TableEventTime(hour: input.hour, minute: input.minute);
- }
-
- String getEventPrefix(String? code) {
- if(code == "cancelled") return "Entfällt: ";
- if(code == "irregular") return "Änderung: ";
- return code ?? "";
- }
-
- Color getEventColor(String? code, DateTime startTime, DateTime endTime) {
- if(code == "cancelled") return const Color(0xff8F19B3);
- if(code == "irregular") return const Color(0xff992B99);
- if(endTime.isBefore(DateTime.now())) return Colors.grey;
- if(startTime.isAfter(DateTime.now())) return Theme.of(context).primaryColor;
- return const Color(0xff99563A);
- }
-}
-
-class CustomTableStyle extends TimetableStyle {
- dynamic context;
- CustomTableStyle(this.context);
-
- @override
- int get startHour => 07;
- @override
- int get endHour => 17;
- @override
- Color get cornerColor => Theme.of(context).primaryColor;
- @override
- Color get timeItemTextColor => Theme.of(context).primaryColor;
- @override
- double get timeItemHeight => MediaQuery.of(context).size.width > 1000 ? 60 : 90;
- @override
- double get timeItemWidth => 40;
- @override
- double get laneHeight => 40;
- @override
- double get laneWidth => (MediaQuery.of(context).size.width - timeItemWidth) / 5;
-
-}
\ No newline at end of file