anko code removed, coroutines are now used for asynchronous functions

* constraintlayout 2.0.0-beta3 -> 2.0.0-beta4
* material-components-android 1.0.0 -> 1.1.0
* this is the first release candidate for version 0.5.1
This commit is contained in:
Jannik 2020-02-04 19:58:07 +01:00
parent 2d497d1a96
commit 2cb4b72369
Signed by: Seil0
GPG Key ID: E8459F3723C52C24
10 changed files with 118 additions and 87 deletions

View File

@ -1,7 +1,5 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
@ -12,8 +10,8 @@ android {
applicationId "org.mosad.seil0.projectlaogai"
minSdkVersion 23
targetSdkVersion 29
versionCode 14
versionName "0.5.0"
versionCode 15
versionName "0.5.190"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "build_time", buildTime()
setProperty("archivesBaseName", "projectlaogai-$versionName")
@ -49,12 +47,12 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation 'org.jetbrains.anko:anko-commons:0.10.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta3'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta4'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.afollestad:aesthetic:1.0.0-beta05'
implementation 'com.afollestad.material-dialogs:core:3.1.1'

View File

@ -52,7 +52,6 @@ import kotlin.system.measureTimeMillis
/**
* TODO save the current fragment to show it when the app is restarted
* TODO since anko is dead, we should use coroutines
*/
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {

View File

@ -27,6 +27,10 @@ import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonParser
import com.google.gson.reflect.TypeToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cCourse
import org.mosad.seil0.projectlaogai.hsoparser.Course
import org.mosad.seil0.projectlaogai.hsoparser.MensaMenu
@ -53,7 +57,7 @@ class CacheController(cont: 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 - mensaMenu.meta.updateTime) > 86400) {
println("update mensa blocking")
TCoRAPIController.getMensa(context).get()
GlobalScope.launch(Dispatchers.Default) { TCoRAPIController.getMensa(context).join() }
}
// check if we need to update the timetables before displaying them
@ -61,23 +65,29 @@ class CacheController(cont: Context) {
cal.time = Date(timetables[0].meta.updateTime * 1000)
// if a) it`s monday and the last cache update was not on a sunday or b) the cache is older than 24hr, update blocking
if((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - timetables[0].meta.updateTime) > 86400) {
if ((currentDay == Calendar.MONDAY && cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) || (currentTime - timetables[0].meta.updateTime) > 86400) {
println("updating timetable after sunday!")
val jobA = TCoRAPIController.getTimetable(cCourse.courseName, 0, context)
val jobB = TCoRAPIController.getTimetable(cCourse.courseName, 1, context)
jobA.get()
jobB.get()
GlobalScope.launch(Dispatchers.Default) {
val threads = listOf(
TCoRAPIController.getTimetable(cCourse.courseName, 0, context),
TCoRAPIController.getTimetable(cCourse.courseName, 1, context)
)
threads.joinAll()
}
TCoRAPIController.getTimetable(cCourse.courseName, 0, context)
TCoRAPIController.getTimetable(cCourse.courseName, 1, context)
}
// check if an update is necessary, not blocking
if(currentTime - PreferencesController.coursesCacheTime > 86400)
if (currentTime - PreferencesController.coursesCacheTime > 86400)
TCoRAPIController.getCoursesList(context)
if(currentTime - PreferencesController.mensaCacheTime > 10800)
if (currentTime - PreferencesController.mensaCacheTime > 10800)
TCoRAPIController.getMensa(context)
if(currentTime - PreferencesController.timetableCacheTime > 10800) {
if (currentTime - PreferencesController.timetableCacheTime > 10800) {
TCoRAPIController.getTimetable(cCourse.courseName, 0, context)
TCoRAPIController.getTimetable(cCourse.courseName, 1, context)
}
@ -99,13 +109,16 @@ class CacheController(cont: Context) {
// make sure the file exists
if (!file.exists())
TCoRAPIController.getCoursesList(context).get()
GlobalScope.launch(Dispatchers.Default) { TCoRAPIController.getCoursesList(context).join() }
val fileReader = FileReader(file)
val bufferedReader = BufferedReader(fileReader)
val coursesObject = JsonParser.parseString(bufferedReader.readLine()).asJsonObject
coursesList = Gson().fromJson(coursesObject.getAsJsonArray("courses"), object : TypeToken<List<Course>>() {}.type)
coursesList = Gson().fromJson(
coursesObject.getAsJsonArray("courses"),
object : TypeToken<List<Course>>() {}.type
)
}
/**
@ -116,9 +129,8 @@ class CacheController(cont: Context) {
val file = File(context.filesDir, "mensa.json")
// make sure the file exists
if (!file.exists()) {
TCoRAPIController.getMensa(context).get()
}
if (!file.exists())
GlobalScope.launch(Dispatchers.Default) { TCoRAPIController.getMensa(context).join() }
val fileReader = FileReader(file)
val bufferedReader = BufferedReader(fileReader)
@ -136,8 +148,11 @@ class CacheController(cont: Context) {
val file = File(context.filesDir, "timetable-$courseName-$week.json")
// make sure the file exists
if (!file.exists())
TCoRAPIController.getTimetable(courseName, week, context).get()
if (!file.exists()) {
GlobalScope.launch(Dispatchers.Default) {
TCoRAPIController.getTimetable(courseName, week, context).join()
}
}
val fileReader = FileReader(file)
val bufferedReader = BufferedReader(fileReader)

View File

@ -24,7 +24,7 @@ package org.mosad.seil0.projectlaogai.controller
import android.content.Context
import android.util.Log
import org.jetbrains.anko.doAsync
import kotlinx.coroutines.*
import org.json.JSONObject
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.coursesCacheTime
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.mensaCacheTime
@ -44,7 +44,7 @@ class TCoRAPIController {
/**
* get the json object from tcor api and write it as file (cache)
*/
fun getCoursesList(context: Context) = doAsync {
fun getCoursesList(context: Context) = GlobalScope.launch {
try {
val url = URL("$tcorBaseURL/courseList")
val file = File(context.filesDir, "courses.json")
@ -53,9 +53,11 @@ class TCoRAPIController {
val coursesObject = JSONObject(url.readText()) //JSONObject(inReader.readLine())
// write the json object to a file
val writer = BufferedWriter(FileWriter(file))
writer.write(coursesObject.toString())
writer.close()
withContext(Dispatchers.IO) {
val writer = BufferedWriter(FileWriter(file))
writer.write(coursesObject.toString())
writer.close()
}
// update cache time
coursesCacheTime = System.currentTimeMillis() / 1000
@ -69,7 +71,7 @@ class TCoRAPIController {
/**
* get the json object from tcor api and write it as file (cache)
*/
fun getMensa(context: Context) = doAsync {
fun getMensa(context: Context) = GlobalScope.launch {
try {
val url = URL("$tcorBaseURL/mensamenu")
val file = File(context.filesDir, "mensa.json")
@ -78,9 +80,11 @@ class TCoRAPIController {
val mensaObject = JSONObject(url.readText()) //JSONObject(inReader.readLine())
// write the json object to a file
val writer = BufferedWriter(FileWriter(file))
writer.write(mensaObject.toString())
writer.close()
withContext(Dispatchers.IO) {
val writer = BufferedWriter(FileWriter(file))
writer.write(mensaObject.toString())
writer.close()
}
// update cache time
mensaCacheTime = System.currentTimeMillis() / 1000
@ -94,18 +98,20 @@ class TCoRAPIController {
/**
* get the json object from tcor api and write it as file (cache)
*/
fun getTimetable(courseName: String, week: Int, context: Context) = doAsync {
fun getTimetable(courseName: String, week: Int, context: Context) = GlobalScope.launch {
try {
val url = URL("$tcorBaseURL/timetable?courseName=$courseName&week=$week")
val file = File(context.filesDir, "timetable-$courseName-$week.json")
// read data from the API
val mensaObject = JSONObject(url.readText()) //JSONObject(inReader.readLine())
val timetableObject = JSONObject(url.readText()) //JSONObject(inReader.readLine())
// write the json object to a file
val writer = BufferedWriter(FileWriter(file))
writer.write(mensaObject.toString())
writer.close()
withContext(Dispatchers.IO) {
val writer = BufferedWriter(FileWriter(file))
writer.write(timetableObject.toString())
writer.close()
}
// update cache time
timetableCacheTime = System.currentTimeMillis() / 1000

View File

@ -31,8 +31,10 @@ import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_home.*
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaMenu
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.timetables
@ -54,11 +56,10 @@ class HomeFragment : Fragment() {
private val formatter = SimpleDateFormat("E dd.MM", Locale.getDefault())
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_home, container, false)
addMensaMenu().get()
addTimeTable().get()
addMensaMenu()
addTimeTable()
// Inflate the layout for this fragment
return view
@ -67,13 +68,13 @@ class HomeFragment : Fragment() {
/**
* add the current mensa meal to the home screens
*/
private fun addMensaMenu() = doAsync {
private fun addMensaMenu() = GlobalScope.launch(Dispatchers.Default) {
var dayMeals: ArrayList<Meal>
val cal = Calendar.getInstance()
val mensaCardView = DayCardView(context!!)
uiThread {
withContext(Dispatchers.Main) {
if (isAdded) {
if (cal.get(Calendar.HOUR_OF_DAY) < 15) {
@ -117,9 +118,9 @@ class HomeFragment : Fragment() {
/**
* add the current timetable to the home screen
*/
private fun addTimeTable() = doAsync {
private fun addTimeTable() = GlobalScope.launch(Dispatchers.Default) {
uiThread {
withContext(Dispatchers.Main) {
if (isAdded && timetables.isNotEmpty()) {
try {
@ -140,7 +141,7 @@ class HomeFragment : Fragment() {
* @param startDayIndex the day index you want to start searching
* @return a DayCardView with all lessons added
*/
private fun findNextDay(startDayIndex: Int) : DayCardView {
private fun findNextDay(startDayIndex: Int): DayCardView {
val dayCardView = DayCardView(context!!)
var dayTimetable: TimetableDay? = null
var dayIndexSearch = startDayIndex
@ -151,7 +152,7 @@ class HomeFragment : Fragment() {
dayTimetable = timetables[weekIndexSearch].timetable.days[dayIndex]
// some wired calendar magic, calculate the correct date to be shown ((timetable week - current week * 7) + (dayIndex - dayIndex of current week)
val daysToAdd =(timetables[weekIndexSearch].meta.weekNumberYear - NotRetardedCalendar.getWeekOfYear()) * 7 + (dayIndex - NotRetardedCalendar.getDayOfWeekIndex())
val daysToAdd = (timetables[weekIndexSearch].meta.weekNumberYear - NotRetardedCalendar.getWeekOfYear()) * 7 + (dayIndex - NotRetardedCalendar.getDayOfWeekIndex())
dayCardView.addTimetableDay(dayTimetable, daysToAdd)
// if there are no lessons don't show the dayCardView
@ -179,7 +180,7 @@ class HomeFragment : Fragment() {
noLesson.textSize = 18.0F
noLesson.setTypeface(null, Typeface.BOLD)
noLesson.textAlignment = View.TEXT_ALIGNMENT_CENTER
noLesson.setPadding(7,7,7,7)
noLesson.setPadding(7, 7, 7, 7)
return noLesson
}

View File

@ -28,8 +28,10 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_mensa.*
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.CacheController
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaMenu
@ -53,12 +55,14 @@ class MensaFragment : Fragment() {
// init actions
refreshAction()
// add the current week (week starts on sunday)
val dayCurrent = if(NotRetardedCalendar.getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar.getDayOfWeekIndex()
addWeek(mensaMenu.currentWeek, dayCurrent).get()
GlobalScope.launch(Dispatchers.Default) {
val dayCurrent = if(NotRetardedCalendar.getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar.getDayOfWeekIndex()
addWeek(mensaMenu.currentWeek, dayCurrent).join()
// add the next week
addWeek(mensaMenu.nextWeek, 0)
}
// add the next week
addWeek(mensaMenu.nextWeek, 0)
// TODO should we show a info if there is no more food this & next week?
@ -70,9 +74,9 @@ 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) = doAsync {
private fun addWeek(menusWeek: MensaWeek, dayStart: Int) = GlobalScope.launch(Dispatchers.Default) {
uiThread {
withContext(Dispatchers.Main) {
// only add the days dayStart to Fri since the mensa is closed on Sat/Sun
for (dayIndex in dayStart..4) {
@ -105,8 +109,8 @@ class MensaFragment : Fragment() {
/**
* initialize the refresh action
*/
private fun refreshAction() = doAsync {
uiThread {
private fun refreshAction() = GlobalScope.launch(Dispatchers.Default) {
withContext(Dispatchers.Main) {
// set the refresh listener
refreshLayout_Mensa.setOnRefreshListener {
updateMensaScreen()
@ -118,18 +122,18 @@ class MensaFragment : Fragment() {
/**
* refresh the mensa cache and update the mensa screen
*/
private fun updateMensaScreen() = doAsync {
private fun updateMensaScreen() = GlobalScope.launch(Dispatchers.Default) {
// update the cache
TCoRAPIController.getMensa(context!!).get() // blocking since we want the new data
TCoRAPIController.getMensa(context!!).join() // blocking since we want the new data
CacheController.readMensa(context!!)
uiThread {
withContext(Dispatchers.Main) {
// remove all menus from the layout
linLayout_Mensa.removeAllViews()
// add the refreshed menus
val dayCurrent = if (NotRetardedCalendar.getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar.getDayOfWeekIndex()
addWeek(mensaMenu.currentWeek, dayCurrent).get()
addWeek(mensaMenu.currentWeek, dayCurrent).join()
// add the next week
addWeek(mensaMenu.nextWeek, 0)

View File

@ -39,8 +39,7 @@ import com.afollestad.materialdialogs.list.listItems
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import de.psdev.licensesdialog.LicensesDialog
import kotlinx.android.synthetic.main.fragment_settings.*
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import kotlinx.coroutines.*
import org.mosad.seil0.projectlaogai.BuildConfig
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.CacheController
@ -54,7 +53,6 @@ import org.mosad.seil0.projectlaogai.controller.TCoRAPIController
import org.mosad.seil0.projectlaogai.hsoparser.DataTypes
import java.util.*
/**
* The settings controller class
* contains all needed parts to display and the settings screen
@ -245,17 +243,20 @@ class SettingsFragment : Fragment() {
.customView(R.layout.dialog_loading)
dialog.show()
doAsync {
GlobalScope.launch(Dispatchers.Default) {
PreferencesController.saveCourse(context, coursesList[index]) // save the course
// update current & next weeks timetable
TCoRAPIController.getTimetable(cCourse.courseName, 0, context).get() // blocking since we want the new data
TCoRAPIController.getTimetable(cCourse.courseName, 1, context).get() // blocking since we want the new data
val threads = listOf(
TCoRAPIController.getTimetable(cCourse.courseName, 0, context),
TCoRAPIController.getTimetable(cCourse.courseName, 1, context)
)
threads.joinAll() // blocking since we want the new data
CacheController.readTimetable(cCourse.courseName, 0, context)
CacheController.readTimetable(cCourse.courseName, 1, context)
uiThread {
withContext(Dispatchers.Main) {
dialog.dismiss()
txtView_Course.text = cCourse.courseName // update txtView
}

View File

@ -31,8 +31,7 @@ import androidx.fragment.app.Fragment
import com.afollestad.materialdialogs.MaterialDialog
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.android.synthetic.main.fragment_timetable.*
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import kotlinx.coroutines.*
import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.CacheController
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.timetables
@ -74,9 +73,9 @@ class TimeTableFragment : Fragment() {
/**
* initialize the actions
*/
private fun initActions() = doAsync {
private fun initActions() = GlobalScope.launch(Dispatchers.Default) {
uiThread {
withContext(Dispatchers.Main) {
refreshLayout_Timetable.setOnRefreshListener {
updateTimetableScreen()
}
@ -104,18 +103,18 @@ class TimeTableFragment : Fragment() {
/**
* add the current and next weeks lessons
*/
private fun addInitWeeks() = doAsync {
private fun addInitWeeks() = GlobalScope.launch(Dispatchers.Default) {
val currentDayIndex = NotRetardedCalendar.getDayOfWeekIndex()
addWeek(currentDayIndex, 5, 0).get() // add current week
addWeek(currentDayIndex, 5, 0).join() // add current week
addWeek(0, currentDayIndex - 1, 1) // add next week
}
private fun addWeek(startDayIndex: Int, dayEndIndex: Int, weekIndex: Int) = doAsync {
private fun addWeek(startDayIndex: Int, dayEndIndex: Int, weekIndex: Int) = GlobalScope.launch(Dispatchers.Default) {
val timetable = timetables[weekIndex].timetable
val timetableMeta = timetables[weekIndex].meta
uiThread {
withContext(Dispatchers.Main) {
for (dayIndex in startDayIndex..dayEndIndex) {
val dayCardView = DayCardView(context!!)
@ -132,15 +131,18 @@ class TimeTableFragment : Fragment() {
}
}
private fun updateTimetableScreen() = doAsync {
private fun updateTimetableScreen() = GlobalScope.launch(Dispatchers.Default) {
// update the cache
TCoRAPIController.getTimetable(cCourse.courseName, 0, context!!).get() // blocking since we want the new data
TCoRAPIController.getTimetable(cCourse.courseName, 1, context!!).get() // blocking since we want the new data
val threads = listOf(
TCoRAPIController.getTimetable(cCourse.courseName, 0, context!!),
TCoRAPIController.getTimetable(cCourse.courseName, 1, context!!)
)
threads.joinAll() // blocking since we want the new data
CacheController.readTimetable(cCourse.courseName, 0, context!!)
CacheController.readTimetable(cCourse.courseName, 1, context!!)
uiThread {
withContext(Dispatchers.Main) {
// remove all menus from the layout
linLayout_Timetable.removeAllViews()
@ -148,7 +150,7 @@ class TimeTableFragment : Fragment() {
val dayIndex = NotRetardedCalendar.getDayOfWeekIndex()
// add current week
addWeek(dayIndex, 5, 0).get()
addWeek(dayIndex, 5, 0).join()
// add next week
addWeek(0, dayIndex - 1, 1)

View File

@ -19,8 +19,8 @@
<license>Apache Software License 2.0</license>
</notice>
<notice>
<name>anko</name>
<url>https://github.com/Kotlin/anko</url>
<name>kotlinx.coroutines</name>
<url>https://github.com/Kotlin/kotlinx.coroutines</url>
<copyright>Copyright JetBrains</copyright>
<license>Apache Software License 2.0</license>
</notice>

View File

@ -0,0 +1,5 @@
This release 0.5.1 is called "artistical Apollon".
* new: it's now possible to use App shortcuts for the timetable, mensa and moodle screen
* change: updated some libs, updated kotlin to 1.3.61
* change: the app was updated to use kotlin coroutines instead of anko for asynchronous work loads