offline stuff work, new menu design, update about

This commit is contained in:
Odweta
2024-02-03 18:43:03 +01:00
parent bd00d83a6f
commit b02ec8d239
119 changed files with 964 additions and 184 deletions
+1
View File
@@ -50,6 +50,7 @@ dependencies {
implementation("androidx.viewpager2:viewpager2:1.0.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.google.android.material:material:1.11.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
testImplementation("junit:junit:4.13.2")
+1
View File
@@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

@@ -1,36 +1,53 @@
package com.odweta.solen
import android.app.Dialog
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Paint
import android.net.Uri
import android.os.Bundle
import android.text.Spannable
import android.text.SpannableString
import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.text.style.UnderlineSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
class AboutFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar)
setStyle(STYLE_NORMAL, R.style.Theme_Solen_PrimaryStatusBar)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.activity_about, container, false)
}
val view = inflater.inflate(R.layout.activity_about, container, false)
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
val link = view.findViewById<TextView>(R.id.link)
val underlinedText = SpannableString(link.text)
underlinedText.setSpan(UnderlineSpan(), 1, link.text.length, 0)
// Change statusBarColor when the back button is pressed (dialog dismissed)
requireActivity().window.statusBarColor = ContextCompat.getColor(
requireContext(),
R.color.primary
)
link.text = underlinedText
makeTextViewClickable(link, "https://gitlab.com/Odweta", 1)
val srcLink = view.findViewById<TextView>(R.id.sourceCode)
val underlinedText2 = SpannableString(srcLink.text)
underlinedText2.setSpan(UnderlineSpan(), 1, srcLink.text.length, 0)
srcLink.text = underlinedText2
makeTextViewClickable(srcLink, "https://gitlab.com/Odweta/solen")
return view
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
@@ -40,4 +57,27 @@ class AboutFragment : DialogFragment() {
return dialog
}
private fun makeTextViewClickable(link: TextView, url: String, offset: Int = 0) {
val clickableSpan = object : ClickableSpan() {
override fun onClick(widget: View) {
if (Vars.internetAvail) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivity(intent)
} else {
Toast.makeText(
requireContext(),
"Bez připojení k internetu.",
Toast.LENGTH_SHORT
).show()
}
}
}
val spannable = Spannable.Factory.getInstance().newSpannable(link.text)
spannable.setSpan(clickableSpan, offset, link.text.length, Spannable.SPAN_COMPOSING)
link.text = spannable
link.movementMethod = LinkMovementMethod.getInstance()
}
}
@@ -18,6 +18,7 @@ import android.widget.ScrollView
import android.widget.Space
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
@@ -78,6 +79,8 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
return view
}
private fun createDayView(day: Day, rootLayout: LinearLayout, resources: Resources) {
val customFont = context?.let { ResourcesCompat.getFont(it, R.font.roboto) }
val scrollView = ScrollView(requireContext())
val dayLayout = LinearLayout(requireContext())
@@ -85,6 +88,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
val nameDateTextView = TextView(requireContext())
val nameDateString = day.name + " " + day.date
nameDateTextView.typeface = customFont
nameDateTextView.text = nameDateString
nameDateTextView.textSize = 30f
nameDateTextView.setTextColor(
@@ -151,6 +155,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
)
val subjectNumberTextView = TextView(requireContext())
subjectNumberTextView.typeface = customFont
subjectNumberTextView.text = subj.number
subjectNumberTextView.textSize = 30f
subjectNumberTextView.setPadding(20, 20, 20, 20)
@@ -180,6 +185,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
if (subj.name != "Volno") {
subjectNameTextView.text = subj.name.uppercase()
}
subjectNameTextView.typeface = customFont
subjectNameTextView.textSize = 27f
subjectNameTextView.setPadding(60, 35, 20, 35)
subjectNameTextView.textAlignment = View.TEXT_ALIGNMENT_CENTER
@@ -201,6 +207,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
subjectLayout.addView(subjectNameTextView)
val subjectPlaceTextView = TextView(requireContext())
subjectPlaceTextView.typeface = customFont
subjectPlaceTextView.text = subj.place
if (subj.free) {
// underline
@@ -232,6 +239,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
val subjectTimeTextView = TextView(requireContext())
val subjectTimeString = subj.start + " - " + subj.end
subjectTimeTextView.typeface = customFont
subjectTimeTextView.text = subjectTimeString
subjectTimeTextView.textSize = 20f
subjectTimeTextView.setPadding(10, 10, 20, 10)
@@ -245,6 +253,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
val subjectTeacherTextView = TextView(requireContext())
subjectTeacherTextView.text = subj.teacher
subjectTeacherTextView.typeface = customFont
subjectTeacherTextView.textSize = 15f
subjectTeacherTextView.setPadding(10, 10, 20, 10)
subjectTeacherTextView.textAlignment = View.TEXT_ALIGNMENT_TEXT_END
@@ -332,6 +341,7 @@ class DayFragment(private val position: Int) : Fragment(R.layout.fragment_day) {
val endTime = day.subjects[day.subjects.size - 1].end
val dayEndString = "Den končí v $endTime"
dayEndTextView.text = dayEndString
dayEndTextView.typeface = customFont
dayEndTextView.textSize = 20f
dayEndTextView.setPadding(0, 30, 0, 30)
dayEndTextView.textAlignment = View.TEXT_ALIGNMENT_CENTER
@@ -2,11 +2,7 @@ package com.odweta.solen
import android.content.Context
import android.content.Intent
import android.graphics.ImageDecoder
import android.graphics.drawable.AnimatedImageDrawable
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
@@ -14,9 +10,25 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
class MainActivity : AppCompatActivity() {
private var week: List<Day> = mutableListOf()
private var toastShowing: Boolean = false
private var toastShown: Boolean = false
private var toast2Shown: Boolean = false
private var done: Boolean = false
private lateinit var toolbar: androidx.appcompat.widget.Toolbar
private var role: String = " - Student"
private lateinit var navbar: BottomNavigationView
// @section COMPANION
companion object {
fun quit(context: Context) {
@@ -51,55 +63,6 @@ class MainActivity : AppCompatActivity() {
}
}
// Override onCreateOptionsMenu to handle menu item clicks
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
// Override onOptionsItemSelected to handle menu item clicks
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
/*R.id.item_refresh -> {
lifecycleScope.launch {
launch()
}
return true
}*/
// TODO: IMPLEMENT MARKS/GRADES
/*R.id.item_marks -> {
showMarksScreen()
return true
}*/
R.id.item_sign_in -> {
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
SignInFragment().show(supportFragmentManager, "fragment_sign_in")
return true
}
R.id.item_settings -> {
showSettingsScreen()
return true
}
R.id.item_sign_out -> {
Dialogs.SignOut(this).show()
return true
}
R.id.item_about -> {
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
AboutFragment().show(supportFragmentManager, "fragment_about")
return true
}
}
return super.onOptionsItemSelected(item)
}
@@ -132,12 +95,61 @@ class MainActivity : AppCompatActivity() {
}
private fun setSignInButtonOnClick() {
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
findViewById<Button>(R.id.signInButton).setOnClickListener {
onSignIn()
}
}
private fun setOnInternetAvailListener() {
lifecycleScope.launch {
while (true) {
if (Util.internetAvail(applicationContext) && !Vars.internetAvail) {
Vars.internetAvail = Util.internetAvail(applicationContext)
withContext(Dispatchers.Main) {
fetchNewData()
}
} else if (!Vars.internetAvail) {
Vars.internetAvail = Util.internetAvail(applicationContext)
supportActionBar?.title = "Bez připojení k internetu."
} else {
Vars.internetAvail = Util.internetAvail(applicationContext)
}
delay(1000) // Check for internet availability every second
}
}
}
private fun fetchNewData() {
lifecycleScope.launch {
done = false
while (!done) {
supportActionBar?.title = "Načítání nových dat"
delay(300)
supportActionBar?.title = "Načítání nových dat."
delay(300)
supportActionBar?.title = "Načítání nových dat.."
delay(300)
supportActionBar?.title = "Načítání nových dat..."
delay(300)
}
role = if (Parsing.userIsParent()) {
" - Rodič"
} else {
" - Student"
}
supportActionBar?.title =
JSONObject(Util.fileToString(Vars.userDataFilePath)).getString("fullName") +
role
}
lifecycleScope.launch {
launchPhase1()
}
}
@@ -166,23 +178,130 @@ class MainActivity : AppCompatActivity() {
}
private fun launchPhase1() {
var week: List<Day>
val toast: Toast = Toast.makeText(
applicationContext,
"Nelze načíst data, zkuste se připojit k internetu.",
Toast.LENGTH_LONG
)
val toast2: Toast = Toast.makeText(
applicationContext,
"Připojeno k internetu.",
Toast.LENGTH_SHORT
)
lifecycleScope.launch {
Network.setupAPI()
// check if the file is available offline, if yes, load the data and don't connect to the internet
Vars.internetAvail = Util.internetAvail(applicationContext)
Vars.timeTableAvailOffline = Util.fileExists(Vars.timeTableFilePath) && !Util.fileIsEmpty(Vars.timeTableFilePath)
if (Vars.token != "NETWORK_UNREACHABLE") {
week = Parsing.parseTimeTableJSON(Network.getTimeTableJSON())
launchPhase2(week)
if (toastShown && Vars.internetAvail && !toast2Shown) {
toast2Shown = true
toast2.show()
}
if (!Vars.timeTableAvailOffline || Vars.internetAvail) {
// set up the API (required for later uses of it)
Network.setupAPI()
if (Vars.internetAvail) {
// cancel a toast, if any
if (toastShowing && !toastShown) {
toast.cancel()
}
// get the JSON data
val timeTableJSON = Network.getTimeTableJSON()
// try to save them into a file for later use
Vars.timeTableAvailOffline =
Util.saveStringToFile(Vars.timeTableFilePath, timeTableJSON)
// parse the data
week = Parsing.parseTimeTableJSON(timeTableJSON)
// continue to launch phase 2
launchPhase2()
} else {
if (Vars.timeTableAvailOffline) {
// cancel a toast, if any
if (toastShowing && !toastShown) {
toast.cancel()
}
// load the offline data
val timeTableJSON = Util.fileToString(Vars.timeTableFilePath)
// parse the data
if (timeTableJSON != "") {
// cancel a toast, if any
if (toastShowing && !toastShown) {
toast.cancel()
}
// parse the data
week = Parsing.parseTimeTableJSON(timeTableJSON)
// continue launching
launchPhase2()
} else {
// make a toast or something
toast.show()
// try to reconnect to the internet
launchPhase1()
}
} else {
// make a toast or something
if (!toastShown) {
toast.show()
toastShowing = true
toastShown = true
}
// try to reconnect to the internet
launchPhase1()
}
}
} else {
// TODO: IMPLEMENT OFFLINE STUFF
// show some sort of warning message and/or load offline files
//week =
// load offline
// cancel a toast, if any
if (toastShowing && !toastShown) {
toast.cancel()
}
// load the offline data
val timeTableJSON = Util.fileToString(Vars.timeTableFilePath)
// parse the data
if (timeTableJSON != "") {
// cancel a toast, if any
if (toastShowing && !toastShown) {
toast.cancel()
}
// parse the data
week = Parsing.parseTimeTableJSON(timeTableJSON)
// continue launching
launchPhase2()
} else {
// make a toast or something
if (!toastShown) {
toast.show()
toastShowing = true
toastShown = true
}
// try to reconnect to the internet
launchPhase1()
}
}
}
}
private fun launchPhase2(week: List<Day>) {
private fun launchPhase2() {
Vars.days = week
for ((i, day) in week.withIndex()) {
Vars.dayMap[i] = day
@@ -190,17 +309,70 @@ class MainActivity : AppCompatActivity() {
setContentView(R.layout.activity_main)
val toolbar = findViewById<androidx.appcompat.widget.Toolbar>(R.id.toolbar)
toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
toolbar.title = ""
toolbar.inflateMenu(R.menu.menu_main)
supportActionBar?.title =
JSONObject(Util.fileToString(Vars.userDataFilePath)).getString("fullName") + role
window.statusBarColor = ContextCompat.getColor(applicationContext, R.color.primary)
navbar = findViewById(R.id.bottomNav)
var frag = supportFragmentManager.findFragmentById(R.id.fragmentContainer)
if (frag == null || frag is CalWeekFragment) {
frag = CalWeekFragment()
navbar.selectedItemId = R.id.nav_timetable
}
if (frag is MarksFragment) {
frag = MarksFragment()
navbar.selectedItemId = R.id.nav_marks
}
if (frag is MenuFragment) {
frag = MenuFragment()
navbar.selectedItemId = R.id.nav_menu
}
val mainFragment = CalWeekFragment()
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, mainFragment)
.replace(R.id.fragmentContainer, frag)
.commit()
window.statusBarColor = ContextCompat.getColor(this, R.color.primary)
navbar.setOnItemSelectedListener {
when (it.itemId) {
R.id.nav_timetable -> {
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, CalWeekFragment())
.commit()
true
}
R.id.nav_marks -> {
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, MarksFragment())
.commit()
true
}
R.id.nav_menu -> {
supportFragmentManager.beginTransaction()
.replace(R.id.fragmentContainer, MenuFragment())
.commit()
true
}
else -> {
false
}
}
}
setOnInternetAvailListener()
done = true
}
@@ -210,12 +382,6 @@ class MainActivity : AppCompatActivity() {
setSignInButtonOnClick()
}
private fun showSettingsScreen() {
window.statusBarColor = ContextCompat.getColor(this, R.color.primary)
val settingsFragment = SettingsFragment()
settingsFragment.show(supportFragmentManager, "Nastavení")
}
private fun showSplashScreen() {
window.statusBarColor = ContextCompat.getColor(this, R.color.black)
@@ -224,17 +390,9 @@ class MainActivity : AppCompatActivity() {
// Assuming you have an ImageView with ID "animatedImageView" in your layout
val animatedImageView: ImageView = findViewById(R.id.loading_gif)
// Load animated image from resources (e.g., a GIF file)
val drawable = ImageDecoder.decodeDrawable(
ImageDecoder.createSource(resources, R.drawable.loading)
)
// Set the drawable to your ImageView
if (drawable is AnimatedImageDrawable) {
animatedImageView.setImageDrawable(drawable)
drawable.start() // Start the animation
}
Glide.with(applicationContext)
.load(R.drawable.loading)
.into(animatedImageView)
}
}
}
@@ -0,0 +1,24 @@
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
import androidx.fragment.app.Fragment
class MarksFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.activity_marks, container, false)
return view
}
}
@@ -0,0 +1,63 @@
package com.odweta.solen
import android.app.AlertDialog
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
import androidx.fragment.app.Fragment
class MenuFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.activity_menu, container, false)
addCallbacks(view)
return view
}
private fun addCallbacks(view: View) {
val settings = view.findViewById<Button>(R.id.menu_button_settings)
val signOut = view.findViewById<Button>(R.id.menu_button_sign_out)
val signIn = view.findViewById<Button>(R.id.menu_button_sign_in)
val about = view.findViewById<Button>(R.id.menu_button_about)
settings.setOnClickListener {
SettingsFragment().show(requireFragmentManager(), "fragment_settings")
}
signOut.setOnClickListener {
val builder: AlertDialog.Builder = AlertDialog.Builder(context)
builder
.setTitle("Opravdu se chcete odhlásit? Tato akce zavře aplikaci.")
.setPositiveButton("Ano") { dialog, _ ->
MainActivity.quit(requireContext())
dialog.dismiss()
}
.setNegativeButton("Ne") { dialog, _ ->
dialog.dismiss()
}
val dialog: AlertDialog = builder.create()
dialog.show()
}
signIn.setOnClickListener {
SignInFragment().show(requireFragmentManager(), "fragment_sign_in")
}
about.setOnClickListener {
AboutFragment().show(requireFragmentManager(), "fragment_about")
}
}
}
@@ -1,5 +1,6 @@
package com.odweta.solen
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.FormBody
@@ -50,9 +51,12 @@ class Network {
if (Vars.token == "NETWORK_UNREACHABLE") {
Vars.userData = ""
Vars.studentId = ""
Vars.internetAvail = false
return@withContext
}
Vars.internetAvail = true
Vars.userData = getUserDataJSON()
Util.saveStringToFile(Vars.userDataFilePath, Vars.userData)
Vars.studentId = getStudentId()
}
}
@@ -23,17 +23,6 @@ class SettingsFragment : DialogFragment() {
): 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()
@@ -13,7 +13,7 @@ import androidx.core.content.ContextCompat
class SignInFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar)
setStyle(STYLE_NORMAL, R.style.Theme_Solen)
}
override fun onCreateView(
@@ -23,16 +23,6 @@ class SignInFragment : DialogFragment() {
return inflater.inflate(R.layout.activity_sign_in, container, false)
}
override fun onCancel(dialog: DialogInterface) {
super.onCancel(dialog)
// Change statusBarColor when the back button is pressed (dialog dismissed)
requireActivity().window.statusBarColor = ContextCompat.getColor(
requireContext(),
R.color.primary
)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
dialog.window?.requestFeature(Window.FEATURE_NO_TITLE)
@@ -1,27 +1,113 @@
package com.odweta.solen
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.util.DisplayMetrics
import android.view.WindowManager
import org.json.JSONObject
import java.io.File
import java.io.IOException
import java.nio.charset.Charset
class Util {
companion object {
fun getDisplayHeight(context: Context): Int {
private fun getDisplayMetrics(context: Context): DisplayMetrics {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
return displayMetrics.heightPixels
return displayMetrics
}
fun getDisplayHeight(context: Context): Int {
return getDisplayMetrics(context).heightPixels
}
fun getDisplayWidth(context: Context): Int {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val displayMetrics = DisplayMetrics()
return getDisplayMetrics(context).widthPixels
}
windowManager.defaultDisplay.getMetrics(displayMetrics)
fun saveStringToFile(filePath: String, s: String): Boolean {
// get a file object with the specified path
val f = File(Vars.fileDir, filePath)
return displayMetrics.widthPixels
// if it does not exist, create it
if (!f.exists()) {
try {
f.createNewFile()
} catch (e: IOException) {
return false
}
}
// write the json to the file
if (f.canWrite()) {
f.writeText(s, Charset.forName("UTF-8"))
} else {
return false
}
return true
}
fun fileToString(filePath: String): String {
val f = File(Vars.fileDir, filePath)
return if (f.exists()) {
if (f.canRead()) {
try {
f.readText()
} catch (e: IOException) {
""
}
} else {
""
}
} else {
""
}
}
fun fileExists(filePath: String): Boolean {
val f = File(Vars.fileDir, filePath)
return f.exists()
}
fun fileIsEmpty(filePath: String): Boolean {
val f = File(Vars.fileDir, filePath)
val content = f.readText()
return content == ""
}
fun internetAvail(context: Context): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
return true
}
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return true
}
}
return false
}
fun deleteFile(path: String): Boolean {
val f = File(Vars.fileDir, path)
if (f.exists()) {
try {
f.delete()
} catch (e: IOException) {
return false
}
return true
} else {
return true
}
}
}
}
@@ -6,9 +6,16 @@ import java.io.File
class Vars {
companion object {
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"
lateinit var fileDir: File
var width: Int = 0
var height: Int = 0
var internetAvail: Boolean = false
var timeTableAvailOffline: Boolean = false
//var marksAvailOffline: Boolean = false
val dayMap = mutableMapOf<Int, Day>()
var days = listOf<Day>()
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

+112 -11
View File
@@ -5,21 +5,122 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/about_app_textView"
<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="168dp"
android:layout_marginTop="349dp"
android:layout_marginEnd="183dp"
android:layout_marginBottom="363dp"
android:text="O aplikaci"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/link"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/solen" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/roboto_src"
android:theme="@style/Theme.Solen.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
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"
app:title="@string/about_app">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<TextView
android:id="@+id/textView"
android:layout_width="299dp"
android:layout_height="100dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="300dp"
android:text="Vylepšená verze školního informačního systému ŠkolaOnLine."
android:textAlignment="center"
android:textColor="#FFFFFF"
android:textColorHighlight="#FFFFFF"
android:textColorHint="#FFFFFF"
android:textColorLink="#FFFFFF"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.416"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@+id/imageView2"
app:layout_constraintVertical_bias="0.804" />
<TextView
android:id="@+id/link"
style="@style/LinkText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="1dp"
android:layout_marginTop="70dp"
android:layout_marginEnd="139dp"
android:layout_marginBottom="188dp"
android:text=" Odweta"
android:textColor="#FFFFFF"
android:textFontWeight="400"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView3"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="1.0" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="144dp"
android:layout_marginTop="70dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="188dp"
android:text="Vývoj:"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/link"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintVertical_bias="1.0" />
<ImageView
android:id="@+id/imageView7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="61dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.303"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/link"
app:layout_constraintVertical_bias="1.0"
app:srcCompat="@mipmap/gitlab_logo_foreground" />
<TextView
android:id="@+id/sourceCode"
style="@style/LinkText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="59dp"
android:layout_marginEnd="96dp"
android:layout_marginBottom="102dp"
android:text="Zdrojový kód"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/imageView7"
app:layout_constraintTop_toBottomOf="@+id/link"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -8,31 +8,46 @@
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="675dp"
android:fontFamily="@font/roboto_src"
android:theme="@style/Theme.Solen.AppBarOverlay">
android:theme="@style/Theme.Solen.AppBarOverlay"
app:popupTheme="@style/Theme.Solen.PopupOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/Theme.Solen.PopupOverlay"
android:theme="@style/Theme.Solen.AppBarOverlay">
</androidx.appcompat.widget.Toolbar>
app:subtitle=""
app:title="" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/dayPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent">
</androidx.viewpager2.widget.ViewPager2>
<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent">
</FrameLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomNav"
android:layout_width="match_parent"
android:layout_height="60dp"
android:scrollIndicators="left"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBarLayout2"
app:layout_constraintVertical_bias="1.0"
app:menu="@menu/menu_navbar"
tools:layout_editor_absoluteX="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="146dp"
android:layout_marginTop="262dp"
android:layout_marginEnd="182dp"
android:layout_marginBottom="442dp"
android:text="ZNAMKY"
android:textColor="#FFFFFF"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/menu_layout_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<Button
android:id="@+id/menu_button_settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="200dp"
android:layout_marginBottom="50dp"
android:text="@string/settings"
app:layout_constraintBottom_toTopOf="@+id/menu_button_sign_out"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/menu_button_sign_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:text="@string/sign_out"
app:layout_constraintBottom_toTopOf="@+id/menu_button_sign_in"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/menu_button_settings" />
<Button
android:id="@+id/menu_button_sign_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:text="@string/sign_in"
app:layout_constraintBottom_toTopOf="@+id/menu_button_about"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/menu_button_sign_out" />
<Button
android:id="@+id/menu_button_about"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="158dp"
android:layout_marginEnd="159dp"
android:layout_marginBottom="200dp"
android:text="@string/about_app"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/menu_button_sign_in" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -19,19 +19,12 @@
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 -->
app:popupTheme="@style/Theme.Solen.PopupOverlay"
app:title="@string/settings">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<ScrollView
@@ -35,15 +35,14 @@
<ImageView
android:id="@+id/loading_gif"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="205dp"
android:layout_marginEnd="206dp"
android:contentDescription="@string/splash_screen"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/loading"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView3"
app:layout_constraintVertical_bias="0.36" />
app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_settings"
android:title="@string/settings" />
<!-- not really needed in the release version, basically just for development purposes
<item
android:id="@+id/item_refresh"
android:title="@string/refresh" />-->
<item
android:id="@+id/item_sign_out"
android:title="@string/sign_out" />
<item
android:id="@+id/item_sign_in"
android:title="@string/sign_in" />
<item
android:id="@+id/item_about"
android:title="@string/about_app" />
</menu>
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/nav_timetable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@android:drawable/ic_dialog_dialer"
android:title="Rozvrh" />
<item
android:id="@+id/nav_marks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@mipmap/grade2_foreground"
android:title="Známky" />
<item
android:id="@+id/nav_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/menu_240"
android:title="Menu" />
</menu>
<!--
options menu for future reference
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_settings"
android:title="@string/settings" />
<item
android:id="@+id/item_sign_out"
android:title="@string/sign_out" />
<item
android:id="@+id/item_sign_in"
android:title="@string/sign_in" />
<item
android:id="@+id/item_about"
android:title="@string/about_app" />
</menu>
item click callbacks
// Override onOptionsItemSelected to handle menu item clicks
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
// TODO: IMPLEMENT MARKS/GRADES
// TODO: NOTE -> IN A NAVBAR
/*R.id.item_marks -> {
showMarksScreen()
return true
}*/
R.id.item_sign_in -> {
SignInFragment().show(supportFragmentManager, "fragment_sign_in")
return true
}
R.id.item_settings -> {
showSettingsScreen()
return true
}
R.id.item_sign_out -> {
Dialogs.SignOut(this).show()
return true
}
R.id.item_about -> {
AboutFragment().show(supportFragmentManager, "fragment_about")
return true
}
}
return super.onOptionsItemSelected(item)
}
-->
@@ -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/gitlab_logo_background"/>
<foreground android:drawable="@mipmap/gitlab_logo_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/gitlab_logo_background"/>
<foreground android:drawable="@mipmap/gitlab_logo_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/grade_background"/>
<foreground android:drawable="@mipmap/grade_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/grade2_background"/>
<foreground android:drawable="@mipmap/grade2_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/grade2_background"/>
<foreground android:drawable="@mipmap/grade2_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/grade_background"/>
<foreground android:drawable="@mipmap/grade_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/menu_background"/>
<foreground android:drawable="@mipmap/menu_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/menu_background"/>
<foreground android:drawable="@mipmap/menu_foreground"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 880 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Some files were not shown because too many files have changed in this diff Show More