Archived
Flattened structure of StwParser.kt somewhat; CanteenFragment.kt now shows an error snack if the user tries to switch canteens while another one is being fetched; made slight adjustments to the translations
This commit is contained in:
@@ -98,6 +98,7 @@ class StwParser(application: Application) {
|
||||
onFinish()
|
||||
|
||||
} catch (e: RuntimeException) {
|
||||
// e.printStackTrace()
|
||||
/*
|
||||
* Call action to let the user know an error occurred. Do this on the main thread to
|
||||
* access UI.
|
||||
@@ -122,9 +123,6 @@ class StwParser(application: Application) {
|
||||
val categories = mutableListOf<OfferCategory>()
|
||||
val items = mutableListOf<OfferItem>()
|
||||
|
||||
// Used to store a parsed date string without creating a new variable on every loop
|
||||
var date: String
|
||||
|
||||
// Reset the primary key value for the date objects
|
||||
dateId = 0
|
||||
|
||||
@@ -150,30 +148,16 @@ class StwParser(application: Application) {
|
||||
// Iterate through each day for which offers are available
|
||||
doc.getElementsByClass("food-plan").forEach { dayPlan ->
|
||||
|
||||
/*
|
||||
* Fetch the date for a given day. It will be in the following format:
|
||||
* 24. Apr
|
||||
* This value will be split between the day (24.) and the month (Apr)
|
||||
*/
|
||||
val rawDate = doc.getElementsByClass("tabs")[0]
|
||||
.getElementsByClass("tab-date")[dateId].text().split(" ")
|
||||
|
||||
/*
|
||||
* Parse the two elements into a single date. The month will be converted to a numeric
|
||||
* value. Example:
|
||||
* Input: 24. Apr
|
||||
* Output: 24.04.
|
||||
*/
|
||||
date = "${rawDate[0]}${rawDate[1].monthToNumber()}."
|
||||
|
||||
// Save the date to its list
|
||||
dates.add(OfferDate(dateId, date))
|
||||
// Get and add the date of this food plan
|
||||
dates.add(doc.getDateByIndex(dateId))
|
||||
|
||||
// Set that the newly created date has no items as of yet
|
||||
dateHasItems = false
|
||||
|
||||
// Iterate through all categories offered on a given day
|
||||
dayPlan.getElementsByClass("food-category").forEach { category ->
|
||||
|
||||
// Set that items for the newly created date have been found
|
||||
dateHasItems = true
|
||||
|
||||
// Retrieve the category text
|
||||
@@ -183,44 +167,24 @@ class StwParser(application: Application) {
|
||||
categories.add(OfferCategory(categoryId, dateId, canteenId, categoryTitle))
|
||||
|
||||
// Iterate through all items in a category
|
||||
category
|
||||
.getElementsByTag("tbody")[0]
|
||||
.getElementsByTag("tr").forEach { element ->
|
||||
category.getAllFoodItems().forEach { element ->
|
||||
// Retrieve the parent element holding the item's title and price
|
||||
val tableRows = element.getElementsByTag("td")
|
||||
|
||||
/*
|
||||
* Retrieve the dietary preferences the item meets and parse them into a
|
||||
* string that can be inserted into the database.
|
||||
*/
|
||||
val prefs = try {
|
||||
with(element
|
||||
// Retrieve the dietary preferences the item meets
|
||||
val prefs = getOrElse(DietaryPreferences.NONE_MET) {
|
||||
element
|
||||
.getElementsByClass("field field-name-field-food-types")[0]
|
||||
) {
|
||||
DietaryPreferences.Object(
|
||||
isFair = isDietaryPreferenceMet(preferenceFairFileName),
|
||||
isFish = isDietaryPreferenceMet(preferenceFishFileName),
|
||||
isPoultry = isDietaryPreferenceMet(preferencePoultryFileName),
|
||||
isLamb = isDietaryPreferenceMet(preferenceLambFileName),
|
||||
isVital = isDietaryPreferenceMet(preferenceVitalFileName),
|
||||
isBeef = isDietaryPreferenceMet(preferenceBeefFileName),
|
||||
isPork = isDietaryPreferenceMet(preferencePorkFileName),
|
||||
isVegan = isDietaryPreferenceMet(preferenceVeganFileName),
|
||||
isVegetarian = isDietaryPreferenceMet(preferenceVegetarianFileName),
|
||||
isGame = isDietaryPreferenceMet(preferenceGameFileName),
|
||||
)
|
||||
}
|
||||
} catch (e: IndexOutOfBoundsException) {
|
||||
DietaryPreferences.NONE_MET
|
||||
.getDietaryPreferencesObject()
|
||||
}
|
||||
|
||||
// Retrieve title and embedded allergens individually
|
||||
val filteredText = getOrElse(orElse = Pair("", "")) {
|
||||
tableRows[1].getFilteredText()
|
||||
tableRows[1].splitTitleAndAllergens()
|
||||
}
|
||||
|
||||
// Save the item to its list
|
||||
items.add(
|
||||
OfferItem(
|
||||
items.add(OfferItem(
|
||||
itemId,
|
||||
categoryId,
|
||||
title = filteredText.first,
|
||||
@@ -238,8 +202,7 @@ class StwParser(application: Application) {
|
||||
),
|
||||
dietaryPreferences = prefs.deconstruct(),
|
||||
allergens = filteredText.second,
|
||||
)
|
||||
)
|
||||
))
|
||||
|
||||
// Increment the item ID to avoid conflict
|
||||
itemId += 1
|
||||
@@ -278,6 +241,44 @@ class StwParser(application: Application) {
|
||||
return StwResults(dates, canteens, categories, items)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a date object from the canteen website by its index.
|
||||
*
|
||||
* @receiver document to parse
|
||||
* @param index position to retrieve date from
|
||||
* @return date object
|
||||
*/
|
||||
private fun Document.getDateByIndex(index: Int): OfferDate {
|
||||
/*
|
||||
* Fetch the date for a given day. It will be in the following format:
|
||||
* 24. Apr
|
||||
* This value will be split between the day (24.) and the month (Apr)
|
||||
*/
|
||||
val rawDate = getElementsByClass("tabs")[0]
|
||||
.getElementsByClass("tab-date")[index].text().split(" ")
|
||||
|
||||
|
||||
/*
|
||||
* Parse the two elements into a single date. The month will be converted to a numeric
|
||||
* value. Example:
|
||||
* Input: 24. Apr
|
||||
* Output: 24.04.
|
||||
*/
|
||||
val date = "${rawDate[0]}${rawDate[1].monthToNumber()}."
|
||||
|
||||
// Save the date to its list
|
||||
return OfferDate(dateId, date)
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all food items from a given element for a given day.
|
||||
*
|
||||
* @receiver element to retrieve food item elements from
|
||||
* @return list of food elements
|
||||
*/
|
||||
private fun Element.getAllFoodItems(): Elements =
|
||||
getElementsByTag("tbody")[0].getElementsByTag("tr")
|
||||
|
||||
/**
|
||||
* Evaluates whether a dietary preference is met by checking if the link to an image can be
|
||||
* found in the HTML.
|
||||
@@ -293,6 +294,27 @@ class StwParser(application: Application) {
|
||||
).isNotEmpty()
|
||||
|
||||
/**
|
||||
* Retrieves a dietary preferences object from a given Element.
|
||||
*
|
||||
* @receiver element to retrieve preferences from
|
||||
* @return [DietaryPreferences.Object]
|
||||
*/
|
||||
private fun Element.getDietaryPreferencesObject(): DietaryPreferences.Object =
|
||||
DietaryPreferences.Object(
|
||||
isFair = isDietaryPreferenceMet(preferenceFairFileName),
|
||||
isFish = isDietaryPreferenceMet(preferenceFishFileName),
|
||||
isPoultry = isDietaryPreferenceMet(preferencePoultryFileName),
|
||||
isLamb = isDietaryPreferenceMet(preferenceLambFileName),
|
||||
isVital = isDietaryPreferenceMet(preferenceVitalFileName),
|
||||
isBeef = isDietaryPreferenceMet(preferenceBeefFileName),
|
||||
isPork = isDietaryPreferenceMet(preferencePorkFileName),
|
||||
isVegan = isDietaryPreferenceMet(preferenceVeganFileName),
|
||||
isVegetarian = isDietaryPreferenceMet(preferenceVegetarianFileName),
|
||||
isGame = isDietaryPreferenceMet(preferenceGameFileName),
|
||||
)
|
||||
|
||||
/**
|
||||
* Retrieves the item's title and its dietary preferences that are embedded in its title.
|
||||
* 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, &). This method also parses allergens and additives, since they are listed on
|
||||
@@ -300,9 +322,9 @@ class StwParser(application: Application) {
|
||||
* website user.
|
||||
*
|
||||
* @receiver element to parse the text content of
|
||||
* @return the filtered string and a string describing allergens and additives
|
||||
* @return the filtered title and a string describing allergens and additives
|
||||
*/
|
||||
private fun Element.getFilteredText(): Pair<String, String> {
|
||||
private fun Element.splitTitleAndAllergens(): Pair<String, String> {
|
||||
// Retrieve the element's inner HTML and replace faulty characters
|
||||
var text = html()
|
||||
.replace("&", "&")
|
||||
|
||||
@@ -153,8 +153,22 @@ class CanteenFragment : AppFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
// Set up floating action button for switching the canteen
|
||||
// Set up floating action button for switching canteens
|
||||
binding.fabSwitchCanteen.setOnClickListener {
|
||||
|
||||
/*
|
||||
* Show an error message is the user is trying to switch canteens while another one is
|
||||
* being downloaded.
|
||||
*/
|
||||
if (binding.swipeRefreshLayout.isRefreshing) {
|
||||
context.theme.showErrorSnackBar(
|
||||
binding.snackbarContainer,
|
||||
getString(R.string.canteen_fab_switch_canteen_error),
|
||||
)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
// Create menu for selecting a new canteen
|
||||
PopupMenu(binding.root.context, binding.fabSwitchCanteen).apply {
|
||||
setOnMenuItemClickListener { item ->
|
||||
viewModel.preferenceCanteen = when (item?.itemId) {
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
<string name="sheet_schedule_update_header_edit">Bestehende Veranstaltung bearbeiten</string>
|
||||
<string name="sheet_schedule_update_header_add">Neue Veranstaltung hinzufügen</string>
|
||||
<string name="sheet_schedule_update_title_hint">Veranstaltungstitel</string>
|
||||
<string name="sheet_schedule_update_lecturers_hint">Dozierende(r)</string>
|
||||
<string name="sheet_schedule_update_lecturers_hint">Dozierende*r</string>
|
||||
<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>
|
||||
@@ -68,7 +68,8 @@
|
||||
<string name="canteen_no_offer_desc">Für diesen Tag sind keine Angebote vorhanden</string>
|
||||
<string name="canteen_news_sheet_title">Neuigkeiten für diese Mensa</string>
|
||||
<string name="canteen_fab_opening_hours_content_desc">Zeige Öffnungszeiten</string>
|
||||
<string name="canteen_fab_switch_canteen">Wechsle Mensa</string>
|
||||
<string name="canteen_fab_switch_canteen">Mensa wechseln</string>
|
||||
<string name="canteen_fab_switch_canteen_error">Ein Plan wird gerade heruntergeladen.</string>
|
||||
<string name="canteen_fab_refresh_content_desc">Aktualisiere Angebote</string>
|
||||
<string name="canteen_fab_refresh_text">Aktualisieren</string>
|
||||
|
||||
@@ -145,7 +146,7 @@
|
||||
<string name="allergen_almonds">Mandeln</string>
|
||||
<string name="allergen_hazelnuts">Haselnüsse</string>
|
||||
<string name="allergen_walnuts">Walnüsse</string>
|
||||
<string name="allergen_cashew_nuts">Cashew-Kerne</string>
|
||||
<string name="allergen_cashew_nuts">Cashewkerne</string>
|
||||
<string name="allergen_pecans">Pecannüsse</string>
|
||||
<string name="allergen_brazil_nuts">Paranüsse</string>
|
||||
<string name="allergen_pistachios">Pistazien</string>
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
<string name="canteen_news_sheet_title">News for this canteen</string>
|
||||
<string name="canteen_fab_opening_hours_content_desc">Show opening hours</string>
|
||||
<string name="canteen_fab_switch_canteen">Switch canteen</string>
|
||||
<string name="canteen_fab_switch_canteen_error">A plan is being downloaded.</string>
|
||||
<string name="canteen_fab_refresh_content_desc">Refresh offers</string>
|
||||
<string name="canteen_fab_refresh_text">Refresh</string>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user