spiced up the theme a bit (still needs work though), started to work on offline stuff, also fixed some bugs and done some polishing
@@ -37,18 +37,19 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation("androidx.core:core-ktx:1.10.1")
|
implementation("androidx.core:core-ktx:1.12.0")
|
||||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||||
implementation("com.google.android.material:material:1.9.0")
|
implementation("com.google.android.material:material:1.11.0")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.1")
|
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
|
||||||
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
|
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0")
|
||||||
implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
|
implementation("androidx.navigation:navigation-fragment-ktx:2.7.6")
|
||||||
implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
|
implementation("androidx.navigation:navigation-ui-ktx:2.7.6")
|
||||||
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.4.0")
|
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.7.0")
|
||||||
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
implementation("androidx.viewpager2:viewpager2:1.0.0")
|
implementation("androidx.viewpager2:viewpager2:1.0.0")
|
||||||
implementation("com.github.bumptech.glide:glide:4.16.0")
|
implementation("com.github.bumptech.glide:glide:4.16.0")
|
||||||
|
implementation("com.google.android.material:material:1.11.0")
|
||||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||||
testImplementation("junit:junit:4.13.2")
|
testImplementation("junit:junit:4.13.2")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.Solen.NoActionBar">
|
android:theme="@style/Theme.Solen">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.File
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
|
class Account(val username: String, val password: String, private val error: Int) {
|
||||||
|
companion object {
|
||||||
|
private fun parseAccountDataFile(file: File): Account {
|
||||||
|
val lines: List<String> = file.readLines()
|
||||||
|
|
||||||
|
if (lines.size >= 2) {
|
||||||
|
if (lines[0] != "" && lines[1] != "") {
|
||||||
|
return Account(lines[0], lines[1], 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Account("", "", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearAccountFile() {
|
||||||
|
val file = File(Vars.fileDir, Vars.accountDataFilePath)
|
||||||
|
file.delete()
|
||||||
|
file.createNewFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun haveSaved(): Boolean {
|
||||||
|
/* check if a file exists
|
||||||
|
* no -> create it and return false
|
||||||
|
* yes -> read the contents and use them as the username and password
|
||||||
|
*/
|
||||||
|
|
||||||
|
// check if file exists
|
||||||
|
val file = File(Vars.fileDir, Vars.accountDataFilePath)
|
||||||
|
|
||||||
|
return if (!file.exists()) {
|
||||||
|
// it does not exist
|
||||||
|
file.createNewFile()
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
// it exists, so it shall be parsed
|
||||||
|
val acc: Account = parseAccountDataFile(file)
|
||||||
|
Vars.username = acc.username
|
||||||
|
Vars.password = acc.password
|
||||||
|
acc.error == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun save(acc: Account): Boolean {
|
||||||
|
return try {
|
||||||
|
val file = File(Vars.fileDir, Vars.accountDataFilePath)
|
||||||
|
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
||||||
|
|
||||||
|
true
|
||||||
|
} catch (e: Exception) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun isValid(acc: Account): Boolean {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
Vars.username = acc.username
|
||||||
|
Vars.password = acc.password
|
||||||
|
|
||||||
|
val token = Network.getToken()
|
||||||
|
!JSONObject(token).has("error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import android.content.res.Resources
|
|||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
import android.graphics.drawable.GradientDrawable
|
import android.graphics.drawable.GradientDrawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -23,14 +24,7 @@ import androidx.lifecycle.Lifecycle
|
|||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
|
||||||
interface MainActivityListener {
|
|
||||||
fun onLaunch(view: View)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("INFERRED_TYPE_VARIABLE_INTO_EMPTY_INTERSECTION_WARNING")
|
|
||||||
class CalWeekFragment : Fragment() {
|
class CalWeekFragment : Fragment() {
|
||||||
//private var mainActivityListener: MainActivityListener? = null
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
@@ -41,12 +35,7 @@ class CalWeekFragment : Fragment() {
|
|||||||
val viewPager: ViewPager2 = view.findViewById(R.id.dayPager)
|
val viewPager: ViewPager2 = view.findViewById(R.id.dayPager)
|
||||||
val adapter = DayPagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)
|
val adapter = DayPagerAdapter(childFragmentManager, viewLifecycleOwner.lifecycle)
|
||||||
|
|
||||||
for (i in 0 until adapter.itemCount) {
|
for (i in 0 until Vars.days.size) {
|
||||||
childFragmentManager.beginTransaction().remove(requireActivity().findViewById(adapter.getItemId(i)
|
|
||||||
.toInt())).commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in 0 until MainActivity.days.size) {
|
|
||||||
adapter.addFragment(DayFragment(i))
|
adapter.addFragment(DayFragment(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +73,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
val view = inflater.inflate(R.layout.fragment_day, container, false)
|
val view = inflater.inflate(R.layout.fragment_day, container, false)
|
||||||
|
|
||||||
val dayLayout: LinearLayout = view.findViewById(R.id.layoutDayMain)
|
val dayLayout: LinearLayout = view.findViewById(R.id.layoutDayMain)
|
||||||
MainActivity.dayMap[position]?.let { createDayView(it, dayLayout, resources) }
|
Vars.dayMap[position]?.let { createDayView(it, dayLayout, resources) }
|
||||||
|
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
@@ -98,16 +87,34 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
val nameDateString = day.name + " " + day.date
|
val nameDateString = day.name + " " + day.date
|
||||||
nameDateTextView.text = nameDateString
|
nameDateTextView.text = nameDateString
|
||||||
nameDateTextView.textSize = 30f
|
nameDateTextView.textSize = 30f
|
||||||
nameDateTextView.setPadding(10, 10, 10, 40)
|
nameDateTextView.setTextColor(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
requireContext(),
|
||||||
|
R.color.white
|
||||||
|
)
|
||||||
|
)
|
||||||
|
nameDateTextView.setPadding(10, 40, 10, 40)
|
||||||
nameDateTextView.gravity = Gravity.CENTER_HORIZONTAL
|
nameDateTextView.gravity = Gravity.CENTER_HORIZONTAL
|
||||||
|
|
||||||
rootLayout.addView(nameDateTextView)
|
rootLayout.addView(nameDateTextView)
|
||||||
|
|
||||||
for (subj in day.subjects) {
|
for (subj in day.subjects) {
|
||||||
val subjectBackground = when (subj.substitute) {
|
val subjectBackground = when (subj.substitute) {
|
||||||
"0" -> if (subj.place != "Volno") { R.color.cal_week_subject } else { R.color.cal_week_free }
|
"0" -> if (subj.place != "Volno") {
|
||||||
"1" -> if (subj.place != "Volno") { R.color.cal_week_substitute } else { R.color.cal_week_free }
|
R.color.cal_week_subject
|
||||||
"2" -> if (subj.place != "Volno") { R.color.cal_week_event } else { R.color.cal_week_free }
|
} else {
|
||||||
|
R.color.cal_week_free
|
||||||
|
}
|
||||||
|
"1" -> if (subj.place != "Volno") {
|
||||||
|
R.color.cal_week_substitute
|
||||||
|
} else {
|
||||||
|
R.color.cal_week_free
|
||||||
|
}
|
||||||
|
"2" -> if (subj.place != "Volno") {
|
||||||
|
R.color.cal_week_event
|
||||||
|
} else {
|
||||||
|
R.color.cal_week_free
|
||||||
|
}
|
||||||
else -> R.color.cal_week_subject
|
else -> R.color.cal_week_subject
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +194,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if (subj.name == "Volno") {
|
if (subj.free) {
|
||||||
subjectNameTextView.setPadding(260, 35, 20, 35)
|
subjectNameTextView.setPadding(260, 35, 20, 35)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +202,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
|
|
||||||
val subjectPlaceTextView = TextView(requireContext())
|
val subjectPlaceTextView = TextView(requireContext())
|
||||||
subjectPlaceTextView.text = subj.place
|
subjectPlaceTextView.text = subj.place
|
||||||
if (subj.name == "Volno") {
|
if (subj.free) {
|
||||||
// underline
|
// underline
|
||||||
subjectPlaceTextView.setTypeface(null, Typeface.ITALIC)
|
subjectPlaceTextView.setTypeface(null, Typeface.ITALIC)
|
||||||
}
|
}
|
||||||
@@ -291,15 +298,6 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
// Remove the listener to avoid multiple callbacks
|
// Remove the listener to avoid multiple callbacks
|
||||||
rootLayout.viewTreeObserver.removeOnPreDrawListener(this)
|
rootLayout.viewTreeObserver.removeOnPreDrawListener(this)
|
||||||
|
|
||||||
if (dayLayout.height < rootLayout.height) {
|
|
||||||
val sepr = Space(requireContext())
|
|
||||||
sepr.layoutParams = LinearLayout.LayoutParams(
|
|
||||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
rootLayout.height - dayLayout.height
|
|
||||||
)
|
|
||||||
rootLayout.addView(sepr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call your function or perform an action here
|
// Call your function or perform an action here
|
||||||
if (day.subjects[0].substitute != "2") {
|
if (day.subjects[0].substitute != "2") {
|
||||||
subjectPlaceTextView.setPadding(
|
subjectPlaceTextView.setPadding(
|
||||||
@@ -315,15 +313,6 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
subjectNameTextView.gravity = Gravity.CENTER_VERTICAL
|
subjectNameTextView.gravity = Gravity.CENTER_VERTICAL
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for substitute hours and change the background
|
|
||||||
/*for (s in day.subjects) {
|
|
||||||
when (s.substitute) {
|
|
||||||
"1" -> subjectLayout.background = substituteDrawable
|
|
||||||
"2" -> subjectLayout.background = eventDrawable
|
|
||||||
else -> break
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// Return true to continue with the drawing, or false to cancel
|
// Return true to continue with the drawing, or false to cancel
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -387,17 +376,27 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
|
|||||||
scrollView.addView(dayLayout)
|
scrollView.addView(dayLayout)
|
||||||
|
|
||||||
rootLayout.addView(scrollView)
|
rootLayout.addView(scrollView)
|
||||||
|
|
||||||
|
// fill in the rest with empty space
|
||||||
|
val sepr = Space(requireContext())
|
||||||
|
sepr.layoutParams = LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
Vars.height - rootLayout.height
|
||||||
|
)
|
||||||
|
|
||||||
|
rootLayout.addView(sepr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Subject {
|
class Subject {
|
||||||
var name: String = ""
|
lateinit var name: String
|
||||||
var place: String = ""
|
lateinit var place: String
|
||||||
var teacher: String = ""
|
lateinit var teacher: String
|
||||||
var substitute: String = ""
|
lateinit var substitute: String
|
||||||
var number: String = ""
|
lateinit var number: String
|
||||||
var start: String = ""
|
lateinit var start: String
|
||||||
var end: String = ""
|
lateinit var end: String
|
||||||
|
var free: Boolean = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun freeSubject(number: String, start: String, end: String): Subject {
|
fun freeSubject(number: String, start: String, end: String): Subject {
|
||||||
@@ -410,6 +409,7 @@ class Subject {
|
|||||||
s.number = number
|
s.number = number
|
||||||
s.start = start
|
s.start = start
|
||||||
s.end = end
|
s.end = end
|
||||||
|
s.free = true
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import android.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
|
||||||
|
class Dialogs {
|
||||||
|
class SignOut(context: Context) : AlertDialog(context) {
|
||||||
|
init {
|
||||||
|
// Initialize your dialog properties
|
||||||
|
setTitle("Upozornění")
|
||||||
|
setMessage("Opravdu se chcete odhlásit? Tato akce vymaže uložené přihlašovací údaje a zavře aplikaci. Budete se poté muset znovu přihlásit.")
|
||||||
|
setCancelable(true) // Set whether the dialog can be canceled by tapping outside
|
||||||
|
|
||||||
|
// Set positive button (e.g., "OK" button)
|
||||||
|
setButton(
|
||||||
|
BUTTON_POSITIVE,
|
||||||
|
"Ano"
|
||||||
|
) { _, _ ->
|
||||||
|
Account.clearAccountFile()
|
||||||
|
MainActivity.quit(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set negative button (e.g., "Cancel" button)
|
||||||
|
setButton(
|
||||||
|
BUTTON_NEGATIVE,
|
||||||
|
"Ne"
|
||||||
|
) { _, _ ->
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LanguageChange(context: Context) : AlertDialog(context) {
|
||||||
|
init {
|
||||||
|
// Initialize your dialog properties
|
||||||
|
setTitle("Změnit jazyk")
|
||||||
|
setCancelable(true)
|
||||||
|
// Inflate the layout for the dialog
|
||||||
|
val view = LayoutInflater.from(context).inflate(R.layout.radio_group_language, null)
|
||||||
|
setView(view)
|
||||||
|
|
||||||
|
// Set positive button (e.g., "OK" button)
|
||||||
|
setButton(
|
||||||
|
BUTTON_POSITIVE,
|
||||||
|
"OK"
|
||||||
|
) { _, _ ->
|
||||||
|
// functionality here
|
||||||
|
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set negative button (e.g., "Cancel" button)
|
||||||
|
setButton(
|
||||||
|
BUTTON_NEGATIVE,
|
||||||
|
"Zrušit"
|
||||||
|
) { _, _ ->
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,70 +1,54 @@
|
|||||||
package com.odweta.solen
|
package com.odweta.solen
|
||||||
|
|
||||||
import android.R.attr.maxHeight
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.graphics.ImageDecoder
|
import android.graphics.ImageDecoder
|
||||||
import android.graphics.drawable.AnimatedImageDrawable
|
import android.graphics.drawable.AnimatedImageDrawable
|
||||||
|
import android.media.Image
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
|
||||||
import android.view.View.MeasureSpec
|
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.json.JSONException
|
|
||||||
import org.json.JSONObject
|
|
||||||
import java.io.File
|
|
||||||
import java.io.IOException
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
|
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
class MainActivity : AppCompatActivity(), MainActivityListener {
|
// @section COMPANION
|
||||||
companion object {
|
companion object {
|
||||||
val dayMap = mutableMapOf<Int, Day>()
|
fun quit(context: Context) {
|
||||||
var days = listOf<Day>()
|
// Create an Intent to launch the home screen
|
||||||
}
|
val homeIntent = Intent(Intent.ACTION_MAIN)
|
||||||
|
homeIntent.addCategory(Intent.CATEGORY_HOME)
|
||||||
|
homeIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
|
|
||||||
private val accountDataFilePath: String = "account_data.txt"
|
// Start the home screen activity
|
||||||
|
context.startActivity(homeIntent)
|
||||||
|
|
||||||
private val client = OkHttpClient()
|
// If the context is an Activity, finish it to close the current activity
|
||||||
|
if (context is AppCompatActivity) {
|
||||||
private lateinit var username: String
|
context.finish()
|
||||||
private lateinit var password: String
|
|
||||||
private val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api"
|
|
||||||
private val tokenUrl = "$apiBaseUrl/connect/token"
|
|
||||||
private lateinit var token: String
|
|
||||||
private val userDataUrl = "$apiBaseUrl/v1/user"
|
|
||||||
private lateinit var userData: String
|
|
||||||
private lateinit var studentId: String
|
|
||||||
private val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
|
||||||
//private val marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list"
|
|
||||||
|
|
||||||
private suspend fun setupAPI() {
|
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
token = JSONObject(getToken()).get("access_token").toString()
|
|
||||||
if (token == "") {
|
|
||||||
return@withContext
|
|
||||||
}
|
}
|
||||||
userData = getUserDataJSON()
|
|
||||||
studentId = getStudentId()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @section LISTENERS
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
showSplashScreen()
|
|
||||||
|
|
||||||
|
// set variables
|
||||||
|
Vars.fileDir = applicationContext.filesDir
|
||||||
|
Vars.width = Util.getDisplayWidth(this)
|
||||||
|
Vars.height = Util.getDisplayHeight(this)
|
||||||
|
|
||||||
|
// start the app (coroutine because splashscreen)
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
launch()
|
launch()
|
||||||
}
|
}
|
||||||
@@ -76,24 +60,6 @@ class MainActivity : AppCompatActivity(), MainActivityListener {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSignInScreen() {
|
|
||||||
setContentView(R.layout.activity_sign_in)
|
|
||||||
setSignInButtonOnClick()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showSettingsScreen() {
|
|
||||||
setContentView(R.layout.activity_settings)
|
|
||||||
findViewById<Button>(R.id.settingsBackButton).setOnClickListener {
|
|
||||||
launchPhase1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setSignInButtonOnClick() {
|
|
||||||
findViewById<Button>(R.id.signInButton).setOnClickListener {
|
|
||||||
onSignIn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override onOptionsItemSelected to handle menu item clicks
|
// Override onOptionsItemSelected to handle menu item clicks
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
@@ -103,17 +69,20 @@ class MainActivity : AppCompatActivity(), MainActivityListener {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.item_sign_in -> {
|
R.id.item_sign_in -> {
|
||||||
showSignInScreen()
|
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
|
||||||
|
SignInFragment().show(supportFragmentManager, "fragment_sign_in")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.item_settings -> {
|
R.id.item_settings -> {
|
||||||
showSettingsScreen()
|
showSettingsScreen()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.item_sign_out -> {
|
R.id.item_sign_out -> {
|
||||||
clearAccountFile()
|
Dialogs.SignOut(this).show()
|
||||||
showSignInScreen()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,26 +90,10 @@ class MainActivity : AppCompatActivity(), MainActivityListener {
|
|||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun clearAccountFile() {
|
|
||||||
val file = File(applicationContext.filesDir, accountDataFilePath)
|
|
||||||
file.delete()
|
|
||||||
file.createNewFile()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onLaunch(view: View) {
|
|
||||||
launch()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun accountIsValid(acc: Account): Boolean {
|
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
username = acc.username
|
|
||||||
password = acc.password
|
|
||||||
|
|
||||||
val token = getToken()
|
|
||||||
!JSONObject(token).has("error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// @section SIGN_IN
|
||||||
private fun onSignIn() {
|
private fun onSignIn() {
|
||||||
val acc = Account(
|
val acc = Account(
|
||||||
findViewById<EditText>(R.id.usernameField).text.toString(),
|
findViewById<EditText>(R.id.usernameField).text.toString(),
|
||||||
@@ -150,10 +103,10 @@ class MainActivity : AppCompatActivity(), MainActivityListener {
|
|||||||
|
|
||||||
showSplashScreen()
|
showSplashScreen()
|
||||||
|
|
||||||
saveAccount(acc)
|
Account.save(acc)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val valid = accountIsValid(acc)
|
val valid = Account.isValid(acc)
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
launch()
|
launch()
|
||||||
@@ -168,7 +121,97 @@ class MainActivity : AppCompatActivity(), MainActivityListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setSignInButtonOnClick() {
|
||||||
|
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
|
||||||
|
findViewById<Button>(R.id.signInButton).setOnClickListener {
|
||||||
|
onSignIn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// @section LAUNCH
|
||||||
|
private fun launch() {
|
||||||
|
// show the splash/loading screen
|
||||||
|
showSplashScreen()
|
||||||
|
|
||||||
|
// start
|
||||||
|
lifecycleScope.launch {
|
||||||
|
/* check if there is a saved user account
|
||||||
|
* if yes, use that
|
||||||
|
* otherwise show the login activity
|
||||||
|
*/
|
||||||
|
|
||||||
|
val accSaved: Boolean = Account.haveSaved()
|
||||||
|
|
||||||
|
if (!accSaved) {
|
||||||
|
// show the sign in screen
|
||||||
|
showSignInScreen()
|
||||||
|
} else {
|
||||||
|
// launch!
|
||||||
|
launchPhase1(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchPhase1(showSplash: Boolean) {
|
||||||
|
var week: List<Day>
|
||||||
|
|
||||||
|
if (showSplash) {
|
||||||
|
showSplashScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
Network.setupAPI()
|
||||||
|
|
||||||
|
if (Vars.token != "NETWORK_UNREACHABLE") {
|
||||||
|
week = Parsing.parseTimeTableJSON(Network.getTimeTableJSON())
|
||||||
|
launchPhase2(week)
|
||||||
|
} else {
|
||||||
|
// show some sort of warning message and/or load offline files
|
||||||
|
//week =
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchPhase2(week: List<Day>) {
|
||||||
|
Vars.days = week
|
||||||
|
for ((i, day) in week.withIndex()) {
|
||||||
|
Vars.dayMap[i] = day
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
|
val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
|
||||||
|
setSupportActionBar(toolbar)
|
||||||
|
toolbar.title = ""
|
||||||
|
toolbar.inflateMenu(R.menu.menu_main)
|
||||||
|
|
||||||
|
val mainFragment = CalWeekFragment()
|
||||||
|
supportFragmentManager.beginTransaction()
|
||||||
|
.replace(R.id.fragmentContainer, mainFragment)
|
||||||
|
.commit()
|
||||||
|
|
||||||
|
window.statusBarColor = ContextCompat.getColor(this, R.color.primary)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// @section SPLASH_SCREENS
|
||||||
|
private fun showSignInScreen() {
|
||||||
|
setContentView(R.layout.activity_sign_in)
|
||||||
|
setSignInButtonOnClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showSettingsScreen() {
|
||||||
|
window.statusBarColor = ContextCompat.getColor(this, R.color.primary)
|
||||||
|
val settingsFragment = SettingsFragment()
|
||||||
|
settingsFragment.show(supportFragmentManager, "Nastavení")
|
||||||
|
}
|
||||||
|
|
||||||
private fun showSplashScreen() {
|
private fun showSplashScreen() {
|
||||||
|
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
setContentView(R.layout.activity_splash_screen)
|
setContentView(R.layout.activity_splash_screen)
|
||||||
|
|
||||||
@@ -187,411 +230,4 @@ class MainActivity : AppCompatActivity(), MainActivityListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Account(val username: String, val password: String, val error: Int)
|
|
||||||
|
|
||||||
private fun parseAccountDataFile(file: File): Account {
|
|
||||||
val lines: List<String> = file.readLines()
|
|
||||||
|
|
||||||
if (lines.size >= 2) {
|
|
||||||
if (lines[0] != "" && lines[1] != "") {
|
|
||||||
return Account(lines[0], lines[1], 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Account("", "", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun haveSavedAccount(): Boolean {
|
|
||||||
/* check if a file exists
|
|
||||||
* no -> create it and return false
|
|
||||||
* yes -> read the contents and use them as the username and password
|
|
||||||
*/
|
|
||||||
|
|
||||||
// check if file exists
|
|
||||||
val file = File(applicationContext.filesDir, accountDataFilePath)
|
|
||||||
|
|
||||||
return if (!file.exists()) {
|
|
||||||
// it does not exist
|
|
||||||
file.createNewFile()
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
// it exists, so it shall be parsed
|
|
||||||
val acc: Account = parseAccountDataFile(file)
|
|
||||||
username = acc.username
|
|
||||||
password = acc.password
|
|
||||||
acc.error == 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveAccount(acc: Account): Boolean {
|
|
||||||
return try {
|
|
||||||
val file = File(applicationContext.filesDir, accountDataFilePath)
|
|
||||||
file.writeText("${acc.username}\n${acc.password}\n", Charset.forName("UTF-8"))
|
|
||||||
|
|
||||||
true
|
|
||||||
} catch (e: Exception) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launchPhase1() {
|
|
||||||
var week: List<Day>
|
|
||||||
showSplashScreen()
|
|
||||||
lifecycleScope.launch {
|
|
||||||
setupAPI()
|
|
||||||
week = parseJSON(getTimeTableJSON())
|
|
||||||
|
|
||||||
launchPhase2(week)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launchPhase2(week: List<Day>) {
|
|
||||||
days = week
|
|
||||||
for ((i, day) in week.withIndex()) {
|
|
||||||
dayMap[i] = day
|
|
||||||
}
|
|
||||||
|
|
||||||
setContentView(R.layout.activity_main)
|
|
||||||
|
|
||||||
val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
|
|
||||||
setSupportActionBar(toolbar)
|
|
||||||
toolbar.title = ""
|
|
||||||
toolbar.inflateMenu(R.menu.menu_main)
|
|
||||||
|
|
||||||
val mainFragment = CalWeekFragment()
|
|
||||||
supportFragmentManager.beginTransaction()
|
|
||||||
.replace(R.id.fragmentContainer, mainFragment)
|
|
||||||
.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launch() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
/* check if there is a saved user account
|
|
||||||
* if yes, use that
|
|
||||||
* otherwise show the login activity
|
|
||||||
*/
|
|
||||||
|
|
||||||
val accSaved: Boolean = haveSavedAccount()
|
|
||||||
|
|
||||||
if (!accSaved) {
|
|
||||||
// show the sign in screen
|
|
||||||
showSignInScreen()
|
|
||||||
} else {
|
|
||||||
// launch!
|
|
||||||
launchPhase1()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getToken(): String {
|
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val request = Request.Builder()
|
|
||||||
.url(tokenUrl)
|
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
.post(
|
|
||||||
FormBody.Builder()
|
|
||||||
.add("grant_type", "password")
|
|
||||||
.add("username", username)
|
|
||||||
.add("password", password)
|
|
||||||
.add("client_id", "test_client")
|
|
||||||
.add("scope", "openid offline_access profile sol_api")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
try {
|
|
||||||
val resp = client.newCall(request).execute()
|
|
||||||
val respString = resp.body?.string()
|
|
||||||
val respJson = respString?.let { JSONObject(it) }
|
|
||||||
respJson.toString()
|
|
||||||
} catch (e: JSONException) {
|
|
||||||
"""{"error": "json"}"""
|
|
||||||
} catch (e: Exception) {
|
|
||||||
//e.printStackTrace()
|
|
||||||
"""{"error": "network"}"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getStudentId(): String {
|
|
||||||
return if (!userIsParent()) {
|
|
||||||
JSONObject(userData).get("personID").toString()
|
|
||||||
} else {
|
|
||||||
JSONObject(userData).getJSONArray("children").getJSONObject(0).get("id").toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getUserDataJSON(): String {
|
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val request = Request.Builder()
|
|
||||||
.url(userDataUrl)
|
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
.header("Authorization", "Bearer $token") // using Bearer auth token
|
|
||||||
.get()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
try {
|
|
||||||
val resp = client.newCall(request).execute()
|
|
||||||
val respString = resp.body?.string().toString()
|
|
||||||
respString
|
|
||||||
} catch (e: IOException) {
|
|
||||||
"""{"error": "network"}"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun userIsParent(): Boolean {
|
|
||||||
return if (userData != "") JSONObject(userData).get("userType").toString() == "parent"
|
|
||||||
else false
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun getTimeTableJSON(): String {
|
|
||||||
return withContext(Dispatchers.IO) {
|
|
||||||
val userIsParent = userIsParent()
|
|
||||||
var url = timeTableUrl
|
|
||||||
if (userIsParent) {
|
|
||||||
url += "?studentId=$studentId"
|
|
||||||
}
|
|
||||||
|
|
||||||
val request = Request.Builder()
|
|
||||||
.url(url)
|
|
||||||
.header("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
.header("Authorization", "Bearer $token")
|
|
||||||
.get()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
try {
|
|
||||||
val resp = client.newCall(request).execute()
|
|
||||||
resp.body?.string().toString()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
"""{"error": "network"}"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseJSON(jsonString: String): List<Day> {
|
|
||||||
val jsonObject = JSONObject(jsonString)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* return a List that looks like this:
|
|
||||||
* [<name>, <date>, [<subj_name>, <subj_place>, <teacher>, <substitute>, <number>, <start_time>, <end_time>]]
|
|
||||||
* ["Po", "8.1.", ["D", "207", "Strakova S.", 0, 1, "08:00", "08:45" ]]
|
|
||||||
*/
|
|
||||||
|
|
||||||
val week = mutableListOf<Day>()
|
|
||||||
|
|
||||||
if (jsonObject.has("error")) {
|
|
||||||
return week
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access the "body" array from the main JSON object
|
|
||||||
val bodyArray = jsonObject.getJSONArray("days")
|
|
||||||
|
|
||||||
// Convert the JSON array to a list of JSON objects
|
|
||||||
val jsonObjectList = mutableListOf<JSONObject>()
|
|
||||||
for (i in 0 until bodyArray.length()) {
|
|
||||||
val nestedJsonObject = bodyArray.getJSONObject(i)
|
|
||||||
jsonObjectList.add(nestedJsonObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (obj in jsonObjectList) {
|
|
||||||
// for each day
|
|
||||||
val dateRAW = obj.get("date").toString()
|
|
||||||
var dayStr = dateRAW.split("T")[0].split("-")[2]
|
|
||||||
var monthStr = dateRAW.split("T")[0].split("-")[1]
|
|
||||||
|
|
||||||
if (dayStr[0] == '0') { dayStr = dayStr.slice(1..<dayStr.length) }
|
|
||||||
if (monthStr[0] == '0') { monthStr = monthStr.slice(1..<monthStr.length) }
|
|
||||||
|
|
||||||
val date = "$dayStr. $monthStr."
|
|
||||||
|
|
||||||
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
|
|
||||||
val localDateTime = LocalDateTime.parse(dateRAW, formatter)
|
|
||||||
|
|
||||||
val name = when (localDateTime.dayOfWeek.toString()) {
|
|
||||||
"MONDAY" -> "Pondělí"
|
|
||||||
"TUESDAY" -> "Úterý"
|
|
||||||
"WEDNESDAY" -> "Středa"
|
|
||||||
"THURSDAY" -> "Čtvrtek"
|
|
||||||
"FRIDAY" -> "Pátek"
|
|
||||||
"SATURDAY" -> "Sobota"
|
|
||||||
"SUNDAY" -> "Neděle"
|
|
||||||
else -> localDateTime.dayOfWeek.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
val subjects = mutableListOf<Subject>()
|
|
||||||
val auxSubjects = mutableListOf<Subject>()
|
|
||||||
|
|
||||||
val subjectJSONList = mutableListOf<JSONObject>()
|
|
||||||
val subjectArray = obj.getJSONArray("schedules")
|
|
||||||
for (i in 0 until subjectArray.length()) {
|
|
||||||
subjectJSONList.add(subjectArray.getJSONObject(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
for (subj in subjectJSONList) {
|
|
||||||
// for each subject in one particular day
|
|
||||||
val subject = Subject()
|
|
||||||
val kind = subj.getJSONObject("hourKind").get("id")
|
|
||||||
val type = subj.getJSONObject("hourType").get("id")
|
|
||||||
|
|
||||||
if (
|
|
||||||
(type == "SUPLOVANA") ||
|
|
||||||
(type != "SUPLOVANI" && type != "ROZVRH")
|
|
||||||
) {
|
|
||||||
when (kind) {
|
|
||||||
"ZRUSENI_VYUKY_ROZVRH" -> {
|
|
||||||
subject.name = subj.get("title").toString()
|
|
||||||
subject.place = ""
|
|
||||||
subject.teacher = ""
|
|
||||||
subject.substitute = "2" // 2 means school event
|
|
||||||
|
|
||||||
val hourspan = subj.getJSONArray("detailHours").length()
|
|
||||||
subject.number = "1 - $hourspan"
|
|
||||||
subject.start = subj.get("beginTime").toString()
|
|
||||||
subject.start = subject.start.slice(0..subject.start.length-4)
|
|
||||||
subject.end = subj.get("endTime").toString()
|
|
||||||
subject.end = subject.end.slice(0..subject.end.length-4)
|
|
||||||
|
|
||||||
subjects.add(subject)
|
|
||||||
}
|
|
||||||
"S_NAHRADOU_SKOL_AKCE" -> {
|
|
||||||
subject.name = subj.get("title").toString()
|
|
||||||
subject.place = ""
|
|
||||||
subject.teacher = ""
|
|
||||||
subject.substitute = "2" // 2 means school event
|
|
||||||
|
|
||||||
val hourspan = subj.getJSONArray("detailHours").length()
|
|
||||||
if (hourspan == 1) {
|
|
||||||
val detailHours = subj.getJSONArray("detailHours")
|
|
||||||
subject.number = detailHours.getJSONObject(0).get("id").toString()
|
|
||||||
subject.start = detailHours.getJSONObject(0).get("timeFrom").toString()
|
|
||||||
subject.start = subject.start.slice(0..subject.start.length - 4)
|
|
||||||
subject.end = detailHours.getJSONObject(0).get("timeto").toString()
|
|
||||||
subject.end = subject.end.slice(0..subject.end.length - 4)
|
|
||||||
subjects.add(subject)
|
|
||||||
} else {
|
|
||||||
for (i in 0..<hourspan) {
|
|
||||||
val newSubject = Subject()
|
|
||||||
newSubject.name = subject.name
|
|
||||||
newSubject.place = subject.place
|
|
||||||
newSubject.teacher = subject.teacher
|
|
||||||
newSubject.substitute = subject.substitute
|
|
||||||
|
|
||||||
val detailHours = subj.getJSONArray("detailHours")
|
|
||||||
newSubject.number = detailHours.getJSONObject(i).get("id").toString()
|
|
||||||
newSubject.start =
|
|
||||||
detailHours.getJSONObject(i).get("timeFrom").toString()
|
|
||||||
newSubject.start =
|
|
||||||
newSubject.start.slice(0..newSubject.start.length - 4)
|
|
||||||
newSubject.end = detailHours.getJSONObject(i).get("timeto").toString()
|
|
||||||
newSubject.end = newSubject.end.slice(0..newSubject.end.length - 4)
|
|
||||||
subjects.add(newSubject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
subject.name = subj.getJSONObject("subject").get("abbrev").toString()
|
|
||||||
subject.place =
|
|
||||||
subj.getJSONArray("rooms").getJSONObject(0).get("abbrev").toString()
|
|
||||||
subject.teacher = "" +
|
|
||||||
"${subj.getJSONArray("teachers").getJSONObject(0).get("name")} " +
|
|
||||||
"${subj.getJSONArray("teachers").getJSONObject(0).get("surname")}"
|
|
||||||
if (type == "ROZVRH") {
|
|
||||||
subject.substitute = "0"
|
|
||||||
} else if (type == "SUPLOVANI") {
|
|
||||||
subject.substitute = "1"
|
|
||||||
}
|
|
||||||
val hourspan = subj.getJSONArray("detailHours").length()
|
|
||||||
if (hourspan == 1) {
|
|
||||||
val detailHours = subj.getJSONArray("detailHours")
|
|
||||||
subject.number = detailHours.getJSONObject(0).get("id").toString()
|
|
||||||
subject.start = detailHours.getJSONObject(0).get("timeFrom").toString()
|
|
||||||
subject.start = subject.start.slice(0..subject.start.length - 4)
|
|
||||||
subject.end = detailHours.getJSONObject(0).get("timeto").toString()
|
|
||||||
subject.end = subject.end.slice(0..subject.end.length - 4)
|
|
||||||
subjects.add(subject)
|
|
||||||
} else {
|
|
||||||
for (i in 0..<hourspan) {
|
|
||||||
val newSubject = Subject()
|
|
||||||
newSubject.name = subject.name
|
|
||||||
newSubject.place = subject.place
|
|
||||||
newSubject.teacher = subject.teacher
|
|
||||||
newSubject.substitute = subject.substitute
|
|
||||||
|
|
||||||
val detailHours = subj.getJSONArray("detailHours")
|
|
||||||
newSubject.number = detailHours.getJSONObject(i).get("id").toString()
|
|
||||||
newSubject.start =
|
|
||||||
detailHours.getJSONObject(i).get("timeFrom").toString()
|
|
||||||
newSubject.start =
|
|
||||||
newSubject.start.slice(0..newSubject.start.length - 4)
|
|
||||||
newSubject.end = detailHours.getJSONObject(i).get("timeto").toString()
|
|
||||||
newSubject.end = newSubject.end.slice(0..newSubject.end.length - 4)
|
|
||||||
subjects.add(newSubject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
// rust pseudocode
|
|
||||||
|
|
||||||
let mut res: Vec<i32> = vec![];
|
|
||||||
for i in 0..v.len()-1 {
|
|
||||||
if v[i] == v[i+1]-1 {
|
|
||||||
res.push(v[i]);
|
|
||||||
} else {
|
|
||||||
res.push(v[i]);
|
|
||||||
|
|
||||||
while res[res.len()-1]+1 != v[i+1] {
|
|
||||||
res.push(res[res.len()-1]+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.push(v[v.len()-1]);
|
|
||||||
|
|
||||||
res
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (subjects.size > 1) {
|
|
||||||
for (i in 0..<subjects.size-1) {
|
|
||||||
if (subjects[i].number == ((subjects[i + 1].number.toInt() - 1).toString())) {
|
|
||||||
auxSubjects.add(subjects[i])
|
|
||||||
} else {
|
|
||||||
auxSubjects.add(subjects[i])
|
|
||||||
|
|
||||||
while ((auxSubjects[auxSubjects.size - 1].number.toInt() + 1).toString() != subjects[i + 1].number) {
|
|
||||||
auxSubjects.add(
|
|
||||||
Subject.freeSubject(
|
|
||||||
(auxSubjects[auxSubjects.size - 1].number.toInt() + 1).toString(),
|
|
||||||
"",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auxSubjects.add(subjects[subjects.size - 1])
|
|
||||||
} else {
|
|
||||||
auxSubjects.add(subjects[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
for ((i, s) in auxSubjects.withIndex()) {
|
|
||||||
if (s.place == "Volno") {
|
|
||||||
s.start = auxSubjects[i-1].end
|
|
||||||
s.end = auxSubjects[i+1].start
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val day = Day()
|
|
||||||
day.name = name
|
|
||||||
day.date = date
|
|
||||||
day.subjects = auxSubjects
|
|
||||||
|
|
||||||
week.add(day)
|
|
||||||
}
|
|
||||||
|
|
||||||
return week
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import okhttp3.Request
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class Network {
|
||||||
|
companion object {
|
||||||
|
suspend fun getToken(): String {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(Vars.tokenUrl)
|
||||||
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.post(
|
||||||
|
FormBody.Builder()
|
||||||
|
.add("grant_type", "password")
|
||||||
|
.add("username", Vars.username)
|
||||||
|
.add("password", Vars.password)
|
||||||
|
.add("client_id", "test_client")
|
||||||
|
.add("scope", "openid offline_access profile sol_api")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
try {
|
||||||
|
val resp = Vars.client.newCall(request).execute()
|
||||||
|
val respString = resp.body?.string()
|
||||||
|
val respJson = respString?.let { JSONObject(it) }
|
||||||
|
respJson.toString()
|
||||||
|
} catch (e: JSONException) {
|
||||||
|
"""{"error": "json"}"""
|
||||||
|
} catch (e: Exception) {
|
||||||
|
//e.printStackTrace()
|
||||||
|
"""{"error": "network"}"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun setupAPI() {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val token = getToken()
|
||||||
|
Vars.token = "NETWORK_UNREACHABLE"
|
||||||
|
if (!JSONObject(token).has("error")) {
|
||||||
|
Vars.token = JSONObject(token).get("access_token").toString()
|
||||||
|
}
|
||||||
|
if (Vars.token == "NETWORK_UNREACHABLE") {
|
||||||
|
Vars.userData = ""
|
||||||
|
Vars.studentId = ""
|
||||||
|
return@withContext
|
||||||
|
}
|
||||||
|
Vars.userData = getUserDataJSON()
|
||||||
|
Vars.studentId = getStudentId()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getStudentId(): String {
|
||||||
|
return if (!Parsing.userIsParent()) {
|
||||||
|
JSONObject(Vars.userData).get("personID").toString()
|
||||||
|
} else {
|
||||||
|
JSONObject(Vars.userData).getJSONArray("children").getJSONObject(0).get("id").toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getUserDataJSON(): String {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(Vars.userDataUrl)
|
||||||
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.header("Authorization", "Bearer ${Vars.token}") // using Bearer auth token
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
try {
|
||||||
|
val resp = Vars.client.newCall(request).execute()
|
||||||
|
val respString = resp.body?.string().toString()
|
||||||
|
respString
|
||||||
|
} catch (e: IOException) {
|
||||||
|
"""{"error": "network"}"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getTimeTableJSON(): String {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val userIsParent = Parsing.userIsParent()
|
||||||
|
var url = Vars.timeTableUrl
|
||||||
|
if (userIsParent) {
|
||||||
|
url += "?studentId=${Vars.studentId}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
.header("Authorization", "Bearer ${Vars.token}")
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
try {
|
||||||
|
val resp = Vars.client.newCall(request).execute()
|
||||||
|
resp.body?.string().toString()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
"""{"error": "network"}"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
class Parsing {
|
||||||
|
companion object {
|
||||||
|
fun userIsParent(): Boolean {
|
||||||
|
return if (Vars.userData != "") JSONObject(Vars.userData).get("userType")
|
||||||
|
.toString() == "parent"
|
||||||
|
else false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseTimeTableJSON(jsonString: String): List<Day> {
|
||||||
|
val jsonObject = JSONObject(jsonString)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return a List that looks like this:
|
||||||
|
* [<name>, <date>, [<subj_name>, <subj_place>, <teacher>, <substitute>, <number>, <start_time>, <end_time>]]
|
||||||
|
* ["Po", "8.1.", ["D", "207", "Strakova S.", 0, 1, "08:00", "08:45" ]]
|
||||||
|
*/
|
||||||
|
|
||||||
|
val week = mutableListOf<Day>()
|
||||||
|
|
||||||
|
if (jsonObject.has("error")) {
|
||||||
|
return week
|
||||||
|
}
|
||||||
|
|
||||||
|
// Access the "body" array from the main JSON object
|
||||||
|
val bodyArray = jsonObject.getJSONArray("days")
|
||||||
|
|
||||||
|
// Convert the JSON array to a list of JSON objects
|
||||||
|
val jsonObjectList = mutableListOf<JSONObject>()
|
||||||
|
for (i in 0 until bodyArray.length()) {
|
||||||
|
val nestedJsonObject = bodyArray.getJSONObject(i)
|
||||||
|
jsonObjectList.add(nestedJsonObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (obj in jsonObjectList) {
|
||||||
|
// for each day
|
||||||
|
val dateRAW = obj.get("date").toString()
|
||||||
|
var dayStr = dateRAW.split("T")[0].split("-")[2]
|
||||||
|
var monthStr = dateRAW.split("T")[0].split("-")[1]
|
||||||
|
|
||||||
|
if (dayStr[0] == '0') { dayStr = dayStr.slice(1..<dayStr.length) }
|
||||||
|
if (monthStr[0] == '0') { monthStr = monthStr.slice(1..<monthStr.length) }
|
||||||
|
|
||||||
|
val date = "$dayStr. $monthStr."
|
||||||
|
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
|
||||||
|
val localDateTime = LocalDateTime.parse(dateRAW, formatter)
|
||||||
|
|
||||||
|
val name = when (localDateTime.dayOfWeek.toString()) {
|
||||||
|
"MONDAY" -> "Pondělí"
|
||||||
|
"TUESDAY" -> "Úterý"
|
||||||
|
"WEDNESDAY" -> "Středa"
|
||||||
|
"THURSDAY" -> "Čtvrtek"
|
||||||
|
"FRIDAY" -> "Pátek"
|
||||||
|
"SATURDAY" -> "Sobota"
|
||||||
|
"SUNDAY" -> "Neděle"
|
||||||
|
else -> localDateTime.dayOfWeek.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
val subjects = mutableListOf<Subject>()
|
||||||
|
val auxSubjects = mutableListOf<Subject>()
|
||||||
|
|
||||||
|
val subjectJSONList = mutableListOf<JSONObject>()
|
||||||
|
val subjectArray = obj.getJSONArray("schedules")
|
||||||
|
for (i in 0 until subjectArray.length()) {
|
||||||
|
subjectJSONList.add(subjectArray.getJSONObject(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (subj in subjectJSONList) {
|
||||||
|
// for each subject in one particular day
|
||||||
|
val subject = Subject()
|
||||||
|
val kind = subj.getJSONObject("hourKind").get("id")
|
||||||
|
val type = subj.getJSONObject("hourType").get("id")
|
||||||
|
|
||||||
|
if (
|
||||||
|
(type == "SUPLOVANA") ||
|
||||||
|
(type != "SUPLOVANI" && type != "ROZVRH")
|
||||||
|
) {
|
||||||
|
when (kind) {
|
||||||
|
"ZRUSENI_VYUKY_ROZVRH" -> {
|
||||||
|
subject.name = subj.get("title").toString()
|
||||||
|
subject.place = ""
|
||||||
|
subject.teacher = ""
|
||||||
|
subject.substitute = "2" // 2 means school event
|
||||||
|
|
||||||
|
val hourspan = subj.getJSONArray("detailHours").length()
|
||||||
|
subject.number = "1 - $hourspan"
|
||||||
|
subject.start = subj.get("beginTime").toString()
|
||||||
|
subject.start = subject.start.slice(0..subject.start.length-4)
|
||||||
|
subject.end = subj.get("endTime").toString()
|
||||||
|
subject.end = subject.end.slice(0..subject.end.length-4)
|
||||||
|
|
||||||
|
subjects.add(subject)
|
||||||
|
}
|
||||||
|
"S_NAHRADOU_SKOL_AKCE" -> {
|
||||||
|
subject.name = subj.get("title").toString()
|
||||||
|
subject.place = ""
|
||||||
|
subject.teacher = ""
|
||||||
|
subject.substitute = "2" // 2 means school event
|
||||||
|
|
||||||
|
val hourspan = subj.getJSONArray("detailHours").length()
|
||||||
|
if (hourspan == 1) {
|
||||||
|
val detailHours = subj.getJSONArray("detailHours")
|
||||||
|
subject.number = detailHours.getJSONObject(0).get("id").toString()
|
||||||
|
subject.start = detailHours.getJSONObject(0).get("timeFrom").toString()
|
||||||
|
subject.start = subject.start.slice(0..subject.start.length - 4)
|
||||||
|
subject.end = detailHours.getJSONObject(0).get("timeto").toString()
|
||||||
|
subject.end = subject.end.slice(0..subject.end.length - 4)
|
||||||
|
subjects.add(subject)
|
||||||
|
} else {
|
||||||
|
for (i in 0..<hourspan) {
|
||||||
|
val newSubject = Subject()
|
||||||
|
newSubject.name = subject.name
|
||||||
|
newSubject.place = subject.place
|
||||||
|
newSubject.teacher = subject.teacher
|
||||||
|
newSubject.substitute = subject.substitute
|
||||||
|
|
||||||
|
val detailHours = subj.getJSONArray("detailHours")
|
||||||
|
newSubject.number = detailHours.getJSONObject(i).get("id").toString()
|
||||||
|
newSubject.start =
|
||||||
|
detailHours.getJSONObject(i).get("timeFrom").toString()
|
||||||
|
newSubject.start =
|
||||||
|
newSubject.start.slice(0..newSubject.start.length - 4)
|
||||||
|
newSubject.end = detailHours.getJSONObject(i).get("timeto").toString()
|
||||||
|
newSubject.end = newSubject.end.slice(0..newSubject.end.length - 4)
|
||||||
|
subjects.add(newSubject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
subject.name = subj.getJSONObject("subject").get("abbrev").toString()
|
||||||
|
subject.place =
|
||||||
|
subj.getJSONArray("rooms").getJSONObject(0).get("abbrev").toString()
|
||||||
|
subject.teacher = "" +
|
||||||
|
"${subj.getJSONArray("teachers").getJSONObject(0).get("name")} " +
|
||||||
|
"${subj.getJSONArray("teachers").getJSONObject(0).get("surname")}"
|
||||||
|
if (type == "ROZVRH") {
|
||||||
|
subject.substitute = "0"
|
||||||
|
} else if (type == "SUPLOVANI") {
|
||||||
|
subject.substitute = "1"
|
||||||
|
}
|
||||||
|
val hourspan = subj.getJSONArray("detailHours").length()
|
||||||
|
if (hourspan == 1) {
|
||||||
|
val detailHours = subj.getJSONArray("detailHours")
|
||||||
|
subject.number = detailHours.getJSONObject(0).get("id").toString()
|
||||||
|
subject.start = detailHours.getJSONObject(0).get("timeFrom").toString()
|
||||||
|
subject.start = subject.start.slice(0..subject.start.length - 4)
|
||||||
|
subject.end = detailHours.getJSONObject(0).get("timeto").toString()
|
||||||
|
subject.end = subject.end.slice(0..subject.end.length - 4)
|
||||||
|
subjects.add(subject)
|
||||||
|
} else {
|
||||||
|
for (i in 0..<hourspan) {
|
||||||
|
val newSubject = Subject()
|
||||||
|
newSubject.name = subject.name
|
||||||
|
newSubject.place = subject.place
|
||||||
|
newSubject.teacher = subject.teacher
|
||||||
|
newSubject.substitute = subject.substitute
|
||||||
|
|
||||||
|
val detailHours = subj.getJSONArray("detailHours")
|
||||||
|
newSubject.number = detailHours.getJSONObject(i).get("id").toString()
|
||||||
|
newSubject.start =
|
||||||
|
detailHours.getJSONObject(i).get("timeFrom").toString()
|
||||||
|
newSubject.start =
|
||||||
|
newSubject.start.slice(0..newSubject.start.length - 4)
|
||||||
|
newSubject.end = detailHours.getJSONObject(i).get("timeto").toString()
|
||||||
|
newSubject.end = newSubject.end.slice(0..newSubject.end.length - 4)
|
||||||
|
subjects.add(newSubject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// rust pseudocode
|
||||||
|
|
||||||
|
let mut res: Vec<i32> = vec![];
|
||||||
|
for i in 0..v.len()-1 {
|
||||||
|
if v[i] == v[i+1]-1 {
|
||||||
|
res.push(v[i]);
|
||||||
|
} else {
|
||||||
|
res.push(v[i]);
|
||||||
|
|
||||||
|
while res[res.len()-1]+1 != v[i+1] {
|
||||||
|
res.push(res[res.len()-1]+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push(v[v.len()-1]);
|
||||||
|
|
||||||
|
res
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (subjects.size > 1) {
|
||||||
|
for (i in 0..<subjects.size-1) {
|
||||||
|
if (subjects[i].number == ((subjects[i + 1].number.toInt() - 1).toString())) {
|
||||||
|
auxSubjects.add(subjects[i])
|
||||||
|
} else {
|
||||||
|
auxSubjects.add(subjects[i])
|
||||||
|
|
||||||
|
while ((auxSubjects[auxSubjects.size - 1].number.toInt() + 1).toString() != subjects[i + 1].number) {
|
||||||
|
auxSubjects.add(
|
||||||
|
Subject.freeSubject(
|
||||||
|
(auxSubjects[auxSubjects.size - 1].number.toInt() + 1).toString(),
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auxSubjects.add(subjects[subjects.size - 1])
|
||||||
|
} else {
|
||||||
|
auxSubjects.add(subjects[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((i, s) in auxSubjects.withIndex()) {
|
||||||
|
if (s.free) {
|
||||||
|
s.start = auxSubjects[i-1].end
|
||||||
|
s.end = auxSubjects[i+1].start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val day = Day()
|
||||||
|
day.name = name
|
||||||
|
day.date = date
|
||||||
|
day.subjects = auxSubjects
|
||||||
|
|
||||||
|
week.add(day)
|
||||||
|
}
|
||||||
|
|
||||||
|
return week
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.Window
|
||||||
|
import android.widget.Button
|
||||||
|
import android.widget.ImageView
|
||||||
|
|
||||||
|
class SettingsFragment : DialogFragment() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar_Fullscreen)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
val view = inflater.inflate(R.layout.activity_settings, container, false)
|
||||||
|
|
||||||
|
// Example: Dismiss the fragment when the back button is clicked
|
||||||
|
view.findViewById<ImageView>(R.id.settingsBackButton).setOnClickListener {
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
// toolbar
|
||||||
|
//val toolbar = view.findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
|
||||||
|
//setSupportActionBar(toolbar)
|
||||||
|
//toolbar.title = ""
|
||||||
|
//toolbar.inflateMenu(R.menu.menu_main)
|
||||||
|
|
||||||
|
val button: Button = view.findViewById(R.id.setting_language_button_choice) // replace with your button ID
|
||||||
|
button.setOnClickListener {
|
||||||
|
Dialogs.LanguageChange(requireContext()).show()
|
||||||
|
}
|
||||||
|
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val dialog = super.onCreateDialog(savedInstanceState)
|
||||||
|
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.view.Window
|
||||||
|
|
||||||
|
class SignInFragment : DialogFragment() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setStyle(STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return inflater.inflate(R.layout.activity_sign_in, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val dialog = super.onCreateDialog(savedInstanceState)
|
||||||
|
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
|
||||||
|
dialog.setCancelable(true)
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.DisplayMetrics
|
||||||
|
import android.view.WindowManager
|
||||||
|
|
||||||
|
class Util {
|
||||||
|
companion object {
|
||||||
|
fun getDisplayHeight(context: Context): Int {
|
||||||
|
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||||
|
val displayMetrics = DisplayMetrics()
|
||||||
|
|
||||||
|
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
|
||||||
|
return displayMetrics.heightPixels
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDisplayWidth(context: Context): Int {
|
||||||
|
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
|
||||||
|
val displayMetrics = DisplayMetrics()
|
||||||
|
|
||||||
|
windowManager.defaultDisplay.getMetrics(displayMetrics)
|
||||||
|
|
||||||
|
return displayMetrics.widthPixels
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.odweta.solen
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Vars {
|
||||||
|
companion object {
|
||||||
|
const val accountDataFilePath: String = "account_data.txt"
|
||||||
|
lateinit var fileDir: File
|
||||||
|
var width: Int = 0
|
||||||
|
var height: Int = 0
|
||||||
|
|
||||||
|
val dayMap = mutableMapOf<Int, Day>()
|
||||||
|
var days = listOf<Day>()
|
||||||
|
|
||||||
|
lateinit var username: String
|
||||||
|
lateinit var password: String
|
||||||
|
|
||||||
|
val client = OkHttpClient()
|
||||||
|
|
||||||
|
private const val apiBaseUrl = "https://aplikace.skolaonline.cz/solapi/api"
|
||||||
|
const val tokenUrl = "$apiBaseUrl/connect/token"
|
||||||
|
lateinit var token: String
|
||||||
|
const val userDataUrl = "$apiBaseUrl/v1/user"
|
||||||
|
lateinit var userData: String
|
||||||
|
lateinit var studentId: String
|
||||||
|
const val timeTableUrl = "$apiBaseUrl/v1/timeTable"
|
||||||
|
//val marksUrl = "$apiBaseUrl/v1/students/$studentId/marks/list"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 122 KiB |
@@ -0,0 +1,11 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="#333333"
|
||||||
|
android:alpha="0.6">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M17.77,3.77l-1.77,-1.77l-10,10l10,10l1.77,-1.77l-8.23,-8.23z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="#FFFFFF"
|
||||||
|
android:alpha="0.8">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M17.77,3.77l-1.77,-1.77l-10,10l10,10l1.77,-1.77l-8.23,-8.23z"/>
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 322 B |
|
After Width: | Height: | Size: 312 B |
|
After Width: | Height: | Size: 240 B |
|
After Width: | Height: | Size: 222 B |
|
After Width: | Height: | Size: 348 B |
|
After Width: | Height: | Size: 331 B |
|
After Width: | Height: | Size: 479 B |
|
After Width: | Height: | Size: 447 B |
@@ -1,21 +1,80 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/settingsBackButton"
|
android:id="@+id/appBarLayout"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:fontFamily="@font/roboto_src"
|
||||||
android:layout_marginTop="8dp"
|
android:theme="@style/Theme.Solen.AppBarOverlay">
|
||||||
android:layout_marginEnd="315dp"
|
|
||||||
android:layout_marginBottom="675dp"
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:text="Zpět"
|
android:id="@+id/settingsToolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
android:theme="@style/Theme.Solen.AppBarOverlay"
|
||||||
|
app:popupTheme="@style/Theme.Solen.PopupOverlay">
|
||||||
|
|
||||||
|
<!-- Add an ImageView for the image in the Toolbar -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/settingsBackButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:contentDescription="@string/back_button"
|
||||||
|
app:srcCompat="@drawable/ic_back_arrow" /> <!-- Adjust margin as needed -->
|
||||||
|
|
||||||
|
</androidx.appcompat.widget.Toolbar>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:id="@+id/scrollView2"
|
||||||
|
android:layout_width="409dp"
|
||||||
|
android:layout_height="673dp"
|
||||||
|
android:layout_marginStart="1dp"
|
||||||
|
android:layout_marginTop="1dp"
|
||||||
|
android:layout_marginEnd="1dp"
|
||||||
|
android:layout_marginBottom="1dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toBottomOf="@+id/appBarLayout">
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/setting_language"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/settings_language_text"
|
||||||
|
android:layout_width="180dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/lang_change"
|
||||||
|
android:textSize="20sp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/setting_language_button_choice"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="@string/lang_choose" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -5,44 +5,67 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="457dp"
|
||||||
|
android:layout_height="307dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:layout_marginBottom="17dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/usernameField"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:srcCompat="@drawable/solen" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/usernameField"
|
android:id="@+id/usernameField"
|
||||||
android:layout_width="0dp"
|
android:layout_width="237dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="50dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="292dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="52dp"
|
||||||
|
android:background="@color/primary"
|
||||||
android:ems="10"
|
android:ems="10"
|
||||||
android:hint="Uživatelské jméno"
|
android:hint="Uživatelské jméno"
|
||||||
android:inputType="text"
|
android:inputType="text"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHighlight="@color/white"
|
||||||
|
android:textColorHint="@color/white"
|
||||||
|
android:textColorLink="@color/white"
|
||||||
|
app:circularflow_radiusInDP="20dp"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/passwordField"
|
app:layout_constraintBottom_toTopOf="@+id/passwordField"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/passwordField"
|
android:id="@+id/passwordField"
|
||||||
android:layout_width="0dp"
|
android:layout_width="237dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="50dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginBottom="288dp"
|
||||||
android:layout_marginBottom="16dp"
|
android:background="@color/primary"
|
||||||
android:ems="10"
|
android:ems="10"
|
||||||
android:hint="Heslo"
|
android:hint="Heslo"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
|
android:paddingHorizontal="20dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textColorHighlight="@color/white"
|
||||||
|
android:textColorHint="@color/white"
|
||||||
|
android:textColorLink="@color/white"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/usernameField" />
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/signInButton"
|
android:id="@+id/signInButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="80dp"
|
||||||
android:layout_marginStart="137dp"
|
android:layout_marginStart="137dp"
|
||||||
android:layout_marginTop="72dp"
|
android:layout_marginTop="72dp"
|
||||||
android:layout_marginEnd="137dp"
|
android:layout_marginEnd="137dp"
|
||||||
android:layout_marginBottom="88dp"
|
android:layout_marginBottom="88dp"
|
||||||
android:text="Přihlásit se"
|
android:text="Přihlásit se"
|
||||||
|
android:textSize="20sp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
android:contentDescription="@string/background"
|
android:contentDescription="@string/background"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.501"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.562"
|
||||||
app:srcCompat="@color/black" />
|
app:srcCompat="@color/black" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@@ -25,8 +27,10 @@
|
|||||||
android:contentDescription="@string/kolaonline_enhanced"
|
android:contentDescription="@string/kolaonline_enhanced"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.495"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0.16"
|
||||||
app:srcCompat="@drawable/solen" />
|
app:srcCompat="@drawable/solen" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
@@ -35,10 +39,11 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="205dp"
|
android:layout_marginStart="205dp"
|
||||||
android:layout_marginEnd="206dp"
|
android:layout_marginEnd="206dp"
|
||||||
|
android:contentDescription="@string/splash_screen"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/imageView3"
|
app:layout_constraintTop_toBottomOf="@+id/imageView3"
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
app:layout_constraintVertical_bias="0.36" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
android:id="@+id/layoutDayMain"
|
android:id="@+id/layoutDayMain"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:background="@color/black"
|
||||||
android:fontFamily="@font/roboto">
|
android:fontFamily="@font/roboto"
|
||||||
</LinearLayout>
|
android:orientation="vertical"></LinearLayout>
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/settings_language_choice"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" >
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_button_language_cz"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/lang_cz" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:id="@+id/radio_button_language_en"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/lang_en" />
|
||||||
|
</RadioGroup>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
After Width: | Height: | Size: 719 B |
@@ -1,17 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/item_sign_in"
|
android:id="@+id/item_settings"
|
||||||
android:title="@string/sign_in" />
|
android:title="@string/settings" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/item_refresh"
|
||||||
|
android:title="@string/refresh" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/item_sign_out"
|
android:id="@+id/item_sign_out"
|
||||||
android:title="@string/sign_out" />
|
android:title="@string/sign_out" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/item_refresh"
|
android:id="@+id/item_sign_in"
|
||||||
android:icon="@android:drawable/ic_popup_sync"
|
android:title="@string/sign_in" />
|
||||||
android:title="@string/refresh" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/item_settings"
|
|
||||||
android:icon="@android:drawable/ic_menu_manage"
|
|
||||||
android:title="@string/settings" />
|
|
||||||
</menu>
|
</menu>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@mipmap/left_arrow_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/left_arrow_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@mipmap/left_arrow_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/left_arrow_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
After Width: | Height: | Size: 910 B |
|
After Width: | Height: | Size: 40 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 620 B |
|
After Width: | Height: | Size: 40 B |
|
After Width: | Height: | Size: 688 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 42 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 48 B |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 48 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
@@ -1,16 +0,0 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="Theme.Solen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
|
||||||
<!-- Primary brand color. -->
|
|
||||||
<item name="colorPrimary">@color/purple_200</item>
|
|
||||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
|
||||||
<item name="colorOnPrimary">@color/black</item>
|
|
||||||
<!-- Secondary brand color. -->
|
|
||||||
<item name="colorSecondary">@color/teal_200</item>
|
|
||||||
<item name="colorSecondaryVariant">@color/teal_200</item>
|
|
||||||
<item name="colorOnSecondary">@color/black</item>
|
|
||||||
<!-- Status bar color. -->
|
|
||||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,11 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="purple_200">#FFED7D31</color>
|
<color name="primary">#FFED7D31</color>
|
||||||
<color name="purple_500">#FF6C5F5B</color>
|
<color name="secondary">#FF000000</color>
|
||||||
<color name="purple_700">#FF000000</color>
|
|
||||||
<!--<color name="purple_700">#FF4F4A45</color>-->
|
|
||||||
<color name="teal_200">#FFF6F1EE</color>
|
|
||||||
<color name="teal_700">#FFF6F1EE</color>
|
|
||||||
<color name="black">#FF000000</color>
|
<color name="black">#FF000000</color>
|
||||||
<color name="white">#FFFFFFFF</color>
|
<color name="white">#FFFFFFFF</color>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,13 @@
|
|||||||
<string name="splash_image">splash image</string>
|
<string name="splash_image">splash image</string>
|
||||||
<string name="background">background</string>
|
<string name="background">background</string>
|
||||||
<string name="settings">Nastavení</string>
|
<string name="settings">Nastavení</string>
|
||||||
<string name="sign_in">Přihlásit se</string>
|
<string name="sign_in">Změnit přihlášení</string>
|
||||||
<string name="sign_out">Odhlásit se</string>
|
<string name="sign_out">Odhlásit se</string>
|
||||||
<string name="refresh">Znovu načíst data</string>
|
<string name="refresh">Znovu načíst data</string>
|
||||||
|
<string name="back_button">Back button</string>
|
||||||
|
<string name="lang_cz">Čeština</string>
|
||||||
|
<string name="lang_en">English</string>
|
||||||
|
<string name="lang_change">Změnit jazyk</string>
|
||||||
|
<string name="lang_choose">Vybrat</string>
|
||||||
|
<string name="splash_screen">splash screen</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,17 +1,21 @@
|
|||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
<!-- Base application theme. -->
|
<!-- Base application theme. -->
|
||||||
<style name="Theme.Solen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
<style name="Theme.Solen" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
|
||||||
<!-- Primary brand color. -->
|
<!-- Primary brand color. -->
|
||||||
<item name="colorPrimary">@color/purple_500</item>
|
<item name="colorPrimary">@color/primary</item>
|
||||||
<item name="colorPrimaryVariant">@color/purple_700</item>
|
<item name="colorPrimaryVariant">@color/primary</item>
|
||||||
<item name="colorOnPrimary">@color/white</item>
|
<item name="colorOnPrimary">@color/white</item>
|
||||||
<!-- Secondary brand color. -->
|
<!-- Secondary brand color. -->
|
||||||
<item name="colorSecondary">@color/teal_200</item>
|
<item name="colorSecondary">@color/secondary</item>
|
||||||
<item name="colorSecondaryVariant">@color/teal_700</item>
|
<item name="colorSecondaryVariant">@color/secondary</item>
|
||||||
<item name="colorOnSecondary">@color/black</item>
|
<item name="colorOnSecondary">@color/black</item>
|
||||||
<!-- Status bar color. -->
|
<!-- Status bar color. -->
|
||||||
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
|
<item name="android:statusBarColor">@color/black</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Background color -->
|
||||||
|
<item name="android:colorBackground">@color/black</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Solen.NoActionBar">
|
<style name="Theme.Solen.NoActionBar">
|
||||||
@@ -24,4 +28,11 @@
|
|||||||
<style name="Theme.Solen.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
|
<style name="Theme.Solen.PopupOverlay" parent="ThemeOverlay.AppCompat.Light">
|
||||||
<item name="android:textColor">@color/white</item>
|
<item name="android:textColor">@color/white</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="Theme.Solen.FullScreenDialog" parent="Theme.AppCompat.Dialog">
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowFullscreen">true</item>
|
||||||
|
<item name="android:windowIsFloating">false</item>
|
||||||
|
<item name="android:windowBackground">@android:color/transparent</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||