From ac1c1dfa26db7967efe6d200e6da4a768b17ee3c Mon Sep 17 00:00:00 2001 From: Odweta Date: Sun, 22 Dec 2024 09:49:21 +0100 Subject: [PATCH] refresh button working (not 100% test coverage) --- mobile/.idea/caches/deviceStreaming.xml | 340 ------------------ .../src/main/java/com/odweta/solon/Global.kt | 66 ++-- .../src/main/java/com/odweta/solon/Launch.kt | 43 ++- .../java/com/odweta/solon/MainActivity.kt | 2 +- .../src/main/java/com/odweta/solon/Navbar.kt | 3 + .../src/main/java/com/odweta/solon/Network.kt | 31 +- .../src/main/java/com/odweta/solon/Parsing.kt | 70 ++-- .../src/main/java/com/odweta/solon/SignIn.kt | 19 +- .../src/main/java/com/odweta/solon/Splash.kt | 7 +- .../main/java/com/odweta/solon/Timetable.kt | 69 ++-- .../src/main/java/com/odweta/solon/Toolbar.kt | 29 +- .../src/main/java/com/odweta/solon/Util.kt | 10 +- 12 files changed, 191 insertions(+), 498 deletions(-) delete mode 100644 mobile/.idea/caches/deviceStreaming.xml diff --git a/mobile/.idea/caches/deviceStreaming.xml b/mobile/.idea/caches/deviceStreaming.xml deleted file mode 100644 index 406736c..0000000 --- a/mobile/.idea/caches/deviceStreaming.xml +++ /dev/null @@ -1,340 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/mobile/app/src/main/java/com/odweta/solon/Global.kt b/mobile/app/src/main/java/com/odweta/solon/Global.kt index 7b1f32b..b82ba54 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Global.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Global.kt @@ -181,24 +181,6 @@ class LectureNote( } } -var lectureNotes: HashMap = hashMapOf() -var selectedLecture: Int = 0 - -var selectedDay: Int = 0 -var dayEndString: String = "" - -var isChecked: Boolean = true - -const val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api" -const val tokenUrl = "$apiBaseUrl/connect/token" -var token: String = "" -const val userDataUrl = "$apiBaseUrl/v1/user" -var userData: String = "" -//var studentId: String = "" -const val timeTableUrl = "$apiBaseUrl/v1/timeTable" -var syid = "" // school year id -var marksUrl = "$apiBaseUrl/v1/students/abc/marks/list?SemesterId=$syid" - class Subject { lateinit var name: String lateinit var place: String @@ -284,48 +266,62 @@ enum class ScreenElement { } class Global { - lateinit var token: String - lateinit var userData: JSONObject - lateinit var timetable: List lateinit var timetableJSON: JSONObject - lateinit var marks: MutableMap> lateinit var marksJSON: JSONObject - lateinit var studentClass: String + lateinit var marks: MutableMap> lateinit var settings: SettingsData - lateinit var studentId: String lateinit var fileDir: File + + lateinit var token: String + lateinit var studentClass: String + lateinit var studentId: String + + var userData: JSONObject = JSONObject() + var timetable: List = listOf() + var lectureNotes: HashMap = hashMapOf() + var username: String = "" var password: String = "" - var isAPISetUp: Boolean = false + var noSignInBackHandle: Boolean = false - var lectureNotes: HashMap = hashMapOf() - var status by mutableStateOf("") + + var selectedLecture: Int = 0 + var currentLectureNumber: Int = 0 + var currentScreen by mutableStateOf(Screen.Main) var currentScreenElement by mutableStateOf(ScreenElement.Timetable) + + var status by mutableStateOf("") + + var isAPISetUp by mutableStateOf(false) + var launched by mutableStateOf(false) + var refreshed by mutableStateOf(false) + inner class FilePaths { val accountData: String = "account_data.txt" - val timeTable: String = "timetable.json" + val timetable: String = "timetable.json" val userData: String = "userdata.json" val marks: String = "marks.json" val settings: String = "settings.txt" val lectureNotes: String = "lecture_notes.csv" } val filePaths = FilePaths() + inner class APIEndPoints { - val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api" - val tokenUrl = "$apiBaseUrl/connect/token" - lateinit var token: String - val userDataUrl = "$apiBaseUrl/v1/user" - lateinit var userData: String - val timeTableUrl = "$apiBaseUrl/v1/timeTable" - lateinit var marksUrl: String + val apiBase = "https://aplikace.skolaonline.cz/solapi/api" + val token = "$apiBase/connect/token" + val userData = "$apiBase/v1/user" + val timetable = "$apiBase/v1/timeTable" + var marks: String = "$apiBase/v1/students//marks/list" } val apiEndPoints = APIEndPoints() + inner class Dimens { val borderWidth = 5.dp val roundedCorner = 8.dp } val dimens = Dimens() + inner class Modifiers { var bar = Modifier .fillMaxWidth() diff --git a/mobile/app/src/main/java/com/odweta/solon/Launch.kt b/mobile/app/src/main/java/com/odweta/solon/Launch.kt index ce4aff3..b1837f1 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Launch.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Launch.kt @@ -2,6 +2,7 @@ package com.odweta.solon import android.content.Context import android.util.Log +import androidx.compose.ui.graphics.Color import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay @@ -9,8 +10,10 @@ import kotlinx.coroutines.launch import org.json.JSONObject fun launchStart(ctx: Context) { + global.launched = false if (Account.haveSaved()) { if (Util.internetAvail(ctx)) { + global.currentScreen = Screen.Splash remoteLoad(ctx) } else { localLoad(ctx) @@ -22,34 +25,38 @@ fun launchStart(ctx: Context) { } fun remoteLoad(ctx: Context) { - var remoteTimetable: JSONObject - var remoteMarks: JSONObject + Log.d("debug", "remoteLoad called") if (!global.isAPISetUp) { CoroutineScope(Dispatchers.IO) .launch { Network.setupAPI() - remoteTimetable = Network.getTimeTable() - global.timetableJSON = remoteTimetable - remoteMarks = Network.getMarks() - global.marksJSON = remoteMarks + global.timetableJSON = Network.getTimeTable() + global.marksJSON = Network.getMarks() launchContinue( ctx, - remoteTimetable, - remoteMarks + global.timetableJSON, + global.marksJSON ) } } else { - launchContinue( - ctx, - global.timetableJSON, - global.marksJSON - ) + Log.d("debug", "API set up, continuing") + CoroutineScope(Dispatchers.IO).launch { + launchContinue( + ctx, + Network.getTimeTable(), + Network.getMarks() + ) + } } } fun localLoad(ctx: Context) { - val localTimetable = JSONObject(Util.fileToString(timeTableFilePath)) + global.userData = JSONObject(Util.fileToString(global.filePaths.userData)) + global.studentId = Network.getStudentId() + global.studentClass = Network.getStudentClass() + global.apiEndPoints.marks = "${global.apiEndPoints.apiBase}/v1/students/${global.studentId}/marks/list" + val localTimetable = JSONObject(Util.fileToString(global.filePaths.timetable)) val localMarks = JSONObject(Util.fileToString(marksFilePath)) launchContinue( @@ -78,10 +85,16 @@ fun launchContinue( val lectureNotes = Util.fileToString(global.filePaths.lectureNotes) Parsing.parseLectureNotes(lectureNotes) + Log.d("debug", "parsed the things") + // listen for internet availability in case of disconnection if (!internetAwaitListenerRunning) setOnInternetAvailListener(ctx) + global.launched = true + global.refreshed = true + refreshButtonContentColor.value = Color.White + // show the default (main) screen global.currentScreen = Screen.Main @@ -90,6 +103,8 @@ fun launchContinue( // show the full name of the user in the toolbar as a status statusFactory.show(StatusType.NameRole) + + Log.d("debug", "done and should show nameRole status") } private fun setOnInternetAvailListener(ctx: Context) { diff --git a/mobile/app/src/main/java/com/odweta/solon/MainActivity.kt b/mobile/app/src/main/java/com/odweta/solon/MainActivity.kt index 7b807fa..5078185 100644 --- a/mobile/app/src/main/java/com/odweta/solon/MainActivity.kt +++ b/mobile/app/src/main/java/com/odweta/solon/MainActivity.kt @@ -31,7 +31,7 @@ class MainActivity : ComponentActivity() { setContent { SolonTheme { when (global.currentScreen) { - Screen.Main -> MainScreen() + Screen.Main -> if (global.launched) MainScreen() Screen.Splash -> SplashScreen() Screen.SignIn -> SignInScreen() } diff --git a/mobile/app/src/main/java/com/odweta/solon/Navbar.kt b/mobile/app/src/main/java/com/odweta/solon/Navbar.kt index 783b4b7..c5592a9 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Navbar.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Navbar.kt @@ -27,6 +27,8 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import com.odweta.solon.ui.theme.PastelYellow import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch private var timetableColor: MutableState = mutableStateOf(PastelYellow) private var marksColor: MutableState = mutableStateOf(Color.White) @@ -47,6 +49,7 @@ fun NavbarScreen() { Button( onClick = { remoteLoad(ctx) + statusFactory.show(StatusType.Loading) refreshButtonContentColor.value = PastelYellow }, colors = ButtonDefaults.buttonColors( diff --git a/mobile/app/src/main/java/com/odweta/solon/Network.kt b/mobile/app/src/main/java/com/odweta/solon/Network.kt index d18ef27..b058ad3 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Network.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Network.kt @@ -1,8 +1,5 @@ package com.odweta.solon -import android.util.Log -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext import okhttp3.FormBody import okhttp3.Request import org.json.JSONException @@ -13,7 +10,7 @@ class Network { companion object { fun getToken(): String { val request = Request.Builder() - .url(global.apiEndPoints.tokenUrl) + .url(global.apiEndPoints.token) .header("Content-Type", "application/x-www-form-urlencoded") .post( FormBody.Builder() @@ -57,7 +54,16 @@ class Network { } global.userData = getUserData() Util.saveStringToFile(global.filePaths.userData, global.userData.toString()) - global.studentClass = if (!Parsing.userIsParent()) { + global.studentClass = getStudentClass() + global.studentId = getStudentId() + + global.apiEndPoints.marks = "${global.apiEndPoints.apiBase}/v1/students/${global.studentId}/marks/list" + + global.isAPISetUp = true + } + + fun getStudentClass(): String { // TODO: move to Parsing + return if (!Parsing.userIsParent()) { JSONObject( Util.fileToString(global.filePaths.userData) ).getJSONObject("class").getString("name") @@ -67,14 +73,9 @@ class Network { Util.fileToString(global.filePaths.userData) ).getJSONArray("children").getJSONObject(0).getString("className") } - global.studentId = getStudentId() - - global.apiEndPoints.marksUrl = "$apiBaseUrl/v1/students/${global.studentId}/marks/list" - - global.isAPISetUp = true } - fun getStudentId(): String { + fun getStudentId(): String { // TODO: move to Parsing return if (!Parsing.userIsParent()) { global.userData.getString("personID") } else { @@ -86,7 +87,7 @@ class Network { fun getUserData(): JSONObject { val request = Request.Builder() - .url(global.apiEndPoints.userDataUrl) + .url(global.apiEndPoints.userData) .header("Content-Type", "application/x-www-form-urlencoded") .header("Authorization", "Bearer ${global.token}") // using Bearer auth token .get() @@ -105,8 +106,8 @@ class Network { fun getTimeTable(): JSONObject { val userIsParent = Parsing.userIsParent() - val url = if (!userIsParent) global.apiEndPoints.timeTableUrl - else "${global.apiEndPoints.timeTableUrl}?studentId=${global.studentId}" + val url = if (!userIsParent) global.apiEndPoints.timetable + else "${global.apiEndPoints.timetable}?studentId=${global.studentId}" val request = Request.Builder() .url(url) @@ -127,7 +128,7 @@ class Network { fun getMarks(): JSONObject { val request = Request.Builder() - .url(global.apiEndPoints.marksUrl) + .url(global.apiEndPoints.marks) .header("Content-Type", "application/x-www-form-urlencoded") .header("Authorization", "Bearer ${global.token}") .get() diff --git a/mobile/app/src/main/java/com/odweta/solon/Parsing.kt b/mobile/app/src/main/java/com/odweta/solon/Parsing.kt index e3bbdc3..f28ab97 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Parsing.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Parsing.kt @@ -47,29 +47,26 @@ class Parsing { } fun userIsParent(): Boolean { - return if (userData != "") - JSONObject(userData).getString("userType") == "parent" + return if (global.userData != JSONObject()) + global.userData.getString("userType") == "parent" else false } - fun parseTimetable(jsonString: JSONObject): List { - Log.d("debug", "gotten json: $jsonString") - val jsonObject = jsonString - + fun parseTimetable(json: JSONObject): List { /* * return a List that looks like this: * [, , [, , , , , , ]] * ["Po", "8.1.", ["D", "207", "Strakova S.", 0, 1, "08:00", "08:45" ]] */ - val week = mutableListOf() + val timetable = mutableListOf() - if (jsonObject.has("error")) { - return week + if (json.has("error")) { + return timetable } // Access the "body" array from the main JSON object - val bodyArray = jsonObject.getJSONArray("days") + val bodyArray = json.getJSONArray("days") // Convert the JSON array to a list of JSON objects val jsonObjectList = mutableListOf() @@ -88,8 +85,12 @@ class Parsing { .split("-") // remove leading zeros - while (dayStr[0] == '0') { dayStr = dayStr.slice(1.. { - subject.name = subj.get("title").toString() + subject.name = subj.getString("title") subject.place = "" subject.teacher = "" subject.substitute = "2" // 2 means school event val hourspan = subj.getJSONArray("detailHours").length() subject.number = "1 - $hourspan" - subject.start = subj.get("beginTime").toString() + subject.start = subj.getString("beginTime") subject.start = subject.start.slice(0..subject.start.length - 4) - subject.end = subj.get("endTime").toString() + subject.end = subj.getString("endTime") subject.end = subject.end.slice(0..subject.end.length - 4) subjects.add(subject) } + "S_NAHRADOU_SKOL_AKCE" -> eventLecture(subject, subj, subjects) "S_NAHRADOU_VYUKA" -> eventLecture(subject, subj, subjects) } } else { - subject.name = subj.getJSONObject("subject").get("abbrev").toString() + subject.name = subj.getJSONObject("subject").getString("abbrev") subject.place = - subj.getJSONArray("rooms").getJSONObject(0).get("abbrev").toString() - subject.teacher = "" + - "${ - subj.getJSONArray("teachers").getJSONObject(0).get("name") - } " + - "${ - subj.getJSONArray("teachers").getJSONObject(0) - .get("surname") - }" + subj.getJSONArray("rooms").getJSONObject(0).getString("abbrev") + subject.teacher = if (subj.getJSONArray("teachers").length() > 0) { + subj.getJSONArray("teachers").getJSONObject(0) + .getString("fullName") // TODO: keep in mind that fullName might not be a valid field (name and surname are!) + } else { + "" + } subject.substitute = when (type) { "ROZVRH" -> "0" "SUPLOVANI" -> "1" @@ -244,7 +244,7 @@ class Parsing { */ if (subjects.size > 1) { - for (i in 0..> { diff --git a/mobile/app/src/main/java/com/odweta/solon/SignIn.kt b/mobile/app/src/main/java/com/odweta/solon/SignIn.kt index 6370cd9..319f2c3 100644 --- a/mobile/app/src/main/java/com/odweta/solon/SignIn.kt +++ b/mobile/app/src/main/java/com/odweta/solon/SignIn.kt @@ -39,20 +39,21 @@ import kotlinx.coroutines.launch import androidx.compose.foundation.layout.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import kotlinx.coroutines.Dispatchers -private var buttonText: MutableState = mutableStateOf("Přihlásit se") +private var buttonText by mutableStateOf("Přihlásit se") private fun changeButtonText(s: String) { - buttonText.value = s + buttonText = s } -fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: String, usernameText: String, passwordText: String) { +fun signInButtonCallback(ctx: Context, usernameText: String, passwordText: String) { username = usernameText password = passwordText val acc = Account(username, password, 0) var checked = false - coscope.launch { + CoroutineScope(Dispatchers.IO).launch { while (!checked) { delay(300) changeButtonText("Přihlašování") @@ -85,7 +86,7 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri changeButtonText("Přihlásit se") } - coscope.launch { + CoroutineScope(Dispatchers.IO).launch { val valid = Account.isValid(acc) checked = true @@ -108,9 +109,7 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri fun SignInScreen() { // handle the back gesture (back swipe form side or back button on bottom android navbar) if (!global.noSignInBackHandle) { - BackHandler { - global.currentScreen = Screen.Main - } + BackHandler { global.currentScreen = Screen.Main } } var usernameText by remember { mutableStateOf("") } @@ -200,7 +199,7 @@ fun SignInScreen() { Button( onClick = { - signInButtonCallback(ctx, coscope, buttonText.value, usernameText, passwordText) + signInButtonCallback(ctx, usernameText, passwordText) }, colors = ButtonDefaults.buttonColors( contentColor = Color.White, @@ -215,7 +214,7 @@ fun SignInScreen() { .width(230.dp) ) { Text( - text = buttonText.value, + text = buttonText, fontSize = 23.sp ) } diff --git a/mobile/app/src/main/java/com/odweta/solon/Splash.kt b/mobile/app/src/main/java/com/odweta/solon/Splash.kt index 5567c9a..619df60 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Splash.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Splash.kt @@ -40,12 +40,7 @@ fun SplashScreen() { AndroidView( modifier = Modifier.size(200.dp), - factory = { context: Context -> - ImageView(context).apply { - // Set a placeholder if needed - // setImageResource(R.drawable.placeholder) - } - }, + factory = { context: Context -> ImageView(context) }, update = { imageView -> Glide.with(imageView.context) .load(R.drawable.loading) diff --git a/mobile/app/src/main/java/com/odweta/solon/Timetable.kt b/mobile/app/src/main/java/com/odweta/solon/Timetable.kt index 95bf245..0fc6b4c 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Timetable.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Timetable.kt @@ -69,19 +69,16 @@ import java.time.LocalDate import java.time.LocalTime import java.time.format.DateTimeFormatter -var showDetailDialog = mutableStateOf(false) +var showDetailDialog by mutableStateOf(false) @Composable fun TimetableScreen() { Box( - modifier = Modifier - .fillMaxSize(), + modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter ) { DayPager() - if (showDetailDialog.value) { - DetailDialog() - } + if (showDetailDialog) DetailDialog() } } @@ -90,7 +87,7 @@ fun TimetableScreen() { @Composable fun DetailDialog() { Dialog( - onDismissRequest = { showDetailDialog.value = false }, // Close the dialog on dismiss + onDismissRequest = { showDetailDialog = false }, // Close the dialog on dismiss properties = DialogProperties( dismissOnBackPress = true, dismissOnClickOutside = true @@ -102,7 +99,7 @@ fun DetailDialog() { .padding(horizontal = 20.dp) .background( color = Color.Black, - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ) ) { Column( @@ -110,9 +107,9 @@ fun DetailDialog() { ) { Text( text = "" + - lectureNotes[selectedLecture]?.number.toString() + + global.lectureNotes[global.selectedLecture]?.number.toString() + " – " + - lectureNotes[selectedLecture]?.lectureName.toString(), + global.lectureNotes[global.selectedLecture]?.lectureName.toString(), color = Color.White, textAlign = TextAlign.Left, modifier = Modifier.padding(top = 10.dp) @@ -125,7 +122,7 @@ fun DetailDialog() { Button( modifier = Modifier.background( color = Color.Black, - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ), onClick = { isExpanded = true }, colors = ButtonColors( @@ -135,7 +132,7 @@ fun DetailDialog() { disabledContentColor = Color.White ) ) { - val type = when (lectureNotes[selectedLecture]?.type?.value) { + val type = when (global.lectureNotes[global.selectedLecture]?.type?.value) { LectureNoteType.Normal -> "Normální" LectureNoteType.Writing -> "Písemný test" LectureNoteType.Speaking -> "Ústní zkoušení" @@ -160,7 +157,7 @@ fun DetailDialog() { enabled = true, onClick = { isExpanded = false - lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Normal + global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Normal Util.saveLectureNotes() }, text = { Text("Normální poznámka", color = Color.White) } @@ -170,7 +167,7 @@ fun DetailDialog() { enabled = true, onClick = { isExpanded = false - lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Writing + global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Writing Util.saveLectureNotes() }, text = { Text("Písemný test", color = Color.White) } @@ -180,7 +177,7 @@ fun DetailDialog() { enabled = true, onClick = { isExpanded = false - lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Speaking + global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Speaking Util.saveLectureNotes() }, text = { Text("Ústní zkoušení", color = Color.White) } @@ -190,7 +187,7 @@ fun DetailDialog() { enabled = true, onClick = { isExpanded = false - lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Other + global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Other Util.saveLectureNotes() }, text = { Text("Jiné", color = Color.White) } @@ -200,9 +197,9 @@ fun DetailDialog() { //////////////////////////////////////////////// TextField( - value = lectureNotes[selectedLecture]?.note?.value ?: "", + value = global.lectureNotes[global.selectedLecture]?.note?.value ?: "", onValueChange = { newText: String -> - lectureNotes[selectedLecture]?.note?.value = newText + global.lectureNotes[global.selectedLecture]?.note?.value = newText Util.saveLectureNotes() }, singleLine = true, @@ -228,12 +225,12 @@ fun DetailDialog() { @OptIn(ExperimentalFoundationApi::class) @Composable fun DayPager() { - val pagerState = rememberPagerState(pageCount = { days.size }) + val pagerState = rememberPagerState(pageCount = { if (global.timetable.isNotEmpty()) global.timetable.size else 6 }) // FIXME HorizontalPager( state = pagerState, modifier = Modifier.fillMaxSize() ) { pageIndex -> - DayScreen(days[pageIndex]) + DayScreen(global.timetable[pageIndex]) } } @@ -287,7 +284,7 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier { val now = LocalTime.now() if (dateParsed == todayDate && isTimeBetween(now, startTimeParsed, endTimeParsed)) { - currentLectureNumber = lectureNumber + global.currentLectureNumber = lectureNumber } val m = if (settings.useAmoledMode.checked.value) { @@ -295,9 +292,9 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier { .fillMaxWidth() .height(70.dp) .border( - width = borderWidthDimen, + width = global.dimens.borderWidth, color = getSubjectColor(s, false), // decide on the color (transparent) - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ) } else { Modifier @@ -305,15 +302,15 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier { .height(70.dp) .background( color = getSubjectColor(s, true), // decide on the color (transparent) - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ) } - return if (lectureNumber == currentLectureNumber && dateParsed == todayDate) { + return if (lectureNumber == global.currentLectureNumber && dateParsed == todayDate) { m.border( - width = borderWidthDimen, + width = global.dimens.borderWidth, color = getSubjectColor(s, false), - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ) } else { m @@ -359,12 +356,12 @@ private fun DayScreen(day: Day) { .width(50.dp) .fillMaxHeight() .border( - width = borderWidthDimen, + width = global.dimens.borderWidth, color = getSubjectColor( subject, false ), - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ) } else { Modifier @@ -375,7 +372,7 @@ private fun DayScreen(day: Day) { subject, true ), - shape = RoundedCornerShape(roundedCornerDimen) + shape = RoundedCornerShape(global.dimens.roundedCorner) ) } @@ -482,7 +479,7 @@ private fun DayScreen(day: Day) { if (settings.useSvobodaMode.checked.value) { if ( subject.teacher == "Jindřich Svoboda" && - studentClass == "5. G" + global.studentClass == "5. G" ) { Image( painter = painterResource(R.drawable.spock), @@ -529,14 +526,14 @@ private fun DayScreen(day: Day) { .fillMaxSize() .zIndex(99f) .clickable { - selectedLecture = lectureId - showDetailDialog.value = true + global.selectedLecture = lectureId + showDetailDialog = true }) if ( - (lectureNotes[lectureId] != null && lectureNotes[lectureId]?.note?.value != "") || - (lectureNotes[lectureId] != null && lectureNotes[lectureId]?.type?.value != LectureNoteType.Normal) && - (lectureNotes[lectureId] != null && lectureNotes[lectureId]?.type?.value != LectureNoteType.Other) + (global.lectureNotes[lectureId] != null && global.lectureNotes[lectureId]?.note?.value != "") || + (global.lectureNotes[lectureId] != null && global.lectureNotes[lectureId]?.type?.value != LectureNoteType.Normal) && + (global.lectureNotes[lectureId] != null && global.lectureNotes[lectureId]?.type?.value != LectureNoteType.Other) ) { Icon( modifier = Modifier.padding(start = 3.dp, top = 1.dp), diff --git a/mobile/app/src/main/java/com/odweta/solon/Toolbar.kt b/mobile/app/src/main/java/com/odweta/solon/Toolbar.kt index 3fe747a..1e903c8 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Toolbar.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Toolbar.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.setValue import androidx.compose.runtime.mutableStateOf @@ -14,6 +15,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import org.json.JSONObject @Composable @@ -48,10 +53,11 @@ fun ToolbarScreen() { enum class StatusType { NameRole, - NoInternet + NoInternet, + Loading } -interface StatusFactoryInterface { +private interface StatusFactoryInterface { fun show(type: StatusType) } @@ -70,6 +76,25 @@ object StatusFactory: StatusFactoryInterface { StatusType.NoInternet -> { showStatus("Bez připojení k internetu.") } + StatusType.Loading -> { + CoroutineScope(Dispatchers.IO).launch { + global.refreshed = false + val anim = listOf( + "Přihlašování", + "Přihlašování.", + "Přihlašování..", + "Přihlašování...", + "Přihlašování..", + "Přihlašování." + ) + var i = 0 + while (!global.refreshed) { + if (i == anim.size) i = 0 + showStatus(anim[i++]) + delay(300) + } + } + } } } } diff --git a/mobile/app/src/main/java/com/odweta/solon/Util.kt b/mobile/app/src/main/java/com/odweta/solon/Util.kt index f667ff0..c09a3cf 100644 --- a/mobile/app/src/main/java/com/odweta/solon/Util.kt +++ b/mobile/app/src/main/java/com/odweta/solon/Util.kt @@ -280,8 +280,8 @@ class Util { note += ",${parts[part]}" } - lectureNotes[id]?.note = mutableStateOf(note) - lectureNotes[id]?.type = mutableStateOf(type) + global.lectureNotes[id]?.note = mutableStateOf(note) + global.lectureNotes[id]?.type = mutableStateOf(type) } } } @@ -301,7 +301,7 @@ class Util { for (day in days) { for ((subjectIndex, subject) in day.subjects.withIndex()) { val id = getLectureId(day.date, subjectIndex) - lectureNotes[id] = LectureNote( + global.lectureNotes[id] = LectureNote( id = id, type = mutableStateOf(LectureNoteType.Normal), note = mutableStateOf(""), @@ -315,8 +315,8 @@ class Util { } fun saveLectureNotes() { - val toSave = lectureNotesToCsvString(lectureNotes) - saveStringToFile(lectureNotesFilePath, toSave) + val toSave = lectureNotesToCsvString(global.lectureNotes) + saveStringToFile(global.filePaths.lectureNotes, toSave) } } } \ No newline at end of file