StwParser.kt now collects all its data before adding everything to the database all at once, fixing problems where LiveData would update before all transactions were finished; ViewPagers have been updated to use Adapters extending FragmentStateAdapter instead of RecyclerView.Adapter

This commit is contained in:
denizk0461
2023-04-27 21:58:10 +02:00
parent ccd77a5daf
commit ce7b854e8c
15 changed files with 373 additions and 164 deletions
@@ -5,6 +5,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.PopupMenu
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.viewModels
import com.denizk0461.studip.R
import com.denizk0461.studip.adapter.CanteenOfferItemAdapter
@@ -145,7 +146,11 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
// Set up the view pager's adapter
viewPagerAdapter = CanteenOfferPageAdapter(
listOf(), 0, this, viewModel.preferenceAllergen
activity as FragmentActivity,
listOf(),
0,
this,
viewModel.preferenceAllergen,
)
// Assign the adapter to the view pager
@@ -163,7 +168,9 @@ class CanteenFragment : AppFragment(), CanteenOfferItemAdapter.OnClickListener {
val groupedElements = offers.groupElements().distinct()
// Find all dates stored in the database
val newDates = /*groupedElements.map { it.date }.distinct() TODO */viewModel.getDates()
// val newDates = /*groupedElements.map { it.date }.distinct() TODO */viewModel.getDates()
val newDates = groupedElements.map { it.date }.distinct()
// Update the date count stored in this fragment
dateSize = newDates.size
@@ -0,0 +1,71 @@
package com.denizk0461.studip.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.denizk0461.studip.adapter.CanteenOfferItemAdapter
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
import com.denizk0461.studip.databinding.RecyclerViewBinding
import com.denizk0461.studip.model.CanteenOfferGroup
/**
* Fragment that is instantiated by [StudIPEventPageAdapter] to display individual days' pages and
* their events.
*
* @param offers all offers for a given canteen, grouped by category (not filtered by day at
* this point)
* @param onClickListener for managing click and long press events
* @param displayAllergens whether the user wants allergens to be marked
* @param currentDay current day
*/
class CanteenPageFragment(
private var offers: List<CanteenOfferGroup>,
private val onClickListener: CanteenOfferItemAdapter.OnClickListener,
private val displayAllergens: Boolean,
private val currentDay: Int,
) : AppFragment() {
// Nullable view binding reference
private var _binding: RecyclerViewBinding? = null
/*
* Non-null reference to the view binding. This property is only valid between onCreateView and
* onDestroyView.
*/
private val binding get() = _binding!!
// Instantiate the view binding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = RecyclerViewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.apply {
// Set page to scroll vertically
layoutManager = LinearLayoutManager(
context, LinearLayoutManager.VERTICAL, false
)
/*
* Create new adapter for every page. Attribute position denotes day that will be set up
* by the newly created adapter (0 = Monday, 4 = Friday)
* TODO check if the filtered list is empty, and tell the user if it is
*/
val o = offers.filter { it.dateId == currentDay }
adapter = CanteenOfferItemAdapter(
o,
onClickListener,
displayAllergens,
)
// Animate creation of new page
scheduleLayoutAnimation()
}
}
}
@@ -1,9 +1,12 @@
package com.denizk0461.studip.fragment
import android.os.Bundle
import android.os.Parcelable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.viewModels
import com.denizk0461.studip.R
import com.denizk0461.studip.adapter.StudIPEventItemAdapter
@@ -39,13 +42,12 @@ class EventFragment : AppFragment() {
private var dayOfWeek: Int = 0
// Titles for the view pager's tabs
private val dayStrings = listOf(
R.string.monday,
R.string.tuesday,
R.string.wednesday,
R.string.thursday,
R.string.friday,
)
private lateinit var weekdays: Array<String>
// private var viewPagerScrollPosition: Parcelable? = null
private var viewPagerPosition = -1
private var hasFragmentStarted = false
// Instantiate the view binding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
@@ -56,40 +58,45 @@ class EventFragment : AppFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
/*
* Determine the current day.
* TODO expand to weekend
*/
weekdays = resources.getStringArray(R.array.weekdays)
// Determine the current day
dayOfWeek = when (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) {
Calendar.TUESDAY -> 1
Calendar.WEDNESDAY -> 2
Calendar.THURSDAY -> 3
Calendar.FRIDAY -> 4
else -> 0
Calendar.SATURDAY -> 5
Calendar.SUNDAY -> 6
else -> 0 // assume Monday
}
// Set up the view pager's adapter
viewPagerAdapter = StudIPEventPageAdapter(listOf(), object : StudIPEventItemAdapter.OnClickListener {
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
}
})
viewPagerAdapter =
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
binding.viewPager.adapter = viewPagerAdapter
// Create and attach the object mediating the tabs for the view pager
TabLayoutMediator(binding.dayTabLayout, binding.viewPager) { tab, position ->
tab.text = getString(dayStrings[position])
tab.text = weekdays[position]
}.attach()
// Set up LiveData observer to refresh the view on update
@@ -97,16 +104,53 @@ class EventFragment : AppFragment() {
// Update the item list in the view pager's adapter
viewPagerAdapter.setNewItems(events)
// Scroll to the current day
switchToCurrentDayView()
if (!hasFragmentStarted) {
// Scroll to the current day, if no page has been stored to be scrolled to
switchToCurrentDayView()
hasFragmentStarted = true
// } else {
// /*
// * If a page was previously saved, scroll to that one instead. This is meant to
// * prevent jumping from
// */
// binding.viewPager.currentItem = viewPagerPosition
}
}
}
override fun onPause() {
// viewPagerPosition = binding.viewPager.currentItem
// Log.d("AAA?", "onpause: $viewPagerPosition")
super.onPause()
}
override fun onResume() {
super.onResume()
binding.viewPager.currentItem = viewPagerPosition
Log.d("AAA?", "onresume: pos: $viewPagerPosition; vpp: ${binding.viewPager.currentItem}")
// Scroll to the current day
switchToCurrentDayView()
// switchToCurrentDayView()
}
/**
* Called when the layout changes (e.g. device rotation) but NOT when the fragment is selected
* from the bottom navigation view.
*/
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
Log.d("AAA?", "${binding.viewPager.currentItem}")
outState.putInt(
"viewPagerCurrentPage",
binding.viewPager.currentItem
)
}
override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState)
val restoredPage = savedInstanceState?.getInt("viewPagerCurrentPage") ?: 0
viewPagerPosition = restoredPage
}
// Invalidate the view binding
@@ -0,0 +1,60 @@
package com.denizk0461.studip.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import com.denizk0461.studip.adapter.StudIPEventPageAdapter
import com.denizk0461.studip.adapter.StudIPEventItemAdapter
import com.denizk0461.studip.databinding.RecyclerViewBinding
import com.denizk0461.studip.model.StudIPEvent
/**
* Fragment that is instantiated by [StudIPEventPageAdapter] to display individual days' pages and
* 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,
* 4 = Friday)
* @param onClickListener used for listening to clicks and long presses
*/
class EventPageFragment(
private val events: List<StudIPEvent>,
private val currentDay: Int,
private val onClickListener: StudIPEventItemAdapter.OnClickListener,
) : AppFragment() {
// Nullable view binding reference
private var _binding: RecyclerViewBinding? = null
/*
* Non-null reference to the view binding. This property is only valid between onCreateView and
* onDestroyView.
*/
private val binding get() = _binding!!
// Instantiate the view binding
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = RecyclerViewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.apply {
// Set page to scroll vertically
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
/*
* Create new adapter for every page. Attribute position denotes day that will be set up
* by the newly created adapter (0 = Monday, 4 = Friday)
*/
adapter = StudIPEventItemAdapter(events, currentDay, onClickListener) // TODO check if empty
// Animate creation of new page
scheduleLayoutAnimation()
}
}
}