refresh button working (not 100% test coverage)

This commit is contained in:
Odweta
2024-12-22 09:49:21 +01:00
parent ce6afefd3f
commit ac1c1dfa26
12 changed files with 191 additions and 498 deletions
-340
View File
@@ -1,340 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceStreaming">
<option name="deviceSelectionList">
<list>
<PersistentDeviceSelectionData>
<option name="api" value="27" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="F01L" />
<option name="id" value="F01L" />
<option name="manufacturer" value="FUJITSU" />
<option name="name" value="F-01L" />
<option name="screenDensity" value="360" />
<option name="screenX" value="720" />
<option name="screenY" value="1280" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="OPPO" />
<option name="codename" value="OP573DL1" />
<option name="id" value="OP573DL1" />
<option name="manufacturer" value="OPPO" />
<option name="name" value="CPH2557" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="28" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="SH-01L" />
<option name="id" value="SH-01L" />
<option name="manufacturer" value="SHARP" />
<option name="name" value="AQUOS sense2 SH-01L" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="Lenovo" />
<option name="codename" value="TB370FU" />
<option name="id" value="TB370FU" />
<option name="manufacturer" value="Lenovo" />
<option name="name" value="Tab P12" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1840" />
<option name="screenY" value="2944" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="samsung" />
<option name="codename" value="a51" />
<option name="id" value="a51" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy A51" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="akita" />
<option name="id" value="akita" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="b0q" />
<option name="id" value="b0q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S22 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="32" />
<option name="brand" value="google" />
<option name="codename" value="bluejay" />
<option name="id" value="bluejay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="caiman" />
<option name="id" value="caiman" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro" />
<option name="screenDensity" value="360" />
<option name="screenX" value="960" />
<option name="screenY" value="2142" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="comet" />
<option name="id" value="comet" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro Fold" />
<option name="screenDensity" value="390" />
<option name="screenX" value="2076" />
<option name="screenY" value="2152" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="29" />
<option name="brand" value="samsung" />
<option name="codename" value="crownqlteue" />
<option name="id" value="crownqlteue" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Note9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2220" />
<option name="screenY" value="1080" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="dm3q" />
<option name="id" value="dm3q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S23 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="e1q" />
<option name="id" value="e1q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S24" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix_camera" />
<option name="id" value="felix_camera" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold (Camera-enabled)" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="gts8uwifi" />
<option name="id" value="gts8uwifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab S8 Ultra" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1848" />
<option name="screenY" value="2960" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="husky" />
<option name="id" value="husky" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8 Pro" />
<option name="screenDensity" value="390" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="motorola" />
<option name="codename" value="java" />
<option name="id" value="java" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="G20" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="komodo" />
<option name="id" value="komodo" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro XL" />
<option name="screenDensity" value="360" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="lynx" />
<option name="id" value="lynx" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="google" />
<option name="codename" value="oriole" />
<option name="id" value="oriole" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="panther" />
<option name="id" value="panther" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q5q" />
<option name="id" value="q5q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold5" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1812" />
<option name="screenY" value="2176" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q6q" />
<option name="id" value="q6q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1856" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="r11" />
<option name="id" value="r11" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Watch" />
<option name="screenDensity" value="320" />
<option name="screenX" value="384" />
<option name="screenY" value="384" />
<option name="type" value="WEAR_OS" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="redfin" />
<option name="id" value="redfin" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 5" />
<option name="screenDensity" value="440" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="shiba" />
<option name="id" value="shiba" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="tangorpro" />
<option name="id" value="tangorpro" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Tablet" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="tokay" />
<option name="id" value="tokay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
</list>
</option>
</component>
</project>
@@ -181,24 +181,6 @@ class LectureNote(
} }
} }
var lectureNotes: HashMap<Int, LectureNote> = 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 { class Subject {
lateinit var name: String lateinit var name: String
lateinit var place: String lateinit var place: String
@@ -284,48 +266,62 @@ enum class ScreenElement {
} }
class Global { class Global {
lateinit var token: String
lateinit var userData: JSONObject
lateinit var timetable: List<Day>
lateinit var timetableJSON: JSONObject lateinit var timetableJSON: JSONObject
lateinit var marks: MutableMap<String, MutableList<Mark>>
lateinit var marksJSON: JSONObject lateinit var marksJSON: JSONObject
lateinit var studentClass: String lateinit var marks: MutableMap<String, MutableList<Mark>>
lateinit var settings: SettingsData lateinit var settings: SettingsData
lateinit var studentId: String
lateinit var fileDir: File lateinit var fileDir: File
lateinit var token: String
lateinit var studentClass: String
lateinit var studentId: String
var userData: JSONObject = JSONObject()
var timetable: List<Day> = listOf()
var lectureNotes: HashMap<Int, LectureNote> = hashMapOf()
var username: String = "" var username: String = ""
var password: String = "" var password: String = ""
var isAPISetUp: Boolean = false
var noSignInBackHandle: Boolean = false var noSignInBackHandle: Boolean = false
var lectureNotes: HashMap<Int, LectureNote> = hashMapOf()
var status by mutableStateOf("") var selectedLecture: Int = 0
var currentLectureNumber: Int = 0
var currentScreen by mutableStateOf(Screen.Main) var currentScreen by mutableStateOf(Screen.Main)
var currentScreenElement by mutableStateOf(ScreenElement.Timetable) 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 { inner class FilePaths {
val accountData: String = "account_data.txt" val accountData: String = "account_data.txt"
val timeTable: String = "timetable.json" val timetable: String = "timetable.json"
val userData: String = "userdata.json" val userData: String = "userdata.json"
val marks: String = "marks.json" val marks: String = "marks.json"
val settings: String = "settings.txt" val settings: String = "settings.txt"
val lectureNotes: String = "lecture_notes.csv" val lectureNotes: String = "lecture_notes.csv"
} }
val filePaths = FilePaths() val filePaths = FilePaths()
inner class APIEndPoints { inner class APIEndPoints {
val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api" val apiBase = "https://aplikace.skolaonline.cz/solapi/api"
val tokenUrl = "$apiBaseUrl/connect/token" val token = "$apiBase/connect/token"
lateinit var token: String val userData = "$apiBase/v1/user"
val userDataUrl = "$apiBaseUrl/v1/user" val timetable = "$apiBase/v1/timeTable"
lateinit var userData: String var marks: String = "$apiBase/v1/students/<student id>/marks/list"
val timeTableUrl = "$apiBaseUrl/v1/timeTable"
lateinit var marksUrl: String
} }
val apiEndPoints = APIEndPoints() val apiEndPoints = APIEndPoints()
inner class Dimens { inner class Dimens {
val borderWidth = 5.dp val borderWidth = 5.dp
val roundedCorner = 8.dp val roundedCorner = 8.dp
} }
val dimens = Dimens() val dimens = Dimens()
inner class Modifiers { inner class Modifiers {
var bar = Modifier var bar = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -2,6 +2,7 @@ package com.odweta.solon
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import androidx.compose.ui.graphics.Color
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -9,8 +10,10 @@ import kotlinx.coroutines.launch
import org.json.JSONObject import org.json.JSONObject
fun launchStart(ctx: Context) { fun launchStart(ctx: Context) {
global.launched = false
if (Account.haveSaved()) { if (Account.haveSaved()) {
if (Util.internetAvail(ctx)) { if (Util.internetAvail(ctx)) {
global.currentScreen = Screen.Splash
remoteLoad(ctx) remoteLoad(ctx)
} else { } else {
localLoad(ctx) localLoad(ctx)
@@ -22,34 +25,38 @@ fun launchStart(ctx: Context) {
} }
fun remoteLoad(ctx: Context) { fun remoteLoad(ctx: Context) {
var remoteTimetable: JSONObject Log.d("debug", "remoteLoad called")
var remoteMarks: JSONObject
if (!global.isAPISetUp) { if (!global.isAPISetUp) {
CoroutineScope(Dispatchers.IO) CoroutineScope(Dispatchers.IO)
.launch { .launch {
Network.setupAPI() Network.setupAPI()
remoteTimetable = Network.getTimeTable() global.timetableJSON = Network.getTimeTable()
global.timetableJSON = remoteTimetable global.marksJSON = Network.getMarks()
remoteMarks = Network.getMarks()
global.marksJSON = remoteMarks
launchContinue( launchContinue(
ctx, ctx,
remoteTimetable, global.timetableJSON,
remoteMarks global.marksJSON
) )
} }
} else { } else {
launchContinue( Log.d("debug", "API set up, continuing")
ctx, CoroutineScope(Dispatchers.IO).launch {
global.timetableJSON, launchContinue(
global.marksJSON ctx,
) Network.getTimeTable(),
Network.getMarks()
)
}
} }
} }
fun localLoad(ctx: Context) { 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)) val localMarks = JSONObject(Util.fileToString(marksFilePath))
launchContinue( launchContinue(
@@ -78,10 +85,16 @@ fun launchContinue(
val lectureNotes = Util.fileToString(global.filePaths.lectureNotes) val lectureNotes = Util.fileToString(global.filePaths.lectureNotes)
Parsing.parseLectureNotes(lectureNotes) Parsing.parseLectureNotes(lectureNotes)
Log.d("debug", "parsed the things")
// listen for internet availability in case of disconnection // listen for internet availability in case of disconnection
if (!internetAwaitListenerRunning) if (!internetAwaitListenerRunning)
setOnInternetAvailListener(ctx) setOnInternetAvailListener(ctx)
global.launched = true
global.refreshed = true
refreshButtonContentColor.value = Color.White
// show the default (main) screen // show the default (main) screen
global.currentScreen = Screen.Main global.currentScreen = Screen.Main
@@ -90,6 +103,8 @@ fun launchContinue(
// show the full name of the user in the toolbar as a status // show the full name of the user in the toolbar as a status
statusFactory.show(StatusType.NameRole) statusFactory.show(StatusType.NameRole)
Log.d("debug", "done and should show nameRole status")
} }
private fun setOnInternetAvailListener(ctx: Context) { private fun setOnInternetAvailListener(ctx: Context) {
@@ -31,7 +31,7 @@ class MainActivity : ComponentActivity() {
setContent { setContent {
SolonTheme { SolonTheme {
when (global.currentScreen) { when (global.currentScreen) {
Screen.Main -> MainScreen() Screen.Main -> if (global.launched) MainScreen()
Screen.Splash -> SplashScreen() Screen.Splash -> SplashScreen()
Screen.SignIn -> SignInScreen() Screen.SignIn -> SignInScreen()
} }
@@ -27,6 +27,8 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.odweta.solon.ui.theme.PastelYellow import com.odweta.solon.ui.theme.PastelYellow
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
private var timetableColor: MutableState<Color> = mutableStateOf(PastelYellow) private var timetableColor: MutableState<Color> = mutableStateOf(PastelYellow)
private var marksColor: MutableState<Color> = mutableStateOf(Color.White) private var marksColor: MutableState<Color> = mutableStateOf(Color.White)
@@ -47,6 +49,7 @@ fun NavbarScreen() {
Button( Button(
onClick = { onClick = {
remoteLoad(ctx) remoteLoad(ctx)
statusFactory.show(StatusType.Loading)
refreshButtonContentColor.value = PastelYellow refreshButtonContentColor.value = PastelYellow
}, },
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
@@ -1,8 +1,5 @@
package com.odweta.solon package com.odweta.solon
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Request import okhttp3.Request
import org.json.JSONException import org.json.JSONException
@@ -13,7 +10,7 @@ class Network {
companion object { companion object {
fun getToken(): String { fun getToken(): String {
val request = Request.Builder() val request = Request.Builder()
.url(global.apiEndPoints.tokenUrl) .url(global.apiEndPoints.token)
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
.post( .post(
FormBody.Builder() FormBody.Builder()
@@ -57,7 +54,16 @@ class Network {
} }
global.userData = getUserData() global.userData = getUserData()
Util.saveStringToFile(global.filePaths.userData, global.userData.toString()) 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( JSONObject(
Util.fileToString(global.filePaths.userData) Util.fileToString(global.filePaths.userData)
).getJSONObject("class").getString("name") ).getJSONObject("class").getString("name")
@@ -67,14 +73,9 @@ class Network {
Util.fileToString(global.filePaths.userData) Util.fileToString(global.filePaths.userData)
).getJSONArray("children").getJSONObject(0).getString("className") ).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()) { return if (!Parsing.userIsParent()) {
global.userData.getString("personID") global.userData.getString("personID")
} else { } else {
@@ -86,7 +87,7 @@ class Network {
fun getUserData(): JSONObject { fun getUserData(): JSONObject {
val request = Request.Builder() val request = Request.Builder()
.url(global.apiEndPoints.userDataUrl) .url(global.apiEndPoints.userData)
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", "Bearer ${global.token}") // using Bearer auth token .header("Authorization", "Bearer ${global.token}") // using Bearer auth token
.get() .get()
@@ -105,8 +106,8 @@ class Network {
fun getTimeTable(): JSONObject { fun getTimeTable(): JSONObject {
val userIsParent = Parsing.userIsParent() val userIsParent = Parsing.userIsParent()
val url = if (!userIsParent) global.apiEndPoints.timeTableUrl val url = if (!userIsParent) global.apiEndPoints.timetable
else "${global.apiEndPoints.timeTableUrl}?studentId=${global.studentId}" else "${global.apiEndPoints.timetable}?studentId=${global.studentId}"
val request = Request.Builder() val request = Request.Builder()
.url(url) .url(url)
@@ -127,7 +128,7 @@ class Network {
fun getMarks(): JSONObject { fun getMarks(): JSONObject {
val request = Request.Builder() val request = Request.Builder()
.url(global.apiEndPoints.marksUrl) .url(global.apiEndPoints.marks)
.header("Content-Type", "application/x-www-form-urlencoded") .header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", "Bearer ${global.token}") .header("Authorization", "Bearer ${global.token}")
.get() .get()
@@ -47,29 +47,26 @@ class Parsing {
} }
fun userIsParent(): Boolean { fun userIsParent(): Boolean {
return if (userData != "") return if (global.userData != JSONObject())
JSONObject(userData).getString("userType") == "parent" global.userData.getString("userType") == "parent"
else false else false
} }
fun parseTimetable(jsonString: JSONObject): List<Day> { fun parseTimetable(json: JSONObject): List<Day> {
Log.d("debug", "gotten json: $jsonString")
val jsonObject = jsonString
/* /*
* return a List that looks like this: * return a List that looks like this:
* [<name>, <date>, [<subj_name>, <subj_place>, <teacher>, <substitute>, <number>, <start_time>, <end_time>]] * [<name>, <date>, [<subj_name>, <subj_place>, <teacher>, <substitute>, <number>, <start_time>, <end_time>]]
* ["Po", "8.1.", ["D", "207", "Strakova S.", 0, 1, "08:00", "08:45" ]] * ["Po", "8.1.", ["D", "207", "Strakova S.", 0, 1, "08:00", "08:45" ]]
*/ */
val week = mutableListOf<Day>() val timetable = mutableListOf<Day>()
if (jsonObject.has("error")) { if (json.has("error")) {
return week return timetable
} }
// Access the "body" array from the main JSON object // 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 // Convert the JSON array to a list of JSON objects
val jsonObjectList = mutableListOf<JSONObject>() val jsonObjectList = mutableListOf<JSONObject>()
@@ -88,8 +85,12 @@ class Parsing {
.split("-") .split("-")
// remove leading zeros // remove leading zeros
while (dayStr[0] == '0') { dayStr = dayStr.slice(1..<dayStr.length) } while (dayStr[0] == '0') {
while (monthStr[0] == '0') { monthStr = monthStr.slice(1..<monthStr.length) } dayStr = dayStr.slice(1..<dayStr.length)
}
while (monthStr[0] == '0') {
monthStr = monthStr.slice(1..<monthStr.length)
}
// format it into a string that is readable // format it into a string that is readable
val date = "$dayStr. $monthStr." val date = "$dayStr. $monthStr."
@@ -130,35 +131,34 @@ class Parsing {
if (type != "SUPLOVANI" && type != "ROZVRH") { if (type != "SUPLOVANI" && type != "ROZVRH") {
when (kind) { when (kind) {
"ZRUSENI_VYUKY_ROZVRH" -> { "ZRUSENI_VYUKY_ROZVRH" -> {
subject.name = subj.get("title").toString() subject.name = subj.getString("title")
subject.place = "" subject.place = ""
subject.teacher = "" subject.teacher = ""
subject.substitute = "2" // 2 means school event subject.substitute = "2" // 2 means school event
val hourspan = subj.getJSONArray("detailHours").length() val hourspan = subj.getJSONArray("detailHours").length()
subject.number = "1 - $hourspan" 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.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) subject.end = subject.end.slice(0..subject.end.length - 4)
subjects.add(subject) subjects.add(subject)
} }
"S_NAHRADOU_SKOL_AKCE" -> eventLecture(subject, subj, subjects) "S_NAHRADOU_SKOL_AKCE" -> eventLecture(subject, subj, subjects)
"S_NAHRADOU_VYUKA" -> eventLecture(subject, subj, subjects) "S_NAHRADOU_VYUKA" -> eventLecture(subject, subj, subjects)
} }
} else { } else {
subject.name = subj.getJSONObject("subject").get("abbrev").toString() subject.name = subj.getJSONObject("subject").getString("abbrev")
subject.place = subject.place =
subj.getJSONArray("rooms").getJSONObject(0).get("abbrev").toString() subj.getJSONArray("rooms").getJSONObject(0).getString("abbrev")
subject.teacher = "" + subject.teacher = if (subj.getJSONArray("teachers").length() > 0) {
"${ subj.getJSONArray("teachers").getJSONObject(0)
subj.getJSONArray("teachers").getJSONObject(0).get("name") .getString("fullName") // TODO: keep in mind that fullName might not be a valid field (name and surname are!)
} " + } else {
"${ ""
subj.getJSONArray("teachers").getJSONObject(0) }
.get("surname")
}"
subject.substitute = when (type) { subject.substitute = when (type) {
"ROZVRH" -> "0" "ROZVRH" -> "0"
"SUPLOVANI" -> "1" "SUPLOVANI" -> "1"
@@ -244,7 +244,7 @@ class Parsing {
*/ */
if (subjects.size > 1) { if (subjects.size > 1) {
for (i in 0..<subjects.size-1) { for (i in 0..<subjects.size - 1) {
if (subjects[i].number == ((subjects[i + 1].number.toInt() - 1).toString())) { if (subjects[i].number == ((subjects[i + 1].number.toInt() - 1).toString())) {
auxSubjects.add(subjects[i]) auxSubjects.add(subjects[i])
} else { } else {
@@ -257,8 +257,8 @@ class Parsing {
auxSubjects.add( auxSubjects.add(
Subject.freeSubject( Subject.freeSubject(
previous.toString(), previous.toString(),
subjects[i-1].end, subjects[i - 1].end,
subjects[i+1].start subjects[i + 1].start
) )
) )
previous += 1 previous += 1
@@ -292,8 +292,8 @@ class Parsing {
for ((i, s) in auxSubjects.withIndex()) { for ((i, s) in auxSubjects.withIndex()) {
if (s.free) { if (s.free) {
s.start = auxSubjects[i-1].end s.start = auxSubjects[i - 1].end
s.end = auxSubjects[i+1].start s.end = auxSubjects[i + 1].start
} }
} }
@@ -313,15 +313,17 @@ class Parsing {
prevSubject = s prevSubject = s
} }
nextSubjects[nextSubjects.size-1].start = day.subjects[day.subjects.size-1].start nextSubjects[nextSubjects.size - 1].start =
nextSubjects[nextSubjects.size-1].end = day.subjects[day.subjects.size-1].end day.subjects[day.subjects.size - 1].start
nextSubjects[nextSubjects.size - 1].end = day.subjects[day.subjects.size - 1].end
day.subjects = nextSubjects day.subjects = nextSubjects
week.add(day) timetable.add(day)
} }
return week Log.d("debug", "timetable: $timetable")
return timetable
} }
fun parseMarks(jsonString: JSONObject): MutableMap<String, MutableList<Mark>> { fun parseMarks(jsonString: JSONObject): MutableMap<String, MutableList<Mark>> {
@@ -39,20 +39,21 @@ import kotlinx.coroutines.launch
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import kotlinx.coroutines.Dispatchers
private var buttonText: MutableState<String> = mutableStateOf("Přihlásit se") private var buttonText by mutableStateOf("Přihlásit se")
private fun changeButtonText(s: String) { 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 username = usernameText
password = passwordText password = passwordText
val acc = Account(username, password, 0) val acc = Account(username, password, 0)
var checked = false var checked = false
coscope.launch { CoroutineScope(Dispatchers.IO).launch {
while (!checked) { while (!checked) {
delay(300) delay(300)
changeButtonText("Přihlašování") changeButtonText("Přihlašování")
@@ -85,7 +86,7 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri
changeButtonText("Přihlásit se") changeButtonText("Přihlásit se")
} }
coscope.launch { CoroutineScope(Dispatchers.IO).launch {
val valid = Account.isValid(acc) val valid = Account.isValid(acc)
checked = true checked = true
@@ -108,9 +109,7 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri
fun SignInScreen() { fun SignInScreen() {
// handle the back gesture (back swipe form side or back button on bottom android navbar) // handle the back gesture (back swipe form side or back button on bottom android navbar)
if (!global.noSignInBackHandle) { if (!global.noSignInBackHandle) {
BackHandler { BackHandler { global.currentScreen = Screen.Main }
global.currentScreen = Screen.Main
}
} }
var usernameText by remember { mutableStateOf("") } var usernameText by remember { mutableStateOf("") }
@@ -200,7 +199,7 @@ fun SignInScreen() {
Button( Button(
onClick = { onClick = {
signInButtonCallback(ctx, coscope, buttonText.value, usernameText, passwordText) signInButtonCallback(ctx, usernameText, passwordText)
}, },
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
contentColor = Color.White, contentColor = Color.White,
@@ -215,7 +214,7 @@ fun SignInScreen() {
.width(230.dp) .width(230.dp)
) { ) {
Text( Text(
text = buttonText.value, text = buttonText,
fontSize = 23.sp fontSize = 23.sp
) )
} }
@@ -40,12 +40,7 @@ fun SplashScreen() {
AndroidView( AndroidView(
modifier = Modifier.size(200.dp), modifier = Modifier.size(200.dp),
factory = { context: Context -> factory = { context: Context -> ImageView(context) },
ImageView(context).apply {
// Set a placeholder if needed
// setImageResource(R.drawable.placeholder)
}
},
update = { imageView -> update = { imageView ->
Glide.with(imageView.context) Glide.with(imageView.context)
.load(R.drawable.loading) .load(R.drawable.loading)
@@ -69,19 +69,16 @@ import java.time.LocalDate
import java.time.LocalTime import java.time.LocalTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
var showDetailDialog = mutableStateOf(false) var showDetailDialog by mutableStateOf(false)
@Composable @Composable
fun TimetableScreen() { fun TimetableScreen() {
Box( Box(
modifier = Modifier modifier = Modifier.fillMaxSize(),
.fillMaxSize(),
contentAlignment = Alignment.BottomCenter contentAlignment = Alignment.BottomCenter
) { ) {
DayPager() DayPager()
if (showDetailDialog.value) { if (showDetailDialog) DetailDialog()
DetailDialog()
}
} }
} }
@@ -90,7 +87,7 @@ fun TimetableScreen() {
@Composable @Composable
fun DetailDialog() { fun DetailDialog() {
Dialog( Dialog(
onDismissRequest = { showDetailDialog.value = false }, // Close the dialog on dismiss onDismissRequest = { showDetailDialog = false }, // Close the dialog on dismiss
properties = DialogProperties( properties = DialogProperties(
dismissOnBackPress = true, dismissOnBackPress = true,
dismissOnClickOutside = true dismissOnClickOutside = true
@@ -102,7 +99,7 @@ fun DetailDialog() {
.padding(horizontal = 20.dp) .padding(horizontal = 20.dp)
.background( .background(
color = Color.Black, color = Color.Black,
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
) { ) {
Column( Column(
@@ -110,9 +107,9 @@ fun DetailDialog() {
) { ) {
Text( Text(
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, color = Color.White,
textAlign = TextAlign.Left, textAlign = TextAlign.Left,
modifier = Modifier.padding(top = 10.dp) modifier = Modifier.padding(top = 10.dp)
@@ -125,7 +122,7 @@ fun DetailDialog() {
Button( Button(
modifier = Modifier.background( modifier = Modifier.background(
color = Color.Black, color = Color.Black,
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(global.dimens.roundedCorner)
), ),
onClick = { isExpanded = true }, onClick = { isExpanded = true },
colors = ButtonColors( colors = ButtonColors(
@@ -135,7 +132,7 @@ fun DetailDialog() {
disabledContentColor = Color.White disabledContentColor = Color.White
) )
) { ) {
val type = when (lectureNotes[selectedLecture]?.type?.value) { val type = when (global.lectureNotes[global.selectedLecture]?.type?.value) {
LectureNoteType.Normal -> "Normální" LectureNoteType.Normal -> "Normální"
LectureNoteType.Writing -> "Písemný test" LectureNoteType.Writing -> "Písemný test"
LectureNoteType.Speaking -> "Ústní zkoušení" LectureNoteType.Speaking -> "Ústní zkoušení"
@@ -160,7 +157,7 @@ fun DetailDialog() {
enabled = true, enabled = true,
onClick = { onClick = {
isExpanded = false isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Normal global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Normal
Util.saveLectureNotes() Util.saveLectureNotes()
}, },
text = { Text("Normální poznámka", color = Color.White) } text = { Text("Normální poznámka", color = Color.White) }
@@ -170,7 +167,7 @@ fun DetailDialog() {
enabled = true, enabled = true,
onClick = { onClick = {
isExpanded = false isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Writing global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Writing
Util.saveLectureNotes() Util.saveLectureNotes()
}, },
text = { Text("Písemný test", color = Color.White) } text = { Text("Písemný test", color = Color.White) }
@@ -180,7 +177,7 @@ fun DetailDialog() {
enabled = true, enabled = true,
onClick = { onClick = {
isExpanded = false isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Speaking global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Speaking
Util.saveLectureNotes() Util.saveLectureNotes()
}, },
text = { Text("Ústní zkoušení", color = Color.White) } text = { Text("Ústní zkoušení", color = Color.White) }
@@ -190,7 +187,7 @@ fun DetailDialog() {
enabled = true, enabled = true,
onClick = { onClick = {
isExpanded = false isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Other global.lectureNotes[global.selectedLecture]?.type?.value = LectureNoteType.Other
Util.saveLectureNotes() Util.saveLectureNotes()
}, },
text = { Text("Jiné", color = Color.White) } text = { Text("Jiné", color = Color.White) }
@@ -200,9 +197,9 @@ fun DetailDialog() {
//////////////////////////////////////////////// ////////////////////////////////////////////////
TextField( TextField(
value = lectureNotes[selectedLecture]?.note?.value ?: "", value = global.lectureNotes[global.selectedLecture]?.note?.value ?: "",
onValueChange = { newText: String -> onValueChange = { newText: String ->
lectureNotes[selectedLecture]?.note?.value = newText global.lectureNotes[global.selectedLecture]?.note?.value = newText
Util.saveLectureNotes() Util.saveLectureNotes()
}, },
singleLine = true, singleLine = true,
@@ -228,12 +225,12 @@ fun DetailDialog() {
@OptIn(ExperimentalFoundationApi::class) @OptIn(ExperimentalFoundationApi::class)
@Composable @Composable
fun DayPager() { fun DayPager() {
val pagerState = rememberPagerState(pageCount = { days.size }) val pagerState = rememberPagerState(pageCount = { if (global.timetable.isNotEmpty()) global.timetable.size else 6 }) // FIXME
HorizontalPager( HorizontalPager(
state = pagerState, state = pagerState,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { pageIndex -> ) { 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() val now = LocalTime.now()
if (dateParsed == todayDate && isTimeBetween(now, startTimeParsed, endTimeParsed)) { if (dateParsed == todayDate && isTimeBetween(now, startTimeParsed, endTimeParsed)) {
currentLectureNumber = lectureNumber global.currentLectureNumber = lectureNumber
} }
val m = if (settings.useAmoledMode.checked.value) { val m = if (settings.useAmoledMode.checked.value) {
@@ -295,9 +292,9 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
.fillMaxWidth() .fillMaxWidth()
.height(70.dp) .height(70.dp)
.border( .border(
width = borderWidthDimen, width = global.dimens.borderWidth,
color = getSubjectColor(s, false), // decide on the color (transparent) color = getSubjectColor(s, false), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
} else { } else {
Modifier Modifier
@@ -305,15 +302,15 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
.height(70.dp) .height(70.dp)
.background( .background(
color = getSubjectColor(s, true), // decide on the color (transparent) 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( m.border(
width = borderWidthDimen, width = global.dimens.borderWidth,
color = getSubjectColor(s, false), color = getSubjectColor(s, false),
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
} else { } else {
m m
@@ -359,12 +356,12 @@ private fun DayScreen(day: Day) {
.width(50.dp) .width(50.dp)
.fillMaxHeight() .fillMaxHeight()
.border( .border(
width = borderWidthDimen, width = global.dimens.borderWidth,
color = getSubjectColor( color = getSubjectColor(
subject, subject,
false false
), ),
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
} else { } else {
Modifier Modifier
@@ -375,7 +372,7 @@ private fun DayScreen(day: Day) {
subject, subject,
true true
), ),
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
} }
@@ -482,7 +479,7 @@ private fun DayScreen(day: Day) {
if (settings.useSvobodaMode.checked.value) { if (settings.useSvobodaMode.checked.value) {
if ( if (
subject.teacher == "Jindřich Svoboda" && subject.teacher == "Jindřich Svoboda" &&
studentClass == "5. G" global.studentClass == "5. G"
) { ) {
Image( Image(
painter = painterResource(R.drawable.spock), painter = painterResource(R.drawable.spock),
@@ -529,14 +526,14 @@ private fun DayScreen(day: Day) {
.fillMaxSize() .fillMaxSize()
.zIndex(99f) .zIndex(99f)
.clickable { .clickable {
selectedLecture = lectureId global.selectedLecture = lectureId
showDetailDialog.value = true showDetailDialog = true
}) })
if ( if (
(lectureNotes[lectureId] != null && lectureNotes[lectureId]?.note?.value != "") || (global.lectureNotes[lectureId] != null && global.lectureNotes[lectureId]?.note?.value != "") ||
(lectureNotes[lectureId] != null && lectureNotes[lectureId]?.type?.value != LectureNoteType.Normal) && (global.lectureNotes[lectureId] != null && global.lectureNotes[lectureId]?.type?.value != LectureNoteType.Normal) &&
(lectureNotes[lectureId] != null && lectureNotes[lectureId]?.type?.value != LectureNoteType.Other) (global.lectureNotes[lectureId] != null && global.lectureNotes[lectureId]?.type?.value != LectureNoteType.Other)
) { ) {
Icon( Icon(
modifier = Modifier.padding(start = 3.dp, top = 1.dp), modifier = Modifier.padding(start = 3.dp, top = 1.dp),
@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -14,6 +15,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp 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 import org.json.JSONObject
@Composable @Composable
@@ -48,10 +53,11 @@ fun ToolbarScreen() {
enum class StatusType { enum class StatusType {
NameRole, NameRole,
NoInternet NoInternet,
Loading
} }
interface StatusFactoryInterface { private interface StatusFactoryInterface {
fun show(type: StatusType) fun show(type: StatusType)
} }
@@ -70,6 +76,25 @@ object StatusFactory: StatusFactoryInterface {
StatusType.NoInternet -> { StatusType.NoInternet -> {
showStatus("Bez připojení k internetu.") 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)
}
}
}
} }
} }
} }
@@ -280,8 +280,8 @@ class Util {
note += ",${parts[part]}" note += ",${parts[part]}"
} }
lectureNotes[id]?.note = mutableStateOf(note) global.lectureNotes[id]?.note = mutableStateOf(note)
lectureNotes[id]?.type = mutableStateOf(type) global.lectureNotes[id]?.type = mutableStateOf(type)
} }
} }
} }
@@ -301,7 +301,7 @@ class Util {
for (day in days) { for (day in days) {
for ((subjectIndex, subject) in day.subjects.withIndex()) { for ((subjectIndex, subject) in day.subjects.withIndex()) {
val id = getLectureId(day.date, subjectIndex) val id = getLectureId(day.date, subjectIndex)
lectureNotes[id] = LectureNote( global.lectureNotes[id] = LectureNote(
id = id, id = id,
type = mutableStateOf(LectureNoteType.Normal), type = mutableStateOf(LectureNoteType.Normal),
note = mutableStateOf(""), note = mutableStateOf(""),
@@ -315,8 +315,8 @@ class Util {
} }
fun saveLectureNotes() { fun saveLectureNotes() {
val toSave = lectureNotesToCsvString(lectureNotes) val toSave = lectureNotesToCsvString(global.lectureNotes)
saveStringToFile(lectureNotesFilePath, toSave) saveStringToFile(global.filePaths.lectureNotes, toSave)
} }
} }
} }