Archived
Info table now recognises line breaks from the website and shows them in the dialog; implemented debug dialog that presents the most recent exception caused in DataFetcher.kt
This commit is contained in:
+2
-2
@@ -10,8 +10,8 @@ android {
|
|||||||
applicationId "com.denizd.substitutionplan"
|
applicationId "com.denizd.substitutionplan"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
versionCode 41
|
versionCode 42
|
||||||
versionName "2.3.3"
|
versionName "2.3.4"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
|||||||
@@ -86,10 +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
|
// 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
|
// 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)
|
||||||
@@ -100,7 +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)
|
// 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)
|
||||||
@@ -113,7 +113,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Displays the date and time of the last refresh of the substitution plan in a snack bar
|
// 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()
|
||||||
@@ -136,12 +136,12 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
""
|
""
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Legacy function
|
// 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()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Launch the user-specified fragment (general or personal plan)
|
// Launch the user-specified fragment (general or personal plan)
|
||||||
val defaultFragment = if (prefs.getBoolean("defaultPersonalised", false)) {
|
val defaultFragment = if (prefs.getBoolean("defaultPersonalised", false)) {
|
||||||
bottomNav.selectedItemId = R.id.personal
|
bottomNav.selectedItemId = R.id.personal
|
||||||
toolbarTxt.text = personalPlanTitle()
|
toolbarTxt.text = personalPlanTitle()
|
||||||
@@ -153,7 +153,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
}
|
}
|
||||||
loadFragment(defaultFragment)
|
loadFragment(defaultFragment)
|
||||||
|
|
||||||
/// Opens the corresponding fragment or the info dialog
|
// Opens the corresponding fragment or the info dialog
|
||||||
bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->
|
bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->
|
||||||
val fragment = when (item.itemId) {
|
val fragment = when (item.itemId) {
|
||||||
R.id.plan -> {
|
R.id.plan -> {
|
||||||
@@ -185,7 +185,7 @@ internal class Main : AppCompatActivity(R.layout.app_bar_main) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Scrolls to the top of any currently displayed fragment
|
// 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.menu -> {
|
R.id.plan, R.id.personal, R.id.menu -> {
|
||||||
@@ -255,7 +255,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)
|
||||||
|
|||||||
@@ -7,9 +7,12 @@ import android.media.RingtoneManager
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.AsyncTask
|
import android.os.AsyncTask
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
@@ -73,6 +76,8 @@ internal class DataFetcher(
|
|||||||
if (prefs.getBoolean("testUrls", false)) {
|
if (prefs.getBoolean("testUrls", false)) {
|
||||||
substUrl = "https://djd4rkn355.github.io/subst_test.html"
|
substUrl = "https://djd4rkn355.github.io/subst_test.html"
|
||||||
foodUrl = "https://djd4rkn355.github.io/food_test.html"
|
foodUrl = "https://djd4rkn355.github.io/food_test.html"
|
||||||
|
} else if ((prefs.getString("custom_test_url", "") ?: "").isNotEmpty()) {
|
||||||
|
substUrl = "https://djd4rkn355.github.io/${prefs.getString("custom_test_url", "")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forceRefresh) {
|
if (forceRefresh) {
|
||||||
@@ -99,13 +104,13 @@ internal class DataFetcher(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
|
||||||
mView.get()?.let { v: View ->
|
mView.get()?.let { v: View ->
|
||||||
val snackBarView = v.findViewById<View>(R.id.coordination)
|
val snackBarView = v.findViewById<View>(R.id.coordination)
|
||||||
Snackbar.make(snackBarView, mContext.get()?.getString(R.string.no_internet_connection) ?: "", Snackbar.LENGTH_LONG).setBackgroundTint(ContextCompat.getColor(mContext.get()!!,
|
Snackbar.make(snackBarView, mContext.get()?.getString(R.string.no_internet_connection) ?: "", Snackbar.LENGTH_LONG).setBackgroundTint(ContextCompat.getColor(mContext.get()!!,
|
||||||
R.color.colorError
|
R.color.colorError
|
||||||
)).show()
|
)).show()
|
||||||
}
|
}
|
||||||
|
prefs.edit().putString("debug_recent_exception", Log.getStackTraceString(e)).apply()
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -157,7 +162,7 @@ internal class DataFetcher(
|
|||||||
val substRepo = SubstRepository(mApplication)
|
val substRepo = SubstRepository(mApplication)
|
||||||
if (currentTime != prefs.getString("timeNew", "")) {
|
if (currentTime != prefs.getString("timeNew", "")) {
|
||||||
val rows = doc.select("tr")
|
val rows = doc.select("tr")
|
||||||
val paragraphs = doc.select("p")
|
val paragraphs = doc.select("h6")
|
||||||
val substArray = ArrayList<Substitution>()
|
val substArray = ArrayList<Substitution>()
|
||||||
|
|
||||||
val coursePreference = prefs.getString("courses", "") ?: ""
|
val coursePreference = prefs.getString("courses", "") ?: ""
|
||||||
@@ -165,9 +170,9 @@ internal class DataFetcher(
|
|||||||
|
|
||||||
for (i in 0 until paragraphs.size) {
|
for (i in 0 until paragraphs.size) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
informational = paragraphs[i].text()
|
informational = formatElement(paragraphs[i].html())
|
||||||
} else {
|
} else {
|
||||||
informational += "\n\n" + paragraphs[i].text()
|
informational += "\n\n" + formatElement(paragraphs[i].html())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
edit.putString("informational", informational).apply()
|
edit.putString("informational", informational).apply()
|
||||||
@@ -189,7 +194,7 @@ internal class DataFetcher(
|
|||||||
additional = cols[5].text(),
|
additional = cols[5].text(),
|
||||||
teacher = cols[6].text(),
|
teacher = cols[6].text(),
|
||||||
type = cols[7].text(),
|
type = cols[7].text(),
|
||||||
priority = HelperFunctions.assignRanking(group, date.substring(0, 3) == "psa"),
|
priority = HelperFunctions.assignRanking(group, (date.length > 2 && date.substring(0, 3) == "psa")),
|
||||||
date_priority = HelperFunctions.assignDatePriority(date),
|
date_priority = HelperFunctions.assignDatePriority(date),
|
||||||
website_priority = websitePriority
|
website_priority = websitePriority
|
||||||
)
|
)
|
||||||
@@ -268,4 +273,9 @@ internal class DataFetcher(
|
|||||||
manager.notify(1, notification.build())
|
manager.notify(1, notification.build())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun formatElement(element: String): String {
|
||||||
|
return element
|
||||||
|
.replace("<br>", "\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -414,68 +414,83 @@ internal class SettingsFragment : Fragment(), View.OnClickListener, View.OnLongC
|
|||||||
R.string.experimental_menu_dialog_text
|
R.string.experimental_menu_dialog_text
|
||||||
)
|
)
|
||||||
dialogButton.setOnClickListener {
|
dialogButton.setOnClickListener {
|
||||||
when (dialogEditText.text.toString()) {
|
with (dialogEditText.text.toString()) {
|
||||||
"_statistics" -> {
|
when {
|
||||||
val alertDialogDev = AlertDialog.Builder(mContext)
|
this == "_statistics" -> {
|
||||||
val devDialogView = View.inflate(mContext, R.layout.diagnostics_dialog, null)
|
val alertDialogDev = AlertDialog.Builder(mContext)
|
||||||
val devDialogText = devDialogView.findViewById<TextView>(R.id.dialogtext)
|
val devDialogView = View.inflate(mContext, R.layout.diagnostics_dialog, null)
|
||||||
val resetLaunchBtn = devDialogView.findViewById<MaterialButton>(R.id.btnResetLaunch)
|
val devDialogText = devDialogView.findViewById<TextView>(R.id.dialogtext)
|
||||||
val resetNotificationBtn = devDialogView.findViewById<MaterialButton>(R.id.btnResetNotif)
|
val resetLaunchBtn = devDialogView.findViewById<MaterialButton>(R.id.btnResetLaunch)
|
||||||
|
val resetNotificationBtn = devDialogView.findViewById<MaterialButton>(R.id.btnResetNotif)
|
||||||
|
|
||||||
devDialogView.findViewById<TextView>(R.id.textviewtitle).text = getString(R.string.statistics_dialog_title)
|
devDialogView.findViewById<TextView>(R.id.textviewtitle).text = getString(R.string.statistics_dialog_title)
|
||||||
devDialogText.text = getDiagnosticsText()
|
|
||||||
|
|
||||||
resetLaunchBtn.setOnClickListener {
|
|
||||||
prefs.edit().putInt("launchDev", 0).apply()
|
|
||||||
devDialogText.text = getDiagnosticsText()
|
devDialogText.text = getDiagnosticsText()
|
||||||
}
|
|
||||||
|
|
||||||
resetNotificationBtn.setOnClickListener {
|
resetLaunchBtn.setOnClickListener {
|
||||||
prefs.edit().putInt("pingFB", 0).apply()
|
prefs.edit().putInt("launchDev", 0).apply()
|
||||||
devDialogText.text = getDiagnosticsText()
|
devDialogText.text = getDiagnosticsText()
|
||||||
}
|
}
|
||||||
|
|
||||||
alertDialogDev.setView(devDialogView)
|
resetNotificationBtn.setOnClickListener {
|
||||||
alertDialogDev.show()
|
prefs.edit().putInt("pingFB", 0).apply()
|
||||||
}
|
devDialogText.text = getDiagnosticsText()
|
||||||
"_login" -> {
|
}
|
||||||
prefs.edit().putBoolean("successful_login", false).apply()
|
|
||||||
makeToast("Login flag cleared")
|
alertDialogDev.setView(devDialogView)
|
||||||
}
|
alertDialogDev.show()
|
||||||
"_firsttime" -> {
|
|
||||||
prefs.edit().putBoolean("firstTime", true).apply()
|
|
||||||
makeToast("First time flag cleared")
|
|
||||||
}
|
|
||||||
"_testurls" -> {
|
|
||||||
val currentTest = !prefs.getBoolean("testUrls", false)
|
|
||||||
prefs.edit().putBoolean("testUrls", currentTest).apply()
|
|
||||||
makeToast("Test URLs set to $currentTest")
|
|
||||||
}
|
|
||||||
"_devchannel" -> {
|
|
||||||
val subbed = if (prefs.getBoolean("subscribedToFBDebugChannel", false)) {
|
|
||||||
unsubscribeFromTopic(Topic.DEVELOPMENT)
|
|
||||||
"Unsubscribed from"
|
|
||||||
} else {
|
|
||||||
subscribeToTopic(Topic.DEVELOPMENT)
|
|
||||||
"Subscribed to"
|
|
||||||
}
|
}
|
||||||
prefs.edit().putBoolean("subscribedToFBDebugChannel", !prefs.getBoolean("subscribedToFBDebugChannel", false)).apply()
|
this == "_login" -> {
|
||||||
makeToast("$subbed Firebase development channel")
|
prefs.edit().putBoolean("successful_login", false).apply()
|
||||||
}
|
makeToast("Login flag cleared")
|
||||||
"_ioschannel" -> {
|
|
||||||
val subbed = if (prefs.getBoolean("subscribedToiOSChannel", false)) {
|
|
||||||
unsubscribeFromTopic(Topic.IOS)
|
|
||||||
"Unsubscribed from"
|
|
||||||
} else {
|
|
||||||
subscribeToTopic(Topic.IOS)
|
|
||||||
"Subscribed to"
|
|
||||||
}
|
}
|
||||||
prefs.edit().putBoolean("subscribedToiOSChannel", !prefs.getBoolean("subscribedToiOSChannel", false)).apply()
|
this == "_firsttime" -> {
|
||||||
makeToast("$subbed iOS channel")
|
prefs.edit().putBoolean("firstTime", true).apply()
|
||||||
|
makeToast("First time flag cleared")
|
||||||
|
}
|
||||||
|
this == "_testurls" -> {
|
||||||
|
val currentTest = !prefs.getBoolean("testUrls", false)
|
||||||
|
prefs.edit().putBoolean("testUrls", currentTest)
|
||||||
|
.putString("custom_test_url", "").apply()
|
||||||
|
makeToast("Cleared custom URL")
|
||||||
|
makeToast("Test URLs set to $currentTest")
|
||||||
|
}
|
||||||
|
length > 4 && substring(0, 4) == "_url" -> {
|
||||||
|
prefs.edit().putString("custom_test_url", substring(4, length)).apply()
|
||||||
|
makeToast("Successfully entered custom URL")
|
||||||
|
}
|
||||||
|
length == 4 && substring(0, 4) == "_url" -> {
|
||||||
|
prefs.edit().putString("custom_test_url", "").apply()
|
||||||
|
makeToast("Cleared custom URL")
|
||||||
|
}
|
||||||
|
this == "_devchannel" -> {
|
||||||
|
val subbed = if (prefs.getBoolean("subscribedToFBDebugChannel", false)) {
|
||||||
|
unsubscribeFromTopic(Topic.DEVELOPMENT)
|
||||||
|
"Unsubscribed from"
|
||||||
|
} else {
|
||||||
|
subscribeToTopic(Topic.DEVELOPMENT)
|
||||||
|
"Subscribed to"
|
||||||
|
}
|
||||||
|
prefs.edit().putBoolean("subscribedToFBDebugChannel", !prefs.getBoolean("subscribedToFBDebugChannel", false)).apply()
|
||||||
|
makeToast("$subbed Firebase development channel")
|
||||||
|
}
|
||||||
|
this == "_ioschannel" -> {
|
||||||
|
val subbed = if (prefs.getBoolean("subscribedToiOSChannel", false)) {
|
||||||
|
unsubscribeFromTopic(Topic.IOS)
|
||||||
|
"Unsubscribed from"
|
||||||
|
} else {
|
||||||
|
subscribeToTopic(Topic.IOS)
|
||||||
|
"Subscribed to"
|
||||||
|
}
|
||||||
|
prefs.edit().putBoolean("subscribedToiOSChannel", !prefs.getBoolean("subscribedToiOSChannel", false)).apply()
|
||||||
|
makeToast("$subbed iOS channel")
|
||||||
|
}
|
||||||
|
this == "_viewstacktrace" -> {
|
||||||
|
createDialog("Debug Stack Trace", prefs.getString("debug_recent_exception", "") ?: "")
|
||||||
|
}
|
||||||
|
this == "_write" -> HelperFunctions.writePrefsToXml(prefs, mContext, activity!!)
|
||||||
|
this == "_read" -> HelperFunctions.readPrefsFromXml(prefs, mContext, activity!!)
|
||||||
|
else -> makeToast(getString(R.string.invalid_code))
|
||||||
}
|
}
|
||||||
"_write" -> HelperFunctions.writePrefsToXml(prefs, mContext, activity!!)
|
|
||||||
"_read" -> HelperFunctions.readPrefsFromXml(prefs, mContext, activity!!)
|
|
||||||
else -> makeToast(getString(R.string.invalid_code))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alertDialog.setView(dialogView)
|
alertDialog.setView(dialogView)
|
||||||
|
|||||||
@@ -33,4 +33,6 @@
|
|||||||
<item name="dialogCornerRadius">12dp</item>
|
<item name="dialogCornerRadius">12dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme0.LegacyAlert" parent="Theme.AppCompat.Dialog.Alert"/>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user