Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66f3ad791f | ||
|
|
910e968653 | ||
|
|
31197830d0 | ||
|
|
a619c8b92e | ||
|
|
04d8527434 | ||
|
|
bea50f7fe7 | ||
|
|
e9a422eda0 | ||
|
|
cc86373989 | ||
|
|
8b98d92c2b | ||
|
|
b10438c109 | ||
|
|
69f48750f1 | ||
|
|
81fb398ae2 | ||
|
|
1516a00841 | ||
|
|
6dae99d311 |
@@ -1,3 +1,3 @@
|
|||||||

|

|
||||||
# Zorientujte se rychleji v této odlehčené verzi Školy OnLine
|
# Zorientujte se rychleji v této odlehčené verzi Školy OnLine
|
||||||
# Odkaz na stažení aplikace pro Android [zde](https://gitlab.com/Odweta/solon/-/releases/2.3.0/downloads/app-release.apk) (verze 2.3.0)
|
# Odkaz na stažení aplikace pro Android [zde](https://gitlab.com/Odweta/solon/-/releases/2.5/downloads/app-release.apk) (verze 2.5)
|
||||||
|
|||||||
@@ -1,26 +1,39 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo -n "version number: "
|
echo -n "[glpat]: "
|
||||||
read ver
|
|
||||||
|
|
||||||
echo -n "glpat: "
|
|
||||||
read glpat
|
read glpat
|
||||||
|
|
||||||
|
echo -n "[keystore password]: "
|
||||||
|
read ks_pass
|
||||||
|
|
||||||
cd ./mobile
|
cd ./mobile
|
||||||
|
|
||||||
|
ver=$(./gradlew printVersionName -q)
|
||||||
|
|
||||||
|
# add, commit, push
|
||||||
|
echo
|
||||||
|
echo "[add, commit, push]"
|
||||||
|
echo
|
||||||
|
git add ..
|
||||||
|
git commit -m "made new release $ver"
|
||||||
|
git push -f
|
||||||
|
|
||||||
# build
|
# build
|
||||||
|
echo
|
||||||
|
echo "[building]"
|
||||||
|
echo
|
||||||
./gradlew assembleRelease
|
./gradlew assembleRelease
|
||||||
|
|
||||||
# sign
|
# sign
|
||||||
~/Android/Sdk/build-tools/35.0.0/apksigner sign --alignment-preserved --ks ~/Documents/android-keystore.jks app/build/outputs/apk/release/com.odweta.solon_$ver.apk
|
echo
|
||||||
|
echo "[signing]"
|
||||||
# add, commit, push
|
echo
|
||||||
git add ..
|
~/Android/Sdk/build-tools/35.0.0/apksigner sign --alignment-preserved --ks ~/Documents/android-keystore.jks --ks-pass pass:$ks_pass app/build/outputs/apk/release/com.odweta.solon_$ver.apk
|
||||||
git commit -m "made new release $ver"
|
|
||||||
git push
|
|
||||||
|
|
||||||
# create the tag
|
# create the tag
|
||||||
echo "\n[creating tag v$ver]"
|
echo
|
||||||
|
echo "[creating tag v$ver]"
|
||||||
|
echo
|
||||||
data_str='{ "tag_name": "'$ver'", "ref": "HEAD", "message": "Tagging release v'$ver'" }'
|
data_str='{ "tag_name": "'$ver'", "ref": "HEAD", "message": "Tagging release v'$ver'" }'
|
||||||
curl --request POST \
|
curl --request POST \
|
||||||
--header "PRIVATE-TOKEN: $glpat" \
|
--header "PRIVATE-TOKEN: $glpat" \
|
||||||
@@ -29,7 +42,9 @@ curl --request POST \
|
|||||||
"https://gitlab.com/api/v4/projects/47146187/repository/tags"
|
"https://gitlab.com/api/v4/projects/47146187/repository/tags"
|
||||||
|
|
||||||
# make a release
|
# make a release
|
||||||
echo "\n[publishing release $ver]"
|
echo
|
||||||
|
echo "[publishing release $ver]"
|
||||||
|
echo
|
||||||
data_str='{ "name": "v'$ver'", "tag_name": "'$ver'", "ref": "HEAD" }'
|
data_str='{ "name": "v'$ver'", "tag_name": "'$ver'", "ref": "HEAD" }'
|
||||||
curl --request POST \
|
curl --request POST \
|
||||||
--header "PRIVATE-TOKEN: $glpat" \
|
--header "PRIVATE-TOKEN: $glpat" \
|
||||||
@@ -38,14 +53,18 @@ curl --request POST \
|
|||||||
"https://gitlab.com/api/v4/projects/47146187/releases"
|
"https://gitlab.com/api/v4/projects/47146187/releases"
|
||||||
|
|
||||||
# attach a file
|
# attach a file
|
||||||
echo "\n[attaching the release apk]"
|
echo
|
||||||
|
echo "[attaching the release apk]"
|
||||||
|
echo
|
||||||
asset_url="https://gitlab.com/-/project/47146187"$(curl --request POST \
|
asset_url="https://gitlab.com/-/project/47146187"$(curl --request POST \
|
||||||
--header "PRIVATE-TOKEN: $glpat" \
|
--header "PRIVATE-TOKEN: $glpat" \
|
||||||
--form "file=@app/build/outputs/apk/release/com.odweta.solon_$ver.apk" \
|
--form "file=@app/build/outputs/apk/release/com.odweta.solon_$ver.apk" \
|
||||||
"https://gitlab.com/api/v4/projects/47146187/uploads" | jq .url -r)
|
"https://gitlab.com/api/v4/projects/47146187/uploads" | jq .url -r)
|
||||||
|
|
||||||
# add the file as a stable release asset
|
# add the file as a stable release asset
|
||||||
echo "\n[creating release asset]"
|
echo
|
||||||
|
echo "[creating release asset]"
|
||||||
|
echo
|
||||||
curl --request POST \
|
curl --request POST \
|
||||||
--header "PRIVATE-TOKEN: $glpat" \
|
--header "PRIVATE-TOKEN: $glpat" \
|
||||||
--data name="app-release.apk" \
|
--data name="app-release.apk" \
|
||||||
|
|||||||
@@ -4,6 +4,26 @@ plugins {
|
|||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.register("printVersionName") {
|
||||||
|
doLast {
|
||||||
|
println(android.defaultConfig.versionName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("deploy") {
|
||||||
|
dependsOn("assembleDebug")
|
||||||
|
dependsOn("installDebug")
|
||||||
|
doLast {
|
||||||
|
exec {
|
||||||
|
commandLine("adb", "shell", "am", "start", "-n", "com.odweta.solon/.MainActivity")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("b") {
|
||||||
|
dependsOn("assembleDebug")
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.odweta.solon"
|
namespace = "com.odweta.solon"
|
||||||
compileSdk = 34
|
compileSdk = 34
|
||||||
@@ -12,8 +32,8 @@ android {
|
|||||||
applicationId = "com.odweta.solon"
|
applicationId = "com.odweta.solon"
|
||||||
minSdk = 28
|
minSdk = 28
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = 208
|
versionCode = 211
|
||||||
versionName = "2.3.0"
|
versionName = "2.4"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1,37 +0,0 @@
|
|||||||
{
|
|
||||||
"version": 3,
|
|
||||||
"artifactType": {
|
|
||||||
"type": "APK",
|
|
||||||
"kind": "Directory"
|
|
||||||
},
|
|
||||||
"applicationId": "com.odweta.solon",
|
|
||||||
"variantName": "release",
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"type": "SINGLE",
|
|
||||||
"filters": [],
|
|
||||||
"attributes": [],
|
|
||||||
"versionCode": 1,
|
|
||||||
"versionName": "2.0",
|
|
||||||
"outputFile": "app-release.apk"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"elementType": "File",
|
|
||||||
"baselineProfiles": [
|
|
||||||
{
|
|
||||||
"minApi": 28,
|
|
||||||
"maxApi": 30,
|
|
||||||
"baselineProfiles": [
|
|
||||||
"baselineProfiles/1/app-release.dm"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"minApi": 31,
|
|
||||||
"maxApi": 2147483647,
|
|
||||||
"baselineProfiles": [
|
|
||||||
"baselineProfiles/0/app-release.dm"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"minSdkVersionForDexing": 28
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
@@ -8,17 +9,10 @@ import java.nio.charset.Charset
|
|||||||
|
|
||||||
class Account(val username: String, val password: String, private val error: Int) {
|
class Account(val username: String, val password: String, private val error: Int) {
|
||||||
companion object {
|
companion object {
|
||||||
private fun parseAccountDataFile(file: File): Account {
|
private fun parseAccountDataFile(): Account {
|
||||||
val lines: List<String> = file.readLines()
|
val lines: List<String> = File(global.fileDir, global.filePaths.accountData).readLines()
|
||||||
|
|
||||||
if (lines.size >= 2) {
|
|
||||||
if (lines[0] != "" && lines[1] != "") {
|
|
||||||
return Account(lines[0], lines[1], 0)
|
return Account(lines[0], lines[1], 0)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return Account("", "", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun haveSaved(): Boolean {
|
fun haveSaved(): Boolean {
|
||||||
/* check if a file exists
|
/* check if a file exists
|
||||||
@@ -27,15 +21,17 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// check if file exists
|
// check if file exists
|
||||||
val file = File(global.fileDir, global.filePaths.accountData)
|
|
||||||
|
|
||||||
return if (!file.exists()) {
|
return if (
|
||||||
|
!Util.fileExists(global.filePaths.accountData) ||
|
||||||
|
Util.fileIsEmpty(global.filePaths.accountData)
|
||||||
|
) {
|
||||||
// it does not exist
|
// it does not exist
|
||||||
file.createNewFile()
|
File(global.fileDir, global.filePaths.accountData).createNewFile()
|
||||||
false
|
false
|
||||||
} 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()
|
||||||
global.username = acc.username
|
global.username = acc.username
|
||||||
global.password = acc.password
|
global.password = acc.password
|
||||||
acc.error == 0
|
acc.error == 0
|
||||||
@@ -43,23 +39,20 @@ class Account(val username: String, val password: String, private val error: Int
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun save(acc: Account): Boolean {
|
fun save(acc: Account): Boolean {
|
||||||
return try {
|
val payload = "${acc.username}\n${acc.password}"
|
||||||
val file = File(global.fileDir, global.filePaths.accountData)
|
return Util.saveStringToFile(global.filePaths.accountData, payload)
|
||||||
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
|
||||||
|
|
||||||
true
|
|
||||||
} catch (e: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun isValid(acc: Account): Boolean {
|
fun isValid(acc: Account): Boolean {
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
global.username = acc.username
|
global.username = acc.username
|
||||||
global.password = acc.password
|
global.password = acc.password
|
||||||
|
|
||||||
val token = networkRequestFactory.perform(NetworkRequestType.Token).getString("token")
|
val tokenJSON = networkRequestFactory.perform(NetworkRequestType.Token)
|
||||||
!JSONObject(token).has("error")
|
return if (tokenJSON.has("token")) {
|
||||||
|
val token = tokenJSON.getString("token")
|
||||||
|
!token.contains("\"error\"")
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,7 @@ interface BackButtonFactoryInterface {
|
|||||||
@Composable
|
@Composable
|
||||||
fun BackButton(onClick: () -> Unit) {
|
fun BackButton(onClick: () -> Unit) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(start = 10.dp)
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(start = 5.dp)
|
|
||||||
) {
|
) {
|
||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
@@ -66,7 +64,10 @@ object BackButtonFactory: BackButtonFactoryInterface {
|
|||||||
override fun get(type: BackButtonType): @Composable () -> Unit {
|
override fun get(type: BackButtonType): @Composable () -> Unit {
|
||||||
return when (type) {
|
return when (type) {
|
||||||
BackButtonType.Menu -> { { BackButton { global.currentScreenElement = ScreenElement.Menu } } }
|
BackButtonType.Menu -> { { BackButton { global.currentScreenElement = ScreenElement.Menu } } }
|
||||||
BackButtonType.MarksAll -> { { BackButton { global.marksDepthLevel = MarksDepthLevel.All } } }
|
BackButtonType.MarksAll -> { { BackButton {
|
||||||
|
global.currentScreenElement = ScreenElement.Marks
|
||||||
|
global.marksDepthLevel = MarksDepthLevel.All
|
||||||
|
} } }
|
||||||
BackButtonType.MarksSubject -> { { BackButton { global.marksDepthLevel = MarksDepthLevel.Subject } } }
|
BackButtonType.MarksSubject -> { { BackButton { global.marksDepthLevel = MarksDepthLevel.Subject } } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,33 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInHorizontally
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
|
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.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
|
import androidx.compose.runtime.RecomposeScope
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
import com.odweta.solon.ui.theme.PastelYellow
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
enum class Screen {
|
enum class Screen {
|
||||||
Main,
|
Main,
|
||||||
@@ -34,7 +46,8 @@ class Setting(auxId: SettingsId, auxName: String, auxChecked: Boolean) {
|
|||||||
enum class SettingsId {
|
enum class SettingsId {
|
||||||
Svoboda,
|
Svoboda,
|
||||||
Amoled,
|
Amoled,
|
||||||
RefreshButton
|
RefreshButton,
|
||||||
|
Animations
|
||||||
}
|
}
|
||||||
|
|
||||||
class SettingsData {
|
class SettingsData {
|
||||||
@@ -56,7 +69,13 @@ class SettingsData {
|
|||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun toString() = "$useSvobodaMode\n$useAmoledMode\n$showRefreshButton"
|
var useAnimations: Setting = Setting(
|
||||||
|
SettingsId.Animations,
|
||||||
|
"Používat animace v aplikaci",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun toString() = "$useSvobodaMode\n$useAmoledMode\n$showRefreshButton\n$useAnimations"
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class LectureNoteType {
|
enum class LectureNoteType {
|
||||||
@@ -76,23 +95,13 @@ fun String.toLectureNoteType(): LectureNoteType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LectureNote(id: Int, note: MutableState<String>, type: MutableState<LectureNoteType>, number: Int, lectureName: String) {
|
data class LectureNote(
|
||||||
var id: Int = 0
|
var id: Int,
|
||||||
var note: MutableState<String> =
|
var note: MutableState<String> = mutableStateOf(""),
|
||||||
mutableStateOf("")
|
var type: MutableState<LectureNoteType> = mutableStateOf(LectureNoteType.Normal),
|
||||||
var type: MutableState<LectureNoteType> =
|
var number: Int,
|
||||||
mutableStateOf(LectureNoteType.Normal)
|
var lectureName: String
|
||||||
var number: Int = 0
|
)
|
||||||
var lectureName: String = ""
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.id = id
|
|
||||||
this.note = note
|
|
||||||
this.type = type
|
|
||||||
this.number = number
|
|
||||||
this.lectureName = lectureName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Subject {
|
class Subject {
|
||||||
lateinit var name: String
|
lateinit var name: String
|
||||||
@@ -174,9 +183,12 @@ class Mark {
|
|||||||
enum class ScreenElement {
|
enum class ScreenElement {
|
||||||
Timetable,
|
Timetable,
|
||||||
Marks,
|
Marks,
|
||||||
|
NewMarks,
|
||||||
|
FinalMarks,
|
||||||
Menu,
|
Menu,
|
||||||
About,
|
About,
|
||||||
Settings
|
Settings,
|
||||||
|
SignOut
|
||||||
}
|
}
|
||||||
|
|
||||||
class Global {
|
class Global {
|
||||||
@@ -260,3 +272,22 @@ class Global {
|
|||||||
val global = Global()
|
val global = Global()
|
||||||
|
|
||||||
var settings = SettingsData()
|
var settings = SettingsData()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun <T> Animate(targetState: T, content: @Composable (target: T) -> Unit) {
|
||||||
|
if (settings.useAnimations.checked.value == true) {
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = targetState,
|
||||||
|
transitionSpec = {
|
||||||
|
(slideInVertically(initialOffsetY = { it }) + fadeIn()).togetherWith(
|
||||||
|
slideOutVertically(targetOffsetY = { it }) + fadeOut()
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxSize(), label = "animated content"
|
||||||
|
) { target ->
|
||||||
|
content(target)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
content(targetState)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,10 +28,17 @@ fun remoteLoad(ctx: Context) {
|
|||||||
if (!global.isAPISetUp) {
|
if (!global.isAPISetUp) {
|
||||||
CoroutineScope(Dispatchers.IO)
|
CoroutineScope(Dispatchers.IO)
|
||||||
.launch {
|
.launch {
|
||||||
|
// setup API
|
||||||
setupAPI()
|
setupAPI()
|
||||||
|
|
||||||
|
// fetch remote data
|
||||||
global.timetableJSON = networkRequestFactory.perform(NetworkRequestType.Timetable)
|
global.timetableJSON = networkRequestFactory.perform(NetworkRequestType.Timetable)
|
||||||
global.marksJSON = networkRequestFactory.perform(NetworkRequestType.Marks)
|
global.marksJSON = networkRequestFactory.perform(NetworkRequestType.Marks)
|
||||||
|
|
||||||
|
// save to local for later local load
|
||||||
|
Util.saveStringToFile(global.filePaths.timetable, global.timetableJSON.toString())
|
||||||
|
Util.saveStringToFile(global.filePaths.marks, global.marksJSON.toString())
|
||||||
|
|
||||||
launchContinue(
|
launchContinue(
|
||||||
ctx,
|
ctx,
|
||||||
global.timetableJSON,
|
global.timetableJSON,
|
||||||
@@ -76,11 +83,11 @@ fun launchContinue(
|
|||||||
global.marks = parsedMarks
|
global.marks = parsedMarks
|
||||||
global.newMarks = Parsing.parseNewMarks(marks)
|
global.newMarks = Parsing.parseNewMarks(marks)
|
||||||
|
|
||||||
// load the settings
|
// // load the settings
|
||||||
val settingsData = Util.fileToString(global.filePaths.settings).toSettingsData()
|
// global.settings = Util.fileToString(global.filePaths.settings).toSettingsData()
|
||||||
global.settings = settingsData
|
|
||||||
|
|
||||||
// load the lecture notes
|
// load the lecture notes
|
||||||
|
Util.loadLectureNotes()
|
||||||
Util.csvToLectureNotes()
|
Util.csvToLectureNotes()
|
||||||
|
|
||||||
// listen for internet availability in case of disconnection
|
// listen for internet availability in case of disconnection
|
||||||
|
|||||||
@@ -8,25 +8,38 @@ import androidx.compose.foundation.layout.Box
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.currentRecomposeScope
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
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
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import androidx.compose.ui.input.pointer.PointerIcon.Companion.Text
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.odweta.solon.ui.theme.SolonTheme
|
import com.odweta.solon.ui.theme.SolonTheme
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// for seemless <currentScreen> switching
|
||||||
window.statusBarColor = Color.Black.toArgb()
|
window.statusBarColor = Color.Black.toArgb()
|
||||||
|
window.setBackgroundDrawable(resources.getDrawable(R.drawable.black))
|
||||||
|
|
||||||
global.fileDir = applicationContext.filesDir
|
global.fileDir = applicationContext.filesDir
|
||||||
|
|
||||||
launchStart(applicationContext)
|
launchStart(applicationContext)
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
SolonTheme {
|
SolonTheme {
|
||||||
when (global.currentScreen) {
|
Animate(global.currentScreen) { targetScreen ->
|
||||||
|
when (targetScreen) {
|
||||||
Screen.Main -> if (global.launched) MainScreen()
|
Screen.Main -> if (global.launched) MainScreen()
|
||||||
Screen.Splash -> SplashScreen()
|
Screen.Splash -> SplashScreen()
|
||||||
Screen.SignIn -> SignInScreen()
|
Screen.SignIn -> SignInScreen()
|
||||||
@@ -34,6 +47,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScreen() {
|
fun MainScreen() {
|
||||||
@@ -54,12 +68,17 @@ class MainActivity : ComponentActivity() {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
) {
|
) {
|
||||||
when (global.currentScreenElement) {
|
Animate(global.currentScreenElement) { targetScreen ->
|
||||||
|
when (targetScreen) {
|
||||||
ScreenElement.Timetable -> TimetableScreen()
|
ScreenElement.Timetable -> TimetableScreen()
|
||||||
ScreenElement.Marks -> MarksScreen()
|
ScreenElement.Marks -> MarksScreen()
|
||||||
|
ScreenElement.NewMarks -> NewMarksScreen()
|
||||||
|
ScreenElement.FinalMarks -> FinalMarksScreen()
|
||||||
ScreenElement.Menu -> MenuScreen()
|
ScreenElement.Menu -> MenuScreen()
|
||||||
ScreenElement.About -> AboutScreen()
|
ScreenElement.About -> AboutScreen()
|
||||||
ScreenElement.Settings -> SettingsScreen()
|
ScreenElement.Settings -> SettingsScreen()
|
||||||
|
ScreenElement.SignOut -> SignOutScreen()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ 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.AutoAwesome
|
import androidx.compose.material.icons.filled.AutoAwesome
|
||||||
|
import androidx.compose.material.icons.filled.WorkspacePremium
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -29,20 +30,16 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.setValue
|
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.draw.shadow
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.Shadow
|
import androidx.compose.ui.graphics.Shadow
|
||||||
import androidx.compose.ui.platform.LocalContext
|
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.ui.window.DialogProperties
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.compose.ui.zIndex
|
|
||||||
import com.odweta.solon.ui.theme.PastelGreen
|
import com.odweta.solon.ui.theme.PastelGreen
|
||||||
import com.odweta.solon.ui.theme.PastelGreenTransparent
|
import com.odweta.solon.ui.theme.PastelGreenTransparent
|
||||||
import com.odweta.solon.ui.theme.PastelOrange
|
import com.odweta.solon.ui.theme.PastelOrange
|
||||||
@@ -53,10 +50,10 @@ import com.odweta.solon.ui.theme.PastelRed
|
|||||||
import com.odweta.solon.ui.theme.PastelRedTransparent
|
import com.odweta.solon.ui.theme.PastelRedTransparent
|
||||||
import com.odweta.solon.ui.theme.PastelYellow
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
import com.odweta.solon.ui.theme.PastelYellowTransparent
|
import com.odweta.solon.ui.theme.PastelYellowTransparent
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
var showNewMarksDialog by mutableStateOf(false)
|
var showNewMarksDialog by mutableStateOf(false)
|
||||||
|
var showFinalMarksDialog by mutableStateOf(false)
|
||||||
|
|
||||||
enum class MarksDepthLevel {
|
enum class MarksDepthLevel {
|
||||||
All,
|
All,
|
||||||
@@ -66,46 +63,69 @@ enum class MarksDepthLevel {
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MarksScreen() {
|
fun MarksScreen() {
|
||||||
when (global.marksDepthLevel) {
|
Animate(global.marksDepthLevel) { targetDepthLevel ->
|
||||||
|
when (targetDepthLevel) {
|
||||||
MarksDepthLevel.All -> MarksAll()
|
MarksDepthLevel.All -> MarksAll()
|
||||||
MarksDepthLevel.Subject -> MarksSubject()
|
MarksDepthLevel.Subject -> MarksSubject()
|
||||||
MarksDepthLevel.Detail -> MarksDetail()
|
MarksDepthLevel.Detail -> MarksDetail()
|
||||||
}
|
}
|
||||||
if (showNewMarksDialog) {
|
}
|
||||||
val scrollStateNewMarks = rememberScrollState()
|
}
|
||||||
|
|
||||||
Dialog(
|
@Composable
|
||||||
onDismissRequest = { showNewMarksDialog = false },
|
fun NewMarksScreen() {
|
||||||
properties = DialogProperties(
|
BackHandler { global.currentScreenElement = ScreenElement.Marks }
|
||||||
dismissOnBackPress = true,
|
|
||||||
dismissOnClickOutside = true
|
val ss = rememberScrollState()
|
||||||
)
|
|
||||||
) {
|
|
||||||
Column(
|
Column(
|
||||||
Modifier.verticalScroll(scrollStateNewMarks).padding(vertical = 10.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
backButtonFactory.get(BackButtonType.MarksAll)()
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
color = Color.Black,
|
||||||
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
|
)
|
||||||
|
.border(
|
||||||
|
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
||||||
|
color = PastelYellow,
|
||||||
|
width = global.dimens.borderWidth
|
||||||
|
)
|
||||||
|
.height(70.dp)
|
||||||
|
.padding(10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
"Nové známky",
|
"Nové známky",
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 30.sp,
|
fontSize = 30.sp,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center
|
||||||
modifier = Modifier.background(
|
|
||||||
color = Color.Black,
|
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
|
||||||
).border(
|
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
|
||||||
color = PastelYellow,
|
|
||||||
width = global.dimens.borderWidth
|
|
||||||
).padding(10.dp)
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Spacer(Modifier.height(10.dp))
|
Spacer(Modifier.height(10.dp))
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.verticalScroll(ss)
|
||||||
|
) {
|
||||||
for ((k, v) in global.newMarks) {
|
for ((k, v) in global.newMarks) {
|
||||||
if (v.size > 0) {
|
if (v.size > 0) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(10.dp)
|
.padding(horizontal = 10.dp)
|
||||||
|
.padding(bottom = 10.dp)
|
||||||
.border(
|
.border(
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
||||||
color = PastelYellow,
|
color = PastelYellow,
|
||||||
@@ -133,7 +153,8 @@ fun MarksScreen() {
|
|||||||
Text(
|
Text(
|
||||||
i.theme,
|
i.theme,
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
modifier = Modifier.padding(end = 5.dp, top = 5.dp)
|
modifier = Modifier
|
||||||
|
.padding(end = 5.dp, top = 5.dp)
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
@@ -146,7 +167,8 @@ fun MarksScreen() {
|
|||||||
.background(
|
.background(
|
||||||
color = getAvgColor(i.grade, true),
|
color = getAvgColor(i.grade, true),
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
).padding(5.dp),
|
)
|
||||||
|
.padding(5.dp),
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
shadow = Shadow(
|
shadow = Shadow(
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
@@ -170,6 +192,65 @@ fun MarksScreen() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FinalMarksScreen() {
|
||||||
|
BackHandler { global.currentScreenElement = ScreenElement.Marks }
|
||||||
|
|
||||||
|
val ss = rememberScrollState()
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
backButtonFactory.get(BackButtonType.MarksAll)()
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
color = Color.Black,
|
||||||
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
|
)
|
||||||
|
.border(
|
||||||
|
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
||||||
|
color = PastelYellow,
|
||||||
|
width = global.dimens.borderWidth
|
||||||
|
)
|
||||||
|
.height(70.dp)
|
||||||
|
.padding(10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
"Uzavřené známky",
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = 30.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(10.dp))
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.verticalScroll(ss)
|
||||||
|
) {
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
Text("test", color = Color.White)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +302,7 @@ fun MarksAll() {
|
|||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
) {
|
) {
|
||||||
for ((subject, markList) in global.marks) {
|
for ((subject, markList) in global.marks) {
|
||||||
val amoledModifier = if (settings.useAmoledMode.checked.value) {
|
val amoledModifier = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Modifier
|
Modifier
|
||||||
.width(150.dp)
|
.width(150.dp)
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
@@ -243,7 +324,7 @@ fun MarksAll() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val amoledModifierBackground = if (settings.useAmoledMode.checked.value) {
|
val amoledModifierBackground = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(70.dp)
|
.height(70.dp)
|
||||||
@@ -273,7 +354,7 @@ fun MarksAll() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val amoledSpacerModifier = if (settings.useAmoledMode.checked.value) {
|
val amoledSpacerModifier = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Modifier
|
Modifier
|
||||||
.width(10.dp)
|
.width(10.dp)
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
@@ -360,22 +441,46 @@ fun MarksAll() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Box(Modifier.fillMaxSize()) {
|
Box(Modifier.fillMaxSize()) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.BottomCenter)
|
||||||
|
) {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = { showNewMarksDialog = true },
|
onClick = { global.currentScreenElement = ScreenElement.NewMarks },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomEnd)
|
|
||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
.background(Color.Black, shape = RoundedCornerShape(global.dimens.roundedCorner)),
|
.background(
|
||||||
containerColor = Color.Black,
|
Color.Black,
|
||||||
contentColor = PastelYellow
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
|
),
|
||||||
|
contentColor = PastelYellow,
|
||||||
|
containerColor = Color.Black
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.padding(start = 4.dp, top = 4.dp),
|
|
||||||
imageVector = Icons.Default.AutoAwesome,
|
imageVector = Icons.Default.AutoAwesome,
|
||||||
contentDescription = "New marks in subject",
|
contentDescription = "New marks in subject",
|
||||||
tint = PastelYellow // You can customize the icon color
|
tint = PastelYellow // You can customize the icon color
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FloatingActionButton(
|
||||||
|
onClick = { global.currentScreenElement = ScreenElement.FinalMarks },
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.background(
|
||||||
|
Color.Black,
|
||||||
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
|
),
|
||||||
|
contentColor = PastelYellow,
|
||||||
|
containerColor = Color.Black
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.WorkspacePremium,
|
||||||
|
contentDescription = "Final marks",
|
||||||
|
tint = PastelYellow // You can customize the icon color
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,7 +518,7 @@ fun MarksSubject() {
|
|||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
color = if (settings.useAmoledMode.checked.value) {
|
color = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
getAvgColor(
|
getAvgColor(
|
||||||
@@ -454,7 +559,7 @@ fun MarksSubject() {
|
|||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
color = if (settings.useAmoledMode.checked.value) {
|
color = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
PastelYellowTransparent
|
PastelYellowTransparent
|
||||||
@@ -481,7 +586,7 @@ fun MarksSubject() {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 5.dp)
|
.padding(horizontal = 5.dp)
|
||||||
.background(
|
.background(
|
||||||
color = if (settings.useAmoledMode.checked.value) {
|
color = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
getAvgColor(mark.grade)
|
getAvgColor(mark.grade)
|
||||||
@@ -561,7 +666,7 @@ fun MarksDetail() {
|
|||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
if (settings.useAmoledMode.checked.value) {
|
if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
getAvgColor(
|
getAvgColor(
|
||||||
@@ -597,7 +702,7 @@ fun MarksDetail() {
|
|||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
)
|
)
|
||||||
.background(
|
.background(
|
||||||
if (settings.useAmoledMode.checked.value) {
|
if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
PastelYellowTransparent
|
PastelYellowTransparent
|
||||||
@@ -614,7 +719,7 @@ fun MarksDetail() {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 5.dp)
|
.padding(horizontal = 5.dp)
|
||||||
.background(
|
.background(
|
||||||
color = if (settings.useAmoledMode.checked.value) {
|
color = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
PastelYellowTransparent
|
PastelYellowTransparent
|
||||||
@@ -657,7 +762,7 @@ fun MarksDetail() {
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 5.dp)
|
.padding(horizontal = 5.dp)
|
||||||
.background(
|
.background(
|
||||||
color = if (settings.useAmoledMode.checked.value) {
|
color = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Color.Black
|
Color.Black
|
||||||
} else {
|
} else {
|
||||||
PastelYellowTransparent
|
PastelYellowTransparent
|
||||||
|
|||||||
@@ -1,14 +1,30 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.scaleIn
|
||||||
|
import androidx.compose.animation.scaleOut
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
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.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ExitToApp
|
||||||
|
import androidx.compose.material.icons.filled.AccountBox
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||||
|
import androidx.compose.material.icons.filled.ExitToApp
|
||||||
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@@ -19,8 +35,11 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.odweta.solon.ui.theme.PastelYellow
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
@@ -28,7 +47,7 @@ import kotlin.system.exitProcess
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MenuScreen() {
|
fun MenuScreen() {
|
||||||
var showDialog by remember { mutableStateOf(false) }
|
val menuSeparatorDimen = 40.dp
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -36,87 +55,50 @@ fun MenuScreen() {
|
|||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
MenuButton({ showDialog = true }, "Odhlásit se")
|
Row {
|
||||||
|
MenuButton(
|
||||||
Spacer(modifier = Modifier.height(80.dp))
|
{ global.currentScreenElement = ScreenElement.SignOut },
|
||||||
|
Icons.AutoMirrored.Filled.ExitToApp,
|
||||||
MenuButton({ global.currentScreen = Screen.SignIn }, "Změnit přihlášení")
|
"Odhlásit se"
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(80.dp))
|
|
||||||
|
|
||||||
MenuButton({ global.currentScreenElement = ScreenElement.About }, "O aplikaci")
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(80.dp))
|
|
||||||
|
|
||||||
MenuButton({ global.currentScreenElement = ScreenElement.Settings }, "Nastavení")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dialog implementation
|
|
||||||
if (showDialog) {
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { showDialog = false }, // Close the dialog on dismiss
|
|
||||||
title = {
|
|
||||||
Text(text = "Odhlásit se", color = Color.White)
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text("Opravdu se chcete odhlásit? Tato akce zavře aplikaci.", color = Color.White)
|
|
||||||
},
|
|
||||||
containerColor = Color.Black,
|
|
||||||
modifier = Modifier
|
|
||||||
.border(
|
|
||||||
width = global.dimens.borderWidth,
|
|
||||||
color = PastelYellow,
|
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)), // Yellow border
|
|
||||||
confirmButton = {
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
showDialog = false
|
|
||||||
Util.deleteFile(global.filePaths.userData)
|
|
||||||
Util.deleteFile(global.filePaths.timetable)
|
|
||||||
Util.deleteFile(global.filePaths.marks)
|
|
||||||
Util.deleteFile(global.filePaths.accountData)
|
|
||||||
Util.deleteFile(global.filePaths.lectureNotes)
|
|
||||||
// do not delete settings
|
|
||||||
exitProcess(0)
|
|
||||||
},
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
|
||||||
containerColor = Color.Black, // Black background for the button
|
|
||||||
contentColor = Color.White // Yellow text for the button
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.border(
|
|
||||||
width = global.dimens.borderWidth,
|
|
||||||
color = PastelYellow,
|
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)) // Yellow border
|
|
||||||
) {
|
|
||||||
Text("Ano")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissButton = {
|
|
||||||
Button(
|
|
||||||
onClick = {
|
|
||||||
showDialog = false
|
|
||||||
},
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
|
||||||
containerColor = Color.Black, // Black background for the button
|
|
||||||
contentColor = Color.White,
|
|
||||||
// Yellow text for the button
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.border(
|
|
||||||
width = global.dimens.borderWidth,
|
|
||||||
color = PastelYellow,
|
|
||||||
shape = RoundedCornerShape(global.dimens.roundedCorner)) // Yellow border
|
|
||||||
) {
|
|
||||||
Text("Ne")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(menuSeparatorDimen))
|
||||||
|
|
||||||
|
MenuButton(
|
||||||
|
{
|
||||||
|
global.noSignInBackHandle = false
|
||||||
|
global.currentScreen = Screen.SignIn
|
||||||
|
},
|
||||||
|
Icons.Default.AccountBox,
|
||||||
|
"Změnit přihlášení"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(menuSeparatorDimen))
|
||||||
|
|
||||||
|
Row {
|
||||||
|
MenuButton(
|
||||||
|
{ global.currentScreenElement = ScreenElement.About },
|
||||||
|
Icons.Default.Info,
|
||||||
|
"O aplikaci"
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(menuSeparatorDimen))
|
||||||
|
|
||||||
|
MenuButton(
|
||||||
|
{ global.currentScreenElement = ScreenElement.Settings },
|
||||||
|
Icons.Default.Settings,
|
||||||
|
"Nastavení"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MenuButton(onClick: () -> Unit, text: String) {
|
fun MenuButton(onClick: () -> Unit, icon: ImageVector, altText: String) {
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
Button(
|
Button(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
@@ -129,12 +111,21 @@ fun MenuButton(onClick: () -> Unit, text: String) {
|
|||||||
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
shape = RoundedCornerShape(global.dimens.roundedCorner),
|
||||||
color = PastelYellow
|
color = PastelYellow
|
||||||
)
|
)
|
||||||
.width(230.dp)
|
.size(80.dp)
|
||||||
.height(80.dp)
|
|
||||||
) {
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = altText,
|
||||||
|
modifier = Modifier.size(40.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = altText,
|
||||||
fontSize = 23.sp
|
modifier = Modifier.padding(5.dp).width(80.dp),
|
||||||
|
color = Color.White,
|
||||||
|
fontSize = 17.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,7 @@ fun NavbarScreen() {
|
|||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
var spacerModifier = 30.dp
|
var spacerModifier = 30.dp
|
||||||
if (settings.showRefreshButton.checked.value) {
|
if (settings.showRefreshButton.checked.value == true) {
|
||||||
spacerModifier = 15.dp
|
spacerModifier = 15.dp
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|||||||
@@ -11,15 +11,21 @@ import org.json.JSONObject
|
|||||||
|
|
||||||
fun setupAPI() {
|
fun setupAPI() {
|
||||||
global.token = "NETWORK_UNREACHABLE"
|
global.token = "NETWORK_UNREACHABLE"
|
||||||
val token = networkRequestFactory.perform(NetworkRequestType.Token).getString("token")
|
|
||||||
if (""""error": """ !in token) {
|
val tokenJSON = networkRequestFactory.perform(NetworkRequestType.Token)
|
||||||
|
if (tokenJSON.has("token")) {
|
||||||
|
val token = tokenJSON.getString("token")
|
||||||
|
if ("\"error\": " !in token) {
|
||||||
global.token = token
|
global.token = token
|
||||||
}
|
}
|
||||||
if (global.token == "NETWORK_UNREACHABLE" || """"error": """ in global.token) {
|
}
|
||||||
|
|
||||||
|
if (global.token == "NETWORK_UNREACHABLE" || "\"error\":" in global.token) {
|
||||||
global.userData = JSONObject()
|
global.userData = JSONObject()
|
||||||
global.studentId = ""
|
global.studentId = ""
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
global.userData = networkRequestFactory.perform(NetworkRequestType.UserData)
|
global.userData = networkRequestFactory.perform(NetworkRequestType.UserData)
|
||||||
Util.saveStringToFile(global.filePaths.userData, global.userData.toString())
|
Util.saveStringToFile(global.filePaths.userData, global.userData.toString())
|
||||||
global.studentClass = Parsing.getStudentClass()
|
global.studentClass = Parsing.getStudentClass()
|
||||||
@@ -90,7 +96,6 @@ object NetworkRequestFactory: NetworkRequestInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getAPI(url: String): JSONObject {
|
private fun getAPI(url: String): JSONObject {
|
||||||
Log.d("debug TOKEN", global.token)
|
|
||||||
val response = get(url, headersOf(
|
val response = get(url, headersOf(
|
||||||
"Content-Type", "application/x-www-form-urlencoded",
|
"Content-Type", "application/x-www-form-urlencoded",
|
||||||
"Authorization", "Bearer ${global.token}"
|
"Authorization", "Bearer ${global.token}"
|
||||||
|
|||||||
@@ -153,9 +153,12 @@ class Parsing {
|
|||||||
subject.name = subj.getJSONObject("subject").getString("abbrev")
|
subject.name = subj.getJSONObject("subject").getString("abbrev")
|
||||||
subject.place =
|
subject.place =
|
||||||
subj.getJSONArray("rooms").getJSONObject(0).getString("abbrev")
|
subj.getJSONArray("rooms").getJSONObject(0).getString("abbrev")
|
||||||
subject.teacher = if (subj.getJSONArray("teachers").length() > 0) {
|
subject.teacher =
|
||||||
subj.getJSONArray("teachers").getJSONObject(0)
|
if (subj.getJSONArray("teachers").length() > 0) {
|
||||||
.getString("fullName") // TODO: keep in mind that fullName might not be a valid field (name and surname are!)
|
subj.getJSONArray("teachers")
|
||||||
|
.getJSONObject(0).getString("name") + " " +
|
||||||
|
subj.getJSONArray("teachers")
|
||||||
|
.getJSONObject(0).getString("name")
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
@@ -322,7 +325,6 @@ class Parsing {
|
|||||||
timetable.add(day)
|
timetable.add(day)
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.d("debug", "timetable: $timetable")
|
|
||||||
return timetable
|
return timetable
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,6 +408,16 @@ class Parsing {
|
|||||||
|
|
||||||
for (i in 0..<marksJSONArray.length()) {
|
for (i in 0..<marksJSONArray.length()) {
|
||||||
marksList.add(marksJSONArray.getJSONObject(i))
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
|
marksList.add(marksJSONArray.getJSONObject(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
for (subj in subjectMap.values) {
|
for (subj in subjectMap.values) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
@@ -16,19 +17,33 @@ import androidx.compose.material3.Switch
|
|||||||
import androidx.compose.material3.SwitchColors
|
import androidx.compose.material3.SwitchColors
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.currentComposer
|
||||||
|
import androidx.compose.runtime.currentRecomposeScope
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
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
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.lifecycle.liveData
|
||||||
import com.odweta.solon.ui.theme.PastelYellow
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen() {
|
fun SettingsScreen() {
|
||||||
// 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 { global.currentScreenElement = ScreenElement.Menu }
|
BackHandler { global.currentScreenElement = ScreenElement.Menu }
|
||||||
|
|
||||||
|
// load the settings dat every time the settings screen is opened,
|
||||||
|
// maybe i can add a flag that determines if the settings are up to date?
|
||||||
|
settings = Util.fileToString(global.filePaths.settings).toSettingsData()
|
||||||
|
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
Column(modifier = Modifier
|
Column(modifier = Modifier
|
||||||
@@ -38,22 +53,20 @@ fun SettingsScreen() {
|
|||||||
) {
|
) {
|
||||||
backButtonFactory.get(BackButtonType.Menu)()
|
backButtonFactory.get(BackButtonType.Menu)()
|
||||||
|
|
||||||
Spacer(Modifier.height(10.dp))
|
|
||||||
|
|
||||||
SettingsTableRow(settings.useSvobodaMode)
|
SettingsTableRow(settings.useSvobodaMode)
|
||||||
|
|
||||||
Spacer(Modifier.height(10.dp))
|
|
||||||
|
|
||||||
SettingsTableRow(settings.useAmoledMode)
|
SettingsTableRow(settings.useAmoledMode)
|
||||||
|
|
||||||
Spacer(Modifier.height(10.dp))
|
|
||||||
|
|
||||||
SettingsTableRow(settings.showRefreshButton)
|
SettingsTableRow(settings.showRefreshButton)
|
||||||
|
|
||||||
|
SettingsTableRow(settings.useAnimations)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsTableRow(setting: Setting) {
|
fun SettingsTableRow(setting: Setting) {
|
||||||
|
Spacer(Modifier.height(10.dp))
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
@@ -71,15 +84,9 @@ fun SettingsTableRow(setting: Setting) {
|
|||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
Switch(
|
Switch(
|
||||||
checked = setting.checked.value,
|
checked = setting.checked.value == true,
|
||||||
onCheckedChange = {
|
onCheckedChange = {
|
||||||
setting.checked.value = it
|
setting.checked.value = it
|
||||||
when (setting.id) {
|
|
||||||
SettingsId.Svoboda -> settings.useSvobodaMode = setting
|
|
||||||
SettingsId.Amoled -> settings.useAmoledMode = setting
|
|
||||||
SettingsId.RefreshButton -> settings.showRefreshButton = setting
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
Util.saveStringToFile(global.filePaths.settings, settings.toString())
|
Util.saveStringToFile(global.filePaths.settings, settings.toString())
|
||||||
},
|
},
|
||||||
colors = SwitchColors(
|
colors = SwitchColors(
|
||||||
@@ -113,6 +120,7 @@ fun String.toSettingsData(): SettingsData {
|
|||||||
val useSvobodaMode = settings[0].split("#")
|
val useSvobodaMode = settings[0].split("#")
|
||||||
val useAmoledMode = settings[1].split("#")
|
val useAmoledMode = settings[1].split("#")
|
||||||
val showRefreshButton = settings[2].split("#")
|
val showRefreshButton = settings[2].split("#")
|
||||||
|
val useAnimations = settings[3].split("#")
|
||||||
|
|
||||||
auxSettingsData.useSvobodaMode.id = SettingsId.Svoboda
|
auxSettingsData.useSvobodaMode.id = SettingsId.Svoboda
|
||||||
auxSettingsData.useSvobodaMode.name = useSvobodaMode[1]
|
auxSettingsData.useSvobodaMode.name = useSvobodaMode[1]
|
||||||
@@ -126,5 +134,9 @@ fun String.toSettingsData(): SettingsData {
|
|||||||
auxSettingsData.showRefreshButton.name = showRefreshButton[1]
|
auxSettingsData.showRefreshButton.name = showRefreshButton[1]
|
||||||
auxSettingsData.showRefreshButton.checked.value = showRefreshButton[2].toBoolean()
|
auxSettingsData.showRefreshButton.checked.value = showRefreshButton[2].toBoolean()
|
||||||
|
|
||||||
|
auxSettingsData.useAnimations.id = SettingsId.Animations
|
||||||
|
auxSettingsData.useAnimations.name = useAnimations[1]
|
||||||
|
auxSettingsData.useAnimations.checked.value = useAnimations[2].toBoolean()
|
||||||
|
|
||||||
return auxSettingsData
|
return auxSettingsData
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
@@ -40,6 +41,7 @@ import androidx.compose.foundation.layout.*
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
private var buttonText by mutableStateOf("Přihlásit se")
|
private var buttonText by mutableStateOf("Přihlásit se")
|
||||||
|
|
||||||
@@ -96,6 +98,7 @@ fun signInButtonCallback(ctx: Context, usernameText: String, passwordText: Strin
|
|||||||
global.currentScreen = Screen.Splash
|
global.currentScreen = Screen.Splash
|
||||||
launchStart(ctx)
|
launchStart(ctx)
|
||||||
} else {
|
} else {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
ctx,
|
ctx,
|
||||||
"Neplatné přihlašovací údaje nebo nejste připojeni k internetu, zkuste to znovu.",
|
"Neplatné přihlašovací údaje nebo nejste připojeni k internetu, zkuste to znovu.",
|
||||||
@@ -103,6 +106,7 @@ fun signInButtonCallback(ctx: Context, usernameText: String, passwordText: Strin
|
|||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -115,7 +119,6 @@ fun SignInScreen() {
|
|||||||
var usernameText by remember { mutableStateOf("") }
|
var usernameText by remember { mutableStateOf("") }
|
||||||
var passwordText by remember { mutableStateOf("") }
|
var passwordText by remember { mutableStateOf("") }
|
||||||
val ctx = LocalContext.current
|
val ctx = LocalContext.current
|
||||||
val coscope = rememberCoroutineScope()
|
|
||||||
var isPasswordVisible by remember { mutableStateOf(false) } // State for visibility toggle
|
var isPasswordVisible by remember { mutableStateOf(false) } // State for visibility toggle
|
||||||
val visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation()
|
val visualTransformation = if (isPasswordVisible) VisualTransformation.None else PasswordVisualTransformation()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
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.material3.Button
|
||||||
|
import androidx.compose.material3.ButtonDefaults
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.TextUnit
|
||||||
|
import androidx.compose.ui.unit.TextUnitType
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.odweta.solon.ui.theme.PastelYellow
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SignOutScreen() {
|
||||||
|
// handle the back gesture (back swipe form side or back button on bottom android navbar)
|
||||||
|
BackHandler { global.currentScreenElement = ScreenElement.Menu }
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.Top,
|
||||||
|
horizontalAlignment = Alignment.Start
|
||||||
|
) {
|
||||||
|
backButtonFactory.get(BackButtonType.Menu)()
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.weight(1f),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Opravdu se chcete odhlásit? Tato akce zavře aplikaci.",
|
||||||
|
color = Color.White,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 27.sp,
|
||||||
|
lineHeight = 40.sp,
|
||||||
|
modifier = Modifier.padding(bottom = 10.dp).padding(horizontal = 10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Row {
|
||||||
|
SignOutButton(
|
||||||
|
onClick = {
|
||||||
|
Util.deleteFile(global.filePaths.userData)
|
||||||
|
Util.deleteFile(global.filePaths.timetable)
|
||||||
|
Util.deleteFile(global.filePaths.marks)
|
||||||
|
Util.deleteFile(global.filePaths.accountData)
|
||||||
|
Util.deleteFile(global.filePaths.lectureNotes)
|
||||||
|
// do not delete settings
|
||||||
|
exitProcess(0)
|
||||||
|
},
|
||||||
|
label = "Ano"
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(Modifier.width(10.dp))
|
||||||
|
|
||||||
|
SignOutButton(
|
||||||
|
onClick = {
|
||||||
|
global.currentScreenElement = ScreenElement.Menu
|
||||||
|
},
|
||||||
|
label = "Ne"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SignOutButton(onClick: () -> Unit, label: String) {
|
||||||
|
Button(
|
||||||
|
onClick = onClick,
|
||||||
|
colors = ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Black, // Black background for the button
|
||||||
|
contentColor = Color.White // Yellow text for the button
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.border(
|
||||||
|
width = global.dimens.borderWidth,
|
||||||
|
color = PastelYellow,
|
||||||
|
shape = RoundedCornerShape(global.dimens.roundedCorner)
|
||||||
|
) // Yellow border
|
||||||
|
) {
|
||||||
|
Text(label, fontSize = 17.sp)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -293,7 +293,7 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
|
|||||||
global.currentLectureNumber = lectureNumber
|
global.currentLectureNumber = lectureNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
val m = if (settings.useAmoledMode.checked.value) {
|
val m = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(70.dp)
|
.height(70.dp)
|
||||||
@@ -356,8 +356,10 @@ private fun DayScreen(day: Day) {
|
|||||||
) {
|
) {
|
||||||
for ((subjectIndex, subject) in day.subjects.withIndex()) {
|
for ((subjectIndex, subject) in day.subjects.withIndex()) {
|
||||||
val lectureId = Util.getLectureId(day.date, subjectIndex)
|
val lectureId = Util.getLectureId(day.date, subjectIndex)
|
||||||
|
global.lectureNotes[lectureId]?.number = subject.number.toInt()
|
||||||
|
global.lectureNotes[lectureId]?.lectureName = subject.name
|
||||||
|
|
||||||
val amoledModifier = if (settings.useAmoledMode.checked.value) {
|
val amoledModifier = if (settings.useAmoledMode.checked.value == true) {
|
||||||
Modifier
|
Modifier
|
||||||
.width(50.dp)
|
.width(50.dp)
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
@@ -482,7 +484,7 @@ private fun DayScreen(day: Day) {
|
|||||||
.padding(vertical = 5.dp),
|
.padding(vertical = 5.dp),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
if (settings.useSvobodaMode.checked.value) {
|
if (settings.useSvobodaMode.checked.value == true) {
|
||||||
if (
|
if (
|
||||||
subject.teacher == "Jindřich Svoboda" &&
|
subject.teacher == "Jindřich Svoboda" &&
|
||||||
global.studentClass == "5. G"
|
global.studentClass == "5. G"
|
||||||
|
|||||||
@@ -1,10 +1,21 @@
|
|||||||
package com.odweta.solon
|
package com.odweta.solon
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.slideInHorizontally
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
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.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Upload
|
||||||
|
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.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
@@ -12,16 +23,22 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
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
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
|
private var showLoadingIcon by mutableStateOf(false)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ToolbarScreen() {
|
fun ToolbarScreen() {
|
||||||
// make the font size adaptive relative to the length of the user's name
|
// make the font size adaptive relative to the length of the user's name
|
||||||
@@ -43,12 +60,28 @@ fun ToolbarScreen() {
|
|||||||
toolbarTextSizeAdaptive = 10.sp
|
toolbarTextSizeAdaptive = 10.sp
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(modifier = Modifier.padding(10.dp)) {
|
Animate(global.status) { targetText ->
|
||||||
|
Row(modifier = Modifier.padding(10.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center) {
|
||||||
Text(
|
Text(
|
||||||
text = global.status,
|
text = targetText,
|
||||||
fontSize = toolbarTextSizeAdaptive,
|
fontSize = toolbarTextSizeAdaptive,
|
||||||
color = Color.White
|
color = Color.White
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (settings.useAnimations.checked.value == true) {
|
||||||
|
AnimatedVisibility(showLoadingIcon) {
|
||||||
|
AndroidView(
|
||||||
|
modifier = Modifier.size(50.dp).padding(start = 10.dp),
|
||||||
|
factory = { context: Context -> ImageView(context) },
|
||||||
|
update = { imageView ->
|
||||||
|
Glide.with(imageView.context)
|
||||||
|
.load(R.drawable.loading)
|
||||||
|
.into(imageView)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,20 +113,14 @@ object StatusFactory: StatusFactoryInterface {
|
|||||||
StatusType.Loading -> {
|
StatusType.Loading -> {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
global.refreshed = false
|
global.refreshed = false
|
||||||
val anim = listOf(
|
showStatus("Načítání nových dat")
|
||||||
"Načítání nových dat",
|
delay(100L)
|
||||||
"Načítání nových dat.",
|
showLoadingIcon = true
|
||||||
"Načítání nových dat..",
|
|
||||||
"Načítání nových dat...",
|
|
||||||
"Načítání nových dat..",
|
|
||||||
"Načítání nových dat."
|
|
||||||
)
|
|
||||||
var i = 0
|
|
||||||
while (!global.refreshed) {
|
while (!global.refreshed) {
|
||||||
if (i == anim.size) i = 0
|
showStatus("Načítání nových dat")
|
||||||
showStatus(anim[i++])
|
|
||||||
delay(300)
|
|
||||||
}
|
}
|
||||||
|
showLoadingIcon = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
cp app/build/outputs/apk/release/com.odweta.solon_$1.apk ../release/
|
|
||||||
Reference in New Issue
Block a user