Archived
Login page now disallows visiting a domain other than the school's login page to prevent a successful login from another domain allowing access to the app's content
This commit is contained in:
@@ -11,29 +11,33 @@ import com.denizd.substitutionplan.models.Colour
|
||||
import com.denizd.substitutionplan.R
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
internal class ColourAdapter(private var mColours: List<Colour>, onClickListener: OnClickListener) : RecyclerView.Adapter<ColourAdapter.ColourViewHolder>() {
|
||||
/**
|
||||
* Adapter class used for displaying the courses as well as their associated colours in the
|
||||
* customisation dialog. Used in SettingsFragment.kt
|
||||
*
|
||||
* @param colours a list of all courses and their associated colour
|
||||
* @param onClickListener a reference to an OnClickListener
|
||||
*/
|
||||
internal class ColourAdapter(private var colours: List<Colour>, private val onClickListener: OnClickListener) : RecyclerView.Adapter<ColourAdapter.ColourViewHolder>() {
|
||||
|
||||
private val mOnClickListener = onClickListener
|
||||
|
||||
class ColourViewHolder(view: View, clickListener: OnClickListener) : RecyclerView.ViewHolder(view), View.OnClickListener {
|
||||
internal class ColourViewHolder(view: View, private val clickListener: OnClickListener) : RecyclerView.ViewHolder(view), View.OnClickListener {
|
||||
val title: TextView = view.findViewById(R.id.item_text)
|
||||
var image: ImageView = view.findViewById(R.id.item_image)
|
||||
val titleNoLang: TextView = view.findViewById(R.id.item_text_no_lang)
|
||||
val cardView: MaterialCardView = view.findViewById(R.id.cardView)
|
||||
private val mClickListener = clickListener
|
||||
init { view.setOnClickListener(this) }
|
||||
|
||||
override fun onClick(v: View?) { mClickListener.onClick(adapterPosition, title.text.toString(), titleNoLang.text.toString()) }
|
||||
override fun onClick(v: View?) { clickListener.onClick(adapterPosition, title.text.toString(), titleNoLang.text.toString()) }
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ColourViewHolder {
|
||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
|
||||
return ColourViewHolder(v, mOnClickListener)
|
||||
return ColourViewHolder(v, onClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ColourViewHolder, position: Int) {
|
||||
val currentItem = mColours[position]
|
||||
val currentItem = colours[position]
|
||||
|
||||
holder.title.text = currentItem.title
|
||||
holder.titleNoLang.text = currentItem.titleNoLang
|
||||
@@ -54,7 +58,7 @@ internal class ColourAdapter(private var mColours: List<Colour>, onClickListener
|
||||
holder.title.setTextColor(ContextCompat.getColor(holder.title.context, textColor))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = mColours.size
|
||||
override fun getItemCount(): Int = colours.size
|
||||
|
||||
internal interface OnClickListener {
|
||||
fun onClick(position: Int, title: String, titleNoLang: String)
|
||||
|
||||
@@ -5,39 +5,38 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
|
||||
import java.util.ArrayList
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.denizd.substitutionplan.models.Food
|
||||
import com.denizd.substitutionplan.R
|
||||
|
||||
internal class FoodAdapter(food: ArrayList<Food>) : RecyclerView.Adapter<FoodAdapter.CardViewHolder>() {
|
||||
private var mFood: List<Food>? = null
|
||||
/**
|
||||
* Adapter class used in FoodFragment.kt to display the food menu to the user
|
||||
*
|
||||
* @param foods a list of all food entries on the menu
|
||||
*/
|
||||
internal class FoodAdapter(private var foods: List<Food>) : RecyclerView.Adapter<FoodAdapter.FoodViewHolder>() {
|
||||
|
||||
class CardViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var mFood: TextView = itemView.findViewById(R.id.cardInfoText)
|
||||
internal class FoodViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var text: TextView = itemView.findViewById(R.id.cardInfoText)
|
||||
}
|
||||
|
||||
init {
|
||||
mFood = food
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FoodViewHolder {
|
||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.just_a_card, parent, false)
|
||||
return CardViewHolder(v)
|
||||
return FoodViewHolder(v)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
|
||||
val currentItem = mFood!![position]
|
||||
override fun onBindViewHolder(holder: FoodViewHolder, position: Int) {
|
||||
val currentItem = foods[position]
|
||||
|
||||
holder.mFood.text = currentItem.food
|
||||
holder.text.text = currentItem.food
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return mFood!!.size
|
||||
return foods.size
|
||||
}
|
||||
|
||||
fun setFood(food: List<Food>) {
|
||||
mFood = food
|
||||
fun setFood(foods: List<Food>) {
|
||||
this.foods = foods
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,40 +10,39 @@ import com.denizd.substitutionplan.R
|
||||
import com.denizd.substitutionplan.models.Ringtone
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
|
||||
internal class RingtoneAdapter(private var _ringtones: List<Ringtone>, onClickListener: OnClickListener) : RecyclerView.Adapter<RingtoneAdapter.RingtoneViewHolder>() {
|
||||
/**
|
||||
* Adapter class used for displaying all available notification ringtones to the user up to
|
||||
* Android version 7 (Nougat). Used in SettingsFragment.kt
|
||||
*
|
||||
* @param ringtones a list of all ringtones including their URI
|
||||
* @param onClickListener a reference to an OnClickListener to set the ringtone
|
||||
*/
|
||||
internal class RingtoneAdapter(private val ringtones: List<Ringtone>, private val onClickListener: OnClickListener) : RecyclerView.Adapter<RingtoneAdapter.RingtoneViewHolder>() {
|
||||
|
||||
private val _onClickListener = onClickListener
|
||||
|
||||
class RingtoneViewHolder(view: View, clickListener: OnClickListener) : RecyclerView.ViewHolder(view), View.OnClickListener {
|
||||
internal class RingtoneViewHolder(view: View, private val clickListener: OnClickListener) : RecyclerView.ViewHolder(view), View.OnClickListener {
|
||||
val name: TextView = view.findViewById(R.id.item_text)
|
||||
val uri: TextView = view.findViewById(R.id.item_text_no_lang)
|
||||
val cardView: MaterialCardView = view.findViewById(R.id.cardView)
|
||||
private val _clickListener = clickListener
|
||||
init { view.setOnClickListener(this) }
|
||||
|
||||
override fun onClick(v: View?) { _clickListener.onRingtoneClick(adapterPosition, name.text.toString(), uri.text.toString()) }
|
||||
override fun onClick(v: View?) { clickListener.onRingtoneClick(adapterPosition, name.text.toString(), uri.text.toString()) }
|
||||
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RingtoneViewHolder {
|
||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_item, parent, false)
|
||||
return RingtoneViewHolder(
|
||||
v,
|
||||
_onClickListener
|
||||
)
|
||||
return RingtoneViewHolder(v, onClickListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RingtoneViewHolder, position: Int) {
|
||||
val currentItem = _ringtones[position]
|
||||
val currentItem = ringtones[position]
|
||||
|
||||
holder.name.text = currentItem.name
|
||||
holder.uri.text = currentItem.uri
|
||||
holder.cardView.setCardBackgroundColor(ContextCompat.getColor(holder.cardView.context,
|
||||
R.color.colorBackground
|
||||
))
|
||||
holder.cardView.setCardBackgroundColor(ContextCompat.getColor(holder.cardView.context, R.color.colorBackground))
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = _ringtones.size
|
||||
override fun getItemCount(): Int = ringtones.size
|
||||
|
||||
internal interface OnClickListener {
|
||||
fun onRingtoneClick(position: Int, name: String, uri: String)
|
||||
|
||||
+24
-65
@@ -1,6 +1,7 @@
|
||||
package com.denizd.substitutionplan.adapters
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.text.SpannableString
|
||||
@@ -16,18 +17,20 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.denizd.substitutionplan.data.HelperFunctions
|
||||
import com.denizd.substitutionplan.R
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
import com.google.android.material.card.MaterialCardView
|
||||
import java.util.*
|
||||
|
||||
internal class CardAdapter(private var mSubst: List<Subst>, private val prefs: SharedPreferences) : RecyclerView.Adapter<CardAdapter.CardViewHolder>() {
|
||||
/**
|
||||
* Adapter class for the Recycler View used to display the substitution plan in
|
||||
* PlanFragment.kt and its subclasses
|
||||
*
|
||||
* @param substitutions a list of all substitutions of data type Substitution
|
||||
* @param prefs a reference to the app's Shared Preferences used to get user-set colours
|
||||
*/
|
||||
internal class SubstitutionAdapter(private var substitutions: List<Substitution>, private val prefs: SharedPreferences) : RecyclerView.Adapter<SubstitutionAdapter.CardViewHolder>() {
|
||||
|
||||
private var colour = 0
|
||||
private var colourString = ""
|
||||
private var colorCheck = ""
|
||||
private val cancellations = arrayOf("eigenverantwortliches arbeiten", "entfall", "entfällt", "fällt aus", "freisetzung", "vtr. ohne lehrer")
|
||||
|
||||
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 group: TextView = view.findViewById(R.id.group)
|
||||
@@ -38,16 +41,16 @@ internal class CardAdapter(private var mSubst: List<Subst>, private val prefs: S
|
||||
var additional: TextView = view.findViewById(R.id.additional)
|
||||
var teacher: TextView = view.findViewById(R.id.teacher)
|
||||
var spacer: TextView = view.findViewById(R.id.spacer)
|
||||
|
||||
var card: MaterialCardView = view.findViewById(R.id.planCard)
|
||||
val context: Context = card.context
|
||||
init { view.setOnClickListener(this) }
|
||||
override fun onClick(v: View?) {
|
||||
if (date.text.toString().length > 7 && date.text.toString().substring(3, 7) == "http") {
|
||||
try {
|
||||
CustomTabsIntent.Builder().build().launchUrl(card.context,
|
||||
Uri.parse(date.text.toString().substring(3)))
|
||||
CustomTabsIntent.Builder().build().launchUrl(context,
|
||||
Uri.parse(date.text.substring(3)))
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Toast.makeText(card.context, card.context.getString(R.string.chrome_not_found), Toast.LENGTH_LONG).show()
|
||||
Toast.makeText(context, context.getString(R.string.chrome_not_found), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,12 +62,13 @@ internal class CardAdapter(private var mSubst: List<Subst>, private val prefs: S
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
|
||||
val currentItem = mSubst[position]
|
||||
val currentItem = substitutions[position]
|
||||
var psa = false
|
||||
val strings = arrayOf(SpannableString(currentItem.group), SpannableString(currentItem.time),
|
||||
SpannableString(currentItem.course), SpannableString(currentItem.room),
|
||||
SpannableString(currentItem.teacher))
|
||||
var cardBackgroundColour = 0
|
||||
val cardBackgroundColour: Int
|
||||
var colour = 0
|
||||
|
||||
for (string in strings) {
|
||||
val questionMarkIndex = string.indexOf("?")
|
||||
@@ -76,11 +80,11 @@ internal class CardAdapter(private var mSubst: List<Subst>, private val prefs: S
|
||||
val add = currentItem.additional.toLowerCase(Locale.ROOT)
|
||||
val type = currentItem.type.toLowerCase(Locale.ROOT)
|
||||
if (add.isNotEmpty()) {
|
||||
if (HelperFunctions.checkStringForArray(add, cancellations)) {
|
||||
if (HelperFunctions.checkStringForArray(add, HelperFunctions.cancellations)) {
|
||||
strikeThrough(strings)
|
||||
}
|
||||
} else {
|
||||
if (HelperFunctions.checkStringForArray(type, cancellations)) {
|
||||
if (HelperFunctions.checkStringForArray(type, HelperFunctions.cancellations)) {
|
||||
strikeThrough(strings)
|
||||
}
|
||||
}
|
||||
@@ -100,7 +104,7 @@ internal class CardAdapter(private var mSubst: List<Subst>, private val prefs: S
|
||||
cardBackgroundColour = R.color.colorAccent
|
||||
View.GONE
|
||||
} else {
|
||||
colourString = getColourString(holder.course.text.toString())
|
||||
val colourString = HelperFunctions.getColourString(holder.course.text.toString())
|
||||
val colourPrefsInt = if (colourString.isNotEmpty()) {
|
||||
prefs.getString("card$colourString", "") ?: ""
|
||||
} else {
|
||||
@@ -150,58 +154,13 @@ internal class CardAdapter(private var mSubst: List<Subst>, private val prefs: S
|
||||
holder.teacher.setTextColor(textColor)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = mSubst.size
|
||||
override fun getItemCount(): Int = substitutions.size
|
||||
|
||||
fun setSubst(subst: List<Subst>) {
|
||||
mSubst = subst
|
||||
fun setSubst(substitutions: List<Substitution>) {
|
||||
this.substitutions = substitutions
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private fun getColourString(course: String): String {
|
||||
return try {
|
||||
colorCheck = course.toLowerCase(Locale.ROOT).substring(0, 3)
|
||||
when (colorCheck) {
|
||||
"deu", "dep", "daz", "fda" -> "German"
|
||||
"mat", "map" -> "Maths"
|
||||
"eng", "enp", "ena" -> "English"
|
||||
"spo", "spp", "spth" -> "PhysEd"
|
||||
"pol", "pop" -> "Politics"
|
||||
"dar", "dap" -> "Theatre"
|
||||
"phy", "php" -> "Physics"
|
||||
"bio", "bip", "nw1", "nw2", "nw3", "nw4" -> "Biology"
|
||||
"che", "chp" -> "Chemistry"
|
||||
"phi", "psp" -> "Philosophy"
|
||||
"laa", "laf", "lat" -> "Latin"
|
||||
"spa", "spf" -> "Spanish"
|
||||
"fra", "frf", "frz" -> "French"
|
||||
"inf" -> "CompSci"
|
||||
"ges" -> "History"
|
||||
"rel" -> "Religion"
|
||||
"geg" -> "Geography"
|
||||
"kun" -> "Arts"
|
||||
"mus" -> "Music"
|
||||
"tue" -> "Turkish"
|
||||
"chi" -> "Chinese"
|
||||
"gll" -> "GLL"
|
||||
"wat" -> "WAT"
|
||||
"för" -> "Forder"
|
||||
"met", "wpb" -> "WP"
|
||||
else -> ""
|
||||
}
|
||||
} catch (e: StringIndexOutOfBoundsException) {
|
||||
try {
|
||||
colorCheck = course.toLowerCase(Locale.ROOT).substring(0, 2)
|
||||
when (colorCheck) {
|
||||
"nw" -> "Biology"
|
||||
"wp" -> "WP"
|
||||
else -> ""
|
||||
}
|
||||
} catch (e2: StringIndexOutOfBoundsException) {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun strikeThrough(strings: Array<SpannableString>) {
|
||||
for (i in 2..4) { strings[i].setSpan(StrikethroughSpan(), 0, strings[i].length, 0) }
|
||||
}
|
||||
@@ -18,7 +18,7 @@ import com.denizd.substitutionplan.R
|
||||
import com.denizd.substitutionplan.database.SubstRepository
|
||||
import com.denizd.substitutionplan.activities.Main
|
||||
import com.denizd.substitutionplan.models.Food
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.jsoup.Jsoup
|
||||
import java.lang.ref.WeakReference
|
||||
@@ -57,7 +57,7 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole
|
||||
private val edit = prefs.edit()
|
||||
private var currentTime = ""
|
||||
private var currentFoodTime = ""
|
||||
private var substUrl = "https://djd4rkn355.github.io/subst.html"
|
||||
private var substUrl = "https://djd4rkn355.github.io/avh_substitutions.html"
|
||||
private var foodUrl = "https://djd4rkn355.github.io/food.html"
|
||||
|
||||
override fun doInBackground(vararg params: Void?): Void? {
|
||||
@@ -149,7 +149,7 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole
|
||||
if (currentTime != prefs.getString("timeNew", "")) {
|
||||
val rows = doc.select("tr")
|
||||
val paragraphs = doc.select("p")
|
||||
val substArray = ArrayList<Subst>()
|
||||
val substArray = ArrayList<Substitution>()
|
||||
|
||||
val coursePreference = prefs.getString("courses", "") ?: ""
|
||||
val classPreference = prefs.getString("classes", "") ?: ""
|
||||
@@ -169,7 +169,7 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole
|
||||
val row = rows[i]
|
||||
val cols = row.select("th")
|
||||
|
||||
val subst = Subst(
|
||||
val subst = Substitution(
|
||||
group = cols[0].text(),
|
||||
date = cols[1].text(),
|
||||
time = cols[2].text(),
|
||||
@@ -237,11 +237,12 @@ internal class DataFetcher(isPlan: Boolean, isMenu: Boolean, isJobService: Boole
|
||||
val notification = NotificationCompat.Builder(context, HelperFunctions.notificationChannelId)
|
||||
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
|
||||
.setCustomContentView(notificationLayout)
|
||||
.setSmallIcon(R.drawable.ic_avhlogo)
|
||||
.setContentIntent(openAppPending)
|
||||
.setAutoCancel(true)
|
||||
.setColor(ContextCompat.getColor(context, R.color.colorAccent))
|
||||
|
||||
notification.setSmallIcon(if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) R.drawable.ic_avh else R.drawable.ic_avhlogo)
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
val sound = if ((prefs.getString("ringtoneUri", "") ?: "").isNotEmpty()) {
|
||||
Uri.parse(prefs.getString("ringtoneUri", "") ?: "")
|
||||
|
||||
@@ -20,7 +20,7 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.ContextCompat.checkSelfPermission
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.denizd.substitutionplan.R
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
import java.util.*
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -45,6 +45,12 @@ internal object HelperFunctions {
|
||||
"brown", "grey", "pureWhite", "salmon", "tangerine", "banana", "flora", "spindrift", "sky", "orchid",
|
||||
"lavender", "carnation", "brown2", "pureBlack")
|
||||
|
||||
/**
|
||||
* A list of all phrases used to describe that a course has been cancelled. Expand 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")
|
||||
|
||||
private val colourIntegers = intArrayOf(
|
||||
0,
|
||||
R.color.bgRed,
|
||||
@@ -135,6 +141,60 @@ internal object HelperFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns a string that is used to get the colour set for a specific course
|
||||
* from Shared Preferences
|
||||
*
|
||||
* @param course the course abbreviation as a string
|
||||
*
|
||||
* @return the string used to store the course's colour in Shared Preferences
|
||||
*/
|
||||
fun getColourString(course: String): String {
|
||||
var colorCheck: String
|
||||
return try {
|
||||
colorCheck = course.toLowerCase(Locale.ROOT).substring(0, 3)
|
||||
when (colorCheck) {
|
||||
"deu", "dep", "daz", "fda" -> "German"
|
||||
"mat", "map" -> "Maths"
|
||||
"eng", "enp", "ena" -> "English"
|
||||
"spo", "spp", "spth" -> "PhysEd"
|
||||
"pol", "pop" -> "Politics"
|
||||
"dar", "dap" -> "Theatre"
|
||||
"phy", "php" -> "Physics"
|
||||
"bio", "bip", "nw1", "nw2", "nw3", "nw4" -> "Biology"
|
||||
"che", "chp" -> "Chemistry"
|
||||
"phi", "psp" -> "Philosophy"
|
||||
"laa", "laf", "lat" -> "Latin"
|
||||
"spa", "spf" -> "Spanish"
|
||||
"fra", "frf", "frz" -> "French"
|
||||
"inf" -> "CompSci"
|
||||
"ges" -> "History"
|
||||
"rel" -> "Religion"
|
||||
"geg" -> "Geography"
|
||||
"kun" -> "Arts"
|
||||
"mus" -> "Music"
|
||||
"tue" -> "Turkish"
|
||||
"chi" -> "Chinese"
|
||||
"gll" -> "GLL"
|
||||
"wat" -> "WAT"
|
||||
"för" -> "Forder"
|
||||
"met", "wpb" -> "WP"
|
||||
else -> ""
|
||||
}
|
||||
} catch (e: StringIndexOutOfBoundsException) {
|
||||
try {
|
||||
colorCheck = course.toLowerCase(Locale.ROOT).substring(0, 2)
|
||||
when (colorCheck) {
|
||||
"nw" -> "Biology"
|
||||
"wp" -> "WP"
|
||||
else -> ""
|
||||
}
|
||||
} catch (e2: StringIndexOutOfBoundsException) {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function served as a way to transfer a deprecated method of storing user-defined
|
||||
* course colours to a new method. It is not required otherwise, but still remains in
|
||||
@@ -163,17 +223,17 @@ internal object HelperFunctions {
|
||||
* This function serves for checking whether a course on the substitution plan is relevant to
|
||||
* the user and should be shown on their personal plan as well as in their notifications
|
||||
*
|
||||
* @param subst the substitution item
|
||||
* @param substitution the substitution item
|
||||
* @param coursePreference a string that represents the courses the user is enrolled in
|
||||
* @param classPreference a string that represents the group the user is in
|
||||
* @param psa decide whether or not any PSA items should be included in the filter
|
||||
*
|
||||
* @return true if the substitution is relevant to the user, false otherwise
|
||||
*/
|
||||
fun checkPersonalSubstitutions(subst: Subst, coursePreference: String, classPreference: String, psa: Boolean): Boolean {
|
||||
val group = subst.group
|
||||
val course = subst.course
|
||||
if (psa && subst.date.isNotEmpty() && subst.date.substring(0, 3) == "psa") {
|
||||
fun checkPersonalSubstitutions(substitution: Substitution, coursePreference: String, classPreference: String, psa: Boolean): Boolean {
|
||||
val group = substitution.group
|
||||
val course = substitution.course
|
||||
if (psa && substitution.date.isNotEmpty() && substitution.date.substring(0, 3) == "psa") {
|
||||
return true
|
||||
}
|
||||
if (coursePreference.isEmpty() && classPreference.isNotEmpty()) {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.denizd.substitutionplan.data
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.util.Log
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
/**
|
||||
* Class that extends WebViewClient to provide a function that checks the webpage's cookies to
|
||||
@@ -10,27 +13,40 @@ import android.webkit.WebViewClient
|
||||
*
|
||||
* @param successListener a reference to the OnLoginSuccessListener implemented in an activity
|
||||
*/
|
||||
internal class LoginWebViewClient(successListener: OnLoginSuccessListener) : WebViewClient() {
|
||||
internal class LoginWebViewClient(private val successListener: OnLoginSuccessListener) : WebViewClient() {
|
||||
|
||||
private val mSuccessListener = successListener
|
||||
/**
|
||||
* onPageStarted has been overridden to prevent users from reaching a domain different from
|
||||
* the school's login page
|
||||
*/
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
super.onPageStarted(view, url, favicon)
|
||||
|
||||
if (url != "https://307.joomla.schule.bremen.de/index.php/component/users/profile?Itemid=171"
|
||||
&& url != "https://307.joomla.schule.bremen.de/index.php/component/users/#top") {
|
||||
reloadLoginPage(webView = view)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* OnPageFinished has been overridden to check if the cookie "joomla_user_state=logged_in"
|
||||
* exists, and returns true to the OnLoginSuccessListener
|
||||
*
|
||||
* @param view a reference to the WebView
|
||||
* @param url a reference to the url of the WebView
|
||||
*/
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
super.onPageFinished(view, url)
|
||||
view?.scrollY = -4000
|
||||
view?.scrollY = -10_000
|
||||
|
||||
val cookies = CookieManager.getInstance().getCookie(url)
|
||||
|
||||
if (cookies.contains("joomla_user_state=logged_in")) {
|
||||
mSuccessListener.onLoginSucceeded(true)
|
||||
successListener.onLoginSucceeded(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reloadLoginPage(webView: WebView?) {
|
||||
webView?.loadUrl("https://307.joomla.schule.bremen.de/index.php/component/users/#top")
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface that provides onLoginSucceeded to the activity or fragment that implements it
|
||||
*/
|
||||
|
||||
@@ -3,23 +3,23 @@ package com.denizd.substitutionplan.database
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.room.*
|
||||
import com.denizd.substitutionplan.models.Food
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
|
||||
@Dao
|
||||
internal interface SubstDao {
|
||||
|
||||
// @get:Query("SELECT * FROM subst_table ORDER BY date ASC, `group` ASC, time ASC, priority DESC")
|
||||
@get:Query("SELECT * FROM subst_table ORDER BY priority DESC")
|
||||
val allSubst: LiveData<List<Subst>>
|
||||
val allSubstitutions: LiveData<List<Substitution>>
|
||||
|
||||
@Insert
|
||||
fun insertSubst(subst: Subst)
|
||||
fun insertSubst(substitution: Substitution)
|
||||
|
||||
@Update
|
||||
fun updateSubst(subst: Subst)
|
||||
fun updateSubst(substitution: Substitution)
|
||||
|
||||
@Delete
|
||||
fun deleteSubst(subst: Subst)
|
||||
fun deleteSubst(substitution: Substitution)
|
||||
|
||||
@Query("DELETE FROM subst_table")
|
||||
fun deleteAllSubst()
|
||||
|
||||
@@ -7,9 +7,9 @@ import androidx.room.RoomDatabase
|
||||
import androidx.room.migration.Migration
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.denizd.substitutionplan.models.Food
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
|
||||
@Database(entities = [Subst::class, Food::class], version = 7, exportSchema = false)
|
||||
@Database(entities = [Substitution::class, Food::class], version = 7, exportSchema = false)
|
||||
internal abstract class SubstDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun substDao(): SubstDao
|
||||
|
||||
@@ -4,32 +4,32 @@ import android.app.Application
|
||||
import android.os.AsyncTask
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
|
||||
internal class SubstRepository(application: Application) {
|
||||
|
||||
private val substDao: SubstDao?
|
||||
val allSubst: LiveData<List<Subst>>?
|
||||
val allSubstitutions: LiveData<List<Substitution>>?
|
||||
|
||||
init {
|
||||
val database =
|
||||
SubstDatabase.getInstance(application)
|
||||
substDao = database?.substDao()
|
||||
allSubst = substDao?.allSubst
|
||||
allSubstitutions = substDao?.allSubstitutions
|
||||
}
|
||||
|
||||
fun insert(subst: Subst) {
|
||||
InsertSubstAsync(substDao).execute(subst)
|
||||
fun insert(substitution: Substitution) {
|
||||
InsertSubstAsync(substDao).execute(substitution)
|
||||
}
|
||||
|
||||
fun deleteAllSubst() {
|
||||
DeleteAllSubstAsync(substDao).execute()
|
||||
}
|
||||
|
||||
class InsertSubstAsync(substDao: SubstDao?) : AsyncTask<Subst, Void, Void>() {
|
||||
class InsertSubstAsync(substDao: SubstDao?) : AsyncTask<Substitution, Void, Void>() {
|
||||
private val mSubstDao = substDao
|
||||
override fun doInBackground(vararg substs: Subst): Void? {
|
||||
mSubstDao?.insertSubst(substs[0])
|
||||
override fun doInBackground(vararg substitutions: Substitution): Void? {
|
||||
mSubstDao?.insertSubst(substitutions[0])
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,16 +6,16 @@ import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.denizd.substitutionplan.data.DataFetcher
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
|
||||
internal class SubstViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
private val repository: SubstRepository = SubstRepository(application)
|
||||
val allSubst: LiveData<List<Subst>>?
|
||||
val allSubstitutions: LiveData<List<Substitution>>?
|
||||
private val app = application
|
||||
|
||||
init {
|
||||
allSubst = repository.allSubst
|
||||
allSubstitutions = repository.allSubstitutions
|
||||
}
|
||||
|
||||
fun refresh(swipeRefreshLayout: SwipeRefreshLayout, rootView: View, refreshMenu: Boolean) {
|
||||
|
||||
@@ -35,17 +35,10 @@ internal class FoodFragment : Fragment(R.layout.food_layout) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val pullToRefresh = view.findViewById<SwipeRefreshLayout>(R.id.pullToRefresh)
|
||||
|
||||
try {
|
||||
recyclerView = view.findViewById(R.id.linear_food)
|
||||
recyclerView.hasFixedSize()
|
||||
recyclerView.layoutManager = GridLayoutManager(mContext, 1)
|
||||
recyclerView.adapter = mAdapter
|
||||
|
||||
try {
|
||||
recyclerView.removeAllViews()
|
||||
} catch (ignored: NullPointerException) {}
|
||||
|
||||
} catch (ignored: NullPointerException) {}
|
||||
recyclerView = view.findViewById(R.id.linear_food)
|
||||
recyclerView.hasFixedSize()
|
||||
recyclerView.layoutManager = GridLayoutManager(mContext, 1)
|
||||
recyclerView.adapter = mAdapter
|
||||
|
||||
foodViewModel = ViewModelProviders.of(this).get(FoodViewModel::class.java)
|
||||
foodViewModel.allFoods?.observe(this, Observer<List<Food>> { foodList ->
|
||||
|
||||
@@ -3,14 +3,14 @@ package com.denizd.substitutionplan.fragments
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.lifecycle.Observer
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
|
||||
internal class GeneralPlanFragment : PlanFragment() {
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
substViewModel.allSubst?.observe(this, Observer<List<Subst>> { substitutions ->
|
||||
substViewModel.allSubstitutions?.observe(this, Observer<List<Substitution>> { substitutions ->
|
||||
mAdapter.setSubst(substitutions)
|
||||
recyclerView.scheduleLayoutAnimation()
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ import android.view.View
|
||||
import androidx.lifecycle.Observer
|
||||
import com.denizd.substitutionplan.data.HelperFunctions
|
||||
import com.denizd.substitutionplan.R
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
|
||||
internal class PersonalPlanFragment : PlanFragment() {
|
||||
|
||||
@@ -19,7 +19,7 @@ internal class PersonalPlanFragment : PlanFragment() {
|
||||
val coursePreference = prefs.getString("courses", "") ?: ""
|
||||
val classPreference = prefs.getString("classes", "") ?: ""
|
||||
|
||||
substViewModel.allSubst?.observe(this, Observer<List<Subst>> { substitutions ->
|
||||
substViewModel.allSubstitutions?.observe(this, Observer<List<Substitution>> { substitutions ->
|
||||
planCardList.clear()
|
||||
personalPlanEmptyEmoticon.visibility = View.GONE
|
||||
personalPlanEmptyText.visibility = View.GONE
|
||||
|
||||
@@ -15,15 +15,15 @@ import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import com.denizd.substitutionplan.*
|
||||
import com.denizd.substitutionplan.adapters.CardAdapter
|
||||
import com.denizd.substitutionplan.adapters.SubstitutionAdapter
|
||||
import com.denizd.substitutionplan.database.SubstViewModel
|
||||
import com.denizd.substitutionplan.models.Subst
|
||||
import com.denizd.substitutionplan.models.Substitution
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
internal open class PlanFragment : Fragment(R.layout.plan) {
|
||||
lateinit var recyclerView: RecyclerView
|
||||
lateinit var mAdapter: CardAdapter
|
||||
var planCardList = ArrayList<Subst>()
|
||||
lateinit var mAdapter: SubstitutionAdapter
|
||||
var planCardList = ArrayList<Substitution>()
|
||||
lateinit var substViewModel: SubstViewModel
|
||||
private lateinit var mContext: Context
|
||||
lateinit var prefs: SharedPreferences
|
||||
@@ -53,7 +53,7 @@ internal open class PlanFragment : Fragment(R.layout.plan) {
|
||||
recyclerView = view.findViewById(R.id.linearRecycler)
|
||||
recyclerView.hasFixedSize()
|
||||
recyclerView.layoutManager = GridLayoutManager(mContext, getGridColumnCount(resources.configuration))
|
||||
mAdapter = CardAdapter(planCardList, prefs)
|
||||
mAdapter = SubstitutionAdapter(planCardList, prefs)
|
||||
recyclerView.adapter = mAdapter
|
||||
|
||||
if (prefs.getInt("firstTimeOpening", 0) == 1) {
|
||||
|
||||
@@ -188,69 +188,6 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
when (v?.id) {
|
||||
R.id.chipHelpCourses -> createDialog(getString(R.string.courses_help_dialog_title), getString(R.string.courses_help_dialog_text))
|
||||
R.id.chipHelpClasses -> createDialog(getString(R.string.grade_help_dialog_title), getString(
|
||||
R.string.grade_help_dialog_text
|
||||
))
|
||||
R.id.btnCustomiseColours -> createColourDialog()
|
||||
R.id.btnNoNotif -> createDialog(mContext.getString(R.string.no_notifications_title), mContext.getString(R.string.no_notifications_dialog_text))
|
||||
R.id.btnCustomiseRingtone -> createRingtoneDialog()
|
||||
R.id.btnWebsite -> {
|
||||
try {
|
||||
customTabsIntent.launchUrl(mContext, Uri.parse("http://307.joomla.schule.bremen.de"))
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
makeToast(getString(R.string.chrome_not_found))
|
||||
}
|
||||
}
|
||||
R.id.btnLicences -> {
|
||||
createDialog(mContext.getString(R.string.licences_title), licences)
|
||||
}
|
||||
R.id.btnTerms -> {
|
||||
createDialog("Terms & Conditions", termsAndConditions)
|
||||
}
|
||||
R.id.btnPrivacyP -> {
|
||||
createDialog("Privacy Policy", privacyPolicy)
|
||||
}
|
||||
R.id.btnForceRefresh -> {
|
||||
DataFetcher(
|
||||
isPlan = true,
|
||||
isMenu = true,
|
||||
isJobService = false,
|
||||
context = mContext,
|
||||
application = activity!!.application,
|
||||
parentView = view!!.rootView,
|
||||
forced = true
|
||||
).execute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCheckedChanged(v: CompoundButton?, isChecked: Boolean) {
|
||||
if (v?.isPressed == true) {
|
||||
when (v.id) {
|
||||
R.id.switchDisableGreeting -> {
|
||||
prefs.edit().putBoolean("greeting", isChecked).apply()
|
||||
}
|
||||
R.id.switchNotifications -> {
|
||||
prefs.edit().putBoolean("notif", isChecked).apply()
|
||||
if (isChecked) {
|
||||
subscribeToTopic(Topic.ANDROID)
|
||||
} else {
|
||||
unsubscribeFromTopic(Topic.ANDROID)
|
||||
}
|
||||
}
|
||||
R.id.switchDefaultPlan -> {
|
||||
prefs.edit().putBoolean("defaultPersonalised", isChecked).apply()
|
||||
}
|
||||
R.id.switchAutoRefresh -> {
|
||||
prefs.edit().putBoolean("autoRefresh", isChecked).apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDialog(title: String, text: String) {
|
||||
val alertDialog = AlertDialog.Builder(mContext,
|
||||
R.style.AlertDialog
|
||||
@@ -262,7 +199,7 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
}
|
||||
|
||||
private fun createColourDialog() {
|
||||
val colourCustomiserBuilder = AlertDialog.Builder(mContext, R.style.AlertDialog)
|
||||
val colourCustomisationDialogBuilder = AlertDialog.Builder(mContext, R.style.AlertDialog)
|
||||
|
||||
val dialogView = View.inflate(mContext, R.layout.recycler_dialog, null)
|
||||
val titleText = dialogView.findViewById<TextView>(R.id.empty_textviewtitle)
|
||||
@@ -273,9 +210,9 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
layoutManager = GridLayoutManager(mContext, 1)
|
||||
adapter = ColourAdapter(getColourList(), this@SettingsFragment)
|
||||
}
|
||||
colourCustomiserBuilder.setView(dialogView)
|
||||
val colourCustomiserDialog = colourCustomiserBuilder.create()
|
||||
colourCustomiserDialog.show()
|
||||
colourCustomisationDialogBuilder.setView(dialogView)
|
||||
val colourCustomisationDialog = colourCustomisationDialogBuilder.create()
|
||||
colourCustomisationDialog.show()
|
||||
}
|
||||
|
||||
private fun getColourList(): ArrayList<Colour> {
|
||||
@@ -371,15 +308,6 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
return alarms
|
||||
}
|
||||
|
||||
override fun onRingtoneClick(position: Int, name: String, uri: String) {
|
||||
prefs.edit().apply {
|
||||
putString("ringtoneName", name)
|
||||
putString("ringtoneUri", uri)
|
||||
}.apply()
|
||||
setRingtoneText()
|
||||
ringtoneCustomiserDialog.dismiss()
|
||||
}
|
||||
|
||||
private fun setRingtoneText() {
|
||||
currentRingtone.text = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
mContext.getString(R.string.pick_ringtone_desc_o)
|
||||
@@ -393,36 +321,6 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(position: Int, title: String, titleNoLang: String) {
|
||||
val colourPickerBuilder = AlertDialog.Builder(mContext, R.style.AlertDialog)
|
||||
val pickerDialogView = View.inflate(mContext, R.layout.empty_dialog, null)
|
||||
val pickerTitleText = pickerDialogView.findViewById<TextView>(R.id.empty_textviewtitle)
|
||||
val pickerLayout = pickerDialogView.findViewById<LinearLayout>(R.id.empty_linearlayout)
|
||||
pickerTitleText.text = title
|
||||
|
||||
val picker = View.inflate(mContext, R.layout.bg_colour_picker, null)
|
||||
pickerLayout.addView(picker)
|
||||
colourPickerBuilder.setView(pickerDialogView)
|
||||
val colourPickerDialog: AlertDialog = colourPickerBuilder.create()
|
||||
|
||||
val buttons = intArrayOf(R.id.def, R.id.red, R.id.orange, R.id.yellow, R.id.green,
|
||||
R.id.teal, R.id.cyan, R.id.blue, R.id.purple, R.id.pink, R.id.brown, R.id.grey,
|
||||
R.id.pureWhite, R.id.salmon, R.id.tangerine, R.id.banana, R.id.flora, R.id.spindrift,
|
||||
R.id.sky, R.id.orchid, R.id.lavender, R.id.carnation, R.id.brown2, R.id.pureBlack)
|
||||
val colours = HelperFunctions.colourNames
|
||||
|
||||
for (i2 in buttons.indices) {
|
||||
picker.findViewById<MaterialButton>(buttons[i2]).setOnClickListener {
|
||||
prefs.edit().putString("card$titleNoLang", colours[i2]).apply()
|
||||
val recyclerViewState = colourRecycler.layoutManager?.onSaveInstanceState()
|
||||
colourRecycler.adapter = ColourAdapter(getColourList(), this)
|
||||
colourRecycler.layoutManager?.onRestoreInstanceState(recyclerViewState)
|
||||
colourPickerDialog.dismiss()
|
||||
}
|
||||
}
|
||||
colourPickerDialog.show()
|
||||
}
|
||||
|
||||
private fun debugMenu(): Boolean {
|
||||
val alertDialog = AlertDialog.Builder(mContext, R.style.AlertDialog)
|
||||
val dialogView = View.inflate(mContext, R.layout.edittext_dialog, null)
|
||||
@@ -437,16 +335,14 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
)
|
||||
dialogButton.setOnClickListener {
|
||||
when (dialogEditText.text.toString()) {
|
||||
"_DIAGNOSTICS" -> {
|
||||
"_STATISTICS" -> {
|
||||
val alertDialogDev = AlertDialog.Builder(mContext, R.style.AlertDialog)
|
||||
val devDialogView = View.inflate(mContext, R.layout.diagnostics_dialog, null)
|
||||
val devDialogText = devDialogView.findViewById<TextView>(R.id.dialogtext)
|
||||
val resetLaunchBtn = devDialogView.findViewById<Button>(R.id.btnResetLaunch)
|
||||
val resetNotificationBtn = devDialogView.findViewById<Button>(R.id.btnResetNotif)
|
||||
|
||||
devDialogView.findViewById<TextView>(R.id.textviewtitle).text = getString(
|
||||
R.string.diagnostics_dialog_title
|
||||
)
|
||||
devDialogView.findViewById<TextView>(R.id.textviewtitle).text = getString(R.string.statistics_dialog_title)
|
||||
devDialogText.text = getDiagnosticsText()
|
||||
|
||||
resetLaunchBtn.setOnClickListener {
|
||||
@@ -462,15 +358,19 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
alertDialogDev.setView(devDialogView)
|
||||
alertDialogDev.show()
|
||||
}
|
||||
"2018-04-20" -> {
|
||||
"2019-06-06" -> {
|
||||
try {
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.youtube.com/watch?v=Jc2xfYuLWgE")) // Freak
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.youtube.com/watch?v=Jc2xfYuLWgE")) // 'Freak'
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setPackage("com.google.android.youtube")
|
||||
startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
makeToast(getString(R.string.youtube_not_found))
|
||||
}
|
||||
}
|
||||
"_LOGIN" -> {
|
||||
prefs.edit().putBoolean("successful_login", false).apply()
|
||||
makeToast("Login flag cleared")
|
||||
}
|
||||
"_FIRSTTIME" -> {
|
||||
prefs.edit().putBoolean("firstTime", true).apply()
|
||||
makeToast("First time flag cleared")
|
||||
@@ -531,6 +431,115 @@ internal class SettingsFragment : Fragment(R.layout.content_settings), View.OnCl
|
||||
private fun subscribeToTopic(topic: Topic) = FirebaseMessaging.getInstance().subscribeToTopic(topic.tag)
|
||||
private fun unsubscribeFromTopic(topic: Topic) = FirebaseMessaging.getInstance().unsubscribeFromTopic(topic.tag)
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
when (v?.id) {
|
||||
R.id.chipHelpCourses -> createDialog(getString(R.string.courses_help_dialog_title), getString(R.string.courses_help_dialog_text))
|
||||
R.id.chipHelpClasses -> createDialog(getString(R.string.grade_help_dialog_title), getString(
|
||||
R.string.grade_help_dialog_text
|
||||
))
|
||||
R.id.btnCustomiseColours -> createColourDialog()
|
||||
R.id.btnNoNotif -> createDialog(mContext.getString(R.string.no_notifications_title), mContext.getString(R.string.no_notifications_dialog_text))
|
||||
R.id.btnCustomiseRingtone -> createRingtoneDialog()
|
||||
R.id.btnWebsite -> {
|
||||
try {
|
||||
customTabsIntent.launchUrl(mContext, Uri.parse("http://307.joomla.schule.bremen.de"))
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
makeToast(getString(R.string.chrome_not_found))
|
||||
}
|
||||
}
|
||||
R.id.btnLicences -> {
|
||||
createDialog(mContext.getString(R.string.licences_title), licences)
|
||||
}
|
||||
R.id.btnTerms -> {
|
||||
createDialog("Terms & Conditions", termsAndConditions)
|
||||
}
|
||||
R.id.btnPrivacyP -> {
|
||||
createDialog("Privacy Policy", privacyPolicy)
|
||||
}
|
||||
R.id.btnForceRefresh -> {
|
||||
DataFetcher(
|
||||
isPlan = true,
|
||||
isMenu = true,
|
||||
isJobService = false,
|
||||
context = mContext,
|
||||
application = activity!!.application,
|
||||
parentView = view!!.rootView,
|
||||
forced = true
|
||||
).execute()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRingtoneClick(position: Int, name: String, uri: String) {
|
||||
prefs.edit().apply {
|
||||
putString("ringtoneName", name)
|
||||
putString("ringtoneUri", uri)
|
||||
}.apply()
|
||||
setRingtoneText()
|
||||
ringtoneCustomiserDialog.dismiss()
|
||||
}
|
||||
|
||||
/**
|
||||
* OnClick method for colour customisation dialog
|
||||
* @param position the position of the clicked item
|
||||
* @param title the title of the clicked course
|
||||
* @param titleNoLang the language-independent string used for storing the course's colour in
|
||||
* Shared Preferences
|
||||
*/
|
||||
override fun onClick(position: Int, title: String, titleNoLang: String) {
|
||||
val colourPickerBuilder = AlertDialog.Builder(mContext, R.style.AlertDialog)
|
||||
val pickerDialogView = View.inflate(mContext, R.layout.empty_dialog, null)
|
||||
val pickerTitleText = pickerDialogView.findViewById<TextView>(R.id.empty_textviewtitle)
|
||||
val pickerLayout = pickerDialogView.findViewById<LinearLayout>(R.id.empty_linearlayout)
|
||||
pickerTitleText.text = title
|
||||
|
||||
val picker = View.inflate(mContext, R.layout.bg_colour_picker, null)
|
||||
pickerLayout.addView(picker)
|
||||
colourPickerBuilder.setView(pickerDialogView)
|
||||
val colourPickerDialog: AlertDialog = colourPickerBuilder.create()
|
||||
|
||||
val buttons = intArrayOf(R.id.def, R.id.red, R.id.orange, R.id.yellow, R.id.green,
|
||||
R.id.teal, R.id.cyan, R.id.blue, R.id.purple, R.id.pink, R.id.brown, R.id.grey,
|
||||
R.id.pureWhite, R.id.salmon, R.id.tangerine, R.id.banana, R.id.flora, R.id.spindrift,
|
||||
R.id.sky, R.id.orchid, R.id.lavender, R.id.carnation, R.id.brown2, R.id.pureBlack)
|
||||
val colours = HelperFunctions.colourNames
|
||||
|
||||
for (i2 in buttons.indices) {
|
||||
picker.findViewById<MaterialButton>(buttons[i2]).setOnClickListener {
|
||||
prefs.edit().putString("card$titleNoLang", colours[i2]).apply()
|
||||
val recyclerViewState = colourRecycler.layoutManager?.onSaveInstanceState()
|
||||
colourRecycler.adapter = ColourAdapter(getColourList(), this)
|
||||
colourRecycler.layoutManager?.onRestoreInstanceState(recyclerViewState)
|
||||
colourPickerDialog.dismiss()
|
||||
}
|
||||
}
|
||||
colourPickerDialog.show()
|
||||
}
|
||||
|
||||
override fun onCheckedChanged(v: CompoundButton?, isChecked: Boolean) {
|
||||
if (v?.isPressed == true) {
|
||||
when (v.id) {
|
||||
R.id.switchDisableGreeting -> {
|
||||
prefs.edit().putBoolean("greeting", isChecked).apply()
|
||||
}
|
||||
R.id.switchNotifications -> {
|
||||
prefs.edit().putBoolean("notif", isChecked).apply()
|
||||
if (isChecked) {
|
||||
subscribeToTopic(Topic.ANDROID)
|
||||
} else {
|
||||
unsubscribeFromTopic(Topic.ANDROID)
|
||||
}
|
||||
}
|
||||
R.id.switchDefaultPlan -> {
|
||||
prefs.edit().putBoolean("defaultPersonalised", isChecked).apply()
|
||||
}
|
||||
R.id.switchAutoRefresh -> {
|
||||
prefs.edit().putBoolean("autoRefresh", isChecked).apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val licences = "Libraries:" +
|
||||
"\n • jsoup HTML parser © 2009-2018 Jonathan Hedley, licensed under the open source MIT Licence" +
|
||||
"\n\nFont:" +
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "subst_table")
|
||||
internal data class Subst(
|
||||
internal data class Substitution(
|
||||
val group: String,
|
||||
val date: String,
|
||||
val time: String,
|
||||
@@ -106,7 +106,7 @@
|
||||
android:id="@+id/temporary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="subst plan"
|
||||
android:text="substitution plan"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
|
||||
@@ -14,20 +14,14 @@
|
||||
android:layout_marginBottom="3dp"
|
||||
app:cardElevation="2dp">
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:id="@+id/cardInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cardInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/colorText"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/colorText"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"/>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
@@ -33,7 +33,7 @@
|
||||
<string name="setup_successful">Viel Spaß!</string>
|
||||
<string name="greeting_title">Aktiviere Begrüßungen</string>
|
||||
<string name="greeting_desc">Falls du möchtest, dass ich nett bin :)</string>
|
||||
<string name="licences_title">Lizenzen und Mitwirkende</string>
|
||||
<string name="licences_title">Lizenzen & Mitwirkende</string>
|
||||
<string name="licences_desc">Was die App ausmacht (Englisch)</string>
|
||||
<string name="version">Versionsnummer</string>
|
||||
<string name="privacy_policy_title">Datenschutzerklärung</string>
|
||||
@@ -52,7 +52,7 @@
|
||||
<string name="apply">Anwenden</string>
|
||||
<string name="invalid_code">Ungültiger Code</string>
|
||||
<string name="experimental_menu_dialog_title">Experimentalmenü</string>
|
||||
<string name="diagnostics_dialog_title">Diagnosemenü</string>
|
||||
<string name="statistics_dialog_title">Statistikmenü</string>
|
||||
<string name="enable_course_notifications">Kursbenachrichtigungen aktivieren</string>
|
||||
<string name="no_personal_substitutions">Kein Entfall für dich</string>
|
||||
<string name="customise_colours_title">Benutzerdefinierte Farben</string>
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
<string name="personal">Personal</string>
|
||||
<string name="settings">Settings</string>
|
||||
|
||||
<!-- for Settings fragment -->
|
||||
<string name="enable_course_notifications_title">Enable course notifications</string>
|
||||
<string name="enable_course_notifications_desc">This does not affect broadcasts</string>
|
||||
|
||||
@@ -39,7 +38,7 @@
|
||||
<string name="greeting_title">Enable greeting</string>
|
||||
<string name="greeting_desc">If you want me to be nice :)</string>
|
||||
|
||||
<string name="licences_title">Licences and contributors</string>
|
||||
<string name="licences_title">Licences & contributors</string>
|
||||
<string name="licences_desc">What went into making this app</string>
|
||||
<string name="version">Version Number</string>
|
||||
|
||||
@@ -59,7 +58,7 @@
|
||||
<string name="courses_help_dialog_title">How to enter your courses</string>
|
||||
<string name="courses_help_dialog_text">You need to enter the course abbreviation for every course you want in your personal plan and want to be notified about. You can find them on your time table.\n\nHere\'s a few examples:\n\nMathematics in 5th grade (juniors) would be MAT.\n\nAdvanced English in E-Phase (seniors) for the English profile may be ENP1.\n\nBasic Biology in Q1 could be bio1.\n\nIn most cases, entering courses while in junior phase is redundant.\nSeparate multiple courses by spaces, commas are optional.\nCapitalisation is required.</string>
|
||||
<string name="experimental_menu_dialog_title">Experimental Menu</string>
|
||||
<string name="diagnostics_dialog_title">Diagnostics Menu</string>
|
||||
<string name="statistics_dialog_title">Statistics Menu</string>
|
||||
<string name="experimental_menu_dialog_text">This menu is currently intended for testing only. Additional features may be added in the future. Feel free to try arbitrary codes.</string>
|
||||
<string name="apply">Apply</string>
|
||||
<string name="invalid_code">Invalid code</string>
|
||||
|
||||
Reference in New Issue
Block a user