42 Commits
Author SHA1 Message Date
Odweta 59eab71cc4 made deploy script 2024-12-18 14:10:36 +01:00
Odweta eb289db339 gitignore 2024-12-18 14:09:31 +01:00
Odweta 5b0f016add gitignore update 2024-12-18 11:41:15 +01:00
Odweta f8b05884d3 made new release 2.2.2 (207) 2024-12-18 11:31:59 +01:00
Odweta 1344d57685 gitignore and update fastlane 2024-12-18 11:03:43 +01:00
Odweta cb57affc10 lecture notes now work and also added some cosmetic fixes 2024-12-18 10:00:53 +01:00
Odweta 4f43154a13 made new release 2.2.1 2024-12-16 11:08:15 +01:00
Odweta 24dbb3969c improved some stuff 2024-12-16 10:57:02 +01:00
Odweta c7dacbf1bd settings: optionally tag new mark 2024-12-16 10:19:10 +01:00
Odweta af96914ec7 tagged lectures with notes 2024-12-16 10:09:09 +01:00
Odweta 8ddbdc43f9 improved lecture notes with a type and showing the name and number of the lecture 2024-12-16 09:53:19 +01:00
Odweta 3bb5ce5ca7 fixed incorrect color in MarksDetail regarding the average field 2024-12-15 10:42:14 +01:00
Odweta bda937095c made new release 2.2 (205) 2024-12-15 00:20:17 +01:00
Odweta 67392ccb3d release 2.1 (pull) 2024-12-15 00:09:40 +01:00
Odweta a163d6b285 you can now add notes to every lecture and they will automatically be saved locally 2024-12-15 00:05:44 +01:00
Odweta e67f87864c WIP lecture notes 2024-12-14 20:21:49 +01:00
Odweta 8e9693bfe6 fixed colors in MarksSubject and tagged new marks 2024-12-14 18:44:21 +01:00
Odweta c6646e554f made new release 2.1 (204) 2024-12-08 09:35:46 +01:00
Odweta 98b6b72e81 add generic release app name 2024-12-03 19:19:20 +01:00
Odweta c6a5c50a7d build and sign release 2.1 2024-12-03 16:28:14 +01:00
Odweta 09bddaac3c made new logo 2024-12-02 13:48:35 +01:00
Odweta bb39f10a0b made new logo 2024-12-02 13:48:27 +01:00
Odweta 7e44cb585b sign release again 2024-12-02 11:06:11 +01:00
Odweta 91ba977a86 made release 2.1.1 2024-12-01 15:21:00 +01:00
Odweta 5d9b70f3a1 moved the refresh button to the navbar 2024-12-01 15:17:55 +01:00
Odweta 75a766ca7d signed new release 2.1 (204) 2024-12-01 08:41:55 +01:00
Odweta 23607f93b3 hotfix debug residue 2024-11-30 23:03:12 +01:00
Odweta 887c7d58b5 made new release 2.1 2024-11-30 12:33:08 +01:00
Odweta 4d96707a51 fixed settings file read error 2024-11-30 12:15:36 +01:00
Odweta 5a98379d3f made the AMOLED mode work 2024-11-30 12:06:51 +01:00
Odweta 80e5581f45 made the Svoboda mode work and improved the toolbar ux 2024-11-30 11:38:50 +01:00
Odweta 5200e3ba07 improved menu layout 2024-11-30 11:23:04 +01:00
Odweta f67e28b8f6 made the showRefreshButton setting work 2024-11-30 11:15:08 +01:00
Odweta 597971288e improved the displaying of averages with marks 2024-11-30 11:10:23 +01:00
Odweta 0a4ea395fd added a settings screen skeleton 2024-11-30 09:52:32 +01:00
Odweta 509f7f33a7 added a mark to substituted lectures 2024-11-29 18:41:48 +01:00
Odweta 87470effcd improved the About screen and added version number 2024-11-29 18:33:36 +01:00
Odweta 079872dae2 locked the screen orientation in portrait mode 2024-11-29 10:25:28 +01:00
Odweta 26317052cc added prepending free subjects to timetable when the day does not start with subject number 1 2024-11-26 18:52:03 +01:00
Odweta ed981f89de added a refresh button to the timetable 2024-11-26 18:04:05 +01:00
Odweta fd788195c5 added icon and screenshots 2024-11-20 13:10:18 +01:00
Odweta ed1f67f3e6 signed the apk 2024-11-20 11:20:50 +01:00
64 changed files with 1406 additions and 503 deletions
+1
View File
@@ -13,3 +13,4 @@
.externalNativeBuild
.cxx
local.properties
mobile/app/build
+3 -1
View File
@@ -3,7 +3,9 @@
<component name="MaterialThemeProjectNewConfig">
<option name="metadata">
<MTProjectMetadataState>
<option name="userId" value="35ed75a3:192c279f3e0:-7ffa" />
<option name="migrated" value="true" />
<option name="pristineConfig" value="false" />
<option name="userId" value="-239e49af:192a4be9597:-7ffe" />
</MTProjectMetadataState>
</option>
</component>
+2 -2
View File
@@ -1,3 +1,3 @@
![solon-logo](./solon_logo.png)
![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.0.3.apk?ref_type=heads&inline=false) (verze 2.0.3)
# Odkaz na stažení aplikace pro Android [zde](https://gitlab.com/Odweta/solon/-/releases/2.2.2/downloads/app-release.apk) (verze 2.2.2)
Executable
+58
View File
@@ -0,0 +1,58 @@
#!/bin/bash
echo -n "version number: "
read ver
echo -n "glpat: "
read glpat
cd ./mobile
# build
./gradlew assembleRelease
# sign
~/Android/Sdk/build-tools/35.0.0/apksigner sign --alignment-preserved --ks ~/Documents/android-keystore.jks app/build/outputs/apk/release/com.odweta.solon_$ver.apk
# add, commit, push
git add ..
git commit -m "made new release $ver"
git push
# create the tag
echo "\n[creating tag v$ver]"
data_str='{ "tag_name": "'$ver'", "ref": "HEAD", "message": "Tagging release v'$ver'" }'
curl --request POST \
--header "PRIVATE-TOKEN: $glpat" \
--header "Content-Type: application/json" \
--data "$data_str" \
"https://gitlab.com/api/v4/projects/47146187/repository/tags"
# make a release
echo "\n[publishing release $ver]"
data_str='{ "name": "v'$ver'", "tag_name": "'$ver'", "ref": "HEAD" }'
curl --request POST \
--header "PRIVATE-TOKEN: $glpat" \
--header 'Content-Type: application/json' \
--data "$data_str" \
"https://gitlab.com/api/v4/projects/47146187/releases"
# attach a file
echo "\n[attaching the release apk]"
asset_url="https://gitlab.com/-/project/47146187"$(curl --request POST \
--header "PRIVATE-TOKEN: $glpat" \
--form "file=@app/build/outputs/apk/release/com.odweta.solon_$ver.apk" \
"https://gitlab.com/api/v4/projects/47146187/uploads" | jq .url -r)
# add the file as a stable release asset
echo "\n[creating release asset]"
curl --request POST \
--header "PRIVATE-TOKEN: $glpat" \
--data name="app-release.apk" \
--data url="$asset_url" \
--data filepath="/app-release.apk" \
--data "assets[links][][link_type]=package" \
"https://gitlab.com/api/v4/projects/47146187/releases/$ver/assets/links"
# cd back
cd -
Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

