5 Commits
12 changed files with 367 additions and 567 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
![solon-logo](./solon_logo.png)
# Zorientujte se rychleji v této odlehčené verzi Školy OnLine
# Odkaz na stažení aplikace pro Android [zde](https://gitlab.com/Odweta/solon/-/raw/master/release/com.odweta.solon_2.1.apk?ref_type=heads&inline=false) (verze 2.1)
# Odkaz na stažení aplikace pro Android [zde](https://gitlab.com/Odweta/solon/-/raw/master/release/com.odweta.solon_2.2.apk?ref_type=heads&inline=false) (verze 2.2)
-329
View File
@@ -1,329 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceStreaming">
<option name="deviceSelectionList">
<list>
<PersistentDeviceSelectionData>
<option name="api" value="27" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="F01L" />
<option name="id" value="F01L" />
<option name="manufacturer" value="FUJITSU" />
<option name="name" value="F-01L" />
<option name="screenDensity" value="360" />
<option name="screenX" value="720" />
<option name="screenY" value="1280" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="28" />
<option name="brand" value="DOCOMO" />
<option name="codename" value="SH-01L" />
<option name="id" value="SH-01L" />
<option name="manufacturer" value="SHARP" />
<option name="name" value="AQUOS sense2 SH-01L" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="Lenovo" />
<option name="codename" value="TB370FU" />
<option name="id" value="TB370FU" />
<option name="manufacturer" value="Lenovo" />
<option name="name" value="Tab P12" />
<option name="screenDensity" value="340" />
<option name="screenX" value="1840" />
<option name="screenY" value="2944" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="samsung" />
<option name="codename" value="a51" />
<option name="id" value="a51" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy A51" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="akita" />
<option name="id" value="akita" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="b0q" />
<option name="id" value="b0q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S22 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="32" />
<option name="brand" value="google" />
<option name="codename" value="bluejay" />
<option name="id" value="bluejay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="caiman" />
<option name="id" value="caiman" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro" />
<option name="screenDensity" value="360" />
<option name="screenX" value="960" />
<option name="screenY" value="2142" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="comet" />
<option name="id" value="comet" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro Fold" />
<option name="screenDensity" value="390" />
<option name="screenX" value="2076" />
<option name="screenY" value="2152" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="29" />
<option name="brand" value="samsung" />
<option name="codename" value="crownqlteue" />
<option name="id" value="crownqlteue" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Note9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2220" />
<option name="screenY" value="1080" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="dm3q" />
<option name="id" value="dm3q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S23 Ultra" />
<option name="screenDensity" value="600" />
<option name="screenX" value="1440" />
<option name="screenY" value="3088" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="e1q" />
<option name="id" value="e1q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy S24" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="felix" />
<option name="id" value="felix" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="felix_camera" />
<option name="id" value="felix_camera" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Fold (Camera-enabled)" />
<option name="screenDensity" value="420" />
<option name="screenX" value="2208" />
<option name="screenY" value="1840" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="samsung" />
<option name="codename" value="gts8uwifi" />
<option name="id" value="gts8uwifi" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Tab S8 Ultra" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1848" />
<option name="screenY" value="2960" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="husky" />
<option name="id" value="husky" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8 Pro" />
<option name="screenDensity" value="390" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="motorola" />
<option name="codename" value="java" />
<option name="id" value="java" />
<option name="manufacturer" value="Motorola" />
<option name="name" value="G20" />
<option name="screenDensity" value="280" />
<option name="screenX" value="720" />
<option name="screenY" value="1600" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="komodo" />
<option name="id" value="komodo" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9 Pro XL" />
<option name="screenDensity" value="360" />
<option name="screenX" value="1008" />
<option name="screenY" value="2244" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="lynx" />
<option name="id" value="lynx" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7a" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="31" />
<option name="brand" value="google" />
<option name="codename" value="oriole" />
<option name="id" value="oriole" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="panther" />
<option name="id" value="panther" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 7" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q5q" />
<option name="id" value="q5q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold5" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1812" />
<option name="screenY" value="2176" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="samsung" />
<option name="codename" value="q6q" />
<option name="id" value="q6q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="Galaxy Z Fold6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1856" />
<option name="screenY" value="2160" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="r11" />
<option name="id" value="r11" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Watch" />
<option name="screenDensity" value="320" />
<option name="screenX" value="384" />
<option name="screenY" value="384" />
<option name="type" value="WEAR_OS" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="30" />
<option name="brand" value="google" />
<option name="codename" value="redfin" />
<option name="id" value="redfin" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 5" />
<option name="screenDensity" value="440" />
<option name="screenX" value="1080" />
<option name="screenY" value="2340" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="shiba" />
<option name="id" value="shiba" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 8" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="33" />
<option name="brand" value="google" />
<option name="codename" value="tangorpro" />
<option name="id" value="tangorpro" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel Tablet" />
<option name="screenDensity" value="320" />
<option name="screenX" value="1600" />
<option name="screenY" value="2560" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="google" />
<option name="codename" value="tokay" />
<option name="id" value="tokay" />
<option name="manufacturer" value="Google" />
<option name="name" value="Pixel 9" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1080" />
<option name="screenY" value="2424" />
</PersistentDeviceSelectionData>
</list>
</option>
</component>
</project>
+2 -2
View File
@@ -12,8 +12,8 @@ android {
applicationId = "com.odweta.solon"
minSdk = 28
targetSdk = 34
versionCode = 204
versionName = "2.1"
versionCode = 205
versionName = "2.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -41,6 +41,7 @@ const val timeTableFilePath: String = "timetable.json"
const val userDataFilePath: String = "userdata.json"
const val marksFilePath: String = "marks.json"
const val settingsDataFilePath: String = "settings.txt"
const val lectureNotesFilePath: String = "lecture_notes.csv"
lateinit var fileDir: File
var width: Int = 0
var height: Int = 0
@@ -114,6 +115,8 @@ var settings : SettingsData = SettingsData()
var done: Boolean = false
var internetAwaitListenerRunning: Boolean = false
var timeTableAvailOffline: Boolean = false
var marksAvailOffline: Boolean = false
@@ -135,6 +138,9 @@ var resetNav: Boolean = false
var isAPISetUp: Boolean = false
var lectureNotes: HashMap<Int, MutableState<String>> = hashMapOf()
var selectedLecture: Int = 0
var selectedDay: Int = 0
var dayEndString: String = ""
@@ -16,6 +16,7 @@ private var toast2Shown: Boolean = false
private lateinit var coscope_: CoroutineScope
private fun setOnInternetAvailListener(ctx: Context, coscope: CoroutineScope) {
internetAwaitListenerRunning = true
coscope.launch {
while (true) {
if (Util.internetAvail(ctx) && !internetAvail) {
@@ -140,7 +141,9 @@ private suspend fun launchPhase1(ctx: Context) {
if (!timeTableAvailOffline || !marksAvailOffline || internetAvail) {
// set up the API (required for later uses of it)
Network.setupAPI()
if (!isAPISetUp) {
Network.setupAPI()
}
if (internetAvail) {
// cancel a toast, if any
@@ -272,10 +275,14 @@ private fun launchPhase2(ctx: Context) {
dayList.add(day)
}
Util.loadLectureIds()
loaded = true
coscope_.launch {
setOnInternetAvailListener(ctx, coscope_)
if (!internetAwaitListenerRunning) {
setOnInternetAvailListener(ctx, coscope_)
}
}
val role = if (Parsing.userIsParent()) {
@@ -21,6 +21,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBackIosNew
import androidx.compose.material.icons.filled.AutoAwesome
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
@@ -45,6 +46,8 @@ import com.odweta.solon.ui.theme.PastelRed
import com.odweta.solon.ui.theme.PastelRedTransparent
import com.odweta.solon.ui.theme.PastelYellow
import com.odweta.solon.ui.theme.PastelYellowTransparent
import java.time.LocalDate
import java.time.format.DateTimeFormatter
enum class MarksShow {
All,
@@ -183,6 +186,16 @@ fun MarksAll() {
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(
modifier = amoledModifierBackground
) {
@@ -221,17 +234,30 @@ fun MarksAll() {
}
Box(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.padding(horizontal = 10.dp),
contentAlignment = Alignment.Center
modifier = Modifier.fillMaxSize().weight(1f),
contentAlignment = Alignment.TopStart
) {
Text(
text = marksString,
fontSize = 22.sp,
color = Color.White
)
if (subjectContainsNewMark) {
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(
modifier = Modifier
.fillMaxSize()
.padding(horizontal = 10.dp),
contentAlignment = Alignment.Center
) {
Text(
text = marksString,
fontSize = 22.sp,
color = Color.White
)
}
}
}
}
@@ -353,50 +379,62 @@ fun MarksSubject() {
Spacer(modifier = Modifier.height(10.dp))
}
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 5.dp)
.background(color = if (settings.useAmoledMode.checked.value) {
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.TopStart
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 5.dp)
.background(color = if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
getAvgColor(
Util.avg(marks[subjectToShow]!!)
)
getAvgColor(mark.grade)
},
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 10.dp)
.clickable {
markToShow = mark
marksShow.value = MarksShow.Detail
}
) {
Box(
modifier = Modifier
.width(70.dp)
.align(Alignment.CenterVertically),
contentAlignment = Alignment.Center
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 10.dp)
.clickable {
markToShow = mark
marksShow.value = MarksShow.Detail
}
) {
Text(
text = mark.grade,
color = Color.White,
fontSize = 30.sp
) // grade
Box(
modifier = Modifier
.width(70.dp)
.align(Alignment.CenterVertically),
contentAlignment = Alignment.Center
) {
Text(
text = mark.grade,
color = Color.White,
fontSize = 30.sp
) // grade
}
Box(
modifier = Modifier
.align(Alignment.CenterVertically)
.weight(1f),
contentAlignment = Alignment.CenterStart
) {
Text(
text = mark.theme,
color = Color.White,
fontSize = 20.sp
) // theme
}
}
Box(
modifier = Modifier
.align(Alignment.CenterVertically)
.weight(1f),
contentAlignment = Alignment.CenterStart
) {
Text(
text = mark.theme,
color = Color.White,
fontSize = 20.sp
) // 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))) {
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
)
}
}
}
@@ -486,28 +524,26 @@ fun MarksDetail() {
Spacer(modifier = Modifier.height(20.dp))
Row {
//Box(modifier = Modifier.height(70.dp)) {
Text(
text = markToShow.theme,
color = Color.White,
textAlign = TextAlign.Center,
fontSize = 30.sp,
modifier = Modifier
.fillMaxWidth()
.border(
width = 5.dp,
color = PastelYellow,
shape = RoundedCornerShape(roundedCornerDimen)
)
.background(if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
PastelYellowTransparent
}
)
.padding(vertical = 20.dp)
) // description
//}
Text(
text = markToShow.theme,
color = Color.White,
textAlign = TextAlign.Center,
fontSize = 30.sp,
modifier = Modifier
.fillMaxWidth()
.border(
width = 5.dp,
color = PastelYellow,
shape = RoundedCornerShape(roundedCornerDimen)
)
.background(if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
PastelYellowTransparent
}
)
.padding(vertical = 20.dp)
) // description
} // description
Spacer(modifier = Modifier.height(20.dp))
@@ -1,6 +1,7 @@
package com.odweta.solon
import android.annotation.SuppressLint
import android.util.Log
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -12,43 +13,53 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.Image
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.TextSelectionColors
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
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.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.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.font.FontWeight
import androidx.compose.ui.unit.dp
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.PastelGreenTransparent
import com.odweta.solon.ui.theme.PastelRed
import com.odweta.solon.ui.theme.PastelRedTransparent
import com.odweta.solon.ui.theme.PastelYellow
import com.odweta.solon.ui.theme.PastelYellowTransparent
import kotlinx.coroutines.launch
import java.security.MessageDigest
import java.time.LocalDate
import java.time.LocalTime
import java.time.format.DateTimeFormatter
import kotlin.math.abs
var showDetailDialog = mutableStateOf(false)
@Composable
fun TimetableScreen() {
@@ -58,12 +69,60 @@ fun TimetableScreen() {
contentAlignment = Alignment.BottomCenter
) {
DayPager()
//if (settings.showRefreshButton.checked.value) {
// RefreshButton()
//}
if (showDetailDialog.value) {
DetailDialog()
}
}
}
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DetailDialog(modifier: Modifier = Modifier) {
Dialog(
onDismissRequest = { showDetailDialog.value = false }, // Close the dialog on dismiss
properties = DialogProperties(
dismissOnBackPress = true,
dismissOnClickOutside = true
),
content = {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
.background(
color = Color.Black,
shape = RoundedCornerShape(roundedCornerDimen)
)
) {
if (lectureNotes[selectedLecture] == null) {
lectureNotes[selectedLecture] = mutableStateOf("")
}
TextField(
value = lectureNotes[selectedLecture]!!.value,
onValueChange = { newText: String ->
lectureNotes[selectedLecture]!!.value = newText
Util.saveLectureIds()
},
placeholder = { Text("Sem můžete napsat poznámky k\u00A0této hodině.") },
colors = TextFieldDefaults.textFieldColors(
focusedTextColor = Color.White,
containerColor = Color.Black,
selectionColors = TextSelectionColors(
handleColor = PastelYellow,
backgroundColor = PastelYellowTransparent
),
cursorColor = PastelYellow,
focusedIndicatorColor = PastelYellow,
unfocusedIndicatorColor = PastelYellowTransparent
)
)
}
}
)
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun DayPager(modifier: Modifier = Modifier) {
@@ -76,45 +135,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 {
return if (s.free) {
if (transparent) {
@@ -228,7 +248,8 @@ private fun DayScreen(day: Day) {
.padding(horizontal = 5.dp)
.verticalScroll(scrollState)
) {
for (subject in day.subjects) {
for ((subjectIndex, subject) in day.subjects.withIndex()) {
val lectureId = Util.getLectureId(day.date, subjectIndex)
val amoledModifier = if (settings.useAmoledMode.checked.value) {
Modifier
.width(50.dp)
@@ -270,137 +291,142 @@ private fun DayScreen(day: Day) {
}
}
Row(
modifier = subjectModifier(day, subject, subject.number.toInt())
) {
if (subject.substitute != "2") {
Box(
modifier = amoledModifier,
contentAlignment = Alignment.Center
) {
Text(
text = subject.number,
fontSize = 30.sp,
color = Color.White
)
Box (modifier = subjectModifier(day, subject, subject.number.toInt())) {
Row {
if (subject.substitute != "2") {
Box(
modifier = amoledModifier,
contentAlignment = Alignment.Center
) {
Text(
text = subject.number,
fontSize = 30.sp,
color = Color.White
)
}
}
}
if (subject.substitute != "2") {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
if (!subject.free) {
if (subject.substitute == "1") {
Row {
if (subject.substitute != "2") {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
if (!subject.free) {
if (subject.substitute == "1") {
Row {
Text(
text = subject.name.uppercase(),
color = Color.White,
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = " supl ",
color = Color.Black,
modifier = Modifier.background(color = Color.White)
)
}
} else {
Text(
text = subject.name.uppercase(),
color = Color.White,
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
Spacer(modifier = Modifier.width(10.dp))
Text(
text = " supl ",
color = Color.Black,
modifier = Modifier.background(color = Color.White)
)
}
} else {
Text(
text = subject.name.uppercase(),
color = Color.White,
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
}
}
Text(
text = subject.place,
color = Color.White,
fontSize = 21.sp
)
}
} else {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = subject.name,
color = Color.White,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
Box(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.padding(vertical = 5.dp),
contentAlignment = Alignment.Center
) {
if (settings.useSvobodaMode.checked.value) {
if (
subject.teacher == "Jindřich Svoboda" &&
studentClass == "5. G"
) {
Image(
painter = painterResource(R.drawable.spock),
contentDescription = "Spock",
modifier = Modifier.fillMaxSize()
)
}
}
}
if (subject.substitute != "2") {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(end = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End
) {
// show only for non prepended free lectures
if ((subject.free && subject.start != "00:00" && subject.end != "00:00") || !subject.free) {
Text(
text = "${subject.start}${subject.end}",
text = subject.place,
color = Color.White,
fontSize = 21.sp
)
}
} else {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(start = 20.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = subject.name,
color = Color.White,
fontSize = 20.sp,
fontWeight = FontWeight.Bold
)
}
}
if (!subject.free) {
Box (
contentAlignment = Alignment.BottomEnd
Box(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.padding(vertical = 5.dp),
contentAlignment = Alignment.Center
) {
if (settings.useSvobodaMode.checked.value) {
if (
subject.teacher == "Jindřich Svoboda" &&
studentClass == "5. G"
) {
Text(
text = subject.teacher,
color = Color.White,
fontSize = 12.sp
Image(
painter = painterResource(R.drawable.spock),
contentDescription = "Spock",
modifier = Modifier.fillMaxSize()
)
}
}
}
if (subject.substitute != "2") {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(end = 10.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.End
) {
// show only for non prepended free lectures
if ((subject.free && subject.start != "00:00" && subject.end != "00:00") || !subject.free) {
Text(
text = "${subject.start}${subject.end}",
color = Color.White,
fontSize = 21.sp
)
}
if (!subject.free) {
Box (
contentAlignment = Alignment.BottomEnd
) {
Text(
text = subject.teacher,
color = Color.White,
fontSize = 12.sp
)
}
}
}
}
}
Box(modifier = Modifier
.fillMaxSize()
.zIndex(99f)
.clickable {
selectedLecture = lectureId
showDetailDialog.value = true
})
}
}
//if (settings.showRefreshButton.checked.value) {
// Spacer(modifier = Modifier.height(90.dp))
//}
}
}
}
@@ -8,10 +8,14 @@ import android.net.NetworkCapabilities
import android.os.Build
import android.util.DisplayMetrics
import android.view.WindowManager
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.core.content.pm.PackageInfoCompat
import java.io.File
import java.io.IOException
import java.nio.charset.Charset
import java.security.MessageDigest
import kotlin.math.abs
import kotlin.math.round
class Util {
@@ -115,12 +119,14 @@ class Util {
}
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
for (processInfo in runningAppProcesses) {
if (processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
processInfo.processName == packageName) {
processInfo.processName == packageName
) {
return true
}
}
@@ -147,7 +153,7 @@ class Util {
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(',', '.')
}
@@ -215,7 +221,10 @@ class Util {
val packageManager = context.packageManager
val packageName = context.packageName
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 {
packageManager.getPackageInfo(packageName, 0)
}
@@ -249,5 +258,50 @@ class Util {
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, MutableState<String>> {
val hashMap = HashMap<Int, MutableState<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] = mutableStateOf("")
hashMap[key]!!.value = value
}
}
return hashMap
}
fun hashMapToCsv(hashMap: HashMap<Int, MutableState<String>>): String {
var result = ""
for ((key, value) in hashMap) {
result += "$key,${value.value}\n"
}
return result
}
fun loadLectureIds() {
lectureNotes = csvToHashMap(lectureNotesFilePath)
}
fun saveLectureIds() {
val toSave = hashMapToCsv(lectureNotes)
saveStringToFile(lectureNotesFilePath, toSave)
}
}
}
+1 -1
View File
@@ -21,4 +21,4 @@ kotlin.code.style=official
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
sdk.dir=/home/thinker/Android/Sdk
sdk.dir=~/Android/Sdk
Binary file not shown.
Binary file not shown.