Archived
FetcherActivity.kt now has a bottom app bar with useful actions and extends FragmentActivity instead of AppCompatActivity to show a tutorial bottom sheet
This commit is contained in:
@@ -5,12 +5,13 @@ import android.os.Bundle
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.denizk0461.studip.R
|
||||
import com.denizk0461.studip.data.showErrorSnackBar
|
||||
import com.denizk0461.studip.data.showToast
|
||||
import com.denizk0461.studip.databinding.ActivityFetcherBinding
|
||||
import com.denizk0461.studip.sheet.TextSheet
|
||||
import com.denizk0461.studip.viewmodel.FetcherViewModel
|
||||
import java.io.IOException
|
||||
import java.net.URLDecoder
|
||||
@@ -19,7 +20,7 @@ import java.net.URLDecoder
|
||||
* Activity for allowing the user to log in to access and fetch their schedule from their Stud.IP
|
||||
* profile. Launched through a button in the app's settings.
|
||||
*/
|
||||
class FetcherActivity : AppCompatActivity() {
|
||||
class FetcherActivity : FragmentActivity() {
|
||||
|
||||
// View binding
|
||||
private lateinit var binding: ActivityFetcherBinding
|
||||
@@ -54,13 +55,40 @@ class FetcherActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// Set up bottom app bar for various actions
|
||||
binding.bottomAppBar.setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
R.id.close -> {
|
||||
// Close the activity
|
||||
finish()
|
||||
true
|
||||
}
|
||||
R.id.refresh -> {
|
||||
// Refresh the currently opened page
|
||||
binding.webview.reload()
|
||||
true
|
||||
}
|
||||
R.id.help -> {
|
||||
// Present the user with a small tutorial on how to fetch their timetable
|
||||
TextSheet().also { sheet ->
|
||||
val bundle = Bundle()
|
||||
bundle.putString("header", getString(R.string.fetch_bar_help_sheet_title))
|
||||
bundle.putString("content", getString(R.string.fetch_bar_help_sheet_content))
|
||||
sheet.arguments = bundle
|
||||
}.show(supportFragmentManager, TextSheet::class.java.simpleName)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to load the user-set Stud.IP front page. Redirects to login page if user is
|
||||
* not logged in.
|
||||
*/
|
||||
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
|
||||
|
||||
binding.fab.setOnClickListener { view ->
|
||||
binding.fab.setOnClickListener {
|
||||
|
||||
if (binding.webview.url?.contains(
|
||||
"https://elearning.uni-bremen.de/dispatch.php/calendar/schedule"
|
||||
@@ -78,20 +106,19 @@ class FetcherActivity : AppCompatActivity() {
|
||||
viewModel.parse(URLDecoder.decode(p0, "UTF-8"))
|
||||
|
||||
// Notify the user that the fetch was successful
|
||||
Toast.makeText(
|
||||
this, R.string.toast_fetch_finished, Toast.LENGTH_SHORT
|
||||
).show()
|
||||
showToast(this, getString(R.string.toast_fetch_finished))
|
||||
|
||||
// Close the activity
|
||||
finish()
|
||||
|
||||
} catch (e: IOException) {
|
||||
// Let the user know that an error occurred
|
||||
theme.showErrorSnackBar(binding.rootView, getString(R.string.fetch_error_snack))
|
||||
theme.showErrorSnackBar(binding.rootView, getString(R.string.fetch_error_snack), binding.bottomAppBar)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
theme.showErrorSnackBar(binding.rootView, getString(R.string.fetch_error_webpage_snack))
|
||||
// Tell the user that they must navigate to their timetable
|
||||
theme.showErrorSnackBar(binding.rootView, getString(R.string.fetch_error_webpage_snack), binding.bottomAppBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
@@ -51,13 +52,15 @@ fun showToast(context: Context, text: String) {
|
||||
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
fun Resources.Theme.showErrorSnackBar(view: CoordinatorLayout, text: String) {
|
||||
Snackbar
|
||||
fun Resources.Theme.showErrorSnackBar(view: CoordinatorLayout, text: String, anchor: View? = null) {
|
||||
val s = Snackbar
|
||||
.make(view, text, Snackbar.LENGTH_SHORT)
|
||||
// Set colours to signify an error
|
||||
.setBackgroundTint(getThemedColor(R.attr.colorErrorContainer))
|
||||
.setTextColor(getThemedColor(R.attr.colorOnErrorContainer))
|
||||
.show()
|
||||
|
||||
anchor?.let { a -> s.setAnchorView(a) }
|
||||
s.show()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ class AppRepository(app: Application) {
|
||||
private val dietaryPrefString = "prefs_obj"
|
||||
|
||||
// Blank dietary preference regular expression
|
||||
private val blankDietaryPrefs: String = DietaryPreferences.C_FALSE.toString().repeat(10)
|
||||
private val blankDietaryPrefs: String = DietaryPreferences.TEMPLATE_EMPTY
|
||||
|
||||
/**
|
||||
* Used to observe just to register an update of the user-set dietary preferences.
|
||||
|
||||
@@ -7,20 +7,18 @@ import android.os.Bundle
|
||||
import android.widget.TimePicker
|
||||
|
||||
/**
|
||||
* Dialogue used for letting the user pick a timestamp.
|
||||
* Dialogue used for letting the user pick a timestamp. TODO crashes on config change (multitask)
|
||||
*
|
||||
* @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,
|
||||
private val isEventStart: Boolean,
|
||||
) : DialogFragment(), TimePickerDialog.OnTimeSetListener {
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val timestampSplit = timestamp.split(":")
|
||||
val timestampSplit = (arguments?.getString("timestamp") ?: "").split(":")
|
||||
return TimePickerDialog(
|
||||
activity,
|
||||
this,
|
||||
|
||||
@@ -121,7 +121,7 @@ class CanteenFragment : AppFragment() {
|
||||
chip.isChecked = getPreference(pref)
|
||||
|
||||
// Set a listener for when the user clicks the chip
|
||||
chip.setOnCheckedChangeListener { buttonView, newValue ->
|
||||
chip.setOnCheckedChangeListener { _, newValue ->
|
||||
// Save the preference change to persistent storage
|
||||
setPreference(pref, newValue)
|
||||
}
|
||||
|
||||
@@ -141,7 +141,6 @@ class SettingsFragment : AppFragment() {
|
||||
intent.putExtras(bundle)
|
||||
})
|
||||
}
|
||||
10 -> showToast(context, getString(R.string.settings_app_version_10))
|
||||
15 -> showToast(context, getString(R.string.settings_app_version_15))
|
||||
20 -> showToast(context, getString(R.string.settings_app_version_20))
|
||||
30 -> showToast(context, getString(R.string.settings_app_version_30))
|
||||
@@ -151,7 +150,10 @@ class SettingsFragment : AppFragment() {
|
||||
200 -> showToast(context, getString(R.string.settings_app_version_200))
|
||||
222 -> {
|
||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(mysteryLink)))
|
||||
appVersionClick = -1
|
||||
}
|
||||
238 -> { // after 222 has been reached, this loops every 16 clicks
|
||||
showToast(context, resources.getStringArray(R.array.cheesy).random())
|
||||
appVersionClick = 222
|
||||
}
|
||||
}
|
||||
appVersionClick += 1
|
||||
|
||||
@@ -1,65 +1,38 @@
|
||||
package com.denizk0461.studip.model
|
||||
|
||||
// TODO KDoc
|
||||
enum class AllergenPreferences {
|
||||
GLUTEN_WHEAT,
|
||||
GLUTEN_RYE,
|
||||
GLUTEN_BARLEY,
|
||||
GLUTEN_OATS,
|
||||
GLUTEN_SPELT,
|
||||
GLUTEN_KAMUT,
|
||||
CRUSTACEANS,
|
||||
EGGS,
|
||||
FISH,
|
||||
PEANUTS,
|
||||
SOY,
|
||||
DAIRY,
|
||||
ALMONDS,
|
||||
HAZELNUTS,
|
||||
WALNUTS,
|
||||
CASHEW_NUTS,
|
||||
PECANS,
|
||||
BRAZIL_NUTS,
|
||||
PISTACHIOS,
|
||||
MACADAMIA,
|
||||
CELERY,
|
||||
MUSTARD,
|
||||
SULPHIDES,
|
||||
LUPINS,
|
||||
SESAME,
|
||||
MOLLUSCS,
|
||||
;
|
||||
class AllergenPreferences {
|
||||
|
||||
/**
|
||||
* Object that holds allergy preferences. Can be used to hold both the user-set values as well
|
||||
* as the values of an individual canteen item.
|
||||
*
|
||||
* @param hasWheat
|
||||
* @param hasRye
|
||||
* @param hasBarley
|
||||
* @param hasOats
|
||||
* @param hasSpelt
|
||||
* @param hasKamut
|
||||
* @param hasCrustaceans
|
||||
* @param hasEggs
|
||||
* @param hasFish
|
||||
* @param hasPeanuts
|
||||
* @param hasSoy
|
||||
* @param hasDairy
|
||||
* @param hasAlmonds
|
||||
* @param hasHazelnuts
|
||||
* @param hasWalnuts
|
||||
* @param hasCashewNuts
|
||||
* @param hasPecans
|
||||
* @param hasBrazilNuts
|
||||
* @param hasPistachios
|
||||
* @param hasMacadamia
|
||||
* @param hasCelery
|
||||
* @param hasMustard
|
||||
* @param hasSulphides
|
||||
* @param hasLupins
|
||||
* @param hasSesame
|
||||
* @param hasMolluscs
|
||||
* @param hasWheat whether the offer contains gluten through wheat
|
||||
* @param hasRye whether the offer contains gluten through rye
|
||||
* @param hasBarley whether the offer contains gluten through barley
|
||||
* @param hasOats whether the offer contains gluten through oats
|
||||
* @param hasSpelt whether the offer contains gluten through spelt
|
||||
* @param hasKamut whether the offer contains gluten through kamut
|
||||
* @param hasCrustaceans whether the offer contains crustaceans
|
||||
* @param hasEggs whether the offer contains eggs
|
||||
* @param hasFish whether the offer contains fish
|
||||
* @param hasPeanuts whether the offer contains peanuts
|
||||
* @param hasSoy whether the offer contains soy
|
||||
* @param hasDairy whether the offer contains dairy
|
||||
* @param hasAlmonds whether the offer contains almonds
|
||||
* @param hasHazelnuts whether the offer contains hazelnuts
|
||||
* @param hasWalnuts whether the offer contains walnuts
|
||||
* @param hasCashewNuts whether the offer contains cashew nuts
|
||||
* @param hasPecans whether the offer contains pecan nuts
|
||||
* @param hasBrazilNuts whether the offer contains brazil nuts
|
||||
* @param hasPistachios whether the offer contains pistachios
|
||||
* @param hasMacadamia whether the offer contains macadamia nuts
|
||||
* @param hasCelery whether the offer contains celery
|
||||
* @param hasMustard whether the offer contains mustard
|
||||
* @param hasSulphides whether the offer contains highly concentrated sulphides
|
||||
* @param hasLupins whether the offer contains lupins
|
||||
* @param hasSesame whether the offer contains sesame
|
||||
* @param hasMolluscs whether the offer contains molluscs
|
||||
*/
|
||||
data class Object(
|
||||
val hasWheat: Boolean,
|
||||
@@ -130,15 +103,16 @@ enum class AllergenPreferences {
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val C_TRUE: Char = 'y'
|
||||
const val C_FALSE: Char = 'n'
|
||||
|
||||
/**
|
||||
* Template string representing no allergens.
|
||||
*/
|
||||
const val TEMPLATE: String = ""
|
||||
|
||||
/**
|
||||
* Constructs an AllergenPreferenceObject from a string.
|
||||
*
|
||||
* @param input string that must be 26 characters long
|
||||
* @param input string that must be 26 characters long. This will NOT be checked
|
||||
* @return instance of AllergenPreferences.Object with preferences inserted
|
||||
*/
|
||||
fun construct(input: String): Object {
|
||||
@@ -172,37 +146,5 @@ enum class AllergenPreferences {
|
||||
elements.contains("n"),
|
||||
)
|
||||
}
|
||||
// String(
|
||||
// charArrayOf(
|
||||
// charFor(obj.hasWheat),
|
||||
// charFor(obj.hasRye),
|
||||
// charFor(obj.hasBarley),
|
||||
// charFor(obj.hasOats),
|
||||
// charFor(obj.hasSpelt),
|
||||
// charFor(obj.hasKamut),
|
||||
// charFor(obj.hasCrustaceans),
|
||||
// charFor(obj.hasEggs),
|
||||
// charFor(obj.hasFish),
|
||||
// charFor(obj.hasPeanuts),
|
||||
// charFor(obj.hasSoy),
|
||||
// charFor(obj.hasDairy),
|
||||
// charFor(obj.hasAlmonds),
|
||||
// charFor(obj.hasHazelnuts),
|
||||
// charFor(obj.hasWalnuts),
|
||||
// charFor(obj.hasCashewNuts),
|
||||
// charFor(obj.hasPecans),
|
||||
// charFor(obj.hasBrazilNuts),
|
||||
// charFor(obj.hasPistachios),
|
||||
// charFor(obj.hasMacadamia),
|
||||
// charFor(obj.hasCelery),
|
||||
// charFor(obj.hasMustard),
|
||||
// charFor(obj.hasSulphides),
|
||||
// charFor(obj.hasLupins),
|
||||
// charFor(obj.hasSesame),
|
||||
// charFor(obj.hasMolluscs),
|
||||
// )
|
||||
// )
|
||||
|
||||
private fun charFor(pref: Boolean) = if (pref) C_TRUE else C_FALSE
|
||||
}
|
||||
}
|
||||
@@ -128,17 +128,23 @@ enum class DietaryPreferences(val value: String) {
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Char used to construct a regex to denote that a preference is met
|
||||
* 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
|
||||
* Char used to construct a regex to denote that a preference is not met.
|
||||
*/
|
||||
const val C_FALSE: Char = '.'
|
||||
|
||||
/**
|
||||
* Default value for preferences if none are set.
|
||||
*/
|
||||
const val TEMPLATE_EMPTY: String = ".........."
|
||||
|
||||
/**
|
||||
* Object denoting that no dietary preferences apply.
|
||||
*/
|
||||
val NONE_MET: Object = construct(TEMPLATE_EMPTY)
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,6 +37,9 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
||||
// View model
|
||||
private val viewModel: ScheduleUpdateViewModel by viewModels()
|
||||
|
||||
// Whether the user has once clicked the delete button; used to prevent an accidental click
|
||||
private var hasClickedDelete: Boolean = false
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
@@ -54,6 +57,7 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
||||
binding.editTextLecturers.setText(event.lecturer)
|
||||
binding.editTextRoom.setText(event.room)
|
||||
|
||||
|
||||
/*
|
||||
* Show academic quarter suggestion if it is applicable. For this to be the case, both the
|
||||
* start timestamp and the end timestamp must match up in a pattern that would make it
|
||||
@@ -62,63 +66,63 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
||||
*
|
||||
* 13:00 - 15:30 -> likely no academic quarter intended
|
||||
*/
|
||||
binding.buttonAcademicQuarter.visibility = if (
|
||||
timeslotsAcademicQuarter.contains(timeslotStart) &&
|
||||
timeslotsAcademicQuarter.contains(timeslotEnd)
|
||||
) {
|
||||
binding.buttonAcademicQuarter.setOnClickListener {
|
||||
try {
|
||||
// Retrieve new timestamps with the academic quarter applied, or throw a tantrum
|
||||
val newStart = getTimestampAcademicQuarterStart(timeslotStart)
|
||||
val newEnd = getTimestampAcademicQuarterEnd(timeslotEnd)
|
||||
binding.buttonAcademicQuarter.setOnClickListener {
|
||||
try {
|
||||
// Retrieve new timestamps with the academic quarter applied, or throw a tantrum
|
||||
val newStart = getTimestampAcademicQuarterStart(timeslotStart)
|
||||
val newEnd = getTimestampAcademicQuarterEnd(timeslotEnd)
|
||||
|
||||
// Set the buttons to the new timesatmps
|
||||
timeslotStart = newStart
|
||||
binding.buttonTimeStart.text = newStart
|
||||
timeslotEnd = newEnd
|
||||
binding.buttonTimeEnd.text = newEnd
|
||||
// Set the buttons to the new timesatmps
|
||||
timeslotStart = newStart
|
||||
binding.buttonTimeStart.text = newStart
|
||||
timeslotEnd = newEnd
|
||||
binding.buttonTimeEnd.text = newEnd
|
||||
|
||||
/*
|
||||
/*
|
||||
* Attempt to fix the issue of the bottom sheet jumping up when hiding the
|
||||
* button.
|
||||
*/
|
||||
TransitionManager.beginDelayedTransition(binding.sheet.parent as ViewGroup)
|
||||
binding.buttonAcademicQuarter.visibility = View.GONE
|
||||
TransitionManager.beginDelayedTransition(binding.sheet.parent as ViewGroup)
|
||||
binding.buttonAcademicQuarter.visibility = View.GONE
|
||||
|
||||
// Catch if a timeslot couldn't be found in the list, and tell the user
|
||||
} catch (e: AcademicQuarterNotApplicableException) {
|
||||
showToast(
|
||||
context,
|
||||
getString(R.string.sheet_schedule_update_hint_quarter_error)
|
||||
)
|
||||
}
|
||||
// Catch if a timeslot couldn't be found in the list, and tell the user
|
||||
} catch (e: AcademicQuarterNotApplicableException) {
|
||||
showToast(
|
||||
context,
|
||||
getString(R.string.sheet_schedule_update_hint_quarter_error)
|
||||
)
|
||||
}
|
||||
|
||||
// If the pattern applies, show the button to the user
|
||||
View.VISIBLE
|
||||
} else {
|
||||
// Hide the button if the action is not necessary or applicable
|
||||
View.GONE
|
||||
}
|
||||
|
||||
binding.buttonAcademicQuarter.visibility = getVisibilityForAcademicQuarter(
|
||||
timeslotsAcademicQuarter.contains(timeslotStart),
|
||||
timeslotsAcademicQuarter.contains(timeslotEnd),
|
||||
)
|
||||
|
||||
// Prepare timestamp buttons
|
||||
binding.buttonTimeStart.text = timeslotStart
|
||||
binding.buttonTimeStart.setOnClickListener {
|
||||
// Launch a time picker dialogue to pick a new start timestamp
|
||||
TimePickerFragment(
|
||||
binding.buttonTimeStart.text.toString(),
|
||||
this,
|
||||
true,
|
||||
).show((context as FragmentActivity).supportFragmentManager, "timePicker")
|
||||
).also { sheet ->
|
||||
val bundle = Bundle()
|
||||
bundle.putString("timestamp", binding.buttonTimeStart.text.toString())
|
||||
sheet.arguments = bundle
|
||||
}.show((context as FragmentActivity).supportFragmentManager, "timePicker")
|
||||
}
|
||||
binding.buttonTimeEnd.text = timeslotEnd
|
||||
binding.buttonTimeEnd.setOnClickListener {
|
||||
// Launch a time picker dialogue to pick a new end timestamp
|
||||
TimePickerFragment(
|
||||
binding.buttonTimeEnd.text.toString(),
|
||||
this,
|
||||
false,
|
||||
).show((context as FragmentActivity).supportFragmentManager, "timePicker")
|
||||
).also { sheet ->
|
||||
val bundle = Bundle()
|
||||
bundle.putString("timestamp", binding.buttonTimeEnd.text.toString())
|
||||
sheet.arguments = bundle
|
||||
}.show((context as FragmentActivity).supportFragmentManager, "timePicker")
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -134,9 +138,20 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
||||
|
||||
// Prepare delete button
|
||||
binding.buttonDelete.setOnClickListener {
|
||||
viewModel.delete(event)
|
||||
// Dismiss the sheet upon deletion
|
||||
dismiss()
|
||||
/*
|
||||
* Check if the user has already clicked the button before; this is done to prevent
|
||||
* accidentally deleting an event.
|
||||
*/
|
||||
if (hasClickedDelete) {
|
||||
viewModel.delete(event)
|
||||
// Dismiss the sheet upon deletion
|
||||
dismiss()
|
||||
} else {
|
||||
// Update the text to show the user that they clicked the button once
|
||||
TransitionManager.beginDelayedTransition(binding.buttonContainer as ViewGroup)
|
||||
binding.buttonDelete.text = getString(R.string.sheet_schedule_update_delete_confirm)
|
||||
hasClickedDelete = true
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare update/save button
|
||||
@@ -193,6 +208,26 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
||||
timeslotEnd = newTimestamp
|
||||
binding.buttonTimeEnd.text = newTimestamp
|
||||
}
|
||||
|
||||
// Set appropriate visibility to the academic quarter button
|
||||
TransitionManager.beginDelayedTransition(binding.sheet.parent as ViewGroup)
|
||||
binding.buttonAcademicQuarter.visibility = getVisibilityForAcademicQuarter(
|
||||
timeslotsAcademicQuarter.contains(timeslotStart),
|
||||
timeslotsAcademicQuarter.contains(timeslotEnd),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines which visibility the academic quarter button should have given the timestamps.
|
||||
*
|
||||
* @param isStartValid whether the starting timestamp can be converted to an academic quarter
|
||||
* @param isEndValid whether the ending timestamp can be converted to an academic quarter
|
||||
*/
|
||||
private fun getVisibilityForAcademicQuarter(isStartValid: Boolean, isEndValid: Boolean): Int =
|
||||
if (isStartValid && isEndValid) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
<vector android:height="24dp" android:tint="?attr/colorOnSurfaceVariant"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
<vector android:height="24dp" android:tint="?attr/colorOnSurfaceVariant"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
<vector android:height="24dp" android:tint="?attr/colorOnSurfaceVariant"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
|
||||
|
||||
@@ -8,19 +8,25 @@
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.google.android.material.bottomappbar.BottomAppBar
|
||||
style="@style/Widget.Material3.BottomAppBar"
|
||||
android:id="@+id/bottom_app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
app:menu="@menu/menu_fetcher_bar"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="@dimen/fab_margin"
|
||||
android:layout_marginBottom="@dimen/fab_margin"
|
||||
app:srcCompat="@drawable/save"/>
|
||||
app:srcCompat="@drawable/save"
|
||||
android:contentDescription="@string/fetch_bar_save_desc"
|
||||
app:layout_anchor="@id/bottom_app_bar"/>
|
||||
<!-- android:layout_gravity="bottom|end"-->
|
||||
<!-- android:layout_marginEnd="@dimen/fab_margin"-->
|
||||
<!-- android:layout_marginBottom="@dimen/fab_margin"-->
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
@@ -165,11 +165,13 @@
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/button_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginBottom="8dp">
|
||||
android:layout_marginBottom="8dp"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/button_delete"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/close"
|
||||
android:icon="@drawable/cross"
|
||||
android:title="@string/fetch_bar_close_title"
|
||||
android:contentDescription="@string/fetch_bar_close_desc"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/refresh"
|
||||
android:icon="@drawable/refresh"
|
||||
android:title="@string/fetch_bar_refresh_title"
|
||||
android:contentDescription="@string/fetch_bar_refresh_desc"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/help"
|
||||
android:icon="@drawable/info"
|
||||
android:title="@string/fetch_bar_help_title"
|
||||
android:contentDescription="@string/fetch_bar_help_desc"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
||||
@@ -23,8 +23,19 @@
|
||||
<string name="fetch_error_webpage_snack">Du musst deinen Stundenplan öffnen!</string>
|
||||
<string name="canteen_fetch_error">Mensaplan konnte nicht heruntergeladen werden!</string>
|
||||
|
||||
<string name="fetch_bar_close_title">Schließen</string>
|
||||
<string name="fetch_bar_close_desc">Schließe die Webseite, ohne etwas zu speichern</string>
|
||||
<string name="fetch_bar_refresh_title">Aktualisieren</string>
|
||||
<string name="fetch_bar_refresh_desc">Aktualisiere die Webseite</string>
|
||||
<string name="fetch_bar_help_title">Hilfe</string>
|
||||
<string name="fetch_bar_help_desc">Zeige Hilfe</string>
|
||||
<string name="fetch_bar_help_sheet_title">Wie Du Deinen Stundenplan in der App speichern kannst</string>
|
||||
<string name="fetch_bar_help_sheet_content"> • Logge dich mit deinem Stud.IP-Login ein\n • Öffne deinen Stundenplan (falls er sich nicht automatisch öffnet)\n • Klicke auf den \'Speichern\'-Knopf rechts in der unteren Ecke\n • Fertig!</string>
|
||||
<string name="fetch_bar_save_desc">Speichere den Stundenplan in der App ab</string>
|
||||
|
||||
<string name="save">Speichern</string>
|
||||
<string name="delete">Löschen</string>
|
||||
<string name="sheet_schedule_update_delete_confirm">Sicher?</string>
|
||||
<string name="cancel">Abbrechen</string>
|
||||
<string name="confirm">Bestätigen</string>
|
||||
<string name="sheet_schedule_update_header">Veranstaltung bearbeiten</string>
|
||||
@@ -164,7 +175,6 @@
|
||||
|
||||
<string name="settings_app_version">App-Version</string>
|
||||
|
||||
<string name="settings_app_version_10">oh jaa</string>
|
||||
<string name="settings_app_version_15">klick weiter</string>
|
||||
<string name="settings_app_version_121">Solltest du nicht für deine Klausuren lernen?</string>
|
||||
|
||||
|
||||
@@ -23,8 +23,19 @@
|
||||
<string name="fetch_error_webpage_snack">You must navigate to your schedule!</string>
|
||||
<string name="canteen_fetch_error">Couldn\'t retrieve the canteen plan!</string>
|
||||
|
||||
<string name="fetch_bar_close_title">Close</string>
|
||||
<string name="fetch_bar_close_desc">Close the website without saving anything</string>
|
||||
<string name="fetch_bar_refresh_title">Refresh</string>
|
||||
<string name="fetch_bar_refresh_desc">Refresh the page</string>
|
||||
<string name="fetch_bar_help_title">Help</string>
|
||||
<string name="fetch_bar_help_desc">Show help</string>
|
||||
<string name="fetch_bar_help_sheet_title">How to save your timetable in the app</string>
|
||||
<string name="fetch_bar_help_sheet_content"> • Log in with your Stud.IP login\n • Open your timetable view (in case it doesn\'t open automatically)\n • Click the \'save\' button in the bottom right corner\n • Done!</string>
|
||||
<string name="fetch_bar_save_desc">Save the timetable in the app</string>
|
||||
|
||||
<string name="save">Save</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="sheet_schedule_update_delete_confirm">Sure?</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="sheet_schedule_update_header">Edit Event</string>
|
||||
@@ -153,7 +164,7 @@
|
||||
<string name="settings_pref_colour_subtitle">This colours the icons similar to how they look the website</string> <!-- TODO this text sucks, DE too -->
|
||||
|
||||
<string name="settings_launch_canteen_title">Show canteen plan on app launch</string>
|
||||
<string name="settings_launch_canteen_subtitle">Otherwise your schedule will be shown at launch</string>
|
||||
<string name="settings_launch_canteen_subtitle">Otherwise your schedule will be shown at launch; CURRENTLY BROKEN</string>
|
||||
|
||||
<string name="settings_crashlytics_title">Opt-in to sharing crash data</string>
|
||||
<string name="settings_crashlytics_subtitle">Data will be anonymised</string> <!-- TODO is this true? -->
|
||||
@@ -170,7 +181,6 @@
|
||||
|
||||
<string name="settings_app_version">App Version</string>
|
||||
|
||||
<string name="settings_app_version_10">ahhh yes</string>
|
||||
<string name="settings_app_version_15">keep clicking</string>
|
||||
<string name="settings_app_version_20" translatable="false">^_^</string>
|
||||
<string name="settings_app_version_30" translatable="false">^_____^</string>
|
||||
@@ -181,5 +191,13 @@
|
||||
|
||||
<string name="with_love">with ♡️ from Bremen-Osterholz\nmade by denizk0461 \\__*</string>
|
||||
|
||||
<string name="de4thSpirit" translatable="false">In our hearts, she lives forevermore</string>
|
||||
<string-array name="cheesy" translatable="false">
|
||||
<item>in our hearts, she lives forevermore</item>
|
||||
<item>it\'s only real when it hurts</item>
|
||||
<item>can\'t go back in time – every second is a new one</item>
|
||||
<item>doctor, i am the great clown Pagliacci</item>
|
||||
<item>if we only had one more day, what is the last thing you\'d say?</item>
|
||||
<item>love with your heart, use your head for everything else</item>
|
||||
<item>if I die, I hope I\'m buried in a forest – that is, if any of it\'s left</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user