From 8fb41d65206bae867d3b53e4d72ebe437dc0d510 Mon Sep 17 00:00:00 2001 From: denizk0461 Date: Fri, 28 Apr 2023 22:44:23 +0200 Subject: [PATCH] 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 --- .../studip/adapter/CanteenOfferItemAdapter.kt | 28 ++- .../studip/adapter/CanteenOfferPageAdapter.kt | 34 +--- .../studip/adapter/StudIPEventItemAdapter.kt | 2 +- .../com/denizk0461/studip/data/StwParser.kt | 3 +- .../java/com/denizk0461/studip/db/AppDAO.kt | 24 +++ .../com/denizk0461/studip/db/AppRepository.kt | 20 ++ .../studip/fragment/CanteenFragment.kt | 183 +++++------------- .../studip/fragment/CanteenPageFragment.kt | 166 ++++++++++++++-- .../studip/model/DietaryPreferences.kt | 2 + .../studip/viewmodel/CanteenPageViewModel.kt | 33 ++++ .../studip/viewmodel/CanteenViewModel.kt | 18 +- 11 files changed, 320 insertions(+), 193 deletions(-) create mode 100644 app/src/main/java/com/denizk0461/studip/viewmodel/CanteenPageViewModel.kt 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 bf2c9ba..360ec5c 100644 --- a/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferItemAdapter.kt +++ b/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferItemAdapter.kt @@ -3,8 +3,10 @@ package com.denizk0461.studip.adapter import android.view.LayoutInflater import android.view.ViewGroup import androidx.appcompat.content.res.AppCompatResources +import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import com.denizk0461.studip.R +import com.denizk0461.studip.data.AppDiffUtilCallback import com.denizk0461.studip.databinding.ItemCanteenBinding import com.denizk0461.studip.databinding.ItemCanteenLineBinding import com.denizk0461.studip.databinding.ItemIconBinding @@ -15,16 +17,16 @@ import com.denizk0461.studip.model.DietaryPreferences /** * Custom RecyclerView adapter that lays out the offers of a given canteen on a given day. * - * @param offers list of all offers filtered by canteen and day, grouped by category * @param onClickListener used for listening to clicks and long presses * @param displayAllergens whether the user wants allergens to be marked */ class CanteenOfferItemAdapter( - private val offers: List, private val onClickListener: OnClickListener, private val displayAllergens: Boolean, ) : RecyclerView.Adapter() { + private val offers: MutableList = mutableListOf() + /** * View holder class for parent class * @@ -121,7 +123,7 @@ class CanteenOfferItemAdapter( } // If no dietary preferences are met, set the view to display a neutral icon - if (indices.isEmpty()) indices.add(10) + if (indices.isEmpty()) indices.add(DietaryPreferences.NONE.ordinal) // Iterate through all icons that need to be displayed indices.forEach { index -> @@ -157,6 +159,26 @@ class CanteenOfferItemAdapter( } } + /** + * Updates the data and calculates the difference between the old dataset and the newly provided + * dataset. + * + * @param newData new dataset to be displayed + */ + fun setNewData(newData: List) { + // Calculate the difference between the old list and the new list + val diffResult = DiffUtil.calculateDiff(AppDiffUtilCallback(offers, newData)) + + // Remove all items from the list + offers.clear() + + // Add all items from the new list + offers.addAll(newData) + + // Tell the DiffUtil which items have changed between the two lists + diffResult.dispatchUpdatesTo(this) + } + /** * Adds a star to mark allergens present in an offer. Allergens will be displayed as a star '*' * next to the title. diff --git a/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferPageAdapter.kt b/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferPageAdapter.kt index d8d7b24..05475b1 100644 --- a/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferPageAdapter.kt +++ b/app/src/main/java/com/denizk0461/studip/adapter/CanteenOfferPageAdapter.kt @@ -4,53 +4,29 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter import com.denizk0461.studip.fragment.CanteenPageFragment -import com.denizk0461.studip.model.CanteenOfferGroup /** * Custom ViewPager adapter for managing multiple pages of canteen offers. * * @param fragmentActivity parent fragment activity - * @param offers all offers for a given canteen, grouped by category (not filtered by day at - * this point) - * @param daysCovered tells for how many days offers are available for. - * Example: if the next two weeks are available, Monday through Friday and - * excluding weekends, this value should be 10. - * @param onClickListener for managing click and long press events - * @param displayAllergens whether the user wants allergens to be marked */ class CanteenOfferPageAdapter( fragmentActivity: FragmentActivity, - private var offers: List, - private var daysCovered: Int, - private val onClickListener: CanteenOfferItemAdapter.OnClickListener, - private val displayAllergens: Boolean, ) : FragmentStateAdapter(fragmentActivity) { + private var count: Int = 0 + // Returns the count of days covered - override fun getItemCount(): Int = daysCovered + override fun getItemCount(): Int = count override fun createFragment(position: Int): Fragment = CanteenPageFragment( - offers, - onClickListener, - displayAllergens, position, ) - /** - * Update the entire list of items - * - * @param items the new set of items - */ - fun setNewItems(items: List, daysCovered: Int) { - // Update the count of days covered - this.daysCovered = daysCovered - - // Update items - offers = items - - // Force an update of the view. TODO replace with individual updates, as this is inefficient + fun setItemCount(newCount: Int) { + count = newCount notifyDataSetChanged() } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt b/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt index 02c3cdd..6677d8f 100644 --- a/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt +++ b/app/src/main/java/com/denizk0461/studip/adapter/StudIPEventItemAdapter.kt @@ -29,7 +29,7 @@ class StudIPEventItemAdapter( /** * List of all events. */ - private var events: MutableList = mutableListOf() + private val events: MutableList = mutableListOf() /** * Retrieve an instance of Calendar to check whether the adapter's day matches the current day. 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 e1b0ef1..6fedc78 100644 --- a/app/src/main/java/com/denizk0461/studip/data/StwParser.kt +++ b/app/src/main/java/com/denizk0461/studip/data/StwParser.kt @@ -240,7 +240,7 @@ class StwParser(application: Application) { categoryId, title = "NO\$ITEMS", price = "", - dietaryPreferences = "..........", + dietaryPreferences = "tttttttttt", allergens = "", ) ) @@ -324,7 +324,6 @@ class StwParser(application: Application) { text = text.substring(0 until indexSupOpen) + text.substring((indexSupClose + 6) until text.length) } - /* * Return the stripped and updated HTML string and join the allergen list to a cohesive * string without duplication. diff --git a/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt b/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt index cd4664e..e780226 100644 --- a/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt +++ b/app/src/main/java/com/denizk0461/studip/db/AppDAO.kt @@ -97,6 +97,30 @@ interface AppDAO { ) fun getOffersByPreference(prefs: String): LiveData> + /** + * Retrieves all canteen offers that match given day. Objects will be joined through their + * primary/foreign keys from instances of OfferDate.kt, OfferCanteen.kt, OfferCategory.kt, and + * OfferItem.kt. + * + * @return all canteen offers matching the given day exposed through a LiveData object + */ + @Query( + "SELECT * FROM offer_item " + + "JOIN offer_category ON offer_item.categoryId = offer_category.id " + + "JOIN offer_canteen ON offer_category.canteenId = offer_canteen.id " + + "JOIN offer_date ON offer_category.dateId = offer_date.id " + + "WHERE dateId = :day " + ) + fun getOffersByDay(day: Int): LiveData> + + /** + * Retrieves the amount of dates represented in the offers stored locally. Can be observed. + * + * @return date count as LiveData + */ + @Query("SELECT COUNT(*) FROM offer_date") + fun getDateCount(): LiveData + /** * Retrieves all canteen offer date objects. * diff --git a/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt b/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt index c8cc4ec..8da43fc 100644 --- a/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt +++ b/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt @@ -2,6 +2,7 @@ package com.denizk0461.studip.db import android.app.Application import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.preference.PreferenceManager import com.denizk0461.studip.model.* @@ -25,6 +26,11 @@ class AppRepository(app: Application) { // Blank dietary preference regular expression private val blankDietaryPrefs: String = DietaryPreferences.C_FALSE.toString().repeat(10) + /** + * Used to observe just to register an update of the user-set dietary preferences. + */ + val dietaryPreferencesUpdate: MutableLiveData = MutableLiveData(0) + companion object { /** * Reference to the app's repository. It is only instantiated once because it can only be @@ -79,6 +85,20 @@ class AppRepository(app: Application) { */ val allOffers: LiveData> = dao.allOffers + /** + * Retrieves all canteen offers that match given day. + * + * @return all canteen offers matching the given day exposed through a LiveData object + */ + fun getOffersByDay(day: Int): LiveData> = dao.getOffersByDay(day) + + /** + * Retrieves the amount of dates represented in the offers stored locally. Can be observed. + * + * @return date count as LiveData + */ + fun getDateCount(): LiveData = dao.getDateCount() + /** * Updates a schedule element. * 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 7e28d52..fdd81ec 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt @@ -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() - - // 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.groupElements(): List { - // 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 +// } } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/fragment/CanteenPageFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/CanteenPageFragment.kt index e5aad9e..583b948 100644 --- a/app/src/main/java/com/denizk0461/studip/fragment/CanteenPageFragment.kt +++ b/app/src/main/java/com/denizk0461/studip/fragment/CanteenPageFragment.kt @@ -4,28 +4,27 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.viewModels import androidx.recyclerview.widget.LinearLayoutManager import com.denizk0461.studip.adapter.CanteenOfferItemAdapter import com.denizk0461.studip.adapter.StudIPEventPageAdapter import com.denizk0461.studip.databinding.RecyclerViewBinding +import com.denizk0461.studip.model.CanteenOffer import com.denizk0461.studip.model.CanteenOfferGroup +import com.denizk0461.studip.model.CanteenOfferGroupElement +import com.denizk0461.studip.model.DietaryPreferences +import com.denizk0461.studip.sheet.AllergenSheet +import com.denizk0461.studip.viewmodel.CanteenPageViewModel /** * Fragment that is instantiated by [StudIPEventPageAdapter] to display individual days' pages and * their events. * - * @param offers all offers for a given canteen, grouped by category (not filtered by day at - * this point) - * @param onClickListener for managing click and long press events - * @param displayAllergens whether the user wants allergens to be marked - * @param currentDay current day + * @param currentDay day to display */ class CanteenPageFragment( - private var offers: List, - private val onClickListener: CanteenOfferItemAdapter.OnClickListener, - private val displayAllergens: Boolean, private val currentDay: Int, -) : AppFragment() { +) : AppFragment(), CanteenOfferItemAdapter.OnClickListener { // Nullable view binding reference private var _binding: RecyclerViewBinding? = null @@ -36,6 +35,13 @@ class CanteenPageFragment( */ private val binding get() = _binding!! + // View model reference for providing access to the database + private val viewModel: CanteenPageViewModel by viewModels() + + private lateinit var recyclerViewAdapter: CanteenOfferItemAdapter + + private val offerList: MutableList = mutableListOf() + // Instantiate the view binding override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = RecyclerViewBinding.inflate(inflater, container, false) @@ -45,6 +51,11 @@ class CanteenPageFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + recyclerViewAdapter = CanteenOfferItemAdapter( + this, + viewModel.preferenceAllergen, + ) + binding.recyclerView.apply { // Set page to scroll vertically layoutManager = LinearLayoutManager( @@ -56,16 +67,141 @@ class CanteenPageFragment( * by the newly created adapter (0 = Monday, 4 = Friday) * TODO check if the filtered list is empty, and tell the user if it is */ - val o = offers.filter { it.dateId == currentDay } +// val o = offers.filter { it.dateId == currentDay } - adapter = CanteenOfferItemAdapter( - o, - onClickListener, - displayAllergens, - ) + adapter = recyclerViewAdapter // Animate creation of new page scheduleLayoutAnimation() + + viewModel.getOffersByDay(currentDay).observe(viewLifecycleOwner) { offers -> + offerList.clear() + offerList.addAll(offers) + recyclerViewAdapter.setNewData(offers.filterElements().groupElements().distinct()) +// filterList() + } + } + + viewModel.dietaryPreferencesUpdate.observe(viewLifecycleOwner) { + filterList() } } + + private fun filterList() { + recyclerViewAdapter.setNewData(offerList.filterElements().groupElements().distinct()) + } + + /** + * 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.groupElements(): List { + + return map { (_, date, dateId, category, _, canteen, _, _, _, _, _) -> + // Create new group elements to group the already filtered elements by their categories + CanteenOfferGroup( + date, + dateId, + category, + canteen, + 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 + ) + } + ) + } + } + + private fun List.filterElements(): List { + + // Get dietary preference regex + val prefsRegex = getPrefRegex() + + return if (prefsRegex.toString() == DietaryPreferences.TEMPLATE_EMPTY) { + // Show all elements and skip filtering if no preference is set + this + } else { + // Filter for dietary preferences + this.filter { + prefsRegex.matches(it.dietaryPreferences) + } + } + } + + /** + * 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 == DietaryPreferences.TEMPLATE_EMPTY) { + Regex(DietaryPreferences.TEMPLATE_EMPTY) + } 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() + + // 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 += DietaryPreferences.TEMPLATE_EMPTY.substring(0 until index) + + DietaryPreferences.C_TRUE + + DietaryPreferences.TEMPLATE_EMPTY.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) + } + } + + /** + * Executed when an item has been clicked. + * + * @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 + } } \ No newline at end of file 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 2c5c536..db65055 100644 --- a/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt +++ b/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt @@ -137,6 +137,8 @@ enum class DietaryPreferences(val value: String) { */ const val C_FALSE: Char = '.' + const val TEMPLATE_EMPTY: String = ".........." + /** * Constructs a DietaryPrefObject from a regex string. String must be 10 characters long. * A char equal to C_TRUE is treated as a true boolean value. Any other char is treated as a diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenPageViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenPageViewModel.kt new file mode 100644 index 0000000..403e7d1 --- /dev/null +++ b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenPageViewModel.kt @@ -0,0 +1,33 @@ +package com.denizk0461.studip.viewmodel + +import android.app.Application +import androidx.lifecycle.LiveData +import com.denizk0461.studip.model.CanteenOffer +import com.denizk0461.studip.model.DietaryPreferences +import com.denizk0461.studip.model.SettingsPreferences + +class CanteenPageViewModel(app: Application) : AppViewModel(app) { + + /** + * Retrieves all canteen offers that match given day. + * + * @return all canteen offers matching the given day exposed through a LiveData object + */ + fun getOffersByDay(day: Int): LiveData> = + repo.getOffersByDay(day) + + val dietaryPreferencesUpdate: LiveData = repo.dietaryPreferencesUpdate + + /** + * Retrieve the user's dietary preferences. + * + * @return dietary preferences + */ + fun getDietaryPrefs(): DietaryPreferences.Object = repo.getDietaryPrefsAsObject() + + /** + * This value determines whether the user wants to have allergens marked. + */ + val preferenceAllergen: Boolean + get() = repo.getBooleanPreference(SettingsPreferences.ALLERGEN, defaultValue = true) +} \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt index 7a44fee..0d870f4 100644 --- a/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt +++ b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt @@ -22,12 +22,7 @@ class CanteenViewModel(app: Application) : AppViewModel(app) { */ val allOffers: LiveData> = repo.allOffers - /** - * Retrieve the user's dietary preferences. - * - * @return dietary preferences - */ - fun getDietaryPrefs(): DietaryPreferences.Object = repo.getDietaryPrefsAsObject() + /** * Retrieves all canteen offer date objects. @@ -54,6 +49,17 @@ class CanteenViewModel(app: Application) : AppViewModel(app) { doAsync { parser.parse(canteen, onRefreshUpdate, onFinish) } } + fun registerDietaryPreferencesUpdate() { + repo.dietaryPreferencesUpdate.postValue(repo.dietaryPreferencesUpdate.value?.plus(1)) + } + + /** + * Retrieves the amount of dates represented in the offers stored locally. Can be observed. + * + * @return date count as LiveData + */ + fun getDateCount(): LiveData = repo.getDateCount() + /** * Updates a given dietary preference to a new value. *