From 65c4ffb233dc80f4c6aea55266c7ca8224745597 Mon Sep 17 00:00:00 2001 From: DevKevYT Date: Thu, 22 Dec 2022 13:09:47 +0100 Subject: [PATCH] added mergedblock #192 --- lib/core/api/readme.md | 27 --- lib/core/api/usersession.dart | 1 + lib/core/excel/models/mergedblock.dart | 21 ++ lib/core/excel/models/mergedtimetable.dart | 6 +- lib/core/excel/readme.md | 9 - lib/core/excel/solc_api_manager.dart | 187 ++++-------------- lib/core/excel/validator.dart | 13 +- .../widgets/teacher_class_card.dart | 121 ++++++++---- 8 files changed, 151 insertions(+), 234 deletions(-) delete mode 100644 lib/core/api/readme.md create mode 100644 lib/core/excel/models/mergedblock.dart delete mode 100644 lib/core/excel/readme.md diff --git a/lib/core/api/readme.md b/lib/core/api/readme.md deleted file mode 100644 index b72acf1..0000000 --- a/lib/core/api/readme.md +++ /dev/null @@ -1,27 +0,0 @@ -Beispiel für eine Wochenabfrage: -```dart - -void main() { - - UserSession gw = new UserSession(school: "bbs1-mainz", appID: "testAPP"); - - gw.createSession(username: "USERNAME", password: "PASSWORD").then((e) async { - - TimeTableRange week = await gw.getTimeTableForThisWeek(); - - for (TimeTableDay day in week.getDays()) { - - if (day.isHolidayOrWeekend()) print("\t[FERIEN/WOCHENENDE]"); - - for (TimeTableHour hour in day.getHours()) { - print("\t" + - hour.getTitle() + - " " + - hour.getSubject().name + - " " + - (hour.code != "regular" ? "[" + hour.code + "]" : ""));*/ - } - } - }); -} -``` diff --git a/lib/core/api/usersession.dart b/lib/core/api/usersession.dart index a59e193..60ad872 100644 --- a/lib/core/api/usersession.dart +++ b/lib/core/api/usersession.dart @@ -222,6 +222,7 @@ class UserSession { http.Response r = await _queryURL("/WebUntis/api/token/new"); if (r.statusCode == 200) { _bearerToken = r.body; + log.d("Bearer Token refreshed"); } else { log.w("Warning: Failed to fetch api token. Unable to call 'getNews()' and 'getProfileData()'"); } diff --git a/lib/core/excel/models/mergedblock.dart b/lib/core/excel/models/mergedblock.dart new file mode 100644 index 0000000..8806da3 --- /dev/null +++ b/lib/core/excel/models/mergedblock.dart @@ -0,0 +1,21 @@ +import 'package:sol_connect/core/excel/models/mergedtimetable.dart'; + +///Anders als "mergedTimetable" beinhaltet diese Klasse einen kompletten Block, nicht nur eine Woche +class MergedBlock { + + final _hours = []; + + final DateTime _blockStart; + final DateTime _blockEnd; + + MergedBlock(this._blockStart, this._blockEnd, List weeks) { + for (MergedTimeTable week in weeks) { + _hours.add(week); //TODO @DevKevYT further checks for valid weeks + } + } + + DateTime get blockStart => _blockStart; + + DateTime get blockEnd => _blockEnd; + +} diff --git a/lib/core/excel/models/mergedtimetable.dart b/lib/core/excel/models/mergedtimetable.dart index b714485..ef6b702 100644 --- a/lib/core/excel/models/mergedtimetable.dart +++ b/lib/core/excel/models/mergedtimetable.dart @@ -5,10 +5,6 @@ import 'package:sol_connect/core/excel/models/mappedsheet.dart'; import 'package:sol_connect/core/excel/validator.dart'; class MergedTimeTable { - ///Gibt eine Fehlermeldung zurück, falls dieser Stundenplan nicht mit der Excel gemappt werden konnte. - /// - ///Immer leer, außer `verified() == false` - //String errorMessage = ""; //Der Stundenplan final TimeTableRange timetable; @@ -31,7 +27,7 @@ class MergedTimeTable { ///Gibt die entsprechende Phasierung zum Stunden Index zurück. /// - ///* ` getPhaseFromHourIndex(xIndex: 0, yIndex: 0)` gibt die Phasierung zur ersten Stunde am Montag zurück + ///* `getPhaseFromHourIndex(xIndex: 0, yIndex: 0)` gibt die Phasierung zur ersten Stunde am Montag zurück ///* `getPhaseFromHourIndex(xIndex: 2, yIndex: 2)` gibt die Phasierung zur dritten Stunde am Mittwoch zurück /// ///Gibt immer unbekannte Phasen zurück, wenn `verified() == false` diff --git a/lib/core/excel/readme.md b/lib/core/excel/readme.md deleted file mode 100644 index dd9c986..0000000 --- a/lib/core/excel/readme.md +++ /dev/null @@ -1,9 +0,0 @@ -Kriterien zum "Dynamischen" einlesen ener Excel Datei: - -- Der Stundenplan dient als "Schablone": -Jede Zelle wird abgeglichen. Wenn diese Passend ist mit dem Lehrerkürzel -(Nicht case- sensitive) werden alle anderen Zellen Relativ zu dieser -abgeglichen, ob diese Passend ist. Bis diese "Schablone" passt. -- Lehrerkürzel dürfen nicht Case-Sensitive sein -- Bis jetzt muss jede Woche einzeln eingescannt werden -- Der Stundenplan muss dem Original entsprechen ohne Vertretung oder sonstiges \ No newline at end of file diff --git a/lib/core/excel/solc_api_manager.dart b/lib/core/excel/solc_api_manager.dart index 63774b0..c2fc4d7 100644 --- a/lib/core/excel/solc_api_manager.dart +++ b/lib/core/excel/solc_api_manager.dart @@ -8,23 +8,19 @@ import 'package:logger/logger.dart'; import 'package:sol_connect/core/api/models/utils.dart'; import 'package:sol_connect/core/api/usersession.dart'; import 'package:sol_connect/core/excel/models/cellcolors.dart'; +import 'package:sol_connect/core/excel/models/mergedblock.dart'; import 'package:sol_connect/core/excel/models/phasestatus.dart'; import 'package:sol_connect/core/excel/models/version.dart'; -import 'package:sol_connect/core/excel/solcresponse.dart'; -import 'package:sol_connect/core/exceptions.dart'; import 'package:sol_connect/util/logger.util.dart'; -//Vielleicht einen besseren Namen ausdenken -//Handled alles SOLC-API Server zeug - +///Interface für SOLC-API-3 Server class SOLCApiManager { final Logger log = getLogger(); - int _activeSockets = 0; - String _baseURL; int _port; - static const int timeoutSeconds = 5; //Throw a timeout if a response does not come within x seconds + static const int timeoutSeconds = + 5; //Throw a timeout if a response does not come within x seconds static final Version buildRequired = Version.of("3.0.0"); @@ -45,7 +41,8 @@ class SOLCApiManager { int get port => _port; Future getVersion() async { - http.Response response = await http.Client().get(Uri.parse("$apiAddress/version")); + http.Response response = + await http.Client().get(Uri.parse("$apiAddress/version")); if (response.statusCode == 200 && response.body.isNotEmpty) { return Version.of(jsonDecode(response.body)['data']['displayValue']); } else { @@ -55,8 +52,10 @@ class SOLCApiManager { ///Sendet eine Anfrage an den Server, um Farben einer Excel Datei zu extrahieren. Future getExcelColorData(List fileBytes) async { - var request = http.MultipartRequest("POST", Uri.parse("$apiAddress/getcolor")); - request.files.add(http.MultipartFile.fromBytes('sheet', fileBytes, filename: 'sheet')); + var request = + http.MultipartRequest("POST", Uri.parse("$apiAddress/getcolor")); + request.files.add( + http.MultipartFile.fromBytes('sheet', fileBytes, filename: 'sheet')); http.StreamedResponse response = await request.send(); if (response.statusCode == 200) { @@ -67,24 +66,29 @@ class SOLCApiManager { } ///Wirft eine Exception wenn ein Fehlercode auftritt + ///@deprecated Future getSchoolClassInfo({required int schoolClassId}) async { - SOLCResponse? response = await _querySOLC(command: "phase-status <$schoolClassId>"); - if (response != null) { - return PhaseStatus(response.payload); - } + //SOLCResponse? response = + // await _querySOLC(command: "phase-status <$schoolClassId>"); + //if (response != null) { + // return PhaseStatus(response.payload); + //} return null; } Future> downloadVirtualSheet({required int schoolClassId}) async { List bytes = []; - await _querySOLC(command: "download-file <$schoolClassId>", downloadBytes: bytes); + //await _querySOLC( + // command: "download-file <$schoolClassId>", downloadBytes: bytes); return bytes; } ///Wirft eine Exception wenn ein Fehlercode auftritt - Future downloadSheet({required int schoolClassId, required File targetFile}) async { + Future downloadSheet( + {required int schoolClassId, required File targetFile}) async { List bytes = []; - await _querySOLC(command: "download-file <$schoolClassId>", downloadBytes: bytes); + //await _querySOLC( + // command: "download-file <$schoolClassId>", downloadBytes: bytes); await targetFile.create(recursive: true); await targetFile.writeAsBytes(bytes); @@ -93,137 +97,24 @@ class SOLCApiManager { ///Wirft eine Exception wenn ein Fehlercode auftritt /// ///**ACHTUNG! Bei erfolgreichem hochladen wird der user automatisch serverseitig abgemeldet!** - Future uploadSheet( + Future uploadPhasing( {required UserSession authenticatedUser, required int schoolClassId, - required DateTime blockStart, - required DateTime blockEnd, - required File file}) async { - await _querySOLC( - uploadFileSource: file, - command: - "upload-file <${authenticatedUser.sessionid}> <${authenticatedUser.bearerToken}> <$schoolClassId> <${Utils.convertToUntisDate(blockStart)}> <${Utils.convertToUntisDate(blockEnd)}>"); - await authenticatedUser.regenerateSession(); - } - - ///Transferdata ist eigentlich nur eine Datei - ///Transferdata wird gebraucht, wenn ein Befehl einen Dateiupload oder Download inizialisiert. - /// - ///Zurückgegebene Werte können null sein, je nachdem was für ein Befehl benutzt wurde. - ///Ein rückgabewert gibt es nur wenn eine Serverantwort im JSON Format kommt bzw wenn der Code 0 (SUCCESS) ist. - ///Ansonsten wird alles über die File Objekte gehandled - ///Spezielle Exceptions: - ///* `SOLCServerError` Hat zusätzlich noch die ursprüngliche Nachricht - /// - ///Folgende "normale" Exceptions können geworfen werden: - ///* `UploadFileNotSpecifiedException` Wenn ein Befehl ein Dateiupload erwartet diese jedoch nicht angegeben wurde - ///* `UploadFileNotFoundException` Wenn die hochzuladene Datei im System nicht gefunden werden konnte bzw. nicht existiert - ///* `DownloadFileNotFoundException` Wenn keine Datei zum Download nicht angegeben wurde - /// - @Deprecated('Use [ConflictException]') - Future _querySOLC({required String command, File? uploadFileSource, List? downloadBytes}) async { - SOLCResponse? returnValue; - dynamic exception; - - try { - _activeSockets = _activeSockets + 1; - final socket = await Socket.connect(_baseURL, _port); - - //Sende den Befehl - socket.writeln(command); - await socket.flush(); - - void throwException(Exception e) { - exception = e; - socket.close(); - } - - bool awaitFileStream = false; - - if (downloadBytes != null) { - downloadBytes.clear(); - } - - var subscription = socket.listen( - (event) async { - if (awaitFileStream) { - if (downloadBytes == null) { - throwException(DownloadFileNotFoundException("Kein Ziel zum Download angegeben")); - return; - } - downloadBytes.addAll(event); - return; - } - - dynamic decodedMessage = ""; - try { - decodedMessage = jsonDecode(String.fromCharCodes(event)); - } on FormatException { - socket.close(); - return; - } - - SOLCResponse response = SOLCResponse.handle(decodedMessage); - if (response.isError) { - throwException( - SOLCServerError("${response.errorMessage} (SOLC Error Code: ${response.responseCode})", response)); - return; - } - - //Einfache JSON Antwort - if (response.responseCode == SOLCResponse.CODE_SUCCESS) { - returnValue = response; - socket.close(); - return; - } - - //Server bereit einen Dateiupload zu empfangen - if (response.responseCode == SOLCResponse.CODE_READY) { - if (uploadFileSource == null) { - throwException(UploadFileNotSpecifiedException("Keine Datei zum Upload angegeben")); - socket.close(); - return; - } - if (!(await uploadFileSource.exists())) { - throwException(UploadFileNotFoundException("Datei zum Upload existiert nicht")); - return; - } - await socket.addStream(uploadFileSource.openRead()); - socket.close(); - return; - } - - //Server fragt den Client ob er bereit ist eine Datei zu downloaden. Sende ein "ready-to-recieve" und lade die Date als Stream herunter - if (response.responseCode == SOLCResponse.CODE_SEND_READY) { - awaitFileStream = true; - socket.writeln("ready-to-recieve"); - await socket.flush(); - return; - } - }, - onError: (error) { - _activeSockets--; - throwException(Exception("Ein Fehler ist bei der Verbindung zum SOLC-API Server aufgetreten")); - }, - ); - - await subscription.asFuture().timeout(const Duration(seconds: timeoutSeconds), onTimeout: () { - throwException(SOLCServerResponseTimeoutException("Timeout after $timeoutSeconds seconds")); - }); - - await socket.close(); - await subscription.cancel(); - - _activeSockets--; - log.d("Connection for SOLC command '$command' closed. $_activeSockets active connections."); - } on Exception catch (error) { - _activeSockets--; - throw FailedToEstablishSOLCServerConnection( - "Konnte keine Verbindung zum Konvertierungsserver $_baseURL herstellen: $error"); - } - if (exception != null) { - throw exception; - } - return returnValue; + required MergedBlock block}) async { + + ///Wandelt dieses Objekt in eine PhTP gültige JSON um + var object = { + "version": "1", + "classId": schoolClassId, + "blockStart": Utils.convertToUntisDate(block.blockStart), + "blockEnd": Utils.convertToUntisDate(block.blockEnd) + }; + + http.Response response = await http.post(Uri.parse("$apiAddress/api/phasing/upload"), + headers: { + "JSESSIONID": authenticatedUser.sessionid, + "Authentication": "Bearer ${authenticatedUser.bearerToken}" + }, + body: jsonEncode(object)); } } diff --git a/lib/core/excel/validator.dart b/lib/core/excel/validator.dart index 18f037d..95ba8fa 100644 --- a/lib/core/excel/validator.dart +++ b/lib/core/excel/validator.dart @@ -7,6 +7,7 @@ import 'package:sol_connect/core/api/timetable_manager.dart'; import 'package:sol_connect/core/api/usersession.dart'; import 'package:sol_connect/core/excel/models/cellcolors.dart'; import 'package:sol_connect/core/excel/models/mappedsheet.dart'; +import 'package:sol_connect/core/excel/models/mergedblock.dart'; import 'package:sol_connect/core/excel/models/mergedtimetable.dart'; import 'package:sol_connect/core/excel/models/phaseelement.dart'; import 'package:sol_connect/core/excel/solc_api_manager.dart'; @@ -113,19 +114,25 @@ class ExcelValidator { _collectedTimetables.add(mapped); } - ///Wenn keineException geworfen wurde ist der Merge erfolgreich gewesen. - Future mergeExcelWithWholeBlock(UserSession session) async { + ///Wenn keineException geworfen wurde und ein "MergedBlock" Objekt zurückgegeben wurde, war der merge erfolgreich + Future mergeExcelWithWholeBlock(UserSession session) async { TimeTableRange timeTable = await session.getRelativeTimeTableWeek(0); var nextBlockweeks = await timeTable.getBoundFrame().getManager().getNextBlockWeeks(); + List mergedWeeks = []; for (TimetableFrame blockWeek in nextBlockweeks) { log.d( "Verifying block week phase merge ${blockWeek.getFrameStart()} -> ${blockWeek.getFrameEnd()}"); await blockWeek.getCurrentBlockWeek(); - await mergeExcelWithTimetable(await blockWeek.getWeekData()); + mergedWeeks + .add(await mergeExcelWithTimetable(await blockWeek.getWeekData())); } + + return MergedBlock(nextBlockweeks.first.getFrameStart(), + nextBlockweeks.last.getFrameEnd(), + mergedWeeks); } ///Verifiziert die im Konstruktor angegebene Excel Datei und überprüft, ob der Stundenplan enthalten ist. diff --git a/lib/ui/screens/teacher_classes/widgets/teacher_class_card.dart b/lib/ui/screens/teacher_classes/widgets/teacher_class_card.dart index ea81561..1072974 100644 --- a/lib/ui/screens/teacher_classes/widgets/teacher_class_card.dart +++ b/lib/ui/screens/teacher_classes/widgets/teacher_class_card.dart @@ -7,6 +7,7 @@ import 'package:logger/logger.dart'; import 'package:sol_connect/core/api/models/schoolclass.dart'; import 'package:sol_connect/core/api/models/utils.dart'; import 'package:sol_connect/core/api/usersession.dart'; +import 'package:sol_connect/core/excel/models/mergedblock.dart'; import 'package:sol_connect/core/excel/models/phasestatus.dart'; import 'package:sol_connect/core/excel/solc_api_manager.dart'; import 'package:sol_connect/core/excel/solcresponse.dart'; @@ -18,7 +19,9 @@ import 'package:sol_connect/ui/themes/app_theme.dart'; import 'package:sol_connect/util/logger.util.dart'; class TeacherClassCard extends StatefulHookConsumerWidget { - const TeacherClassCard({required this.schoolClass, this.phaseStatus, Key? key}) : super(key: key); + const TeacherClassCard( + {required this.schoolClass, this.phaseStatus, Key? key}) + : super(key: key); final SchoolClass schoolClass; final PhaseStatus? phaseStatus; @@ -48,9 +51,11 @@ class _TeacherClassCardState extends ConsumerState { duration: duration, elevation: 20, backgroundColor: backgroundColor, - content: Text(message, style: TextStyle(fontSize: 17, color: theme.colors.text)), + content: Text(message, + style: TextStyle(fontSize: 17, color: theme.colors.text)), shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only(topLeft: Radius.circular(15.0), topRight: Radius.circular(15.0)), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(15.0), topRight: Radius.circular(15.0)), ), )); } @@ -82,8 +87,10 @@ class _TeacherClassCardState extends ConsumerState { log.d( "Virtuelle Phasierung für schoolClass: ${widget.schoolClass.displayName} (${widget.schoolClass.id}) herunterladen ..."); - List bytes = - await ref.read(timeTableService).apiManager!.downloadVirtualSheet(schoolClassId: widget.schoolClass.id); + List bytes = await ref + .read(timeTableService) + .apiManager! + .downloadVirtualSheet(schoolClassId: widget.schoolClass.id); // TODO(debug): Debug timeTable is inactive ref.read(timeTableService).session.setTimetableBehaviour( @@ -100,7 +107,9 @@ class _TeacherClassCardState extends ConsumerState { clearSnachbars: true, duration: const Duration(seconds: 15)); - await ref.read(timeTableService).loadCheckedVirtualPhaseFileForNextBlock(bytes: bytes); + await ref + .read(timeTableService) + .loadCheckedVirtualPhaseFileForNextBlock(bytes: bytes); _createSnackbar( message: "Fertig!", @@ -161,9 +170,13 @@ class _TeacherClassCardState extends ConsumerState { padding: const EdgeInsets.only(right: 10), child: Container( color: widget.phaseStatus != null - ? now.millisecondsSinceEpoch < widget.phaseStatus!.blockStart.millisecondsSinceEpoch + ? now.millisecondsSinceEpoch < + widget.phaseStatus!.blockStart + .millisecondsSinceEpoch ? theme.colors.phaseNotStartet - : now.millisecondsSinceEpoch > widget.phaseStatus!.blockEnd.millisecondsSinceEpoch + : now.millisecondsSinceEpoch > + widget.phaseStatus!.blockEnd + .millisecondsSinceEpoch ? theme.colors.phaseOutOfBlock : theme.colors.phaseActive : theme.colors.phaseNotUploadedJet, @@ -187,8 +200,10 @@ class _TeacherClassCardState extends ConsumerState { children: [ Column( children: [ - Text(Utils.convertToDDMMYY(widget.phaseStatus!.blockStart)), - Text(Utils.convertToDDMMYY(widget.phaseStatus!.blockEnd)) + Text(Utils.convertToDDMMYY( + widget.phaseStatus!.blockStart)), + Text(Utils.convertToDDMMYY( + widget.phaseStatus!.blockEnd)) ], ) ], @@ -214,18 +229,22 @@ class _TeacherClassCardState extends ConsumerState { iconSize: 30, color: theme.colors.textInverted, onPressed: () async { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ["xlsx"], - allowMultiple: false, - dialogTitle: "Phasierung hochladen: ${widget.schoolClass.displayName}"); + FilePickerResult? result = + await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ["xlsx"], + allowMultiple: false, + dialogTitle: + "Phasierung hochladen: ${widget.schoolClass.displayName}"); if (result != null) { setState(() { isUploadLoading = true; }); - final UserSession session = ref.read(timeTableService).session; - final SOLCApiManager manager = ref.read(timeTableService).apiManager!; + final UserSession session = + ref.read(timeTableService).session; + final SOLCApiManager manager = + ref.read(timeTableService).apiManager!; // Step 1: Verify timetable for schoolClass: // TODO(debug): Debug timeTable is inactive @@ -237,38 +256,49 @@ class _TeacherClassCardState extends ConsumerState { ExcelValidator tempValidator = ExcelValidator( manager, - File(result.files.first.path!).readAsBytesSync(), + File(result.files.first.path!) + .readAsBytesSync(), ); - log.d("Verifying sheet for class '${widget.schoolClass.displayName}'"); + log.d( + "Verifying sheet for class '${widget.schoolClass.displayName}'"); String errorMessage = ""; + MergedBlock? mergedBlock; try { _createSnackbar( message: "Phasierung für Klasse ${widget.schoolClass.displayName} überprüfen ...", - backgroundColor: theme.colors.elementBackground, + backgroundColor: + theme.colors.elementBackground, theme: theme, context: context, clearSnachbars: true, duration: const Duration(seconds: 15)); - await tempValidator.mergeExcelWithWholeBlock(session); + mergedBlock = await tempValidator + .mergeExcelWithWholeBlock(session); log.d("Success"); session.resetTimetableBehaviour(); } on ExcelMergeFileNotVerified { - errorMessage = "Kein passender Block- Stundenplan in Datei gefunden!"; + errorMessage = + "Kein passender Block- Stundenplan in Datei gefunden!"; } on ExcelConversionAlreadyActive { - errorMessage = "Unbekannter Fehler. Bitte starte die App neu!"; + errorMessage = + "Unbekannter Fehler. Bitte starte die App neu!"; } on SOLCServerError { - errorMessage = "Ein SOLC-API Server Fehler ist aufgetreten"; + errorMessage = + "Ein SOLC-API Server Fehler ist aufgetreten"; } on FailedToEstablishSOLCServerConnection { - errorMessage = "Bitte überprüfe deine Internetverbindung"; + errorMessage = + "Bitte überprüfe deine Internetverbindung"; } on ExcelMergeNonSchoolBlockException { // Doesn't matter } on SocketException { - errorMessage = "Bitte überprüfe deine Internetverbindung"; + errorMessage = + "Bitte überprüfe deine Internetverbindung"; } on NextBlockStartNotInRangeException { - errorMessage = "Nächster Schulblock kann noch nicht festgestellt werden"; + errorMessage = + "Nächster Schulblock kann noch nicht festgestellt werden"; } on ExcelMergeTimetableNotFound { errorMessage = "Phasierung passt nicht zum Stundenplan der ${widget.schoolClass.displayName}"; @@ -279,14 +309,17 @@ class _TeacherClassCardState extends ConsumerState { if (errorMessage.isNotEmpty) { _createSnackbar( - message: "Überprüfung fehlgeschlagen: $errorMessage", - backgroundColor: theme.colors.errorBackground, + message: + "Überprüfung fehlgeschlagen: $errorMessage", + backgroundColor: + theme.colors.errorBackground, theme: theme, context: context, clearSnachbars: true, duration: const Duration(seconds: 7)); - log.e("Failed to verify sheet: $errorMessage"); + log.e( + "Failed to verify sheet: $errorMessage"); session.resetTimetableBehaviour(); setState(() { @@ -301,37 +334,41 @@ class _TeacherClassCardState extends ConsumerState { try { _createSnackbar( message: "Datei hochladen ...", - backgroundColor: theme.colors.elementBackground, + backgroundColor: + theme.colors.elementBackground, theme: theme, context: context, clearSnachbars: true); - await manager.uploadSheet( - authenticatedUser: ref.read(timeTableService).session, - schoolClassId: widget.schoolClass.id, - blockStart: tempValidator.getBlockStart()!, // Can't be null - blockEnd: tempValidator.getBlockEnd()!, - file: File(result.files.first.path!), - ); + await manager.uploadPhasing( + authenticatedUser: + ref.read(timeTableService).session, + schoolClassId: widget.schoolClass.id, + block: mergedBlock!); + log.d("File uploaded"); _createSnackbar( message: "Fertig!", - backgroundColor: theme.colors.successColor, + backgroundColor: + theme.colors.successColor, theme: theme, context: context, clearSnachbars: true); ref.read(teacherService).toggleReloading(); - await Future.delayed(const Duration(seconds: 2), () { + await Future.delayed( + const Duration(seconds: 2), () { setState(() { isUploadLoading = false; }); }); } catch (e) { _createSnackbar( - message: "Hochladen fehlgeschlagen: ${e.toString()}", - backgroundColor: theme.colors.errorBackground, + message: + "Hochladen fehlgeschlagen: ${e.toString()}", + backgroundColor: + theme.colors.errorBackground, theme: theme, context: context, clearSnachbars: true);