Archived
Implemented allergen functionality by showing the user a bottom sheet
This commit is contained in:
@@ -156,14 +156,17 @@ class StwParser {
|
||||
isGame = prefs.isDietaryPreferenceMet(imageLinkPrefGame),
|
||||
).deconstruct()
|
||||
|
||||
val filteredText = tableRows[1].getFilteredText()
|
||||
|
||||
// Save the item to persistent storage
|
||||
repo.insert(
|
||||
OfferItem(
|
||||
itemId,
|
||||
categoryId,
|
||||
title = tableRows[1].getFilteredText(),
|
||||
title = filteredText.first,
|
||||
price = tableRows.getTextOrEmpty(2),
|
||||
prefString,
|
||||
dietaryPreferences = prefString,
|
||||
allergens = filteredText.second,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -193,28 +196,67 @@ class StwParser {
|
||||
/**
|
||||
* Processes certain character references into human-readable characters. Since the fetched HTML
|
||||
* contains unresolved symbols such as &, they need to be replaced with their counterpart
|
||||
* (in this case, &).
|
||||
* (in this case, &). This method also parses allergens and additives, since they are listed on
|
||||
* the website of the Studierendenwerk, but they are invisible, rendering them pointless to the
|
||||
* website user.
|
||||
*
|
||||
* @return the filtered string
|
||||
* @return the filtered string and a string describing allergens and additives
|
||||
*/
|
||||
private fun Element.getFilteredText(): String {
|
||||
private fun Element.getFilteredText(): Pair<String, String> {
|
||||
// Retrieve the element's inner HTML and replace faulty characters
|
||||
var text = html()
|
||||
.replace("&", "&")
|
||||
.replace(">", ">")
|
||||
.replace("<", "<")
|
||||
|
||||
// All allergens will be collected here
|
||||
var allergens: String = ""
|
||||
|
||||
/*
|
||||
* Used to determine whether any allergens have already been found in the item. Should this
|
||||
* be the case, a delimiter is added.
|
||||
*/
|
||||
var hasAllergens: Boolean = false
|
||||
|
||||
/*
|
||||
* Allergens are stored in super tags. Example:
|
||||
* <sup>4, a1, a4, c, g</sup>
|
||||
* This is the start index of the opening tag (inclusive).
|
||||
*/
|
||||
var indexSupOpen = 0
|
||||
|
||||
// This is the end index of the closing tag (exclusive)
|
||||
var indexSupClose = 0
|
||||
|
||||
/*
|
||||
* The Studierendenwerk's website lists allergens, but they are invisible, rendering them
|
||||
* pointless to the website user. As of now, this information is discarded in the app.
|
||||
* TODO implement allergen functionality
|
||||
*/
|
||||
// while (text.contains("<sup>")) {
|
||||
// text = text.substring(0 until text.indexOf("<sup>")) + text.substring(text.indexOf("</sup>")+6 until text.length)
|
||||
// }
|
||||
while (text.contains("<sup>")) {
|
||||
// Add a delimiter if allergens have already been added
|
||||
if (hasAllergens) allergens += ","
|
||||
|
||||
// Set indices for the <sup> tags
|
||||
indexSupOpen = text.indexOf("<sup>")
|
||||
indexSupClose = text.indexOf("</sup>")
|
||||
|
||||
// Add allergens
|
||||
allergens += text.substring(indexSupOpen + 5 until indexSupClose)
|
||||
|
||||
// Remove allergens from the title of the offer
|
||||
text = text.substring(0 until indexSupOpen) +
|
||||
text.substring((indexSupClose + 6) until text.length)
|
||||
|
||||
/*
|
||||
* Make sure that the delimiter will be added if more than one instance of allergens is
|
||||
* found.
|
||||
*/
|
||||
hasAllergens = true
|
||||
}
|
||||
|
||||
// Return the stripped and updated HTML string
|
||||
return text
|
||||
return Pair(text, allergens)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ import com.denizk0461.studip.model.*
|
||||
OfferCategory::class,
|
||||
OfferItem::class
|
||||
],
|
||||
version = 10,
|
||||
version = 11,
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.denizk0461.studip.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@@ -130,6 +129,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
viewModel.fetchOffers(onRefreshUpdate = { status ->
|
||||
// TODO refresh updates
|
||||
}, onFinish = {
|
||||
createTabLayoutMediator()
|
||||
// binding.swipeRefreshLayout.isRefreshing = false
|
||||
// createTabLayoutMediator()
|
||||
})
|
||||
@@ -138,16 +138,17 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
|
||||
/**
|
||||
* Create and attach the object mediating the tabs for the view pager.
|
||||
* TODO this is crash-prone
|
||||
*/
|
||||
private fun createTabLayoutMediator() {
|
||||
// Fetch all dates from the database
|
||||
val dates = viewModel.getDates()
|
||||
|
||||
if (dates.isNotEmpty()) {
|
||||
Log.d("eek!7", "dates: ${dates}, viewpager pages: ${binding.viewPager.adapter?.itemCount}")
|
||||
TabLayoutMediator(binding.dayTabLayout, binding.viewPager) { tab, position ->
|
||||
Log.d("eek!9", position.toString())
|
||||
tab.text = dates[position].date
|
||||
}.attach()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +265,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
|
||||
it.title,
|
||||
it.price,
|
||||
it.dietaryPreferences,
|
||||
it.allergens
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.denizk0461.studip.model
|
||||
|
||||
import com.denizk0461.studip.R
|
||||
|
||||
object Allergens {
|
||||
/**
|
||||
* Converts an allergen into the string ID for its localised full-text version. Elements are
|
||||
* derived from the website of the Studierendenwerk Bremen:
|
||||
* https://www.stw-bremen.de/de/mensa/allergene
|
||||
*
|
||||
* @param value allergen that will be converted
|
||||
* @return string resource ID for the allergen
|
||||
*/
|
||||
fun getStringRes(value: String): Int = when (value) {
|
||||
// Additives
|
||||
"1" -> R.string.allergen_dye
|
||||
"2" -> R.string.allergen_preservatives
|
||||
"3" -> R.string.allergen_antioxidants
|
||||
"4" -> R.string.allergen_phosphates
|
||||
"5" -> R.string.allergen_sweeteners
|
||||
"6" -> R.string.allergen_phenylalanine
|
||||
"7" -> R.string.allergen_sulphured
|
||||
"8" -> R.string.allergen_blackened
|
||||
"9" -> R.string.allergen_waxed
|
||||
"10" -> R.string.allergen_alcohol
|
||||
"11" -> R.string.allergen_flavour_enhancers
|
||||
"12" -> R.string.allergen_caffeine
|
||||
"13" -> R.string.allergen_rennet
|
||||
// Allergens
|
||||
"a1" -> R.string.allergen_wheat
|
||||
"a2" -> R.string.allergen_rye
|
||||
"a3" -> R.string.allergen_barley
|
||||
"a4" -> R.string.allergen_oat
|
||||
"a5" -> R.string.allergen_spelt
|
||||
"a6" -> R.string.allergen_kamut
|
||||
"b" -> R.string.allergen_crustaceans
|
||||
"c" -> R.string.allergen_eggs
|
||||
"d" -> R.string.allergen_fish
|
||||
"e" -> R.string.allergen_peanuts
|
||||
"f" -> R.string.allergen_soy
|
||||
"g" -> R.string.allergen_dairy
|
||||
"h1" -> R.string.allergen_almonds
|
||||
"h2" -> R.string.allergen_hazelnuts
|
||||
"h3" -> R.string.allergen_walnuts
|
||||
"h4" -> R.string.allergen_cashew_nuts
|
||||
"h5" -> R.string.allergen_pecans
|
||||
"h6" -> R.string.allergen_brazil_nuts
|
||||
"h7" -> R.string.allergen_pistachios
|
||||
"h8" -> R.string.allergen_macadamia
|
||||
"i" -> R.string.allergen_celery
|
||||
"j" -> R.string.allergen_mustard
|
||||
"k" -> R.string.allergen_sulphides
|
||||
"l" -> R.string.allergen_lupins
|
||||
"m" -> R.string.allergen_sesame
|
||||
"n" -> R.string.allergen_molluscs
|
||||
else -> 0 // shouldn't occur
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import androidx.room.ColumnInfo
|
||||
* @param price students' price for the individual canteen offer
|
||||
* @param dietaryPreferences dietary preferences used to filter for the user's needs - see
|
||||
* DietaryPrefObject.kt
|
||||
* @param allergens allergens and additives that are present in the item
|
||||
*/
|
||||
data class CanteenOffer(
|
||||
val itemId: Int,
|
||||
@@ -31,4 +32,5 @@ data class CanteenOffer(
|
||||
val title: String,
|
||||
val price: String,
|
||||
@ColumnInfo(name = "dietary_preferences") val dietaryPreferences: String,
|
||||
val allergens: String,
|
||||
)
|
||||
|
||||
@@ -9,9 +9,11 @@ package com.denizk0461.studip.model
|
||||
* @param price students' price for the individual canteen offer
|
||||
* @param dietaryPreferences dietary preferences used to filter for the user's needs - see
|
||||
* DietaryPrefObject.kt
|
||||
* @param allergens allergens and additives that are present in the item
|
||||
*/
|
||||
data class CanteenOfferGroupElement(
|
||||
val title: String,
|
||||
val price: String,
|
||||
val dietaryPreferences: String,
|
||||
val allergens: String,
|
||||
)
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.room.PrimaryKey
|
||||
* @param price students' price for the individual canteen offer
|
||||
* @param dietaryPreferences dietary preferences used to filter for the user's needs - see
|
||||
* DietaryPrefObject.kt
|
||||
* @param allergens allergens and additives that are present in the item
|
||||
*/
|
||||
@Entity(
|
||||
tableName = "offer_item",
|
||||
@@ -32,4 +33,5 @@ data class OfferItem(
|
||||
val title: String,
|
||||
val price: String,
|
||||
@ColumnInfo(name = "dietary_preferences") val dietaryPreferences: String,
|
||||
val allergens: String,
|
||||
)
|
||||
@@ -5,6 +5,7 @@ import android.view.View
|
||||
import com.denizk0461.studip.R
|
||||
import com.denizk0461.studip.data.viewBinding
|
||||
import com.denizk0461.studip.databinding.SheetAllergenBinding
|
||||
import com.denizk0461.studip.model.Allergens
|
||||
import com.denizk0461.studip.model.CanteenOfferGroupElement
|
||||
|
||||
class AllergenSheet(private val offer: CanteenOfferGroupElement) : AppSheet(R.layout.sheet_allergen) {
|
||||
@@ -16,7 +17,43 @@ class AllergenSheet(private val offer: CanteenOfferGroupElement) : AppSheet(R.la
|
||||
|
||||
binding.apply {
|
||||
title.text = offer.title
|
||||
textContent.text = "hello there"
|
||||
textContent.text = offer.allergens.compileAllergenString()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves localised strings for all allergens present in a given offer and compiles them into
|
||||
* a human-readable string, if any allergens are present.
|
||||
*
|
||||
* @return a string of all allergens
|
||||
*/
|
||||
private fun String.compileAllergenString(): String {
|
||||
|
||||
// Let the user know if no allergens are present
|
||||
if (this.isBlank()) return getString(R.string.allergens_none)
|
||||
|
||||
// Stores all localised allergens
|
||||
var allergenString = ""
|
||||
|
||||
// Used to insert a delimiter if more than one allergen is found
|
||||
var isFirst = true
|
||||
|
||||
// Split all allergens to iterate through them
|
||||
val allergens = this.replace(" ", "").split(",")
|
||||
|
||||
// Iterate through all allergens
|
||||
allergens.forEach { allergen ->
|
||||
// Insert a delimiter if more than one allergen is found
|
||||
if (!isFirst) allergenString += ", "
|
||||
|
||||
// Add a localised string for the allergen
|
||||
allergenString += getString(Allergens.getStringRes(allergen))
|
||||
|
||||
// Set when the first allergen has been processed
|
||||
isFirst = false
|
||||
}
|
||||
|
||||
// Insert the allergens into a template string
|
||||
return getString(R.string.allergens_contains, allergenString)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user