diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3aecceb..a5e3a03 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,6 +14,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.StudIPTimetable"
tools:targetApi="31">
+
+
(
}
}
-fun Fragment.viewBinding(viewBindingFactory: (View) -> T) =
+fun Fragment.viewBinding(viewBindingFactory: (View) -> T): FragmentViewBindingDelegate =
FragmentViewBindingDelegate(this, viewBindingFactory)
\ No newline at end of file
diff --git a/app/src/main/java/com/denizk0461/studip/data/Misc.kt b/app/src/main/java/com/denizk0461/studip/data/Misc.kt
index 2aeea6b..092ce7e 100644
--- a/app/src/main/java/com/denizk0461/studip/data/Misc.kt
+++ b/app/src/main/java/com/denizk0461/studip/data/Misc.kt
@@ -5,7 +5,8 @@ import android.content.res.Resources
import android.util.TypedValue
import android.widget.Toast
import androidx.annotation.AttrRes
-import com.denizk0461.studip.R
+import com.denizk0461.studip.exception.AcademicQuarterNotApplicableException
+import kotlin.jvm.Throws
/**
* Miscellaneous functions and variables that don't belong into any specific class.
@@ -45,7 +46,9 @@ fun showToast(context: Context, text: String) {
* Provides a conversion method between a timestamp ending in a full hour, and one with an academic
* quarter applied.
*/
-val timeslotsAcademicQuarter = listOf(
+val timeslotsAcademicQuarter: List = listOf(
+ "0:00",
+ "2:00",
"4:00",
"6:00",
"8:00",
@@ -56,28 +59,57 @@ val timeslotsAcademicQuarter = listOf(
"18:00",
"20:00",
"22:00",
+ "24:00",
)
-val timeslotsAcademicQuarterStart = mapOf(
- "4:00" to "4:15",
- "6:00" to "6:15",
- "8:00" to "8:15",
- "10:00" to "10:15",
- "12:00" to "12:15",
- "14:00" to "14:15",
- "16:00" to "16:15",
- "18:00" to "18:15",
- "20:00" to "20:15",
-)
+/**
+ * Provides a means of converting from a timestamp ending in a full hour to a timestamp that takes
+ * the academic quarter into account. Should only be used on events where it can be assumed that the
+ * academic quarter was implied in the timestamp. Use this for the beginning of an event.
+ *
+ * @param input timestamp to apply the academic quarter to
+ * @return timestamp with the academic quarter applied to it
+ */
+@Throws(AcademicQuarterNotApplicableException::class)
+fun getTimestampAcademicQuarterStart(input: String): String = when (input) {
+ "0:00" -> "0:15"
+ "2:00" -> "2:15"
+ "4:00" -> "4:15"
+ "6:00" -> "6:15"
+ "8:00" -> "8:15"
+ "10:00" -> "10:15"
+ "12:00" -> "12:15"
+ "14:00" -> "14:15"
+ "16:00" -> "16:15"
+ "18:00" -> "18:15"
+ "20:00" -> "20:15"
+ "22:00" -> "22:15"
+ "24:00" -> "0:15"
+ else -> throw AcademicQuarterNotApplicableException()
+}
-val timeslotsAcademicQuarterEnd = mapOf(
- "6:00" to "5:45",
- "8:00" to "7:45",
- "10:00" to "9:45",
- "12:00" to "11:45",
- "14:00" to "13:45",
- "16:00" to "15:45",
- "18:00" to "17:45",
- "20:00" to "19:45",
- "22:00" to "21:45",
-)
\ No newline at end of file
+/**
+ * Provides a means of converting from a timestamp ending in a full hour to a timestamp that takes
+ * the academic quarter into account. Should only be used on events where it can be assumed that the
+ * academic quarter was implied in the timestamp. Use this for the end of an event.
+ *
+ * @param input timestamp to apply the academic quarter to
+ * @return timestamp with the academic quarter applied to it
+ */
+@Throws(AcademicQuarterNotApplicableException::class)
+fun getTimestampAcademicQuarterEnd(input: String): String = when (input) {
+ "0:00" -> "23:45"
+ "2:00" -> "1:45"
+ "4:00" -> "3:45"
+ "6:00" -> "5:45"
+ "8:00" -> "7:45"
+ "10:00" -> "9:45"
+ "12:00" -> "11:45"
+ "14:00" -> "13:45"
+ "16:00" -> "15:45"
+ "18:00" -> "17:45"
+ "20:00" -> "19:45"
+ "22:00" -> "21:45"
+ "24:00" -> "23:45"
+ else -> throw AcademicQuarterNotApplicableException()
+}
\ No newline at end of file
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 4807d82..19fc18e 100644
--- a/app/src/main/java/com/denizk0461/studip/data/StwParser.kt
+++ b/app/src/main/java/com/denizk0461/studip/data/StwParser.kt
@@ -180,7 +180,7 @@ class StwParser {
.getElementsByClass("field field-name-field-food-types")[0]
// Parse the preferences into a string for the database
- val prefString = DietaryPrefObject(
+ val prefString = DietaryPreferences.Object(
isFair = prefs.isDietaryPreferenceMet(imageLinkPrefFair),
isFish = prefs.isDietaryPreferenceMet(imageLinkPrefFish),
isPoultry = prefs.isDietaryPreferenceMet(imageLinkPrefPoultry),
diff --git a/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt b/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt
index d3afc20..4c86893 100644
--- a/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt
+++ b/app/src/main/java/com/denizk0461/studip/db/AppDatabase.kt
@@ -21,7 +21,9 @@ import com.denizk0461.studip.model.*
)
abstract class AppDatabase : RoomDatabase() {
- // The database access object
+ /**
+ * The database access object. Database transactions go through this.
+ */
abstract fun dao(): AppDAO
companion object {
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 30e593e..a03bac2 100644
--- a/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt
+++ b/app/src/main/java/com/denizk0461/studip/db/AppRepository.kt
@@ -23,7 +23,7 @@ class AppRepository(app: Application) {
private val dietaryPrefString = "prefs_obj"
// Blank dietary preference regular expression
- private val blankDietaryPrefs: String = DietaryPrefObject.C_FALSE.toString().repeat(10)
+ private val blankDietaryPrefs: String = DietaryPreferences.C_FALSE.toString().repeat(10)
/**
* Retrieves all Stud.IP events.
@@ -49,7 +49,7 @@ class AppRepository(app: Application) {
*
* @return opening hours
*/
- fun getCanteenOpeningHours() = dao.getCanteenOpeningHours()
+ fun getCanteenOpeningHours(): String = dao.getCanteenOpeningHours()
/**
* Retrieves all canteen offers.
@@ -89,16 +89,17 @@ class AppRepository(app: Application) {
*
* @return dietary preferences as a regular expression string
*/
- private fun getDietaryPrefs(): String {
+ private fun getDietaryPrefsAsString(): String {
return prefs.getString(dietaryPrefString, blankDietaryPrefs) ?: blankDietaryPrefs
}
/**
- * Retrieve the user's dietary preferences as a DietaryPrefObject.
+ * Retrieve the user's dietary preferences as a [DietaryPreferences.Object].
*
- * @return dietary preferences as an instance of DietaryPrefObject.kt
+ * @return dietary preferences as an instance of [DietaryPreferences.Object]
*/
- fun getDietaryPrefsAsObj(): DietaryPrefObject = DietaryPrefObject.construct(getDietaryPrefs())
+ fun getDietaryPrefsAsObject(): DietaryPreferences.Object =
+ DietaryPreferences.construct(getDietaryPrefsAsString())
/**
* Updates a given dietary preference to a new value.
@@ -107,7 +108,7 @@ class AppRepository(app: Application) {
* @param newValue value to set the preference to
*/
fun setPreference(pref: DietaryPreferences, newValue: Boolean) {
- val oldString = getDietaryPrefs().toMutableList()
+ val oldString = getDietaryPrefsAsString().toMutableList()
oldString[pref.ordinal] = newValue.toChar()
val newString = oldString.joinToString("")
@@ -120,7 +121,11 @@ class AppRepository(app: Application) {
*
* @return char denoting whether a preference needs to be met
*/
- private fun Boolean.toChar() = if (this) DietaryPrefObject.C_TRUE else DietaryPrefObject.C_FALSE
+ private fun Boolean.toChar() = if (this) {
+ DietaryPreferences.C_TRUE
+ } else {
+ DietaryPreferences.C_FALSE
+ }
/**
* Retrieves a single user-specified dietary preference.
@@ -129,7 +134,7 @@ class AppRepository(app: Application) {
* @return whether the preference needs to be met1
*/
fun getBooleanPreference(pref: DietaryPreferences): Boolean =
- getDietaryPrefs()[pref.ordinal] == DietaryPrefObject.C_TRUE
+ getDietaryPrefsAsString()[pref.ordinal] == DietaryPreferences.C_TRUE
/**
* Deletes all canteen offers from the database.
diff --git a/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt b/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt
index 87b802d..0cd2ed1 100644
--- a/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt
+++ b/app/src/main/java/com/denizk0461/studip/dialog/TimePickerFragment.kt
@@ -6,6 +6,13 @@ import android.app.TimePickerDialog
import android.os.Bundle
import android.widget.TimePicker
+/**
+ * Dialogue used for letting the user pick a timestamp.
+ *
+ * @param timestamp timestamp that is to be edited
+ * @param listener listener for when the user finishes setting a time
+ * @param isEventStart whether the timestamp to be edited is the start of the event
+ */
class TimePickerFragment(
private val timestamp: String,
private val listener: OnTimeSetListener,
@@ -14,14 +21,36 @@ class TimePickerFragment(
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val timestampSplit = timestamp.split(":")
- return TimePickerDialog(activity, this, timestampSplit[0].toInt(), timestampSplit[1].toInt(), true)
+ return TimePickerDialog(
+ activity,
+ this,
+ timestampSplit[0].toInt(),
+ timestampSplit[1].toInt(),
+ true,
+ )
}
+ /**
+ * Custom implementation of TimePickerDialog#OnTimeSetListener that includes a boolean to find
+ * out whether the start or the end timestamp has been edited.
+ */
interface OnTimeSetListener {
+
+ /**
+ * Timestamp has been edited by the user.
+ *
+ * @param hours hour of the timestamp
+ * @param minutes minute of the timestamp
+ * @param isEventStart whether the timestamp to be edited is the start of the event
+ */
fun onTimeSet(hours: Int, minutes: Int, isEventStart: Boolean)
}
+ /**
+ * Override the implementation of TimePickerDialog#OnTimeSetListener.
+ */
override fun onTimeSet(picker: TimePicker?, hours: Int, minutes: Int) {
+ // Use custom implementation of OnTimeSetListener
listener.onTimeSet(hours, minutes, isEventStart)
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizk0461/studip/exception/AcademicQuarterNotApplicableException.kt b/app/src/main/java/com/denizk0461/studip/exception/AcademicQuarterNotApplicableException.kt
new file mode 100644
index 0000000..cdac01e
--- /dev/null
+++ b/app/src/main/java/com/denizk0461/studip/exception/AcademicQuarterNotApplicableException.kt
@@ -0,0 +1,9 @@
+package com.denizk0461.studip.exception
+
+import java.io.IOException
+
+/**
+ * This exception should be used when a conversion to an academic quarter is attempted to be applied
+ * to a timestamp that is not meant for it.
+ */
+class AcademicQuarterNotApplicableException : IOException()
\ No newline at end of file
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 52655a0..482f689 100644
--- a/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt
+++ b/app/src/main/java/com/denizk0461/studip/fragment/CanteenFragment.kt
@@ -108,7 +108,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
// Assign a preference value to every button to filter for dietary preferences
val chipMap = mapOf(
- binding.chipPrefFair to DietaryPreferences.FAIR,
+ binding.chipPrefFair to DietaryPreferences.WELFARE,
binding.chipPrefFish to DietaryPreferences.FISH,
binding.chipPrefPoultry to DietaryPreferences.POULTRY,
binding.chipPrefLamb to DietaryPreferences.LAMB,
@@ -255,7 +255,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
// Find all preferences that need to be met
prefs.forEachIndexed { index, c ->
- if (c == DietaryPrefObject.C_TRUE) indices.add(index)
+ if (c == DietaryPreferences.C_TRUE) indices.add(index)
}
// Needs to be set to correctly assemble the regular expression
@@ -268,7 +268,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
// Add the expression looking for the single preference to the entire string
regexString += emptyPreferenceRegex.substring(0 until index) +
- DietaryPrefObject.C_TRUE +
+ DietaryPreferences.C_TRUE +
emptyPreferenceRegex.substring(index+1)
// Ensure that OR statements will be placed between the individual expressions
@@ -290,7 +290,7 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
// Get dietary preference regex
val prefsRegex = getPrefRegex()
- val filteredForPreferences = if (prefsRegex.toString() == emptyPreferenceRegex) {
+ val filteredForPrefs = if (prefsRegex.toString() == emptyPreferenceRegex) {
// Show all elements and skip filtering if no preference is set
this
} else {
@@ -300,15 +300,15 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
}
}
- return filteredForPreferences.map { offer ->
+ return filteredForPrefs.map { (_, date, dateId, category, _, canteen, _, _, _, _, _) ->
// Create new group elements to group the already filtered elements by their categories
CanteenOfferGroup(
- offer.date,
- offer.dateId,
- offer.category,
- offer.canteen,
- filteredForPreferences.filter {
- it.category == offer.category && it.date == offer.date && it.canteen == offer.canteen
+ 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(
diff --git a/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt
index 73f16b1..4eda2ae 100644
--- a/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt
+++ b/app/src/main/java/com/denizk0461/studip/fragment/EventFragment.kt
@@ -11,7 +11,6 @@ import com.denizk0461.studip.adapter.StudIPEventPageAdapter
import com.denizk0461.studip.databinding.FragmentEventBinding
import com.denizk0461.studip.model.StudIPEvent
import com.denizk0461.studip.sheet.ScheduleUpdateSheet
-import com.denizk0461.studip.sheet.TextSheet
import com.denizk0461.studip.viewmodel.EventViewModel
import com.google.android.material.tabs.TabLayoutMediator
import java.util.*
diff --git a/app/src/main/java/com/denizk0461/studip/fragment/SettingsFragment.kt b/app/src/main/java/com/denizk0461/studip/fragment/SettingsFragment.kt
index f3d0556..63d7812 100644
--- a/app/src/main/java/com/denizk0461/studip/fragment/SettingsFragment.kt
+++ b/app/src/main/java/com/denizk0461/studip/fragment/SettingsFragment.kt
@@ -137,7 +137,7 @@ class SettingsFragment : AppFragment() {
binding.appVersionText.text =
"${BuildConfig.VERSION_NAME}-${
if (BuildConfig.DEBUG)
- "dev-[${SimpleDateFormat("yyyy-MM-dd, HH:mm:ss.SSS").format(Date(BuildConfig.TIMESTAMP))}]"
+ "dev-[${SimpleDateFormat("yyyy-MM-dd, HH:mm:ss.SSS", Locale.GERMANY).format(Date(BuildConfig.TIMESTAMP))}]"
else
"release"
}"
diff --git a/app/src/main/java/com/denizk0461/studip/model/Allergens.kt b/app/src/main/java/com/denizk0461/studip/model/Allergens.kt
index e1ef3d1..f69dd01 100644
--- a/app/src/main/java/com/denizk0461/studip/model/Allergens.kt
+++ b/app/src/main/java/com/denizk0461/studip/model/Allergens.kt
@@ -2,7 +2,11 @@ package com.denizk0461.studip.model
import com.denizk0461.studip.R
+/**
+ * This class provides static functions for dealing with allergens present in a canteen offer.
+ */
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:
diff --git a/app/src/main/java/com/denizk0461/studip/model/CanteenOffer.kt b/app/src/main/java/com/denizk0461/studip/model/CanteenOffer.kt
index 57d1d09..3619e9a 100644
--- a/app/src/main/java/com/denizk0461/studip/model/CanteenOffer.kt
+++ b/app/src/main/java/com/denizk0461/studip/model/CanteenOffer.kt
@@ -18,7 +18,7 @@ import androidx.room.ColumnInfo
* @param title text content of the individual canteen offer
* @param price students' price for the individual canteen offer
* @param dietaryPreferences dietary preferences used to filter for the user's needs - see
- * DietaryPrefObject.kt
+ * [DietaryPreferences]
* @param allergens allergens and additives that are present in the item
*/
data class CanteenOffer(
diff --git a/app/src/main/java/com/denizk0461/studip/model/CanteenOfferGroupElement.kt b/app/src/main/java/com/denizk0461/studip/model/CanteenOfferGroupElement.kt
index e1e18fe..11cf27b 100644
--- a/app/src/main/java/com/denizk0461/studip/model/CanteenOfferGroupElement.kt
+++ b/app/src/main/java/com/denizk0461/studip/model/CanteenOfferGroupElement.kt
@@ -5,10 +5,10 @@ package com.denizk0461.studip.model
* this are assigned to corresponding date, canteen, and category via an instance of
* CanteenOfferGroup.kt.
*
- * @param title text content of the individual canteen offer
- * @param price students' price for the individual canteen offer
+ * @param title text content of the individual canteen offer
+ * @param price students' price for the individual canteen offer
* @param dietaryPreferences dietary preferences used to filter for the user's needs - see
- * DietaryPrefObject.kt
+ * [DietaryPreferences]
* @param allergens allergens and additives that are present in the item
*/
data class CanteenOfferGroupElement(
diff --git a/app/src/main/java/com/denizk0461/studip/model/DietaryPrefObject.kt b/app/src/main/java/com/denizk0461/studip/model/DietaryPrefObject.kt
deleted file mode 100644
index 3d3e1c9..0000000
--- a/app/src/main/java/com/denizk0461/studip/model/DietaryPrefObject.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.denizk0461.studip.model
-
-/**
- * Object that holds dietary preferences. Can be used to hold both the user-set values as well as
- * the values of an individual canteen item.
- *
- * @param isFair item contains meat from fairly-treated animals (lol sure)
- * @param isFish item contains fish
- * @param isPoultry item contains chicken
- * @param isLamb item contains lamb
- * @param isVital i don't actually know
- * @param isBeef item contains beef
- * @param isPork item contains pork
- * @param isVegan item is plant-based; contains no animal-derived ingredients
- * @param isVegetarian item is vegetarian; contains no animal parts
- * @param isGame item contains game meat (e.g. deer)
- */
-data class DietaryPrefObject(
- val isFair: Boolean,
- val isFish: Boolean,
- val isPoultry: Boolean,
- val isLamb: Boolean,
- val isVital: Boolean,
- val isBeef: Boolean,
- val isPork: Boolean,
- val isVegan: Boolean,
- val isVegetarian: Boolean,
- val isGame: Boolean,
-) {
- companion object {
- // Char used to construct a regex to denote that a preference is met
- const val C_TRUE = 't'
- // Char used to construct a regex to denote that a preference is not met
- const val C_FALSE = '.'
-
- /**
- * 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
- * false boolean value.
- *
- * @param values the regex string
- * @return an instance of DietaryPrefObject
- */
- fun construct(values: String) = DietaryPrefObject(
- isFair = values[0] == C_TRUE,
- isFish = values[1] == C_TRUE,
- isPoultry = values[2] == C_TRUE,
- isLamb = values[3] == C_TRUE,
- isVital = values[4] == C_TRUE,
- isBeef = values[5] == C_TRUE,
- isPork = values[6] == C_TRUE,
- isVegan = values[7] == C_TRUE,
- isVegetarian = values[8] == C_TRUE,
- isGame = values[9] == C_TRUE,
- )
- }
-
- /**
- * Constructs a regular expression string from a DietaryPrefObject. This can be used to filter for specific
- * preferences. Example:
- * .......t..
- * This expression filters for items that are vegan ('t' in position 8) and ignores all other
- * preference options ('.' in all other positions).
- *
- * @return a 10-character long regular expression
- */
- fun deconstruct() = String(
- charArrayOf(
- if (this.isFair) C_TRUE else C_FALSE,
- if (this.isFish) C_TRUE else C_FALSE,
- if (this.isPoultry) C_TRUE else C_FALSE,
- if (this.isLamb) C_TRUE else C_FALSE,
- if (this.isVital) C_TRUE else C_FALSE,
- if (this.isBeef) C_TRUE else C_FALSE,
- if (this.isPork) C_TRUE else C_FALSE,
- if (this.isVegan) C_TRUE else C_FALSE,
- if (this.isVegetarian) C_TRUE else C_FALSE,
- if (this.isGame) C_TRUE else C_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 d236961..2c5c536 100644
--- a/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt
+++ b/app/src/main/java/com/denizk0461/studip/model/DietaryPreferences.kt
@@ -3,35 +3,170 @@ package com.denizk0461.studip.model
import com.denizk0461.studip.R
/**
- * Enumeration that can be used in conjunction with DietaryPrefObject.kt to more concisely look up,
- * specify, and iterate through dietary preferences. Order of these elements matches the order used
- * on the website of the Studierendenwerk Bremen.
+ * Enumeration for more concisely looking up, specifying, and iterating through dietary preferences.
+ * Order of these elements matches the order used on the website of the Studierendenwerk Bremen.
*
* @param value string value that can be used where the enum value itself cannot be used (e.g.
* SharedPreferences)
*/
enum class DietaryPreferences(val value: String) {
- FAIR("isFair"),
+ /**
+ * Offer contains meat for which animal welfare standards were upheld.
+ */
+ WELFARE("isFair"),
+
+ /**
+ * Offer contains fish products.
+ */
FISH("isFish"),
+
+ /**
+ * Offer contains poultry (chicken) products.
+ */
POULTRY("isPoultry"),
+
+ /**
+ * Offer contains lamb products.
+ */
LAMB("isLamb"),
+
+ /**
+ * Offer contains products that are good for ur health i guess?
+ */
VITAL("isVital"),
+
+ /**
+ * Offer contains beef (cow) products.
+ */
BEEF("isBeef"),
+
+ /**
+ * Offer contains pork (pig) products.
+ */
PORK("isPork"),
+
+ /**
+ * Offer contains no animal products and is fully plant-based (vegan).
+ */
VEGAN("isVegan"),
+
+ /**
+ * Offer contains no animal parts and is vegetarian.
+ */
VEGETARIAN("isVegetarian"),
+
+ /**
+ * Offer contains game (wild animals such as deer, gosh, is that not barbaric? Sorry for being
+ * dramatic, but I didn't even know that was served at our canteens until I started making this
+ * app).
+ */
GAME("isGame"),
+
+ /**
+ * Offer doesn't fulfil any of the dietary preferences listed above.
+ */
NONE("hasNone"),
+
+ /**
+ * Offer has encountered an error.
+ */
ERROR("onError")
;
+ /**
+ * Object that holds dietary preferences. Can be used to hold both the user-set values as well as
+ * the values of an individual canteen item.
+ *
+ * @param isFair item contains meat from fairly-treated animals (lol sure)
+ * @param isFish item contains fish
+ * @param isPoultry item contains chicken
+ * @param isLamb item contains lamb
+ * @param isVital i don't actually know
+ * @param isBeef item contains beef
+ * @param isPork item contains pork
+ * @param isVegan item is plant-based; contains no animal-derived ingredients
+ * @param isVegetarian item is vegetarian; contains no animal parts
+ * @param isGame item contains game meat (e.g. deer)
+ */
+ data class Object(
+ val isFair: Boolean,
+ val isFish: Boolean,
+ val isPoultry: Boolean,
+ val isLamb: Boolean,
+ val isVital: Boolean,
+ val isBeef: Boolean,
+ val isPork: Boolean,
+ val isVegan: Boolean,
+ val isVegetarian: Boolean,
+ val isGame: Boolean,
+ ) {
+ /**
+ * Constructs a regular expression string from a DietaryPrefObject. This can be used to filter for specific
+ * preferences. Example:
+ * .......t..
+ * This expression filters for items that are vegan ('t' in position 8) and ignores all other
+ * preference options ('.' in all other positions).
+ *
+ * @return a 10-character long regular expression
+ */
+ fun deconstruct(): String = String(
+ charArrayOf(
+ if (this.isFair) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isFish) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isPoultry) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isLamb) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isVital) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isBeef) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isPork) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isVegan) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isVegetarian) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ if (this.isGame) DietaryPreferences.C_TRUE else DietaryPreferences.C_FALSE,
+ )
+ )
+ }
+
companion object {
/**
- * Provides a converting function between
+ * Char used to construct a regex to denote that a preference is met
+ */
+ const val C_TRUE: Char = 't'
+
+ /**
+ * Char used to construct a regex to denote that a preference is not met
+ */
+ const val C_FALSE: Char = '.'
+
+ /**
+ * 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
+ * false boolean value.
+ *
+ * @param values the regex string
+ * @return an instance of DietaryPrefObject
+ */
+ fun construct(values: String): Object = Object(
+ isFair = values[0] == DietaryPreferences.C_TRUE,
+ isFish = values[1] == DietaryPreferences.C_TRUE,
+ isPoultry = values[2] == DietaryPreferences.C_TRUE,
+ isLamb = values[3] == DietaryPreferences.C_TRUE,
+ isVital = values[4] == DietaryPreferences.C_TRUE,
+ isBeef = values[5] == DietaryPreferences.C_TRUE,
+ isPork = values[6] == DietaryPreferences.C_TRUE,
+ isVegan = values[7] == DietaryPreferences.C_TRUE,
+ isVegetarian = values[8] == DietaryPreferences.C_TRUE,
+ isGame = values[9] == DietaryPreferences.C_TRUE,
+ )
+
+ /**
+ * Provides a converting function between the ordinals of the enumeration and corresponding
+ * string and drawable values.
+ *
+ * @param index ordinal of the enum item
+ * @return string resource ID and drawable resource ID as a pair
*/
fun getData(index: Int): Pair = when (index) {
- FAIR.ordinal -> Pair(R.string.pref_fair, R.drawable.handshake)
+ WELFARE.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)
diff --git a/app/src/main/java/com/denizk0461/studip/model/OfferItem.kt b/app/src/main/java/com/denizk0461/studip/model/OfferItem.kt
index 5b12364..af36d26 100644
--- a/app/src/main/java/com/denizk0461/studip/model/OfferItem.kt
+++ b/app/src/main/java/com/denizk0461/studip/model/OfferItem.kt
@@ -13,7 +13,7 @@ import androidx.room.PrimaryKey
* @param title text content of the individual canteen offer
* @param price students' price for the individual canteen offer
* @param dietaryPreferences dietary preferences used to filter for the user's needs - see
- * DietaryPrefObject.kt
+ * [DietaryPreferences]
* @param allergens allergens and additives that are present in the item
*/
@Entity(
diff --git a/app/src/main/java/com/denizk0461/studip/model/SettingsPreferences.kt b/app/src/main/java/com/denizk0461/studip/model/SettingsPreferences.kt
index 85d339c..20a136f 100644
--- a/app/src/main/java/com/denizk0461/studip/model/SettingsPreferences.kt
+++ b/app/src/main/java/com/denizk0461/studip/model/SettingsPreferences.kt
@@ -7,13 +7,29 @@ package com.denizk0461.studip.model
* @param key key for the SharedPreferences transaction
*/
enum class SettingsPreferences(val key: String) {
- // Whether the user wants to have allergens displayed in the canteen overview
+
+ /**
+ * Whether the user wants to have allergens displayed in the canteen overview.
+ */
ALLERGEN("setting_allergen"),
- // Whether the user wants the next course in his schedule to be highlighted
+
+ /**
+ * Whether the user wants the next course in his schedule to be highlighted.
+ */
COURSE_HIGHLIGHTING("setting_highlight"),
+ /**
+ * Whether the user wants the app to launch with the canteen fragment.
+ */
LAUNCH_CANTEEN_ON_START("settings_launch_canteen"),
- // Whether the user opts into sending crash report
+
+ /**
+ * Whether the user opts into sending crash report.
+ */
DATA_HANDLING("setting_data_handling"),
+
+ /**
+ * The canteen the user has picked.
+ */
CANTEEN("setting_canteen"),
;
}
\ No newline at end of file
diff --git a/app/src/main/java/com/denizk0461/studip/sheet/AppSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/AppSheet.kt
index 46ce437..de0cc16 100644
--- a/app/src/main/java/com/denizk0461/studip/sheet/AppSheet.kt
+++ b/app/src/main/java/com/denizk0461/studip/sheet/AppSheet.kt
@@ -19,7 +19,9 @@ open class AppSheet(@LayoutRes private val layoutId: Int) : BottomSheetDialogFra
// Internal context object
private lateinit var _context: Context
- // Get non-null context. Only valid after onAttach()
+ /**
+ * Get non-null context. Only valid after onAttach().
+ */
override fun getContext(): Context = _context
override fun onAttach(context: Context) {
@@ -27,7 +29,6 @@ open class AppSheet(@LayoutRes private val layoutId: Int) : BottomSheetDialogFra
_context = context
}
- // Inflate the given layout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
LayoutInflater.from(context).inflate(layoutId, container, false)
}
\ No newline at end of file
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 fa7fae9..2b1ec6b 100644
--- a/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt
+++ b/app/src/main/java/com/denizk0461/studip/sheet/ScheduleUpdateSheet.kt
@@ -6,14 +6,15 @@ import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.transition.TransitionManager
import com.denizk0461.studip.R
+import com.denizk0461.studip.data.getTimestampAcademicQuarterEnd
+import com.denizk0461.studip.data.getTimestampAcademicQuarterStart
import com.denizk0461.studip.data.parseToMinutes
import com.denizk0461.studip.data.showToast
import com.denizk0461.studip.data.timeslotsAcademicQuarter
-import com.denizk0461.studip.data.timeslotsAcademicQuarterEnd
-import com.denizk0461.studip.data.timeslotsAcademicQuarterStart
import com.denizk0461.studip.data.viewBinding
import com.denizk0461.studip.databinding.SheetScheduleUpdateBinding
import com.denizk0461.studip.dialog.TimePickerFragment
+import com.denizk0461.studip.exception.AcademicQuarterNotApplicableException
import com.denizk0461.studip.model.StudIPEvent
/**
@@ -60,10 +61,8 @@ class ScheduleUpdateSheet(
binding.buttonAcademicQuarter.setOnClickListener {
try {
// Retrieve new timestamps with the academic quarter applied, or throw a tantrum
- val newStart = timeslotsAcademicQuarterStart[timeslotStart]
- ?: throw NullPointerException()
- val newEnd = timeslotsAcademicQuarterEnd[timeslotEnd]
- ?: throw NullPointerException()
+ val newStart = getTimestampAcademicQuarterStart(timeslotStart)
+ val newEnd = getTimestampAcademicQuarterEnd(timeslotEnd)
// Set the buttons to the new timesatmps
timeslotStart = newStart
@@ -79,7 +78,7 @@ class ScheduleUpdateSheet(
binding.buttonAcademicQuarter.visibility = View.GONE
// Catch if a timeslot couldn't be found in the list, and tell the user
- } catch (e: NullPointerException) {
+ } catch (e: AcademicQuarterNotApplicableException) {
showToast(context, getString(R.string.sheet_schedule_update_hint_quarter_error))
}
}
diff --git a/app/src/main/java/com/denizk0461/studip/sheet/TextSheet.kt b/app/src/main/java/com/denizk0461/studip/sheet/TextSheet.kt
index 5f2fc75..9879af5 100644
--- a/app/src/main/java/com/denizk0461/studip/sheet/TextSheet.kt
+++ b/app/src/main/java/com/denizk0461/studip/sheet/TextSheet.kt
@@ -2,7 +2,6 @@ package com.denizk0461.studip.sheet
import android.os.Bundle
import android.view.View
-import androidx.annotation.StringRes
import com.denizk0461.studip.R
import com.denizk0461.studip.data.viewBinding
import com.denizk0461.studip.databinding.SheetTextBinding
diff --git a/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt b/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt
index 7d77b20..5dc9ef6 100644
--- a/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt
+++ b/app/src/main/java/com/denizk0461/studip/viewmodel/AppViewModel.kt
@@ -18,7 +18,9 @@ import kotlinx.coroutines.runBlocking
*/
open class AppViewModel(app: Application) : AndroidViewModel(app) {
- // Reference to the app's repository for database transactions
+ /**
+ * Reference to the app's repository for database transactions.
+ */
protected val repo: AppRepository = Dependencies.repo
/**
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 f617da4..2a4ac1c 100644
--- a/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt
+++ b/app/src/main/java/com/denizk0461/studip/viewmodel/CanteenViewModel.kt
@@ -27,7 +27,7 @@ class CanteenViewModel(app: Application) : AppViewModel(app) {
*
* @return dietary preferences
*/
- fun getDietaryPrefs(): DietaryPrefObject = repo.getDietaryPrefsAsObj()
+ fun getDietaryPrefs(): DietaryPreferences.Object = repo.getDietaryPrefsAsObject()
/**
* Retrieves all canteen offer date objects.
@@ -43,7 +43,13 @@ class CanteenViewModel(app: Application) : AppViewModel(app) {
*/
fun getCanteenOpeningHours(): String = returnBlocking { repo.getCanteenOpeningHours() }
- // Fetch the canteen offers asynchronously. Updates will be provided through a LiveData object.
+ /**
+ * Fetch the canteen offers asynchronously. Updates will be provided through a LiveData object.
+ *
+ * @param canteen canteen from which to fetch offers from
+ * @param onRefreshUpdate action to execute when a status update is available
+ * @param onFinish action to execute when the operation has finished
+ */
fun fetchOffers(canteen: Int, onRefreshUpdate: (status: Int) -> Unit, onFinish: () -> Unit) {
doAsync { parser.parse(canteen, onRefreshUpdate, onFinish) }
}
@@ -72,6 +78,9 @@ class CanteenViewModel(app: Application) : AppViewModel(app) {
val preferenceAllergen: Boolean
get() = repo.getBooleanPreference(SettingsPreferences.ALLERGEN, defaultValue = true)
+ /**
+ * This value determines which canteen the user has selected.
+ */
var preferenceCanteen: Int
get() = repo.getIntPreference(SettingsPreferences.CANTEEN)
set(newValue) { repo.setPreference(SettingsPreferences.CANTEEN, newValue) }
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
deleted file mode 100644
index 2b068d1..0000000
--- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/flatware.xml b/app/src/main/res/drawable/flatware.xml
deleted file mode 100644
index e21135a..0000000
--- a/app/src/main/res/drawable/flatware.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..7e9689c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_canteen.xml b/app/src/main/res/layout/fragment_canteen.xml
index 2a29546..90f7421 100644
--- a/app/src/main/res/layout/fragment_canteen.xml
+++ b/app/src/main/res/layout/fragment_canteen.xml
@@ -36,7 +36,6 @@
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="hello"
android:textSize="18sp"
android:fontFamily="@font/lato_bolditalic"
app:layout_constraintTop_toTopOf="parent"
diff --git a/app/src/main/res/layout/item_canteen_line.xml b/app/src/main/res/layout/item_canteen_line.xml
index 6ed7399..5137b78 100644
--- a/app/src/main/res/layout/item_canteen_line.xml
+++ b/app/src/main/res/layout/item_canteen_line.xml
@@ -7,8 +7,7 @@
android:clickable="true"
android:focusable="true"
android:paddingHorizontal="16dp"
- android:paddingVertical="2dp"
- android:background="?android:attr/selectableItemBackground">
+ android:paddingVertical="2dp">
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index eca70cf..7353dbd 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
deleted file mode 100644
index 6f3b755..0000000
--- a/app/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..c57cfd7
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
deleted file mode 100644
index c209e78..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..c57cfd7
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
deleted file mode 100644
index b2dfe3d..0000000
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..cea0c83
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
deleted file mode 100644
index 4f0f1d6..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..cea0c83
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
deleted file mode 100644
index 62b611d..0000000
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8028973
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
deleted file mode 100644
index 948a307..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..8028973
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
deleted file mode 100644
index 1b9a695..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..b03f865
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
deleted file mode 100644
index 28d4b77..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b03f865
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9287f50..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..9fe7b4b
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
deleted file mode 100644
index aa7d642..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9fe7b4b
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
deleted file mode 100644
index 9126ae3..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and /dev/null differ
diff --git a/app/src/main/res/values-v29/themes.xml b/app/src/main/res/values-v29/themes.xml
index fe5092b..5b2a3a2 100644
--- a/app/src/main/res/values-v29/themes.xml
+++ b/app/src/main/res/values-v29/themes.xml
@@ -1,5 +1,4 @@
-
-
+