Edited canteen views to have direct database access in the CanteenPageFragment.kt, allowing for filtering the individual days through the database; filtering now works (with changes animated!!) through updating a LiveData and observing it in the page fragment

This commit is contained in:
denizk0461
2023-04-28 22:44:23 +02:00
parent 509a0434c5
commit 8fb41d6520
11 changed files with 320 additions and 193 deletions
@@ -8,11 +8,9 @@ import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.viewModels
import com.denizk0461.studip.R
import com.denizk0461.studip.adapter.CanteenOfferItemAdapter
import com.denizk0461.studip.adapter.CanteenOfferPageAdapter
import com.denizk0461.studip.databinding.FragmentCanteenBinding
import com.denizk0461.studip.model.*
import com.denizk0461.studip.sheet.AllergenSheet
import com.denizk0461.studip.sheet.TextSheet
import com.denizk0461.studip.viewmodel.CanteenViewModel
import com.google.android.material.tabs.TabLayoutMediator
@@ -21,7 +19,7 @@ import com.google.android.material.tabs.TabLayoutMediator
* User-facing fragment view that displays the canteen offers from the website of the
* Studierendenwerk Bremen.
*/
class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
class CanteenFragment : AppFragment() {
// Nullable view binding reference
private var _binding: FragmentCanteenBinding? = null
@@ -83,7 +81,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
binding.swipeRefreshLayout.isRefreshing = true
// Refresh the canteen menu for the newly selected canteen
refresh()
// refresh()
true
}
inflate(R.menu.menu_canteens)
@@ -148,40 +146,41 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
// Set up the view pager's adapter
viewPagerAdapter = CanteenOfferPageAdapter(
activity as FragmentActivity,
listOf(),
0,
this,
viewModel.preferenceAllergen,
)
viewModel.getDateCount().observe(viewLifecycleOwner) { dateCount ->
viewPagerAdapter.itemCount = dateCount
binding.swipeRefreshLayout.isRefreshing = false
}
// Assign the adapter to the view pager
binding.viewPager.adapter = viewPagerAdapter
// Set up LiveData observer to refresh the view on update
viewModel.allOffers.observe(viewLifecycleOwner) { offers ->
// Update the element list stored in this fragment
elements = offers
// Group elements by category
val groupedElements = offers.groupElements().distinct()
// Find all dates for which items are available
val newDates = groupedElements.map { it.date }.distinct()
// Update the date count stored in this fragment
dateSize = newDates.size
// Update the item list in the view pager's adapter
viewPagerAdapter.setNewItems(groupedElements, dateSize)
// Set the text for the opening hours dialogue
openingHours = viewModel.getCanteenOpeningHours()
binding.swipeRefreshLayout.isRefreshing = false
// Create and attach the tab layout for the ViewPager
createTabLayoutMediator(newDates)
}
// viewModel.allOffers.observe(viewLifecycleOwner) { offers ->
// // Update the element list stored in this fragment
// elements = offers
//
// // Group elements by category
// val groupedElements = offers.groupElements().distinct()
//
// // Find all dates for which items are available
// val newDates = groupedElements.map { it.date }.distinct()
//
// // Update the date count stored in this fragment
// dateSize = newDates.size
//
// // Update the item list in the view pager's adapter
//// viewPagerAdapter.setNewItems(groupedElements, dateSize)
//
// // Set the text for the opening hours dialogue
// openingHours = viewModel.getCanteenOpeningHours()
//
// binding.swipeRefreshLayout.isRefreshing = false
//
// // Create and attach the tab layout for the ViewPager
// createTabLayoutMediator(newDates)
// }
// Set up functions for when the user swipes to refresh the view
binding.swipeRefreshLayout.setOnRefreshListener {
@@ -223,7 +222,8 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
viewModel.setPreference(pref, newValue)
// Update the view
viewPagerAdapter.setNewItems(elements.groupElements().distinct(), dateSize)
viewModel.registerDietaryPreferencesUpdate()
// viewPagerAdapter.setNewItems(elements.groupElements().distinct(), dateSize)
}
/**
@@ -235,97 +235,6 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
private fun getPreference(pref: DietaryPreferences): Boolean =
viewModel.getPreference(pref)
/**
* Retrieves the user's dietary preferences and compiles them into a regular expression that can
* be used to filter out items that don't fulfil the preferences. Example:
* .......t..|........t.
* This will retrieve all items that marked as either vegetarian or vegan
* *
* @return regular expression object reflecting the user's preferences
*/
private fun getPrefRegex(): Regex {
// Retrieve the user's dietary preference as a string
val prefs = viewModel.getDietaryPrefs().deconstruct()
// Return the 'empty' template string if no preference has been set or found
return if (prefs == emptyPreferenceRegex) {
Regex(emptyPreferenceRegex)
} else {
// Create the variable to insert the regular expression into
var regexString = ""
// Create the object to store which preferences need to be met
val indices = mutableListOf<Int>()
// Find all preferences that need to be met
prefs.forEachIndexed { index, c ->
if (c == DietaryPreferences.C_TRUE) indices.add(index)
}
// Needs to be set to correctly assemble the regular expression
var isFirst = true
// Iterate through every preference that has been set
indices.forEach { index ->
// Set an OR if more than one preference needs to be met
if (!isFirst) regexString += '|'
// Add the expression looking for the single preference to the entire string
regexString += emptyPreferenceRegex.substring(0 until index) +
DietaryPreferences.C_TRUE +
emptyPreferenceRegex.substring(index+1)
// Ensure that OR statements will be placed between the individual expressions
isFirst = false
}
// Compile the string to a regular expression object
Regex(regexString)
}
}
/**
* Groups [CanteenOffer] elements by their categories into [CanteenOfferGroup] elements and
* filters for the user's dietary preferences.
*
* @return the grouped and filtered elements
*/
private fun List<CanteenOffer>.groupElements(): List<CanteenOfferGroup> {
// Get dietary preference regex
val prefsRegex = getPrefRegex()
val filteredForPrefs = if (prefsRegex.toString() == emptyPreferenceRegex) {
// Show all elements and skip filtering if no preference is set
this
} else {
// Filter for dietary preferences
this.filter {
prefsRegex.matches(it.dietaryPreferences)
}
}
return filteredForPrefs.map { (_, date, dateId, category, _, canteen, _, _, _, _, _) ->
// Create new group elements to group the already filtered elements by their categories
CanteenOfferGroup(
date,
dateId,
category,
canteen,
filteredForPrefs.filter {
it.category == category && it.date == date && it.canteen == canteen
}.map {
// Map the individual items to their respective groups
CanteenOfferGroupElement(
it.title,
it.price,
it.dietaryPreferences,
it.allergens
)
}
)
}
}
/**
* Retrieves the localised string for the canteen selected by the user.
*
@@ -370,17 +279,17 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
*
* @param offer item that has been clicked
*/
override fun onClick(offer: CanteenOfferGroupElement, category: String) {
openBottomSheet(AllergenSheet(offer, category))
}
/**
* Executed when an item has been long-pressed.
*
* @param offer item that has been long-pressed
* @return whether the long press was successful
*/
override fun onLongClick(offer: CanteenOfferGroupElement): Boolean {
return false
}
// override fun onClick(offer: CanteenOfferGroupElement, category: String) {
// openBottomSheet(AllergenSheet(offer, category))
// }
//
// /**
// * Executed when an item has been long-pressed.
// *
// * @param offer item that has been long-pressed
// * @return whether the long press was successful
// */
// override fun onLongClick(offer: CanteenOfferGroupElement): Boolean {
// return false
// }
}