Started implementation of event update sheet

This commit is contained in:
denizk0461
2023-04-24 15:43:42 +02:00
parent a53232a814
commit 9b6e267cb0
24 changed files with 410 additions and 53 deletions
@@ -3,6 +3,7 @@ package com.denizk0461.studip.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.denizk0461.studip.data.parseToMinutes
import com.denizk0461.studip.model.StudIPEvent
import com.denizk0461.studip.databinding.ItemEventBinding
import java.util.*
@@ -150,17 +151,6 @@ class StudIPEventItemAdapter(
else -> Calendar.MONDAY
}
/**
* Converts a time stamp string to its numeric value in minutes.
* Example: 13:20. (20 minutes) + (13 hours * 60 minutes) = 800 minutes.
*
* @return minute value of the string
*/
private fun String.parseToMinutes(): Int {
val parts = split(":")
return (parts[0].toInt() * 60) + parts[1].toInt()
}
/**
* Interface used to evaluate clicks and long presses on a given item.
*/
@@ -3,6 +3,18 @@ package com.denizk0461.studip.data
/**
* Miscellaneous functions and variables that don't belong into any specific class.
*/
/**
* Converts a time stamp string to its numeric value in minutes.
* Example: 13:20. (20 minutes) + (13 hours * 60 minutes) = 800 minutes.
*
* @return minute value of the string
*/
fun String.parseToMinutes(): Int {
val parts = split(":")
return (parts[0].toInt() * 60) + parts[1].toInt()
}
object Misc {
// private val timeslotAcademicQuarter = mapOf(
@@ -76,6 +76,9 @@ class StudIPParser {
// Retrieve the time slot and split it into start and end time stamps
val timeSlot = entryInfo[0].split(" - ")
// Time the event starts at
val eventStart = timeSlot[0]
// Construct the newly scraped Stud.IP event
val event = StudIPEvent(
id = id,
@@ -83,8 +86,9 @@ class StudIPParser {
lecturer = parsedLecturers,
room = entryInfo[1],
day = index,
timeslotStart = timeSlot[0],
timeslotStart = eventStart,
timeslotEnd = timeSlot[1],
timeslotId = eventStart.parseToMinutes(),
)
// Add the new element to the temporary list
@@ -1,9 +1,7 @@
package com.denizk0461.studip.db
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.Query
import androidx.room.*
import com.denizk0461.studip.model.*
/**
@@ -16,13 +14,29 @@ interface AppDAO {
/* --- Stud.IP schedule events --- */
/**
* Retrieves all Stud.IP events.
* Retrieves all Stud.IP events, ordered by their timeslots, then their IDs.
*
* @return all Stud.IP events exposed through a LiveData object
*/
@get:Query("SELECT * FROM events ORDER BY id")
@get:Query("SELECT * FROM events ORDER BY timeslotId, id")
val allEvents: LiveData<List<StudIPEvent>>
/**
* Updates a given Stud.IP element.
*
* @param event object to be updated
*/
@Update
fun update(event: StudIPEvent)
/**
* Updates a given Stud.IP element.
*
* @param event object to be updated
*/
@Delete
fun delete(event: StudIPEvent)
/**
* Inserts a Stud.IP event into the database.
*
@@ -17,7 +17,7 @@ import com.denizk0461.studip.model.*
OfferCategory::class,
OfferItem::class
],
version = 12,
version = 13,
)
abstract class AppDatabase : RoomDatabase() {
@@ -51,6 +51,24 @@ class AppRepository(app: Application) {
*/
val allOffers: LiveData<List<CanteenOffer>> = dao.allOffers
/**
* Updates a schedule element.
*
* @param event the event to update
*/
fun update(event: StudIPEvent) {
dao.update(event)
}
/**
* Deletes a schedule element.
*
* @param event the event to delete
*/
fun delete(event: StudIPEvent) {
dao.delete(event)
}
/**
* Retrieves all canteen offer date objects.
*
@@ -147,18 +165,20 @@ class AppRepository(app: Application) {
// --- settings preferences --- //
/**
* Retrieves the user's preference on displaying allergens.
* Retrieves ta user-set boolean preference.
*
* @return whether the user set this preference
* @param pref preference to retrieve
* @return whether the user set this preference
*/
fun getPreferenceAllergen(): Boolean = prefs.getBoolean("setting_allergen", false)
fun getPreference(pref: SettingsPreferences): Boolean = prefs.getBoolean(pref.key, false)
/**
* Updates the user's preference on displaying allergens.
* Updates a user-set boolean preference.
*
* @param value new value to set the preference to
* @param pref preference to set
* @param newValue new value to set the preference to
*/
fun setPreferenceAllergen(value: Boolean) {
prefs.edit().putBoolean("setting_allergen", value).apply()
fun setPreference(pref: SettingsPreferences, newValue: Boolean) {
prefs.edit().putBoolean(pref.key, newValue).apply()
}
}
@@ -0,0 +1,27 @@
package com.denizk0461.studip.dialog
import android.app.Dialog
import androidx.fragment.app.DialogFragment
import android.app.TimePickerDialog
import android.os.Bundle
import android.widget.TimePicker
class TimePickerFragment(
private val timestamp: String,
private val listener: OnTimeSetListener,
private val isEventStart: Boolean,
) : DialogFragment(), TimePickerDialog.OnTimeSetListener {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val timestampSplit = timestamp.split(":")
return TimePickerDialog(activity, this, timestampSplit[0].toInt(), timestampSplit[1].toInt(), true)
}
interface OnTimeSetListener {
fun onTimeSet(hours: Int, minutes: Int, isEventStart: Boolean)
}
override fun onTimeSet(picker: TimePicker?, hours: Int, minutes: Int) {
listener.onTimeSet(hours, minutes, isEventStart)
}
}
@@ -10,6 +10,8 @@ import com.denizk0461.studip.adapter.StudIPEventItemAdapter
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
import com.denizk0461.studip.databinding.FragmentEventBinding
import com.denizk0461.studip.model.StudIPEvent
import com.denizk0461.studip.sheet.ScheduleUpdateSheet
import com.denizk0461.studip.sheet.TextSheet
import com.denizk0461.studip.viewmodel.EventViewModel
import com.google.android.material.tabs.TabLayoutMediator
import java.util.*
@@ -73,8 +75,13 @@ class EventFragment : AppFragment() {
// TODO implement functionality or delete
}
override fun onLongClick(event: StudIPEvent): Boolean {
// TODO implement functionality or delete
return false
// Open a bottom sheet to edit the event
openBottomSheet(ScheduleUpdateSheet(event, onUpdate = { eventToUpdate ->
viewModel.update(eventToUpdate)
}, onDelete = { eventToDelete ->
viewModel.delete(eventToDelete)
}))
return true
}
})
@@ -52,13 +52,31 @@ class SettingsFragment : AppFragment() {
launchWebView()
}
binding.switchAllergens.apply {
isChecked = viewModel.preferenceAllergen
setOnCheckedChangeListener { _, b ->
viewModel.preferenceAllergen = b
// Set up switch for highlighting the next course in the schedule
binding.switchHighlight.apply {
isChecked = viewModel.preferenceCourseHighlighting
setOnCheckedChangeListener { _, newValue ->
viewModel.preferenceCourseHighlighting = newValue
}
}
// Set up switch for displaying allergens
binding.switchAllergens.apply {
isChecked = viewModel.preferenceAllergen
setOnCheckedChangeListener { _, newValue ->
viewModel.preferenceAllergen = newValue
}
}
// Set up switch for crash report opt-in
binding.switchCrashlytics.apply {
isChecked = viewModel.preferenceDataHandling
setOnCheckedChangeListener { _, newValue ->
viewModel.preferenceDataHandling = newValue
}
}
// Set click listener for the data handling dialogue
binding.buttonDataHandling.setOnClickListener {
openBottomSheet(TextSheet(
R.string.settings_data_sheet_header,
@@ -0,0 +1,17 @@
package com.denizk0461.studip.model
/**
* Enumeration class for user-set preferences that will be saved in persistent storage via
* SharedPreferences.
*
* @param key key for the SharedPreferences transaction
*/
enum class SettingsPreferences(val key: String) {
// Whether the user wants to have allergens displayed in the canteen overview
ALLERGEN("setting_allergen"),
// Whether the user wants the next course in his schedule to be highlighted
COURSE_HIGHLIGHTING("setting_highlight"),
// Whether the user opts into sending crash report
DATA_HANDLING("setting_data_handling"),
;
}
@@ -13,6 +13,7 @@ import androidx.room.PrimaryKey
* @param day day the event takes place on; 0 = Monday, 4 = Friday
* @param timeslotStart time the event starts at
* @param timeslotEnd time the event ends at
* @param timeslotId minute the event starts at - used for ordering
* @param colour user-defined colour the event will be shown in - UNIMPLEMENTED
*/
@Entity(tableName = "events")
@@ -24,6 +25,7 @@ data class StudIPEvent(
val day: Int,
val timeslotStart: String,
val timeslotEnd: String,
val timeslotId: Int,
val colour: Int = 0,
) {
@@ -24,6 +24,7 @@ class AllergenSheet(
private val category: String,
) : AppSheet(R.layout.sheet_allergen) {
// View binding
private val binding: SheetAllergenBinding by viewBinding(SheetAllergenBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -0,0 +1,68 @@
package com.denizk0461.studip.sheet
import android.os.Bundle
import android.view.View
import com.denizk0461.studip.R
import com.denizk0461.studip.data.parseToMinutes
import com.denizk0461.studip.data.viewBinding
import com.denizk0461.studip.databinding.SheetScheduleUpdateBinding
import com.denizk0461.studip.dialog.TimePickerFragment
import com.denizk0461.studip.model.StudIPEvent
class ScheduleUpdateSheet(
private val event: StudIPEvent,
private val onUpdate: (event: StudIPEvent) -> Unit,
private val onDelete: (event: StudIPEvent) -> Unit,
) : AppSheet(R.layout.sheet_schedule_update), TimePickerFragment.OnTimeSetListener {
// Editable fields
private var timeslotStart = event.timeslotStart
private var timeslotEnd = event.timeslotEnd
private var colour = event.colour
// View binding
private val binding: SheetScheduleUpdateBinding by viewBinding(SheetScheduleUpdateBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.apply {
editTextTitle.setText(event.title)
editTextLecturers.setText(event.lecturer)
editTextRoom.setText(event.room)
}
binding.buttonDelete.setOnClickListener {
onDelete(event)
dismiss()
}
binding.buttonSave.setOnClickListener {
onUpdate(
StudIPEvent(
id = event.id,
title = binding.editTextTitle.text.toString(),
lecturer = binding.editTextLecturers.text.toString(),
room = binding.editTextRoom.text.toString(),
day = event.day,
timeslotStart = timeslotStart,
timeslotEnd = timeslotEnd,
timeslotId = timeslotStart.parseToMinutes(),
colour = colour,
)
)
dismiss()
}
}
/**
*
*/
override fun onTimeSet(hours: Int, minutes: Int, isEventStart: Boolean) {
if (isEventStart) {
timeslotStart = "$hours:$minutes"
} else {
timeslotEnd = "$hours:$minutes"
}
}
}
@@ -18,11 +18,13 @@ class TextSheet(
@StringRes private val content: Int
) : AppSheet(R.layout.sheet_text) {
// View binding
private val binding: SheetTextBinding by viewBinding(SheetTextBinding::bind)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Set text values
binding.apply {
textHeader.text = getString(header)
textContent.text = getString(content)
@@ -3,10 +3,7 @@ package com.denizk0461.studip.viewmodel
import android.app.Application
import androidx.lifecycle.LiveData
import com.denizk0461.studip.data.StwParser
import com.denizk0461.studip.model.CanteenOffer
import com.denizk0461.studip.model.DietaryPrefObject
import com.denizk0461.studip.model.DietaryPreferences
import com.denizk0461.studip.model.OfferDate
import com.denizk0461.studip.model.*
/**
* View model for [com.denizk0461.studip.fragment.CanteenFragment]
@@ -66,5 +63,5 @@ class CanteenViewModel(app: Application) : AppViewModel(app) {
* This value determines whether the user wants to have allergens marked.
*/
val preferenceAllergen: Boolean
get() = repo.getPreferenceAllergen()
get() = repo.getPreference(SettingsPreferences.ALLERGEN)
}
@@ -17,4 +17,18 @@ class EventViewModel(app: Application) : AppViewModel(app) {
* @return all Stud.IP events exposed through a LiveData object
*/
val allEvents: LiveData<List<StudIPEvent>> = repo.allEvents
/**
* Updates a schedule element.
*
* @param event the event to update
*/
fun update(event: StudIPEvent) { doAsync { repo.update(event) } }
/**
* Deletes a schedule element.
*
* @param event the event to delete
*/
fun delete(event: StudIPEvent) { doAsync { repo.delete(event) } }
}
@@ -1,6 +1,7 @@
package com.denizk0461.studip.viewmodel
import android.app.Application
import com.denizk0461.studip.model.SettingsPreferences
/**
* View model for [com.denizk0461.studip.fragment.SettingsFragment]
@@ -9,10 +10,24 @@ import android.app.Application
*/
class SettingsViewModel(app: Application) : AppViewModel(app) {
/**
* This value determines whether the user opts into submitting crash reports.
*/
var preferenceCourseHighlighting: Boolean
get() = repo.getPreference(SettingsPreferences.DATA_HANDLING)
set(newValue) { repo.setPreference(SettingsPreferences.DATA_HANDLING, newValue) }
/**
* This value determines whether the user wants to have allergens marked.
*/
var preferenceAllergen: Boolean
get() = repo.getPreferenceAllergen()
set(value) { repo.setPreferenceAllergen(value) }
get() = repo.getPreference(SettingsPreferences.ALLERGEN)
set(newValue) { repo.setPreference(SettingsPreferences.ALLERGEN, newValue) }
/**
* This value determines whether the user opts into submitting crash reports.
*/
var preferenceDataHandling: Boolean
get() = repo.getPreference(SettingsPreferences.DATA_HANDLING)
set(newValue) { repo.setPreference(SettingsPreferences.DATA_HANDLING, newValue) }
}