refined the launch proccess and improved the architecture of global variables
This commit is contained in:
@@ -38,10 +38,10 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
@Composable
|
||||
fun AboutScreen(modifier: Modifier = Modifier) {
|
||||
fun AboutScreen() {
|
||||
// handle the back gesture (back swipe form side or back button on bottom android navbar)
|
||||
BackHandler {
|
||||
isShowing.value = IsShowing.Menu
|
||||
isShowing = IsShowing.Menu
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -50,35 +50,7 @@ fun AboutScreen(modifier: Modifier = Modifier) {
|
||||
verticalArrangement = Arrangement.Top,
|
||||
horizontalAlignment = Alignment.Start
|
||||
) {
|
||||
Box(
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
backButtonFactory.get(BackButtonType.Menu)()
|
||||
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
@@ -126,7 +98,7 @@ fun AboutScreen(modifier: Modifier = Modifier) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HorizontalLine(modifier: Modifier = Modifier) {
|
||||
fun HorizontalLine() {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
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.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.odweta.solon.ui.theme.PastelYellow
|
||||
import okhttp3.OkHttpClient
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
|
||||
// Global values (dimens, modifiers, ...)
|
||||
@@ -72,7 +74,7 @@ var screenToShow: MutableState<Screen> = mutableStateOf(Screen.Main)
|
||||
|
||||
var signedInAndReadyToLaunch: MutableState<Boolean> = mutableStateOf(false)
|
||||
|
||||
var isShowing: MutableState<IsShowing> = mutableStateOf(IsShowing.Timetable)
|
||||
var isShowing by mutableStateOf(IsShowing.Timetable)
|
||||
|
||||
var toolbarText: MutableState<String> = mutableStateOf("")
|
||||
|
||||
@@ -281,3 +283,45 @@ class 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()
|
||||
.weight(1f)
|
||||
) {
|
||||
when (isShowing.value) {
|
||||
when (isShowing) {
|
||||
IsShowing.Timetable -> TimetableScreen()
|
||||
IsShowing.Marks -> MarksScreen()
|
||||
IsShowing.Menu -> MenuScreen()
|
||||
|
||||
@@ -14,21 +14,18 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||
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.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -55,13 +52,13 @@ enum class MarksShow {
|
||||
Detail
|
||||
}
|
||||
|
||||
var marksShow: MutableState<MarksShow> = mutableStateOf(MarksShow.All)
|
||||
var marksShow by mutableStateOf(MarksShow.All)
|
||||
private var subjectToShow: String = ""
|
||||
private var markToShow: Mark = Mark()
|
||||
|
||||
@Composable
|
||||
fun MarksScreen() {
|
||||
when (marksShow.value) {
|
||||
when (marksShow) {
|
||||
MarksShow.All -> MarksAll()
|
||||
MarksShow.Subject -> MarksSubject()
|
||||
MarksShow.Detail -> MarksDetail()
|
||||
@@ -145,7 +142,7 @@ fun MarksAll() {
|
||||
shape = RoundedCornerShape(roundedCornerDimen)
|
||||
)
|
||||
.clickable {
|
||||
marksShow.value = MarksShow.Subject
|
||||
marksShow = MarksShow.Subject
|
||||
subjectToShow = subject
|
||||
}
|
||||
} else {
|
||||
@@ -157,7 +154,7 @@ fun MarksAll() {
|
||||
shape = RoundedCornerShape(roundedCornerDimen)
|
||||
)
|
||||
.clickable {
|
||||
marksShow.value = MarksShow.Subject
|
||||
marksShow = MarksShow.Subject
|
||||
subjectToShow = subject
|
||||
}
|
||||
}
|
||||
@@ -268,7 +265,7 @@ fun MarksAll() {
|
||||
fun MarksSubject() {
|
||||
// handle the back gesture (back swipe form side or back button on bottom android navbar)
|
||||
BackHandler {
|
||||
marksShow.value = MarksShow.All
|
||||
marksShow = MarksShow.All
|
||||
}
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
@@ -283,29 +280,7 @@ fun MarksSubject() {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Button(
|
||||
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)
|
||||
)
|
||||
}
|
||||
backButtonFactory.get(BackButtonType.MarksAll)()
|
||||
|
||||
Box(modifier = Modifier.weight(1f))
|
||||
|
||||
@@ -397,7 +372,7 @@ fun MarksSubject() {
|
||||
.padding(vertical = 10.dp)
|
||||
.clickable {
|
||||
markToShow = mark
|
||||
marksShow.value = MarksShow.Detail
|
||||
marksShow = MarksShow.Detail
|
||||
}
|
||||
) {
|
||||
Box(
|
||||
@@ -450,7 +425,7 @@ fun MarksSubject() {
|
||||
fun MarksDetail() {
|
||||
// handle the back gesture (back swipe form side or back button on bottom android navbar)
|
||||
BackHandler {
|
||||
marksShow.value = MarksShow.Subject
|
||||
marksShow = MarksShow.Subject
|
||||
}
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
@@ -466,29 +441,7 @@ fun MarksDetail() {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Button(
|
||||
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)
|
||||
)
|
||||
}
|
||||
backButtonFactory.get(BackButtonType.MarksSubject)()
|
||||
|
||||
Box(modifier = Modifier.weight(1f))
|
||||
|
||||
@@ -540,7 +493,8 @@ fun MarksDetail() {
|
||||
color = PastelYellow,
|
||||
shape = RoundedCornerShape(roundedCornerDimen)
|
||||
)
|
||||
.background(if (settings.useAmoledMode.checked.value) {
|
||||
.background(
|
||||
if (settings.useAmoledMode.checked.value) {
|
||||
Color.Black
|
||||
} else {
|
||||
PastelYellowTransparent
|
||||
|
||||
@@ -44,11 +44,11 @@ fun MenuScreen(modifier: Modifier = Modifier) {
|
||||
|
||||
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))
|
||||
|
||||
MenuButton({ isShowing.value = IsShowing.Settings }, "Nastavení")
|
||||
MenuButton({ isShowing = IsShowing.Settings }, "Nastavení")
|
||||
}
|
||||
|
||||
// Dialog implementation
|
||||
|
||||
@@ -67,7 +67,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
isShowing.value = IsShowing.Timetable
|
||||
isShowing = IsShowing.Timetable
|
||||
timetableColor.value = PastelYellow
|
||||
marksColor.value = Color.White
|
||||
menuColor.value = Color.White
|
||||
@@ -88,11 +88,11 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
isShowing.value = IsShowing.Marks
|
||||
isShowing = IsShowing.Marks
|
||||
timetableColor.value = Color.White
|
||||
marksColor.value = PastelYellow
|
||||
menuColor.value = Color.White
|
||||
marksShow.value = MarksShow.All
|
||||
marksShow = MarksShow.All
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
contentColor = marksColor.value,
|
||||
@@ -110,7 +110,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
|
||||
|
||||
Button(
|
||||
onClick = {
|
||||
isShowing.value = IsShowing.Menu
|
||||
isShowing = IsShowing.Menu
|
||||
timetableColor.value = Color.White
|
||||
marksColor.value = Color.White
|
||||
menuColor.value = PastelYellow
|
||||
|
||||
@@ -29,8 +29,12 @@ class Network {
|
||||
|
||||
try {
|
||||
val resp = client.newCall(request).execute()
|
||||
val respString = resp.body?.string()
|
||||
respString.toString()
|
||||
val respString = resp.body?.string().toString()
|
||||
if (JSONObject(respString).has("access_token")) {
|
||||
JSONObject(respString).getString("access_token")
|
||||
} else {
|
||||
""""error": "network""""
|
||||
}
|
||||
//val respJson = respString?.let { JSONObject(it) }
|
||||
//respJson.toString()
|
||||
} 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 {
|
||||
return withContext(Dispatchers.IO) {
|
||||
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 {
|
||||
return withContext(Dispatchers.IO) {
|
||||
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
|
||||
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.odweta.solon.Util.Companion.getLectureId
|
||||
import org.json.JSONObject
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
@@ -49,8 +51,8 @@ class Parsing {
|
||||
else false
|
||||
}
|
||||
|
||||
fun parseTimeTableJSON(jsonString: String): List<Day> {
|
||||
val jsonObject = JSONObject(jsonString)
|
||||
fun parseTimetable(jsonString: JSONObject): List<Day> {
|
||||
val jsonObject = jsonString
|
||||
|
||||
/*
|
||||
* return a List that looks like this:
|
||||
@@ -320,9 +322,9 @@ class Parsing {
|
||||
return week
|
||||
}
|
||||
|
||||
fun parseMarksJSON(jsonString: String): MutableMap<String, MutableList<Mark>> {
|
||||
fun parseMarks(jsonString: JSONObject): MutableMap<String, MutableList<Mark>> {
|
||||
// no marks
|
||||
val json = JSONObject(jsonString)
|
||||
val json = jsonString
|
||||
if (json.has("marks") && json.getJSONArray("marks").length() == 0) {
|
||||
val noMarks = mutableMapOf<String, MutableList<Mark>>()
|
||||
val list = mutableListOf<Mark>()
|
||||
@@ -379,5 +381,38 @@ class Parsing {
|
||||
|
||||
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) {
|
||||
// handle the back gesture (back swipe form side or back button on bottom android navbar)
|
||||
BackHandler {
|
||||
isShowing.value = IsShowing.Menu
|
||||
isShowing = IsShowing.Menu
|
||||
}
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
@@ -54,7 +54,7 @@ fun SettingsScreen(modifier: Modifier = Modifier) {
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
isShowing.value = IsShowing.Menu
|
||||
isShowing = IsShowing.Menu
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
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,9 +109,11 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri
|
||||
@Composable
|
||||
fun SignInScreen() {
|
||||
// handle the back gesture (back swipe form side or back button on bottom android navbar)
|
||||
if (!global.noSignInBackHandle) {
|
||||
BackHandler {
|
||||
screenToShow.value = Screen.Main
|
||||
}
|
||||
}
|
||||
|
||||
var usernameText by remember { mutableStateOf("") }
|
||||
var passwordText 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()
|
||||
for (line in lines) {
|
||||
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 = ""
|
||||
for ((key, lectureNote) in hashMap) {
|
||||
result +=
|
||||
|
||||
Reference in New Issue
Block a user