2020-08-14 21:41:43 +02:00
/ * *
* ProjectLaogai
*
* Copyright 2019 - 2020 < seil0 @mosad . xyz >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston ,
* MA 02110 - 1301 , USA .
*
* /
package org.mosad.seil0.projectlaogai.fragments
2020-08-16 21:30:18 +02:00
import android.graphics.Rect
2020-08-14 21:41:43 +02:00
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
2020-08-15 18:13:29 +02:00
import android.widget.TextView
2020-08-16 21:30:18 +02:00
import androidx.core.content.res.ResourcesCompat
2020-08-14 21:41:43 +02:00
import androidx.fragment.app.Fragment
2020-08-16 21:30:18 +02:00
import kotlinx.coroutines.*
2020-08-14 21:41:43 +02:00
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.QISPOSParser
2020-08-28 21:38:44 +02:00
import org.mosad.seil0.projectlaogai.controller.cache.CacheController
2020-08-15 18:13:29 +02:00
import org.mosad.seil0.projectlaogai.controller.preferences.EncryptedPreferences
2020-08-17 22:30:12 +02:00
import org.mosad.seil0.projectlaogai.controller.preferences.Preferences
2020-12-06 18:00:28 +01:00
import org.mosad.seil0.projectlaogai.databinding.FragmentGradesBinding
2020-08-14 21:41:43 +02:00
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
import org.mosad.seil0.projectlaogai.uicomponents.GradeLinearLayout
2020-08-15 18:13:29 +02:00
import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoginDialog
2020-08-28 21:38:44 +02:00
import kotlin.system.measureTimeMillis
2020-08-14 21:41:43 +02:00
/ * *
2020-08-15 18:13:29 +02:00
* The grades fragment class
* contains all needed parts to display and the grades screen
2020-08-14 21:41:43 +02:00
* /
class GradesFragment : Fragment ( ) {
2020-08-16 21:30:18 +02:00
private lateinit var parser : QISPOSParser
2020-12-06 18:00:28 +01:00
private lateinit var binding : FragmentGradesBinding
2020-08-16 21:30:18 +02:00
2020-12-06 18:00:28 +01:00
override fun onCreateView ( inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ) : View {
binding = FragmentGradesBinding . inflate ( inflater , container , false )
return binding . root
2020-08-17 22:30:12 +02:00
}
override fun onViewCreated ( view : View , savedInstanceState : Bundle ? ) {
super . onViewCreated ( view , savedInstanceState )
2020-08-14 21:41:43 +02:00
2020-12-06 18:00:28 +01:00
binding . refreshLayoutGrades . setProgressBackgroundColorSchemeColor ( Preferences . themeSecondary )
2020-08-28 23:21:17 +02:00
initActions ( )
2020-08-14 21:41:43 +02:00
2020-08-16 21:30:18 +02:00
parser = QISPOSParser ( context !! ) // init the parser
2020-08-29 17:21:34 +02:00
if ( checkCredentials ( ) ) {
2020-08-15 18:13:29 +02:00
GlobalScope . launch ( Dispatchers . Default ) {
2020-08-29 17:21:34 +02:00
// if the cache is older than 24hr, update blocking
val currentTime = System . currentTimeMillis ( ) / 1000
2020-10-18 15:53:37 +02:00
withContext ( Dispatchers . Main ) {
if ( ( currentTime - Preferences . gradesCacheTime ) > 86400 && checkQisposStatus ( ) ) {
2020-12-06 18:00:28 +01:00
binding . refreshLayoutGrades . isRefreshing = true
2020-10-18 15:53:37 +02:00
CacheController . updateGrades ( context !! ) . join ( )
2020-08-29 17:21:34 +02:00
}
}
2020-08-14 21:41:43 +02:00
addGrades ( )
2020-08-15 18:13:29 +02:00
}
2020-08-14 21:41:43 +02:00
}
}
2020-08-28 23:21:17 +02:00
/ * *
* initialize the actions
* /
private fun initActions ( ) = GlobalScope . launch ( Dispatchers . Default ) {
2020-12-06 18:00:28 +01:00
binding . refreshLayoutGrades . setOnRefreshListener {
binding . linLayoutGrades . removeAllViews ( ) // clear layout
2020-08-28 23:21:17 +02:00
// TODO add loading textView
GlobalScope . launch ( Dispatchers . Default ) {
CacheController . updateGrades ( context !! ) . join ( )
addGrades ( )
}
}
}
2020-08-15 18:13:29 +02:00
/ * *
* check if the credentials are set , if not show a login dialog
* /
private fun checkCredentials ( ) : Boolean {
val credentials = EncryptedPreferences . readCredentials ( context !! )
var credentialsPresent = false
// if there is no password set, show the login dialog
if ( credentials . first . isEmpty ( ) || credentials . second . isEmpty ( ) ) {
LoginDialog ( this . context !! )
. positiveButton {
EncryptedPreferences . saveCredentials ( email , password , context )
addGrades ( )
}
. negativeButton {
2020-12-06 18:00:28 +01:00
binding . txtViewLoading . text = resources . getString ( R . string . credentials _missing )
2020-08-15 18:13:29 +02:00
}
. show {
email = EncryptedPreferences . email
password = " "
}
} else {
credentialsPresent = true
}
return credentialsPresent
}
2020-08-16 21:30:18 +02:00
/ * *
* check if qispos is available , if not show an error
* /
private fun checkQisposStatus ( ) : Boolean {
val statusCode = parser . checkQISPOSStatus ( )
2020-08-17 22:30:12 +02:00
// show error if the status code is not 200
if ( statusCode != 200 ) {
val infoText = resources . getString ( when ( statusCode ) {
503 -> R . string . qispos _unavailable
else -> R . string . qispos _generic _error
} )
2020-08-16 21:30:18 +02:00
2020-08-17 22:30:12 +02:00
val img = ResourcesCompat . getDrawable ( resources , R . drawable . ic _error _outline _black _24dp , null ) ?. apply {
bounds = Rect ( 0 , 0 , 75 , 75 )
}
2020-08-16 21:30:18 +02:00
2020-12-06 18:00:28 +01:00
binding . txtViewLoading . apply {
2020-08-17 22:30:12 +02:00
text = infoText
setCompoundDrawables ( null , null , null , img )
}
2020-08-16 21:30:18 +02:00
}
return statusCode == 200
}
2020-08-28 21:38:44 +02:00
/ * *
* add the grades to the layout , async
* TODO this is slow as hell
* /
2020-08-14 21:41:43 +02:00
private fun addGrades ( ) = GlobalScope . launch ( Dispatchers . Default ) {
2020-08-28 21:38:44 +02:00
val addGradesTime = measureTimeMillis {
val grades = CacheController ( context !! ) . readGrades ( )
2020-08-15 18:13:29 +02:00
2020-08-28 21:38:44 +02:00
withContext ( Dispatchers . Main ) {
2020-12-06 18:00:28 +01:00
binding . linLayoutGrades . removeAllViews ( ) // clear layout
2020-08-28 21:38:44 +02:00
}
2020-08-15 18:13:29 +02:00
2020-08-28 21:38:44 +02:00
// TODO this loop takes 3/4 of the time
// for each semester add a new card
grades . forEach { semester ->
val usedSubjects = ArrayList < String > ( )
val semesterCard = DayCardView ( context !! )
semesterCard . setDayHeading ( semester . key )
// for each subject add a new linLayout
semester . value . forEachIndexed { index , subject ->
if ( usedSubjects . contains ( subject . name ) ) {
return @forEachIndexed
}
// get the first sub subjects
val subSubject = semester . value . firstOrNull {
it . name . contains ( subject . name ) && it . name != subject . name
}
// if sub subject is not null, add it to used subjects
subSubject ?. let {
usedSubjects . add ( it . name )
}
val subjectLayout = GradeLinearLayout ( context ) . set {
subjectName = subject . name
grade = subject . grade
subSubjectName = subSubject ?. name . toString ( )
subGrade = subSubject ?. grade . toString ( )
}
// disable sub-subject if not set
if ( subSubject == null )
subjectLayout . disableSubSubject ( )
// disable divider if last element
if ( index == semester . value . lastIndex || semester . value . indexOf ( subSubject ) == semester . value . lastIndex )
subjectLayout . disableDivider ( )
semesterCard . getLinLayoutDay ( ) . addView ( subjectLayout )
2020-08-15 18:13:29 +02:00
}
2020-08-28 21:38:44 +02:00
// without context we can't access the view
withContext ( Dispatchers . Main ) {
2020-12-06 18:00:28 +01:00
binding . linLayoutGrades . addView ( semesterCard )
2020-08-14 21:41:43 +02:00
}
2020-08-28 21:38:44 +02:00
}
2020-08-14 21:41:43 +02:00
2020-08-28 21:38:44 +02:00
val txtViewLegal = TextView ( context ) . apply {
text = resources . getString ( R . string . without _guarantee )
textAlignment = View . TEXT _ALIGNMENT _CENTER
2020-08-14 21:41:43 +02:00
}
2020-08-28 21:38:44 +02:00
// stop refreshing and show legal warning
2020-08-14 21:41:43 +02:00
withContext ( Dispatchers . Main ) {
2020-12-06 18:00:28 +01:00
binding . linLayoutGrades . addView ( txtViewLegal )
binding . refreshLayoutGrades . isRefreshing = false
2020-08-14 21:41:43 +02:00
}
2020-08-15 18:13:29 +02:00
2020-08-14 21:41:43 +02:00
}
2020-08-28 23:21:17 +02:00
println ( " added grades in $addGradesTime ms " )
2020-08-14 21:41:43 +02:00
}
}