Add DSBDownloader

Add update DSBActivity MainContent
This commit is contained in:
BuildTools
2024-04-20 15:15:27 +02:00
parent 6e24a54682
commit ee1239750f
3 changed files with 221 additions and 3 deletions

View File

@@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"

View File

@@ -1,12 +1,18 @@
package com.schoolapp.cleverclass
import android.graphics.BitmapFactory
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -19,12 +25,24 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.unit.dp
import com.schoolapp.cleverclass.ui.theme.CleverClassTheme
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.File
class DSBActivity : ComponentActivity() {
@OptIn(DelicateCoroutinesApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GlobalScope.launch(Dispatchers.IO) {
downloadDSB(this@DSBActivity)
}
setContent {
CleverClassTheme {
Surface(
@@ -42,7 +60,7 @@ class DSBActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DSBContent(activity: ComponentActivity){
Column() {
Column {
TopAppBar(
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(MaterialTheme.colorScheme.primaryContainer),
title = {
@@ -63,8 +81,27 @@ fun DSBContent(activity: ComponentActivity){
modifier = Modifier.fillMaxWidth()
)
Column() {
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
val mainFolder = File(activity.filesDir, "dataDSB")
mainFolder.listFiles()?.forEach { folder ->
DayPrefab(folder = folder)
Spacer(modifier = Modifier.height(48.dp))
}
}
}
}
}
@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))
}
}
}

View File

@@ -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()
}
}
}
}