WIP lecture notes

This commit is contained in:
Odweta
2024-12-14 20:21:49 +01:00
parent 8e9693bfe6
commit e67f87864c
5 changed files with 223 additions and 162 deletions
@@ -41,6 +41,7 @@ const val timeTableFilePath: String = "timetable.json"
const val userDataFilePath: String = "userdata.json" const val userDataFilePath: String = "userdata.json"
const val marksFilePath: String = "marks.json" const val marksFilePath: String = "marks.json"
const val settingsDataFilePath: String = "settings.txt" const val settingsDataFilePath: String = "settings.txt"
const val lectureNotesFilePath: String = "lecture_notes.csv"
lateinit var fileDir: File lateinit var fileDir: File
var width: Int = 0 var width: Int = 0
var height: Int = 0 var height: Int = 0
@@ -114,6 +115,8 @@ var settings : SettingsData = SettingsData()
var done: Boolean = false var done: Boolean = false
var internetAwaitListenerRunning: Boolean = false
var timeTableAvailOffline: Boolean = false var timeTableAvailOffline: Boolean = false
var marksAvailOffline: Boolean = false var marksAvailOffline: Boolean = false
@@ -135,6 +138,8 @@ var resetNav: Boolean = false
var isAPISetUp: Boolean = false var isAPISetUp: Boolean = false
var lectureNotes: HashMap<Int, String> = hashMapOf()
var selectedDay: Int = 0 var selectedDay: Int = 0
var dayEndString: String = "" var dayEndString: String = ""
@@ -16,6 +16,7 @@ private var toast2Shown: Boolean = false
private lateinit var coscope_: CoroutineScope private lateinit var coscope_: CoroutineScope
private fun setOnInternetAvailListener(ctx: Context, coscope: CoroutineScope) { private fun setOnInternetAvailListener(ctx: Context, coscope: CoroutineScope) {
internetAwaitListenerRunning = true
coscope.launch { coscope.launch {
while (true) { while (true) {
if (Util.internetAvail(ctx) && !internetAvail) { if (Util.internetAvail(ctx) && !internetAvail) {
@@ -140,7 +141,9 @@ private suspend fun launchPhase1(ctx: Context) {
if (!timeTableAvailOffline || !marksAvailOffline || internetAvail) { if (!timeTableAvailOffline || !marksAvailOffline || internetAvail) {
// set up the API (required for later uses of it) // set up the API (required for later uses of it)
if (!isAPISetUp) {
Network.setupAPI() Network.setupAPI()
}
if (internetAvail) { if (internetAvail) {
// cancel a toast, if any // cancel a toast, if any
@@ -272,11 +275,15 @@ private fun launchPhase2(ctx: Context) {
dayList.add(day) dayList.add(day)
} }
Util.loadLectureIds()
loaded = true loaded = true
coscope_.launch { coscope_.launch {
if (!internetAwaitListenerRunning) {
setOnInternetAvailListener(ctx, coscope_) setOnInternetAvailListener(ctx, coscope_)
} }
}
val role = if (Parsing.userIsParent()) { val role = if (Parsing.userIsParent()) {
" Rodič" " Rodič"
@@ -20,7 +20,6 @@ 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.Icons
import androidx.compose.material.icons.filled.Adjust
import androidx.compose.material.icons.filled.ArrowBackIosNew import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.AutoAwesome import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material3.Button import androidx.compose.material3.Button
@@ -12,43 +12,51 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
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.text.selection.TextSelectionColors
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material3.AlertDialog
import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldColors
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope 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.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
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.PastelRed 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 kotlinx.coroutines.launch import java.security.MessageDigest
import java.time.LocalDate import java.time.LocalDate
import java.time.LocalTime import java.time.LocalTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import kotlin.math.abs
@Composable @Composable
fun TimetableScreen() { fun TimetableScreen() {
@@ -76,45 +84,6 @@ fun DayPager(modifier: Modifier = Modifier) {
} }
} }
//@Composable
/*fun RefreshButton(modifier: Modifier = Modifier) {
val coscope = rememberCoroutineScope()
val ctx = LocalContext.current
Box(
modifier = Modifier
.padding(bottom = 10.dp)
.background(color = Color.Black, shape = RoundedCornerShape(roundedCornerDimen))
) {
Button(
onClick = {
coscope.launch {
fetchNewData(ctx, coscope)
}
},
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.padding(vertical = 10.dp)
) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Refresh icon",
modifier = Modifier.size(25.dp)
)
}
}
}
*/
private fun getSubjectColor(s: Subject, transparent: Boolean): Color { private fun getSubjectColor(s: Subject, transparent: Boolean): Color {
return if (s.free) { return if (s.free) {
if (transparent) { if (transparent) {
@@ -198,9 +167,11 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun DayScreen(day: Day) { private fun DayScreen(day: Day) {
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
var showDetailDialog by remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxSize()) { Column(modifier = Modifier.fillMaxSize()) {
Row( Row(
@@ -228,7 +199,7 @@ private fun DayScreen(day: Day) {
.padding(horizontal = 5.dp) .padding(horizontal = 5.dp)
.verticalScroll(scrollState) .verticalScroll(scrollState)
) { ) {
for (subject in day.subjects) { for ((subjectIndex, subject) in day.subjects.withIndex()) {
val amoledModifier = if (settings.useAmoledMode.checked.value) { val amoledModifier = if (settings.useAmoledMode.checked.value) {
Modifier Modifier
.width(50.dp) .width(50.dp)
@@ -270,9 +241,8 @@ private fun DayScreen(day: Day) {
} }
} }
Row( Box (modifier = subjectModifier(day, subject, subject.number.toInt())) {
modifier = subjectModifier(day, subject, subject.number.toInt()) Row {
) {
if (subject.substitute != "2") { if (subject.substitute != "2") {
Box( Box(
modifier = amoledModifier, modifier = amoledModifier,
@@ -370,7 +340,7 @@ private fun DayScreen(day: Day) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxHeight() .fillMaxHeight()
.padding(end = 20.dp), .padding(end = 10.dp),
verticalArrangement = Arrangement.Center, verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End horizontalAlignment = Alignment.End
) { ) {
@@ -397,10 +367,39 @@ private fun DayScreen(day: Day) {
} }
} }
} }
Box(modifier = Modifier.fillMaxSize().zIndex(99f).clickable { showDetailDialog = true })
if (showDetailDialog) {
Dialog(
onDismissRequest = { showDetailDialog = false }, // Close the dialog on dismiss
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true
),
content = {
Box(
modifier = Modifier
.width(100.dp)
.height(100.dp)
.background(
color = Color.Black,
shape = RoundedCornerShape(roundedCornerDimen)
)
) {
TextField(
value = lectureNotes[Util.getLectureId(day.date, subjectIndex)] ?: "",
onValueChange = { newText ->
lectureNotes[Util.getLectureId(day.date, subjectIndex)] = newText
Util.saveLectureIds()
}
)
}
}
)
}
}
} }
//if (settings.showRefreshButton.checked.value) {
// Spacer(modifier = Modifier.height(90.dp))
//}
} }
} }
} }
@@ -12,6 +12,8 @@ import androidx.core.content.pm.PackageInfoCompat
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.nio.charset.Charset import java.nio.charset.Charset
import java.security.MessageDigest
import kotlin.math.abs
import kotlin.math.round import kotlin.math.round
class Util { class Util {
@@ -115,12 +117,14 @@ class Util {
} }
fun isAppInForeground(context: Context, packageName: String): Boolean { fun isAppInForeground(context: Context, packageName: String): Boolean {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager val activityManager =
context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val runningAppProcesses = activityManager.runningAppProcesses ?: return false val runningAppProcesses = activityManager.runningAppProcesses ?: return false
for (processInfo in runningAppProcesses) { for (processInfo in runningAppProcesses) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
processInfo.processName == packageName) { processInfo.processName == packageName
) {
return true return true
} }
} }
@@ -147,7 +151,7 @@ class Util {
weights.add(mark.weight.toFloat()) weights.add(mark.weight.toFloat())
} }
return "${Math.round(sum/sum(weights) * 100f) / 100f}".replace(",", ".") return "${Math.round(sum / sum(weights) * 100f) / 100f}".replace(",", ".")
//return String.format("%.2f", (sum / sum(weights))).replace(',', '.') //return String.format("%.2f", (sum / sum(weights))).replace(',', '.')
} }
@@ -215,7 +219,10 @@ class Util {
val packageManager = context.packageManager val packageManager = context.packageManager
val packageName = context.packageName val packageName = context.packageName
val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
packageManager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(0)) packageManager.getPackageInfo(
packageName,
PackageManager.PackageInfoFlags.of(0)
)
} else { } else {
packageManager.getPackageInfo(packageName, 0) packageManager.getPackageInfo(packageName, 0)
} }
@@ -249,5 +256,49 @@ class Util {
return auxSettingsData return auxSettingsData
} }
fun getLectureId(date: String, subjectIndex: Int): Int {
val concat = "$date[$subjectIndex]"
val bytes = concat.toByteArray()
val md5AsBytes = MessageDigest.getInstance("MD5").digest(bytes)
return abs(md5AsBytes.take(4).fold(0) { acc, byte ->
(acc shl 8) or (byte.toInt() and 0xff)
})
}
fun csvToHashMap(filePath: String): HashMap<Int, String> {
val hashMap = HashMap<Int, String>()
val lines = fileToString(filePath).lines()
for (line in lines) {
if (line.isBlank()) continue
val parts = line.split(",")
if (parts.size == 2) {
val key = parts[0].trim().toInt()
val value = parts[1].trim()
hashMap[key] = value
}
}
return hashMap
}
fun hashMapToCsv(hashMap: HashMap<Int, String>): String {
var result = ""
for ((key, value) in hashMap) {
result += "$key,$value\n"
}
return result
}
fun loadLectureIds() {
lectureNotes = csvToHashMap(lectureNotesFilePath)
}
fun saveLectureIds() {
val toSave = hashMapToCsv(lectureNotes)
saveStringToFile(lectureNotesFilePath, toSave)
}
} }
} }