WIP lecture notes
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user