16 Commits
0.4.0 ... 0.4.1

Author SHA1 Message Date
ac37bce145 Merge branch 'develop' of Seil0/ProjectLaogai into master 2019-05-02 14:43:20 +02:00
6fd82254e0 updated description for f-droid 2019-05-02 14:42:28 +02:00
0dd8ba9475 release 0.4.1 2019-05-01 01:04:09 +02:00
770e9a255d Update 'README.md' 2019-05-01 00:46:47 +02:00
4589badbfc updated versionName to 0.4.1
* updated material-dialogs 2.6.0 -> 2.8.1
2019-05-01 00:36:33 +02:00
74f75bfbde update to kotlin 1.3.31, gradle 5.1.1 & gradle plugin 3.4.0 2019-04-25 18:27:57 +01:00
a00c651bfd disable layout change animation 2019-04-08 18:39:43 +02:00
77757ad9ca fixed mensa screen crash if day has no meals 2019-04-08 14:04:26 +02:00
fe111ac56b added refresh to timetable screen 2019-04-06 14:13:01 +02:00
2bd86ff6bb added fastlane metadata 2019-04-05 15:03:53 +02:00
dbaf496a79 minor clean up and refactoring 2019-04-03 20:37:17 +02:00
77326a8ed6 added ability to refresh the mensa menus
* some minor clean ups
2019-04-03 19:21:51 +02:00
9fc897e194 fixed initial accent color 2019-04-02 13:23:37 +02:00
f9ac219ec6 Merge remote-tracking branch 'origin/master' into develop 2019-04-02 13:22:32 +02:00
ff1d353cae removed versionNameSuffix 2019-04-01 18:03:03 +02:00
6e5cf29eaa removed maven repo 2019-04-01 17:55:37 +02:00
24 changed files with 274 additions and 187 deletions

View File

