started working on the grand refactor (the app launches)
This commit is contained in:
@@ -27,7 +27,7 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// check if file exists
|
// check if file exists
|
||||||
val file = File(fileDir, accountDataFilePath)
|
val file = File(global.fileDir, accountDataFilePath)
|
||||||
|
|
||||||
return if (!file.exists()) {
|
return if (!file.exists()) {
|
||||||
// it does not exist
|
// it does not exist
|
||||||
@@ -36,15 +36,15 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
} else {
|
} else {
|
||||||
// it exists, so it shall be parsed
|
// it exists, so it shall be parsed
|
||||||
val acc: Account = parseAccountDataFile(file)
|
val acc: Account = parseAccountDataFile(file)
|
||||||
username = acc.username
|
global.username = acc.username
|
||||||
password = acc.password
|
global.password = acc.password
|
||||||
acc.error == 0
|
acc.error == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun save(acc: Account): Boolean {
|
fun save(acc: Account): Boolean {
|
||||||
return try {
|
return try {
|
||||||
val file = File(fileDir, accountDataFilePath)
|
val file = File(global.fileDir, accountDataFilePath)
|
||||||
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
||||||
|
|
||||||
true
|
true
|
||||||
@@ -55,8 +55,8 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
|
|
||||||
suspend fun isValid(acc: Account): Boolean {
|
suspend fun isValid(acc: Account): Boolean {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
username = acc.username
|
global.username = acc.username
|
||||||
password = acc.password
|
global.password = acc.password
|
||||||
|
|
||||||
val token = Network.getToken()
|
val token = Network.getToken()
|
||||||
!JSONObject(token).has("error")
|
!JSONObject(token).has("error")
|
||||||
|
|||||||
@@ -45,10 +45,8 @@ const val userDataFilePath: String = "userdata.json"
|
|||||||
const val marksFilePath: String = "marks.json"
|
const val marksFilePath: String = "marks.json"
|
||||||
const val settingsDataFilePath: String = "settings.txt"
|
const val settingsDataFilePath: String = "settings.txt"
|
||||||
const val lectureNotesFilePath: String = "lecture_notes.csv"
|
const val lectureNotesFilePath: String = "lecture_notes.csv"
|
||||||
lateinit var fileDir: File
|
|
||||||
var width: Int = 0
|
var width: Int = 0
|
||||||
var height: Int = 0
|
var height: Int = 0
|
||||||
var internetAvail: Boolean = false
|
|
||||||
|
|
||||||
var loaded: Boolean = false
|
var loaded: Boolean = false
|
||||||
|
|
||||||
@@ -137,7 +135,6 @@ val dayMap = mutableMapOf<Int, Day>()
|
|||||||
val dayList = mutableListOf<Day>()
|
val dayList = mutableListOf<Day>()
|
||||||
var days = listOf<Day>()
|
var days = listOf<Day>()
|
||||||
|
|
||||||
var marksJSON: String = ""
|
|
||||||
var marks: MutableMap<String, MutableList<Mark>> = mutableMapOf()
|
var marks: MutableMap<String, MutableList<Mark>> = mutableMapOf()
|
||||||
|
|
||||||
var username: String = ""
|
var username: String = ""
|
||||||
@@ -145,10 +142,6 @@ var password: String = ""
|
|||||||
|
|
||||||
val client = OkHttpClient()
|
val client = OkHttpClient()
|
||||||
|
|
||||||
var resetNav: Boolean = false
|
|
||||||
|
|
||||||
var isAPISetUp: Boolean = false
|
|
||||||
|
|
||||||
enum class LectureNoteType {
|
enum class LectureNoteType {
|
||||||
Normal, // obycejna poznamka
|
Normal, // obycejna poznamka
|
||||||
Writing, // pisemny test
|
Writing, // pisemny test
|
||||||
@@ -203,10 +196,10 @@ const val tokenUrl = "$apiBaseUrl/connect/token"
|
|||||||
var token: String = ""
|
var token: String = ""
|
||||||
const val userDataUrl = "$apiBaseUrl/v1/user"
|
const val userDataUrl = "$apiBaseUrl/v1/user"
|
||||||
var userData: String = ""
|
var userData: String = ""
|
||||||
var studentId: String = ""
|
//var studentId: String = ""
|
||||||
const val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
const val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
||||||
var syid = "" // school year id
|
var syid = "" // school year id
|
||||||
var marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list?SemesterId=$syid"
|
var marksUrl = "$apiBaseUrl/v1/students/abc/marks/list?SemesterId=$syid"
|
||||||
|
|
||||||
class Subject {
|
class Subject {
|
||||||
lateinit var name: String
|
lateinit var name: String
|
||||||
@@ -284,44 +277,68 @@ class Mark {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object FilePaths {
|
enum class ScreenElement {
|
||||||
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,
|
Timetable,
|
||||||
Marks,
|
Marks,
|
||||||
Menu
|
Menu,
|
||||||
|
About,
|
||||||
|
Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
object Global {
|
class Global {
|
||||||
lateinit var token: String
|
lateinit var token: String
|
||||||
lateinit var userData: JSONObject
|
lateinit var userData: JSONObject
|
||||||
lateinit var timetable: List<Day>
|
lateinit var timetable: List<Day>
|
||||||
|
lateinit var timetableJSON: JSONObject
|
||||||
lateinit var marks: MutableMap<String, MutableList<Mark>>
|
lateinit var marks: MutableMap<String, MutableList<Mark>>
|
||||||
var noSignInBackHandle: Boolean = false
|
lateinit var marksJSON: JSONObject
|
||||||
val filePaths: FilePaths = FilePaths
|
lateinit var studentClass: String
|
||||||
val apiEndPoints: APIEndpoints = APIEndpoints
|
|
||||||
lateinit var settings: SettingsData
|
lateinit var settings: SettingsData
|
||||||
|
lateinit var studentId: String
|
||||||
|
lateinit var fileDir: File
|
||||||
|
var username: String = ""
|
||||||
|
var password: String = ""
|
||||||
|
var isAPISetUp: Boolean = false
|
||||||
|
var noSignInBackHandle: Boolean = false
|
||||||
var lectureNotes: HashMap<Int, LectureNote> = hashMapOf()
|
var lectureNotes: HashMap<Int, LectureNote> = hashMapOf()
|
||||||
var currentScreen by mutableStateOf(Screen.Main)
|
var currentScreen by mutableStateOf(Screen.Main)
|
||||||
var currentMainElement by mutableStateOf(MainElement.Timetable)
|
var currentScreenElement by mutableStateOf(ScreenElement.Timetable)
|
||||||
|
inner class FilePaths {
|
||||||
|
val accountData: String = "account_data.txt"
|
||||||
|
val timeTable: String = "timetable.json"
|
||||||
|
val userData: String = "userdata.json"
|
||||||
|
val marks: String = "marks.json"
|
||||||
|
val settings: String = "settings.txt"
|
||||||
|
val lectureNotes: String = "lecture_notes.csv"
|
||||||
|
}
|
||||||
|
val filePaths = FilePaths()
|
||||||
|
inner class APIEndPoints {
|
||||||
|
val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api"
|
||||||
|
val tokenUrl = "$apiBaseUrl/connect/token"
|
||||||
|
lateinit var token: String
|
||||||
|
val userDataUrl = "$apiBaseUrl/v1/user"
|
||||||
|
lateinit var userData: String
|
||||||
|
val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
||||||
|
lateinit var marksUrl: String
|
||||||
|
}
|
||||||
|
val apiEndPoints = APIEndPoints()
|
||||||
|
inner class Dimens {
|
||||||
|
val borderWidth = 5.dp
|
||||||
|
val roundedCorner = 8.dp
|
||||||
|
}
|
||||||
|
val dimens = Dimens()
|
||||||
|
inner class Modifiers {
|
||||||
|
var bar = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(100.dp)
|
||||||
|
.padding(20.dp)
|
||||||
|
.border(
|
||||||
|
width = Dimens().borderWidth,
|
||||||
|
color = PastelYellow,
|
||||||
|
shape = RoundedCornerShape(Dimens().roundedCorner)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val modifiers = Modifiers()
|
||||||
}
|
}
|
||||||
|
|
||||||
val global = Global
|
val global = Global()
|
||||||
@@ -1,308 +1,112 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.widget.Toast
|
import android.util.Log
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
private var week: List<Day> = mutableListOf()
|
fun launchStart(ctx: Context) {
|
||||||
private var toastShowing: Boolean = false
|
if (Account.haveSaved()) {
|
||||||
private var toastShown: Boolean = false
|
if (Util.internetAvail(ctx)) {
|
||||||
private var toast2Shown: Boolean = false
|
remoteLoad(ctx)
|
||||||
|
} else {
|
||||||
|
localLoad(ctx)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
global.noSignInBackHandle = true
|
||||||
|
screenToShow.value = Screen.SignIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private lateinit var coscope_: CoroutineScope
|
fun remoteLoad(ctx: Context) {
|
||||||
|
var remoteTimetable: JSONObject
|
||||||
|
var remoteMarks: JSONObject
|
||||||
|
if (!global.isAPISetUp) {
|
||||||
|
CoroutineScope(Dispatchers.IO)
|
||||||
|
.launch {
|
||||||
|
Network.setupAPI()
|
||||||
|
remoteTimetable = Network.getTimeTable()
|
||||||
|
global.timetableJSON = remoteTimetable
|
||||||
|
remoteMarks = Network.getMarks()
|
||||||
|
global.marksJSON = remoteMarks
|
||||||
|
|
||||||
private fun setOnInternetAvailListener(ctx: Context, coscope: CoroutineScope) {
|
launchContinue(
|
||||||
|
ctx,
|
||||||
|
remoteTimetable,
|
||||||
|
remoteMarks
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
launchContinue(
|
||||||
|
ctx,
|
||||||
|
global.timetableJSON,
|
||||||
|
global.marksJSON
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.currentScreenElement = ScreenElement.Timetable
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setOnInternetAvailListener(ctx: Context) {
|
||||||
internetAwaitListenerRunning = true
|
internetAwaitListenerRunning = true
|
||||||
coscope.launch {
|
var internetAvail = Util.internetAvail(ctx)
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (Util.internetAvail(ctx) && !internetAvail) {
|
if (Util.internetAvail(ctx) && !internetAvail) {
|
||||||
internetAvail = Util.internetAvail(ctx)
|
internetAvail = Util.internetAvail(ctx)
|
||||||
coscope.launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
fetchNewData(ctx, coscope)
|
remoteLoad(ctx)
|
||||||
}
|
}
|
||||||
} else if (!internetAvail) {
|
} else if (!internetAvail) {
|
||||||
internetAvail = Util.internetAvail(ctx)
|
internetAvail = Util.internetAvail(ctx)
|
||||||
toolbarText.value = "Bez připojení k internetu."
|
showStatus("Bez připojení k internetu.")
|
||||||
} else {
|
} else {
|
||||||
internetAvail = Util.internetAvail(ctx)
|
internetAvail = Util.internetAvail(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(1000) // Check for internet availability every second
|
delay(1000) // Check for internet availability every second
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fetchNewData(ctx: Context, coscope: CoroutineScope) {
|
|
||||||
coscope.launch {
|
|
||||||
done = false
|
|
||||||
|
|
||||||
// variables for the loading animation
|
|
||||||
val loadingArray: Array<String> = arrayOf(
|
|
||||||
"Načítání nových dat",
|
|
||||||
"Načítání nových dat.",
|
|
||||||
"Načítání nových dat..",
|
|
||||||
"Načítání nových dat...",
|
|
||||||
"Načítání nových dat..",
|
|
||||||
"Načítání nových dat."
|
|
||||||
)
|
|
||||||
val delayTime: Long = 300 // delay in ms
|
|
||||||
|
|
||||||
// show a loading animation
|
|
||||||
while (!done && Util.internetAvail(ctx)) {
|
|
||||||
for (text in loadingArray) {
|
|
||||||
if (done) break
|
|
||||||
toolbarText.value = text
|
|
||||||
delay(delayTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine the role of the student
|
|
||||||
val role = if (Parsing.userIsParent()) {
|
|
||||||
" – Rodič"
|
|
||||||
} else {
|
|
||||||
" – Student"
|
|
||||||
}
|
|
||||||
|
|
||||||
// display the full name of the user in the toolbar
|
|
||||||
toolbarText.value =
|
|
||||||
"${
|
|
||||||
JSONObject(
|
|
||||||
Util.fileToString(
|
|
||||||
userDataFilePath
|
|
||||||
)
|
|
||||||
).getString("fullName")}$role"
|
|
||||||
}
|
|
||||||
|
|
||||||
coscope.launch {
|
|
||||||
launchPhase1(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun launchPhase0(ctx: Context, coscope: CoroutineScope) {
|
|
||||||
// start a sign in activity
|
|
||||||
// gather input and put it into global state (if login is needed)
|
|
||||||
// otherwise show the splash screen and load the app
|
|
||||||
|
|
||||||
/* check if there is a saved user account
|
|
||||||
*
|
|
||||||
* if yes, use that
|
|
||||||
* otherwise show the login activity
|
|
||||||
*/
|
|
||||||
|
|
||||||
coscope_ = coscope
|
|
||||||
fileDir = ctx.filesDir
|
|
||||||
width = Util.getDisplayWidth(ctx)
|
|
||||||
height = Util.getDisplayHeight(ctx)
|
|
||||||
|
|
||||||
val accSaved: Boolean = Account.haveSaved()
|
|
||||||
|
|
||||||
if (!accSaved) {
|
|
||||||
// show the sign in screen
|
|
||||||
screenToShow.value = Screen.SignIn
|
|
||||||
} else {
|
|
||||||
// show the splash/loading screen
|
|
||||||
screenToShow.value = Screen.Splash
|
|
||||||
coscope.launch {
|
|
||||||
// launch!
|
|
||||||
launchPhase1(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun launchPhase1(ctx: Context) {
|
|
||||||
// TODO: CONVERT TO SNACKBARS
|
|
||||||
val toast: Toast = Toast.makeText(
|
|
||||||
ctx,
|
|
||||||
"Nelze načíst data, zkuste se připojit k internetu.",
|
|
||||||
Toast.LENGTH_LONG
|
|
||||||
)
|
|
||||||
|
|
||||||
val toast2: Toast = Toast.makeText(
|
|
||||||
ctx,
|
|
||||||
"Připojeno k internetu.",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
)
|
|
||||||
|
|
||||||
// check if the file is available offline,
|
|
||||||
// if yes, load the data and don't connect to the internet
|
|
||||||
internetAvail = Util.internetAvail(ctx)
|
|
||||||
timeTableAvailOffline =
|
|
||||||
Util.fileExists(timeTableFilePath) && !Util.fileIsEmpty(timeTableFilePath)
|
|
||||||
marksAvailOffline =
|
|
||||||
Util.fileExists(marksFilePath) && !Util.fileIsEmpty(marksFilePath)
|
|
||||||
|
|
||||||
if (toastShown && internetAvail && !toast2Shown) {
|
|
||||||
toast2Shown = true
|
|
||||||
toast2.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!timeTableAvailOffline || !marksAvailOffline || internetAvail) {
|
|
||||||
// set up the API (required for later uses of it)
|
|
||||||
if (!isAPISetUp) {
|
|
||||||
Network.setupAPI()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (internetAvail) {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the JSON data
|
|
||||||
var timeTableJSON = Network.getTimeTableJSON()
|
|
||||||
if (timeTableJSON == """{"error": "network"}""") {
|
|
||||||
timeTableJSON = Util.fileToString(timeTableFilePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch and parse marks
|
|
||||||
marksJSON = Network.getMarksJSON()
|
|
||||||
if (marksJSON == """{"error": "network"}""") {
|
|
||||||
marksJSON = Util.fileToString(marksFilePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
timeTableAvailOffline =
|
|
||||||
Util.saveStringToFile(timeTableFilePath, timeTableJSON)
|
|
||||||
marksAvailOffline =
|
|
||||||
Util.saveStringToFile(marksFilePath, marksJSON)
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
|
||||||
marks = Parsing.parseMarksJSON(marksJSON)
|
|
||||||
|
|
||||||
// set the settings
|
|
||||||
if (Util.fileExists(settingsDataFilePath) && !Util.fileIsEmpty(settingsDataFilePath)) {
|
|
||||||
settings = Util.stringToSettingsData(Util.fileToString(settingsDataFilePath))
|
|
||||||
} // else load the default settings
|
|
||||||
|
|
||||||
// continue to launch phase 2
|
|
||||||
done = true
|
|
||||||
launchPhase2(ctx)
|
|
||||||
} else {
|
|
||||||
if (timeTableAvailOffline) {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the offline data
|
|
||||||
val timeTableJSON = Util.fileToString(timeTableFilePath)
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
if (timeTableJSON != "") {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
|
||||||
|
|
||||||
// continue launching
|
|
||||||
done = true
|
|
||||||
launchPhase2(ctx)
|
|
||||||
} else {
|
|
||||||
// make a toast or something
|
|
||||||
toast.show()
|
|
||||||
|
|
||||||
// try to reconnect to the internet
|
|
||||||
launchPhase1(ctx)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// make a toast or something
|
|
||||||
if (!toastShown) {
|
|
||||||
toast.show()
|
|
||||||
toastShowing = true
|
|
||||||
toastShown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to reconnect to the internet
|
|
||||||
launchPhase1(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// load offline
|
|
||||||
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// load the offline data
|
|
||||||
val timeTableJSON = Util.fileToString(timeTableFilePath)
|
|
||||||
|
|
||||||
marksJSON = Util.fileToString(marksFilePath)
|
|
||||||
if (marksJSON == "") {
|
|
||||||
marksJSON =
|
|
||||||
"""{"message": "Zatím žádné známky, zkuste aktualizovat data."}"""
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
if (timeTableJSON != "") {
|
|
||||||
// cancel a toast, if any
|
|
||||||
if (toastShowing && !toastShown) {
|
|
||||||
toast.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse the data
|
|
||||||
week = Parsing.parseTimeTableJSON(timeTableJSON)
|
|
||||||
|
|
||||||
marks = Parsing.parseMarksJSON(marksJSON)
|
|
||||||
|
|
||||||
// continue launching
|
|
||||||
done = true
|
|
||||||
launchPhase2(ctx)
|
|
||||||
} else {
|
|
||||||
// make a toast or something
|
|
||||||
if (!toastShown) {
|
|
||||||
toast.show()
|
|
||||||
toastShowing = true
|
|
||||||
toastShown = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to reconnect to the internet
|
|
||||||
launchPhase1(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launchPhase2(ctx: Context) {
|
|
||||||
days = week
|
|
||||||
for ((i, day) in week.withIndex()) {
|
|
||||||
dayMap[i] = day
|
|
||||||
dayList.add(day)
|
|
||||||
}
|
|
||||||
|
|
||||||
Util.loadLectureNotes()
|
|
||||||
|
|
||||||
loaded = true
|
|
||||||
|
|
||||||
coscope_.launch {
|
|
||||||
if (!internetAwaitListenerRunning) {
|
|
||||||
setOnInternetAvailListener(ctx, coscope_)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val role = if (Parsing.userIsParent()) {
|
|
||||||
" – Rodič"
|
|
||||||
} else {
|
|
||||||
" – Student"
|
|
||||||
}
|
|
||||||
|
|
||||||
toolbarText.value = "${
|
|
||||||
JSONObject(
|
|
||||||
Util.fileToString(
|
|
||||||
userDataFilePath
|
|
||||||
)
|
|
||||||
).getString("fullName")
|
|
||||||
}$role"
|
|
||||||
|
|
||||||
// set the main content view
|
|
||||||
screenToShow.value = Screen.Main
|
|
||||||
|
|
||||||
if (settings.showRefreshButton.checked.value) {
|
|
||||||
refreshButtonContentColor.value = Color.White
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,19 +24,13 @@ class MainActivity : ComponentActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
makeStatusBarBlack(window)
|
makeStatusBarBlack(window)
|
||||||
|
global.fileDir = applicationContext.filesDir
|
||||||
|
|
||||||
|
launchStart(applicationContext)
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
if (!loaded) {
|
|
||||||
launchPhase0(LocalContext.current, rememberCoroutineScope())
|
|
||||||
}
|
|
||||||
|
|
||||||
when (signedInAndReadyToLaunch.value) {
|
|
||||||
true -> launchPhase0(LocalContext.current, rememberCoroutineScope())
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
SolonTheme {
|
SolonTheme {
|
||||||
when (screenToShow.value) {
|
when (global.currentScreen) {
|
||||||
Screen.Main -> MainScreen()
|
Screen.Main -> MainScreen()
|
||||||
Screen.Splash -> SplashScreen()
|
Screen.Splash -> SplashScreen()
|
||||||
Screen.SignIn -> SignInScreen()
|
Screen.SignIn -> SignInScreen()
|
||||||
@@ -46,14 +40,14 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScreen(modifier: Modifier = Modifier) {
|
fun MainScreen() {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(Color.Black)
|
.background(Color.Black)
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = barModifier,
|
modifier = global.modifiers.bar,
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
ToolbarScreen()
|
ToolbarScreen()
|
||||||
@@ -64,17 +58,17 @@ class MainActivity : ComponentActivity() {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
when (isShowing) {
|
when (global.currentScreenElement) {
|
||||||
IsShowing.Timetable -> TimetableScreen()
|
ScreenElement.Timetable -> TimetableScreen()
|
||||||
IsShowing.Marks -> MarksScreen()
|
ScreenElement.Marks -> MarksScreen()
|
||||||
IsShowing.Menu -> MenuScreen()
|
ScreenElement.Menu -> MenuScreen()
|
||||||
IsShowing.About -> AboutScreen()
|
ScreenElement.About -> AboutScreen()
|
||||||
IsShowing.Settings -> SettingsScreen()
|
ScreenElement.Settings -> SettingsScreen()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = barModifier,
|
modifier = global.modifiers.bar,
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
NavbarScreen()
|
NavbarScreen()
|
||||||
|
|||||||
@@ -34,9 +34,8 @@ private var menuColor: MutableState<Color> = mutableStateOf(Color.White)
|
|||||||
var refreshButtonContentColor: MutableState<Color> = mutableStateOf(Color.White)
|
var refreshButtonContentColor: MutableState<Color> = mutableStateOf(Color.White)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NavbarScreen(modifier: Modifier = Modifier) {
|
fun NavbarScreen() {
|
||||||
val ctx = LocalContext.current
|
val ctx = LocalContext.current
|
||||||
val coscope = rememberCoroutineScope()
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.Center,
|
horizontalArrangement = Arrangement.Center,
|
||||||
@@ -47,7 +46,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
|
|||||||
spacerModifier = 15.dp
|
spacerModifier = 15.dp
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
fetchNewData(ctx, coscope)
|
remoteLoad(ctx)
|
||||||
refreshButtonContentColor.value = PastelYellow
|
refreshButtonContentColor.value = PastelYellow
|
||||||
},
|
},
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
|||||||
@@ -11,23 +11,22 @@ import java.io.IOException
|
|||||||
|
|
||||||
class Network {
|
class Network {
|
||||||
companion object {
|
companion object {
|
||||||
suspend fun getToken(): String {
|
fun getToken(): String {
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(tokenUrl)
|
.url(global.apiEndPoints.tokenUrl)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.post(
|
.post(
|
||||||
FormBody.Builder()
|
FormBody.Builder()
|
||||||
.add("grant_type", "password")
|
.add("grant_type", "password")
|
||||||
.add("username", username)
|
.add("username", global.username)
|
||||||
.add("password", password)
|
.add("password", global.password)
|
||||||
.add("client_id", "test_client")
|
.add("client_id", "test_client")
|
||||||
.add("scope", "openid offline_access profile sol_api")
|
.add("scope", "openid offline_access profile sol_api")
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
return try {
|
||||||
val resp = client.newCall(request).execute()
|
val resp = client.newCall(request).execute()
|
||||||
val respString = resp.body?.string().toString()
|
val respString = resp.body?.string().toString()
|
||||||
if (JSONObject(respString).has("access_token")) {
|
if (JSONObject(respString).has("access_token")) {
|
||||||
@@ -44,114 +43,56 @@ class Network {
|
|||||||
"""{"error": "network"}"""
|
"""{"error": "network"}"""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun setupAPI() {
|
fun setupAPI() {
|
||||||
return withContext(Dispatchers.IO) {
|
global.token = "NETWORK_UNREACHABLE"
|
||||||
token = "NETWORK_UNREACHABLE"
|
val token = getToken()
|
||||||
token = getToken()
|
|
||||||
if (""""error": """ !in token) {
|
if (""""error": """ !in token) {
|
||||||
token = JSONObject(token).get("access_token").toString()
|
global.token = token
|
||||||
}
|
}
|
||||||
if (token == "NETWORK_UNREACHABLE" || """"error": """ in token) {
|
if (global.token == "NETWORK_UNREACHABLE" || """"error": """ in global.token) {
|
||||||
userData = ""
|
global.userData = JSONObject()
|
||||||
studentId = ""
|
global.studentId = ""
|
||||||
internetAvail = false
|
return
|
||||||
return@withContext
|
|
||||||
}
|
}
|
||||||
internetAvail = true
|
global.userData = getUserData()
|
||||||
userData = getUserDataJSON()
|
Util.saveStringToFile(global.filePaths.userData, global.userData.toString())
|
||||||
Util.saveStringToFile(userDataFilePath, userData)
|
global.studentClass = if (!Parsing.userIsParent()) {
|
||||||
studentClass = if (!Parsing.userIsParent()) {
|
|
||||||
JSONObject(
|
JSONObject(
|
||||||
Util.fileToString(userDataFilePath)
|
Util.fileToString(global.filePaths.userData)
|
||||||
).getJSONObject("class").get("name").toString()
|
).getJSONObject("class").getString("name")
|
||||||
} else {
|
} else {
|
||||||
// if the user is a parent, the class will be of their first child
|
// if the user is a parent, the class will be of their first child
|
||||||
JSONObject(
|
JSONObject(
|
||||||
Util.fileToString(userDataFilePath)
|
Util.fileToString(global.filePaths.userData)
|
||||||
).getJSONArray("children").getJSONObject(0).getString("className")
|
).getJSONArray("children").getJSONObject(0).getString("className")
|
||||||
}
|
}
|
||||||
studentId = getStudentId()
|
global.studentId = getStudentId()
|
||||||
//syid = getSYID()
|
|
||||||
syid = ""
|
|
||||||
|
|
||||||
marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list"//?SemesterId=${syid}"
|
global.apiEndPoints.marksUrl = "$apiBaseUrl/v1/students/${global.studentId}/marks/list"
|
||||||
|
|
||||||
isAPISetUp = true
|
global.isAPISetUp = true
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private fun getSYID(): String {
|
fun getStudentId(): String {
|
||||||
val f = Util.fileToString(userDataFilePath)
|
|
||||||
|
|
||||||
lateinit var syidRoot: String
|
|
||||||
lateinit var toAdd: String
|
|
||||||
|
|
||||||
if (!Parsing.userIsParent()) {
|
|
||||||
syidRoot = JSONObject(f).getString("schoolYearId")
|
|
||||||
toAdd = JSONObject(f).getString("studyYear")
|
|
||||||
} else {
|
|
||||||
syidRoot = JSONObject(f)
|
|
||||||
.getJSONArray("children")
|
|
||||||
.getJSONObject(0)
|
|
||||||
.getString("schoolYearId")
|
|
||||||
|
|
||||||
toAdd = JSONObject(f)
|
|
||||||
.getJSONArray("children")
|
|
||||||
.getJSONObject(0)
|
|
||||||
.getString("studyYear")
|
|
||||||
}
|
|
||||||
|
|
||||||
val syidStart = syidRoot[0]
|
|
||||||
var syidNum = syidRoot.slice(1..<syidRoot.length).toInt()
|
|
||||||
|
|
||||||
for (ch in toAdd) {
|
|
||||||
syidNum += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return syidStart.toString() + syidNum.toString()
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private fun getStudentId(): String {
|
|
||||||
return if (!Parsing.userIsParent()) {
|
return if (!Parsing.userIsParent()) {
|
||||||
JSONObject(userData).getString("personID")
|
global.userData.getString("personID")
|
||||||
} else {
|
} else {
|
||||||
JSONObject(userData).getJSONArray("children")
|
global.userData.getJSONArray("children")
|
||||||
.getJSONObject(0)
|
.getJSONObject(0)
|
||||||
.getString("id")
|
.getString("id")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getUserDataJSON(): String {
|
fun getUserData(): JSONObject {
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(userDataUrl)
|
.url(global.apiEndPoints.userDataUrl)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.header("Authorization", "Bearer $token") // using Bearer auth token
|
.header("Authorization", "Bearer ${global.token}") // using Bearer auth token
|
||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
return try {
|
||||||
val resp = client.newCall(request).execute()
|
|
||||||
val respString = resp.body?.string().toString()
|
|
||||||
respString
|
|
||||||
} catch (e: IOException) {
|
|
||||||
"""{"error": "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 resp = client.newCall(request).execute()
|
||||||
val respString = resp.body?.string().toString()
|
val respString = resp.body?.string().toString()
|
||||||
JSONObject(respString)
|
JSONObject(respString)
|
||||||
@@ -161,48 +102,20 @@ class Network {
|
|||||||
JSONObject("""{"error": "network"}""")
|
JSONObject("""{"error": "network"}""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getTimeTableJSON(): String {
|
fun getTimeTable(): JSONObject {
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val userIsParent = Parsing.userIsParent()
|
val userIsParent = Parsing.userIsParent()
|
||||||
var url = timeTableUrl
|
val url = if (!userIsParent) global.apiEndPoints.timeTableUrl
|
||||||
if (userIsParent) {
|
else "${global.apiEndPoints.timeTableUrl}?studentId=${global.studentId}"
|
||||||
url += "?studentId=$studentId"
|
|
||||||
}
|
|
||||||
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(url)
|
.url(url)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.header("Authorization", "Bearer $token")
|
.header("Authorization", "Bearer ${global.token}")
|
||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
return try {
|
||||||
val resp = client.newCall(request).execute()
|
|
||||||
resp.body?.string().toString()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
"""{"error": "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()
|
val resp = client.newCall(request).execute()
|
||||||
JSONObject(resp.body?.string().toString())
|
JSONObject(resp.body?.string().toString())
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
@@ -211,36 +124,16 @@ class Network {
|
|||||||
JSONObject("""{"error": "network"}""")
|
JSONObject("""{"error": "network"}""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getMarksJSON(): String {
|
fun getMarks(): JSONObject {
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
.url(marksUrl)
|
.url(global.apiEndPoints.marksUrl)
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
.header("Authorization", "Bearer $token")
|
.header("Authorization", "Bearer ${global.token}")
|
||||||
.get()
|
.get()
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
try {
|
return try {
|
||||||
val resp = client.newCall(request).execute()
|
|
||||||
resp.body?.string().toString()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
"""{"error": "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()
|
val resp = client.newCall(request).execute()
|
||||||
JSONObject(resp.body?.string().toString())
|
JSONObject(resp.body?.string().toString())
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
@@ -251,4 +144,3 @@ class Network {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import com.odweta.solon.Util.Companion.getLectureId
|
import com.odweta.solon.Util.Companion.getLectureId
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
@@ -52,6 +53,7 @@ class Parsing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun parseTimetable(jsonString: JSONObject): List<Day> {
|
fun parseTimetable(jsonString: JSONObject): List<Day> {
|
||||||
|
Log.d("debug", "gotten json: $jsonString")
|
||||||
val jsonObject = jsonString
|
val jsonObject = jsonString
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -338,9 +340,9 @@ class Parsing {
|
|||||||
|
|
||||||
val marksList = mutableListOf<JSONObject>()
|
val marksList = mutableListOf<JSONObject>()
|
||||||
|
|
||||||
val marksJSONArray = JSONObject(jsonString).getJSONArray("marks")
|
val marksJSONArray = jsonString.getJSONArray("marks")
|
||||||
|
|
||||||
val subjectsJSONArray = JSONObject(jsonString).getJSONArray("subjects")
|
val subjectsJSONArray = jsonString.getJSONArray("subjects")
|
||||||
val subjectMap = mutableMapOf<String, String>()
|
val subjectMap = mutableMapOf<String, String>()
|
||||||
|
|
||||||
for (i in 0..<subjectsJSONArray.length()) {
|
for (i in 0..<subjectsJSONArray.length()) {
|
||||||
|
|||||||
@@ -150,6 +150,9 @@ fun SettingsTableRow(setting: Setting) {
|
|||||||
|
|
||||||
fun String.toSettingsData(): SettingsData {
|
fun String.toSettingsData(): SettingsData {
|
||||||
val settings = this.split("\n")
|
val settings = this.split("\n")
|
||||||
|
if (settings.size <= 1) {
|
||||||
|
return SettingsData()
|
||||||
|
}
|
||||||
val auxSettingsData = SettingsData()
|
val auxSettingsData = SettingsData()
|
||||||
val useSvobodaMode = settings[0].split("#")
|
val useSvobodaMode = settings[0].split("#")
|
||||||
val useAmoledMode = settings[1].split("#")
|
val useAmoledMode = settings[1].split("#")
|
||||||
|
|||||||
@@ -86,16 +86,14 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
coscope.launch {
|
coscope.launch {
|
||||||
signedInAndReadyToLaunch.value = false
|
|
||||||
val valid = Account.isValid(acc)
|
val valid = Account.isValid(acc)
|
||||||
|
|
||||||
checked = true
|
checked = true
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
Account.save(acc)
|
Account.save(acc)
|
||||||
signedInAndReadyToLaunch.value = true
|
global.currentScreen = Screen.Splash
|
||||||
screenToShow.value = Screen.Splash
|
launchStart(ctx)
|
||||||
fetchNewData(ctx, coscope)
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -111,7 +109,7 @@ 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 {
|
||||||
screenToShow.value = Screen.Main
|
global.currentScreen = Screen.Main
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +145,7 @@ fun SignInScreen() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.border(
|
.border(
|
||||||
width = 5.dp, color = PastelYellow, shape = RoundedCornerShape(
|
width = 5.dp, color = PastelYellow, shape = RoundedCornerShape(
|
||||||
roundedCornerDimen
|
global.dimens.roundedCorner
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.width(230.dp),
|
.width(230.dp),
|
||||||
@@ -174,7 +172,7 @@ fun SignInScreen() {
|
|||||||
width = 5.dp,
|
width = 5.dp,
|
||||||
color = PastelYellow,
|
color = PastelYellow,
|
||||||
shape = RoundedCornerShape(
|
shape = RoundedCornerShape(
|
||||||
roundedCornerDimen
|
global.dimens.roundedCorner
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
colors = TextFieldDefaults.colors(
|
colors = TextFieldDefaults.colors(
|
||||||
@@ -211,7 +209,7 @@ fun SignInScreen() {
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.border(
|
.border(
|
||||||
width = 5.dp,
|
width = 5.dp,
|
||||||
shape = RoundedCornerShape(roundedCornerDimen),
|
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
||||||
color = PastelYellow
|
color = PastelYellow
|
||||||
)
|
)
|
||||||
.width(230.dp)
|
.width(230.dp)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class Util {
|
|||||||
|
|
||||||
fun saveStringToFile(filePath: String, s: String): Boolean {
|
fun saveStringToFile(filePath: String, s: String): Boolean {
|
||||||
// get a file object with the specified path
|
// get a file object with the specified path
|
||||||
val f = File(fileDir, filePath)
|
val f = File(global.fileDir, filePath)
|
||||||
|
|
||||||
// if it does not exist, create it
|
// if it does not exist, create it
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
@@ -58,7 +58,7 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fileToString(filePath: String): String {
|
fun fileToString(filePath: String): String {
|
||||||
val f = File(fileDir, filePath)
|
val f = File(global.fileDir, filePath)
|
||||||
|
|
||||||
return if (f.exists()) {
|
return if (f.exists()) {
|
||||||
if (f.canRead()) {
|
if (f.canRead()) {
|
||||||
@@ -76,12 +76,12 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun fileExists(filePath: String): Boolean {
|
fun fileExists(filePath: String): Boolean {
|
||||||
val f = File(fileDir, filePath)
|
val f = File(global.fileDir, filePath)
|
||||||
return f.exists()
|
return f.exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fileIsEmpty(filePath: String): Boolean {
|
fun fileIsEmpty(filePath: String): Boolean {
|
||||||
val f = File(fileDir, filePath)
|
val f = File(global.fileDir, filePath)
|
||||||
val content = f.readText()
|
val content = f.readText()
|
||||||
return content == ""
|
return content == ""
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ class Util {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun deleteFile(path: String): Boolean {
|
fun deleteFile(path: String): Boolean {
|
||||||
val f = File(fileDir, path)
|
val f = File(global.fileDir, path)
|
||||||
|
|
||||||
if (f.exists()) {
|
if (f.exists()) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user