remade new marks into a FAB

This commit is contained in:
Odweta
2024-12-22 16:16:07 +01:00
parent 49a28b0064
commit da890ea180
6 changed files with 229 additions and 82 deletions
@@ -14,6 +14,8 @@ import androidx.compose.ui.unit.dp
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
enum class Screen { enum class Screen {
Main, Main,
@@ -32,8 +34,7 @@ class Setting(auxId: SettingsId, auxName: String, auxChecked: Boolean) {
enum class SettingsId { enum class SettingsId {
Svoboda, Svoboda,
Amoled, Amoled,
RefreshButton, RefreshButton
TagNewMarks
} }
class SettingsData { class SettingsData {
@@ -55,13 +56,7 @@ class SettingsData {
true true
) )
var tagNewMarks: Setting = Setting( override fun toString() = "$useSvobodaMode\n$useAmoledMode\n$showRefreshButton"
SettingsId.TagNewMarks,
"Označit nové známky",
true
)
override fun toString() = "$useSvobodaMode\n$useAmoledMode\n$showRefreshButton\n$tagNewMarks"
} }
enum class LectureNoteType { enum class LectureNoteType {
@@ -158,6 +153,7 @@ class Mark {
lateinit var subject: String // subjectId -> parse that lateinit var subject: String // subjectId -> parse that
lateinit var date: String // markDate lateinit var date: String // markDate
lateinit var theme: String // theme lateinit var theme: String // theme
var editDate: LocalDateTime = LocalDateTime.now()
override fun toString(): String { override fun toString(): String {
return "mark: ${this.grade} * ${this.weight}, subject: ${this.subject}, description: ${this.theme}, date: ${this.date}" return "mark: ${this.grade} * ${this.weight}, subject: ${this.subject}, description: ${this.theme}, date: ${this.date}"
@@ -187,6 +183,7 @@ class Global {
lateinit var timetableJSON: JSONObject lateinit var timetableJSON: JSONObject
lateinit var marksJSON: JSONObject lateinit var marksJSON: JSONObject
lateinit var marks: MutableMap<String, MutableList<Mark>> lateinit var marks: MutableMap<String, MutableList<Mark>>
lateinit var newMarks: MutableMap<String, MutableList<Mark>>
lateinit var settings: SettingsData lateinit var settings: SettingsData
lateinit var fileDir: File lateinit var fileDir: File
@@ -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 androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -73,6 +74,7 @@ fun launchContinue(
global.timetable = parsedTimetable global.timetable = parsedTimetable
val parsedMarks = Parsing.parseMarks(marks) val parsedMarks = Parsing.parseMarks(marks)
global.marks = parsedMarks global.marks = parsedMarks
global.newMarks = Parsing.parseNewMarks(marks)
// load the settings // load the settings
val settingsData = Util.fileToString(global.filePaths.settings).toSettingsData() val settingsData = Util.fileToString(global.filePaths.settings).toSettingsData()
@@ -20,16 +20,29 @@ 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.material3.FloatingActionButton
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
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.platform.LocalContext
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.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
@@ -43,6 +56,8 @@ import com.odweta.solon.ui.theme.PastelYellowTransparent
import java.time.LocalDate import java.time.LocalDate
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
var showNewMarksDialog by mutableStateOf(false)
enum class MarksDepthLevel { enum class MarksDepthLevel {
All, All,
Subject, Subject,
@@ -56,6 +71,106 @@ fun MarksScreen() {
MarksDepthLevel.Subject -> MarksSubject() MarksDepthLevel.Subject -> MarksSubject()
MarksDepthLevel.Detail -> MarksDetail() MarksDepthLevel.Detail -> MarksDetail()
} }
if (showNewMarksDialog) {
val scrollStateNewMarks = rememberScrollState()
Dialog(
onDismissRequest = { showNewMarksDialog = false },
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true
)
) {
Column(
Modifier.verticalScroll(scrollStateNewMarks).padding(vertical = 10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"Nové známky",
color = Color.White,
fontWeight = FontWeight.Bold,
fontSize = 30.sp,
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))
for ((k, v) in global.newMarks) {
if (v.size > 0) {
Column(
modifier = Modifier
.padding(10.dp)
.border(
shape = RoundedCornerShape(global.dimens.roundedCorner),
color = PastelYellow,
width = global.dimens.borderWidth
)
.background(
Color.Black,
shape = RoundedCornerShape(global.dimens.roundedCorner)
)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
k,
color = Color.White,
modifier = Modifier.padding(10.dp),
fontWeight = FontWeight.Bold,
fontSize = 30.sp
)
for (i in v) {
Row(
Modifier.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
i.theme,
color = Color.White,
modifier = Modifier.padding(end = 5.dp, top = 5.dp)
.weight(1f)
)
Column(
horizontalAlignment = Alignment.End
) {
Text(
i.grade + " * " + i.weight,
color = Color.White,
modifier = Modifier
.background(
color = getAvgColor(i.grade, true),
shape = RoundedCornerShape(global.dimens.roundedCorner)
).padding(5.dp),
style = TextStyle(
shadow = Shadow(
color = Color.Black,
offset = Offset(4f, 4f),
blurRadius = 8f
)
)
)
Text(
i.editDate.format(
DateTimeFormatter.ofPattern("dd. MM. yyyy")
),
color = Color.White
)
}
}
HorizontalLine()
}
}
}
}
}
}
}
} }
private fun getAvgColor(avg: String, isBorder: Boolean = false): Color { private fun getAvgColor(avg: String, isBorder: Boolean = false): Color {
@@ -112,7 +227,10 @@ fun MarksAll() {
.fillMaxHeight() .fillMaxHeight()
.border( .border(
width = global.dimens.borderWidth, width = global.dimens.borderWidth,
color = getAvgColor(Util.avg(markList), true), // decide on the color (transparent) color = getAvgColor(
Util.avg(markList),
true
), // decide on the color (transparent)
shape = RoundedCornerShape(global.dimens.roundedCorner) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
} else { } else {
@@ -131,7 +249,10 @@ fun MarksAll() {
.height(70.dp) .height(70.dp)
.border( .border(
width = global.dimens.borderWidth, width = global.dimens.borderWidth,
color = getAvgColor(Util.avg(markList), true), // decide on the color (transparent) color = getAvgColor(
Util.avg(markList),
true
), // decide on the color (transparent)
shape = RoundedCornerShape(global.dimens.roundedCorner) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
.clickable { .clickable {
@@ -176,16 +297,6 @@ fun MarksAll() {
Box(modifier = Modifier.height(10.dp)) Box(modifier = Modifier.height(10.dp))
} }
// only add if mark date is not older than one week
var subjectContainsNewMark = false
for (mark in markList) {
if (LocalDate.parse(mark.date, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.isAfter(LocalDate.now().minusWeeks(1))
) {
subjectContainsNewMark = true
}
}
Row( Row(
modifier = amoledModifierBackground modifier = amoledModifierBackground
) { ) {
@@ -224,18 +335,11 @@ fun MarksAll() {
} }
Box( Box(
modifier = Modifier.fillMaxSize().weight(1f), modifier = Modifier
.fillMaxSize()
.weight(1f),
contentAlignment = Alignment.TopStart contentAlignment = Alignment.TopStart
) { ) {
if (subjectContainsNewMark && settings.tagNewMarks.checked.value) {
Icon(
modifier = Modifier.padding(start = 4.dp, top = 4.dp),
imageVector = Icons.Default.AutoAwesome,
contentDescription = "New marks in subject",
tint = Color.White // You can customize the icon color
)
}
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
@@ -251,6 +355,27 @@ fun MarksAll() {
} }
} }
} }
Spacer(Modifier.height(80.dp))
}
Box(Modifier.fillMaxSize()) {
FloatingActionButton(
onClick = { showNewMarksDialog = true },
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(10.dp)
.background(Color.Black, shape = RoundedCornerShape(global.dimens.roundedCorner)),
containerColor = Color.Black,
contentColor = PastelYellow
) {
Icon(
modifier = Modifier.padding(start = 4.dp, top = 4.dp),
imageVector = Icons.Default.AutoAwesome,
contentDescription = "New marks in subject",
tint = PastelYellow // You can customize the icon color
)
}
} }
} }
@@ -287,7 +412,8 @@ fun MarksSubject() {
), ),
shape = RoundedCornerShape(global.dimens.roundedCorner) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
.background(color = if (settings.useAmoledMode.checked.value) { .background(
color = if (settings.useAmoledMode.checked.value) {
Color.Black Color.Black
} else { } else {
getAvgColor( getAvgColor(
@@ -327,7 +453,8 @@ fun MarksSubject() {
color = PastelYellow, color = PastelYellow,
shape = RoundedCornerShape(global.dimens.roundedCorner) shape = RoundedCornerShape(global.dimens.roundedCorner)
) )
.background(color = if (settings.useAmoledMode.checked.value) { .background(
color = if (settings.useAmoledMode.checked.value) {
Color.Black Color.Black
} else { } else {
PastelYellowTransparent PastelYellowTransparent
@@ -353,7 +480,8 @@ fun MarksSubject() {
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 5.dp) .padding(horizontal = 5.dp)
.background(color = if (settings.useAmoledMode.checked.value) { .background(
color = if (settings.useAmoledMode.checked.value) {
Color.Black Color.Black
} else { } else {
getAvgColor(mark.grade) getAvgColor(mark.grade)
@@ -392,20 +520,6 @@ fun MarksSubject() {
) // theme ) // theme
} }
} }
// only add if mark date is not older than one week
if ((LocalDate
.parse(mark.date, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.isAfter(LocalDate.now().minusWeeks(1))
) && settings.tagNewMarks.checked.value
) {
Icon(
modifier = Modifier.padding(start = 7.dp, top = 4.dp),
imageVector = Icons.Default.AutoAwesome,
contentDescription = "A new mark",
tint = Color.White // You can customize the icon color
)
}
} }
} }
} }
@@ -2,7 +2,9 @@ package com.odweta.solon
import android.util.Log import android.util.Log
import org.json.JSONObject import org.json.JSONObject
import java.time.LocalDate
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
class Parsing { class Parsing {
@@ -324,9 +326,8 @@ class Parsing {
return timetable return timetable
} }
fun parseMarks(jsonString: JSONObject): MutableMap<String, MutableList<Mark>> { fun parseMarks(json: JSONObject): MutableMap<String, MutableList<Mark>> {
// no marks // no marks
val json = jsonString
if (json.has("marks") && json.getJSONArray("marks").length() == 0) { if (json.has("marks") && json.getJSONArray("marks").length() == 0) {
val noMarks = mutableMapOf<String, MutableList<Mark>>() val noMarks = mutableMapOf<String, MutableList<Mark>>()
val list = mutableListOf<Mark>() val list = mutableListOf<Mark>()
@@ -340,9 +341,9 @@ class Parsing {
val marksList = mutableListOf<JSONObject>() val marksList = mutableListOf<JSONObject>()
val marksJSONArray = jsonString.getJSONArray("marks") val marksJSONArray = json.getJSONArray("marks")
val subjectsJSONArray = jsonString.getJSONArray("subjects") val subjectsJSONArray = json.getJSONArray("subjects")
val subjectMap = mutableMapOf<String, String>() val subjectMap = mutableMapOf<String, String>()
for (i in 0..<subjectsJSONArray.length()) { for (i in 0..<subjectsJSONArray.length()) {
@@ -361,16 +362,6 @@ class Parsing {
marks[subj] = mutableListOf() marks[subj] = mutableListOf()
} }
/*
* class Mark {
* lateinit var grade: String // markText
* lateinit var weight: String // weight
* lateinit var subject: String // subjectId -> parse that
* lateinit var date: String // markDate
* lateinit var theme: String // theme
* }
*/
for (markJSON in marksList) { for (markJSON in marksList) {
val mark = Mark() val mark = Mark()
mark.grade = markJSON.getString("markText") mark.grade = markJSON.getString("markText")
@@ -384,6 +375,57 @@ class Parsing {
return marks return marks
} }
fun parseNewMarks(json: JSONObject): MutableMap<String, MutableList<Mark>> {
// no marks
if (json.has("marks") && json.getJSONArray("marks").length() == 0) {
val noMarks = mutableMapOf<String, MutableList<Mark>>()
val list = mutableListOf<Mark>()
list.add(Mark().none())
noMarks["-"] = list
return noMarks
}
// [subject] = (<editDate>, <mark>)
val marks = mutableMapOf<String, MutableList<Mark>>()
val marksList = mutableListOf<JSONObject>()
val marksJSONArray = json.getJSONArray("marks")
val subjectsJSONArray = json.getJSONArray("subjects")
val subjectMap = mutableMapOf<String, String>()
for (i in 0..<subjectsJSONArray.length()) {
val subj = subjectsJSONArray.getJSONObject(i)
subjectMap[subj.getString("id")] = subj.getString("abbrev")
// map names to abbrevs
global.subjectNameMap[subj.getString("abbrev")] = subj.getString("name")
}
for (i in 0..<marksJSONArray.length()) {
marksList.add(marksJSONArray.getJSONObject(i))
}
for (subj in subjectMap.values) {
marks[subj] = mutableListOf()
}
for (markJSON in marksList) {
val mark = Mark()
mark.grade = markJSON.getString("markText")
mark.weight = markJSON.getString("weight")
mark.subject = subjectMap[markJSON.getString("subjectId")].toString()
mark.date = markJSON.getString("markDate")
mark.theme = markJSON.getString("theme")
mark.editDate = LocalDateTime.parse(markJSON.getString("editDate"), DateTimeFormatter.ISO_LOCAL_DATE_TIME)
if (isTimeBetweenD(mark.editDate, LocalDateTime.now().minusWeeks(1), LocalDateTime.now())) marks[mark.subject]?.add(mark)
}
return marks
}
fun getStudentClass(): String { fun getStudentClass(): String {
return if (!userIsParent()) { return if (!userIsParent()) {
global.userData global.userData
@@ -2,8 +2,6 @@ package com.odweta.solon
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -11,16 +9,9 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Switch 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
@@ -58,10 +49,6 @@ fun SettingsScreen() {
Spacer(Modifier.height(10.dp)) Spacer(Modifier.height(10.dp))
SettingsTableRow(settings.showRefreshButton) SettingsTableRow(settings.showRefreshButton)
Spacer(Modifier.height(10.dp))
SettingsTableRow(settings.tagNewMarks)
} }
} }
@@ -91,7 +78,6 @@ 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
SettingsId.TagNewMarks -> settings.tagNewMarks = setting
else -> {} else -> {}
} }
Util.saveStringToFile(global.filePaths.settings, settings.toString()) Util.saveStringToFile(global.filePaths.settings, settings.toString())
@@ -1,6 +1,7 @@
package com.odweta.solon package com.odweta.solon
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
@@ -66,6 +67,7 @@ import com.odweta.solon.ui.theme.PastelYellowTransparent
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime import java.time.LocalTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -255,8 +257,12 @@ private fun getSubjectColor(s: Subject, transparent: Boolean): Color {
} }
} }
} }
fun isTimeBetweenT(givenTime: LocalTime, startTime: LocalTime, endTime: LocalTime): Boolean {
// Check if the given time is between startTime and endTime
return givenTime.isAfter(startTime) && givenTime.isBefore(endTime)
}
fun isTimeBetween(givenTime: LocalTime, startTime: LocalTime, endTime: LocalTime): Boolean { fun isTimeBetweenD(givenTime: LocalDateTime, startTime: LocalDateTime, endTime: LocalDateTime): Boolean {
// Check if the given time is between startTime and endTime // Check if the given time is between startTime and endTime
return givenTime.isAfter(startTime) && givenTime.isBefore(endTime) return givenTime.isAfter(startTime) && givenTime.isBefore(endTime)
} }
@@ -283,7 +289,7 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
val todayDate = LocalDate.now() val todayDate = LocalDate.now()
val now = LocalTime.now() val now = LocalTime.now()
if (dateParsed == todayDate && isTimeBetween(now, startTimeParsed, endTimeParsed)) { if (dateParsed == todayDate && isTimeBetweenT(now, startTimeParsed, endTimeParsed)) {
global.currentLectureNumber = lectureNumber global.currentLectureNumber = lectureNumber
} }