From 9d6489f83b2c3bd59cc42f6078e40c4973b0f120 Mon Sep 17 00:00:00 2001 From: denizk0461 Date: Thu, 27 Apr 2023 15:15:29 +0200 Subject: [PATCH] Implemented ability to change the fragment opened on app start; made some optimisations to DietaryPreferences.kt. BUG: tab layout mediator is annoying af --- .idea/inspectionProfiles/Project_Default.xml | 17 ++++++ .../studip/activity/MainActivity.kt | 15 +++++- .../studip/adapter/CanteenOfferItemAdapter.kt | 8 ++- .../com/denizk0461/studip/data/StwParser.kt | 16 +----- .../studip/fragment/CanteenFragment.kt | 18 ++++--- .../studip/model/DietaryPreferences.kt | 52 ++++++------------- .../denizk0461/studip/sheet/AllergenSheet.kt | 6 ++- .../denizk0461/studip/sheet/DevCodeSheet.kt | 20 +++---- .../studip/sheet/ScheduleUpdateSheet.kt | 10 ++-- app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values/strings.xml | 5 +- 11 files changed, 92 insertions(+), 77 deletions(-) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml index 7ec0e66..f7c3b50 100644 --- a/.idea/inspectionProfiles/Project_Default.xml +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -1,6 +1,23 @@ \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt b/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt index a0662ea..c9dabbc 100644 --- a/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt +++ b/app/src/main/java/com/denizk0461/studip/activity/MainActivity.kt @@ -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" diff --git a/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferItemAdapter.kt b/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferItemAdapter.kt index d9dc0fe..2039729 100644 --- a/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferItemAdapter.kt +++ b/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferItemAdapter.kt @@ -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, ) ) diff --git a/app/src/main/java/com/denizk0461/studip/data/StwParser.kt b/app/src/main/java/com/denizk0461/studip/data/StwParser.kt index 7948a83..4807d82 100644 --- a/app/src/main/java/com/denizk0461/studip/data/StwParser.kt +++ b/app/src/main/java/com/denizk0461/studip/data/StwParser.kt @@ -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)) diff --git a/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt index 391b2ca..52655a0 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt @@ -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) { // 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() }) diff --git a/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt b/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt index 1ec5954..d236961 100644 --- a/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt +++ b/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt @@ -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 = 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 = 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 = 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 + } } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/sheet/AllergenSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/AllergenSheet.kt index c8ad8b0..b45b46b 100644 --- a/app/src/main/java/com/denizk0461/studip/sheet/AllergenSheet.kt +++ b/app/src/main/java/com/denizk0461/studip/sheet/AllergenSheet.kt @@ -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, ) ) diff --git a/app/src/main/java/com/denizk0461/studip/sheet/DevCodeSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/DevCodeSheet.kt index 77ea14b..c10626f 100644 --- a/app/src/main/java/com/denizk0461/studip/sheet/DevCodeSheet.kt +++ b/app/src/main/java/com/denizk0461/studip/sheet/DevCodeSheet.kt @@ -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 ) diff --git a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt index 6de8f7f..fa7fae9 100644 --- a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt +++ b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt @@ -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) { diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3c40651..0421b4f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -21,6 +21,8 @@ Raum Auf akademisches Viertel umstellen Sorry, ein Fehler ist aufgetreten! + Der Kurs kann nicht anfangen nachdem er aufhört! + Der Kurs kann nicht enden bevor er anfängt! Kein Angebot Für diesen Tag sind keine Angebote vorhanden diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aff62c3..003a97d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -22,6 +22,8 @@ Change to academic quarter Sorry, an error occurred! + The course can\'t begin after it ends! + The course can\'t end before it begins! No offers There are no offers available for this day @@ -47,9 +49,10 @@ Interimsmensa HfK [ %s ] + \? - Fair + Animal Welfare Fish Poultry Lamb