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 @@
+<component name="libraryTable">
+  <library name="Flutter Plugins" type="FlutterPluginsLibraryType">
+    <CLASSES>
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_web-2.0.16" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/image_picker_for_web-2.1.12" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_android-6.0.34" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_foundation-2.2.2" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_macos-3.0.5" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/better_open_file-3.6.4" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/package_info-2.0.2" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher-6.1.11" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.2.0" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_foundation-2.2.3" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_android-2.1.4" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/image_picker_android-0.8.6+16" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider-2.0.15" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/image_picker-0.8.7+5" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_web-2.1.0" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_linux-3.0.5" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.2.0" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_windows-3.0.6" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_android-2.0.27" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/url_launcher_ios-6.1.4" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/flutter_native_splash-2.3.0" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_linux-2.1.10" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/sqflite-2.2.8+4" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/shared_preferences-2.1.1" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/image_picker_ios-0.8.7+4" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/file_picker-5.3.0" />
+      <root url="file://$USER_HOME$/.pub-cache/hosted/pub.dev/path_provider_windows-2.1.6" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES />
+  </library>
+</component>
\ 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<Main> {
 
     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<Main> {
         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<Main> {
         ),
         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<AppointmentComponent> createState() => _AppointmentComponentState();
+}
+
+class _AppointmentComponentState extends State<AppointmentComponent> {
+
+  @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<TimeRegionComponent> createState() => _TimeRegionComponentState();
+}
+
+class _TimeRegionComponentState extends State<TimeRegionComponent> {
+  @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<Timetable> {
-  bool draggable = true;
+  CalendarController controller = CalendarController();
+
+  double elementScale = 40;
+  double baseElementScale = 40;
 
   @override
   void initState() {
-    super.initState();
-
     WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
-      Provider.of<TimetableProps>(context, listen: false).nearest();
+      Provider.of<TimetableProps>(context, listen: false).run();
     });
+
+    super.initState();
   }
-  
+
   @override
   Widget build(BuildContext context) {
-    TimetableProps timetable = Provider.of<TimetableProps>(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<TimetableProps>(
         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<TimetableProps>(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<TimeRegion> _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<Appointment> 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<Appointment> 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<WeekView> createState() => _WeekViewState();
-}
-
-class _WeekViewState extends State<WeekView> {
-  @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<LaneEvents> _buildLaneEvents(TimetableProps data) {
-    List<LaneEvents> laneEvents = List<LaneEvents>.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<int> 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<TableEvent>.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<TableEvent> events = List<TableEvent>.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