+12
View File
@@ -62,6 +62,18 @@
<PersistentState>
<option name="children">
<map>
<entry key="backgroundImage">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="imagePath" value="$PROJECT_DIR$/app/src/main/res/drawable/black.png" />
<entry key="scalingPercent" value="172" />
</map>
</option>
</PersistentState>
</value>
</entry>
<entry key="foregroundClipArt">
<value>
<PersistentState>
+12 -1
View File
@@ -14,6 +14,17 @@
<option name="screenX" value="720" />
<option name="screenY" value="1280" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="34" />
<option name="brand" value="OPPO" />
<option name="codename" value="OP573DL1" />
<option name="id" value="OP573DL1" />
<option name="manufacturer" value="OPPO" />
<option name="name" value="CPH2557" />
<option name="screenDensity" value="480" />
<option name="screenX" value="1080" />
<option name="screenY" value="2400" />
</PersistentDeviceSelectionData>
<PersistentDeviceSelectionData>
<option name="api" value="28" />
<option name="brand" value="DOCOMO" />
@@ -262,7 +273,7 @@
<option name="codename" value="q6q" />
<option name="id" value="q6q" />
<option name="manufacturer" value="Samsung" />
<option name="name" value="SM-F956B" />
<option name="name" value="Galaxy Z Fold6" />
<option name="screenDensity" value="420" />
<option name="screenX" value="1856" />
<option name="screenY" value="2160" />
+4 -4
View File
@@ -4,19 +4,19 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2024-10-20T07:27:51.115175643Z">
<DropdownSelection timestamp="2024-11-29T17:18:42.354545820Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/home/thinker/.android/avd/Motorola_Moto_e22_API_31.avd" />
<DeviceId pluginId="LocalEmulator" identifier="path=/home/thinker/.config/.android/avd/Medium_Phone_API_35.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
<SelectionState runConfigName="DefaultPreview">
<SelectionState runConfigName="TimetablePreview">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
<SelectionState runConfigName="Preview">
<SelectionState runConfigName="RBPreview">
<option name="selectionMode" value="DROPDOWN" />
</SelectionState>
</selectionStates>
-1
View File
@@ -2,6 +2,5 @@
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+3 -3
View File
@@ -12,8 +12,8 @@ android {
applicationId = "com.odweta.solon"
minSdk = 28
targetSdk = 34
versionCode = 203
versionName = "2.0.3"
versionCode = 207
versionName = "2.2.2"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -22,7 +22,7 @@ android {
this.outputs
.map { it as com.android.build.gradle.internal.api.ApkVariantOutputImpl }
.forEach { output ->
var apkName = "com.odweta.solon_" + this.versionName + ".apk"
val apkName = "com.odweta.solon_" + this.versionName + ".apk"
output.outputFileName = apkName
}
}
+3 -1
View File
@@ -18,10 +18,12 @@
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Solon"
android:windowSoftInputMode="adjustResize">
android:windowSoftInputMode="adjustResize"
tools:ignore="DiscouragedApi">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -2,6 +2,7 @@ package com.odweta.solon
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
@@ -9,6 +10,7 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -25,6 +27,7 @@ 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.platform.LocalUriHandler
import com.odweta.solon.ui.theme.PastelYellow
import androidx.compose.ui.res.painterResource
@@ -33,7 +36,6 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import java.time.format.TextStyle
@Composable
fun AboutScreen(modifier: Modifier = Modifier) {
@@ -51,6 +53,7 @@ fun AboutScreen(modifier: Modifier = Modifier) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(start = 5.dp)
) {
Button(
onClick = {
@@ -106,30 +109,71 @@ fun AboutScreen(modifier: Modifier = Modifier) {
.padding(10.dp)
)
Row(
modifier = Modifier
.padding(10.dp)
) {
val uriHandler = LocalUriHandler.current
HorizontalLine()
Text(
text = "Vývoj: ",
textAlign = TextAlign.Start,
color = Color.White,
fontSize = 30.sp
AboutTableRow(
"Vývoj",
"@Odweta",
"https://www.gitlab.com/Odweta/solon"
)
AboutTableRow(
"Verze aplikace",
Util.getAppVersion(LocalContext.current)?.versionName ?: "N/A"
)
}
}
}
@Composable
fun HorizontalLine(modifier: Modifier = Modifier) {
Spacer(modifier = Modifier.height(20.dp))
Spacer(modifier = Modifier
.height(2.dp)
.background(color = PastelYellow)
.fillMaxWidth(fraction = 0.8f)
)
Spacer(modifier = Modifier.height(20.dp))
}
@Composable
fun AboutTableRow(key: String, value: String, href: String = "") {
Row(
modifier = Modifier
.padding(10.dp)
.background(color = Color.Black, shape = RoundedCornerShape(roundedCornerDimen))
.fillMaxWidth()
) {
Text(
text = "@Odweta",
text = key,
textAlign = TextAlign.Start,
color = Color.White,
fontSize = 20.sp
)
Spacer(modifier = Modifier.weight(1f))
if (href != "") {
val uriHandler = LocalUriHandler.current
Text(
text = value,
color = PastelYellow,
fontSize = 30.sp,
fontSize = 20.sp,
textAlign = TextAlign.End,
textDecoration = TextDecoration.Underline,
modifier = Modifier.clickable {
uriHandler.openUri("https://www.gitlab.com/Odweta/solon")
uriHandler.openUri(href)
}
)
} else {
Text(
text = value,
color = Color.White,
fontSize = 20.sp,
textAlign = TextAlign.End
)
}
}
}
}
@@ -1,22 +1,19 @@
package com.odweta.solon
import android.view.Window
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import com.odweta.solon.ui.theme.PastelYellow
import com.odweta.solon.ui.theme.PastelYellowTransparent
import okhttp3.OkHttpClient
import java.io.File
@@ -44,6 +41,8 @@ const val accountDataFilePath: String = "account_data.txt"
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
@@ -59,7 +58,8 @@ enum class IsShowing {
Timetable,
Marks,
Menu,
About
About,
Settings
}
enum class Screen {
@@ -76,8 +76,56 @@ var isShowing: MutableState<IsShowing> = mutableStateOf(IsShowing.Timetable)
var toolbarText: MutableState<String> = mutableStateOf("")
// default settings (will get overwritten by the saved settings)
class Setting(auxId: SettingsId, auxName: String, auxChecked: Boolean) {
var id: SettingsId = auxId
var name: String = auxName
var checked: MutableState<Boolean> = mutableStateOf(auxChecked)
override fun toString() = "$id#$name#${checked.value}"
}
enum class SettingsId {
Svoboda,
Amoled,
RefreshButton,
TagNewMarks,
DeleteLocalData
}
class SettingsData {
var useSvobodaMode: Setting = Setting(
SettingsId.Svoboda,
"Používat Svoboda mód",
false
)
var useAmoledMode: Setting = Setting(
SettingsId.Amoled,
"Používat AMOLED mód",
false
)
var showRefreshButton: Setting = Setting(
SettingsId.RefreshButton,
"Zobrazovat tlačítko obnovení dat",
true
)
var tagNewMarks: Setting = Setting(
SettingsId.TagNewMarks,
"Označit nové známky",
true
)
override fun toString() = "$useSvobodaMode\n$useAmoledMode\n$showRefreshButton\n$tagNewMarks"
}
var settings : SettingsData = SettingsData()
var done: Boolean = false
var internetAwaitListenerRunning: Boolean = false
var timeTableAvailOffline: Boolean = false
var marksAvailOffline: Boolean = false
@@ -99,6 +147,50 @@ var resetNav: Boolean = false
var isAPISetUp: Boolean = false
enum class LectureNoteType {
Normal, // obycejna poznamka
Writing, // pisemny test
Speaking, // ustni zkouseni
Other // cokoliv jineho
}
fun String.toLectureNoteType(): LectureNoteType {
return when(this) {
"Normal" -> LectureNoteType.Normal
"Writing" -> LectureNoteType.Writing
"Speaking" -> LectureNoteType.Speaking
"Other" -> LectureNoteType.Other
else -> LectureNoteType.Normal
}
}
class LectureNote(
id: Int,
note: MutableState<String>,
type: MutableState<LectureNoteType>,
number: Int,
lectureName: String
) {
var id: Int = 0
var note: MutableState<String> =
mutableStateOf("")
var type: MutableState<LectureNoteType> =
mutableStateOf(LectureNoteType.Normal)
var number: Int = 0
var lectureName: String = ""
init {
this.id = id
this.note = note
this.type = type
this.number = number
this.lectureName = lectureName
}
}
var lectureNotes: HashMap<Int, LectureNote> = hashMapOf()
var selectedLecture: Int = 0
var selectedDay: Int = 0
var dayEndString: String = ""
@@ -1,15 +1,12 @@
package com.odweta.solon
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.compose.ui.graphics.Color
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
import org.json.JSONObject
import kotlin.math.cos
private var week: List<Day> = mutableListOf()
private var toastShowing: Boolean = false
@@ -19,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) {
@@ -37,7 +35,7 @@ private fun setOnInternetAvailListener(ctx: Context, coscope: CoroutineScope) {
}
}
private fun fetchNewData(ctx: Context, coscope: CoroutineScope) {
fun fetchNewData(ctx: Context, coscope: CoroutineScope) {
coscope.launch {
done = false
@@ -46,23 +44,19 @@ private fun fetchNewData(ctx: Context, coscope: CoroutineScope) {
"Načítání nových dat",
"Načítání nových dat.",
"Načítání nových dat..",
"Načítání nových dat..."
"Načítání nových dat...",
"Načítání nových dat..",
"Načítání nových dat."
)
val delayTime: Long = 300 // delay in ms
// show a loading animation
while (!done && Util.internetAvail(ctx)) {
for (text in loadingArray) {
if (done) break
toolbarText.value = text
delay(delayTime)
}
for (text in loadingArray.reversedArray().slice(1..<loadingArray.size)) {
toolbarText.value = text
delay(delayTime)
}
delay(delayTime)
}
// determine the role of the student
@@ -145,9 +139,11 @@ private suspend fun launchPhase1(ctx: Context) {
toast2.show()
}
if (!timeTableAvailOffline || internetAvail) {
if (!timeTableAvailOffline || !marksAvailOffline || internetAvail) {
// set up the API (required for later uses of it)
if (!isAPISetUp) {
Network.setupAPI()
}
if (internetAvail) {
// cancel a toast, if any
@@ -156,23 +152,31 @@ private suspend fun launchPhase1(ctx: Context) {
}
// get the JSON data
val timeTableJSON = Network.getTimeTableJSON()
// try to save them into a file for later use
timeTableAvailOffline =
Util.saveStringToFile(timeTableFilePath, timeTableJSON)
// parse the data
week = Parsing.parseTimeTableJSON(timeTableJSON)
var timeTableJSON = Network.getTimeTableJSON()
if (timeTableJSON == """{"error": "network"}""") {
timeTableJSON = Util.fileToString(timeTableFilePath)
}
// fetch and parse marks
marksJSON = Network.getMarksJSON()
if (marksJSON == """{"error": "network"}""") {
marksJSON = Util.fileToString(marksFilePath)
}
timeTableAvailOffline =
Util.saveStringToFile(timeTableFilePath, timeTableJSON)
marksAvailOffline =
Util.saveStringToFile(marksFilePath, marksJSON)
// parse the data
week = Parsing.parseTimeTableJSON(timeTableJSON)
marks = Parsing.parseMarksJSON(marksJSON)
// set the settings
if (Util.fileExists(settingsDataFilePath) && !Util.fileIsEmpty(settingsDataFilePath)) {
settings = Util.stringToSettingsData(Util.fileToString(settingsDataFilePath))
} // else load the default settings
// continue to launch phase 2
done = true
launchPhase2(ctx)
@@ -271,11 +275,15 @@ private fun launchPhase2(ctx: Context) {
dayList.add(day)
}
Util.loadLectureNotes()
loaded = true
coscope_.launch {
if (!internetAwaitListenerRunning) {
setOnInternetAvailListener(ctx, coscope_)
}
}
val role = if (Parsing.userIsParent()) {
" Rodič"
@@ -288,8 +296,13 @@ private fun launchPhase2(ctx: Context) {
Util.fileToString(
userDataFilePath
)
).getString("fullName")}$role"
).getString("fullName")
}$role"
// set the main content view
screenToShow.value = Screen.Main
if (settings.showRefreshButton.checked.value) {
refreshButtonContentColor.value = Color.White
}
}
@@ -69,6 +69,7 @@ class MainActivity : ComponentActivity() {
IsShowing.Marks -> MarksScreen()
IsShowing.Menu -> MenuScreen()
IsShowing.About -> AboutScreen()
IsShowing.Settings -> SettingsScreen()
}
}
@@ -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,
@@ -113,6 +116,64 @@ fun MarksAll() {
.verticalScroll(scrollState)
) {
for ((subject, markList) in marks) {
val amoledModifier = if (settings.useAmoledMode.checked.value) {
Modifier
.width(150.dp)
.fillMaxHeight()
.border(
width = borderWidthDimen,
color = getAvgColor(Util.avg(markList), true), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
} else {
Modifier
.width(150.dp)
.fillMaxHeight()
.background(
color = getAvgColor(Util.avg(markList)), // decide on the color (not transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
}
val amoledModifierBackground = if (settings.useAmoledMode.checked.value) {
Modifier
.fillMaxWidth()
.height(70.dp)
.border(
width = borderWidthDimen,
color = getAvgColor(Util.avg(markList), true), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
.clickable {
marksShow.value = MarksShow.Subject
subjectToShow = subject
}
} else {
Modifier
.fillMaxWidth()
.height(70.dp)
.background(
color = getAvgColor(Util.avg(markList)), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
.clickable {
marksShow.value = MarksShow.Subject
subjectToShow = subject
}
}
val amoledSpacerModifier = if (settings.useAmoledMode.checked.value) {
Modifier
.width(10.dp)
.fillMaxHeight()
.background(getAvgColor(Util.avg(markList)))
} else {
Modifier
.width(10.dp)
.fillMaxHeight()
.background(Color.Black)
}
var marksString = ""
for (m in 0 until markList.size-1) {
if (markList[m].grade in "0123456789") {
@@ -125,27 +186,21 @@ fun MarksAll() {
Box(modifier = Modifier.height(10.dp))
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(70.dp)
.background(
color = getAvgColor(Util.avg(markList)), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
.clickable {
marksShow.value = MarksShow.Subject
subjectToShow = subject
// 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
) {
Row(
modifier = Modifier
.width(150.dp)
.fillMaxHeight()
.background(
color = getAvgColor(Util.avg(markList)), // decide on the color (not transparent)
shape = RoundedCornerShape(roundedCornerDimen)
),
modifier = amoledModifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
@@ -160,14 +215,16 @@ fun MarksAll() {
)
Box(
modifier = Modifier
.width(10.dp)
.fillMaxHeight()
.background(Color.Black)
modifier = amoledSpacerModifier
)
val currAvg = Util.avg(markList).replace(".", ",")
var textToShow = currAvg
if (currAvg.length == 3 && currAvg[2] == '0') {
textToShow = currAvg[0].toString()
}
Text(
text = Util.avg(markList).replace(".", ","),
text = textToShow,
fontSize = 28.sp,
color = Color.White,
textAlign = TextAlign.Center,
@@ -176,10 +233,22 @@ fun MarksAll() {
)
}
Box(
modifier = Modifier.fillMaxSize().weight(1f),
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(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.fillMaxSize()
.padding(horizontal = 10.dp),
contentAlignment = Alignment.Center
) {
@@ -192,6 +261,7 @@ fun MarksAll() {
}
}
}
}
}
@Composable
@@ -251,16 +321,25 @@ fun MarksSubject() {
),
shape = RoundedCornerShape(roundedCornerDimen)
)
.background(
.background(color = if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
getAvgColor(
Util.avg(marks[subjectToShow]!!)
)
},
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 15.dp),
contentAlignment = Alignment.Center
) {
val currAvg = Util.avg(marks[subjectToShow]!!).replace(".", ",")
var textToShow = currAvg
if (currAvg.length == 3 && currAvg[2] == '0') {
textToShow = currAvg[0].toString()
}
Text(
text = Util.avg(marks[subjectToShow]!!).replace(".", ","),
text = textToShow,
color = Color.White,
textAlign = TextAlign.Center,
fontSize = 25.sp
@@ -270,7 +349,6 @@ fun MarksSubject() {
Spacer(modifier = Modifier.height(20.dp))
//Box(modifier = Modifier.height(100.dp)) {
Text(
text = subjectNameMap[subjectToShow]!!,
color = Color.White,
@@ -283,10 +361,15 @@ fun MarksSubject() {
color = PastelYellow,
shape = RoundedCornerShape(roundedCornerDimen)
)
.background(PastelYellowTransparent)
.padding(vertical = 20.dp)
.background(color = if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
PastelYellowTransparent
},
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 20.dp, horizontal = 10.dp)
) // subject
//}
Spacer(modifier = Modifier.height(20.dp))
@@ -296,12 +379,19 @@ fun MarksSubject() {
Spacer(modifier = Modifier.height(10.dp))
}
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.TopStart
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 5.dp)
.background(
color = getAvgColor(mark.grade),
.background(color = if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
getAvgColor(mark.grade)
},
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 10.dp)
@@ -336,6 +426,21 @@ fun MarksSubject() {
) // 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
)
}
}
}
}
}
@@ -371,7 +476,7 @@ fun MarksDetail() {
),
modifier = Modifier
.border(
width = 5.dp,
width = borderWidthDimen,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
@@ -392,17 +497,21 @@ fun MarksDetail() {
.width(70.dp)
.height(70.dp)
.border(
width = 5.dp,
width = borderWidthDimen,
color = getAvgColor(
Util.avg(marks[subjectToShow]!!),
Util.avg(mutableListOf(markToShow)),
true
),
shape = RoundedCornerShape(roundedCornerDimen)
)
.background(
if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
getAvgColor(
Util.avg(marks[subjectToShow]!!)
Util.avg(mutableListOf(markToShow))
)
}
)
.padding(vertical = 15.dp),
contentAlignment = Alignment.Center
@@ -419,7 +528,6 @@ fun MarksDetail() {
Spacer(modifier = Modifier.height(20.dp))
Row {
//Box(modifier = Modifier.height(70.dp)) {
Text(
text = markToShow.theme,
color = Color.White,
@@ -432,10 +540,14 @@ fun MarksDetail() {
color = PastelYellow,
shape = RoundedCornerShape(roundedCornerDimen)
)
.background(PastelYellowTransparent)
.background(if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
PastelYellowTransparent
}
)
.padding(vertical = 20.dp)
) // description
//}
} // description
Spacer(modifier = Modifier.height(20.dp))
@@ -445,7 +557,11 @@ fun MarksDetail() {
.fillMaxWidth()
.padding(horizontal = 5.dp)
.background(
color = PastelYellowTransparent,
color = if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
PastelYellowTransparent
},
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 20.dp, horizontal = 10.dp)
@@ -484,7 +600,11 @@ fun MarksDetail() {
.fillMaxWidth()
.padding(horizontal = 5.dp)
.background(
color = PastelYellowTransparent,
color = if (settings.useAmoledMode.checked.value) {
Color.Black
} else {
PastelYellowTransparent
},
shape = RoundedCornerShape(roundedCornerDimen)
)
.padding(vertical = 20.dp, horizontal = 10.dp)
@@ -36,29 +36,20 @@ fun MenuScreen(modifier: Modifier = Modifier) {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
// Button to trigger the dialog
Button(
onClick = { showDialog = true },
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(230.dp)
.height(80.dp)
) {
Text(
text = "Odhlásit se",
fontSize = 23.sp
)
}
MenuButton({ showDialog = true }, "Odhlásit se")
Spacer(modifier = Modifier.height(100.dp))
Spacer(modifier = Modifier.height(80.dp))
MenuButton({ screenToShow.value = Screen.SignIn }, "Změnit přihlášení")
Spacer(modifier = Modifier.height(80.dp))
MenuButton({ isShowing.value = IsShowing.About }, "O aplikaci")
Spacer(modifier = Modifier.height(80.dp))
MenuButton({ isShowing.value = IsShowing.Settings }, "Nastavení")
}
// Dialog implementation
if (showDialog) {
@@ -114,10 +105,12 @@ fun MenuScreen(modifier: Modifier = Modifier) {
}
)
}
}
Button(onClick = {
screenToShow.value = Screen.SignIn
},
@Composable
fun MenuButton(onClick: () -> Unit, text: String) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
@@ -132,33 +125,8 @@ fun MenuScreen(modifier: Modifier = Modifier) {
.height(80.dp)
) {
Text(
text = "Změnit přihlášení",
text = text,
fontSize = 23.sp
)
}
Spacer(modifier = Modifier.height(100.dp))
Button(onClick = {
isShowing.value = IsShowing.About
},
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(230.dp)
.height(80.dp)
) {
Text(
text = "O aplikaci",
fontSize = 23.sp
)
}
}
}
@@ -4,10 +4,12 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Menu
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.Schedule
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
@@ -15,24 +17,54 @@ import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
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.unit.dp
import com.odweta.solon.ui.theme.PastelYellow
import kotlinx.coroutines.CoroutineScope
private var timetableColor: MutableState<Color> = mutableStateOf(PastelYellow)
private var marksColor: MutableState<Color> = mutableStateOf(Color.White)
private var menuColor: MutableState<Color> = mutableStateOf(Color.White)
var refreshButtonContentColor: MutableState<Color> = mutableStateOf(Color.White)
@Composable
fun NavbarScreen(modifier: Modifier = Modifier) {
val ctx = LocalContext.current
val coscope = rememberCoroutineScope()
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
var spacerModifier = 30.dp
if (settings.showRefreshButton.checked.value) {
spacerModifier = 15.dp
Button(
onClick = {
fetchNewData(ctx, coscope)
refreshButtonContentColor.value = PastelYellow
},
colors = ButtonDefaults.buttonColors(
contentColor = refreshButtonContentColor.value,
containerColor = Color.Black
)
) {
Icon(
imageVector = Icons.Default.Refresh,
contentDescription = "Refresh Button",
modifier = Modifier.size(25.dp)
)
}
Spacer(modifier = Modifier.width(spacerModifier))
}
Button(
onClick = {
isShowing.value = IsShowing.Timetable
@@ -52,7 +84,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
)
}
Spacer(modifier = Modifier.width(30.dp))
Spacer(modifier = Modifier.width(spacerModifier))
Button(
onClick = {
@@ -74,7 +106,7 @@ fun NavbarScreen(modifier: Modifier = Modifier) {
)
}
Spacer(modifier = Modifier.width(30.dp))
Spacer(modifier = Modifier.width(spacerModifier))
Button(
onClick = {
@@ -58,10 +58,15 @@ class Network {
internetAvail = true
userData = getUserDataJSON()
Util.saveStringToFile(userDataFilePath, userData)
if (!Parsing.userIsParent()) {
studentClass = JSONObject(
studentClass = if (!Parsing.userIsParent()) {
JSONObject(
Util.fileToString(userDataFilePath)
).getJSONObject("class").get("name").toString()
} else {
// if the user is a parent, the class will be of their first child
JSONObject(
Util.fileToString(userDataFilePath)
).getJSONArray("children").getJSONObject(0).getString("className")
}
studentId = getStudentId()
//syid = getSYID()
@@ -269,6 +269,23 @@ class Parsing {
auxSubjects.add(Subject.empty())
}
// prepend free subjects when day does not start with subject number 1
val newSubjects: MutableList<Subject> = mutableListOf()
var n = auxSubjects[0].number.toInt()
while (n > 1) {
newSubjects.add(
Subject.freeSubject(
number = (n - 1).toString(),
start = "00:00",
end = "00:00"
)
)
n -= 1
}
val finalSubjects: MutableList<Subject> = mutableListOf()
finalSubjects.addAll(newSubjects.reversed())
finalSubjects.addAll(auxSubjects)
for ((i, s) in auxSubjects.withIndex()) {
if (s.free) {
s.start = auxSubjects[i-1].end
@@ -279,7 +296,7 @@ class Parsing {
val day = Day()
day.name = name
day.date = date
day.subjects = auxSubjects
day.subjects = finalSubjects
// get rid of duplicates
val nextSubjects: MutableList<Subject> = mutableListOf()
@@ -0,0 +1,149 @@
package com.odweta.solon
import androidx.activity.compose.BackHandler
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.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
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.shape.RoundedCornerShape
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.SwitchColors
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.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.odweta.solon.ui.theme.PastelYellow
@Composable
fun SettingsScreen(modifier: Modifier = Modifier) {
// handle the back gesture (back swipe form side or back button on bottom android navbar)
BackHandler {
isShowing.value = IsShowing.Menu
}
val scrollState = rememberScrollState()
Column(modifier = Modifier
.fillMaxSize()
.background(color = Color.Black)
.verticalScroll(scrollState)
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(start = 5.dp)
) {
Button(
onClick = {
isShowing.value = IsShowing.Menu
},
colors = ButtonDefaults.buttonColors(
contentColor = Color.White,
containerColor = Color.Black
),
modifier = Modifier
.border(
width = 5.dp,
shape = RoundedCornerShape(roundedCornerDimen),
color = PastelYellow
)
.width(70.dp)
.height(70.dp)
) {
Icon(
imageVector = Icons.Default.ArrowBackIosNew,
contentDescription = "Back icon",
modifier = Modifier.size(40.dp)
)
}
} // back button
Spacer(Modifier.height(10.dp))
SettingsTableRow(settings.useSvobodaMode)
Spacer(Modifier.height(10.dp))
SettingsTableRow(settings.useAmoledMode)
Spacer(Modifier.height(10.dp))
SettingsTableRow(settings.showRefreshButton)
Spacer(Modifier.height(10.dp))
SettingsTableRow(settings.tagNewMarks)
}
}
@Composable
fun SettingsTableRow(setting: Setting) {
Row(
modifier = Modifier
.padding(10.dp)
.background(color = Color.Black, shape = RoundedCornerShape(roundedCornerDimen))
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = setting.name,
textAlign = TextAlign.Start,
color = Color.White,
fontSize = 20.sp
)
Spacer(modifier = Modifier.weight(1f))
Switch(
checked = setting.checked.value,
onCheckedChange = {
setting.checked.value = it
when (setting.id) {
SettingsId.Svoboda -> settings.useSvobodaMode = setting
SettingsId.Amoled -> settings.useAmoledMode = setting
SettingsId.RefreshButton -> settings.showRefreshButton = setting
SettingsId.TagNewMarks -> settings.tagNewMarks = setting
else -> {}
}
Util.saveStringToFile(settingsDataFilePath, settings.toString())
},
colors = SwitchColors(
uncheckedThumbColor = Color.Black,
uncheckedTrackColor = Color.DarkGray,
uncheckedBorderColor = Color.DarkGray,
checkedThumbColor = Color.Black,
checkedTrackColor = PastelYellow,
checkedBorderColor = PastelYellow,
checkedIconColor = Color.White,
uncheckedIconColor = Color.White,
disabledCheckedThumbColor = Color.Black,
disabledCheckedTrackColor = Color.Black,
disabledCheckedBorderColor = Color.Black,
disabledCheckedIconColor = Color.Black,
disabledUncheckedThumbColor = Color.Black,
disabledUncheckedTrackColor = Color.Black,
disabledUncheckedBorderColor = Color.Black,
disabledUncheckedIconColor = Color.Black
)
)
}
}
@@ -39,12 +39,6 @@ import kotlinx.coroutines.launch
import androidx.compose.foundation.layout.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.ime
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.tooling.preview.Preview
private var buttonText: MutableState<String> = mutableStateOf("Přihlásit se")
@@ -101,6 +95,7 @@ fun signInButtonCallback(ctx: Context, coscope: CoroutineScope, buttonText: Stri
Account.save(acc)
signedInAndReadyToLaunch.value = true
screenToShow.value = Screen.Splash
fetchNewData(ctx, coscope)
} else {
Toast.makeText(
ctx,
@@ -1,37 +1,62 @@
package com.odweta.solon
import android.annotation.SuppressLint
import android.text.format.Time
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
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.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
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.AutoAwesome
import androidx.compose.material.icons.filled.EditNote
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusModifier
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.text.style.TextAlign
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.window.PopupProperties
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
@@ -39,15 +64,171 @@ import com.odweta.solon.ui.theme.PastelRedTransparent
import com.odweta.solon.ui.theme.PastelYellow
import com.odweta.solon.ui.theme.PastelYellowTransparent
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.format.DateTimeFormatter
@OptIn(ExperimentalFoundationApi::class)
var showDetailDialog = mutableStateOf(false)
@Composable
fun TimetableScreen() {
val pagerState = rememberPagerState( pageCount = { days.size } )
Box(
modifier = Modifier
.fillMaxSize(),
contentAlignment = Alignment.BottomCenter
) {
DayPager()
if (showDetailDialog.value) {
DetailDialog()
}
}
}
@SuppressLint("UnrememberedMutableState")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DetailDialog() {
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)
)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "" +
lectureNotes[selectedLecture]?.number.toString() +
" " +
lectureNotes[selectedLecture]?.lectureName.toString(),
color = Color.White,
textAlign = TextAlign.Left,
modifier = Modifier.padding(top = 10.dp)
)
///////////////////////////////////////////////////////////
var isExpanded by remember { mutableStateOf(false) }
Button(
modifier = Modifier.background(
color = Color.Black,
shape = RoundedCornerShape(roundedCornerDimen)
),
onClick = { isExpanded = true },
colors = ButtonColors(
containerColor = Color.Black,
contentColor = Color.White,
disabledContainerColor = Color.Black,
disabledContentColor = Color.White
)
) {
val type = when (lectureNotes[selectedLecture]?.type?.value) {
LectureNoteType.Normal -> "Normální"
LectureNoteType.Writing -> "Písemný test"
LectureNoteType.Speaking -> "Ústní zkoušení"
LectureNoteType.Other -> "Jiné"
else -> "Jiné"
}
Text("Typ poznámky: $type")
}
DropdownMenu(
modifier = Modifier.background(color = Color.Black),
onDismissRequest = { isExpanded = false },
expanded = isExpanded,
properties = PopupProperties(
excludeFromSystemGesture = false,
dismissOnClickOutside = true,
dismissOnBackPress = true,
focusable = true
),
) {
DropdownMenuItem(
enabled = true,
onClick = {
isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Normal
Util.saveLectureNotes()
},
text = { Text("Normální poznámka", color = Color.White) }
)
DropdownMenuItem(
enabled = true,
onClick = {
isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Writing
Util.saveLectureNotes()
},
text = { Text("Písemný test", color = Color.White) }
)
DropdownMenuItem(
enabled = true,
onClick = {
isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Speaking
Util.saveLectureNotes()
},
text = { Text("Ústní zkoušení", color = Color.White) }
)
DropdownMenuItem(
enabled = true,
onClick = {
isExpanded = false
lectureNotes[selectedLecture]?.type?.value = LectureNoteType.Other
Util.saveLectureNotes()
},
text = { Text("Jiné", color = Color.White) }
)
}
////////////////////////////////////////////////
TextField(
value = lectureNotes[selectedLecture]?.note?.value ?: "",
onValueChange = { newText: String ->
lectureNotes[selectedLecture]?.note?.value = newText
Util.saveLectureNotes()
},
singleLine = true,
placeholder = { Text("Sem můžete napsat poznámky k\u00A0této hodině.") }, // &nbsp;
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() {
val pagerState = rememberPagerState(pageCount = { days.size })
HorizontalPager(
state = pagerState,
modifier = Modifier.fillMaxSize()
@@ -109,17 +290,28 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
currentLectureNumber = lectureNumber
}
val m = Modifier
val m = if (settings.useAmoledMode.checked.value) {
Modifier
.fillMaxWidth()
.height(70.dp)
.border(
width = borderWidthDimen,
color = getSubjectColor(s, false), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
} else {
Modifier
.fillMaxWidth()
.height(70.dp)
.background(
color = getSubjectColor(s, true), // decide on the color (transparent)
shape = RoundedCornerShape(roundedCornerDimen)
)
}
return if (lectureNumber == currentLectureNumber && dateParsed == todayDate) {
m.border(
width = 5.dp,
width = borderWidthDimen,
color = getSubjectColor(s, false),
shape = RoundedCornerShape(roundedCornerDimen)
)
@@ -128,6 +320,7 @@ fun subjectModifier(d: Day, s: Subject, lectureNumber: Int): Modifier {
}
}
@SuppressLint("UnrememberedMutableState")
@Composable
private fun DayScreen(day: Day) {
val scrollState = rememberScrollState()
@@ -158,12 +351,43 @@ 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)
.fillMaxHeight()
.border(
width = borderWidthDimen,
color = getSubjectColor(
subject,
false
),
shape = RoundedCornerShape(roundedCornerDimen)
)
} else {
Modifier
.width(50.dp)
.fillMaxHeight()
.background(
color = getSubjectColor(
subject,
true
),
shape = RoundedCornerShape(roundedCornerDimen)
)
}
if (day.subjects.indexOf(subject) > 0) {
Box(modifier = Modifier.height(10.dp)) {
if (subject.name == day.subjects[day.subjects.indexOf(subject) - 1].name) {
val drawable =
if (subject.free) { R.drawable.squiggly_line_green }
else { R.drawable.squiggly_line_yellow }
Image(
painter = painterResource(R.drawable.squiggly_line_yellow),
painter = painterResource(drawable),
contentDescription = "Spojovač stejných předmětů",
modifier = Modifier.fillMaxSize()
)
@@ -171,21 +395,14 @@ private fun DayScreen(day: Day) {
}
}
Row(
modifier = subjectModifier(day, subject, subject.number.toInt())
Box (
modifier = subjectModifier(day, subject, subject.number.toInt()),
contentAlignment = Alignment.TopStart
) {
Row {
if (subject.substitute != "2") {
Box(
modifier = Modifier
.width(50.dp)
.fillMaxHeight()
.background(
color = getSubjectColor(
subject,
true
), // decide on the color (not transparent)
shape = RoundedCornerShape(roundedCornerDimen)
),
modifier = amoledModifier,
contentAlignment = Alignment.Center
) {
Text(
@@ -205,12 +422,31 @@ private fun DayScreen(day: Day) {
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
)
}
}
Text(
@@ -243,8 +479,7 @@ private fun DayScreen(day: Day) {
.padding(vertical = 5.dp),
contentAlignment = Alignment.Center
) {
// add this to the 'Svoboda' mode maybe later; for now, it is left out
/*if (!Parsing.userIsParent()) {
if (settings.useSvobodaMode.checked.value) {
if (
subject.teacher == "Jindřich Svoboda" &&
studentClass == "5. G"
@@ -255,22 +490,25 @@ private fun DayScreen(day: Day) {
modifier = Modifier.fillMaxSize()
)
}
}*/
}
}
if (subject.substitute != "2") {
Column(
modifier = Modifier
.fillMaxHeight()
.padding(end = 20.dp),
.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 (
@@ -286,6 +524,28 @@ private fun DayScreen(day: Day) {
}
}
}
Box(modifier = Modifier
.fillMaxSize()
.zIndex(99f)
.clickable {
selectedLecture = lectureId
showDetailDialog.value = true
})
if (
(lectureNotes[lectureId] != null && lectureNotes[lectureId]?.note?.value != "") ||
(lectureNotes[lectureId] != null && lectureNotes[lectureId]?.type?.value != LectureNoteType.Normal) &&
(lectureNotes[lectureId] != null && lectureNotes[lectureId]?.type?.value != LectureNoteType.Other)
) {
Icon(
modifier = Modifier.padding(start = 3.dp, top = 1.dp),
imageVector = Icons.Default.EditNote,
contentDescription = "Lecture has note",
tint = Color.White // You can customize the icon color
)
}
}
}
}
}
@@ -1,6 +1,8 @@
package com.odweta.solon
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+127 -29
View File
@@ -1,33 +1,19 @@
package com.odweta.solon
import android.animation.Animator
import android.animation.AnimatorInflater
import android.animation.AnimatorListenerAdapter
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.app.ActivityManager
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Handler
import android.os.Build
import android.util.DisplayMetrics
import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.widget.Button
import androidx.compose.ui.graphics.Color
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import com.odweta.solon.ui.theme.PastelGreenTransparent
import com.odweta.solon.ui.theme.PastelOrangeTransparent
import com.odweta.solon.ui.theme.PastelRedTransparent
import com.odweta.solon.ui.theme.PastelYellowTransparent
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
class Util {
companion object {
@@ -129,22 +115,20 @@ class Util {
}
}
fun isAppInForeground(context: Context, packageName: String): Boolean {
val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
/*fun isAppInForeground(context: Context, packageName: String): Boolean {
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
}
}
return false
}
fun pixelsToDp(pixels: Int, resources: Resources): Int {
return (pixels * resources.displayMetrics.density).toInt()
}
}*/
fun avg(marks: MutableList<Mark>): String {
var sum = 0f
@@ -166,7 +150,8 @@ class Util {
weights.add(mark.weight.toFloat())
}
return String.format("%.2f", (sum / sum(weights))).replace(',', '.')
return "${Math.round(sum / sum(weights) * 100f) / 100f}".replace(",", ".")
//return String.format("%.2f", (sum / sum(weights))).replace(',', '.')
}
private fun sum(nums: List<Float>): Float {
@@ -220,5 +205,118 @@ class Util {
return d
}*/
data class AppVersion(
val versionName: String,
val versionNumber: Long,
)
fun getAppVersion(
context: Context,
): AppVersion? {
return try {
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)
)
} else {
packageManager.getPackageInfo(packageName, 0)
}
AppVersion(
versionName = packageInfo.versionName.toString(),
versionNumber = PackageInfoCompat.getLongVersionCode(packageInfo),
)
} catch (e: Exception) {
null
}
}
fun stringToSettingsData(s: String): SettingsData {
val settings = s.split("\n")
val auxSettingsData = SettingsData()
val useSvobodaMode = settings[0].split("#")
val useAmoledMode = settings[1].split("#")
val showRefreshButton = settings[2].split("#")
auxSettingsData.useSvobodaMode.id = SettingsId.Svoboda
auxSettingsData.useSvobodaMode.name = useSvobodaMode[1]
auxSettingsData.useSvobodaMode.checked.value = useSvobodaMode[2].toBoolean()
auxSettingsData.useAmoledMode.id = SettingsId.Amoled
auxSettingsData.useAmoledMode.name = useAmoledMode[1]
auxSettingsData.useAmoledMode.checked.value = useAmoledMode[2].toBoolean()
auxSettingsData.showRefreshButton.id = SettingsId.RefreshButton
auxSettingsData.showRefreshButton.name = showRefreshButton[1]
auxSettingsData.showRefreshButton.checked.value = showRefreshButton[2].toBoolean()
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)
})
}
private fun csvToLectureNotes() {
val lines = fileToString(lectureNotesFilePath).lines()
for (line in lines) {
if (line.isBlank()) continue
val parts = line.split(",")
if (parts.size >= 3) {
val id = parts[0].trim().toInt()
val type = parts[1].trim().toLectureNoteType()
var note = parts[2].trim()
for (part in 3.until(parts.size)) {
note += ",${parts[part]}"
}
lectureNotes[id]?.note = mutableStateOf(note)
lectureNotes[id]?.type = mutableStateOf(type)
}
}
}
private fun lectureNotesToCsvString(hashMap: HashMap<Int, LectureNote>): String {
var result = ""
for ((key, lectureNote) in hashMap) {
result +=
"$key," +
"${lectureNote.type.value}," +
"${lectureNote.note.value}\n"
}
return result
}
fun loadLectureNotes() {
for (day in days) {
for ((subjectIndex, subject) in day.subjects.withIndex()) {
val id = getLectureId(day.date, subjectIndex)
lectureNotes[id] = LectureNote(
id = id,
type = mutableStateOf(LectureNoteType.Normal),
note = mutableStateOf(""),
number = subject.number.toInt(),
lectureName = subject.name
)
}
}
csvToLectureNotes()
}
fun saveLectureNotes() {
val toSave = lectureNotesToCsvString(lectureNotes)
saveStringToFile(lectureNotesFilePath, toSave)
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

@@ -1,53 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="108dp"
android:width="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<!-- Background Color -->
<path android:fillColor="#000000"
android:viewportWidth="108"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z"/>
<!-- Vertical Grid Lines -->
<path android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<path android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<path android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<!-- Repeat the lines for remaining grid -->
<!-- Horizontal Grid Lines -->
<path android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<path android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<path android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<!-- Repeat the lines for remaining grid -->
<!-- Additional Grid Lines within the Central Area -->
<path android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<path android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#000000"
android:strokeWidth="0.8"/>
<!-- Repeat similar paths for the remaining inner lines -->
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
</vector>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/launcher_background"/>
<background android:drawable="@mipmap/launcher_background"/>
<foreground android:drawable="@mipmap/launcher_foreground"/>
</adaptive-icon>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/launcher_background"/>
<background android:drawable="@mipmap/launcher_background"/>
<foreground android:drawable="@mipmap/launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 464 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

+1
View File
@@ -21,3 +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=~/Android/Sdk
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 15 KiB