diff --git a/app/build.gradle b/app/build.gradle index 876d2ef..45db2a6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,13 +6,13 @@ android { signingConfigs { } - compileSdkVersion 30 - buildToolsVersion "30.0.2" + compileSdkVersion 33 + buildToolsVersion "30.0.3" defaultConfig { applicationId "org.mosad.seil0.projectlaogai" minSdkVersion 23 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 6091 // 00.06.091 versionName "0.6.1-beta2" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -66,30 +66,30 @@ android { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.2' - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' - implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' + implementation 'androidx.core:core-ktx:1.9.0' + implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3' + implementation 'androidx.navigation:navigation-ui-ktx:2.5.3' + implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - implementation 'androidx.security:security-crypto:1.1.0-alpha02' - implementation "androidx.work:work-runtime-ktx:2.4.0" - implementation 'com.google.android.material:material:1.2.1' - implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.afollestad:aesthetic:1.0.0-beta05' + implementation 'androidx.security:security-crypto:1.1.0-alpha04' + implementation "androidx.work:work-runtime-ktx:2.7.1" + implementation 'com.google.android.material:material:1.7.0' + implementation 'com.google.code.gson:gson:2.10' + // implementation 'com.afollestad:aesthetic:1.0.0-beta05' implementation 'com.afollestad.material-dialogs:core:3.3.0' implementation 'com.afollestad.material-dialogs:color:3.3.0' implementation 'com.afollestad.material-dialogs:bottomsheets:3.3.0' implementation 'de.psdev.licensesdialog:licensesdialog:2.1.0' implementation 'org.apache.commons:commons-lang3:3.11' - implementation 'org.jsoup:jsoup:1.13.1' + implementation 'org.jsoup:jsoup:1.15.3' - testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' - androidTestImplementation 'androidx.test:core:1.3.0' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2' + androidTestImplementation 'androidx.test:core:1.5.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.4' } static def buildTime() { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 737b74b..fb095ac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,55 +1,56 @@ - + package="org.mosad.seil0.projectlaogai"> + + + android:allowBackup="true" + android:fullBackupContent="@xml/backup_descriptor" + android:icon="@mipmap/ic_laogai_icon" + android:label="@string/app_name" + android:roundIcon="@mipmap/ic_laogai_icon" + android:supportsRtl="true" + android:theme="@style/AppTheme.Light"> + android:name=".SplashActivity" + android:screenOrientation="portrait" + android:theme="@style/SplashTheme" + android:exported="true"> - - + + - + - + android:name=".OnboardingActivity" + android:launchMode="singleTop" + android:screenOrientation="portrait" + android:theme="@style/AppTheme.Light" /> + android:name=".MainActivity" + android:exported="true" + android:launchMode="singleTop" + android:screenOrientation="portrait" + android:theme="@style/AppTheme.Light"> - + - + diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/MainActivity.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/MainActivity.kt index 24687ee..acdf00e 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/MainActivity.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/MainActivity.kt @@ -34,14 +34,15 @@ import android.util.Log import android.util.TypedValue import android.view.Menu import android.view.MenuItem +import androidx.activity.addCallback import androidx.appcompat.app.ActionBarDrawerToggle import androidx.appcompat.app.AppCompatActivity import androidx.core.view.GravityCompat import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.commit -import com.afollestad.aesthetic.Aesthetic -import com.afollestad.aesthetic.NavigationViewMode +//import com.afollestad.aesthetic.Aesthetic +//import com.afollestad.aesthetic.NavigationViewMode import com.google.android.material.navigation.NavigationView import org.mosad.seil0.projectlaogai.controller.NFCMensaCard import org.mosad.seil0.projectlaogai.controller.cache.CacheController @@ -67,7 +68,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte private var useNFC = false override fun onCreate(savedInstanceState: Bundle?) { - Aesthetic.attach(this) +// Aesthetic.attach(this) super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) @@ -100,6 +101,12 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte supportFragmentManager.commit { replace(R.id.fragment_container, activeFragment, activeFragment.javaClass.simpleName) } + + onBackPressedDispatcher.addCallback { + if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) { + binding.drawerLayout.closeDrawer(GravityCompat.START) + } + } } override fun onNewIntent(intent: Intent) { @@ -112,7 +119,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte override fun onResume() { super.onResume() - Aesthetic.resume(this) +// Aesthetic.resume(this) if(useNFC) adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray) @@ -120,20 +127,11 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte override fun onPause() { super.onPause() - Aesthetic.pause(this) +// Aesthetic.pause(this) if(useNFC) adapter.disableForegroundDispatch(this) } - override fun onBackPressed() { - if (binding.drawerLayout.isDrawerOpen(GravityCompat.START)) { - binding.drawerLayout.closeDrawer(GravityCompat.START) - } else { - // TODO only call on double tap - super.onBackPressed() - } - } - override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.main, menu) @@ -186,25 +184,25 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte private fun initAesthetic() { // If we haven't set any defaults, do that now - if (Aesthetic.isFirstTime) { - // set the default theme at the first app start - Aesthetic.config { - activityTheme(R.style.AppTheme_Light) - apply() - } - - // show the onboarding activity - startActivity(Intent(this, OnboardingActivity::class.java)) - finish() - } - - Aesthetic.config { - colorPrimary(Preferences.colorPrimary) - colorPrimaryDark(Preferences.colorPrimary) - colorAccent(Preferences.colorAccent) - navigationViewMode(NavigationViewMode.SELECTED_ACCENT) - apply() - } +// if (Aesthetic.isFirstTime) { +// // set the default theme at the first app start +// Aesthetic.config { +// activityTheme(R.style.AppTheme_Light) +// apply() +// } +// // TODO needs to be shown on first start +// // show the onboarding activity +// startActivity(Intent(this, OnboardingActivity::class.java)) +// finish() +// } +// +// Aesthetic.config { +// colorPrimary(Preferences.colorPrimary) +// colorPrimaryDark(Preferences.colorPrimary) +// colorAccent(Preferences.colorAccent) +// navigationViewMode(NavigationViewMode.SELECTED_ACCENT) +// apply() +// } // set theme color values val out = TypedValue() diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/OnboardingActivity.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/OnboardingActivity.kt index b2519d9..25a3e97 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/OnboardingActivity.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/OnboardingActivity.kt @@ -31,6 +31,7 @@ import android.widget.LinearLayout import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.core.text.HtmlCompat +import androidx.lifecycle.lifecycleScope import androidx.viewpager.widget.ViewPager import kotlinx.coroutines.* import org.mosad.seil0.projectlaogai.controller.cache.CacheController @@ -94,7 +95,7 @@ class OnboardingActivity : AppCompatActivity() { val loadingDialog = LoadingDialog(context) loadingDialog.show() - GlobalScope.launch(Dispatchers.Default) { + lifecycleScope.launch(Dispatchers.Default) { Preferences.saveCourse(context, CacheController.coursesList[selectedIndex]) // save the course // update current & next weeks timetable diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/QISPOSParser.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/QISPOSParser.kt index 4311e56..61eec89 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/QISPOSParser.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/QISPOSParser.kt @@ -160,7 +160,8 @@ class QISPOSParser(val context: Context) { // grades root document and url val rootHtml =Jsoup.parse(res.body()) - val gradesRootLink = rootHtml.select("li.menueListStyle > a.auflistung").last().attr("abs:href") + val gradesRootLink = + rootHtml.select("li.menueListStyle > a.auflistung").last()!!.attr("abs:href") // parse grades url val gradesHtml = Jsoup.connect(gradesRootLink) @@ -179,7 +180,7 @@ class QISPOSParser(val context: Context) { .referrer("https://notenverwaltung.hs-offenburg.de/qispos/rds?state=user&type=0") .get() - val gradesListLink = gradesNextHtml.selectFirst("li.treelist > ul > li").selectFirst("a").attr("abs:href") + val gradesListLink = gradesNextHtml.selectFirst("li.treelist > ul > li")!!.selectFirst("a")!!.attr("abs:href") // get the grades list val gradesListHtml = Jsoup.connect(gradesListLink) diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/TCoRAPIController.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/TCoRAPIController.kt index 4b10817..5464222 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/TCoRAPIController.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/TCoRAPIController.kt @@ -84,7 +84,7 @@ class TCoRAPIController { fun getSubjectListAsync(courseName: String, week: Int): Deferred> { val url = URL("$tcorBaseURL/subjectList?course=$courseName&week=$week") - return GlobalScope.async { + return CoroutineScope(Dispatchers.IO).async { Gson().fromJson(url.readText(), ArrayList()::class.java) } } diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/cache/CacheController.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/cache/CacheController.kt index b4446b8..af45b2f 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/cache/CacheController.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/cache/CacheController.kt @@ -64,7 +64,7 @@ class CacheController(private val context: Context) { // if a) it's monday and the last cache update was on sunday or b) the cache is older than 24hr, update blocking if ((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - mensaCacheTime) > 86400) { Log.i(className, "Update mensa blocking") - GlobalScope.launch(Dispatchers.Default) { updateMensaMenu(context).join() } + CoroutineScope(Dispatchers.Default).launch { updateMensaMenu(context).join() } } // check if we need to update the timetable before displaying it @@ -74,7 +74,7 @@ class CacheController(private val context: Context) { if ((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - timetableCacheTime) > 86400) { Log.i(className, "Updating timetable after sunday!") - GlobalScope.launch(Dispatchers.Default) { + CoroutineScope(Dispatchers.Default).launch { val threads = listOf( updateTimetable(Preferences.course.courseName, 0, context), updateTimetable(Preferences.course.courseName, 1, context) @@ -110,7 +110,7 @@ class CacheController(private val context: Context) { val file = File(context.filesDir, "courses.json") var courseListUp = CoursesList() - return GlobalScope.launch(Dispatchers.IO) { + return CoroutineScope(Dispatchers.IO).launch { try { courseListUp = TCoRAPIController.getCourseListNEW() } catch (ex: Exception) { @@ -133,7 +133,7 @@ class CacheController(private val context: Context) { fun updateMensaMenu(context: Context): Job { val file = File(context.filesDir, "mensa.json") - return GlobalScope.launch(Dispatchers.IO) { + return CoroutineScope(Dispatchers.IO).launch { try { mensaMenu = TCoRAPIController.getMensaMenu() } catch (ex: Exception) { @@ -157,7 +157,7 @@ class CacheController(private val context: Context) { var timetable = TimetableWeek() // try to update timetable from tcor, async - return GlobalScope.launch(Dispatchers.IO) { + return CoroutineScope(Dispatchers.IO).launch { try { timetable = TCoRAPIController.getTimetable(courseName, week) } catch (ex: Exception) { @@ -184,7 +184,7 @@ class CacheController(private val context: Context) { fun updateAdditionalLessons(context: Context): Job { val fileLessons = File(context.filesDir, "additional_lessons.json") - return GlobalScope.launch(Dispatchers.IO) { + return CoroutineScope(Dispatchers.IO).launch { TimetableController.subjectMap.forEach { (courseName, subjects) -> // update all subjects for a course subjects.forEach {subject -> @@ -209,7 +209,7 @@ class CacheController(private val context: Context) { val file = File(context.filesDir, "grades_encrypted") val parser = QISPOSParser(context) - return GlobalScope.launch(Dispatchers.IO) { + return CoroutineScope(Dispatchers.IO).launch { if (parser.checkQISPOSStatus() == 200) { // save cache file and update time saveEncrypted(context, file, Gson().toJson(parser.parseGrades())) diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/GradesFragment.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/GradesFragment.kt index 0c9dbe6..c6f7d18 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/GradesFragment.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/GradesFragment.kt @@ -24,12 +24,14 @@ package org.mosad.seil0.projectlaogai.fragments import android.graphics.Rect import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.* import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.controller.QISPOSParser @@ -62,16 +64,16 @@ class GradesFragment : Fragment() { binding.refreshLayoutGrades.setProgressBackgroundColorSchemeColor(Preferences.themeSecondary) initActions() - parser = QISPOSParser(context!!)// init the parser + parser = QISPOSParser(requireContext())// init the parser if (checkCredentials()) { - GlobalScope.launch(Dispatchers.Default) { + lifecycleScope.launch(Dispatchers.Default) { // if the cache is older than 24hr, update blocking val currentTime = System.currentTimeMillis() / 1000 withContext(Dispatchers.Main) { if ((currentTime - Preferences.gradesCacheTime) > 86400 && checkQisposStatus()) { binding.refreshLayoutGrades.isRefreshing = true - CacheController.updateGrades(context!!).join() + CacheController.updateGrades(requireContext()).join() } } @@ -83,13 +85,13 @@ class GradesFragment : Fragment() { /** * initialize the actions */ - private fun initActions() = GlobalScope.launch(Dispatchers.Default) { + private fun initActions() = lifecycleScope.launch(Dispatchers.Default) { binding.refreshLayoutGrades.setOnRefreshListener { binding.linLayoutGrades.removeAllViews() // clear layout // TODO add loading textView - GlobalScope.launch(Dispatchers.Default) { - CacheController.updateGrades(context!!).join() + lifecycleScope.launch(Dispatchers.Default) { + CacheController.updateGrades(requireContext()).join() addGrades() } } @@ -99,12 +101,12 @@ class GradesFragment : Fragment() { * check if the credentials are set, if not show a login dialog */ private fun checkCredentials(): Boolean { - val credentials = EncryptedPreferences.readCredentials(context!!) + val credentials = EncryptedPreferences.readCredentials(requireContext()) var credentialsPresent = false // if there is no password set, show the login dialog if (credentials.first.isEmpty() || credentials.second.isEmpty()) { - LoginDialog(this.context!!) + LoginDialog(this.requireContext()) .positiveButton { EncryptedPreferences.saveCredentials(email, password, context) addGrades() @@ -153,9 +155,9 @@ class GradesFragment : Fragment() { * add the grades to the layout, async * TODO this is slow as hell */ - private fun addGrades() = GlobalScope.launch(Dispatchers.Default) { + private fun addGrades() = lifecycleScope.launch(Dispatchers.Default) { val addGradesTime = measureTimeMillis { - val grades = CacheController(context!!).readGrades() + val grades = CacheController(requireContext()).readGrades() withContext(Dispatchers.Main) { binding.linLayoutGrades.removeAllViews() // clear layout @@ -165,7 +167,7 @@ class GradesFragment : Fragment() { // for each semester add a new card grades.forEach { semester -> val usedSubjects = ArrayList() - val semesterCard = DayCardView(context!!) + val semesterCard = DayCardView(requireContext()) semesterCard.setDayHeading(semester.key) // for each subject add a new linLayout @@ -220,7 +222,7 @@ class GradesFragment : Fragment() { } } - println("added grades in $addGradesTime ms") + Log.i(javaClass.name, "added grades in $addGradesTime ms") } } \ No newline at end of file diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/HomeFragment.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/HomeFragment.kt index 5a9af89..9d9e2be 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/HomeFragment.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/HomeFragment.kt @@ -30,6 +30,7 @@ import android.view.View import android.view.ViewGroup import android.widget.TextView import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.* import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.controller.cache.CacheController.Companion.mensaMenu @@ -68,22 +69,22 @@ class HomeFragment : Fragment() { /** * add the current mensa meal to the home screens */ - private fun addMensaMenu() = GlobalScope.launch(Dispatchers.Default) { + private fun addMensaMenu() = lifecycleScope.launch(Dispatchers.Default) { var dayMeals: ArrayList val cal = Calendar.getInstance() - val mensaCardView = DayCardView(context!!) + val mensaCardView = DayCardView(requireContext()) withContext(Dispatchers.Main) { if (isAdded) { if (cal.get(Calendar.HOUR_OF_DAY) < 15) { dayMeals = mensaMenu.currentWeek.days[NotRetardedCalendar.getDayOfWeekIndex()].meals - mensaCardView.setDayHeading(activity!!.resources.getString(R.string.today_date, formatter.format(cal.time))) + mensaCardView.setDayHeading(getString(R.string.today_date, formatter.format(cal.time))) } else { dayMeals = mensaMenu.currentWeek.days[NotRetardedCalendar.getTomorrowWeekIndex()].meals cal.add(Calendar.DATE, 1) - mensaCardView.setDayHeading(activity!!.resources.getString(R.string.tomorrow_date, formatter.format(cal.time))) + mensaCardView.setDayHeading(getString(R.string.tomorrow_date, formatter.format(cal.time))) } if (dayMeals.size >= 2) { @@ -118,20 +119,15 @@ class HomeFragment : Fragment() { /** * add the current timetable to the home screen */ - private fun addTimeTable() = GlobalScope.launch(Dispatchers.Default) { - - withContext(Dispatchers.Main) { - - if (isAdded && TimetableController.timetable.isNotEmpty()) { - try { - val dayCardView = findNextDay(NotRetardedCalendar.getDayOfWeekIndex()) - binding.linLayoutHome.addView(dayCardView) - } catch (ex: Exception) { - Log.e(className, "could not load timetable", ex) // TODO send feedback - } + private fun addTimeTable() = lifecycleScope.launch(Dispatchers.Main) { + if (isAdded && TimetableController.timetable.isNotEmpty()) { + try { + val dayCardView = findNextDay(NotRetardedCalendar.getDayOfWeekIndex()) + binding.linLayoutHome.addView(dayCardView) + } catch (ex: Exception) { + Log.e(className, "could not load timetable", ex) // TODO send feedback } } - } /** @@ -142,7 +138,7 @@ class HomeFragment : Fragment() { * @return a DayCardView with all lessons added */ private fun findNextDay(startDayIndex: Int): DayCardView { - val dayCardView = DayCardView(context!!) + val dayCardView = DayCardView(requireContext()) var dayTimetable: TimetableDay? = null var dayIndexSearch = startDayIndex var weekIndexSearch = 0 diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/MensaFragment.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/MensaFragment.kt index 7e23e57..4aa8f97 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/MensaFragment.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/MensaFragment.kt @@ -27,8 +27,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.mosad.seil0.projectlaogai.R @@ -62,7 +62,7 @@ class MensaFragment : Fragment() { initActions() // init actions - GlobalScope.launch(Dispatchers.Default) { + lifecycleScope.launch(Dispatchers.Default) { val dayCurrent = if(NotRetardedCalendar.getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar.getDayOfWeekIndex() // add the current and next week @@ -71,7 +71,7 @@ class MensaFragment : Fragment() { // show a info if there are no more menus if (binding.linLayoutMensa.childCount == 0) { - val txtViewInfo = TextViewInfo(context!!).set { + val txtViewInfo = TextViewInfo(requireContext()).set { txt = resources.getString(R.string.no_more_meals) } withContext(Dispatchers.Main) { binding.linLayoutMensa.addView(txtViewInfo) } @@ -84,13 +84,13 @@ class MensaFragment : Fragment() { * @param menusWeek menu of type MensaWeek you want to add * @param dayStart the first day of the week to add */ - private fun addWeek(menusWeek: MensaWeek, dayStart: Int) = GlobalScope.launch(Dispatchers.Default) { + private fun addWeek(menusWeek: MensaWeek, dayStart: Int) = lifecycleScope.launch(Dispatchers.Default) { withContext(Dispatchers.Main) { // only add the days dayStart to Fri since the mensa is closed on Sat/Sun for (dayIndex in dayStart..4) { var helpMeal = MealLinearLayout(context) - val dayCardView = DayCardView(context!!) + val dayCardView = DayCardView(requireContext()) if(menusWeek.days[dayIndex].meals.isNotEmpty()) dayCardView.setDayHeading(menusWeek.days[dayIndex].meals[0].day) @@ -127,8 +127,8 @@ class MensaFragment : Fragment() { /** * refresh the mensa cache and update the mensa screen */ - private fun updateMensaScreen() = GlobalScope.launch(Dispatchers.Default) { - CacheController.updateMensaMenu(context!!).join() // blocking since we want the new data + private fun updateMensaScreen() = lifecycleScope.launch(Dispatchers.Default) { + CacheController.updateMensaMenu(requireContext()).join() // blocking since we want the new data withContext(Dispatchers.Main) { // remove all menus from the layout @@ -145,7 +145,7 @@ class MensaFragment : Fragment() { // show a info if there are no more menus if (binding.linLayoutMensa.childCount == 0) { - val txtViewInfo = TextViewInfo(context!!).set { + val txtViewInfo = TextViewInfo(requireContext()).set { txt = resources.getString(R.string.no_more_meals) } binding.linLayoutMensa.addView(txtViewInfo) diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/SettingsFragment.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/SettingsFragment.kt index 9a10674..cac921e 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/SettingsFragment.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/SettingsFragment.kt @@ -22,21 +22,24 @@ package org.mosad.seil0.projectlaogai.fragments +//import com.afollestad.aesthetic.Aesthetic import android.os.Bundle import android.util.TypedValue import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import com.afollestad.aesthetic.Aesthetic +import androidx.lifecycle.lifecycleScope import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.WhichButton import com.afollestad.materialdialogs.actions.getActionButton -import com.afollestad.materialdialogs.color.colorChooser import com.afollestad.materialdialogs.list.listItemsMultiChoice import com.afollestad.materialdialogs.list.listItemsSingleChoice import de.psdev.licensesdialog.LicensesDialog -import kotlinx.coroutines.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.joinAll +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.mosad.seil0.projectlaogai.BuildConfig import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.controller.GradesController @@ -50,7 +53,6 @@ import org.mosad.seil0.projectlaogai.uicomponents.dialogs.CourseSelectionDialog import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoadingDialog import org.mosad.seil0.projectlaogai.uicomponents.dialogs.LoginDialog import org.mosad.seil0.projectlaogai.util.DataTypes -import java.util.* /** * The settings controller class @@ -86,20 +88,20 @@ class SettingsFragment : Fragment() { binding.switchBuffet.isChecked = Preferences.showBuffet // init switch val outValue = TypedValue() - activity!!.theme.resolveAttribute(R.attr.themeName, outValue, true) + requireActivity().theme.resolveAttribute(R.attr.themeName, outValue, true) when(outValue.string) { "light" -> { - binding.switchBuffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryLight, activity!!.theme)) + binding.switchBuffet.setTextColor(requireActivity().resources.getColor(R.color.textPrimaryLight, requireActivity().theme)) selectedTheme = DataTypes.Theme.Light selectedTheme.string = resources.getString(R.string.themeLight) } "dark" -> { - binding.switchBuffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryDark, activity!!.theme)) + binding.switchBuffet.setTextColor(requireActivity().resources.getColor(R.color.textPrimaryDark, requireActivity().theme)) selectedTheme = DataTypes.Theme.Dark selectedTheme.string = resources.getString(R.string.themeDark) } "black" -> { - binding.switchBuffet.setTextColor(activity!!.resources.getColor(R.color.textPrimaryDark, activity!!.theme)) + binding.switchBuffet.setTextColor(requireActivity().resources.getColor(R.color.textPrimaryDark, requireActivity().theme)) selectedTheme = DataTypes.Theme.Black selectedTheme.string = resources.getString(R.string.themeBlack) } @@ -113,7 +115,7 @@ class SettingsFragment : Fragment() { private fun initActions() { binding.linLayoutUser.setOnClickListener { // open a new dialog - LoginDialog(context!!) + LoginDialog(requireContext()) .positiveButton { EncryptedPreferences.saveCredentials(email, password, context) } @@ -129,13 +131,13 @@ class SettingsFragment : Fragment() { } binding.linLayoutCourse.setOnClickListener { - CourseSelectionDialog(context!!).show { + CourseSelectionDialog(requireContext()).show { list = coursesList.map { it.courseName } listItems { val loadingDialog = LoadingDialog(context) loadingDialog.show() - GlobalScope.launch(Dispatchers.Default) { + lifecycleScope.launch(Dispatchers.Default) { Preferences.saveCourse(context, coursesList[selectedIndex]) // save the course // update current & next weeks timetable @@ -164,7 +166,7 @@ class SettingsFragment : Fragment() { } } - MaterialDialog(context!!).show { + MaterialDialog(requireContext()).show { title(R.string.manage_lessons) positiveButton(R.string.delete) negativeButton(R.string.cancel) @@ -182,7 +184,7 @@ class SettingsFragment : Fragment() { binding.linLayoutAbout.setOnClickListener { // open a new info dialog - MaterialDialog(context!!) + MaterialDialog(requireContext()) .title(R.string.about_dialog_heading) .message(R.string.about_dialog_text) .show() @@ -191,7 +193,7 @@ class SettingsFragment : Fragment() { binding.linLayoutLicence.setOnClickListener { // do the theme magic, as the lib's theme support is broken val outValue = TypedValue() - context!!.theme.resolveAttribute(R.attr.themeName, outValue, true) + requireContext().theme.resolveAttribute(R.attr.themeName, outValue, true) val dialogCss = when (outValue.string) { "light" -> R.string.license_dialog_style_light @@ -204,7 +206,7 @@ class SettingsFragment : Fragment() { } // open a new license dialog - LicensesDialog.Builder(context!!) + LicensesDialog.Builder(requireContext()) .setNotices(R.raw.notices) .setTitle(R.string.licenses) .setIncludeOwnLicense(true) @@ -214,67 +216,67 @@ class SettingsFragment : Fragment() { .show() } - binding.linLayoutTheme.setOnClickListener { - val themes = listOf( - resources.getString(R.string.themeLight), - resources.getString(R.string.themeDark), - resources.getString(R.string.themeBlack) - ) +// binding.linLayoutTheme.setOnClickListener { +// val themes = listOf( +// resources.getString(R.string.themeLight), +// resources.getString(R.string.themeDark), +// resources.getString(R.string.themeBlack) +// ) +// +// MaterialDialog(requireContext()).show { +// title(R.string.theme) +// listItemsSingleChoice(items = themes, initialSelection = selectedTheme.ordinal) { _, index, _ -> +// Aesthetic.config { +// when (index) { +// 0 -> activityTheme(R.style.AppTheme_Light) +// 1 -> activityTheme(R.style.AppTheme_Dark) +// 2 -> activityTheme(R.style.AppTheme_Black) +// else -> activityTheme(R.style.AppTheme_Light) +// } +// apply() +// } +// } +// } +// } - MaterialDialog(context!!).show { - title(R.string.theme) - listItemsSingleChoice(items = themes, initialSelection = selectedTheme.ordinal) { _, index, _ -> - Aesthetic.config { - when (index) { - 0 -> activityTheme(R.style.AppTheme_Light) - 1 -> activityTheme(R.style.AppTheme_Dark) - 2 -> activityTheme(R.style.AppTheme_Black) - else -> activityTheme(R.style.AppTheme_Light) - } - apply() - } - } - } - } +// binding.linLayoutPrimaryColor.setOnClickListener { +// // open a new color chooser dialog +// MaterialDialog(requireContext()) +// .colorChooser(DataTypes().primaryColors, allowCustomArgb = true, initialSelection = Preferences.colorPrimary) { _, color -> +// binding.viewPrimaryColor.setBackgroundColor(color) +// Aesthetic.config { +// colorPrimary(color) +// colorPrimaryDark(color) +// apply() +// } +// Preferences.saveColorPrimary(requireContext(), color) +// } +// .show { +// title(R.string.primary_color) +// positiveButton(R.string.select) +// getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent) +// } +// +// } - binding.linLayoutPrimaryColor.setOnClickListener { - // open a new color chooser dialog - MaterialDialog(context!!) - .colorChooser(DataTypes().primaryColors, allowCustomArgb = true, initialSelection = Preferences.colorPrimary) { _, color -> - binding.viewPrimaryColor.setBackgroundColor(color) - Aesthetic.config { - colorPrimary(color) - colorPrimaryDark(color) - apply() - } - Preferences.saveColorPrimary(context!!, color) - } - .show { - title(R.string.primary_color) - positiveButton(R.string.select) - getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent) - } - - } - - binding.linLayoutAccentColor.setOnClickListener { - // open a new color chooser dialog - MaterialDialog(context!!) - .colorChooser(DataTypes().accentColors, allowCustomArgb = true, initialSelection = Preferences.colorAccent) { _, color -> - binding.viewAccentColor.setBackgroundColor(color) - Aesthetic.config { - colorAccent(color) - apply() - } - - Preferences.saveColorAccent(context!!, color) - } - .show{ - title(R.string.accent_color) - positiveButton(R.string.select) - getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent) - } - } +// binding.linLayoutAccentColor.setOnClickListener { +// // open a new color chooser dialog +// MaterialDialog(requireContext()) +// .colorChooser(DataTypes().accentColors, allowCustomArgb = true, initialSelection = Preferences.colorAccent) { _, color -> +// binding.viewAccentColor.setBackgroundColor(color) +// Aesthetic.config { +// colorAccent(color) +// apply() +// } +// +// Preferences.saveColorAccent(requireContext(), color) +// } +// .show{ +// title(R.string.accent_color) +// positiveButton(R.string.select) +// getActionButton(WhichButton.POSITIVE).updateTextColor(Preferences.colorAccent) +// } +// } binding.linLayoutGradesSync.setOnClickListener { val items = resources.getStringArray(R.array.syncInterval).toList() @@ -286,7 +288,7 @@ class SettingsFragment : Fragment() { else -> 0 } - MaterialDialog(context!!) + MaterialDialog(requireContext()) .title(R.string.grades_sync) .listItemsSingleChoice(items = items, initialSelection = initial) { _, index, _ -> val interval = when (index) { @@ -297,8 +299,8 @@ class SettingsFragment : Fragment() { else -> 0 } - Preferences.saveGradesSync(context!!, interval) - GradesController.updateBackgroundSync(context!!) + Preferences.saveGradesSync(requireContext(), interval) + GradesController.updateBackgroundSync(requireContext()) binding.textGradesSyncDesc.text = if (Preferences.gradesSyncInterval == 0) { resources.getString(R.string.grades_sync_desc_never) @@ -309,7 +311,7 @@ class SettingsFragment : Fragment() { } binding.switchBuffet.setOnClickListener { - Preferences.saveShowBuffet(context!!, binding.switchBuffet.isChecked) + Preferences.saveShowBuffet(requireContext(), binding.switchBuffet.isChecked) } } diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/TimetableFragment.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/TimetableFragment.kt index b0416e8..e163d45 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/TimetableFragment.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/fragments/TimetableFragment.kt @@ -27,6 +27,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import kotlinx.coroutines.* import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.controller.cache.TimetableController @@ -61,7 +62,7 @@ class TimetableFragment : Fragment() { if (timetable.size > 1 && timetable[0].days.isNotEmpty() && timetable[1].days.isNotEmpty()) { initTimetable() } else { - val txtViewInfo = TextViewInfo(context!!).set { + val txtViewInfo = TextViewInfo(requireContext()).set { txt = resources.getString(R.string.timetable_generic_error) }.showImage() binding.linLayoutTimetable.addView(txtViewInfo) @@ -74,13 +75,13 @@ class TimetableFragment : Fragment() { private fun initActions() { binding.refreshLayoutTimetable.setOnRefreshListener { - runBlocking { TimetableController.update(context!!).joinAll() } + runBlocking { TimetableController.update(requireContext()).joinAll() } reloadTimetableUI() } // show the AddLessonDialog if the ftaBtn is clicked binding.faBtnAddSubject.setOnClickListener { - AddSubjectDialog(context!!) + AddSubjectDialog(requireContext()) .positiveButton { TimetableController.addSubject(selectedCourse, selectedSubject, context) runBlocking { reloadTimetableUI() } @@ -101,16 +102,16 @@ class TimetableFragment : Fragment() { /** * add the current and next weeks lessons */ - private fun initTimetable() = GlobalScope.launch(Dispatchers.Default) { + private fun initTimetable() = lifecycleScope.launch(Dispatchers.Default) { val currentDayIndex = NotRetardedCalendar.getDayOfWeekIndex() addTimetableWeek(currentDayIndex, 5, 0).join() // add current week addTimetableWeek(0, currentDayIndex - 1, 1) // add next week } - private fun addTimetableWeek(dayBegin: Int, dayEnd: Int, week: Int) = GlobalScope.launch(Dispatchers.Main) { + private fun addTimetableWeek(dayBegin: Int, dayEnd: Int, week: Int) = lifecycleScope.launch(Dispatchers.Main) { for (dayIndex in dayBegin..dayEnd) { - val dayCardView = DayCardView(context!!) + val dayCardView = DayCardView(requireContext()) // some wired calendar magic, calculate the correct date to be shown // ((timetable week - current week * 7) + (dayIndex - dayIndex of current week) @@ -128,7 +129,7 @@ class TimetableFragment : Fragment() { /** * clear linLayout_Timetable, add the updated timetable */ - private fun reloadTimetableUI() = GlobalScope.launch(Dispatchers.Default) { + private fun reloadTimetableUI() = lifecycleScope.launch(Dispatchers.Default) { withContext(Dispatchers.Main) { // remove all lessons from the layout binding.linLayoutTimetable.removeAllViews() diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/uicomponents/TextViewInfo.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/uicomponents/TextViewInfo.kt index f62c1ee..2ba5100 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/uicomponents/TextViewInfo.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/uicomponents/TextViewInfo.kt @@ -41,7 +41,6 @@ class TextViewInfo(context: Context?): AppCompatTextView(context!!) { init { params.setMargins(0,200,0,0) - } fun set(func: TextViewInfo.() -> Unit): TextViewInfo = apply { diff --git a/build.gradle b/build.gradle index 7bbbd88..a373996 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.4.20' + ext.kotlin_version = '1.7.20' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' + classpath 'com.android.tools.build:gradle:7.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong @@ -18,7 +18,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } }