From ee1239750f6d4b6932c105ab1cc5f08b9715cd50 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sat, 20 Apr 2024 15:15:27 +0200 Subject: [PATCH] Add DSBDownloader Add update DSBActivity MainContent --- app/src/main/AndroidManifest.xml | 2 + .../com/schoolapp/cleverclass/DSBActivity.kt | 43 ++++- .../schoolapp/cleverclass/DSBDownloader.kt | 179 ++++++++++++++++++ 3 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 app/src/main/java/com/schoolapp/cleverclass/DSBDownloader.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 09030d8..d2c4e7f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + + DayPrefab(folder = folder) + Spacer(modifier = Modifier.height(48.dp)) + } } } -} \ No newline at end of file +} + +@Composable +fun DayPrefab(folder: File){ + val imageFiles = folder.listFiles { file -> file.extension == "jpg" }?.toList() + + Column { + imageFiles?.forEach { + val imageBitmap = BitmapFactory.decodeFile(it.absolutePath) + + Image(bitmap = imageBitmap.asImageBitmap(), contentDescription = null) + Spacer(modifier = Modifier.height(8.dp)) + } + } +} diff --git a/app/src/main/java/com/schoolapp/cleverclass/DSBDownloader.kt b/app/src/main/java/com/schoolapp/cleverclass/DSBDownloader.kt new file mode 100644 index 0000000..f7089e1 --- /dev/null +++ b/app/src/main/java/com/schoolapp/cleverclass/DSBDownloader.kt @@ -0,0 +1,179 @@ +package com.schoolapp.cleverclass + +import android.content.Context +import android.util.Base64 +import android.util.Log +import org.json.JSONObject +import java.io.ByteArrayOutputStream +import java.io.File +import java.net.HttpURLConnection +import java.net.URL +import java.util.zip.GZIPInputStream +import java.util.zip.GZIPOutputStream +import java.io.ByteArrayInputStream +import java.io.FileOutputStream +import java.time.LocalDateTime +import java.util.UUID + + +suspend fun downloadDSB(context: Context){ + val mainDir = createDataFolder(context) + + val jsonResponse = downloadDataTask() + + downloadImagesTask(jsonResponse, mainDir) +} + +private fun downloadDataTask() : String { + return try { + val requestBody = createRequestBody() + val jsonRequest = createJsonRequest(requestBody) + + val responseData = fetchData(jsonRequest) + + responseData + } catch (e: Exception) { + Log.e("HTTP", "Error: ${e.message}") + "-1" + } +} + +private fun createRequestBody(): String { + val username = "149002" + val password = "Vertretungsplan" + val currentDateTime = LocalDateTime.now().toString() + + val requestBody = JSONObject().apply { + put("UserId", username) + put("UserPw", password) + put("AppVersion", "2.5.9") + put("Language", "de") + put("OsVersion", "28 8.0") + put("AppId", UUID.randomUUID().toString()) + put("Device", "SM-G930F") + put("BundleId", "de.heinekingmedia.dsbmobile") + put("Date", currentDateTime) + put("LastUpdate", currentDateTime) + } + + return Base64.encodeToString(GZIPCompress(requestBody.toString().toByteArray()), Base64.DEFAULT) +} + +private fun createJsonRequest(requestBody: String): JSONObject { + return JSONObject().apply { + put("req", JSONObject().apply { + put("Data", requestBody) + put("DataType", 1) + }) + } +} + +private fun fetchData(jsonRequest: JSONObject): String { + val url = URL("https://app.dsbcontrol.de/JsonHandler.ashx/GetData") + val connection = (url.openConnection() as HttpURLConnection).apply { + requestMethod = "POST" + setRequestProperty("Content-Type", "application/json") + doOutput = true + } + + connection.outputStream.use { outputStream -> + outputStream.write(jsonRequest.toString().toByteArray()) + } + + return if (connection.responseCode == HttpURLConnection.HTTP_OK) { + val responseData = connection.inputStream.bufferedReader().use { it.readText() } + val compressedResponseData = JSONObject(responseData).getString("d") + decompressGZIPAndDecodeBase64(compressedResponseData) + } else { + Log.e("HTTP", "Error response code: ${connection.responseCode}") + "" + } +} + +private fun GZIPCompress(data: ByteArray): ByteArray { + return ByteArrayOutputStream().use { outputStream -> + GZIPOutputStream(outputStream).bufferedWriter().use { it.write(String(data)) } + outputStream.toByteArray() + } +} + +private fun decompressGZIPAndDecodeBase64(compressedData: String): String { + val compressedByteArray = Base64.decode(compressedData, Base64.DEFAULT) + val inputStream = ByteArrayInputStream(compressedByteArray) + val outputStream = ByteArrayOutputStream() + GZIPInputStream(inputStream).use { gzipInputStream -> + val buffer = ByteArray(1024) + var len: Int + while (gzipInputStream.read(buffer).also { len = it } > 0) { + outputStream.write(buffer, 0, len) + } + } + return outputStream.toString("UTF-8") +} + +private fun downloadImagesTask(jsonResponse: String, mainDir : File){ + clearFolder(mainDir) + + val jsonResponseObject = JSONObject(jsonResponse) + val jsonDaysObject = jsonResponseObject.getJSONArray("ResultMenuItems").getJSONObject(0).getJSONArray("Childs").getJSONObject(0).getJSONObject("Root").getJSONArray("Childs") + + for (d in 0 until jsonDaysObject.length()) { + val jsonDayObject = jsonDaysObject.getJSONObject(d) + val dayID = jsonDayObject.get("Id") + + val day = File(mainDir, dayID.toString()) + day.mkdir() + + val jsonPagesObject = jsonDayObject.getJSONArray("Childs") + + for (p in 0 until jsonPagesObject.length()) { + val jsonPageObject = jsonPagesObject.getJSONObject(p) + val pageIndex = jsonPageObject.get("Index") + val imageLink = jsonPageObject.get("Detail").toString() + + downloadImage(day, URL(imageLink), "$pageIndex.jpg") + } + } +} + +private fun downloadImage(folder: File, url: URL, fileName: String){ + val file = File(folder, fileName) + + val connection = url.openConnection() + val inputStream = connection.getInputStream() + val outputStream = FileOutputStream(file) + + val buffer = ByteArray(1024) + var bytesRead: Int + + while (inputStream.read(buffer).also { bytesRead = it } != -1) { + outputStream.write(buffer, 0, bytesRead) + } + + inputStream.close() + outputStream.close() +} + +private fun createDataFolder(context: Context) : File { + val folderName = "dataDSB" + val folder = File(context.filesDir, folderName) + + if (!folder.exists()) { + folder.mkdir() + } + return folder +} + +private fun clearFolder(directory: File) { + if (directory.exists()) { + val files = directory.listFiles() + if (files != null) { + for (file in files) { + if (file.isDirectory) { + clearFolder(file) + } + file.delete() + } + } + } +} \ No newline at end of file