Archived
Implemented ability to change the fragment opened on app start; made some optimisations to DietaryPreferences.kt. BUG: tab layout mediator is annoying af
This commit is contained in:
@@ -12,6 +12,7 @@ import com.denizk0461.studip.db.AppRepository
|
||||
import com.denizk0461.studip.fragment.EventFragment
|
||||
import com.denizk0461.studip.fragment.CanteenFragment
|
||||
import com.denizk0461.studip.fragment.SettingsFragment
|
||||
import com.denizk0461.studip.model.SettingsPreferences
|
||||
|
||||
/**
|
||||
* Main activity that handles all common fragments. This is opened on app launch.
|
||||
@@ -41,9 +42,21 @@ class MainActivity : AppCompatActivity() {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
// Open the fragment that the user specified to open on app start
|
||||
if (
|
||||
Dependencies.repo.getBooleanPreference(SettingsPreferences.LAUNCH_CANTEEN_ON_START)
|
||||
) {
|
||||
// Open canteen fragment
|
||||
binding.contentMain.navView.selectedItemId = R.id.food
|
||||
currentFragment = "canteen"
|
||||
} else {
|
||||
// Open event fragment
|
||||
binding.contentMain.navView.selectedItemId = R.id.plan
|
||||
currentFragment = "event"
|
||||
}
|
||||
|
||||
// Set up navigation view bar to launch fragments
|
||||
binding.contentMain.navView.setOnItemSelectedListener { item ->
|
||||
|
||||
// Launch fragment based on the item that has been clicked
|
||||
loadFragment(when (item.itemId) {
|
||||
R.id.food -> "canteen"
|
||||
|
||||
@@ -68,11 +68,13 @@ class CanteenOfferItemAdapter(
|
||||
// Inflate a new icon holder
|
||||
val img = ItemIconBinding.inflate(LayoutInflater.from(holder.binding.root.context))
|
||||
|
||||
val (_, drawableId) = DietaryPreferences.getData(DietaryPreferences.ERROR.ordinal)
|
||||
|
||||
// Set a cross icon
|
||||
img.imageView.setImageDrawable(
|
||||
AppCompatResources.getDrawable(
|
||||
holder.binding.root.context,
|
||||
DietaryPreferences.indexToDrawable[11]!!,
|
||||
drawableId,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -117,11 +119,13 @@ class CanteenOfferItemAdapter(
|
||||
// Inflate a new icon holder
|
||||
val img = ItemIconBinding.inflate(LayoutInflater.from(holder.binding.root.context))
|
||||
|
||||
val (_, drawableId) = DietaryPreferences.getData(index)
|
||||
|
||||
// Set the appropriate icon
|
||||
img.imageView.setImageDrawable(
|
||||
AppCompatResources.getDrawable(
|
||||
holder.binding.root.context,
|
||||
DietaryPreferences.indexToDrawable[index]!!,
|
||||
drawableId,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.denizk0461.studip.data
|
||||
|
||||
import android.util.Log
|
||||
import com.denizk0461.studip.db.AppRepository
|
||||
import com.denizk0461.studip.model.*
|
||||
import org.jsoup.Jsoup
|
||||
@@ -63,19 +62,10 @@ class StwParser {
|
||||
// Delete all previous entries and start afresh
|
||||
Dependencies.repo.nukeOffers()
|
||||
|
||||
/*
|
||||
* Fetch offers from every canteen individually. This is done in sequence for
|
||||
* simplicity's sake.
|
||||
* TODO perhaps it can be assumed here that the next two weeks will always be available?
|
||||
* Hence, the date fetch might be superfluous and a database insert call could be
|
||||
* implemented here instead. Another option would be to set the conflict policy to IGNORE
|
||||
* and move the dateId reset from parseFromPage() to parse().
|
||||
*/
|
||||
// links.forEach { link ->
|
||||
parseFromPage(link, Dependencies.repo)
|
||||
// Fetch offers from the chosen canteen
|
||||
parseFromPage(link, Dependencies.repo)
|
||||
|
||||
// TODO implement onRefresh(Int)
|
||||
// }
|
||||
|
||||
// Action call once all fetching activities have finished
|
||||
onFinish()
|
||||
@@ -175,8 +165,6 @@ class StwParser {
|
||||
// Retrieve the category text
|
||||
val categoryTitle = category.getElementsByClass("category-name")[0].text()
|
||||
|
||||
Log.d("AAA?", "$date on $categoryTitle")
|
||||
|
||||
// Save the category to persistent storage
|
||||
repo.insert(OfferCategory(categoryId, dateId, canteenId, categoryTitle))
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
binding.viewPager.adapter = viewPagerAdapter
|
||||
|
||||
// Create and attach the tab mediator for the view pager
|
||||
createTabLayoutMediator()
|
||||
// createTabLayoutMediator()
|
||||
|
||||
// Set up LiveData observer to refresh the view on update
|
||||
viewModel.allOffers.observe(viewLifecycleOwner) { offers ->
|
||||
@@ -163,7 +163,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
val groupedElements = offers.groupElements().distinct()
|
||||
|
||||
// Find all dates stored in the database
|
||||
val newDates = groupedElements.map { it.date }.distinct() // TODO viewModel.getDates()
|
||||
val newDates = /*groupedElements.map { it.date }.distinct() TODO */viewModel.getDates()
|
||||
|
||||
// Update the date count stored in this fragment
|
||||
dateSize = newDates.size
|
||||
@@ -173,6 +173,10 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
|
||||
// Set the text for the opening hours dialogue
|
||||
openingHours = viewModel.getCanteenOpeningHours()
|
||||
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
|
||||
// createTabLayoutMediator(newDates)
|
||||
}
|
||||
|
||||
// Set up functions for when the user swipes to refresh the view
|
||||
@@ -185,10 +189,11 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
* Create and attach the object mediating the tabs for the view pager.
|
||||
* TODO this is crash-prone and doesn't refresh when the dates get renewed (when the last update
|
||||
* was from the day prior)
|
||||
* TODO WHY DO YOU THROW AN INDEXOUTOFBOUNDSEXCEPTION????
|
||||
*/
|
||||
private fun createTabLayoutMediator() {
|
||||
private fun createTabLayoutMediator(dates: List<OfferDate>) {
|
||||
// Fetch all dates from the database
|
||||
val dates = viewModel.getDates()
|
||||
// val dates = viewModel.getDates()
|
||||
|
||||
if (dates.isNotEmpty()) {
|
||||
TabLayoutMediator(binding.dayTabLayout, binding.viewPager) { tab, position ->
|
||||
@@ -340,6 +345,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
|
||||
/**
|
||||
* Downloads the canteen offers and refreshes them in the app.
|
||||
* TODO handle SocketTimeoutException
|
||||
*/
|
||||
private fun refresh() {
|
||||
// Retrieve new offers from the website(s)
|
||||
@@ -350,10 +356,6 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
* Tell the swipe refresh layout to stop refreshing.
|
||||
* TODO if an exception is raised, this will not be fired. This must be changed
|
||||
*/
|
||||
binding.swipeRefreshLayout.isRefreshing = false
|
||||
|
||||
|
||||
// createTabLayoutMediator()
|
||||
// binding.swipeRefreshLayout.isRefreshing = false
|
||||
// createTabLayoutMediator()
|
||||
})
|
||||
|
||||
@@ -21,46 +21,28 @@ enum class DietaryPreferences(val value: String) {
|
||||
VEGAN("isVegan"),
|
||||
VEGETARIAN("isVegetarian"),
|
||||
GAME("isGame"),
|
||||
NONE("hasNone"),
|
||||
ERROR("onError")
|
||||
;
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Provides a converting function between the index of a dietary preference and its according
|
||||
* icon.
|
||||
* TODO this seems inefficient
|
||||
*/
|
||||
val indexToDrawable: Map<Int, Int> = mapOf(
|
||||
0 to R.drawable.handshake,
|
||||
1 to R.drawable.fish,
|
||||
2 to R.drawable.chicken,
|
||||
3 to R.drawable.sheep,
|
||||
4 to R.drawable.yoga,
|
||||
5 to R.drawable.cow,
|
||||
6 to R.drawable.pig,
|
||||
7 to R.drawable.leaf,
|
||||
8 to R.drawable.carrot,
|
||||
9 to R.drawable.deer,
|
||||
10 to R.drawable.circle,
|
||||
11 to R.drawable.cross,
|
||||
)
|
||||
|
||||
/**
|
||||
* Provides a converting function between the index of a dietary preference and its
|
||||
* according localised text string.
|
||||
* TODO this seems inefficient
|
||||
* Provides a converting function between
|
||||
*/
|
||||
val indexToString: Map<Int, Int> = mapOf(
|
||||
0 to R.string.pref_fair,
|
||||
1 to R.string.pref_fish,
|
||||
2 to R.string.pref_poultry,
|
||||
3 to R.string.pref_lamb,
|
||||
4 to R.string.pref_vital,
|
||||
5 to R.string.pref_beef,
|
||||
6 to R.string.pref_pork,
|
||||
7 to R.string.pref_vegan,
|
||||
8 to R.string.pref_vegetarian,
|
||||
9 to R.string.pref_game,
|
||||
10 to 0, // shouldn't occur
|
||||
)
|
||||
fun getData(index: Int): Pair<Int, Int> = when (index) {
|
||||
FAIR.ordinal -> Pair(R.string.pref_fair, R.drawable.handshake)
|
||||
FISH.ordinal -> Pair(R.string.pref_fish, R.drawable.fish)
|
||||
POULTRY.ordinal -> Pair(R.string.pref_poultry, R.drawable.chicken)
|
||||
LAMB.ordinal -> Pair(R.string.pref_lamb, R.drawable.sheep)
|
||||
VITAL.ordinal -> Pair(R.string.pref_vital, R.drawable.yoga)
|
||||
BEEF.ordinal -> Pair(R.string.pref_beef, R.drawable.cow)
|
||||
PORK.ordinal -> Pair(R.string.pref_pork, R.drawable.pig)
|
||||
VEGAN.ordinal -> Pair(R.string.pref_vegan, R.drawable.leaf)
|
||||
VEGETARIAN.ordinal -> Pair(R.string.pref_vegetarian, R.drawable.carrot)
|
||||
GAME.ordinal -> Pair(R.string.pref_game, R.drawable.deer)
|
||||
NONE.ordinal -> Pair(R.string.question_mark, R.drawable.circle)
|
||||
else -> Pair(R.string.question_mark, R.drawable.cross) // ERROR.ordinal
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,14 +45,16 @@ class AllergenSheet(
|
||||
// Inflate the view
|
||||
val prefLine = ItemSheetPreferenceBinding.inflate(LayoutInflater.from(context))
|
||||
|
||||
val (stringId, drawableId) = DietaryPreferences.getData(index)
|
||||
|
||||
// Add the localised text for the preference
|
||||
prefLine.preferenceText.text = getString(DietaryPreferences.indexToString[index]!!)
|
||||
prefLine.preferenceText.text = getString(stringId)
|
||||
|
||||
// Set the appropriate icon
|
||||
prefLine.preferenceImage.setImageDrawable(
|
||||
getDrawable(
|
||||
context,
|
||||
DietaryPreferences.indexToDrawable[index]!!,
|
||||
drawableId,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.util.Base64
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import com.denizk0461.studip.R
|
||||
import com.denizk0461.studip.data.showToast
|
||||
import com.denizk0461.studip.data.viewBinding
|
||||
@@ -52,13 +51,14 @@ class DevCodeSheet(
|
||||
* If you're reading this – why?
|
||||
*/
|
||||
when (binding.input.text.toString().uppercase()) {
|
||||
"U1RST0JF".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90S2k5Wi1mNnFYNA==".d())
|
||||
"U1BJUklU".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9XN25lMzlEU05TZw==".d())
|
||||
"Q0xPVURT".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9rbUJ6YTRhNTB2dw==".d())
|
||||
"NjQxODJL".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9EbTFyZ285UHBUcw==".d())
|
||||
"U0FJTE9S".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9QUHlDYXZ6OG5NWQ==".d())
|
||||
"SE9ORVNU".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9DSEg0OE5LUEFraw==".d())
|
||||
"QkJVT0s/".d() -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90Rm1PMm1TY0tHNA==".d())
|
||||
"U1RST0JF".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90S2k5Wi1mNnFYNA==".d64)
|
||||
"U1BJUklU".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9XN25lMzlEU05TZw==".d64)
|
||||
"Q0xPVURT".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9rbUJ6YTRhNTB2dw==".d64)
|
||||
"NjQxODJL".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9EbTFyZ285UHBUcw==".d64)
|
||||
"U0FJTE9S".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9QUHlDYXZ6OG5NWQ==".d64)
|
||||
"SE9ORVNU".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9DSEg0OE5LUEFraw==".d64)
|
||||
"QkJVT0s/".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90Rm1PMm1TY0tHNA==".d64)
|
||||
"SUhUU0Mq".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS85bXZ4SVdhWHZuWQ==".d64)
|
||||
"NEVENT" -> { // nuke events
|
||||
nukeEvents()
|
||||
showToast(context, "Nuked all events")
|
||||
@@ -107,7 +107,7 @@ class DevCodeSheet(
|
||||
*
|
||||
* @return the encoded string
|
||||
*/
|
||||
private fun String.e(): String = Base64.encodeToString(this.toByteArray(), Base64.DEFAULT)
|
||||
private val String.e64: String get() = Base64.encodeToString(this.toByteArray(), Base64.DEFAULT)
|
||||
|
||||
|
||||
/**
|
||||
@@ -115,7 +115,7 @@ class DevCodeSheet(
|
||||
*
|
||||
* @return the decoded string
|
||||
*/
|
||||
private fun String.d(): String = String(
|
||||
private val String.d64: String get() = String(
|
||||
Base64.decode(this, Base64.DEFAULT),
|
||||
StandardCharsets.UTF_8
|
||||
)
|
||||
|
||||
@@ -161,10 +161,12 @@ class ScheduleUpdateSheet(
|
||||
// Parse the separate ints into a timestamp string. Add a leading zero if necessary.
|
||||
val newTimestamp = "$hours:${String.format("%02d", minutes)}"
|
||||
|
||||
// If start > end, show an error
|
||||
if ((isEventStart && newTimestamp.parseToMinutes() > timeslotEnd.parseToMinutes()) ||
|
||||
(!isEventStart && newTimestamp.parseToMinutes() < timeslotStart.parseToMinutes())) {
|
||||
// TODO tell user that the timestamp must be set earlier/later
|
||||
if (isEventStart && newTimestamp.parseToMinutes() > timeslotEnd.parseToMinutes()) {
|
||||
// If editing start and start > end, show an error
|
||||
showToast(context, getString(R.string.sheet_schedule_update_timestamp_error_start))
|
||||
// If editing end and end < start, show an error
|
||||
} else if (!isEventStart && newTimestamp.parseToMinutes() < timeslotStart.parseToMinutes()) {
|
||||
showToast(context, getString(R.string.sheet_schedule_update_timestamp_error_end))
|
||||
} else {
|
||||
// If the new timestamp is valid, save it
|
||||
if (isEventStart) {
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<string name="sheet_schedule_update_room_hint">Raum</string>
|
||||
<string name="sheet_schedule_update_hint_quarter">Auf akademisches Viertel umstellen</string>
|
||||
<string name="sheet_schedule_update_hint_quarter_error">Sorry, ein Fehler ist aufgetreten!</string>
|
||||
<string name="sheet_schedule_update_timestamp_error_start">Der Kurs kann nicht anfangen nachdem er aufhört!</string>
|
||||
<string name="sheet_schedule_update_timestamp_error_end">Der Kurs kann nicht enden bevor er anfängt!</string>
|
||||
|
||||
<string name="canteen_no_offer_header">Kein Angebot</string>
|
||||
<string name="canteen_no_offer_desc">Für diesen Tag sind keine Angebote vorhanden</string>
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<string name="sheet_schedule_update_timeslot_middle" translatable="false">–</string>
|
||||
<string name="sheet_schedule_update_hint_quarter">Change to academic quarter</string>
|
||||
<string name="sheet_schedule_update_hint_quarter_error">Sorry, an error occurred!</string>
|
||||
<string name="sheet_schedule_update_timestamp_error_start">The course can\'t begin after it ends!</string>
|
||||
<string name="sheet_schedule_update_timestamp_error_end">The course can\'t end before it begins!</string>
|
||||
|
||||
<string name="canteen_no_offer_header">No offers</string>
|
||||
<string name="canteen_no_offer_desc">There are no offers available for this day</string>
|
||||
@@ -47,9 +49,10 @@
|
||||
<string name="mensa_hfk">Interimsmensa HfK</string>
|
||||
|
||||
<string name="sheet_category" translatable="false">[ %s ]</string>
|
||||
<string name="question_mark" translatable="false">\?</string>
|
||||
|
||||
<!-- dietary preferences -->
|
||||
<string name="pref_fair">Fair</string> <!-- is this really the best name? what about 'animal welfare'? -->
|
||||
<string name="pref_fair">Animal Welfare</string> <!-- TODO is this really the best name? what about 'animal welfare'? -->
|
||||
<string name="pref_fish">Fish</string>
|
||||
<string name="pref_poultry">Poultry</string>
|
||||
<string name="pref_lamb">Lamb</string>
|
||||
|
||||
Reference in New Issue
Block a user