@ -1,5 +1,10 @@
![fdroid version](https://img.shields.io/f-droid/v/org.mosad.seil0.projectlaogai.svg?style=flat-square)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=flat-square)](https://www.gnu.org/licenses/gpl-3.0)
# ProjectLaogai "hso App" # ProjectLaogai "hso App"
ProjectLaogai is a app to access the timetable and the mensa menu of Hochschule Offenburg. ProjectLaogai is a app to access the timetable and the mensa menu of Hochschule Offenburg.
[<img src="https://f-droid.org/badge/get-it-on.png" height="75">](https://f-droid.org/packages/org.mosad.seil0.projectlaogai/)
## Features ## Features
* check out the mensa menu of this and next week * check out the mensa menu of this and next week
* access your timetable * access your timetable

View File

@ -12,8 +12,8 @@ android {
applicationId "org.mosad.seil0.projectlaogai" applicationId "org.mosad.seil0.projectlaogai"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 28 targetSdkVersion 28
versionCode 12 versionCode 13
versionName "0.4.0" versionName "0.4.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resValue "string", "build_time", buildTime() resValue "string", "build_time", buildTime()
setProperty("archivesBaseName", "projectlaogai-$versionName") setProperty("archivesBaseName", "projectlaogai-$versionName")
@ -37,12 +37,13 @@ dependencies {
implementation 'org.jetbrains.anko:anko-commons:0.10.8' implementation 'org.jetbrains.anko:anko-commons:0.10.8'
implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha3' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha5'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.code.gson:gson:2.8.5' implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.afollestad:aesthetic:1.0.0-beta05' implementation 'com.afollestad:aesthetic:1.0.0-beta05'
implementation 'com.afollestad.material-dialogs:core:2.6.0' implementation 'com.afollestad.material-dialogs:core:2.8.1'
implementation 'com.afollestad.material-dialogs:color:2.6.0' implementation 'com.afollestad.material-dialogs:color:2.8.1'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'

View File

@ -5,6 +5,7 @@
<application <application
android:allowBackup="true" android:allowBackup="true"
android:fullBackupContent="@xml/backup_descriptor"
android:icon="@mipmap/ic_laogai_icon" android:icon="@mipmap/ic_laogai_icon"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_laogai_icon" android:roundIcon="@mipmap/ic_laogai_icon"

View File

@ -68,7 +68,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
Aesthetic.config { Aesthetic.config {
colorPrimary(Color.BLACK) colorPrimary(Color.BLACK)
colorPrimaryDark(Color.BLACK) colorPrimaryDark(Color.BLACK)
colorAccent(Color.parseColor("#FF1744")) colorAccent(Color.parseColor("#3F51B5"))
apply() apply()
} }
@ -162,10 +162,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
* load the mensa menus of the current week * load the mensa menus of the current week
*/ */
private fun load() { private fun load() {
// load the settings
PreferencesController.load(this) // this must be finished before doing anything else
val startupTime = measureTimeMillis { val startupTime = measureTimeMillis {
// load the settings
PreferencesController.load(this) // this must be finished before doing anything else
val tcor = TCoRAPIController(this) val tcor = TCoRAPIController(this)
val currentTime = System.currentTimeMillis() / 1000 val currentTime = System.currentTimeMillis() / 1000
val currentDay = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) val currentDay = Calendar.getInstance().get(Calendar.DAY_OF_WEEK)
@ -179,8 +179,8 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// update blocking if a) it`s monday and the last cache was not on a monday or b) the cache is older than 6 days // update blocking if a) it`s monday and the last cache was not on a monday or b) the cache is older than 6 days
if((currentDay == Calendar.MONDAY && timetableCacheDay != Calendar.MONDAY) || (System.currentTimeMillis() / 1000) - timetableCacheTime > 518400) { if((currentDay == Calendar.MONDAY && timetableCacheDay != Calendar.MONDAY) || (System.currentTimeMillis() / 1000) - timetableCacheTime > 518400) {
println("updating timetable after sunday!") println("updating timetable after sunday!")
val jobA = tcor.getTimetable(cCourse.courseName, 0) val jobA = TCoRAPIController.getTimetable(cCourse.courseName, 0, this)
val jobB = tcor.getTimetable(cCourse.courseName, 1) val jobB = TCoRAPIController.getTimetable(cCourse.courseName, 1, this)
jobA.get() jobA.get()
jobB.get() jobB.get()
@ -192,7 +192,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
// update blocking if it's sunday after 1500 // update blocking if it's sunday after 1500
// TODO and the last update was before 1500 // TODO and the last update was before 1500
if(currentDay == Calendar.SUNDAY && cal.get(Calendar.HOUR_OF_DAY) >= 15) { if(currentDay == Calendar.SUNDAY && cal.get(Calendar.HOUR_OF_DAY) >= 15) {
val jobA = tcor.getMensa() val jobA = TCoRAPIController.getMensa(this)
jobA.get() jobA.get()
} }
@ -205,14 +205,14 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
tcor.getCoursesList() tcor.getCoursesList()
if(currentTime - mensaCacheTime > 10800) if(currentTime - mensaCacheTime > 10800)
tcor.getMensa() TCoRAPIController.getMensa(this)
if(currentTime - timetableCacheTime > 10800) { if(currentTime - timetableCacheTime > 10800) {
tcor.getTimetable(cCourse.courseName, 0) TCoRAPIController.getTimetable(cCourse.courseName, 0, this)
tcor.getTimetable(cCourse.courseName, 1) TCoRAPIController.getTimetable(cCourse.courseName, 1, this)
} }
} }
println("Completed in $startupTime ms") println("startup completed in $startupTime ms")
} }
} }

View File

@ -42,6 +42,53 @@ class CacheController(cont: Context) {
var mensaCurrentWeek = MensaWeek() var mensaCurrentWeek = MensaWeek()
var mensaNextWeek = MensaWeek() var mensaNextWeek = MensaWeek()
var timetables = ArrayList<TimetableWeek>() var timetables = ArrayList<TimetableWeek>()
/**
* read current and next weeks mensa menus from the cached file
*/
fun readMensa(context: Context) {
val file = File(context.filesDir, "mensa.json")
// make sure the file exists
if (!file.exists()) {
TCoRAPIController.getMensa(context).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, context: Context) {
val file = File(context.filesDir, "timetable-$courseName-$week.json")
// make sure the file exists
if (!file.exists())
TCoRAPIController.getTimetable(courseName, week, context).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)
}
}
} }
/** /**
@ -50,16 +97,16 @@ class CacheController(cont: Context) {
*/ */
fun readStartCache(courseName: String) { fun readStartCache(courseName: String) {
readCoursesList() readCoursesList()
readMensa() readMensa(context)
readTimetable(courseName, 0) readTimetable(courseName, 0, context)
readTimetable(courseName, 1) readTimetable(courseName, 1, context)
} }
/** /**
* read the courses list from the cached file * read the courses list from the cached file
* add them to the coursesList object * add them to the coursesList object
*/ */
fun readCoursesList() { private fun readCoursesList() {
val file = File(context.filesDir, "courses.json") val file = File(context.filesDir, "courses.json")
// make sure the file exists // make sure the file exists
@ -73,50 +120,4 @@ class CacheController(cont: Context) {
coursesList = Gson().fromJson(coursesObject.getAsJsonArray("courses"), object : TypeToken<List<Course>>() {}.type) coursesList = Gson().fromJson(coursesObject.getAsJsonArray("courses"), object : TypeToken<List<Course>>() {}.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)
}
}
} }

