From 85c60adc8d1901cc537d2c5db2d2cff983e93864 Mon Sep 17 00:00:00 2001 From: DevKevYT Date: Mon, 19 Dec 2022 19:05:35 +0100 Subject: [PATCH] Updated cell color to SOLC-API-3 SOLC-API 2.0 #192 --- android/app/build.gradle | 5 +- lib/core/excel/solc_api_manager.dart | 45 +++-- lib/core/excel/validator.dart | 162 ++++++---------- lib/core/service/time_table.service.dart | 11 +- lib/ui/screens/settings/settings.screen.dart | 173 ++++++++++++------ .../settings/widgets/developer_options.dart | 2 +- 6 files changed, 218 insertions(+), 180 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index d0ccc6c..17e43ff 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -26,7 +26,7 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 + compileSdkVersion 31 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -44,9 +44,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "sol.connect" - minSdkVersion 19 + minSdkVersion 18 targetSdkVersion 30 - multiDexEnabled true versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/lib/core/excel/solc_api_manager.dart b/lib/core/excel/solc_api_manager.dart index 33f352a..63774b0 100644 --- a/lib/core/excel/solc_api_manager.dart +++ b/lib/core/excel/solc_api_manager.dart @@ -1,10 +1,13 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'dart:convert' as convert; +import 'package:http/http.dart' as http; 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/phasestatus.dart'; import 'package:sol_connect/core/excel/models/version.dart'; import 'package:sol_connect/core/excel/solcresponse.dart'; @@ -19,32 +22,48 @@ class SOLCApiManager { int _activeSockets = 0; - String _inetAddress; + String _baseURL; int _port; static const int timeoutSeconds = 5; //Throw a timeout if a response does not come within x seconds - static final Version buildRequired = Version.of("2.1.5"); + static final Version buildRequired = Version.of("3.0.0"); - SOLCApiManager(this._inetAddress, this._port); + SOLCApiManager(this._baseURL, this._port); - void setServerAddress(String inetAddress) { - _inetAddress = inetAddress; + void setBaseURL(String baseURL) { + _baseURL = baseURL; } void setServerPort(int port) { _port = port; } - String get inetAddress => _inetAddress; + String get apiAddress => "$_baseURL:$_port/api"; + + String get baseURL => _baseURL; int get port => _port; Future getVersion() async { - SOLCResponse? response = await _querySOLC(command: "version"); - if (response != null) { - return Version.of(response.payload['displayValue']); + 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 { + return Version(0, 0, 0); } - return Version(1, 0, 0); + } + + ///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')); + + http.StreamedResponse response = await request.send(); + if (response.statusCode == 200) { + String json = await convert.utf8.decodeStream(response.stream); + return CellColors(data: jsonDecode(json)['data'], failed: false); + } + return CellColors(failed: true); } ///Wirft eine Exception wenn ein Fehlercode auftritt @@ -100,13 +119,15 @@ class SOLCApiManager { ///* `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(_inetAddress, _port); + final socket = await Socket.connect(_baseURL, _port); //Sende den Befehl socket.writeln(command); @@ -198,7 +219,7 @@ class SOLCApiManager { } on Exception catch (error) { _activeSockets--; throw FailedToEstablishSOLCServerConnection( - "Konnte keine Verbindung zum Konvertierungsserver $_inetAddress herstellen: $error"); + "Konnte keine Verbindung zum Konvertierungsserver $_baseURL herstellen: $error"); } if (exception != null) { throw exception; diff --git a/lib/core/excel/validator.dart b/lib/core/excel/validator.dart index 56ccd85..18f037d 100644 --- a/lib/core/excel/validator.dart +++ b/lib/core/excel/validator.dart @@ -1,6 +1,4 @@ /*Author Philipp Gersch */ -import 'dart:convert'; -import 'dart:io'; import 'package:excel/excel.dart'; import 'package:logger/logger.dart'; import 'package:sol_connect/core/api/models/timetable.hour.dart'; @@ -54,17 +52,12 @@ class MappedPhase { } ///Der "Excel Validator" dient dazu, eine Excel Datei zu überprüfen und wenn diese richtig ist, dem Stundenplan die Phasierung zuzuweisen. -/// -///Das ist eine Beta Version. In dieser darf nur die Excel für eine Woche enthalten sein. In kommenden Versionen wird -///auch der komplett enthaltene Block verarbeitet werden können. class ExcelValidator { final Logger log = getLogger(); final List _fileBytes; Excel? _excel; - bool _queryActive = false; - //Speichere die Farben um beim mehrfachen aufrufen der mergeExcelWithTimetable() Funktion keinen unnötigen traffic zu erzeugen. CellColors _colorData = CellColors(); final _collectedTimetables = []; @@ -123,10 +116,12 @@ class ExcelValidator { ///Wenn keineException geworfen wurde ist der Merge erfolgreich gewesen. Future mergeExcelWithWholeBlock(UserSession session) async { TimeTableRange timeTable = await session.getRelativeTimeTableWeek(0); - var nextBlockweeks = await timeTable.getBoundFrame().getManager().getNextBlockWeeks(); + var nextBlockweeks = + await timeTable.getBoundFrame().getManager().getNextBlockWeeks(); for (TimetableFrame blockWeek in nextBlockweeks) { - log.d("Verifying block week phase merge ${blockWeek.getFrameStart()} -> ${blockWeek.getFrameEnd()}"); + log.d( + "Verifying block week phase merge ${blockWeek.getFrameStart()} -> ${blockWeek.getFrameEnd()}"); await blockWeek.getCurrentBlockWeek(); await mergeExcelWithTimetable(await blockWeek.getWeekData()); @@ -149,33 +144,41 @@ class ExcelValidator { ///* `ExcelConversionServerError`: Wenn ein Fehler Serverseitig aufgetreten ist ///* `FailedToEstablishExcelServerConnection`: Wenn keine Verbindung zum Excel Server hergestellt werden konnte ///* `CurrentPhaseplanOutOfRange`: Wenn die timetable Stunden hat die aber außerhalb des aktuellen Blockes sind. - Future mergeExcelWithTimetable(TimeTableRange timetable, {bool refresh = false}) async { + Future mergeExcelWithTimetable(TimeTableRange timetable, + {bool refresh = false}) async { if (refresh) { _collectedTimetables.clear(); } - _validDateStart ??= await timetable.getBoundFrame().getManager().getNextBlockStart(); - _validDateEnd ??= await timetable.getBoundFrame().getManager().getNextBlockEnd(); + _validDateStart ??= + await timetable.getBoundFrame().getManager().getNextBlockStart(); + _validDateEnd ??= + await timetable.getBoundFrame().getManager().getNextBlockEnd(); if (timetable.isNonSchoolblockWeek()) { - throw ExcelMergeNonSchoolBlockException("Diese Woche enthält keine Schulstunden"); + throw ExcelMergeNonSchoolBlockException( + "Diese Woche enthält keine Schulstunden"); } else { if (_validDateStart != null) { if (timetable.getBoundFrame().getFrameStart().millisecondsSinceEpoch < _validDateStart!.millisecondsSinceEpoch) { - throw CurrentPhaseplanOutOfRange("Dieser Schulblock gehört nicht mehr zur Phasierung!"); + throw CurrentPhaseplanOutOfRange( + "Dieser Schulblock gehört nicht mehr zur Phasierung!"); } } if (_validDateEnd != null) { - if (timetable.getBoundFrame().getFrameStart().millisecondsSinceEpoch >= _validDateEnd!.millisecondsSinceEpoch) { - throw CurrentPhaseplanOutOfRange("Dieser Schulblock gehört nicht mehr zur Phasierung!"); + if (timetable.getBoundFrame().getFrameStart().millisecondsSinceEpoch >= + _validDateEnd!.millisecondsSinceEpoch) { + throw CurrentPhaseplanOutOfRange( + "Dieser Schulblock gehört nicht mehr zur Phasierung!"); } } } //if (refresh || _mapped.isEmpty) { - List foundExcelTimetablesForGivenTimetable = await _verifySheet(timetable); + List foundExcelTimetablesForGivenTimetable = + await _verifySheet(timetable); //} if (foundExcelTimetablesForGivenTimetable.isNotEmpty) { @@ -188,7 +191,8 @@ class ExcelValidator { //+1 weil currentWeek nur der Index ist der bei 0 anfängt //Schließlich vergleiche und verifiziere diesen stundenplan mit dem gemappten Index - MappedSheet verified = _searchRange(mapped.sheet, timetable, startX: mapped.rawX, startY: mapped.rawY); + MappedSheet verified = _searchRange(mapped.sheet, timetable, + startX: mapped.rawX, startY: mapped.rawY); if (verified.startX == mapped.startX && verified.startY == mapped.startY && @@ -199,18 +203,22 @@ class ExcelValidator { //Nicht super schön, aber fürs erste ok while (_colorData.isEmpty() || _colorData.failed) { - await _loadColorData(forceReload: false); + _colorData = await _manager.getExcelColorData(_fileBytes); + if (_colorData.failed) { - log.i("Failed to fetch cell colors"); + log.w("Failed to fetch cell colors"); } } for (MappedPhase hour in mapped.getHours()) { //die x und y sind IMMER die ersten hälften der stunde. Also y+1 ist die 2. hälfte hour._firstHalf = PhaseColor.estimatePhaseFromColor( - _colorData.getColorForCell(xIndex: hour._excelXIndex, yIndex: hour._excelYIndex)); + _colorData.getColorForCell( + xIndex: hour._excelXIndex, yIndex: hour._excelYIndex)); hour._secondHalf = PhaseColor.estimatePhaseFromColor( - _colorData.getColorForCell(xIndex: hour._excelXIndex, yIndex: hour._excelYIndex + 1)); + _colorData.getColorForCell( + xIndex: hour._excelXIndex, + yIndex: hour._excelYIndex + 1)); } //############################## @@ -228,86 +236,15 @@ class ExcelValidator { "Stelle sicher, dass in der Excel ein Stundenplan mit der überschrift 'Woche ${currentWeek + 1}' existiert und dieser auch in die angegebene Woche passt."); } - throw ExcelMergeFileNotVerified("Es konnte kein gültiger Stundenplan auf der Excel Datei gefunden werden."); - } - - ///Sendet eine Anfrage an den Server in 4 Schritten: - ///* Den befehl: In diesem Fall "convertxssf". Dieser signalisiert dem Server, dass gleich eine Excel Datei kommt, die er bitte umwandeln soll (Zellenfarben) - ///* Warten auf die Bestätigung: Wenn der Server berit ist die Excel zu empfangen, sendet er ein "ready" zurück. - ///* Excel als Stream an den Server senden - ///* Daten in ein "CellColors" Objekt umwandeln und zurückgeben - /// - ///Wenn ein Error auftritt wird er geworfen. - ///Diese Funktion kann nicht aufgerufen werden bis eine gestellte Abfrage abgearbeitet wurde. - Future _loadColorData({bool forceReload = false}) async { - if (!_colorData.isEmpty() && !forceReload) return _colorData; - - _colorData = CellColors(); - - if (_queryActive) { - throw ExcelConversionAlreadyActive("Zellenfarben werden bereits beschafft"); - } - - try { - _queryActive = true; - final socket = await Socket.connect(_manager.inetAddress, _manager.port); - - //Sende den Befehl - socket.writeln("convertxssf"); - await socket.flush(); - - var subscription = socket.listen( - (event) async { - // String message = String.fromCharCodes(event); - // print(String.fromCharCodes(event)); - dynamic decodedMessage = ""; - try { - decodedMessage = jsonDecode(String.fromCharCodes(event)); - } on FormatException { - _colorData = CellColors(data: null, failed: true); - socket.close(); - return; - } - - if (decodedMessage['error'] != null) { - throw SOLCServerError( - "Ein Fehler ist bei der Beschaffung der Zellenfarben aufgetreten: ${decodedMessage['error']}"); - } - - if (decodedMessage['message'] != null) { - if (decodedMessage['message'] == "ready-for-file") { - socket.add(_fileBytes); - await socket.flush(); - } else { - _colorData = CellColors(data: decodedMessage['data']); - } - } - }, - onError: (error) { - _queryActive = false; - throw SOLCServerError("Ein Fehler ist bei der Beschaffung der Zellenfarben aufgetreten: $error"); - }, - onDone: () { - //Alles OK! - _queryActive = false; - }, - ); - - await subscription.asFuture(); - await subscription.cancel(); - _queryActive = false; - return _colorData; - } on Exception catch (error) { - _queryActive = false; - throw FailedToEstablishSOLCServerConnection( - "Konnte keine Verbindung zum Konvertierungsserver ${_manager.inetAddress} herstellen: $error"); - } + throw ExcelMergeFileNotVerified( + "Es konnte kein gültiger Stundenplan auf der Excel Datei gefunden werden."); } ///Das sheet konnte nicht verifiziert werden, wenn das gemappte sheet leer ist Future> _verifySheet(TimeTableRange range) async { for (MappedSheet saved in _collectedTimetables) { - if ((await range.getBoundFrame().getCurrentBlockWeek() + 1) == saved.blockWeek) { + if ((await range.getBoundFrame().getCurrentBlockWeek() + 1) == + saved.blockWeek) { return [saved]; } } @@ -323,7 +260,9 @@ class ExcelValidator { yIndex: j, excelWidth: _excel!.tables[table]!.maxCols, excelHeight: _excel!.tables[table]!.maxRows)) { - MappedSheet mappedTimetable = _searchRange(_excel!.tables[table]!, range, startX: i, startY: j); + MappedSheet mappedTimetable = _searchRange( + _excel!.tables[table]!, range, + startX: i, startY: j); if (mappedTimetable.isValid()) { mappedSheets.add(mappedTimetable); @@ -338,7 +277,10 @@ class ExcelValidator { //Errechnet mit den Excel boundaries und bestehenden Stundenplänen ob es sich lohnt den aktuellen index nach einem Stundenplan abzusuchen. //Einfach nur um den Code etwas schneller zu machen bool _worthSearching(List mappedSheets, - {int xIndex = 0, int yIndex = 0, int excelWidth = 0, int excelHeight = 0}) { + {int xIndex = 0, + int yIndex = 0, + int excelWidth = 0, + int excelHeight = 0}) { bool worth = true; for (MappedSheet existing in mappedSheets) { @@ -357,9 +299,14 @@ class ExcelValidator { return worth; } - MappedSheet _searchRange(Sheet sheet, TimeTableRange range, {int startX = 0, int startY = 0}) { + MappedSheet _searchRange(Sheet sheet, TimeTableRange range, + {int startX = 0, int startY = 0}) { MappedSheet mapped = MappedSheet(sheet); - if (sheet.cell(CellIndex.indexByColumnRow(columnIndex: startX, rowIndex: startY)).value == null) { + if (sheet + .cell(CellIndex.indexByColumnRow( + columnIndex: startX, rowIndex: startY)) + .value == + null) { return mapped; } @@ -370,15 +317,19 @@ class ExcelValidator { excelY = startY; for (int ty = 0; ty < 8; ty++, excelY++) { TimeTableHour hour = range.getHourByIndex(xIndex: tx, yIndex: ty); - Data cell = sheet.cell(CellIndex.indexByColumnRow(columnIndex: excelX, rowIndex: excelY)); + Data cell = sheet.cell( + CellIndex.indexByColumnRow(columnIndex: excelX, rowIndex: excelY)); if (hour.lessonCode == Codes.irregular) { hour = hour.replacement; } - String cellValueString = cell.value == null ? "null" : cell.value.toString(); + String cellValueString = + cell.value == null ? "null" : cell.value.toString(); - if (cellValueString.toLowerCase().contains(hour.teacher.name.toString().toLowerCase()) || + if (cellValueString + .toLowerCase() + .contains(hour.teacher.name.toString().toLowerCase()) || hour.teacher.name == "---" || cellValueString == "null" || hour.lessonCode == Codes.empty || @@ -403,7 +354,8 @@ class ExcelValidator { mapped.rawY = startY; //-1: Erst mal davon ausgehen, dass über den Stunden der Tag angegeben ist (Und darüber die Woche vom Block) und links die Stundennummern mapped.startX = startX - 1; - mapped.startY = startY - 2 < 0 ? (startY - 1 < 0 ? startY : startY - 1) : startY - 2; + mapped.startY = + startY - 2 < 0 ? (startY - 1 < 0 ? startY : startY - 1) : startY - 2; //Etwas irreführend. excelX und y werden durch den loop erhöht. Dadurch ergibt sich am ende automatisch die höhe und Breite mapped.width = excelX - 1; mapped.height = excelY - 1; diff --git a/lib/core/service/time_table.service.dart b/lib/core/service/time_table.service.dart index 736ed8e..96a13e7 100644 --- a/lib/core/service/time_table.service.dart +++ b/lib/core/service/time_table.service.dart @@ -35,7 +35,7 @@ class TimeTableService with ChangeNotifier { Future getServerAddress() async { final prefs = await SharedPreferences.getInstance(); - return prefs.getString("serverAddress") ?? "flo-dev.me"; + return "http://localhost"; //prefs.getString("serverAddress") ?? "flo-dev.me"; } Future login( @@ -49,19 +49,22 @@ class TimeTableService with ChangeNotifier { notifyListeners(); //apiManager = SOLCApiManager(await getServerAddress(), 6969); - apiManager = SOLCApiManager(await getServerAddress(), 6969); + apiManager = SOLCApiManager(await getServerAddress(), 8080); apiManager!.getVersion().then( (value) { //Dieser Build benötigt Server version > 2.1.5 if (Version.isOlder(value, SOLCApiManager.buildRequired)) { log.e( - "This build requires SOLC-API Server version > v${SOLCApiManager.buildRequired} (${apiManager!.inetAddress} running on: v$value) Unexpected errors may happen!"); + "This build requires SOLC-API Server version > v${SOLCApiManager.buildRequired} (${apiManager!.baseURL} running on: v$value) Unexpected errors may happen!"); + } else { + log.i("Verified SOLC-API server version. (${apiManager!.baseURL}:${apiManager!.port} running on: v$value)"); } }, ).catchError( (error, stackTrace) { - log.w("Failed to verify SOLC-API Server version. Unexpected errors may happen!"); + log.e(stackTrace); + log.w("Failed to verify SOLC-API Server version. Unexpected errors may happen! ($error)"); }, ); diff --git a/lib/ui/screens/settings/settings.screen.dart b/lib/ui/screens/settings/settings.screen.dart index 065e7a7..57d21a3 100644 --- a/lib/ui/screens/settings/settings.screen.dart +++ b/lib/ui/screens/settings/settings.screen.dart @@ -36,14 +36,17 @@ class SettingsScreen extends ConsumerWidget { bool lightMode; bool working = false; - SnackBar createSnackbar(String message, Color backgroundColor, {Duration duration = const Duration(seconds: 4)}) { + SnackBar createSnackbar(String message, Color backgroundColor, + {Duration duration = const Duration(seconds: 4)}) { return SnackBar( 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)), ), ); } @@ -69,7 +72,8 @@ class SettingsScreen extends ConsumerWidget { onTap: () => FocusManager.instance.primaryFocus?.unfocus(), child: Scaffold( appBar: AppBar( - title: Text('Einstellungen', style: TextStyle(color: theme.colors.text)), + title: + Text('Einstellungen', style: TextStyle(color: theme.colors.text)), backgroundColor: theme.colors.primary, leading: BackButton(color: theme.colors.icon), ), @@ -82,7 +86,8 @@ class SettingsScreen extends ConsumerWidget { controller: scrollController, children: [ Visibility( - visible: ref.read(timeTableService).session.personType != PersonTypes.teacher, + visible: ref.read(timeTableService).session.personType != + PersonTypes.teacher, child: Center( child: Padding( padding: const EdgeInsets.only(top: 25.0), @@ -100,8 +105,10 @@ class SettingsScreen extends ConsumerWidget { ), ), Visibility( - visible: ref.read(timeTableService).session.personType != PersonTypes.teacher && - !ref.read(timeTableService).isPhaseVerified, + visible: + ref.read(timeTableService).session.personType != + PersonTypes.teacher && + !ref.read(timeTableService).isPhaseVerified, child: CustomSettingsCard( padBottom: 5, leading: Icon( @@ -116,22 +123,31 @@ class SettingsScreen extends ConsumerWidget { } working = true; - final SOLCApiManager manager = ref.read(timeTableService).apiManager!; - final int schoolClassId = ref.read(timeTableService).session.schoolClassId; + final SOLCApiManager manager = + ref.read(timeTableService).apiManager!; + final int schoolClassId = ref + .read(timeTableService) + .session + .schoolClassId; ScaffoldMessenger.of(context).clearSnackBars(); //Schritt 1: Überprüfe ob die herunterzuladene Datei noch aktuell ist / existiert# ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - "Überprüfe, ob eine Phasierung verfügbar ist ...", theme.colors.elementBackground, - duration: const Duration(seconds: SOLCApiManager.timeoutSeconds)), + "Überprüfe, ob eine Phasierung verfügbar ist ...", + theme.colors.elementBackground, + duration: const Duration( + seconds: SOLCApiManager.timeoutSeconds)), ); log.d("Checking file status on server ..."); try { - PhaseStatus? status = await manager.getSchoolClassInfo(schoolClassId: schoolClassId); + PhaseStatus? status = + await manager.getSchoolClassInfo( + schoolClassId: schoolClassId); - if (DateTime.now().millisecondsSinceEpoch >= status!.blockEnd.millisecondsSinceEpoch) { + if (DateTime.now().millisecondsSinceEpoch >= + status!.blockEnd.millisecondsSinceEpoch) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( @@ -145,8 +161,10 @@ class SettingsScreen extends ConsumerWidget { } } on SOLCServerError catch (e) { log.e("Server Error: $e"); - if (e.response.responseCode == SOLCResponse.CODE_FILE_MISSING || - e.response.responseCode == SOLCResponse.CODE_ENTRY_MISSING) { + if (e.response.responseCode == + SOLCResponse.CODE_FILE_MISSING || + e.response.responseCode == + SOLCResponse.CODE_ENTRY_MISSING) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( @@ -161,7 +179,8 @@ class SettingsScreen extends ConsumerWidget { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - "Fehler beim Verbindungsaufbau zum Server", theme.colors.errorBackground), + "Fehler beim Verbindungsaufbau zum Server", + theme.colors.errorBackground), ); working = false; return; @@ -169,7 +188,8 @@ class SettingsScreen extends ConsumerWidget { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - "Zeitüberschreitung bei der Serververbindung", theme.colors.errorBackground), + "Zeitüberschreitung bei der Serververbindung", + theme.colors.errorBackground), ); working = false; return; @@ -177,7 +197,8 @@ class SettingsScreen extends ConsumerWidget { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - "Ein unbekannter Fehler ist aufgetreten: $e", theme.colors.errorBackground, + "Ein unbekannter Fehler ist aufgetreten: $e", + theme.colors.errorBackground, duration: const Duration(seconds: 10)), ); working = false; @@ -187,17 +208,21 @@ class SettingsScreen extends ConsumerWidget { //Schritt 2: Downloade die Phasierung ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( - createSnackbar("Phasierung herunterladen ...", theme.colors.elementBackground), + createSnackbar("Phasierung herunterladen ...", + theme.colors.elementBackground), ); - log.d("Downloading sheet for class $schoolClassId ..."); + log.d( + "Downloading sheet for class $schoolClassId ..."); List bytes; try { - bytes = await manager.downloadVirtualSheet(schoolClassId: schoolClassId); + bytes = await manager.downloadVirtualSheet( + schoolClassId: schoolClassId); } catch (e) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - "Ein unerwarteter Serverfehler ist aufgetreten: ($e)", theme.colors.errorBackground, + "Ein unerwarteter Serverfehler ist aufgetreten: ($e)", + theme.colors.errorBackground, duration: const Duration(seconds: 8)), ); working = false; @@ -207,7 +232,8 @@ class SettingsScreen extends ConsumerWidget { //Schritt 3: Lade Phasierung ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( - createSnackbar("Phasierung laden ...", theme.colors.elementBackground, + createSnackbar("Phasierung laden ...", + theme.colors.elementBackground, duration: const Duration(seconds: 15)), ); log.d("Versuche Phasierung zu laden ..."); @@ -217,11 +243,16 @@ class SettingsScreen extends ConsumerWidget { // .session // .setTimetableBehaviour(0, PersonTypes.student, debug: true); try { - await ref.read(timeTableService).loadCheckedVirtualPhaseFileForNextBlock(bytes: bytes); + await ref + .read(timeTableService) + .loadCheckedVirtualPhaseFileForNextBlock( + bytes: bytes); - ScaffoldMessenger.maybeOf(context)!.clearSnackBars(); + ScaffoldMessenger.maybeOf(context)! + .clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( - createSnackbar("Fertig!", theme.colors.successColor), + createSnackbar( + "Fertig!", theme.colors.successColor), ); } on NextBlockStartNotInRangeException { ScaffoldMessenger.of(context).clearSnackBars(); @@ -235,7 +266,8 @@ class SettingsScreen extends ConsumerWidget { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - "Bitte überprüfe deine Internetverbindung", theme.colors.errorBackground), + "Bitte überprüfe deine Internetverbindung", + theme.colors.errorBackground), ); } catch (e) { ScaffoldMessenger.of(context).clearSnackBars(); @@ -247,22 +279,28 @@ class SettingsScreen extends ConsumerWidget { ); } - Future.delayed(const Duration(seconds: 4)).then((value) { + Future.delayed(const Duration(seconds: 4)) + .then((value) { working = false; }); }, )), Visibility( - visible: ref.read(timeTableService).session.personType != PersonTypes.teacher, + visible: ref.read(timeTableService).session.personType != + PersonTypes.teacher, child: CustomSettingsCard( padTop: 5, padBottom: 0, leading: Icon( - phaseLoaded ? Icons.delete_rounded : Icons.folder_open_sharp, + phaseLoaded + ? Icons.delete_rounded + : Icons.folder_open_sharp, color: theme.colors.text, size: 26, ), - text: phaseLoaded ? "Phasierung entfernen" : "Eigene Phasierung laden", + text: phaseLoaded + ? "Phasierung entfernen" + : "Eigene Phasierung laden", onTap: () async { if (working) { return; @@ -273,17 +311,19 @@ class SettingsScreen extends ConsumerWidget { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( - createSnackbar("Phasierung entfernt", theme.colors.elementBackground), + createSnackbar("Phasierung entfernt", + theme.colors.elementBackground), ); working = false; return; } - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ["xlsx"], - allowMultiple: false, - dialogTitle: "Phasierung laden"); + FilePickerResult? result = await FilePicker.platform + .pickFiles( + type: FileType.custom, + allowedExtensions: ["xlsx"], + allowMultiple: false, + dialogTitle: "Phasierung laden"); if (result != null) { ScaffoldMessenger.of(context).showSnackBar( @@ -297,20 +337,29 @@ class SettingsScreen extends ConsumerWidget { String errorMessage = ""; try { - await ref.read(timeTableService).loadCheckedVirtualPhaseFileForNextBlock( - bytes: File(result.files.first.path!).readAsBytesSync(), persistent: true); + await ref + .read(timeTableService) + .loadCheckedVirtualPhaseFileForNextBlock( + bytes: File(result.files.first.path!) + .readAsBytesSync(), + persistent: true); } 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 ExcelMergeTimetableNotFound catch (e) { errorMessage = e.toString(); } catch (e) { @@ -318,18 +367,25 @@ class SettingsScreen extends ConsumerWidget { errorMessage = "Unbekannter Fehler: $e"; } - ScaffoldMessengerState? state = ScaffoldMessenger.maybeOf(context); + ScaffoldMessengerState? state = + ScaffoldMessenger.maybeOf(context); if (state != null) { - ScaffoldMessenger.maybeOf(context)!.clearSnackBars(); + ScaffoldMessenger.maybeOf(context)! + .clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( createSnackbar( - errorMessage == "" ? "Phasierung für aktuellen Block geladen!" : errorMessage, - errorMessage == "" ? theme.colors.successColor : theme.colors.errorBackground, + errorMessage == "" + ? "Phasierung für aktuellen Block geladen!" + : errorMessage, + errorMessage == "" + ? theme.colors.successColor + : theme.colors.errorBackground, ), ); } - Future.delayed(const Duration(seconds: 4)).then((value) { + Future.delayed(const Duration(seconds: 4)) + .then((value) { working = false; }); } @@ -345,23 +401,28 @@ class SettingsScreen extends ConsumerWidget { color: theme.colors.successColor, ), child: Padding( - padding: const EdgeInsets.fromLTRB(10, 8, 5, 10), + padding: + const EdgeInsets.fromLTRB(10, 8, 5, 10), child: Text( validator != null ? "Phasierung geladen für Block ${Utils.convertToDDMM(validator.getBlockStart())} bis ${Utils.convertToDDMM(validator.getBlockEnd())}" : "Phasierung geladen für Block ? - ?", - style: TextStyle(fontSize: 13, color: theme.colors.textInverted), + style: TextStyle( + fontSize: 13, + color: theme.colors.textInverted), ), ), ), ) - : const Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 0)), + : const Padding( + padding: EdgeInsets.fromLTRB(0, 0, 0, 0)), Center( child: Padding( padding: const EdgeInsets.only(top: 25.0), child: Text( "Erscheinungsbild", - style: TextStyle(fontSize: 25, color: theme.colors.textInverted), + style: TextStyle( + fontSize: 25, color: theme.colors.textInverted), ), ), ), @@ -395,7 +456,8 @@ class SettingsScreen extends ConsumerWidget { padding: const EdgeInsets.only(top: 25.0), child: Text( "App Info", - style: TextStyle(fontSize: 25, color: theme.colors.textInverted), + style: TextStyle( + fontSize: 25, color: theme.colors.textInverted), ), ), ), @@ -406,7 +468,8 @@ class SettingsScreen extends ConsumerWidget { ), text: "Github Projekt", onTap: () async { - String url = "https://github.com/floodoo/untis_phasierung"; + String url = + "https://github.com/floodoo/untis_phasierung"; if (!await launchUrlString(url)) { throw "Could not launch $url"; } diff --git a/lib/ui/screens/settings/widgets/developer_options.dart b/lib/ui/screens/settings/widgets/developer_options.dart index 19e6990..16c7dd8 100644 --- a/lib/ui/screens/settings/widgets/developer_options.dart +++ b/lib/ui/screens/settings/widgets/developer_options.dart @@ -56,7 +56,7 @@ class DeveloperOptions extends ConsumerWidget { onEditingComplete: () { if (serverAdressTextController.text != "") { ref.read(settingsService).saveServerAdress(serverAdressTextController.text); - ref.read(timeTableService).apiManager!.setServerAddress(serverAdressTextController.text); + ref.read(timeTableService).apiManager!.setBaseURL(serverAdressTextController.text); } serverAdressTextController.clear(); FocusManager.instance.primaryFocus?.unfocus();