refined the launch proccess and improved the architecture of global variables

This commit is contained in:
Odweta
2024-12-20 17:31:28 +01:00
parent 3240313f75
commit f9d4ff562d
14 changed files with 403 additions and 113 deletions
@@ -38,10 +38,10 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@Composable @Composable
fun AboutScreen(modifier: Modifier = Modifier) { fun AboutScreen() {
// 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)
BackHandler { BackHandler {
isShowing.value = IsShowing.Menu isShowing = IsShowing.Menu
} }
Column( Column(
@@ -50,35 +50,7 @@ fun AboutScreen(modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.Top, verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start horizontalAlignment = Alignment.Start
) { ) {
Box( backButtonFactory.get(BackButtonType.Menu)()
modifier = Modifier
.fillMaxWidth()
.padding(start = 5.dp)
) {
Button(
onClick = {
isShowing.value = IsShowing.Menu
},
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(70.dp)
.height(70.dp)
) {
Icon(
imageVector = Icons.Default.ArrowBackIosNew,
contentDescription = "Back icon",
modifier = Modifier.size(40.dp)
)
}
}
Column( Column(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@@ -126,7 +98,7 @@ fun AboutScreen(modifier: Modifier = Modifier) {
} }
@Composable @Composable
fun HorizontalLine(modifier: Modifier = Modifier) { fun HorizontalLine() {
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
Spacer(modifier = Modifier Spacer(modifier = Modifier
@@ -0,0 +1,75 @@
package com.odweta.solon
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
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.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.odweta.solon.ui.theme.PastelYellow
enum class BackButtonType {
Menu,
MarksSubject,
MarksAll
}
interface BackButtonFactoryInterface {
@Composable
fun get(type: BackButtonType): @Composable () -> Unit
}
@Composable
fun BackButton(onClick: () -> Unit) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(start = 5.dp)
) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(70.dp)
.height(70.dp)
) {
Icon(
imageVector = Icons.Default.ArrowBackIosNew,
contentDescription = "Back icon",
modifier = Modifier.size(40.dp)
)
}
}
}
object BackButtonFactory: BackButtonFactoryInterface {
@Composable
override fun get(type: BackButtonType): @Composable () -> Unit {
return when (type) {
BackButtonType.Menu -> { { BackButton({ isShowing = IsShowing.Menu }) } }
BackButtonType.MarksAll -> { { BackButton({ marksShow = MarksShow.All }) } }
BackButtonType.MarksSubject -> { { BackButton({ marksShow = MarksShow.Subject }) } }
}
}
}
val backButtonFactory = BackButtonFactory
@@ -7,14 +7,16 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
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 okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.json.JSONObject
import java.io.File import java.io.File
// Global values (dimens, modifiers, ...) // Global values (dimens, modifiers, ...)
@@ -72,7 +74,7 @@ var screenToShow: MutableState<Screen> = mutableStateOf(Screen.Main)
var signedInAndReadyToLaunch: MutableState<Boolean> = mutableStateOf(false) var signedInAndReadyToLaunch: MutableState<Boolean> = mutableStateOf(false)
var isShowing: MutableState<IsShowing> = mutableStateOf(IsShowing.Timetable) var isShowing by mutableStateOf(IsShowing.Timetable)
var toolbarText: MutableState<String> = mutableStateOf("") var toolbarText: MutableState<String> = mutableStateOf("")
@@ -281,3 +283,45 @@ class Mark {
return mark return mark
} }
} }
object FilePaths {
const val accountData: String = "account_data.txt"
const val timeTable: String = "timetable.json"
const val userData: String = "userdata.json"
const val marks: String = "marks.json"
const val settings: String = "settings.txt"
const val lectureNotes: String = "lecture_notes.csv"
}
object APIEndpoints {
const val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api"
const val tokenUrl = "$apiBaseUrl/connect/token"
lateinit var token: String
const val userDataUrl = "$apiBaseUrl/v1/user"
lateinit var userData: String
lateinit var studentId: String
const val timeTableUrl = "$apiBaseUrl/v1/timeTable"
var marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list?SemesterId=$syid"
}
enum class MainElement {
Timetable,
Marks,
Menu
}
object Global {
lateinit var token: String
lateinit var userData: JSONObject
lateinit var timetable: List<Day>
lateinit var marks: MutableMap<String, MutableList<Mark>>
var noSignInBackHandle: Boolean = false
val filePaths: FilePaths = FilePaths
val apiEndPoints: APIEndpoints = APIEndpoints
lateinit var settings: SettingsData
var lectureNotes: HashMap<Int, LectureNote> = hashMapOf()
var currentScreen by mutableStateOf(Screen.Main)
var currentMainElement by mutableStateOf(MainElement.Timetable)
}
val global = Global
@@ -0,0 +1,111 @@
package com.odweta.solon
import android.content.Context
import androidx.compose.runtime.mutableStateOf
import com.odweta.solon.Util.Companion.getLectureId
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.json.JSONObject
fun launchStart(ctx: Context) {
if (Account.haveSaved()) {
if (Util.internetAvail(ctx)) {
remoteLoad(ctx)
} else {
localLoad(ctx)
}
} else {
global.noSignInBackHandle = true
screenToShow.value = Screen.SignIn
}
}
fun remoteLoad(ctx: Context) {
if (!isAPISetUp)
CoroutineScope(Dispatchers.IO)
.launch { Network.setupAPI() }
lateinit var token: String
CoroutineScope(Dispatchers.IO)
.launch { token = Network.getToken() }
global.token = token
lateinit var userData: JSONObject
CoroutineScope(Dispatchers.IO)
.launch { userData = Network.getUserData() }
global.userData = userData
lateinit var remoteTimetable: JSONObject
CoroutineScope(Dispatchers.IO)
.launch { remoteTimetable = Network.getTimeTable() }
lateinit var remoteMarks: JSONObject
CoroutineScope(Dispatchers.IO)
.launch { remoteMarks = Network.getMarks() }
launchContinue(
ctx,
remoteTimetable,
remoteMarks
)
}
fun localLoad(ctx: Context) {
val localTimetable = JSONObject(Util.fileToString(timeTableFilePath))
val localMarks = JSONObject(Util.fileToString(marksFilePath))
launchContinue(
ctx,
localTimetable,
localMarks
)
}
fun launchContinue(
ctx: Context,
timetable: JSONObject,
marks: JSONObject
) {
// parse timetable and marks
val parsedTimetable = Parsing.parseTimetable(timetable)
global.timetable = parsedTimetable
val parsedMarks = Parsing.parseMarks(marks)
global.marks = parsedMarks
// load the settings
val settingsData = Util.fileToString(global.filePaths.settings).toSettingsData()
global.settings = settingsData
// load the lecture notes
val lectureNotes = Util.fileToString(global.filePaths.lectureNotes)
Parsing.parseLectureNotes(lectureNotes)
// listen for internet availability in case of disconnection
if (!internetAwaitListenerRunning)
setOnInternetAvailListener(ctx)
// show the default (main) screen
global.currentScreen = Screen.Main
// inside show the timetable
global.currentMainElement = MainElement.Timetable
}
private fun setOnInternetAvailListener(ctx: Context) {
internetAwaitListenerRunning = true
CoroutineScope(Dispatchers.IO).launch {
while (true) {
if (Util.internetAvail(ctx)) {
CoroutineScope(Dispatchers.IO).launch {
remoteLoad(ctx)
}
} else {
showStatus("Bez připojení k internetu.")
}
delay(1000) // Check for internet availability every second
}
}
}
@@ -64,7 +64,7 @@ class MainActivity : ComponentActivity() {
.fillMaxWidth() .fillMaxWidth()
.weight(1f) .weight(1f)
) { ) {
when (isShowing.value) { when (isShowing) {
IsShowing.Timetable -> TimetableScreen() IsShowing.Timetable -> TimetableScreen()
IsShowing.Marks -> MarksScreen() IsShowing.Marks -> MarksScreen()
IsShowing.Menu -> MenuScreen() IsShowing.Menu -> MenuScreen()
@@ -14,21 +14,18 @@ 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.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.AutoAwesome import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -55,13 +52,13 @@ enum class MarksShow {
Detail Detail
} }
var marksShow: MutableState<MarksShow> = mutableStateOf(MarksShow.All) var marksShow by mutableStateOf(MarksShow.All)
private var subjectToShow: String = "" private var subjectToShow: String = ""
private var markToShow: Mark = Mark() private var markToShow: Mark = Mark()
@Composable @Composable
fun MarksScreen() { fun MarksScreen() {
when (marksShow.value) { when (marksShow) {
MarksShow.All -> MarksAll() MarksShow.All -> MarksAll()
MarksShow.Subject -> MarksSubject() MarksShow.Subject -> MarksSubject()
MarksShow.Detail -> MarksDetail() MarksShow.Detail -> MarksDetail()
@@ -145,7 +142,7 @@ fun MarksAll() {
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(roundedCornerDimen)
) )
.clickable { .clickable {
marksShow.value = MarksShow.Subject marksShow = MarksShow.Subject
subjectToShow = subject subjectToShow = subject
} }
} else { } else {
@@ -157,7 +154,7 @@ fun MarksAll() {
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(roundedCornerDimen)
) )
.clickable { .clickable {
marksShow.value = MarksShow.Subject marksShow = MarksShow.Subject
subjectToShow = subject subjectToShow = subject
} }
} }
@@ -268,7 +265,7 @@ fun MarksAll() {
fun MarksSubject() { fun MarksSubject() {
// 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)
BackHandler { BackHandler {
marksShow.value = MarksShow.All marksShow = MarksShow.All
} }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
@@ -283,29 +280,7 @@ fun MarksSubject() {
Row( Row(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Button( backButtonFactory.get(BackButtonType.MarksAll)()
onClick = {
marksShow.value = MarksShow.All
},
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(70.dp)
.height(70.dp)
) {
Icon(
imageVector = Icons.Default.ArrowBackIosNew,
contentDescription = "Back icon",
modifier = Modifier.size(40.dp)
)
}
Box(modifier = Modifier.weight(1f)) Box(modifier = Modifier.weight(1f))
@@ -397,7 +372,7 @@ fun MarksSubject() {
.padding(vertical = 10.dp) .padding(vertical = 10.dp)
.clickable { .clickable {
markToShow = mark markToShow = mark
marksShow.value = MarksShow.Detail marksShow = MarksShow.Detail
} }
) { ) {
Box( Box(
@@ -450,7 +425,7 @@ fun MarksSubject() {
fun MarksDetail() { fun MarksDetail() {
// 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)
BackHandler { BackHandler {
marksShow.value = MarksShow.Subject marksShow = MarksShow.Subject
} }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
@@ -466,29 +441,7 @@ fun MarksDetail() {
Row( Row(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Button( backButtonFactory.get(BackButtonType.MarksSubject)()
onClick = {
marksShow.value = MarksShow.Subject
},
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = borderWidthDimen,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(70.dp)
.height(70.dp)
) {
Icon(
imageVector = Icons.Default.ArrowBackIosNew,
contentDescription = "Back icon",
modifier = Modifier.size(40.dp)
)
}
Box(modifier = Modifier.weight(1f)) Box(modifier = Modifier.weight(1f))
@@ -540,7 +493,8 @@ fun MarksDetail() {
color = PastelYellow, color = PastelYellow,
shape = RoundedCornerShape(roundedCornerDimen) shape = RoundedCornerShape(roundedCornerDimen)
) )
.background(if (settings.useAmoledMode.checked.value) { .background(
if (settings.useAmoledMode.checked.value) {
Color.Black Color.Black
} else { } else {
PastelYellowTransparent PastelYellowTransparent
@@ -44,11 +44,11 @@ fun MenuScreen(modifier: Modifier = Modifier) {
Spacer(modifier = Modifier.height(80.dp)) Spacer(modifier = Modifier.height(80.dp))
MenuButton({ isShowing.value = IsShowing.About }, "O aplikaci") MenuButton({ isShowing = IsShowing.About }, "O aplikaci")
Spacer(modifier = Modifier.height(80.dp)) Spacer(modifier = Modifier.height(80.dp))
MenuButton({ isShowing.value = IsShowing.Settings }, "Nastavení") MenuButton({ isShowing = IsShowing.Settings }, "Nastavení")
} }
// Dialog implementation // Dialog implementation
@@ -67,7 +67,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
Button( Button(
onClick = { onClick = {
isShowing.value = IsShowing.Timetable isShowing = IsShowing.Timetable
timetableColor.value = PastelYellow timetableColor.value = PastelYellow
marksColor.value = Color.White marksColor.value = Color.White
menuColor.value = Color.White menuColor.value = Color.White
@@ -88,11 +88,11 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
Button( Button(
onClick = { onClick = {
isShowing.value = IsShowing.Marks isShowing = IsShowing.Marks
timetableColor.value = Color.White timetableColor.value = Color.White
marksColor.value = PastelYellow marksColor.value = PastelYellow
menuColor.value = Color.White menuColor.value = Color.White
marksShow.value = MarksShow.All marksShow = MarksShow.All
}, },
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
contentColor = marksColor.value, contentColor = marksColor.value,
@@ -110,7 +110,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
Button( Button(
onClick = { onClick = {
isShowing.value = IsShowing.Menu isShowing = IsShowing.Menu
timetableColor.value = Color.White timetableColor.value = Color.White
marksColor.value = Color.White marksColor.value = Color.White
menuColor.value = PastelYellow menuColor.value = PastelYellow
@@ -29,8 +29,12 @@ class Network {
try { try {
val resp = client.newCall(request).execute() val resp = client.newCall(request).execute()
val respString = resp.body?.string() val respString = resp.body?.string().toString()
respString.toString() if (JSONObject(respString).has("access_token")) {
JSONObject(respString).getString("access_token")
} else {
""""error": "network""""
}
//val respJson = respString?.let { JSONObject(it) } //val respJson = respString?.let { JSONObject(it) }
//respJson.toString() //respJson.toString()
} catch (e: JSONException) { } catch (e: JSONException) {
@@ -138,6 +142,27 @@ class Network {
} }
} }
suspend fun getUserData(): JSONObject {
return withContext(Dispatchers.IO) {
val request = Request.Builder()
.url(userDataUrl)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", "Bearer $token") // using Bearer auth token
.get()
.build()
try {
val resp = client.newCall(request).execute()
val respString = resp.body?.string().toString()
JSONObject(respString)
} catch (e: JSONException) {
JSONObject("""{"error": "json"}""")
} catch (e: IOException) {
JSONObject("""{"error": "network"}""")
}
}
}
suspend fun getTimeTableJSON(): String { suspend fun getTimeTableJSON(): String {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val userIsParent = Parsing.userIsParent() val userIsParent = Parsing.userIsParent()
@@ -162,6 +187,32 @@ class Network {
} }
} }
suspend fun getTimeTable(): JSONObject {
return withContext(Dispatchers.IO) {
val userIsParent = Parsing.userIsParent()
var url = timeTableUrl
if (userIsParent) {
url += "?studentId=$studentId"
}
val request = Request.Builder()
.url(url)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", "Bearer $token")
.get()
.build()
try {
val resp = client.newCall(request).execute()
JSONObject(resp.body?.string().toString())
} catch (e: JSONException) {
JSONObject("""{"error": "json"}""")
} catch (e: IOException) {
JSONObject("""{"error": "network"}""")
}
}
}
suspend fun getMarksJSON(): String { suspend fun getMarksJSON(): String {
return withContext(Dispatchers.IO) { return withContext(Dispatchers.IO) {
val request = Request.Builder() val request = Request.Builder()
@@ -179,5 +230,25 @@ class Network {
} }
} }
} }
suspend fun getMarks(): JSONObject {
return withContext(Dispatchers.IO) {
val request = Request.Builder()
.url(marksUrl)
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", "Bearer $token")
.get()
.build()
try {
val resp = client.newCall(request).execute()
JSONObject(resp.body?.string().toString())
} catch (e: JSONException) {
JSONObject("""{"error": "json"}""")
} catch (e: IOException) {
JSONObject("""{"error": "network"}""")
}
}
}
} }
} }
@@ -1,5 +1,7 @@
package com.odweta.solon package com.odweta.solon
import androidx.compose.runtime.mutableStateOf
import com.odweta.solon.Util.Companion.getLectureId
import org.json.JSONObject import org.json.JSONObject
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -49,8 +51,8 @@ class Parsing {
else false else false
} }
fun parseTimeTableJSON(jsonString: String): List<Day> { fun parseTimetable(jsonString: JSONObject): List<Day> {
val jsonObject = JSONObject(jsonString) val jsonObject = jsonString
/* /*
* return a List that looks like this: * return a List that looks like this:
@@ -320,9 +322,9 @@ class Parsing {
return week return week
} }
fun parseMarksJSON(jsonString: String): MutableMap<String, MutableList<Mark>> { fun parseMarks(jsonString: JSONObject): MutableMap<String, MutableList<Mark>> {
// no marks // no marks
val json = JSONObject(jsonString) val json = jsonString
if (json.has("marks") && json.getJSONArray("marks").length() == 0) { if (json.has("marks") && json.getJSONArray("marks").length() == 0) {
val noMarks = mutableMapOf<String, MutableList<Mark>>() val noMarks = mutableMapOf<String, MutableList<Mark>>()
val list = mutableListOf<Mark>() val list = mutableListOf<Mark>()
@@ -379,5 +381,38 @@ class Parsing {
return marks return marks
} }
fun parseLectureNotes(lectureNotes: String) {
for (day in global.timetable) {
for ((subjectIndex, subject) in day.subjects.withIndex()) {
val id = getLectureId(day.date, subjectIndex)
global.lectureNotes[id] = LectureNote(
id = id,
type = mutableStateOf(LectureNoteType.Normal),
note = mutableStateOf(""),
number = subject.number.toInt(),
lectureName = subject.name
)
}
}
val lines = lectureNotes.lines()
for (line in lines) {
if (line.isBlank()) continue
val parts = line.split(",")
if (parts.size >= 3) {
val id = parts[0].trim().toInt()
val type = parts[1].trim().toLectureNoteType()
var note = parts[2].trim()
for (part in 3.until(parts.size)) {
note += ",${parts[part]}"
}
global.lectureNotes[id]?.note = mutableStateOf(note)
global.lectureNotes[id]?.type = mutableStateOf(type)
}
}
}
} }
} }
@@ -37,7 +37,7 @@ import com.odweta.solon.ui.theme.PastelYellow
fun SettingsScreen(modifier: Modifier = Modifier) { fun SettingsScreen(modifier: Modifier = Modifier) {
// 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)
BackHandler { BackHandler {
isShowing.value = IsShowing.Menu isShowing = IsShowing.Menu
} }
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
@@ -54,7 +54,7 @@ fun SettingsScreen(modifier: Modifier = Modifier) {
) { ) {
Button( Button(
onClick = { onClick = {
isShowing.value = IsShowing.Menu isShowing = IsShowing.Menu
}, },
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
contentColor = Color.White, contentColor = Color.White,
@@ -147,3 +147,25 @@ fun SettingsTableRow(setting: Setting) {
) )
} }
} }
fun String.toSettingsData(): SettingsData {
val settings = this.split("\n")
val auxSettingsData = SettingsData()
val useSvobodaMode = settings[0].split("#")
val useAmoledMode = settings[1].split("#")
val showRefreshButton = settings[2].split("#")
auxSettingsData.useSvobodaMode.id = SettingsId.Svoboda
auxSettingsData.useSvobodaMode.name = useSvobodaMode[1]
auxSettingsData.useSvobodaMode.checked.value = useSvobodaMode[2].toBoolean()
auxSettingsData.useAmoledMode.id = SettingsId.Amoled
auxSettingsData.useAmoledMode.name = useAmoledMode[1]
auxSettingsData.useAmoledMode.checked.value = useAmoledMode[2].toBoolean()
auxSettingsData.showRefreshButton.id = SettingsId.RefreshButton
auxSettingsData.showRefreshButton.name = showRefreshButton[1]
auxSettingsData.showRefreshButton.checked.value = showRefreshButton[2].toBoolean()
return auxSettingsData
}
@@ -109,8 +109,10 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri
@Composable @Composable
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)
BackHandler { if (!global.noSignInBackHandle) {
screenToShow.value = Screen.Main BackHandler {
screenToShow.value = Screen.Main
}
} }
var usernameText by remember { mutableStateOf("") } var usernameText by remember { mutableStateOf("") }
@@ -44,3 +44,7 @@ fun ToolbarScreen() {
) )
} }
} }
fun showStatus(text: String) {
toolbarText.value = text
}
@@ -265,7 +265,7 @@ class Util {
}) })
} }
private fun csvToLectureNotes() { fun csvToLectureNotes() {
val lines = fileToString(lectureNotesFilePath).lines() val lines = fileToString(lectureNotesFilePath).lines()
for (line in lines) { for (line in lines) {
if (line.isBlank()) continue if (line.isBlank()) continue
@@ -286,7 +286,7 @@ class Util {
} }
} }
private fun lectureNotesToCsvString(hashMap: HashMap<Int, LectureNote>): String { fun lectureNotesToCsvString(hashMap: HashMap<Int, LectureNote>): String {
var result = "" var result = ""
for ((key, lectureNote) in hashMap) { for ((key, lectureNote) in hashMap) {
result += result +=