View File

@ -34,6 +34,48 @@ import java.net.URL
class TCoRAPIController(cont: Context) { class TCoRAPIController(cont: Context) {
private val context = cont private val context = cont
companion object {
/**
* get the json object from tcor api and write it as file (cache)
*/
fun getMensa(context: Context) = 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, context: Context) = 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)
}
}
/** /**
* get the json object from tcor api and write it as file (cache) * get the json object from tcor api and write it as file (cache)
*/ */
@ -53,44 +95,4 @@ class TCoRAPIController(cont: Context) {
coursesCacheTime = System.currentTimeMillis() / 1000 coursesCacheTime = System.currentTimeMillis() / 1000
PreferencesController.save(context) 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)
}
} }

View File

@ -141,7 +141,7 @@ class HomeFragment : Fragment() {
} else { } else {
MaterialDialog(context!!) MaterialDialog(context!!)
.title(R.string.error) .title(R.string.error)
.message(R.string.gen_tt_error) .message(R.string.timetable_error)
.show() .show()
// TODO log the error and send feedback // TODO log the error and send feedback
} }

View File

@ -26,15 +26,15 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_mensa.* import kotlinx.android.synthetic.main.fragment_mensa.*
import org.jetbrains.anko.doAsync import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread import org.jetbrains.anko.uiThread
import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.controller.CacheController
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaCurrentWeek import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaCurrentWeek
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaNextWeek import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.mensaNextWeek
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cShowBuffet import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cShowBuffet
import org.mosad.seil0.projectlaogai.controller.TCoRAPIController
import org.mosad.seil0.projectlaogai.hsoparser.MensaWeek import org.mosad.seil0.projectlaogai.hsoparser.MensaWeek
import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar
import org.mosad.seil0.projectlaogai.uicomponents.DayCardView import org.mosad.seil0.projectlaogai.uicomponents.DayCardView
@ -46,26 +46,29 @@ import org.mosad.seil0.projectlaogai.uicomponents.MealLinearLayout
*/ */
class MensaFragment : Fragment() { class MensaFragment : Fragment() {
private lateinit var linLayoutMensaFragment: LinearLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_mensa, container, false) val view: View = inflater.inflate(org.mosad.seil0.projectlaogai.R.layout.fragment_mensa, container, false)
linLayoutMensaFragment = view.findViewById(R.id.linLayout_Mensa) // init actions
refreshAction()
// add the current week (week starts on sunday) // add the current week (week starts on sunday)
val dayCurrent = if(NotRetardedCalendar().getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar().getDayOfWeekIndex() val dayCurrent = if(NotRetardedCalendar().getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar().getDayOfWeekIndex()
addWeek(mensaCurrentWeek, dayCurrent).get() addWeek(mensaCurrentWeek, dayCurrent).get()
// add the next week // add the next week
addWeek(mensaNextWeek, 0).get() addWeek(mensaNextWeek, 0)
// TODO should we show a info if there is no more food this & next week?
return view return view
} }
/** /**
* add all menus from dayStart to Friday for a given week * add all menus from dayStart to Friday for a given week
* @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) = doAsync {
@ -75,7 +78,9 @@ class MensaFragment : Fragment() {
for (dayIndex in dayStart..4) { for (dayIndex in dayStart..4) {
var helpMeal = MealLinearLayout(context) var helpMeal = MealLinearLayout(context)
val dayCardView = DayCardView(context!!) val dayCardView = DayCardView(context!!)
dayCardView.setDayHeading(menusWeek.days[dayIndex].meals[0].day)
if(menusWeek.days[dayIndex].meals.isNotEmpty())
dayCardView.setDayHeading(menusWeek.days[dayIndex].meals[0].day)
for (meal in menusWeek.days[dayIndex].meals) { for (meal in menusWeek.days[dayIndex].meals) {
val mealLayout = MealLinearLayout(context) val mealLayout = MealLinearLayout(context)
@ -97,4 +102,40 @@ class MensaFragment : Fragment() {
} }
/**
* initialize the refresh action
*/
private fun refreshAction() = doAsync {
uiThread {
// set the refresh listener
refreshLayout_Mensa.setOnRefreshListener {
updateMensaScreen()
}
}
}
/**
* refresh the mensa cache and update the mensa screen
*/
private fun updateMensaScreen() = doAsync {
// update the cache
TCoRAPIController.getMensa(context!!).get() // blocking since we want the new data
CacheController.readMensa(context!!)
uiThread {
// remove all menus from the layout
linLayout_Mensa.removeAllViews()
// add the refreshed menus
val dayCurrent = if (NotRetardedCalendar().getDayOfWeekIndex() == 6) 0 else NotRetardedCalendar().getDayOfWeekIndex()
addWeek(mensaCurrentWeek, dayCurrent).get()
// add the next week
addWeek(mensaNextWeek, 0)
refreshLayout_Mensa.isRefreshing = false
}
}
} }

