Added a button to direct the user to download their schedule from Stud.IP if they have not done any modifications to their schedule; fixed a bug that would show opening hours of the currently selected canteen or crash the app whenever the info button in FetcherActivity.kt was clicked

This commit is contained in:
denizk0461
2023-05-11 21:31:41 +02:00
parent 91ffcf0637
commit a61f072055
12 changed files with 85 additions and 6 deletions
+2 -2
View File
@@ -12,8 +12,8 @@ android {
applicationId "com.denizk0461.weserplaner" applicationId "com.denizk0461.weserplaner"
minSdk 24 minSdk 24
targetSdk 33 targetSdk 33
versionCode 4 versionCode 5
versionName "1.0.1" versionName "1.0.2"
resourceConfigurations += ["en", "de"] resourceConfigurations += ["en", "de"]
@@ -12,6 +12,7 @@ import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.data.showErrorSnackBar import com.denizk0461.weserplaner.data.showErrorSnackBar
import com.denizk0461.weserplaner.data.showToast import com.denizk0461.weserplaner.data.showToast
import com.denizk0461.weserplaner.databinding.ActivityFetcherBinding import com.denizk0461.weserplaner.databinding.ActivityFetcherBinding
import com.denizk0461.weserplaner.model.TextSheetContentId
import com.denizk0461.weserplaner.sheet.TextSheet import com.denizk0461.weserplaner.sheet.TextSheet
import com.denizk0461.weserplaner.viewmodel.FetcherViewModel import com.denizk0461.weserplaner.viewmodel.FetcherViewModel
import java.io.IOException import java.io.IOException
@@ -98,6 +99,7 @@ class FetcherActivity : FragmentActivity() {
bundle.putString("header", getString(R.string.fetch_bar_help_sheet_title)) bundle.putString("header", getString(R.string.fetch_bar_help_sheet_title))
bundle.putString("content", getString(R.string.fetch_bar_help_sheet_content)) bundle.putString("content", getString(R.string.fetch_bar_help_sheet_content))
bundle.putBoolean("isCancellable", true) bundle.putBoolean("isCancellable", true)
bundle.putInt("contentId", TextSheetContentId.PASS_RAW_STRING)
sheet.arguments = bundle sheet.arguments = bundle
}.show(supportFragmentManager, TextSheet::class.java.simpleName) }.show(supportFragmentManager, TextSheet::class.java.simpleName)
true true
@@ -112,8 +114,6 @@ class FetcherActivity : FragmentActivity() {
*/ */
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.webview
binding.fab.setOnClickListener { binding.fab.setOnClickListener {
if (binding.webview.url?.contains( if (binding.webview.url?.contains(
@@ -2,6 +2,7 @@ package com.denizk0461.weserplaner.data
import android.app.Application import android.app.Application
import com.denizk0461.weserplaner.db.AppRepository import com.denizk0461.weserplaner.db.AppRepository
import com.denizk0461.weserplaner.model.SettingsPreferences
import com.denizk0461.weserplaner.model.StudIPEvent import com.denizk0461.weserplaner.model.StudIPEvent
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
@@ -109,6 +110,9 @@ class StudIPParser(application: Application) {
// After fetching has finished, save the list of new items into persistent storage // After fetching has finished, save the list of new items into persistent storage
repo.insertEvents(newEvents) repo.insertEvents(newEvents)
// Set that the user has modified their schedule
repo.setPreference(SettingsPreferences.HAS_MODIFIED_SCHEDULE, true)
// Return the count of elements that were not able to be fetched // Return the count of elements that were not able to be fetched
return elementsNotFetched return elementsNotFetched
} }
@@ -1,11 +1,14 @@
package com.denizk0461.weserplaner.fragment package com.denizk0461.weserplaner.fragment
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.denizk0461.weserplaner.R import com.denizk0461.weserplaner.R
import com.denizk0461.weserplaner.activity.FetcherActivity
import com.denizk0461.weserplaner.adapter.StudIPEventPageAdapter import com.denizk0461.weserplaner.adapter.StudIPEventPageAdapter
import com.denizk0461.weserplaner.databinding.FragmentEventBinding import com.denizk0461.weserplaner.databinding.FragmentEventBinding
import com.denizk0461.weserplaner.sheet.ScheduleUpdateSheet import com.denizk0461.weserplaner.sheet.ScheduleUpdateSheet
@@ -79,6 +82,19 @@ class EventFragment : AppFragment() {
) )
} }
// Launch the Stud.IP fetcher on click of the fetch button
binding.buttonFetchSchedule.setOnClickListener {
startActivity(Intent(context, FetcherActivity::class.java))
}
/*
* Set the fetch button to be visible if the user has not previously modified their schedule
* in any way (added an event manually or used the Stud.IP fetcher).
*/
if (!viewModel.preferenceHasModifiedSchedule) {
binding.buttonFetchSchedule.visibility = View.VISIBLE
}
// Set up button for adding a new event // Set up button for adding a new event
binding.fabAddEvent.setOnClickListener { binding.fabAddEvent.setOnClickListener {
/* /*
@@ -90,6 +106,16 @@ class EventFragment : AppFragment() {
val bundle = Bundle() val bundle = Bundle()
bundle.putBoolean("isEditing", false) bundle.putBoolean("isEditing", false)
sheet.arguments = bundle sheet.arguments = bundle
/*
* Receive fragment result to update the button visibility.
* TODO doesn't work after configuration change (change into or out of multi
* window)
*/
setFragmentResultListener("eventAdded") { _, _ ->
// Hide the fetch button
binding.buttonFetchSchedule.visibility = View.GONE
}
} }
) )
} }
@@ -63,5 +63,10 @@ enum class SettingsPreferences(val key: String) {
* Whether the user has opened the canteen fragment before. * Whether the user has opened the canteen fragment before.
*/ */
HAS_OPENED_CANTEEN("has_opened_canteen"), HAS_OPENED_CANTEEN("has_opened_canteen"),
/**
* Whether the user has done something to modify their schedule.
*/
HAS_MODIFIED_SCHEDULE("has_modified_schedule"),
; ;
} }
@@ -5,6 +5,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.transition.TransitionManager import androidx.transition.TransitionManager
import com.denizk0461.weserplaner.R import com.denizk0461.weserplaner.R
@@ -93,7 +94,8 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update) {
dismiss() dismiss()
} else { } else {
// Update the text to show the user that they clicked the button once // Update the text to show the user that they clicked the button once
TransitionManager.beginDelayedTransition(binding.buttonContainer as ViewGroup) TransitionManager
.beginDelayedTransition(binding.buttonContainer as ViewGroup)
binding.buttonDelete.text = binding.buttonDelete.text =
getString(R.string.sheet_schedule_update_delete_confirm) getString(R.string.sheet_schedule_update_delete_confirm)
hasClickedDelete = true hasClickedDelete = true
@@ -186,6 +188,13 @@ class ScheduleUpdateSheet : AppSheet(R.layout.sheet_schedule_update) {
colour = colour, colour = colour,
) )
) )
/*
* Send an empty bundle to tell the parent fragment that it should update its view
* according to the changes made here.
*/
parentFragment?.setFragmentResult("eventAdded", Bundle())
// Dismiss the sheet upon update // Dismiss the sheet upon update
dismiss() dismiss()
} }
@@ -19,10 +19,19 @@ class EventViewModel(app: Application) : AppViewModel(app) {
defaultValue = true, defaultValue = true,
) )
/**
* Determines whether the user is launching the app for the first time.
*/
var preferenceFirstLaunch: Boolean var preferenceFirstLaunch: Boolean
get() = repo.getBooleanPreference( get() = repo.getBooleanPreference(
SettingsPreferences.FIRST_LAUNCH, SettingsPreferences.FIRST_LAUNCH,
defaultValue = true, defaultValue = true,
) )
set(value) { repo.setPreference(SettingsPreferences.FIRST_LAUNCH, value) } set(value) { repo.setPreference(SettingsPreferences.FIRST_LAUNCH, value) }
/**
* Determines whether the user has done something to modify their schedule.
*/
val preferenceHasModifiedSchedule: Boolean
get() = repo.getBooleanPreference(SettingsPreferences.HAS_MODIFIED_SCHEDULE)
} }
@@ -1,6 +1,7 @@
package com.denizk0461.weserplaner.viewmodel package com.denizk0461.weserplaner.viewmodel
import android.app.Application import android.app.Application
import com.denizk0461.weserplaner.model.SettingsPreferences
import com.denizk0461.weserplaner.model.StudIPEvent import com.denizk0461.weserplaner.model.StudIPEvent
class ScheduleUpdateViewModel(application: Application) : AppViewModel(application) { class ScheduleUpdateViewModel(application: Application) : AppViewModel(application) {
@@ -10,7 +11,13 @@ class ScheduleUpdateViewModel(application: Application) : AppViewModel(applicati
* *
* @param event the event to save * @param event the event to save
*/ */
fun insert(event: StudIPEvent) { doAsync { repo.insert(event) } } fun insert(event: StudIPEvent) {
// Inser the event
doAsync { repo.insert(event) }
// Set that the user has modified their schedule
repo.setPreference(SettingsPreferences.HAS_MODIFIED_SCHEDULE, true)
}
/** /**
* Updates a schedule element. * Updates a schedule element.
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM17,13l-5,5 -5,-5h3V9h4v4h3z"/>
</vector>
@@ -39,6 +39,16 @@
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/> app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.ElevatedButton"
android:id="@+id/button_fetch_schedule"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:icon="@drawable/cloud_download"
android:text="@string/event_empty_fetch_button"
android:visibility="gone"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_add_event" android:id="@+id/fab_add_event"
android:layout_width="wrap_content" android:layout_width="wrap_content"
+2
View File
@@ -24,6 +24,8 @@
<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="event_empty_fetch_button">Lade Deinen Stundenplan von Stud.IP herunter</string>
<!-- plurals string resource cannot be used here because Android doesn't treat 0 differently from 2 --> <!-- plurals string resource cannot be used here because Android doesn't treat 0 differently from 2 -->
<string name="toast_fetch_finished_zero">Dein Stundenplan wurde aktualisiert!</string> <string name="toast_fetch_finished_zero">Dein Stundenplan wurde aktualisiert!</string>
<string name="toast_fetch_finished_one">Dein Stundenplan wurde aktualisiert, doch eine Veranstaltung konnte nicht heruntergeladen werden.</string> <string name="toast_fetch_finished_one">Dein Stundenplan wurde aktualisiert, doch eine Veranstaltung konnte nicht heruntergeladen werden.</string>
+2
View File
@@ -25,6 +25,8 @@
<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="event_empty_fetch_button">Download your schedule from Stud.IP</string>
<!-- plurals resource cannot be used here; view German translation for details --> <!-- plurals resource cannot be used here; view German translation for details -->
<string name="toast_fetch_finished_zero">Your schedule has been refreshed!</string> <string name="toast_fetch_finished_zero">Your schedule has been refreshed!</string>
<string name="toast_fetch_finished_one">Your schedule has been refreshed, but one item could not be saved.</string> <string name="toast_fetch_finished_one">Your schedule has been refreshed, but one item could not be saved.</string>