From f3b7ff066dd4849ecaae6d940fb187fc8903185f Mon Sep 17 00:00:00 2001 From: Seil0 Date: Sun, 17 Mar 2019 18:12:36 +0100 Subject: [PATCH] added the tcor api * drastically improved loading times, closes #14 --- app/build.gradle | 4 +- .../mosad/seil0/projectlaogai/MainActivity.kt | 95 ++++-------- .../controller/CacheController.kt | 122 +++++++++++++++ .../{ => controller}/PreferencesController.kt | 69 +++++++-- .../controller/TCoRAPIController.kt | 96 ++++++++++++ .../projectlaogai/fragments/HomeFragment.kt | 30 ++-- .../projectlaogai/fragments/MensaFragment.kt | 18 +-- .../fragments/SettingsFragment.kt | 34 ++-- .../fragments/TimeTableFragment.kt | 11 +- .../projectlaogai/hsoparser/DataTypes.kt | 12 +- .../projectlaogai/hsoparser/MensaParser.kt | 78 ---------- .../hsoparser/TimeTableParser.kt | 146 ------------------ app/src/main/res/values/strings.xml | 7 +- 13 files changed, 364 insertions(+), 358 deletions(-) create mode 100644 app/src/main/java/org/mosad/seil0/projectlaogai/controller/CacheController.kt rename app/src/main/java/org/mosad/seil0/projectlaogai/{ => controller}/PreferencesController.kt (64%) create mode 100644 app/src/main/java/org/mosad/seil0/projectlaogai/controller/TCoRAPIController.kt delete mode 100644 app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/MensaParser.kt delete mode 100644 app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/TimeTableParser.kt diff --git a/app/build.gradle b/app/build.gradle index 7d69c03..a15baf9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,7 +13,7 @@ android { minSdkVersion 21 targetSdkVersion 28 versionCode 11 - versionName "0.3.90" + versionName "0.3.95" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { @@ -33,11 +33,11 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'com.google.android.material:material:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' - implementation 'org.jsoup:jsoup:1.11.3' implementation 'org.jetbrains.anko:anko-commons:0.10.8' implementation 'com.afollestad:aesthetic:1.0.0-beta05' implementation 'com.afollestad.material-dialogs:core:2.0.3' implementation 'com.afollestad.material-dialogs:color:2.0.3' + implementation 'com.google.code.gson:gson:2.8.5' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' 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 ca65d44..106ce21 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/MainActivity.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/MainActivity.kt @@ -32,29 +32,23 @@ import androidx.core.view.GravityCompat import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import com.afollestad.aesthetic.Aesthetic -import com.afollestad.materialdialogs.MaterialDialog import com.google.android.material.navigation.NavigationView import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.app_bar_main.* -import org.jetbrains.anko.doAsync -import org.jetbrains.anko.uiThread -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cColorAccent -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cColorPrimary -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cCourse -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cCourseTTLinkList -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableCurrentWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableNextWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cMenusCurrentWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cMenusNextWeek +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cColorAccent +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cColorPrimary +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cCourse +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.coursesCacheTime +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.mensaCacheTime +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.timetableCacheTime +import org.mosad.seil0.projectlaogai.controller.CacheController +import org.mosad.seil0.projectlaogai.controller.PreferencesController +import org.mosad.seil0.projectlaogai.controller.TCoRAPIController import org.mosad.seil0.projectlaogai.fragments.* -import org.mosad.seil0.projectlaogai.hsoparser.MensaParser -import org.mosad.seil0.projectlaogai.hsoparser.TimeTableParser import kotlin.system.measureTimeMillis class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener { - private val mensaParser = MensaParser() - private val timeTableParser = TimeTableParser() private var activeFragment: Fragment = HomeFragment() // the currently active fragment, home at the start override fun onCreate(savedInstanceState: Bundle?) { @@ -75,6 +69,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte colorAccent(Color.parseColor("#FF1744")) apply() } + + // TODO show a course selection } else { Aesthetic.config { colorPrimary(cColorPrimary) @@ -164,62 +160,31 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte * load the mensa menus of the current week */ private fun load() { - val menuLinkCurrentWeek = "https://www.swfr.de/de/essen-trinken/speiseplaene/mensa-offenburg/" // load the settings PreferencesController.load(this) // this must be finished before doing anything else - /** - * load mensa, course timetable and courselist from the swfr/hso website - * TODO make an API see https://git.mosad.xyz/Seil0/TheCitadelofRicks - */ - val time = measureTimeMillis { + val startupTime = measureTimeMillis { - /* getting the course list should be faster than the timetable, - * we need have time until the user opens the dialog - */ - doAsync { - cCourseTTLinkList = timeTableParser.getCourseTTLinks() + // get the cached files + val cache = CacheController(this) + cache.readStartCache(cCourse.courseName) + + // check if an update is necessary + val tcor = TCoRAPIController(this) + val currentTime = System.currentTimeMillis() / 1000 + + if(currentTime - coursesCacheTime > 86400) + tcor.getCoursesList() + + if(currentTime - mensaCacheTime > 10800) + tcor.getMensa() + + if(currentTime - timetableCacheTime > 10800) { + tcor.getTimetable(cCourse.courseName, 0) + tcor.getTimetable(cCourse.courseName, 1) } - - val jobMenusCurrentWeek = doAsync { - cMenusCurrentWeek = mensaParser.getMensaMenu(menuLinkCurrentWeek) - } - - val jobMenusNextWeek = doAsync { - cMenusNextWeek = mensaParser.getMensaMenu(mensaParser.getMenuLinkNextWeek(menuLinkCurrentWeek)) - } - - val jobTTCurrentWeek = doAsync { - try { - cTimeTableCurrentWeek = timeTableParser.getTimeTable(cCourse.courseLink) - timeTableParser.printTimeTableWeek(cTimeTableCurrentWeek) - } catch (e: Exception) { - - uiThread { - MaterialDialog(this@MainActivity) - .title(R.string.error) - .message(R.string.no_tt_error) - .show() - } - - e.stackTrace - } - } - - val jobTTNextWeek = doAsync { - try { - cTimeTableNextWeek = timeTableParser.getTimeTable(cCourse.courseLink.replace("week=0","week=1")) - } catch (e: Exception) { - e.stackTrace - } - } - - jobMenusCurrentWeek.get() - jobMenusNextWeek.get() - jobTTCurrentWeek.get() - jobTTNextWeek.get() } - println("Completed in $time ms") + println("Completed in $startupTime ms") } } diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/controller/CacheController.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/CacheController.kt new file mode 100644 index 0000000..6bfd192 --- /dev/null +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/CacheController.kt @@ -0,0 +1,122 @@ +/** + * ProjectLaogai + * + * Copyright 2019 + * + * 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.controller + +import android.content.Context +import com.google.gson.Gson +import com.google.gson.JsonParser +import org.mosad.seil0.projectlaogai.hsoparser.Course +import org.mosad.seil0.projectlaogai.hsoparser.MensaWeek +import org.mosad.seil0.projectlaogai.hsoparser.TimetableWeek +import java.io.BufferedReader +import java.io.File +import java.io.FileReader +import com.google.gson.reflect.TypeToken + +class CacheController(cont: Context) { + + private val context = cont + + companion object { + var coursesList = ArrayList() + var mensaCurrentWeek = MensaWeek() + var mensaNextWeek = MensaWeek() + var timetables = ArrayList() + } + + /** + * read coursesList, mensa (current and next week), timetable (current and next week) + * @param courseName the course name (e.g AI1) + */ + fun readStartCache(courseName: String) { + readCoursesList() + readMensa() + readTimetable(courseName, 0) + readTimetable(courseName, 1) + } + + /** + * read the courses list from the cached file + * add them to the coursesList object + */ + fun readCoursesList() { + val file = File(context.filesDir, "courses.json") + + // make sure the file exists + if (!file.exists()) + TCoRAPIController(context).getCoursesList().get() + + val fileReader = FileReader(file) + val bufferedReader = BufferedReader(fileReader) + val coursesObject = JsonParser().parse(bufferedReader.readLine()).asJsonObject + + coursesList = Gson().fromJson(coursesObject.getAsJsonArray("courses"), object : TypeToken>() {}.type) + } + + /** + * read current and next weeks mensa menus from the cached file + */ + fun readMensa() { + val file = File(context.filesDir, "mensa.json") + + // make sure the file exists + if (!file.exists()) { + TCoRAPIController(context).getMensa().get() + } + + + val fileReader = FileReader(file) + val bufferedReader = BufferedReader(fileReader) + val mensaObject = JsonParser().parse(bufferedReader.readLine()).asJsonObject + + val currentWeek = mensaObject.getAsJsonObject("currentWeek") + val nextWeek = mensaObject.getAsJsonObject("nextWeek") + + mensaCurrentWeek = Gson().fromJson(currentWeek, MensaWeek().javaClass) + mensaNextWeek = Gson().fromJson(nextWeek, MensaWeek().javaClass) + } + + /** + * read the weeks timetable from the cached file + * @param courseName the course name (e.g AI1) + * @param week the week to read (0 for the current and so on) + */ + fun readTimetable(courseName: String, week: Int) { + val file = File(context.filesDir, "timetable-$courseName-$week.json") + + // make sure the file exists + if (!file.exists()) + TCoRAPIController(context).getTimetable(courseName, week).get() + + val fileReader = FileReader(file) + val bufferedReader = BufferedReader(fileReader) + val timetableObject = JsonParser().parse(bufferedReader.readLine()).asJsonObject + + // make sure you add the single weeks in the exact order! + if (timetables.size == week) { + timetables.add(Gson().fromJson(timetableObject.getAsJsonObject("timetable"), TimetableWeek().javaClass)) + } else if (timetables.size >= week) { + timetables[week] = Gson().fromJson(timetableObject.getAsJsonObject("timetable"), TimetableWeek().javaClass) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/PreferencesController.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/PreferencesController.kt similarity index 64% rename from app/src/main/java/org/mosad/seil0/projectlaogai/PreferencesController.kt rename to app/src/main/java/org/mosad/seil0/projectlaogai/controller/PreferencesController.kt index 040f718..35bb398 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/PreferencesController.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/PreferencesController.kt @@ -20,14 +20,13 @@ * */ -package org.mosad.seil0.projectlaogai +package org.mosad.seil0.projectlaogai.controller import android.content.Context import android.graphics.Color import org.jetbrains.anko.defaultSharedPreferences +import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.hsoparser.Course -import org.mosad.seil0.projectlaogai.hsoparser.MealWeek -import org.mosad.seil0.projectlaogai.hsoparser.TimeTable /** * The PreferencesController class @@ -36,11 +35,9 @@ import org.mosad.seil0.projectlaogai.hsoparser.TimeTable class PreferencesController { companion object { - var cCourseTTLinkList = ArrayList() - var cMenusCurrentWeek = MealWeek() - var cMenusNextWeek = MealWeek() - var cTimeTableCurrentWeek = TimeTable() - var cTimeTableNextWeek = TimeTable() + var coursesCacheTime: Long = 0 + var mensaCacheTime: Long = 0 + var timetableCacheTime: Long = 0 var cColorPrimary: Int = Color.BLACK var cColorAccent: Int = Color.BLACK var cCourse = Course("https://www.hs-offenburg.de/index.php?id=6627&class=class&iddV=DA64F6FE-9DDB-429E-A677-05D0D40CB636&week=0", "AI3") @@ -48,9 +45,23 @@ class PreferencesController { // the save function fun save(context: Context) { - //println(cCourse.courseLink) - // save the course val sharedPref = context.defaultSharedPreferences + + // save the update times (cache) + with (sharedPref.edit()) { + putLong(context.getString(R.string.save_key_coursesCacheTime), + coursesCacheTime + ) + putLong(context.getString(R.string.save_key_mensaCacheTime), + mensaCacheTime + ) + putLong(context.getString(R.string.save_key_timetableCacheTime), + timetableCacheTime + ) + apply() + } + + // save the course with (sharedPref.edit()) { putString(context.getString(R.string.save_key_course), cCourse.courseName) putString(context.getString(R.string.save_key_courseTTLink), cCourse.courseLink) @@ -59,19 +70,25 @@ class PreferencesController { // save the primary color with (sharedPref.edit()) { - putInt(context.getString(R.string.save_key_colorPrimary), cColorPrimary) + putInt(context.getString(R.string.save_key_colorPrimary), + cColorPrimary + ) apply() } // save the accent color with (sharedPref.edit()) { - putInt(context.getString(R.string.save_key_colorAccent), cColorAccent) + putInt(context.getString(R.string.save_key_colorAccent), + cColorAccent + ) apply() } // save showBuffet with (sharedPref.edit()) { - putBoolean(context.getString(R.string.save_key_showBuffet), cShowBuffet) + putBoolean(context.getString(R.string.save_key_showBuffet), + cShowBuffet + ) apply() } @@ -79,19 +96,37 @@ class PreferencesController { // the load function fun load(context: Context) { - // load saved course val sharedPref = context.defaultSharedPreferences + + // load the update times (cache) + coursesCacheTime = sharedPref.getLong(context.getString( + R.string.save_key_coursesCacheTime + ), 0) + mensaCacheTime = sharedPref.getLong(context.getString( + R.string.save_key_mensaCacheTime + ), 0) + timetableCacheTime = sharedPref.getLong(context.getString( + R.string.save_key_timetableCacheTime + ), 0) + + // load saved course cCourse = Course( sharedPref.getString(context.getString(R.string.save_key_courseTTLink), "https://www.hs-offenburg.de/index.php?id=6627&class=class&iddV=DA64F6FE-9DDB-429E-A677-05D0D40CB636&week=0")!!, sharedPref.getString(context.getString(R.string.save_key_course), "AI3")!! ) // load saved colors - cColorPrimary = sharedPref.getInt(context.getString(R.string.save_key_colorPrimary), Color.BLACK) - cColorAccent = sharedPref.getInt(context.getString(R.string.save_key_colorAccent), Color.parseColor("#FF1744")) + cColorPrimary = sharedPref.getInt(context.getString( + R.string.save_key_colorPrimary + ), Color.BLACK) + cColorAccent = sharedPref.getInt(context.getString( + R.string.save_key_colorAccent + ), Color.parseColor("#FF1744")) // load showBuffet - cShowBuffet = sharedPref.getBoolean(context.getString(R.string.save_key_showBuffet), true) + cShowBuffet = sharedPref.getBoolean(context.getString( + R.string.save_key_showBuffet + ), true) } } 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 new file mode 100644 index 0000000..47849af --- /dev/null +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/controller/TCoRAPIController.kt @@ -0,0 +1,96 @@ +/** + * ProjectLaogai + * + * Copyright 2019 + * + * 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.controller + +import android.content.Context +import org.jetbrains.anko.doAsync +import org.json.JSONObject +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.coursesCacheTime +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.mensaCacheTime +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.timetableCacheTime +import java.io.* +import java.net.URL + +class TCoRAPIController(cont: Context) { + private val context = cont + + /** + * get the json object from tcor api and write it as file (cache) + */ + fun getCoursesList() = doAsync { + val url = URL("https://tcor.mosad.xyz/courses") + val file = File(context.filesDir, "courses.json") + + // read data from the API + 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() + + // update cache time + coursesCacheTime = System.currentTimeMillis() / 1000 + PreferencesController.save(context) + } + + /** + * get the json object from tcor api and write it as file (cache) + */ + fun getMensa() = doAsync { + val url = URL("https://tcor.mosad.xyz/mensamenu") + val file = File(context.filesDir, "mensa.json") + + // read data from the API + 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() + + // update cache time + mensaCacheTime = System.currentTimeMillis() / 1000 + PreferencesController.save(context) + } + + /** + * get the json object from tcor api and write it as file (cache) + */ + fun getTimetable(courseName: String, week: Int) = doAsync { + val url = URL("https://tcor.mosad.xyz/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()) + + // write the json object to a file + val writer = BufferedWriter(FileWriter(file)) + writer.write(mensaObject.toString()) + writer.close() + + // update cache time + timetableCacheTime = System.currentTimeMillis() / 1000 + PreferencesController.save(context) + } +} \ 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 b075eb0..eb94c49 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 @@ -32,10 +32,12 @@ import com.afollestad.materialdialogs.MaterialDialog import kotlinx.android.synthetic.main.fragment_home.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.uiThread -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableCurrentWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cMenusCurrentWeek import org.mosad.seil0.projectlaogai.R -import org.mosad.seil0.projectlaogai.hsoparser.* +import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaCurrentWeek +import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.timetables +import org.mosad.seil0.projectlaogai.hsoparser.DataTypes +import org.mosad.seil0.projectlaogai.hsoparser.Meal +import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar import org.mosad.seil0.projectlaogai.uicomponents.LessonCardView import org.mosad.seil0.projectlaogai.uicomponents.LessonTextView import java.util.* @@ -68,14 +70,14 @@ class HomeFragment : Fragment() { */ private fun addCurrentMensaMenu() { doAsync { - val dayMenus: ArrayList + val dayMeals: ArrayList val cal = Calendar.getInstance() if (cal.get(Calendar.HOUR_OF_DAY) < 15) { - dayMenus = cMenusCurrentWeek.day[NotRetardedCalendar().getDayOfWeekIndex()] + dayMeals = mensaCurrentWeek.days[NotRetardedCalendar().getDayOfWeekIndex()].meals } else { - dayMenus = cMenusCurrentWeek.day[NotRetardedCalendar().getTomorrowWeekIndex()] + dayMeals = mensaCurrentWeek.days[NotRetardedCalendar().getTomorrowWeekIndex()].meals uiThread { txtView_Menu1Heading.text = resources.getString(R.string.meal_1_tomorrow) txtView_Menu2Heading.text = resources.getString(R.string.meal_2_tomorrow) @@ -84,19 +86,19 @@ class HomeFragment : Fragment() { uiThread { - if (dayMenus.size >= 2) { + if (dayMeals.size >= 2) { // get the index of the first meal, not a "Schneller Teller" - loop@ for ((i, meal) in dayMenus.withIndex()) { + loop@ for ((i, meal) in dayMeals.withIndex()) { if (meal.heading.contains("Essen")) { - for ((j, part) in dayMenus[i].parts.withIndex()) { + for ((j, part) in dayMeals[i].parts.withIndex()) { txtViewMenu1.append(part) - if (j < (dayMenus[i].parts.size - 2)) + if (j < (dayMeals[i].parts.size - 2)) txtViewMenu1.append("\n") } - for ((j, part) in dayMenus[i + 1].parts.withIndex()) { + for ((j, part) in dayMeals[i + 1].parts.withIndex()) { txtViewMenu2.append(part) - if (j < (dayMenus[i + 1].parts.size - 2)) + if (j < (dayMeals[i + 1].parts.size - 2)) txtViewMenu2.append("\n") } @@ -124,9 +126,9 @@ class HomeFragment : Fragment() { private fun addCurrentTimeTable() { val dayIndex = NotRetardedCalendar().getDayOfWeekIndex() - if (cTimeTableCurrentWeek.days.isNotEmpty() && dayIndex < 6) { + if (timetables[0].days.isNotEmpty() && dayIndex < 6) { - val timeTableDay = cTimeTableCurrentWeek.days[dayIndex] + val timeTableDay = timetables[0].days[dayIndex] // for all timeslots of the day for ((i, timeslot) in timeTableDay.timeslots.withIndex()) { 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 27f4e7d..d09bfc4 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 @@ -23,18 +23,18 @@ package org.mosad.seil0.projectlaogai.fragments import android.os.Bundle -import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout +import androidx.fragment.app.Fragment import org.jetbrains.anko.doAsync import org.jetbrains.anko.uiThread -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cMenusCurrentWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cMenusNextWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cShowBuffet +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cShowBuffet import org.mosad.seil0.projectlaogai.R -import org.mosad.seil0.projectlaogai.hsoparser.MealWeek +import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaCurrentWeek +import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaNextWeek +import org.mosad.seil0.projectlaogai.hsoparser.MensaWeek import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar import org.mosad.seil0.projectlaogai.uicomponents.MensaDayCardView import org.mosad.seil0.projectlaogai.uicomponents.MenuCardView @@ -55,10 +55,10 @@ class MensaFragment : Fragment() { // add the current week (week starts on sunday) val dayCurrent = if(NotRetardedCalendar().getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar().getDayOfWeekIndex() - addWeek(cMenusCurrentWeek, dayCurrent) + addWeek(mensaCurrentWeek, dayCurrent) // add the next week - addWeek(cMenusNextWeek, 0) + addWeek(mensaNextWeek, 0) return view } @@ -66,7 +66,7 @@ class MensaFragment : Fragment() { /** * add all menus from dayStart to Friday for a given week */ - private fun addWeek(menusWeek: MealWeek, dayStart: Int) { + private fun addWeek(menusWeek: MensaWeek, dayStart: Int) { doAsync { @@ -76,7 +76,7 @@ class MensaFragment : Fragment() { val cardViewMensaDay = MensaDayCardView(context!!, null) - for (meal in menusWeek.day[dayIndex]) { + for (meal in menusWeek.days[dayIndex].meals) { val menuViewMenu = MenuCardView(context!!, null) menuViewMenu.setMenuHeading(meal.heading) 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 ca93bb3..d94cd32 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 @@ -37,17 +37,16 @@ import com.afollestad.materialdialogs.list.listItems import kotlinx.android.synthetic.main.fragment_settings.* import org.jetbrains.anko.doAsync import org.jetbrains.anko.uiThread -import org.mosad.seil0.projectlaogai.PreferencesController -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cColorPrimary -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cColorAccent -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cCourse -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cCourseTTLinkList -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cShowBuffet -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableCurrentWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableNextWeek +import org.mosad.seil0.projectlaogai.controller.PreferencesController +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cColorAccent +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cColorPrimary +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cCourse +import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cShowBuffet import org.mosad.seil0.projectlaogai.R +import org.mosad.seil0.projectlaogai.controller.CacheController +import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.coursesList +import org.mosad.seil0.projectlaogai.controller.TCoRAPIController import org.mosad.seil0.projectlaogai.hsoparser.DataTypes -import org.mosad.seil0.projectlaogai.hsoparser.TimeTableParser import java.util.* /** @@ -97,13 +96,13 @@ class SettingsFragment : Fragment() { linLayoutCourse.setOnClickListener { // open a new dialog - val courseList = ArrayList() + val courseNameList = ArrayList() - cCourseTTLinkList.forEach { (_, course) -> - courseList.add(course) + coursesList.forEach { (_, courseName) -> + courseNameList.add(courseName) } - MaterialDialog(context!!).listItems(items = courseList) { _, index, text -> + MaterialDialog(context!!).listItems(items = courseNameList) { _, index, text -> txtView_Course.text = text // update txtView val dialog = MaterialDialog(context!!).cancelable(false) @@ -112,12 +111,15 @@ class SettingsFragment : Fragment() { dialog.show() doAsync { - cCourse = cCourseTTLinkList[index] // set the course + cCourse = coursesList[index] // set the course PreferencesController.save(context!!) // update current & next weeks timetable - cTimeTableCurrentWeek = TimeTableParser().getTimeTable(cCourse.courseLink) - cTimeTableNextWeek = TimeTableParser().getTimeTable(cCourse.courseLink.replace("week=0","week=1")) + TCoRAPIController(context!!).getTimetable(cCourse.courseName, 0) + TCoRAPIController(context!!).getTimetable(cCourse.courseName, 1) + + CacheController(context!!).readTimetable(cCourse.courseName, 0) + CacheController(context!!).readTimetable(cCourse.courseName, 1) uiThread { dialog.dismiss() 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 534fb60..96bbf5a 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 @@ -30,9 +30,8 @@ import android.widget.LinearLayout import androidx.fragment.app.Fragment import org.jetbrains.anko.doAsync import org.jetbrains.anko.uiThread -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableCurrentWeek -import org.mosad.seil0.projectlaogai.PreferencesController.Companion.cTimeTableNextWeek import org.mosad.seil0.projectlaogai.R +import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.timetables import org.mosad.seil0.projectlaogai.hsoparser.DataTypes import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar import org.mosad.seil0.projectlaogai.uicomponents.LessonCardView @@ -55,7 +54,7 @@ class TimeTableFragment : Fragment() { linLayoutTTFragment = view.findViewById(R.id.linLayout_TTFragment) - if (cTimeTableCurrentWeek.days.isNotEmpty()) { + if (timetables[0].days.isNotEmpty()) { addCurrentWeek() } else { // TODO show card with error msg @@ -82,7 +81,7 @@ class TimeTableFragment : Fragment() { cardViewTimeTableDay.setDayHeading(formatter.format(calendar.time)) // for each timeslot of the day - for ((i, timeslot) in cTimeTableCurrentWeek.days[day].timeslots.withIndex()) { + for ((i, timeslot) in timetables[0].days[day].timeslots.withIndex()) { val lessonCardView = LessonCardView(context!!, null) lessonCardView.getTxtViewTime().text = DataTypes().getTime()[i] @@ -119,7 +118,7 @@ class TimeTableFragment : Fragment() { } // add next weeks days, max number = dayIndex, if timetable was loaded - if (cTimeTableNextWeek.days.isNotEmpty()) { + if (timetables[1].days.isNotEmpty()) { calendar.add(Calendar.DATE, 1) // before this we are at a sunday (no lecture on sundays!) for (day in 0..(dayIndex - 1)) { @@ -128,7 +127,7 @@ class TimeTableFragment : Fragment() { cardViewTimeTableDay.setDayHeading(formatter.format(calendar.time)) // for each timeslot of the day - for ((i, timeslot) in cTimeTableNextWeek.days[day].timeslots.withIndex()) { + for ((i, timeslot) in timetables[1].days[day].timeslots.withIndex()) { val lessonCardView = LessonCardView(context!!, null) lessonCardView.getTxtViewTime().text = DataTypes().getTime()[i] diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/DataTypes.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/DataTypes.kt index 8ca8838..92eadd0 100644 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/DataTypes.kt +++ b/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/DataTypes.kt @@ -115,10 +115,16 @@ data class Course(val courseLink: String, val courseName: String) data class Meal(val day: String, val heading: String, val parts: ArrayList, val additives: String) -data class MealWeek(val day: Array> = Array(7) { ArrayList() }) +data class Meals(val meals: ArrayList) + +data class MensaWeek(val days: Array = Array(7) { Meals(ArrayList()) }) + +data class MealWeek(val day: Array> = Array(7) { ArrayList() }) // TODO remove data class Lesson(val lessonSubject: String, val lessonTeacher: String, val lessonRoom:String, val lessonRemark: String) -data class TimeTableDay( val timeslots: Array> = Array(6) { ArrayList()}) +data class TimetableDay( val timeslots: Array> = Array(6) { ArrayList()}) -data class TimeTable(val days: Array = Array(6) { TimeTableDay() }) \ No newline at end of file +data class TimetableWeek(val days: Array = Array(6) { TimetableDay() }) + +data class TimeTable(val days: Array = Array(6) { TimetableDay() }) // TODO remove \ No newline at end of file diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/MensaParser.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/MensaParser.kt deleted file mode 100644 index 0f7db81..0000000 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/MensaParser.kt +++ /dev/null @@ -1,78 +0,0 @@ -/** - * ProjectLaogai - * - * Copyright 2019 - * - * 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.hsoparser - -import org.jsoup.Jsoup -import java.util.* -import kotlin.collections.ArrayList - -class MensaParser { - - /** - * returns the mensa menu for the a week - */ - fun getMensaMenu(menuLink: String): MealWeek { - val mealList = ArrayList() - val mealWeekList = MealWeek() - val menuHTML = Jsoup.connect(menuLink).get() - - menuHTML.select("#speiseplan-tabs").select("div.tab-content").select("div.menu-tagesplan").forEachIndexed { dayIndex, day -> - val strDay = day.select("h3").text() - - - day.select("div.menu-info").forEachIndexed { mealIndex, meal -> - val heading = day.select("h4")[mealIndex].text() - val parts = ArrayList(meal.html().substringBefore("
\n").replace("
", " ").split("\n")) - val additives = meal.select("span.show-with-allergenes").text() - - mealWeekList.day[dayIndex].add(Meal(strDay, heading, parts, additives)) - } - - for (i in 0 .. (day.select("div.row h4").size - 1)) { - try { - val heading = day.select("div.row h4")[i].text() - val parts = ArrayList(day.select("div.row").select("div.menu-info")[i].html().substringBefore("", " ").split("\n")) - val additives = day.select("div.row").select("div.menu-info")[i].select("span.show-with-allergenes").text() - - mealList.add(Meal(strDay, heading, parts, additives)) - } catch (e: Exception) { - //println("Oooups! Something went wrong: ${e.printStackTrace()}") - } - } - } - - // Mon to Sat (0 - 5) - //println(mealWeekList.day[4]) - - return mealWeekList - } - - /** - * return the link of the menus of the next week - */ - fun getMenuLinkNextWeek(menuLink: String): String { - val menuHTML = Jsoup.connect(menuLink).get() - - return "https://www.swfr.de" + menuHTML.select("#speiseplan-tabs").select("a.next-week").attr("href") - } -} diff --git a/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/TimeTableParser.kt b/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/TimeTableParser.kt deleted file mode 100644 index 715ef34..0000000 --- a/app/src/main/java/org/mosad/seil0/projectlaogai/hsoparser/TimeTableParser.kt +++ /dev/null @@ -1,146 +0,0 @@ -/** - * ProjectLaogai - * - * Copyright 2019 - * - * 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.hsoparser - -import org.jsoup.Jsoup - -class TimeTableParser { - private val days = arrayOf("Monday", "Tuesday" ,"Wednesday", "Thursday", "Friday", "Saturday") - private var courseTTLinkList = ArrayList() - - /** - * get the timetable from the given url - * the timetable is organised per row not per column; - * Mon 1, Tue 1, Wed 1, Thur 1, Fri 1, Sat 1, Mon 2 and so on - */ - fun getTimeTable(courseTTURL: String): TimeTable { - var timeTableWeek = TimeTable() // this must be a var! - val scheduleHTML = Jsoup.connect(courseTTURL).get() - - //val week = scheduleHTML.select("h1.timetable-caption").text() - //println("$week successful!\n") - - val rows= scheduleHTML.select("table.timetable").select("tr[scope=\"row\"]") - var sDay = -1 - var sRow = -1 - var sLesson = Lesson("", "", "", "") - - // get each row with index, reflects 1 timeslot per day - for ((rowIndex, row) in rows.withIndex()) { - var day = 0 - - // elements are now all lessons, including empty ones - row.select("td.lastcol, td[style]").forEach { element -> - - // if there is a lecture with rowspan="2", we need to shift everything by one to the left. This is stupid and ugly there needs to bee an API - if ((sDay > -1 && sRow > -1) && (sDay == day && ((sRow + 1) == rowIndex))) { - // we found a lecture that is longer than 1 lesson - timeTableWeek.days[day].timeslots[rowIndex].add(sLesson) // this just works if there is one lecture per slot - - // adjust the following slot - sDay++ - sLesson = Lesson(element.select("div.lesson-subject").text(), element.select("div.lesson-teacher").text(), element.select("div.lesson-room").text(), element.select("div.lesson-remark").text()) - - // adjust the slot directly as we don't get there anymore - if(sDay == 5) { - timeTableWeek.days[day + 1].timeslots[rowIndex].add(sLesson) - } - - } else { - timeTableWeek.days[day].timeslots[rowIndex].add(Lesson(element.select("div.lesson-subject").text(), element.select("div.lesson-teacher").text(), element.select("div.lesson-room").text(), element.select("div.lesson-remark").text())) - } - - // we found a lecture with rowspan="2", save day, row and lesson for later adjustment - if(element.toString().contains("rowspan=\"2\"")) { - sDay = day - sRow = rowIndex - sLesson = timeTableWeek.days[day].timeslots[rowIndex].get(index = 0) - } - - if(element.hasClass("lastcol")) day++ - } - - } - - printTimeTableWeek(timeTableWeek) - - return timeTableWeek - } - - /** - * parse all courses from the courses site at https://www.hs-offenburg.de/studium/vorlesungsplaene/ - */ - fun getCourseTTLinks(): ArrayList { - val courseHTML = Jsoup.connect("https://www.hs-offenburg.de/studium/vorlesungsplaene/").get() - - courseHTML.select("ul.index-group").select("li.Class").select("a[href]").forEachIndexed { _, element -> - courseTTLinkList.add(Course(element.attr("href").replace("http", "https"),element.text())) - } - return courseTTLinkList - } - - @Suppress("unused") - fun printTimeTableWeek(timetable: TimeTable) { - for (j in 0..5) print(days[j].padEnd(75 ,' ') + " | ") - println() - for (j in 0..5) print("-".padEnd(76 + (j.toFloat().div(j).toInt()), '-') + "+") - println() - - // the timeslot - for (i in 0..5) { - - for (j in 0..5) { - val ldiff = if (timetable.days[j].timeslots[i].size == 0) 1 else timetable.days[j].timeslots[i].size - - for (lesson in timetable.days[j].timeslots[i]) print(lesson.lessonSubject.padEnd(75/ldiff ,' ')) - if (ldiff == 2) print(" ") - print(" | ") - } - println() - - for (j in 0..5) { - val ldiff = if (timetable.days[j].timeslots[i].size == 0) 1 else timetable.days[j].timeslots[i].size - - for (lesson in timetable.days[j].timeslots[i]) print(lesson.lessonTeacher.padEnd(75/ldiff ,' ')) - if (ldiff == 2) print(" ") - print(" | ") - } - println() - - for (j in 0..5) { - val ldiff = if (timetable.days[j].timeslots[i].size == 0) 1 else timetable.days[j].timeslots[i].size - - for (lesson in timetable.days[j].timeslots[i]) print(lesson.lessonRoom.padEnd(75/ldiff ,' ')) - if (ldiff == 2) print(" ") - print(" | ") - } - println() - - for (j in 0..5) print("-".padEnd(76 + (j.toFloat().div(j).toInt()), '-') + "+") - println() - } - - println(" \n") - } - -} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1a098ab..71b9bab 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,7 +2,7 @@ Project Laogai Open navigation drawer Close navigation drawer - hso App 0.3.90 + hso App 0.3.95 seil0@mosad.xyz Project Laogai @@ -40,7 +40,7 @@ The accent color, default is indigo. always show buffet select - version 0.3.90 + version 0.3.95 about hso App by @Seil0 "This software is made by @Seil0 and is published under the terms and conditions of GPL 3. For further information visit \ngit.mosad.xyz/Seil0/ProjectLaogai \n\n© 2018-2019 seil0@mosad.xyz " @@ -53,5 +53,8 @@ org.mosad.seil0.projectlaogai.colorPrimary org.mosad.seil0.projectlaogai.colorAccent org.mosad.seil0.projectlaogai.showBuffet + org.mosad.seil0.projectlaogai.coursesCacheTime + org.mosad.seil0.projectlaogai.mensaCacheTime + org.mosad.seil0.projectlaogai.timetableCacheTime