Finish DSBmobile
This commit is contained in:
10
.idea/deploymentTargetDropDown.xml
generated
10
.idea/deploymentTargetDropDown.xml
generated
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="deploymentTargetDropDown">
|
|
||||||
<value>
|
|
||||||
<entry key="app">
|
|
||||||
<State />
|
|
||||||
</entry>
|
|
||||||
</value>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -61,11 +61,13 @@ dependencies {
|
|||||||
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
implementation("androidx.datastore:datastore-preferences:1.0.0")
|
||||||
implementation("com.google.code.gson:gson:2.9.0")
|
implementation("com.google.code.gson:gson:2.9.0")
|
||||||
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||||
|
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||||
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||||
|
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,11 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.CleverClass"
|
android:theme="@style/Theme.CleverClass"
|
||||||
tools:targetApi="31">
|
tools:targetApi="31">
|
||||||
|
<activity
|
||||||
|
android:name=".DSBLoginActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:label="@string/title_activity_dsblogin"
|
||||||
|
android:theme="@style/Theme.CleverClass" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".DSBDayViewActivity"
|
android:name=".DSBDayViewActivity"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.schoolapp.cleverclass
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
@@ -20,7 +21,6 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -31,6 +31,7 @@ import androidx.compose.material3.Text
|
|||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -54,12 +55,23 @@ class DSBActivity : ComponentActivity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val sharedPreferences = this.getSharedPreferences("DSBmobile", Context.MODE_PRIVATE)
|
||||||
|
val username = sharedPreferences.getString("username", "").toString()
|
||||||
|
val password = sharedPreferences.getString("password", "").toString()
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
CleverClassTheme {
|
CleverClassTheme {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
color = MaterialTheme.colorScheme.background
|
color = MaterialTheme.colorScheme.background
|
||||||
) {
|
) {
|
||||||
|
if(username.isEmpty() || password.isEmpty()) {
|
||||||
|
val intent = Intent(this@DSBActivity, DSBLoginActivity::class.java).apply {
|
||||||
|
putExtra(DSBLoginActivity.TYPE_KEY, "FirstTime")
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
DSBContent(activity = this)
|
DSBContent(activity = this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,13 +83,20 @@ class DSBActivity : ComponentActivity() {
|
|||||||
@OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class)
|
@OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun DSBContent(activity: ComponentActivity){
|
fun DSBContent(activity: ComponentActivity){
|
||||||
|
val mainFolder = File(activity.filesDir, "dataDSB")
|
||||||
|
val sharedPreferences = activity.getSharedPreferences("DSBmobile", Context.MODE_PRIVATE)
|
||||||
|
|
||||||
var loadingState by remember {
|
var loadingState by remember {
|
||||||
mutableStateOf(1)
|
mutableStateOf(-2)
|
||||||
|
}
|
||||||
|
var folders by remember {
|
||||||
|
mutableStateOf(mainFolder.listFiles())
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
loadingState = downloadDSB(activity)
|
loadingState = downloadDSB(activity)
|
||||||
|
folders = mainFolder.listFiles()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,12 +119,13 @@ fun DSBContent(activity: ComponentActivity){
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
if(loadingState != 1) {
|
if(loadingState != -2) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
loadingState = 1
|
loadingState = -2
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
loadingState = downloadDSB(activity)
|
loadingState = downloadDSB(activity)
|
||||||
|
folders = mainFolder.listFiles()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
@@ -122,13 +142,16 @@ fun DSBContent(activity: ComponentActivity){
|
|||||||
)
|
)
|
||||||
|
|
||||||
when (loadingState) {
|
when (loadingState) {
|
||||||
1 -> {
|
-2 -> {
|
||||||
DSBLoading()
|
LoadingScreen()
|
||||||
}
|
}
|
||||||
-1 -> {
|
NO_INTERNET_CONNECTION_CODE -> {
|
||||||
DSBNoInternet()
|
DSBError("Keine Internetverbindung")
|
||||||
}
|
}
|
||||||
else -> {
|
1 ->{
|
||||||
|
DSBError("Login fehlgeschlagen")
|
||||||
|
}
|
||||||
|
0 -> {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -137,9 +160,7 @@ fun DSBContent(activity: ComponentActivity){
|
|||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
val mainFolder = File(activity.filesDir, "dataDSB")
|
folders.forEach { folder ->
|
||||||
|
|
||||||
mainFolder.listFiles()?.forEach { folder ->
|
|
||||||
DayPrefab(folder, activity)
|
DayPrefab(folder, activity)
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
Divider()
|
Divider()
|
||||||
@@ -147,28 +168,43 @@ fun DSBContent(activity: ComponentActivity){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else -> {
|
||||||
|
DSBError("Leider ist ein Problem aufgetreten\nFehlercode: $loadingState")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// changes state when Shared Preference is updated
|
||||||
|
val observer = remember {
|
||||||
|
SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||||
|
if (key == "password" || key == "username") {
|
||||||
|
loadingState = -2
|
||||||
|
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
loadingState = downloadDSB(activity)
|
||||||
|
folders = mainFolder.listFiles()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handles observer disposal
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
sharedPreferences.registerOnSharedPreferenceChangeListener(observer)
|
||||||
|
onDispose {
|
||||||
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(observer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun DSBLoading(){
|
fun DSBError(message: String){
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
){
|
|
||||||
CircularProgressIndicator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun DSBNoInternet(){
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
){
|
){
|
||||||
Text(
|
Text(
|
||||||
text = "Keine Internetverbindung",
|
text = message,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.onBackground
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ fun DSBDayViewContent(activity: ComponentActivity){
|
|||||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(MaterialTheme.colorScheme.primaryContainer),
|
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(MaterialTheme.colorScheme.primaryContainer),
|
||||||
title = {
|
title = {
|
||||||
Text(
|
Text(
|
||||||
text = information.get("PlanInfo").toString(),
|
text = information.get("PlanInfo").toString().removeSuffix(".pdf"),
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
color = MaterialTheme.colorScheme.onPrimaryContainer
|
color = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
)},
|
)},
|
||||||
|
|||||||
@@ -14,26 +14,31 @@ import java.util.zip.GZIPInputStream
|
|||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
|
import java.net.SocketException
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
|
||||||
suspend fun downloadDSB(context: Context): Int{
|
suspend fun downloadDSB(context: Context): Int{
|
||||||
|
val sharedPreferences = context.getSharedPreferences("DSBmobile", Context.MODE_PRIVATE)
|
||||||
|
val username = sharedPreferences.getString("username", "").toString()
|
||||||
|
val password = sharedPreferences.getString("password", "").toString()
|
||||||
|
|
||||||
if(!isInternetAvailable(context))
|
if(!isInternetAvailable(context))
|
||||||
return -1
|
return NO_INTERNET_CONNECTION_CODE
|
||||||
|
|
||||||
val mainDir = createDataFolder(context)
|
val mainDir = createDataFolder(context)
|
||||||
|
|
||||||
val jsonResponse = downloadDataTask()
|
val jsonResponse = JSONObject(downloadDataTask(username = username, password = password))
|
||||||
|
if(jsonResponse.get("Resultcode") != 0)
|
||||||
|
return jsonResponse.getInt("Resultcode")
|
||||||
|
|
||||||
downloadImagesTask(jsonResponse, mainDir)
|
return downloadImagesTask(jsonResponse, mainDir)
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadDataTask() : String {
|
private fun downloadDataTask(username: String, password: String) : String {
|
||||||
return try {
|
return try {
|
||||||
val requestBody = createRequestBody()
|
val requestBody = createRequestBody(username = username, password = password)
|
||||||
val jsonRequest = createJsonRequest(requestBody)
|
val jsonRequest = createJsonRequest(requestBody)
|
||||||
|
|
||||||
val responseData = fetchData(jsonRequest)
|
val responseData = fetchData(jsonRequest)
|
||||||
@@ -45,9 +50,7 @@ private fun downloadDataTask() : String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createRequestBody(): String {
|
private fun createRequestBody(username: String, password: String): String {
|
||||||
val username = "149002"
|
|
||||||
val password = "Vertretungsplan"
|
|
||||||
val currentDateTime = LocalDateTime.now().toString()
|
val currentDateTime = LocalDateTime.now().toString()
|
||||||
|
|
||||||
val requestBody = JSONObject().apply {
|
val requestBody = JSONObject().apply {
|
||||||
@@ -118,11 +121,10 @@ private fun decompressGZIPAndDecodeBase64(compressedData: String): String {
|
|||||||
return outputStream.toString("UTF-8")
|
return outputStream.toString("UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadImagesTask(jsonResponse: String, mainDir : File){
|
private fun downloadImagesTask(jsonResponse: JSONObject, mainDir : File) : Int {
|
||||||
clearFolder(mainDir)
|
clearFolder(mainDir)
|
||||||
|
|
||||||
val jsonResponseObject = JSONObject(jsonResponse)
|
val jsonDaysObject = jsonResponse.getJSONArray("ResultMenuItems").getJSONObject(0).getJSONArray("Childs").getJSONObject(0).getJSONObject("Root").getJSONArray("Childs")
|
||||||
val jsonDaysObject = jsonResponseObject.getJSONArray("ResultMenuItems").getJSONObject(0).getJSONArray("Childs").getJSONObject(0).getJSONObject("Root").getJSONArray("Childs")
|
|
||||||
|
|
||||||
for (d in 0 until jsonDaysObject.length()) {
|
for (d in 0 until jsonDaysObject.length()) {
|
||||||
val jsonDayObject = jsonDaysObject.getJSONObject(d)
|
val jsonDayObject = jsonDaysObject.getJSONObject(d)
|
||||||
@@ -139,9 +141,12 @@ private fun downloadImagesTask(jsonResponse: String, mainDir : File){
|
|||||||
val pageIndex = jsonPageObject.get("Index")
|
val pageIndex = jsonPageObject.get("Index")
|
||||||
val imageLink = jsonPageObject.get("Detail").toString()
|
val imageLink = jsonPageObject.get("Detail").toString()
|
||||||
|
|
||||||
downloadImage(day, URL(imageLink), "$pageIndex.jpg")
|
val downloadState = downloadImage(day, URL(imageLink), "$pageIndex.jpg")
|
||||||
|
if (downloadState != 0)
|
||||||
|
return downloadState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDayInformationJson(folder: File, jsonDayObject: JSONObject){
|
private fun createDayInformationJson(folder: File, jsonDayObject: JSONObject){
|
||||||
@@ -158,22 +163,29 @@ private fun createDayInformationJson(folder: File, jsonDayObject: JSONObject){
|
|||||||
infoFile.writeText(infoJson.toString())
|
infoFile.writeText(infoJson.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun downloadImage(folder: File, url: URL, fileName: String){
|
private fun downloadImage(folder: File, url: URL, fileName: String) : Int {
|
||||||
val file = File(folder, fileName)
|
val file = File(folder, fileName)
|
||||||
|
|
||||||
val connection = url.openConnection()
|
try {
|
||||||
val inputStream = connection.getInputStream()
|
val connection = url.openConnection()
|
||||||
val outputStream = FileOutputStream(file)
|
val inputStream = connection.getInputStream()
|
||||||
|
val outputStream = FileOutputStream(file)
|
||||||
|
|
||||||
val buffer = ByteArray(1024)
|
val buffer = ByteArray(1024)
|
||||||
var bytesRead: Int
|
var bytesRead: Int
|
||||||
|
|
||||||
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
|
||||||
outputStream.write(buffer, 0, bytesRead)
|
outputStream.write(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputStream.close()
|
||||||
|
outputStream.close()
|
||||||
}
|
}
|
||||||
|
catch (e: SocketException){
|
||||||
inputStream.close()
|
Log.d("ImageDownloader", e.toString())
|
||||||
outputStream.close()
|
return NO_INTERNET_CONNECTION_CODE
|
||||||
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDataFolder(context: Context) : File {
|
private fun createDataFolder(context: Context) : File {
|
||||||
|
|||||||
316
app/src/main/java/com/schoolapp/cleverclass/DSBLoginActivity.kt
Normal file
316
app/src/main/java/com/schoolapp/cleverclass/DSBLoginActivity.kt
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
package com.schoolapp.cleverclass
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.foundation.text.selection.TextSelectionColors
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material.icons.outlined.Delete
|
||||||
|
import androidx.compose.material.icons.outlined.Info
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextFieldDefaults
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.schoolapp.cleverclass.ui.theme.CleverClassTheme
|
||||||
|
import com.schoolapp.cleverclass.ui.theme.InputPrimaryColor
|
||||||
|
import com.schoolapp.cleverclass.ui.theme.InputSecondaryColor
|
||||||
|
|
||||||
|
private lateinit var activityType : String
|
||||||
|
|
||||||
|
class DSBLoginActivity : ComponentActivity() {
|
||||||
|
companion object{
|
||||||
|
const val TYPE_KEY = "type_key"
|
||||||
|
}
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
activityType = intent.getStringExtra(TYPE_KEY).toString()
|
||||||
|
|
||||||
|
setContent {
|
||||||
|
CleverClassTheme {
|
||||||
|
Surface(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
color = MaterialTheme.colorScheme.background
|
||||||
|
) {
|
||||||
|
DSBLoginContent(activity = this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Content of DSBLogin
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun DSBLoginContent(activity: ComponentActivity){
|
||||||
|
val inputFieldColors = TextFieldDefaults.outlinedTextFieldColors(
|
||||||
|
textColor = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
|
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||||
|
cursorColor = InputPrimaryColor,
|
||||||
|
selectionColors = TextSelectionColors(
|
||||||
|
handleColor = InputPrimaryColor,
|
||||||
|
backgroundColor = InputSecondaryColor
|
||||||
|
),
|
||||||
|
focusedBorderColor = InputSecondaryColor,
|
||||||
|
unfocusedBorderColor = Color.Transparent
|
||||||
|
)
|
||||||
|
|
||||||
|
val sharedPreferences = activity.getSharedPreferences("DSBmobile", Context.MODE_PRIVATE)
|
||||||
|
val editor = sharedPreferences.edit()
|
||||||
|
|
||||||
|
var username by remember {
|
||||||
|
mutableStateOf(sharedPreferences.getString("username", "").toString())
|
||||||
|
}
|
||||||
|
var password by remember {
|
||||||
|
mutableStateOf(sharedPreferences.getString("password", "").toString())
|
||||||
|
}
|
||||||
|
var showPassword by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
var showInfo by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
var showDeleteConfirmation by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
TopAppBar(
|
||||||
|
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(MaterialTheme.colorScheme.primaryContainer),
|
||||||
|
title = { Text(text = "") },
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = { activity.finish() }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.ArrowBack,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(28.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
color = MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
shape = RoundedCornerShape(20),
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(
|
||||||
|
text = "DSBmobile Login Daten",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
|
modifier = Modifier.padding(10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
if (activityType == "Settings")
|
||||||
|
IconButton(onClick = { showDeleteConfirmation = !showDeleteConfirmation }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Delete,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(28.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else if (activityType == "FirstTime")
|
||||||
|
IconButton(onClick = { showInfo = !showInfo }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Outlined.Info,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = username,
|
||||||
|
onValueChange = { username = it },
|
||||||
|
placeholder = {
|
||||||
|
Text(
|
||||||
|
text = "Benutzername",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.primaryContainer
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
singleLine = true,
|
||||||
|
shape = RoundedCornerShape(20),
|
||||||
|
textStyle = MaterialTheme.typography.labelMedium,
|
||||||
|
colors = inputFieldColors
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = password,
|
||||||
|
onValueChange = { password = it },
|
||||||
|
placeholder = {
|
||||||
|
Text(
|
||||||
|
text = "Passwort",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.primaryContainer
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
singleLine = true,
|
||||||
|
shape = RoundedCornerShape(20),
|
||||||
|
textStyle = MaterialTheme.typography.labelMedium,
|
||||||
|
colors = inputFieldColors,
|
||||||
|
visualTransformation = if(showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||||
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
|
||||||
|
trailingIcon = {
|
||||||
|
IconButton(onClick = { showPassword = !showPassword })
|
||||||
|
{
|
||||||
|
Image(
|
||||||
|
painter = painterResource(
|
||||||
|
id = if(showPassword)
|
||||||
|
R.drawable.baseline_visibility_24
|
||||||
|
else
|
||||||
|
R.drawable.baseline_visibility_off_24
|
||||||
|
),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
editor.putString("username", username)
|
||||||
|
editor.putString("password", password)
|
||||||
|
editor.apply()
|
||||||
|
activity.finish()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Speichen",
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.padding(10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showInfo) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showInfo = false },
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = "Der Benutzername und das Passwort können später in den Einstellungen geändert werden",
|
||||||
|
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
|
style = MaterialTheme.typography.labelMedium)
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
Text(
|
||||||
|
text = "Schließen",
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.clickable { showInfo = false }
|
||||||
|
)
|
||||||
|
},
|
||||||
|
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(5.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showDeleteConfirmation) {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { showDeleteConfirmation = false },
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = "Möchten Sie wirklich die Anmeldedaten löschen?",
|
||||||
|
color = MaterialTheme.colorScheme.onPrimaryContainer,
|
||||||
|
style = MaterialTheme.typography.labelMedium
|
||||||
|
)
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
Row(modifier = Modifier.fillMaxWidth()){
|
||||||
|
Text(
|
||||||
|
text = "Bestätigen",
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
editor.putString("username", "")
|
||||||
|
editor.putString("password", "")
|
||||||
|
editor.apply()
|
||||||
|
showDeleteConfirmation = false
|
||||||
|
activity.finish()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Abbrechen",
|
||||||
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.clickable { showDeleteConfirmation = false }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
containerColor = MaterialTheme.colorScheme.primaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -323,7 +323,7 @@ fun FachButton(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles observer creation and disposal
|
// handles observer disposal
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(observer)
|
sharedPreferences.registerOnSharedPreferenceChangeListener(observer)
|
||||||
onDispose {
|
onDispose {
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ import android.os.Bundle
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
@@ -98,6 +100,25 @@ fun SettingsContent(activity: ComponentActivity) {
|
|||||||
Setting(text = "Periodensystem", sharedPreferences, editor)
|
Setting(text = "Periodensystem", sharedPreferences, editor)
|
||||||
Setting(text = "Mebis", sharedPreferences, editor)
|
Setting(text = "Mebis", sharedPreferences, editor)
|
||||||
Setting(text = "DSBmobile", sharedPreferences, editor)
|
Setting(text = "DSBmobile", sharedPreferences, editor)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
Divider()
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable {
|
||||||
|
val intent = Intent(activity, DSBLoginActivity::class.java).apply {
|
||||||
|
putExtra(DSBLoginActivity.TYPE_KEY, "Settings")
|
||||||
|
}
|
||||||
|
activity.startActivity(intent)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "DSBmobile Daten",
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
modifier = Modifier.padding(16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// About Button
|
// About Button
|
||||||
@@ -123,7 +144,6 @@ fun SettingsContent(activity: ComponentActivity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Setting(text : String, sharedPreferences: SharedPreferences, editor: Editor){
|
fun Setting(text : String, sharedPreferences: SharedPreferences, editor: Editor){
|
||||||
val checkedState = remember { mutableStateOf(sharedPreferences.getBoolean(text, true)) }
|
val checkedState = remember { mutableStateOf(sharedPreferences.getBoolean(text, true)) }
|
||||||
@@ -139,8 +159,10 @@ fun Setting(text : String, sharedPreferences: SharedPreferences, editor: Editor)
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(16.dp))
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
Text(text = text,
|
Text(
|
||||||
|
text = text,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
style = MaterialTheme.typography.labelMedium)
|
style = MaterialTheme.typography.labelMedium
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
package com.schoolapp.cleverclass
|
package com.schoolapp.cleverclass
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
|
||||||
|
|
||||||
|
const val NO_INTERNET_CONNECTION_CODE = -1
|
||||||
|
|
||||||
fun formatFloat(number: Float): String {
|
fun formatFloat(number: Float): String {
|
||||||
var formattedString = number.toString()
|
var formattedString = number.toString()
|
||||||
|
|
||||||
@@ -9,4 +19,14 @@ fun formatFloat(number: Float): String {
|
|||||||
formattedString = "0.0"
|
formattedString = "0.0"
|
||||||
|
|
||||||
return formattedString
|
return formattedString
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LoadingScreen(){
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
){
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
5
app/src/main/res/drawable/baseline_visibility_24.xml
Normal file
5
app/src/main/res/drawable/baseline_visibility_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
|
||||||
|
</vector>
|
||||||
5
app/src/main/res/drawable/baseline_visibility_off_24.xml
Normal file
5
app/src/main/res/drawable/baseline_visibility_off_24.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<vector android:height="24dp" android:tint="#000000"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
|
||||||
|
</vector>
|
||||||
@@ -9,4 +9,5 @@
|
|||||||
<string name="title_activity_dsbactivity">DSBActivity</string>
|
<string name="title_activity_dsbactivity">DSBActivity</string>
|
||||||
<string name="title_activity_mebis">MebisActivity</string>
|
<string name="title_activity_mebis">MebisActivity</string>
|
||||||
<string name="title_activity_dsbday_view">DSBDayViewActivity</string>
|
<string name="title_activity_dsbday_view">DSBDayViewActivity</string>
|
||||||
|
<string name="title_activity_dsblogin">DSBLoginActivity</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user