added animations, changed signOut screen

This commit is contained in:
Odweta
2024-12-31 17:22:09 +01:00
parent 1516a00841
commit 81fb398ae2
6 changed files with 207 additions and 88 deletions
@@ -1,10 +1,18 @@
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.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.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@@ -34,7 +42,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 +65,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 {
@@ -184,7 +199,8 @@ enum class ScreenElement {
Marks, Marks,
Menu, Menu,
About, About,
Settings Settings,
SignOut
} }
class Global { class Global {
@@ -268,3 +284,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) {
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,9 +83,8 @@ 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.loadLectureNotes()
@@ -3,6 +3,16 @@ package com.odweta.solon
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.animation.with
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -19,14 +29,18 @@ 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 +48,7 @@ class MainActivity : ComponentActivity() {
} }
} }
} }
}
@Composable @Composable
fun MainScreen() { fun MainScreen() {
@@ -54,12 +69,15 @@ 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.Menu -> MenuScreen() ScreenElement.Menu -> MenuScreen()
ScreenElement.About -> AboutScreen() ScreenElement.About -> AboutScreen()
ScreenElement.Settings -> SettingsScreen() ScreenElement.Settings -> SettingsScreen()
ScreenElement.SignOut -> SignOutScreen()
}
} }
} }
@@ -1,5 +1,12 @@
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
@@ -36,7 +43,7 @@ fun MenuScreen() {
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center
) { ) {
MenuButton({ showDialog = true }, "Odhlásit se") MenuButton({ global.currentScreenElement = ScreenElement.SignOut }, "Odhlásit se")
Spacer(modifier = Modifier.height(80.dp)) Spacer(modifier = Modifier.height(80.dp))
@@ -53,69 +60,6 @@ fun MenuScreen() {
MenuButton({ global.currentScreenElement = ScreenElement.Settings }, "Nastavení") 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")
}
}
)
}
} }
@Composable @Composable
@@ -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,6 +17,7 @@ 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.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
@@ -29,6 +31,10 @@ 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 +44,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)
@@ -78,7 +82,7 @@ fun SettingsTableRow(setting: Setting) {
SettingsId.Svoboda -> settings.useSvobodaMode = setting SettingsId.Svoboda -> settings.useSvobodaMode = setting
SettingsId.Amoled -> settings.useAmoledMode = setting SettingsId.Amoled -> settings.useAmoledMode = setting
SettingsId.RefreshButton -> settings.showRefreshButton = setting SettingsId.RefreshButton -> settings.showRefreshButton = setting
else -> {} SettingsId.Animations -> settings.useAnimations = setting
} }
Util.saveStringToFile(global.filePaths.settings, settings.toString()) Util.saveStringToFile(global.filePaths.settings, settings.toString())
}, },
@@ -113,6 +117,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 +131,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
} }
@@ -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)
)
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)
}
}