diff --git a/app/src/main/java/com/denizk0461/weserplaner/fragment/SettingsFragment.kt b/app/src/main/java/com/denizk0461/weserplaner/fragment/SettingsFragment.kt index 2aaf23d..329f946 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/fragment/SettingsFragment.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/fragment/SettingsFragment.kt @@ -1,12 +1,15 @@ package com.denizk0461.weserplaner.fragment import android.annotation.SuppressLint +import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle +import android.util.Base64 import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.inputmethod.InputMethodManager import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import com.denizk0461.weserplaner.BuildConfig @@ -14,11 +17,12 @@ import com.denizk0461.weserplaner.R import com.denizk0461.weserplaner.activity.FetcherActivity import com.denizk0461.weserplaner.activity.ImageActivity import com.denizk0461.weserplaner.data.getTextSheet +import com.denizk0461.weserplaner.data.showSnackBar import com.denizk0461.weserplaner.data.showToast import com.denizk0461.weserplaner.databinding.FragmentSettingsBinding import com.denizk0461.weserplaner.sheet.AllergenConfigSheet -import com.denizk0461.weserplaner.sheet.DevCodeSheet import com.denizk0461.weserplaner.viewmodel.SettingsViewModel +import java.nio.charset.StandardCharsets import java.text.SimpleDateFormat import java.util.* @@ -45,6 +49,9 @@ class SettingsFragment : AppFragment() { // Click counter on the app version button private var appVersionClick = 1 + // Whether the user has set the text of the allergen setting to its alt text + private var hasSetAllergensAltText = false + // 222 private val mysteryLink = "https://www.youtube.com/watch?v=nhIQMCXJzLI" @@ -57,6 +64,8 @@ class SettingsFragment : AppFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + // --- schedule settings --- // + // Launch the Stud.IP schedule fetcher activity binding.buttonRefreshSchedule.setOnClickListener { launchWebView() @@ -78,6 +87,8 @@ class SettingsFragment : AppFragment() { } } + // --- canteen offer settings --- // + // Set up button to set allergens binding.buttonAllergensConfig.setOnClickListener { openBottomSheet( @@ -95,6 +106,7 @@ class SettingsFragment : AppFragment() { ) } + // Set text according to how many allergens the user has set binding.allergensConfigSubtitle.text = getAllergensConfigCountText() // Set up switch for displaying allergens @@ -105,13 +117,19 @@ class SettingsFragment : AppFragment() { } } - // Set up switch for launching the app with a specific view -// binding.switchLaunchCanteen.apply { -// isChecked = viewModel.preferenceLaunchCanteen -// setOnCheckedChangeListener { _, newValue -> -// viewModel.preferenceLaunchCanteen = newValue -// } -// } + // Change text on allergens setting + binding.settingsAllergensSubtitleView.setOnLongClickListener { + if (hasSetAllergensAltText) { + binding.settingsAllergensTitleView.text = getString(R.string.settings_allergens_title) + binding.settingsAllergensSubtitleView.text = getString(R.string.settings_allergens_subtitle) + hasSetAllergensAltText = false + } else { + binding.settingsAllergensTitleView.text = getString(R.string.settings_allergens_title_alt) + binding.settingsAllergensSubtitleView.text = getString(R.string.settings_allergens_subtitle_alt) + hasSetAllergensAltText = true + } + true + } // Set up button toggle group for changing prices displayed for the canteen offers binding.togglePricingGroup.apply { @@ -139,6 +157,8 @@ class SettingsFragment : AppFragment() { } } + // --- miscellaneous settings --- // + // Set up button toggle group for changing default fragment binding.toggleLaunchFragmentGroup.apply { // Check the fragment that is currently selected @@ -207,10 +227,21 @@ class SettingsFragment : AppFragment() { ) } - // Set long click listener for licences button to open dev code sheet + // Set long click listener for licences button to unlock experimental settings binding.buttonLicences.setOnLongClickListener { + // Return false if the experimental settings are already enabled + if (viewModel.preferenceExperimentalSettingsEnabled) return@setOnLongClickListener false + + // Unlock experimental settings after 3 long presses if (licencesLongClick > 3) { - openBottomSheet(DevCodeSheet()) +// openBottomSheet(DevCodeSheet()) + licencesLongClick = 0 + viewModel.preferenceExperimentalSettingsEnabled = true + binding.cardExperimentalSettings.visibility = View.VISIBLE + context.theme.showSnackBar( + binding.coordinatorLayout, + getString(R.string.settings_unlocked_experiments), + ) } else { licencesLongClick += 1 } @@ -273,15 +304,130 @@ class SettingsFragment : AppFragment() { */ @SuppressLint("SetTextI18n") binding.appVersionText.text = - "${BuildConfig.VERSION_NAME}-${ - if (BuildConfig.DEBUG) - "dev-[${SimpleDateFormat("yyyy-MM-dd, HH:mm:ss.SSS", Locale.GERMANY) - .format(Date(BuildConfig.BUILD_TIME_MILLIS))}]" - else - "release" - }" + "${BuildConfig.VERSION_NAME}-${if (BuildConfig.DEBUG) "dev" else "release"}" + + // --- experimental settings --- // + + // Set visibility of experimental settings depending on whether they have been unlocked + binding.cardExperimentalSettings.visibility = if ( + viewModel.preferenceExperimentalSettingsEnabled + ) { + View.VISIBLE + } else { + View.GONE + } + + binding.buttonHideExperiments.setOnClickListener { + viewModel.preferenceExperimentalSettingsEnabled = false + binding.cardExperimentalSettings.visibility = View.GONE + context.theme.showSnackBar( + binding.coordinatorLayout, + getString(R.string.settings_hide_experiments), + ) + } + + // Set build version code and time text + @SuppressLint("SetTextI18n") + binding.buildTimeText.text = "v${BuildConfig.VERSION_CODE} | ${ + SimpleDateFormat("yyyy-MM-dd, HH:mm:ss.SSS", Locale.GERMANY) + .format(Date(BuildConfig.BUILD_TIME_MILLIS)) + }" + + binding.buttonDevCodes.setOnClickListener { + val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(view.windowToken, 0) + + when (binding.inputDevCode.text.toString().uppercase()) { + "U1RST0JF".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90S2k5Wi1mNnFYNA==".d64) + "U1BJUklU".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9XN25lMzlEU05TZw==".d64) + "Q0xPVURT".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9rbUJ6YTRhNTB2dw==".d64) + "NjQxODJL".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9EbTFyZ285UHBUcw==".d64) + "U0FJTE9S".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9QUHlDYXZ6OG5NWQ==".d64) + "SE9ORVNU".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9DSEg0OE5LUEFraw==".d64) + "QkJVT0s/".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90Rm1PMm1TY0tHNA==".d64) + "SUhUU0Mq".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS85bXZ4SVdhWHZuWQ==".d64) + "SU5TQU5F".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90NE9kYTlUZFYwbw==".d64) + "SE9SSVpO".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9SUVpUUy1CWjhtcw==".d64) + "TUFSR0Uh".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS8tbHFxRHZXRjQ1dw==".d64) + "UE9XRUxM".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9XUGMtVkVxQlBISQ==".d64) + "Q0FMTE1F".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS8xbTV1WnJNMnktMA==".d64) + "SkFNSVJP".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9fMVZoT2c0N3ozNA==".d64) + "TE9ORUxZ".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9uLURFNHNfc3d5Zw==".d64) + "QkVBVVRZ".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9vbVQ1ckttVTVfaw==".d64) + "Uk9NQ09N".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9HUW1nUG5uZjE4WQ==".d64) + "Tk9DQVNI".d64 -> launchLink(listOf( + "aHR0cHM6Ly95b3V0dS5iZS9lRzh3bkx2NTlPbw==", + "aHR0cHM6Ly95b3V0dS5iZS9RSzBZLUQ1bVpaaw==", + ).random().d64) + "Qk9KQUNL".d64 -> { + startActivity(Intent(context, ImageActivity::class.java).also { intent -> + val bundle = Bundle() + bundle.putString("img", "Qk9KQUNL".d64.lowercase()) + intent.putExtras(bundle) + }) + } + "QkNFTExT".d64 -> { + startActivity(Intent(context, ImageActivity::class.java).also { intent -> + val bundle = Bundle() + bundle.putString("img", "QkNFTExT".d64.lowercase()) + intent.putExtras(bundle) + }) + } + "NEVENT" -> { // nuke events + viewModel.nukeEvents() + showToast(context, "Nuked all events") + } + "NCANTE" -> { // nuke canteens + viewModel.nukeOfferCanteens() + showToast(context, "Nuked all canteens") + } + "NDATES" -> { // nuke dates + viewModel.nukeOfferDates() + showToast(context, "Nuked all dates") + } + "NCATEG" -> { // nuke categories + viewModel.nukeOfferCategories() + showToast(context, "Nuked all categories") + } + "NITEMS" -> { // nuke items + viewModel.nukeOfferItems() + showToast(context, "Nuked all items") + } + "NEVERY" -> { // nuke everything + viewModel.nukeEverything() + showToast(context, "Nuked everything") + } + else -> context.theme.showSnackBar( + binding.coordinatorLayout, + getString(R.string.settings_dev_codes_invalid) + ) + } + } } + /** + * Launches a web link. + * + * @param link link to open + */ + private fun launchLink(link: String) { + // Let the user know they accomplished something with their life + showToast(context, "✨") + + // Give the user a slight dopamine boost + startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link))) + } + + /** + * Decodes Base64 to a regular string. + * + * @return the decoded string + */ + private val String.d64: String get() = String( + Base64.decode(this, Base64.DEFAULT), + StandardCharsets.UTF_8 + ) + // Invalidate the view binding override fun onDestroyView() { super.onDestroyView() diff --git a/app/src/main/java/com/denizk0461/weserplaner/model/SettingsPreferences.kt b/app/src/main/java/com/denizk0461/weserplaner/model/SettingsPreferences.kt index bead8d2..be0feaf 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/model/SettingsPreferences.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/model/SettingsPreferences.kt @@ -63,5 +63,10 @@ enum class SettingsPreferences(val key: String) { * Whether the user has opened the canteen fragment before. */ HAS_OPENED_CANTEEN("has_opened_canteen"), + + /** + * Whether the user has enabled experimental settings. + */ + EXPERIMENTAL_ENABLED("experimental_enabled"), ; } \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/sheet/DevCodeSheet.kt b/app/src/main/java/com/denizk0461/weserplaner/sheet/DevCodeSheet.kt deleted file mode 100644 index 3affe91..0000000 --- a/app/src/main/java/com/denizk0461/weserplaner/sheet/DevCodeSheet.kt +++ /dev/null @@ -1,139 +0,0 @@ -package com.denizk0461.weserplaner.sheet - -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.util.Base64 -import android.view.View -import androidx.fragment.app.viewModels -import com.denizk0461.weserplaner.R -import com.denizk0461.weserplaner.activity.ImageActivity -import com.denizk0461.weserplaner.data.showToast -import com.denizk0461.weserplaner.data.viewBinding -import com.denizk0461.weserplaner.databinding.SheetDevCodeBinding -import com.denizk0461.weserplaner.viewmodel.DevCodeViewModel -import java.nio.charset.StandardCharsets - -/** - * Sheet that presents the user / developer with a text field to input developer codes / cheat - * codes. - */ -class DevCodeSheet : AppSheet(R.layout.sheet_dev_code) { - - // View binding - private val binding: SheetDevCodeBinding by viewBinding(SheetDevCodeBinding::bind) - - // View model - private val viewModel: DevCodeViewModel by viewModels() - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - // Execute an action based on the input - binding.buttonConfirm.setOnClickListener { - /* - * Codes are implemented here. - * - * About the inks; they are safe (which is suspicious of me to say), just encoded so - * people can't just look at the file and figure out all the codes! Of course, they're - * easily decoded, but who would go for that? You would have to have a lot of time to - * waste to do that. Then again, I was the one who encoded all of these links in the - * first place, so I suppose the joke's on me... - * - * If you're reading this, I ask you – why? - */ - when (binding.input.text.toString().uppercase()) { - "U1RST0JF".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90S2k5Wi1mNnFYNA==".d64) - "U1BJUklU".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9XN25lMzlEU05TZw==".d64) - "Q0xPVURT".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9rbUJ6YTRhNTB2dw==".d64) - "NjQxODJL".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9EbTFyZ285UHBUcw==".d64) - "U0FJTE9S".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9QUHlDYXZ6OG5NWQ==".d64) - "SE9ORVNU".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9DSEg0OE5LUEFraw==".d64) - "QkJVT0s/".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90Rm1PMm1TY0tHNA==".d64) - "SUhUU0Mq".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS85bXZ4SVdhWHZuWQ==".d64) - "SU5TQU5F".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS90NE9kYTlUZFYwbw==".d64) - "SE9SSVpO".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9SUVpUUy1CWjhtcw==".d64) - "TUFSR0Uh".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS8tbHFxRHZXRjQ1dw==".d64) - "UE9XRUxM".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9XUGMtVkVxQlBISQ==".d64) - "Q0FMTE1F".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS8xbTV1WnJNMnktMA==".d64) - "SkFNSVJP".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9fMVZoT2c0N3ozNA==".d64) - "TE9ORUxZ".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9uLURFNHNfc3d5Zw==".d64) - "QkVBVVRZ".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9vbVQ1ckttVTVfaw==".d64) - "Uk9NQ09N".d64 -> launchLink("aHR0cHM6Ly95b3V0dS5iZS9HUW1nUG5uZjE4WQ==".d64) - "Tk9DQVNI".d64 -> launchLink(listOf( - "aHR0cHM6Ly95b3V0dS5iZS9lRzh3bkx2NTlPbw==", - "aHR0cHM6Ly95b3V0dS5iZS9RSzBZLUQ1bVpaaw==", - ).random().d64) - "Qk9KQUNL".d64 -> { - startActivity(Intent(context, ImageActivity::class.java).also { intent -> - val bundle = Bundle() - bundle.putString("img", "Qk9KQUNL".d64.lowercase()) - intent.putExtras(bundle) - }) - } - "QkNFTExT".d64 -> { - startActivity(Intent(context, ImageActivity::class.java).also { intent -> - val bundle = Bundle() - bundle.putString("img", "QkNFTExT".d64.lowercase()) - intent.putExtras(bundle) - }) - } - "NEVENT" -> { // nuke events - viewModel.nukeEvents() - showToast(context, "Nuked all events") - } - "NCANTE" -> { // nuke canteens - viewModel.nukeOfferCanteens() - showToast(context, "Nuked all canteens") - } - "NDATES" -> { // nuke dates - viewModel.nukeOfferDates() - showToast(context, "Nuked all dates") - } - "NCATEG" -> { // nuke categories - viewModel.nukeOfferCategories() - showToast(context, "Nuked all categories") - } - "NITEMS" -> { // nuke items - viewModel.nukeOfferItems() - showToast(context, "Nuked all items") - } - "NEVERY" -> { // nuke everything - viewModel.nukeEverything() - showToast(context, "Nuked everything") - } - else -> showToast(context, "Code is invalid") - } - dismiss() - } - - // Set up close button - binding.buttonCancel.setOnClickListener { - // Do nothing and dismiss the sheet - dismiss() - } - } - - /** - * Launches a web link. - * - * @param link link to open - */ - private fun launchLink(link: String) { - // Let the user know they accomplished something with their life - showToast(context, "✨") - - // Give the user a slight dopamine boost - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link))) - } - - /** - * Decodes Base64 to a regular string. - * - * @return the decoded string - */ - private val String.d64: String get() = String( - Base64.decode(this, Base64.DEFAULT), - StandardCharsets.UTF_8 - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/DevCodeViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/DevCodeViewModel.kt deleted file mode 100644 index cffef4e..0000000 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/DevCodeViewModel.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.denizk0461.weserplaner.viewmodel - -import android.app.Application - -class DevCodeViewModel(application: Application) : AppViewModel(application) { - - /** - * Deletes everything from the database. - */ - fun nukeEverything() { - nukeEvents() - nukeOfferItems() - nukeOfferCategories() - nukeOfferCanteens() - nukeOfferDates() - } - - /** - * Deletes all Stud.IP events from the database. - */ - fun nukeEvents() { doAsync { repo.nukeEvents() } } - - /** - * Deletes all canteen items from the database. - */ - fun nukeOfferItems() { doAsync { repo.nukeOfferItems() } } - - /** - * Deletes all canteen categories from the database. - */ - fun nukeOfferCategories() { doAsync { repo.nukeOfferCategories() } } - - /** - * Deletes all canteens from the database. - */ - fun nukeOfferCanteens() { doAsync { repo.nukeOfferCanteens() } } - - /** - * Deletes all canteen dates from the database. - */ - fun nukeOfferDates() { doAsync { repo.nukeOfferDates() } } -} \ No newline at end of file diff --git a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt index 4b21663..8bcd164 100644 --- a/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt +++ b/app/src/main/java/com/denizk0461/weserplaner/viewmodel/SettingsViewModel.kt @@ -78,4 +78,49 @@ class SettingsViewModel(app: Application) : AppViewModel(app) { var preferenceDataHandling: Boolean get() = repo.getBooleanPreference(SettingsPreferences.DATA_HANDLING) set(newValue) { repo.setPreference(SettingsPreferences.DATA_HANDLING, newValue) } + + /** + * This value determines whether the user has enabled experimental settings. + */ + var preferenceExperimentalSettingsEnabled: Boolean + get() = repo.getBooleanPreference(SettingsPreferences.EXPERIMENTAL_ENABLED) + set(newValue) { repo.setPreference(SettingsPreferences.EXPERIMENTAL_ENABLED, newValue) } + + // --- functions for dev codes --- // + + /** + * Deletes everything from the database. + */ + fun nukeEverything() { + nukeEvents() + nukeOfferItems() + nukeOfferCategories() + nukeOfferCanteens() + nukeOfferDates() + } + + /** + * Deletes all Stud.IP events from the database. + */ + fun nukeEvents() { doAsync { repo.nukeEvents() } } + + /** + * Deletes all canteen items from the database. + */ + fun nukeOfferItems() { doAsync { repo.nukeOfferItems() } } + + /** + * Deletes all canteen categories from the database. + */ + fun nukeOfferCategories() { doAsync { repo.nukeOfferCategories() } } + + /** + * Deletes all canteens from the database. + */ + fun nukeOfferCanteens() { doAsync { repo.nukeOfferCanteens() } } + + /** + * Deletes all canteen dates from the database. + */ + fun nukeOfferDates() { doAsync { repo.nukeOfferDates() } } } \ No newline at end of file diff --git a/app/src/main/res/drawable/double_arrow_right.xml b/app/src/main/res/drawable/double_arrow_right.xml new file mode 100644 index 0000000..3562ff1 --- /dev/null +++ b/app/src/main/res/drawable/double_arrow_right.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 960252f..6b356ad 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -3,6 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" tools:context=".fragment.SettingsFragment" + android:id="@+id/coordinator_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> @@ -37,7 +38,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:paddingBottom="8dp"> + android:paddingBottom="8dp" + android:animateLayoutChanges="true"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f66c496..40f62aa 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -169,6 +169,7 @@ Stud.IP-Stundenplan Mensenangebote Sonstiges + Experimentelles Aktualisiere deinen Stud.IP-Stundenplan Dies wird alle Anpassungen löschen! @@ -194,6 +195,8 @@ Markiere Angebote mit Allergenen mit einem Stern* Wird auch für Zusatzstoffe genutzt + App entwickelt von denizk0461 + Danke, dass du meine App nutzt ☺︎♡ Wähle, mit welchem Bildschirm die App startet diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 540dbfe..6d55795 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -173,6 +173,7 @@ Stud.IP Schedule Canteen Offers Miscellaneous + Experimental Refresh your Stud.IP schedule This will clear any customisations! @@ -198,6 +199,8 @@ Mark offers with allergens with a star* Also applies to additives + App developed by denizk0461 + Thank you for using my app ☺︎♡ Colour dietary preferences Icons will be coloured similarly to how they look the website @@ -215,11 +218,23 @@ View licences Resources that made this app possible + Experimental settings have been unlocked. + Experimental settings have been hidden. Cheat Codes App Version + Hide experimental settings + Show them again via licences button + + Gradle build code & time + + Development codes + 6 chars + + This code could not be found. + keep clicking ^_^ ^_____^