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.WebResourceRequest
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
import android.widget.Toast
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import com.denizk0461.studip.R
|
import com.denizk0461.studip.R
|
||||||
import com.denizk0461.studip.data.showErrorSnackBar
|
import com.denizk0461.studip.data.showErrorSnackBar
|
||||||
|
import com.denizk0461.studip.data.showToast
|
||||||
import com.denizk0461.studip.databinding.ActivityFetcherBinding
|
import com.denizk0461.studip.databinding.ActivityFetcherBinding
|
||||||
|
import com.denizk0461.studip.sheet.TextSheet
|
||||||
import com.denizk0461.studip.viewmodel.FetcherViewModel
|
import com.denizk0461.studip.viewmodel.FetcherViewModel
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URLDecoder
|
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
|
* 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.
|
* profile. Launched through a button in the app's settings.
|
||||||
*/
|
*/
|
||||||
class FetcherActivity : AppCompatActivity() {
|
class FetcherActivity : FragmentActivity() {
|
||||||
|
|
||||||
// View binding
|
// View binding
|
||||||
private lateinit var binding: ActivityFetcherBinding
|
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
|
* Attempt to load the user-set Stud.IP front page. Redirects to login page if user is
|
||||||
* not logged in.
|
* not logged in.
|
||||||
*/
|
*/
|
||||||
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
|
binding.webview.loadUrl("https://elearning.uni-bremen.de/index.php?again=yes")
|
||||||
|
|
||||||
binding.fab.setOnClickListener { view ->
|
binding.fab.setOnClickListener {
|
||||||
|
|
||||||
if (binding.webview.url?.contains(
|
if (binding.webview.url?.contains(
|
||||||
"https://elearning.uni-bremen.de/dispatch.php/calendar/schedule"
|
"https://elearning.uni-bremen.de/dispatch.php/calendar/schedule"
|
||||||
@@ -78,20 +106,19 @@ class FetcherActivity : AppCompatActivity() {
|
|||||||
viewModel.parse(URLDecoder.decode(p0, "UTF-8"))
|
viewModel.parse(URLDecoder.decode(p0, "UTF-8"))
|
||||||
|
|
||||||
// Notify the user that the fetch was successful
|
// Notify the user that the fetch was successful
|
||||||
Toast.makeText(
|
showToast(this, getString(R.string.toast_fetch_finished))
|
||||||
this, R.string.toast_fetch_finished, Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
|
|
||||||
// Close the activity
|
// Close the activity
|
||||||
finish()
|
finish()
|
||||||
|
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
// Let the user know that an error occurred
|
// 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 {
|
} 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.Bundle
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.AttrRes
|
import androidx.annotation.AttrRes
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
@@ -51,13 +52,15 @@ fun showToast(context: Context, text: String) {
|
|||||||
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Resources.Theme.showErrorSnackBar(view: CoordinatorLayout, text: String) {
|
fun Resources.Theme.showErrorSnackBar(view: CoordinatorLayout, text: String, anchor: View? = null) {
|
||||||
Snackbar
|
val s = Snackbar
|
||||||
.make(view, text, Snackbar.LENGTH_SHORT)
|
.make(view, text, Snackbar.LENGTH_SHORT)
|
||||||
// Set colours to signify an error
|
// Set colours to signify an error
|
||||||
.setBackgroundTint(getThemedColor(R.attr.colorErrorContainer))
|
.setBackgroundTint(getThemedColor(R.attr.colorErrorContainer))
|
||||||
.setTextColor(getThemedColor(R.attr.colorOnErrorContainer))
|
.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"
|
private val dietaryPrefString = "prefs_obj"
|
||||||
|
|
||||||
// Blank dietary preference regular expression
|
// 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.
|
* 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
|
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 listener listener for when the user finishes setting a time
|
||||||
* @param isEventStart whether the timestamp to be edited is the start of the event
|
* @param isEventStart whether the timestamp to be edited is the start of the event
|
||||||
*/
|
*/
|
||||||
class TimePickerFragment(
|
class TimePickerFragment(
|
||||||
private val timestamp: String,
|
|
||||||
private val listener: OnTimeSetListener,
|
private val listener: OnTimeSetListener,
|
||||||
private val isEventStart: Boolean,
|
private val isEventStart: Boolean,
|
||||||
) : DialogFragment(), TimePickerDialog.OnTimeSetListener {
|
) : DialogFragment(), TimePickerDialog.OnTimeSetListener {
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val timestampSplit = timestamp.split(":")
|
val timestampSplit = (arguments?.getString("timestamp") ?: "").split(":")
|
||||||
return TimePickerDialog(
|
return TimePickerDialog(
|
||||||
activity,
|
activity,
|
||||||
this,
|
this,
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ class CanteenFragment : AppFragment() {
|
|||||||
chip.isChecked = getPreference(pref)
|
chip.isChecked = getPreference(pref)
|
||||||
|
|
||||||
// Set a listener for when the user clicks the chip
|
// Set a listener for when the user clicks the chip
|
||||||
chip.setOnCheckedChangeListener { buttonView, newValue ->
|
chip.setOnCheckedChangeListener { _, newValue ->
|
||||||
// Save the preference change to persistent storage
|
// Save the preference change to persistent storage
|
||||||
setPreference(pref, newValue)
|
setPreference(pref, newValue)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,6 @@ class SettingsFragment : AppFragment() {
|
|||||||
intent.putExtras(bundle)
|
intent.putExtras(bundle)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
10 -> showToast(context, getString(R.string.settings_app_version_10))
|
|
||||||
15 -> showToast(context, getString(R.string.settings_app_version_15))
|
15 -> showToast(context, getString(R.string.settings_app_version_15))
|
||||||
20 -> showToast(context, getString(R.string.settings_app_version_20))
|
20 -> showToast(context, getString(R.string.settings_app_version_20))
|
||||||
30 -> showToast(context, getString(R.string.settings_app_version_30))
|
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))
|
200 -> showToast(context, getString(R.string.settings_app_version_200))
|
||||||
222 -> {
|
222 -> {
|
||||||
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(mysteryLink)))
|
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
|
appVersionClick += 1
|
||||||
|
|||||||
@@ -1,65 +1,38 @@
|
|||||||
package com.denizk0461.studip.model
|
package com.denizk0461.studip.model
|
||||||
|
|
||||||
// TODO KDoc
|
// TODO KDoc
|
||||||
enum class AllergenPreferences {
|
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,
|
|
||||||
;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object that holds allergy preferences. Can be used to hold both the user-set values as well
|
* 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.
|
* as the values of an individual canteen item.
|
||||||
*
|
*
|
||||||
* @param hasWheat
|
* @param hasWheat whether the offer contains gluten through wheat
|
||||||
* @param hasRye
|
* @param hasRye whether the offer contains gluten through rye
|
||||||
* @param hasBarley
|
* @param hasBarley whether the offer contains gluten through barley
|
||||||
* @param hasOats
|
* @param hasOats whether the offer contains gluten through oats
|
||||||
* @param hasSpelt
|
* @param hasSpelt whether the offer contains gluten through spelt
|
||||||
* @param hasKamut
|
* @param hasKamut whether the offer contains gluten through kamut
|
||||||
* @param hasCrustaceans
|
* @param hasCrustaceans whether the offer contains crustaceans
|
||||||
* @param hasEggs
|
* @param hasEggs whether the offer contains eggs
|
||||||
* @param hasFish
|
* @param hasFish whether the offer contains fish
|
||||||
* @param hasPeanuts
|
* @param hasPeanuts whether the offer contains peanuts
|
||||||
* @param hasSoy
|
* @param hasSoy whether the offer contains soy
|
||||||
* @param hasDairy
|
* @param hasDairy whether the offer contains dairy
|
||||||
* @param hasAlmonds
|
* @param hasAlmonds whether the offer contains almonds
|
||||||
* @param hasHazelnuts
|
* @param hasHazelnuts whether the offer contains hazelnuts
|
||||||
* @param hasWalnuts
|
* @param hasWalnuts whether the offer contains walnuts
|
||||||
* @param hasCashewNuts
|
* @param hasCashewNuts whether the offer contains cashew nuts
|
||||||
* @param hasPecans
|
* @param hasPecans whether the offer contains pecan nuts
|
||||||
* @param hasBrazilNuts
|
* @param hasBrazilNuts whether the offer contains brazil nuts
|
||||||
* @param hasPistachios
|
* @param hasPistachios whether the offer contains pistachios
|
||||||
* @param hasMacadamia
|
* @param hasMacadamia whether the offer contains macadamia nuts
|
||||||
* @param hasCelery
|
* @param hasCelery whether the offer contains celery
|
||||||
* @param hasMustard
|
* @param hasMustard whether the offer contains mustard
|
||||||
* @param hasSulphides
|
* @param hasSulphides whether the offer contains highly concentrated sulphides
|
||||||
* @param hasLupins
|
* @param hasLupins whether the offer contains lupins
|
||||||
* @param hasSesame
|
* @param hasSesame whether the offer contains sesame
|
||||||
* @param hasMolluscs
|
* @param hasMolluscs whether the offer contains molluscs
|
||||||
*/
|
*/
|
||||||
data class Object(
|
data class Object(
|
||||||
val hasWheat: Boolean,
|
val hasWheat: Boolean,
|
||||||
@@ -130,15 +103,16 @@ enum class AllergenPreferences {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val C_TRUE: Char = 'y'
|
|
||||||
const val C_FALSE: Char = 'n'
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template string representing no allergens.
|
||||||
|
*/
|
||||||
const val TEMPLATE: String = ""
|
const val TEMPLATE: String = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an AllergenPreferenceObject from a 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
|
* @return instance of AllergenPreferences.Object with preferences inserted
|
||||||
*/
|
*/
|
||||||
fun construct(input: String): Object {
|
fun construct(input: String): Object {
|
||||||
@@ -172,37 +146,5 @@ enum class AllergenPreferences {
|
|||||||
elements.contains("n"),
|
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 {
|
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'
|
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 = '.'
|
const val C_FALSE: Char = '.'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for preferences if none are set.
|
||||||
|
*/
|
||||||
const val TEMPLATE_EMPTY: String = ".........."
|
const val TEMPLATE_EMPTY: String = ".........."
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object denoting that no dietary preferences apply.
|
||||||
|
*/
|
||||||
val NONE_MET: Object = construct(TEMPLATE_EMPTY)
|
val NONE_MET: Object = construct(TEMPLATE_EMPTY)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,6 +37,9 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
|||||||
// View model
|
// View model
|
||||||
private val viewModel: ScheduleUpdateViewModel by viewModels()
|
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?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
@@ -54,6 +57,7 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
|||||||
binding.editTextLecturers.setText(event.lecturer)
|
binding.editTextLecturers.setText(event.lecturer)
|
||||||
binding.editTextRoom.setText(event.room)
|
binding.editTextRoom.setText(event.room)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show academic quarter suggestion if it is applicable. For this to be the case, both the
|
* 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
|
* start timestamp and the end timestamp must match up in a pattern that would make it
|
||||||
@@ -62,10 +66,6 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
|||||||
*
|
*
|
||||||
* 13:00 - 15:30 -> likely no academic quarter intended
|
* 13:00 - 15:30 -> likely no academic quarter intended
|
||||||
*/
|
*/
|
||||||
binding.buttonAcademicQuarter.visibility = if (
|
|
||||||
timeslotsAcademicQuarter.contains(timeslotStart) &&
|
|
||||||
timeslotsAcademicQuarter.contains(timeslotEnd)
|
|
||||||
) {
|
|
||||||
binding.buttonAcademicQuarter.setOnClickListener {
|
binding.buttonAcademicQuarter.setOnClickListener {
|
||||||
try {
|
try {
|
||||||
// Retrieve new timestamps with the academic quarter applied, or throw a tantrum
|
// Retrieve new timestamps with the academic quarter applied, or throw a tantrum
|
||||||
@@ -94,31 +94,35 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the pattern applies, show the button to the user
|
binding.buttonAcademicQuarter.visibility = getVisibilityForAcademicQuarter(
|
||||||
View.VISIBLE
|
timeslotsAcademicQuarter.contains(timeslotStart),
|
||||||
} else {
|
timeslotsAcademicQuarter.contains(timeslotEnd),
|
||||||
// Hide the button if the action is not necessary or applicable
|
)
|
||||||
View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare timestamp buttons
|
// Prepare timestamp buttons
|
||||||
binding.buttonTimeStart.text = timeslotStart
|
binding.buttonTimeStart.text = timeslotStart
|
||||||
binding.buttonTimeStart.setOnClickListener {
|
binding.buttonTimeStart.setOnClickListener {
|
||||||
// Launch a time picker dialogue to pick a new start timestamp
|
// Launch a time picker dialogue to pick a new start timestamp
|
||||||
TimePickerFragment(
|
TimePickerFragment(
|
||||||
binding.buttonTimeStart.text.toString(),
|
|
||||||
this,
|
this,
|
||||||
true,
|
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.text = timeslotEnd
|
||||||
binding.buttonTimeEnd.setOnClickListener {
|
binding.buttonTimeEnd.setOnClickListener {
|
||||||
// Launch a time picker dialogue to pick a new end timestamp
|
// Launch a time picker dialogue to pick a new end timestamp
|
||||||
TimePickerFragment(
|
TimePickerFragment(
|
||||||
binding.buttonTimeEnd.text.toString(),
|
|
||||||
this,
|
this,
|
||||||
false,
|
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
|
// Prepare delete button
|
||||||
binding.buttonDelete.setOnClickListener {
|
binding.buttonDelete.setOnClickListener {
|
||||||
|
/*
|
||||||
|
* Check if the user has already clicked the button before; this is done to prevent
|
||||||
|
* accidentally deleting an event.
|
||||||
|
*/
|
||||||
|
if (hasClickedDelete) {
|
||||||
viewModel.delete(event)
|
viewModel.delete(event)
|
||||||
// Dismiss the sheet upon deletion
|
// Dismiss the sheet upon deletion
|
||||||
dismiss()
|
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
|
// Prepare update/save button
|
||||||
@@ -193,6 +208,26 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update), TimePicker
|
|||||||
timeslotEnd = newTimestamp
|
timeslotEnd = newTimestamp
|
||||||
binding.buttonTimeEnd.text = 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:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
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"/>
|
<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:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
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"/>
|
<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:viewportHeight="24" android:viewportWidth="24"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
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"/>
|
<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
|
<WebView
|
||||||
android:id="@+id/webview"
|
android:id="@+id/webview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"/>
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
style="@style/Widget.Material3.BottomAppBar"
|
||||||
app:layout_constraintEnd_toEndOf="parent"/>
|
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
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
android:id="@+id/fab"
|
android:id="@+id/fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
app:srcCompat="@drawable/save"
|
||||||
android:layout_marginEnd="@dimen/fab_margin"
|
android:contentDescription="@string/fetch_bar_save_desc"
|
||||||
android:layout_marginBottom="@dimen/fab_margin"
|
app:layout_anchor="@id/bottom_app_bar"/>
|
||||||
app:srcCompat="@drawable/save"/>
|
<!-- android:layout_gravity="bottom|end"-->
|
||||||
|
<!-- android:layout_marginEnd="@dimen/fab_margin"-->
|
||||||
|
<!-- android:layout_marginBottom="@dimen/fab_margin"-->
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -165,11 +165,13 @@
|
|||||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||||
|
|
||||||
<androidx.appcompat.widget.LinearLayoutCompat
|
<androidx.appcompat.widget.LinearLayoutCompat
|
||||||
|
android:id="@+id/button_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:gravity="end"
|
android:gravity="end"
|
||||||
android:layout_marginBottom="8dp">
|
android:layout_marginBottom="8dp"
|
||||||
|
android:animateLayoutChanges="true">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/button_delete"
|
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="fetch_error_webpage_snack">Du musst deinen Stundenplan öffnen!</string>
|
||||||
<string name="canteen_fetch_error">Mensaplan konnte nicht heruntergeladen werden!</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="save">Speichern</string>
|
||||||
<string name="delete">Löschen</string>
|
<string name="delete">Löschen</string>
|
||||||
|
<string name="sheet_schedule_update_delete_confirm">Sicher?</string>
|
||||||
<string name="cancel">Abbrechen</string>
|
<string name="cancel">Abbrechen</string>
|
||||||
<string name="confirm">Bestätigen</string>
|
<string name="confirm">Bestätigen</string>
|
||||||
<string name="sheet_schedule_update_header">Veranstaltung bearbeiten</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">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_15">klick weiter</string>
|
||||||
<string name="settings_app_version_121">Solltest du nicht für deine Klausuren lernen?</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="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="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="save">Save</string>
|
||||||
<string name="delete">Delete</string>
|
<string name="delete">Delete</string>
|
||||||
|
<string name="sheet_schedule_update_delete_confirm">Sure?</string>
|
||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="confirm">Confirm</string>
|
<string name="confirm">Confirm</string>
|
||||||
<string name="sheet_schedule_update_header">Edit Event</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_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_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_title">Opt-in to sharing crash data</string>
|
||||||
<string name="settings_crashlytics_subtitle">Data will be anonymised</string> <!-- TODO is this true? -->
|
<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">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_15">keep clicking</string>
|
||||||
<string name="settings_app_version_20" translatable="false">^_^</string>
|
<string name="settings_app_version_20" translatable="false">^_^</string>
|
||||||
<string name="settings_app_version_30" 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="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>
|
</resources>
|
||||||
Reference in New Issue
Block a user