View File

@ -176,11 +176,11 @@ class SettingsFragment : Fragment() {
PreferencesController.save(context) PreferencesController.save(context)
// update current & next weeks timetable // update current & next weeks timetable
TCoRAPIController(context).getTimetable(cCourse.courseName, 0) TCoRAPIController.getTimetable(cCourse.courseName, 0, context).get() // blocking since we want the new data
TCoRAPIController(context).getTimetable(cCourse.courseName, 1) TCoRAPIController.getTimetable(cCourse.courseName, 1, context).get() // blocking since we want the new data
CacheController(context).readTimetable(cCourse.courseName, 0) CacheController.readTimetable(cCourse.courseName, 0, context)
CacheController(context).readTimetable(cCourse.courseName, 1) CacheController.readTimetable(cCourse.courseName, 1, context)
uiThread { uiThread {
dialog.dismiss() dialog.dismiss()

View File

@ -27,13 +27,18 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.afollestad.materialdialogs.MaterialDialog
import kotlinx.android.synthetic.main.fragment_timetable.* import kotlinx.android.synthetic.main.fragment_timetable.*
import org.jetbrains.anko.doAsync import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread import org.jetbrains.anko.uiThread
import org.mosad.seil0.projectlaogai.R import org.mosad.seil0.projectlaogai.R
import org.mosad.seil0.projectlaogai.controller.CacheController
import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.timetables import org.mosad.seil0.projectlaogai.controller.CacheController.Companion.timetables
import org.mosad.seil0.projectlaogai.controller.PreferencesController.Companion.cCourse
import org.mosad.seil0.projectlaogai.controller.TCoRAPIController
import org.mosad.seil0.projectlaogai.hsoparser.DataTypes import org.mosad.seil0.projectlaogai.hsoparser.DataTypes
import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar import org.mosad.seil0.projectlaogai.hsoparser.NotRetardedCalendar
import org.mosad.seil0.projectlaogai.hsoparser.TimetableWeek
import org.mosad.seil0.projectlaogai.uicomponents.* import org.mosad.seil0.projectlaogai.uicomponents.*
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -44,37 +49,51 @@ import java.util.*
*/ */
class TimeTableFragment : Fragment() { class TimeTableFragment : Fragment() {
private val formatter = SimpleDateFormat("E dd.MM", Locale.getDefault()) // TODO change to android call when min api is 24
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view: View = inflater.inflate(R.layout.fragment_timetable, container, false) val view: View = inflater.inflate(R.layout.fragment_timetable, container, false)
// init actions
refreshAction()
if (timetables[0].days.isNotEmpty() && timetables[1].days.isNotEmpty()) { if (timetables[0].days.isNotEmpty() && timetables[1].days.isNotEmpty()) {
addWeeks() addInitWeeks()
} else { } else {
// TODO show card with error msg MaterialDialog(context!!)
.title(R.string.error)
.message(R.string.timetable_error)
.show()
} }
return view return view
} }
/** /**
* add the all days with at least one lesson to the timetable screen * add the current and next weeks lessons
*/ */
private fun addWeeks() = doAsync { private fun addInitWeeks() = doAsync {
val dayIndex = NotRetardedCalendar().getDayOfWeekIndex() val dayIndex = NotRetardedCalendar().getDayOfWeekIndex()
val formatter = SimpleDateFormat("E dd.MM", Locale.getDefault()) // TODO change to android call when min api is 24
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
// add current week
addWeek(dayIndex, 5, timetables[0], calendar).get()
// add next week
addWeek(0, dayIndex - 1, timetables[1], calendar)
}
private fun addWeek(dayStart: Int, dayEnd: Int, timetable: TimetableWeek, calendar: Calendar) = doAsync {
uiThread { uiThread {
// add the current week for (day in dayStart..dayEnd) {
for (day in dayIndex..5) {
var helpLesson = LessonLinearLayout(context) var helpLesson = LessonLinearLayout(context)
val dayCardView = DayCardView(context!!) val dayCardView = DayCardView(context!!)
dayCardView.setDayHeading(formatter.format(calendar.time)) dayCardView.setDayHeading(formatter.format(calendar.time))
// for each timeslot of the day // for each timeslot of the day
for ((tsIndex, timeslot) in timetables[0].days[day].timeslots.withIndex()) { for ((tsIndex, timeslot) in timetable.days[day].timeslots.withIndex()) {
for(lesson in timeslot) { for(lesson in timeslot) {
@ -102,43 +121,46 @@ class TimeTableFragment : Fragment() {
} }
calendar.add(Calendar.DATE, 1) // before this we are at a sunday (no lecture on sundays!) calendar.add(Calendar.DATE, 1) // before this we are at a sunday (no lecture on sundays!)
}
}
// add the next week /**
for (day in 0..(dayIndex - 1)) { * initialize the refresh action
var helpLesson = LessonLinearLayout(context!!) */
val dayCardView = DayCardView(context!!) private fun refreshAction() = doAsync {
dayCardView.setDayHeading(formatter.format(calendar.time)) uiThread {
// set the refresh listener
// for each timeslot of the day refreshLayout_Timetable.setOnRefreshListener {
for ((tsIndex, timeslot) in timetables[1].days[day].timeslots.withIndex()) { updateTimetableScreen()
for(lesson in timeslot) {
if(lesson.lessonSubject.isNotEmpty()) {
val lessonLayout = LessonLinearLayout(context!!)
lessonLayout.setLesson(lesson, DataTypes().getTime()[tsIndex])
dayCardView.getLinLayoutDay().addView(lessonLayout)
if (lesson != timeslot.last())
lessonLayout.disableDivider()
helpLesson = lessonLayout
}
}
}
helpLesson.disableDivider()
calendar.add(Calendar.DATE, 1)
// if there are no lessons don't show the dayCardView
if (dayCardView.getLinLayoutDay().childCount > 1)
linLayout_Timetable.addView(dayCardView)
} }
} }
} }
private fun updateTimetableScreen() = doAsync {
// 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
CacheController.readTimetable(cCourse.courseName, 0, context!!)
CacheController.readTimetable(cCourse.courseName, 1, context!!)
uiThread {
// remove all menus from the layout
linLayout_Timetable.removeAllViews()
// add the refreshed timetables
val dayIndex = NotRetardedCalendar().getDayOfWeekIndex()
val calendar = Calendar.getInstance()
// add current week
addWeek(dayIndex, 5, timetables[0], calendar).get()
// add next week
addWeek(0, dayIndex - 1, timetables[1], calendar)
refreshLayout_Timetable.isRefreshing = false
}
}
} }

View File

@ -15,7 +15,8 @@
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/linLayout_Home"> android:layout_height="wrap_content"
android:id="@+id/linLayout_Home">
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>

View File

@ -5,9 +5,10 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".fragments.MensaFragment"> tools:context=".fragments.MensaFragment">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:id="@+id/refreshLayout_Mensa">
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -15,10 +16,12 @@
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/linLayout_Mensa" android:layout_height="wrap_content"
android:background="@color/themePrimary"> android:animateLayoutChanges="false"
</LinearLayout> android:background="@color/themePrimary"
android:id="@+id/linLayout_Mensa"/>
</ScrollView> </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</FrameLayout> </FrameLayout>

View File

@ -8,6 +8,7 @@
<!-- TODO: Update blank fragment layout --> <!-- TODO: Update blank fragment layout -->
<WebView <WebView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/webView"/> android:layout_height="match_parent"
android:id="@+id/webView"/>
</FrameLayout> </FrameLayout>

View File

@ -5,9 +5,10 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".fragments.TimeTableFragment"> tools:context=".fragments.TimeTableFragment">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:id="@+id/refreshLayout_Timetable">
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -15,10 +16,10 @@
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:id="@+id/linLayout_Timetable" android:layout_height="wrap_content"
android:background="@color/themePrimary"> android:animateLayoutChanges="false"
</LinearLayout> android:background="@color/themePrimary"
android:id="@+id/linLayout_Timetable"/>
</ScrollView> </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</FrameLayout> </FrameLayout>

View File

@ -12,8 +12,7 @@
<string name="no_more_food">Diese Woche keine weitere Essensausgabe</string> <string name="no_more_food">Diese Woche keine weitere Essensausgabe</string>
<string name="no_lesson_today">heute keine Vorlesung!</string> <string name="no_lesson_today">heute keine Vorlesung!</string>
<string name="error">Fehler</string> <string name="error">Fehler</string>
<string name="no_tt_error">Stundenplan konnte nicht geladen werden!</string> <string name="timetable_error">Stundenplan konnte nicht geladen werden!</string>
<string name="gen_tt_error">Allgemeiner Stundenplan Fehler!"</string>
<string name="info">Info</string> <string name="info">Info</string>
<string name="user">Benutzer</string> <string name="user">Benutzer</string>
<string name="course_desc">Tippen, um den Kurs zu ändern</string> <string name="course_desc">Tippen, um den Kurs zu ändern</string>

View File

@ -3,7 +3,6 @@
<color name="colorPrimary">#000000</color> <color name="colorPrimary">#000000</color>
<color name="colorPrimaryDark">#000000</color> <color name="colorPrimaryDark">#000000</color>
<color name="colorAccent">#3F51B5</color> <color name="colorAccent">#3F51B5</color>
<color name="colorMensaDay">#EBE8E9</color>
<color name="ic_launcher_background">#FFFFFF</color> <color name="ic_launcher_background">#FFFFFF</color>
<color name="themePrimary">#FFFFFF</color> <color name="themePrimary">#FFFFFF</color>
@ -27,6 +26,4 @@
<color name="themeSecondaryLight">#FFFFFF</color> <color name="themeSecondaryLight">#FFFFFF</color>
<color name="themeTertiaryLight">#424242</color> <!-- TODO find a better color --> <color name="themeTertiaryLight">#424242</color> <!-- TODO find a better color -->
<color name="test">#424242</color>
</resources> </resources>

View File

@ -20,8 +20,7 @@
<string name="no_lesson_today">"No lecture today!"</string> <string name="no_lesson_today">"No lecture today!"</string>
<string name="error">Error</string> <string name="error">Error</string>
<string name="no_tt_error">Could not load timetable!"</string> <string name="timetable_error">Could not load timetable!"</string>
<string name="gen_tt_error">There was an error with the timetable!"</string>
<string name="sample_user" translatable="false">SampleUser@stud.hs-offenburg.de</string> <string name="sample_user" translatable="false">SampleUser@stud.hs-offenburg.de</string>
<string name="sample_course" translatable="false">SampleCourse 3</string> <string name="sample_course" translatable="false">SampleCourse 3</string>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<exclude domain="file" path="mensa.json"/>
<exclude domain="file" path="courses.json"/>
</full-backup-content>

View File

@ -1,13 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.21' ext.kotlin_version = '1.3.31'
repositories { repositories {
google() google()
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.android.tools.build:gradle:3.4.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

View File

@ -0,0 +1,7 @@
ProjectLaogai ist eine App um den Stundenplan und das Mensa-Essen der Hochschule Offenburg anzuzeigen.
Features:
* schaue was es diese und nächste WOche in der Mensa zu Essen gibt
* schaue dir deinen Stundenplan an
* öffne moodle direkt in der App
* viele lustige Bugs

View File

@ -0,0 +1 @@
eine App für die Hochschule Offenburg

View File

@ -1,5 +1,4 @@
ProjectLaogai is a app to access the timetable and the mensa menu ProjectLaogai is an app to access the timetable and the mensa menu of Hochschule Offenburg.
of Hochschule Offenburg.
Features: Features:
* check out the mensa menu of this and next week * check out the mensa menu of this and next week

View File

@ -1 +1 @@
access the timetable and mensa menu at Hochschule Offenburg an app for the Hochschule Offenburg

View File

@ -1,5 +1,6 @@
#Thu Apr 25 17:58:09 WEST 2019
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip