Archived
Food menu now splits up holiday messages; added documentation
This commit is contained in:
@@ -25,6 +25,7 @@ import com.denizd.substitutionplan.data.HelperFunctions
|
|||||||
import com.denizd.substitutionplan.data.LoginWebViewClient
|
import com.denizd.substitutionplan.data.LoginWebViewClient
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import java.lang.Exception
|
||||||
import kotlin.math.hypot
|
import kotlin.math.hypot
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +81,8 @@ internal class Login : AppCompatActivity(R.layout.activity_login_webview), Login
|
|||||||
|
|
||||||
private fun success() {
|
private fun success() {
|
||||||
prefs.edit().putBoolean("successful_login", true).apply()
|
prefs.edit().putBoolean("successful_login", true).apply()
|
||||||
|
val handler = Handler()
|
||||||
|
try {
|
||||||
val layoutAfterCircleReveal = findViewById<LinearLayout>(R.id.layoutAfterCircleReveal)
|
val layoutAfterCircleReveal = findViewById<LinearLayout>(R.id.layoutAfterCircleReveal)
|
||||||
|
|
||||||
val x: Int = logInButton.right - logInButton.width / 2
|
val x: Int = logInButton.right - logInButton.width / 2
|
||||||
@@ -88,7 +90,6 @@ internal class Login : AppCompatActivity(R.layout.activity_login_webview), Login
|
|||||||
val endRadius = hypot(parentLayout.width.toDouble(), parentLayout.height.toDouble()).toInt()
|
val endRadius = hypot(parentLayout.width.toDouble(), parentLayout.height.toDouble()).toInt()
|
||||||
View.inflate(this, R.layout.unlock_screen, layoutAfterCircleReveal)
|
View.inflate(this, R.layout.unlock_screen, layoutAfterCircleReveal)
|
||||||
val anim = ViewAnimationUtils.createCircularReveal(layoutAfterCircleReveal, x, y, 0F, endRadius.toFloat())
|
val anim = ViewAnimationUtils.createCircularReveal(layoutAfterCircleReveal, x, y, 0F, endRadius.toFloat())
|
||||||
val handler = Handler()
|
|
||||||
val animOut = AnimationUtils.loadAnimation(this, R.anim.fade_out_short)
|
val animOut = AnimationUtils.loadAnimation(this, R.anim.fade_out_short)
|
||||||
anim.duration = 600
|
anim.duration = 600
|
||||||
val colour = findViewById<LinearLayout>(R.id.colourLayout)
|
val colour = findViewById<LinearLayout>(R.id.colourLayout)
|
||||||
@@ -115,10 +116,14 @@ internal class Login : AppCompatActivity(R.layout.activity_login_webview), Login
|
|||||||
mImgCheck.start()
|
mImgCheck.start()
|
||||||
}
|
}
|
||||||
}, 600)
|
}, 600)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
} finally {
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
val main = Intent(this, Main::class.java)
|
val main = Intent(this, Main::class.java)
|
||||||
startActivity(main)
|
startActivity(main)
|
||||||
finish()
|
finish()
|
||||||
}, 3000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -86,8 +86,10 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
val contextView = findViewById<View>(R.id.coordination)
|
val contextView = findViewById<View>(R.id.coordination)
|
||||||
val window = this.window
|
val window = this.window
|
||||||
|
|
||||||
|
/// Sets the theme explicitly to dismiss the splash screen
|
||||||
setTheme(R.style.AppTheme0)
|
setTheme(R.style.AppTheme0)
|
||||||
|
|
||||||
|
/// Sets the system bar's colours according to the current Android version
|
||||||
val barColour = when {
|
val barColour = when {
|
||||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.M -> ContextCompat.getColor(context, R.color.legacyBlack)
|
Build.VERSION.SDK_INT < Build.VERSION_CODES.M -> ContextCompat.getColor(context, R.color.legacyBlack)
|
||||||
Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> ContextCompat.getColor(context, R.color.colorBackground)
|
Build.VERSION.SDK_INT <= Build.VERSION_CODES.P -> ContextCompat.getColor(context, R.color.colorBackground)
|
||||||
@@ -98,6 +100,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
window.statusBarColor = barColour
|
window.statusBarColor = barColour
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies theming with additional workarounds for API levels 23-28 (M-P)
|
||||||
when (prefs.getInt("themeInt", 0)) {
|
when (prefs.getInt("themeInt", 0)) {
|
||||||
0 -> {
|
0 -> {
|
||||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||||
@@ -114,12 +117,18 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Displays the date and time of the last refresh of the substitution plan in a snack bar
|
||||||
if (!prefs.getBoolean("autoRefresh", false) && prefs.getInt("firstTimeOpening", 0) != 0) {
|
if (!prefs.getBoolean("autoRefresh", false) && prefs.getInt("firstTimeOpening", 0) != 0) {
|
||||||
try {
|
try {
|
||||||
Snackbar.make(contextView, "${getString(R.string.last_updated)} ${prefs.getString("timeNew", "")}", Snackbar.LENGTH_LONG).show()
|
Snackbar.make(contextView, "${getString(R.string.last_updated)} ${prefs.getString("timeNew", "")}", Snackbar.LENGTH_LONG).show()
|
||||||
} catch (e: IllegalArgumentException) {}
|
} catch (e: IllegalArgumentException) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the greeting string if enabled by the user, sets it empty otherwise.
|
||||||
|
* Don't set the text view of the greeting string to View.GONE, as that will mess
|
||||||
|
* with the constraints
|
||||||
|
*/
|
||||||
val textViewGreeting = findViewById<TextView>(R.id.text_greeting)
|
val textViewGreeting = findViewById<TextView>(R.id.text_greeting)
|
||||||
textViewGreeting.text = if (prefs.getBoolean("greeting", true) && (prefs.getString("username", "") ?: "").isNotEmpty()) {
|
textViewGreeting.text = if (prefs.getBoolean("greeting", true) && (prefs.getString("username", "") ?: "").isNotEmpty()) {
|
||||||
getGreetingString()
|
getGreetingString()
|
||||||
@@ -127,6 +136,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Legacy function
|
||||||
if (prefs.getInt("firstTimeOpening", 0) == 0) {
|
if (prefs.getInt("firstTimeOpening", 0) == 0) {
|
||||||
edit.putInt("firstTimeOpening", prefs.getInt("firstTimeOpening", 0) + 1).apply()
|
edit.putInt("firstTimeOpening", prefs.getInt("firstTimeOpening", 0) + 1).apply()
|
||||||
}
|
}
|
||||||
@@ -143,6 +153,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
}
|
}
|
||||||
loadFragment(defaultFragment)
|
loadFragment(defaultFragment)
|
||||||
|
|
||||||
|
/// Opens the corresponding fragment or the info dialog
|
||||||
bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->
|
bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->
|
||||||
var fragmentLoading = true
|
var fragmentLoading = true
|
||||||
lateinit var fragment: Fragment
|
lateinit var fragment: Fragment
|
||||||
@@ -176,6 +187,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Scrolls to the top of any currently displayed fragment
|
||||||
bottomNav.setOnNavigationItemReselectedListener { item: MenuItem ->
|
bottomNav.setOnNavigationItemReselectedListener { item: MenuItem ->
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.plan, R.id.personal -> {
|
R.id.plan, R.id.personal -> {
|
||||||
@@ -231,6 +243,10 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
}, prefs.getString("username", ""))
|
}, prefs.getString("username", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the strings provided in the substitution plan's info boxes as well as the
|
||||||
|
* refresh date and time from Shared Preferences and displays them in a dialog
|
||||||
|
*/
|
||||||
private fun openInfoDialog() {
|
private fun openInfoDialog() {
|
||||||
val dialog = AlertDialog.Builder(context)
|
val dialog = AlertDialog.Builder(context)
|
||||||
val dialogView = View.inflate(context, R.layout.simple_dialog, null)
|
val dialogView = View.inflate(context, R.layout.simple_dialog, null)
|
||||||
@@ -247,9 +263,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/// Triggers FBPingService.kt to re-subscribe to the selected Firebase topics every 15 minutes
|
||||||
* Triggers FBPingService.kt to re-subscribe to the selected Firebase topics every 15 minutes
|
|
||||||
*/
|
|
||||||
private fun pingFirebaseTopics() {
|
private fun pingFirebaseTopics() {
|
||||||
val componentName = ComponentName(this, FBPingService::class.java)
|
val componentName = ComponentName(this, FBPingService::class.java)
|
||||||
val info = JobInfo.Builder(42, componentName)
|
val info = JobInfo.Builder(42, componentName)
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ import java.util.*
|
|||||||
*/
|
*/
|
||||||
internal class SubstitutionAdapter(private var substitutions: List<Substitution>, private val prefs: SharedPreferences) : RecyclerView.Adapter<SubstitutionAdapter.CardViewHolder>() {
|
internal class SubstitutionAdapter(private var substitutions: List<Substitution>, private val prefs: SharedPreferences) : RecyclerView.Adapter<SubstitutionAdapter.CardViewHolder>() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ViewHolder class used by SubstitutionAdapter.kt to resolve references to views in
|
||||||
|
* course_card.xml that will be inflated and populated with data in
|
||||||
|
* SubstitutionAdapter#onBindViewHolder
|
||||||
|
*
|
||||||
|
* @param view a reference to the xml that is to be inflated
|
||||||
|
*/
|
||||||
internal class CardViewHolder(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
|
internal class CardViewHolder(view: View) : RecyclerView.ViewHolder(view), View.OnClickListener {
|
||||||
|
|
||||||
var iconView: ImageView = view.findViewById(R.id.iconView)
|
var iconView: ImageView = view.findViewById(R.id.iconView)
|
||||||
@@ -43,7 +50,9 @@ internal class SubstitutionAdapter(private var substitutions: List<Substitution>
|
|||||||
var spacer: TextView = view.findViewById(R.id.spacer)
|
var spacer: TextView = view.findViewById(R.id.spacer)
|
||||||
var card: MaterialCardView = view.findViewById(R.id.planCard)
|
var card: MaterialCardView = view.findViewById(R.id.planCard)
|
||||||
val context: Context = card.context
|
val context: Context = card.context
|
||||||
|
|
||||||
init { view.setOnClickListener(this) }
|
init { view.setOnClickListener(this) }
|
||||||
|
|
||||||
override fun onClick(v: View?) {
|
override fun onClick(v: View?) {
|
||||||
if (date.text.toString().length > 7 && date.text.toString().substring(3, 7) == "http") {
|
if (date.text.toString().length > 7 && date.text.toString().substring(3, 7) == "http") {
|
||||||
try {
|
try {
|
||||||
@@ -77,14 +86,14 @@ internal class SubstitutionAdapter(private var substitutions: List<Substitution>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val add = currentItem.additional.toLowerCase(Locale.ROOT)
|
val add = currentItem.additional
|
||||||
val type = currentItem.type.toLowerCase(Locale.ROOT)
|
val type = currentItem.type.toLowerCase(Locale.ROOT)
|
||||||
if (add.isNotEmpty()) {
|
if (add.isNotEmpty()) {
|
||||||
if (HelperFunctions.checkStringForArray(add, HelperFunctions.cancellations)) {
|
if (HelperFunctions.checkStringForArray(add, HelperFunctions.cancellations, true)) {
|
||||||
strikeThrough(strings)
|
strikeThrough(strings)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (HelperFunctions.checkStringForArray(type, HelperFunctions.cancellations)) {
|
if (HelperFunctions.checkStringForArray(type, HelperFunctions.cancellations, true)) {
|
||||||
strikeThrough(strings)
|
strikeThrough(strings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,6 +170,7 @@ internal class SubstitutionAdapter(private var substitutions: List<Substitution>
|
|||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strikes through the strings for course, room and teacher
|
||||||
private fun strikeThrough(strings: Array<SpannableString>) {
|
private fun strikeThrough(strings: Array<SpannableString>) {
|
||||||
for (i in 2..4) { strings[i].setSpan(StrikethroughSpan(), 0, strings[i].length, 0) }
|
for (i in 2..4) { strings[i].setSpan(StrikethroughSpan(), 0, strings[i].length, 0) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,9 +122,9 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole
|
|||||||
foodRepository.deleteAll()
|
foodRepository.deleteAll()
|
||||||
|
|
||||||
val indices = ArrayList<Int>()
|
val indices = ArrayList<Int>()
|
||||||
val daysAndVon = arrayOf("Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "von")
|
val daysAndVon = arrayOf("montag", "dienstag", "mittwoch", "donnerstag", "freitag", "von", "wünschen")
|
||||||
for (i in 0 until foodElements.size) {
|
for (i in 0 until foodElements.size) {
|
||||||
if (HelperFunctions.checkStringForArray(foodElements[i].text(), daysAndVon)) indices.add(i)
|
if (HelperFunctions.checkStringForArray(foodElements[i].text(), daysAndVon, true)) indices.add(i)
|
||||||
}
|
}
|
||||||
indices.add(foodElements.size)
|
indices.add(foodElements.size)
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ internal object HelperFunctions {
|
|||||||
"lavender", "carnation", "brown2", "pureBlack")
|
"lavender", "carnation", "brown2", "pureBlack")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of all phrases used to describe that a course has been cancelled. Expand this
|
* A lowercased list of all phrases used to describe that a course has been cancelled. Expand
|
||||||
* if necessary. No further code changes required if this is expanded
|
* this if necessary. No further code changes required if this is expanded
|
||||||
*/
|
*/
|
||||||
val cancellations = arrayOf("eigenverantwortliches arbeiten", "entfall", "entfällt", "fällt aus", "freisetzung", "vtr. ohne lehrer")
|
val cancellations = arrayOf("eigenverantwortliches arbeiten", "entfall", "entfällt", "fällt aus", "freisetzung", "vtr. ohne lehrer")
|
||||||
|
|
||||||
@@ -305,8 +305,9 @@ internal object HelperFunctions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkStringForArray(s: String, checking: Array<String>): Boolean {
|
fun checkStringForArray(checkedString: String, checkingArray: Array<String>, lowerCased: Boolean): Boolean {
|
||||||
checking.forEach { check ->
|
val s = if (lowerCased) checkedString.toLowerCase(Locale.ROOT) else checkedString
|
||||||
|
checkingArray.forEach { check ->
|
||||||
if (s.contains(check)) return true
|
if (s.contains(check)) return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -330,7 +331,7 @@ internal object HelperFunctions {
|
|||||||
val a = group.substring(0, 2).toInt()
|
val a = group.substring(0, 2).toInt()
|
||||||
-a
|
-a
|
||||||
}
|
}
|
||||||
checkStringForArray(group.substring(0, 1), juniors) -> -101
|
checkStringForArray(group.substring(0, 1), juniors, false) -> -101
|
||||||
else -> -100
|
else -> -100
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package com.denizd.substitutionplan.data
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum class for declaring Firebase Cloud Messaging topics without using the raw strings
|
* Enum class for declaring Firebase Cloud Messaging topics without using the raw strings
|
||||||
* throughout the project
|
* throughout the project to avoid human error
|
||||||
*/
|
*/
|
||||||
internal enum class Topic(val tag: String) {
|
internal enum class Topic(val tag: String) {
|
||||||
ANDROID("substitutions-android"),
|
ANDROID("substitutions-android"),
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import com.google.firebase.messaging.FirebaseMessaging
|
|||||||
* issues regarding the app being force-closed in the background and not being able to receive
|
* issues regarding the app being force-closed in the background and not being able to receive
|
||||||
* notifications.
|
* notifications.
|
||||||
*
|
*
|
||||||
* I am unsure about its effectiveness, though notifications do seem to arrive
|
* I am unsure about its effectiveness, though notifications do seem to arrive relatively reliably
|
||||||
*/
|
*/
|
||||||
internal class FBPingService : JobService() {
|
internal class FBPingService : JobService() {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user