Archived
Updated EventPageFragment.kt to have access to its own ViewModel and, by extension, its own reference to the database, which forgoes the need to transport data from EventFragment.kt through StudIPEventPageAdapter.kt to EventPageFragment.kt and allows for filtering for a specific day's items through the database rather than needing to iterate through the list via an extension function manually. Also implemented DiffUtil to perform individual updates rather than calling notifyDataSetChanged() every time a single item has been changed.
This commit is contained in:
@@ -20,7 +20,7 @@ import com.denizk0461.studip.model.CanteenOfferGroup
|
|||||||
* @param displayAllergens whether the user wants allergens to be marked
|
* @param displayAllergens whether the user wants allergens to be marked
|
||||||
*/
|
*/
|
||||||
class CanteenOfferPageAdapter(
|
class CanteenOfferPageAdapter(
|
||||||
val fragmentActivity: FragmentActivity,
|
fragmentActivity: FragmentActivity,
|
||||||
private var offers: List<CanteenOfferGroup>,
|
private var offers: List<CanteenOfferGroup>,
|
||||||
private var daysCovered: Int,
|
private var daysCovered: Int,
|
||||||
private val onClickListener: CanteenOfferItemAdapter.OnClickListener,
|
private val onClickListener: CanteenOfferItemAdapter.OnClickListener,
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package com.denizk0461.studip.adapter
|
|||||||
import android.content.res.ColorStateList
|
import android.content.res.ColorStateList
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.denizk0461.studip.data.AppDiffUtilCallback
|
||||||
import com.google.android.material.R
|
import com.google.android.material.R
|
||||||
import com.denizk0461.studip.data.getThemedColor
|
import com.denizk0461.studip.data.getThemedColor
|
||||||
import com.denizk0461.studip.data.parseToMinutes
|
import com.denizk0461.studip.data.parseToMinutes
|
||||||
@@ -12,29 +14,30 @@ import com.denizk0461.studip.databinding.ItemEventBinding
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom RecyclerView adapter that lays out the Stud.IP events of a given day.
|
* Custom RecyclerView adapter that lays out the Stud.IP events for a given day.
|
||||||
*
|
*
|
||||||
* @param events list of all events (still not filtered by day at this point)
|
|
||||||
* @param currentDay current day that is used to show only events of a given day (0 = Monday,
|
* @param currentDay current day that is used to show only a given day's events (0 = Monday,
|
||||||
* 4 = Friday)
|
* 4 = Friday)
|
||||||
* @param onClickListener used for listening to clicks and long presses
|
* @param onClickListener used for listening to clicks and long presses
|
||||||
*/
|
*/
|
||||||
class StudIPEventItemAdapter(
|
class StudIPEventItemAdapter(
|
||||||
events: List<StudIPEvent>,
|
|
||||||
private val currentDay: Int,
|
private val currentDay: Int,
|
||||||
private val onClickListener: OnClickListener,
|
private val onClickListener: OnClickListener,
|
||||||
) : RecyclerView.Adapter<StudIPEventItemAdapter.EventViewHolder>() {
|
) : RecyclerView.Adapter<StudIPEventItemAdapter.EventViewHolder>() {
|
||||||
|
|
||||||
// Filter events to only show those of a given day
|
/**
|
||||||
private val filteredEvents: List<StudIPEvent> = events.filter { it.day == currentDay }
|
* List of all events (still not filtered by day at this point)
|
||||||
|
*/
|
||||||
|
private var events: MutableList<StudIPEvent> = mutableListOf()
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Retrieve an instance of Calendar to check whether the adapter's day matches the current day.
|
* Retrieve an instance of Calendar to check whether the adapter's day matches the current day.
|
||||||
* TODO this can be optimised by checking in StudIPEventPageAdapter.kt and delivering a boolean
|
* TODO this can be optimised by checking in EventPageFragment.kt and delivering a boolean
|
||||||
*/
|
*/
|
||||||
private val currentCalendar = Calendar.getInstance()
|
private val currentCalendar = Calendar.getInstance()
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Used to disallow highlighting more than one course at a time, since only a single course
|
* Used to disallow highlighting more than one course at a time, since only a single course
|
||||||
* could be coming up at a given time.
|
* could be coming up at a given time.
|
||||||
*/
|
*/
|
||||||
@@ -58,12 +61,11 @@ class StudIPEventItemAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the amount of items to the size of the filtered list, so only events of the current day
|
// Set the amount of items to the size of the filtered list, so only events of the current day
|
||||||
override fun getItemCount(): Int = filteredEvents.size
|
override fun getItemCount(): Int = events.size
|
||||||
|
|
||||||
// TODO inflate a view saying "no events" if none are available for a given day
|
|
||||||
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
|
||||||
// Retrieve item for current position
|
// Retrieve item for current position
|
||||||
val currentItem = filteredEvents[position]
|
val currentItem = events[position]
|
||||||
|
|
||||||
// Set up text fields with corresponding values
|
// Set up text fields with corresponding values
|
||||||
holder.binding.textTitle.text = currentItem.title
|
holder.binding.textTitle.text = currentItem.title
|
||||||
@@ -117,6 +119,26 @@ class StudIPEventItemAdapter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the data and calculates the difference between the old dataset and the newly provided
|
||||||
|
* dataset.
|
||||||
|
*
|
||||||
|
* @param newData new dataset to be displayed
|
||||||
|
*/
|
||||||
|
fun setNewData(newData: List<StudIPEvent>) {
|
||||||
|
// Calculate the difference between the old list and the new list
|
||||||
|
val diffResult = DiffUtil.calculateDiff(AppDiffUtilCallback(events, newData))
|
||||||
|
|
||||||
|
// Remove all items from the list
|
||||||
|
events.clear()
|
||||||
|
|
||||||
|
// Add all items from the new list
|
||||||
|
events.addAll(newData)
|
||||||
|
|
||||||
|
// Tell the DiffUtil which items have changed between the two lists
|
||||||
|
diffResult.dispatchUpdatesTo(this)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a given course is the next course coming up. This is done by checking whether the
|
* Checks if a given course is the next course coming up. This is done by checking whether the
|
||||||
* day of the course matches the current real world day, as well as by evaluating if the end
|
* day of the course matches the current real world day, as well as by evaluating if the end
|
||||||
@@ -131,7 +153,6 @@ class StudIPEventItemAdapter(
|
|||||||
(calendar.get(Calendar.DAY_OF_WEEK) == this.day.toCalendarDay()) &&
|
(calendar.get(Calendar.DAY_OF_WEEK) == this.day.toCalendarDay()) &&
|
||||||
((calendar.get(Calendar.MINUTE) + calendar.get(Calendar.HOUR_OF_DAY) * 60) < this.timeslotEnd.parseToMinutes())
|
((calendar.get(Calendar.MINUTE) + calendar.get(Calendar.HOUR_OF_DAY) * 60) < this.timeslotEnd.parseToMinutes())
|
||||||
|
|
||||||
// Converts day as defined in StudIPEvent.kt to day from Calendar
|
|
||||||
/**
|
/**
|
||||||
* Converts a numeric value as defined in StudIPEvent.kt to a calendar day. Used to convert from
|
* Converts a numeric value as defined in StudIPEvent.kt to a calendar day. Used to convert from
|
||||||
* American convention (where Sunday is the first day, 1 = Sunday, 2 = Monday, 7 = Saturday) to
|
* American convention (where Sunday is the first day, 1 = Sunday, 2 = Monday, 7 = Saturday) to
|
||||||
|
|||||||
@@ -3,20 +3,15 @@ package com.denizk0461.studip.adapter
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
import com.denizk0461.studip.model.StudIPEvent
|
|
||||||
import com.denizk0461.studip.fragment.EventPageFragment
|
import com.denizk0461.studip.fragment.EventPageFragment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom ViewPager adapter for managing multiple pages of Stud.IP events.
|
* Custom ViewPager adapter for managing multiple pages of Stud.IP events.
|
||||||
*
|
*
|
||||||
* @param fragmentActivity parent fragment activity
|
* @param fragmentActivity parent fragment activity
|
||||||
* @param events all events (not filtered by day at this point)
|
|
||||||
* @param onClickListener for managing click and long press events
|
|
||||||
*/
|
*/
|
||||||
class StudIPEventPageAdapter(
|
class StudIPEventPageAdapter(
|
||||||
fragmentActivity: FragmentActivity,
|
fragmentActivity: FragmentActivity,
|
||||||
private var events: List<StudIPEvent>,
|
|
||||||
private val onClickListener: StudIPEventItemAdapter.OnClickListener,
|
|
||||||
) : FragmentStateAdapter(fragmentActivity) {
|
) : FragmentStateAdapter(fragmentActivity) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -25,18 +20,5 @@ class StudIPEventPageAdapter(
|
|||||||
override fun getItemCount(): Int = 7
|
override fun getItemCount(): Int = 7
|
||||||
|
|
||||||
override fun createFragment(position: Int): Fragment =
|
override fun createFragment(position: Int): Fragment =
|
||||||
EventPageFragment(events, position, onClickListener)
|
EventPageFragment(position)
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the entire list of items
|
|
||||||
*
|
|
||||||
* @param items the new set of items
|
|
||||||
*/
|
|
||||||
fun setNewItems(items: List<StudIPEvent>) {
|
|
||||||
// Update items
|
|
||||||
events = items
|
|
||||||
|
|
||||||
// Force an update of the view. TODO replace with individual updates, as this is inefficient
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.denizk0461.studip.data
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class used to calculate the difference between two lists to provide the adapter with
|
||||||
|
* means to perform operations only on items that have been newly added/modified/deleted.
|
||||||
|
*
|
||||||
|
* @param oldList old list
|
||||||
|
* @param newList new list
|
||||||
|
*/
|
||||||
|
class AppDiffUtilCallback(
|
||||||
|
private val oldList: List<Any>,
|
||||||
|
private val newList: List<Any>,
|
||||||
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the old list's size count.
|
||||||
|
*
|
||||||
|
* @return size of the old list
|
||||||
|
*/
|
||||||
|
override fun getOldListSize(): Int = oldList.size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the new list's size count.
|
||||||
|
*
|
||||||
|
* @return size of the new list
|
||||||
|
*/
|
||||||
|
override fun getNewListSize(): Int = newList.size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether two items in the lists contain items of the same class.
|
||||||
|
*
|
||||||
|
* @param oldItemPosition position of the item in the old list to be checked
|
||||||
|
* @param newItemPosition position of the item in the new list to be checked
|
||||||
|
* @return whether the two items are of the same class
|
||||||
|
*/
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
oldList[oldItemPosition].javaClass == newList[newItemPosition].javaClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether two items in the lists have the same contents.
|
||||||
|
*
|
||||||
|
* @param oldItemPosition position of the item in the old list to be checked
|
||||||
|
* @param newItemPosition position of the item in the new list to be checked
|
||||||
|
* @return whether the two items are the same (content is equal)
|
||||||
|
*/
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
oldList[oldItemPosition].hashCode() == newList[newItemPosition].hashCode()
|
||||||
|
}
|
||||||
@@ -21,6 +21,14 @@ interface AppDAO {
|
|||||||
@get:Query("SELECT * FROM studipevents ORDER BY timeslotId, id")
|
@get:Query("SELECT * FROM studipevents ORDER BY timeslotId, id")
|
||||||
val allEvents: LiveData<List<StudIPEvent>>
|
val allEvents: LiveData<List<StudIPEvent>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Stud.IP events for a specific day, ordered by their timeslots, then their IDs.
|
||||||
|
*
|
||||||
|
* @return Stud.IP events for a certain day exposed through a LiveData object
|
||||||
|
*/
|
||||||
|
@Query("SELECT * FROM studipevents WHERE day = :day ORDER BY timeslotId, id")
|
||||||
|
fun getEventsForDay(day: Int): LiveData<List<StudIPEvent>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a given Stud.IP element.
|
* Updates a given Stud.IP element.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ class AppRepository(app: Application) {
|
|||||||
private val blankDietaryPrefs: String = DietaryPreferences.C_FALSE.toString().repeat(10)
|
private val blankDietaryPrefs: String = DietaryPreferences.C_FALSE.toString().repeat(10)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all Stud.IP events.
|
* Retrieves Stud.IP events for a specific day, ordered by their timeslots, then their IDs.
|
||||||
*
|
*
|
||||||
* @return all Stud.IP events exposed through a LiveData object
|
* @return Stud.IP events for a certain day exposed through a LiveData object
|
||||||
*/
|
*/
|
||||||
val allEvents: LiveData<List<StudIPEvent>> = dao.allEvents
|
fun getEventsForDay(day: Int): LiveData<List<StudIPEvent>> = dao.getEventsForDay(day)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a list of Stud.IP events into the database.
|
* Inserts a list of Stud.IP events into the database.
|
||||||
@@ -166,13 +166,6 @@ class AppRepository(app: Application) {
|
|||||||
*/
|
*/
|
||||||
fun nukeOfferDates() { dao.nukeOfferDates() }
|
fun nukeOfferDates() { dao.nukeOfferDates() }
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a date into the database.
|
|
||||||
*
|
|
||||||
* @param date object to be saved to the database
|
|
||||||
*/
|
|
||||||
fun insert(date: OfferDate) { dao.insert(date) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a list of dates into the database.
|
* Inserts a list of dates into the database.
|
||||||
*
|
*
|
||||||
@@ -180,13 +173,6 @@ class AppRepository(app: Application) {
|
|||||||
*/
|
*/
|
||||||
fun insertDates(dates: List<OfferDate>) { dao.insertDates(dates) }
|
fun insertDates(dates: List<OfferDate>) { dao.insertDates(dates) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a canteen into the database.
|
|
||||||
*
|
|
||||||
* @param canteen object to be saved to the database
|
|
||||||
*/
|
|
||||||
fun insert(canteen: OfferCanteen) { dao.insert(canteen) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a list of canteens into the database.
|
* Inserts a list of canteens into the database.
|
||||||
*
|
*
|
||||||
@@ -194,13 +180,6 @@ class AppRepository(app: Application) {
|
|||||||
*/
|
*/
|
||||||
fun insertCanteens(canteens: List<OfferCanteen>) { dao.insertCanteens(canteens) }
|
fun insertCanteens(canteens: List<OfferCanteen>) { dao.insertCanteens(canteens) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a canteen offer category into the database.
|
|
||||||
*
|
|
||||||
* @param category object to be saved to the database
|
|
||||||
*/
|
|
||||||
fun insert(category: OfferCategory) { dao.insert(category) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a list of categories into the database.
|
* Inserts a list of categories into the database.
|
||||||
*
|
*
|
||||||
@@ -208,13 +187,6 @@ class AppRepository(app: Application) {
|
|||||||
*/
|
*/
|
||||||
fun insertCategories(categories: List<OfferCategory>) { dao.insertCategories(categories) }
|
fun insertCategories(categories: List<OfferCategory>) { dao.insertCategories(categories) }
|
||||||
|
|
||||||
/**
|
|
||||||
* Inserts a canteen offer item into the database.
|
|
||||||
*
|
|
||||||
* @param item object to be saved to the database
|
|
||||||
*/
|
|
||||||
fun insert(item: OfferItem) { dao.insert(item) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts a list of items into the database.
|
* Inserts a list of items into the database.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package com.denizk0461.studip.fragment
|
package com.denizk0461.studip.fragment
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Parcelable
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@@ -9,11 +8,8 @@ import android.view.ViewGroup
|
|||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import com.denizk0461.studip.R
|
import com.denizk0461.studip.R
|
||||||
import com.denizk0461.studip.adapter.StudIPEventItemAdapter
|
|
||||||
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
|
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
|
||||||
import com.denizk0461.studip.databinding.FragmentEventBinding
|
import com.denizk0461.studip.databinding.FragmentEventBinding
|
||||||
import com.denizk0461.studip.model.StudIPEvent
|
|
||||||
import com.denizk0461.studip.sheet.ScheduleUpdateSheet
|
|
||||||
import com.denizk0461.studip.viewmodel.EventViewModel
|
import com.denizk0461.studip.viewmodel.EventViewModel
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -73,24 +69,7 @@ class EventFragment : AppFragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up the view pager's adapter
|
// Set up the view pager's adapter
|
||||||
viewPagerAdapter =
|
viewPagerAdapter = StudIPEventPageAdapter(activity as FragmentActivity)
|
||||||
StudIPEventPageAdapter(activity as FragmentActivity, listOf(), object : StudIPEventItemAdapter.OnClickListener {
|
|
||||||
override fun onClick(event: StudIPEvent) {
|
|
||||||
// TODO implement functionality or delete
|
|
||||||
}
|
|
||||||
override fun onLongClick(event: StudIPEvent): Boolean {
|
|
||||||
// Save the current page of the ViewPager
|
|
||||||
viewPagerPosition = binding.viewPager.currentItem
|
|
||||||
|
|
||||||
// Open a bottom sheet to edit the event
|
|
||||||
openBottomSheet(ScheduleUpdateSheet(event, onUpdate = { eventToUpdate ->
|
|
||||||
viewModel.update(eventToUpdate)
|
|
||||||
}, onDelete = { eventToDelete ->
|
|
||||||
viewModel.delete(eventToDelete)
|
|
||||||
}))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Assign the adapter to the view pager
|
// Assign the adapter to the view pager
|
||||||
binding.viewPager.adapter = viewPagerAdapter
|
binding.viewPager.adapter = viewPagerAdapter
|
||||||
@@ -101,25 +80,25 @@ class EventFragment : AppFragment() {
|
|||||||
}.attach()
|
}.attach()
|
||||||
|
|
||||||
// Set up LiveData observer to refresh the view on update
|
// Set up LiveData observer to refresh the view on update
|
||||||
viewModel.allEvents.observe(viewLifecycleOwner) { events ->
|
// viewModel.allEvents.observe(viewLifecycleOwner) { events ->
|
||||||
|
//
|
||||||
Log.d("AAAbA?", events.toString())
|
// Log.d("AAAbA?", events.toString())
|
||||||
|
//
|
||||||
// Update the item list in the view pager's adapter
|
// // Update the item list in the view pager's adapter
|
||||||
viewPagerAdapter.setNewItems(events)
|
// viewPagerAdapter.setNewItems(events)
|
||||||
|
//
|
||||||
if (!hasFragmentStarted) {
|
// if (!hasFragmentStarted) {
|
||||||
// Scroll to the current day, if no page has been stored to be scrolled to
|
// // Scroll to the current day, if no page has been stored to be scrolled to
|
||||||
switchToCurrentDayView()
|
// switchToCurrentDayView()
|
||||||
hasFragmentStarted = true
|
// hasFragmentStarted = true
|
||||||
// } else {
|
//// } else {
|
||||||
// /*
|
//// /*
|
||||||
// * If a page was previously saved, scroll to that one instead. This is meant to
|
//// * If a page was previously saved, scroll to that one instead. This is meant to
|
||||||
// * prevent jumping from
|
//// * prevent jumping from
|
||||||
// */
|
//// */
|
||||||
// binding.viewPager.currentItem = viewPagerPosition
|
//// binding.viewPager.currentItem = viewPagerPosition
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
|||||||
@@ -4,26 +4,25 @@ 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.viewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
|
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
|
||||||
import com.denizk0461.studip.adapter.StudIPEventItemAdapter
|
import com.denizk0461.studip.adapter.StudIPEventItemAdapter
|
||||||
import com.denizk0461.studip.databinding.RecyclerViewBinding
|
import com.denizk0461.studip.databinding.RecyclerViewBinding
|
||||||
import com.denizk0461.studip.model.StudIPEvent
|
import com.denizk0461.studip.model.StudIPEvent
|
||||||
|
import com.denizk0461.studip.sheet.ScheduleUpdateSheet
|
||||||
|
import com.denizk0461.studip.viewmodel.EventPageViewModel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment that is instantiated by [StudIPEventPageAdapter] to display individual days' pages and
|
* Fragment that is instantiated by [StudIPEventPageAdapter] to display individual days' pages and
|
||||||
* their events.
|
* their events.
|
||||||
*
|
*
|
||||||
* @param events list of all events (still not filtered by day at this point)
|
|
||||||
* @param currentDay current day that is used to show only events of a given day (0 = Monday,
|
* @param currentDay current day that is used to show only events of a given day (0 = Monday,
|
||||||
* 4 = Friday)
|
* 4 = Friday)
|
||||||
* @param onClickListener used for listening to clicks and long presses
|
|
||||||
*/
|
*/
|
||||||
class EventPageFragment(
|
class EventPageFragment(
|
||||||
private val events: List<StudIPEvent>,
|
|
||||||
private val currentDay: Int,
|
private val currentDay: Int,
|
||||||
private val onClickListener: StudIPEventItemAdapter.OnClickListener,
|
) : AppFragment(), StudIPEventItemAdapter.OnClickListener {
|
||||||
) : AppFragment() {
|
|
||||||
|
|
||||||
// Nullable view binding reference
|
// Nullable view binding reference
|
||||||
private var _binding: RecyclerViewBinding? = null
|
private var _binding: RecyclerViewBinding? = null
|
||||||
@@ -34,6 +33,14 @@ class EventPageFragment(
|
|||||||
*/
|
*/
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
|
||||||
|
// View model reference for providing access to the database
|
||||||
|
private val viewModel: EventPageViewModel by viewModels()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter that manages the page's items
|
||||||
|
*/
|
||||||
|
private val eventAdapter = StudIPEventItemAdapter(currentDay, this)
|
||||||
|
|
||||||
// Instantiate the view binding
|
// Instantiate the view binding
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
_binding = RecyclerViewBinding.inflate(inflater, container, false)
|
_binding = RecyclerViewBinding.inflate(inflater, container, false)
|
||||||
@@ -49,12 +56,32 @@ class EventPageFragment(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Create new adapter for every page. Attribute position denotes day that will be set up
|
* Create new adapter for every page. Attribute position denotes day that will be set up
|
||||||
* by the newly created adapter (0 = Monday, 4 = Friday)
|
* by the newly created adapter (0 = Monday, 4 = Friday, 6 = Sunday)
|
||||||
*/
|
*/
|
||||||
adapter = StudIPEventItemAdapter(events, currentDay, onClickListener) // TODO check if empty
|
adapter = eventAdapter
|
||||||
|
|
||||||
// Animate creation of new page
|
// Animate creation of new page
|
||||||
scheduleLayoutAnimation()
|
scheduleLayoutAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up LiveData observer to refresh the view on update
|
||||||
|
viewModel.getEventsForDay(currentDay).observe(viewLifecycleOwner) { events ->
|
||||||
|
// eventAdapter.setNewItems(events)
|
||||||
|
eventAdapter.setNewData(events)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(event: StudIPEvent) {
|
||||||
|
// TODO implement functionality or delete
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLongClick(event: StudIPEvent): Boolean {
|
||||||
|
// Open a bottom sheet to edit the event
|
||||||
|
openBottomSheet(ScheduleUpdateSheet(event, onUpdate = { eventToUpdate ->
|
||||||
|
viewModel.update(eventToUpdate)
|
||||||
|
}, onDelete = { eventToDelete ->
|
||||||
|
viewModel.delete(eventToDelete)
|
||||||
|
}))
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ data class StudIPEvent(
|
|||||||
*/
|
*/
|
||||||
fun timeslot(): String = "$timeslotStart – $timeslotEnd"
|
fun timeslot(): String = "$timeslotStart – $timeslotEnd"
|
||||||
|
|
||||||
// Auto-generated methods
|
// Auto-generated methods. Necessary for [AppDiffUtilCallback]
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
@@ -45,11 +45,19 @@ data class StudIPEvent(
|
|||||||
|
|
||||||
other as StudIPEvent
|
other as StudIPEvent
|
||||||
|
|
||||||
|
if (id != other.id) return false
|
||||||
if (title != other.title) return false
|
if (title != other.title) return false
|
||||||
if (!lecturer.contentEquals(other.lecturer)) return false
|
if (lecturer != other.lecturer) return false
|
||||||
|
if (room != other.room) return false
|
||||||
|
if (day != other.day) return false
|
||||||
|
if (timeslotStart != other.timeslotStart) return false
|
||||||
|
if (timeslotEnd != other.timeslotEnd) return false
|
||||||
|
if (timeslotId != other.timeslotId) return false
|
||||||
|
if (colour != other.colour) return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
override fun hashCode(): Int {
|
||||||
var result = id
|
var result = id
|
||||||
result = 31 * result + title.hashCode()
|
result = 31 * result + title.hashCode()
|
||||||
@@ -58,7 +66,8 @@ data class StudIPEvent(
|
|||||||
result = 31 * result + day
|
result = 31 * result + day
|
||||||
result = 31 * result + timeslotStart.hashCode()
|
result = 31 * result + timeslotStart.hashCode()
|
||||||
result = 31 * result + timeslotEnd.hashCode()
|
result = 31 * result + timeslotEnd.hashCode()
|
||||||
result = 31 * result + colour.hashCode()
|
result = 31 * result + timeslotId
|
||||||
|
result = 31 * result + colour
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.denizk0461.studip.viewmodel
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import com.denizk0461.studip.model.StudIPEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View model for [com.denizk0461.studip.fragment.EventPageFragment]
|
||||||
|
*
|
||||||
|
* @param app reference to the app
|
||||||
|
*/
|
||||||
|
class EventPageViewModel(app: Application) : AppViewModel(app) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Stud.IP events for a specific day, ordered by their timeslots, then their IDs.
|
||||||
|
*
|
||||||
|
* @return Stud.IP events for a certain day exposed through a LiveData object
|
||||||
|
*/
|
||||||
|
fun getEventsForDay(day: Int): LiveData<List<StudIPEvent>> = repo.getEventsForDay(day)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,34 +1,10 @@
|
|||||||
package com.denizk0461.studip.viewmodel
|
package com.denizk0461.studip.viewmodel
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.lifecycle.LiveData
|
|
||||||
import com.denizk0461.studip.model.StudIPEvent
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View model for [com.denizk0461.studip.fragment.EventFragment]
|
* View model for [com.denizk0461.studip.fragment.EventFragment]
|
||||||
*
|
*
|
||||||
* @param app reference to the app
|
* @param app reference to the app
|
||||||
*/
|
*/
|
||||||
class EventViewModel(app: Application) : AppViewModel(app) {
|
class EventViewModel(app: Application) : AppViewModel(app)
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves all Stud.IP events.
|
|
||||||
*
|
|
||||||
* @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) } }
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user