Wait for adapter to contain data before attaching it to recyclerview to prevent loosing scroll position when rotating device

This commit is contained in:
Sylvain Berfini 2024-09-09 11:13:13 +02:00
parent 6c22b1f66d
commit db751efa91
11 changed files with 74 additions and 43 deletions

View file

@ -88,10 +88,6 @@ class ConferenceParticipantsListFragment : GenericCallFragment() {
binding.participantsList.setHasFixedSize(true) binding.participantsList.setHasFixedSize(true)
binding.participantsList.layoutManager = LinearLayoutManager(requireContext()) binding.participantsList.layoutManager = LinearLayoutManager(requireContext())
if (binding.participantsList.adapter != adapter) {
binding.participantsList.adapter = adapter
}
binding.setBackClickListener { binding.setBackClickListener {
findNavController().popBackStack() findNavController().popBackStack()
} }
@ -107,6 +103,12 @@ class ConferenceParticipantsListFragment : GenericCallFragment() {
viewModel.conferenceModel.participants.observe(viewLifecycleOwner) { viewModel.conferenceModel.participants.observe(viewLifecycleOwner) {
Log.i("$TAG participants list updated with [${it.size}] items") Log.i("$TAG participants list updated with [${it.size}] items")
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.participantsList.adapter != adapter) {
binding.participantsList.adapter = adapter
}
} }
viewModel.conferenceModel.removeParticipantEvent.observe(viewLifecycleOwner) { viewModel.conferenceModel.removeParticipantEvent.observe(viewLifecycleOwner) {

View file

@ -120,10 +120,6 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() {
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter) val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter)
binding.contactsAndSuggestionsList.addItemDecoration(headerItemDecoration) binding.contactsAndSuggestionsList.addItemDecoration(headerItemDecoration)
if (binding.contactsAndSuggestionsList.adapter != adapter) {
binding.contactsAndSuggestionsList.adapter = adapter
}
adapter.onClickedEvent.observe(viewLifecycleOwner) { adapter.onClickedEvent.observe(viewLifecycleOwner) {
it.consume { model -> it.consume { model ->
startCall(model) startCall(model)
@ -139,6 +135,12 @@ abstract class AbstractNewTransferCallFragment : GenericCallFragment() {
val count = adapter.itemCount val count = adapter.itemCount
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.contactsAndSuggestionsList.adapter != adapter) {
binding.contactsAndSuggestionsList.adapter = adapter
}
if (count == 0) { if (count == 0) {
(view.parent as? ViewGroup)?.doOnPreDraw { (view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition() startPostponedEnterTransition()

View file

@ -76,10 +76,6 @@ class CallsListFragment : GenericCallFragment() {
binding.callsList.setHasFixedSize(true) binding.callsList.setHasFixedSize(true)
binding.callsList.layoutManager = LinearLayoutManager(requireContext()) binding.callsList.layoutManager = LinearLayoutManager(requireContext())
if (binding.callsList.adapter != adapter) {
binding.callsList.adapter = adapter
}
adapter.callLongClickedEvent.observe(viewLifecycleOwner) { adapter.callLongClickedEvent.observe(viewLifecycleOwner) {
it.consume { model -> it.consume { model ->
val modalBottomSheet = CallMenuDialogFragment(model) { val modalBottomSheet = CallMenuDialogFragment(model) {
@ -108,6 +104,12 @@ class CallsListFragment : GenericCallFragment() {
viewModel.calls.observe(viewLifecycleOwner) { viewModel.calls.observe(viewLifecycleOwner) {
Log.i("$TAG Calls list updated with [${it.size}] items") Log.i("$TAG Calls list updated with [${it.size}] items")
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.callsList.adapter != adapter) {
binding.callsList.adapter = adapter
}
} }
} }

View file

@ -111,6 +111,8 @@ class ConversationForwardMessageFragment : SlidingPaneChildFragment() {
) )
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.contactsList.adapter != adapter) { if (binding.contactsList.adapter != adapter) {
binding.contactsList.adapter = adapter binding.contactsList.adapter = adapter
} }

View file

@ -400,10 +400,6 @@ open class ConversationFragment : SlidingPaneChildFragment() {
layoutManager.stackFromEnd = true layoutManager.stackFromEnd = true
binding.eventsList.layoutManager = layoutManager binding.eventsList.layoutManager = layoutManager
if (binding.eventsList.adapter != adapter) {
binding.eventsList.adapter = adapter
}
val callbacks = RecyclerViewSwipeUtilsCallback( val callbacks = RecyclerViewSwipeUtilsCallback(
R.drawable.reply, R.drawable.reply,
ConversationEventAdapter.EventViewHolder::class.java ConversationEventAdapter.EventViewHolder::class.java
@ -480,6 +476,12 @@ open class ConversationFragment : SlidingPaneChildFragment() {
Log.i("$TAG Events (messages) list submitted, contains [${items.size}] items") Log.i("$TAG Events (messages) list submitted, contains [${items.size}] items")
adapter.submitList(items) adapter.submitList(items)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.eventsList.adapter != adapter) {
binding.eventsList.adapter = adapter
}
(view.parent as? ViewGroup)?.doOnPreDraw { (view.parent as? ViewGroup)?.doOnPreDraw {
sharedViewModel.openSlidingPaneEvent.value = Event(true) sharedViewModel.openSlidingPaneEvent.value = Event(true)
} }

View file

@ -120,10 +120,6 @@ class ConversationsListFragment : AbstractMainFragment() {
binding.conversationsList.setHasFixedSize(true) binding.conversationsList.setHasFixedSize(true)
binding.conversationsList.layoutManager = LinearLayoutManager(requireContext()) binding.conversationsList.layoutManager = LinearLayoutManager(requireContext())
if (binding.conversationsList.adapter != adapter) {
binding.conversationsList.adapter = adapter
}
adapter.conversationLongClickedEvent.observe(viewLifecycleOwner) { adapter.conversationLongClickedEvent.observe(viewLifecycleOwner) {
it.consume { model -> it.consume { model ->
val modalBottomSheet = ConversationDialogFragment( val modalBottomSheet = ConversationDialogFragment(
@ -181,6 +177,13 @@ class ConversationsListFragment : AbstractMainFragment() {
listViewModel.conversations.observe(viewLifecycleOwner) { listViewModel.conversations.observe(viewLifecycleOwner) {
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.conversationsList.adapter != adapter) {
binding.conversationsList.adapter = adapter
}
Log.i("$TAG Conversations list ready with [${it.size}] items") Log.i("$TAG Conversations list ready with [${it.size}] items")
listViewModel.fetchInProgress.value = false listViewModel.fetchInProgress.value = false
} }

View file

@ -133,17 +133,17 @@ class ContactsListFragment : AbstractMainFragment() {
configureAdapter(adapter) configureAdapter(adapter)
configureAdapter(favouritesAdapter) configureAdapter(favouritesAdapter)
if (binding.contactsList.adapter != adapter) {
binding.contactsList.adapter = adapter
}
if (binding.favouritesContactsList.adapter != favouritesAdapter) {
binding.favouritesContactsList.adapter = favouritesAdapter
}
listViewModel.contactsList.observe( listViewModel.contactsList.observe(
viewLifecycleOwner viewLifecycleOwner
) { ) {
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.contactsList.adapter != adapter) {
binding.contactsList.adapter = adapter
}
Log.i("$TAG Contacts list updated with [${it.size}] items") Log.i("$TAG Contacts list updated with [${it.size}] items")
listViewModel.fetchInProgress.value = false listViewModel.fetchInProgress.value = false
} }
@ -152,6 +152,13 @@ class ContactsListFragment : AbstractMainFragment() {
viewLifecycleOwner viewLifecycleOwner
) { ) {
favouritesAdapter.submitList(it) favouritesAdapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.favouritesContactsList.adapter != favouritesAdapter) {
binding.favouritesContactsList.adapter = favouritesAdapter
}
Log.i("$TAG Favourites contacts list updated with [${it.size}] items") Log.i("$TAG Favourites contacts list updated with [${it.size}] items")
} }

View file

@ -106,10 +106,6 @@ class HistoryFragment : SlidingPaneChildFragment() {
binding.callHistory.setHasFixedSize(true) binding.callHistory.setHasFixedSize(true)
binding.callHistory.layoutManager = LinearLayoutManager(requireContext()) binding.callHistory.layoutManager = LinearLayoutManager(requireContext())
if (binding.callHistory.adapter != adapter) {
binding.callHistory.adapter = adapter
}
viewModel.callLogFoundEvent.observe(viewLifecycleOwner) { viewModel.callLogFoundEvent.observe(viewLifecycleOwner) {
it.consume { found -> it.consume { found ->
if (found) { if (found) {
@ -136,6 +132,12 @@ class HistoryFragment : SlidingPaneChildFragment() {
viewModel.historyCallLogs.observe(viewLifecycleOwner) { viewModel.historyCallLogs.observe(viewLifecycleOwner) {
Log.i("$TAG Call history list ready with [${it.size}] items") Log.i("$TAG Call history list ready with [${it.size}] items")
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.callHistory.adapter != adapter) {
binding.callHistory.adapter = adapter
}
} }
viewModel.historyDeletedEvent.observe(viewLifecycleOwner) { viewModel.historyDeletedEvent.observe(viewLifecycleOwner) {

View file

@ -107,10 +107,6 @@ class HistoryListFragment : AbstractMainFragment() {
binding.historyList.setHasFixedSize(true) binding.historyList.setHasFixedSize(true)
binding.historyList.layoutManager = LinearLayoutManager(requireContext()) binding.historyList.layoutManager = LinearLayoutManager(requireContext())
if (binding.historyList.adapter != adapter) {
binding.historyList.adapter = adapter
}
adapter.callLogLongClickedEvent.observe(viewLifecycleOwner) { adapter.callLogLongClickedEvent.observe(viewLifecycleOwner) {
it.consume { model -> it.consume { model ->
val modalBottomSheet = HistoryMenuDialogFragment( val modalBottomSheet = HistoryMenuDialogFragment(
@ -191,6 +187,13 @@ class HistoryListFragment : AbstractMainFragment() {
listViewModel.callLogs.observe(viewLifecycleOwner) { listViewModel.callLogs.observe(viewLifecycleOwner) {
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.historyList.adapter != adapter) {
binding.historyList.adapter = adapter
}
Log.i("$TAG Call logs ready with [${it.size}] items") Log.i("$TAG Call logs ready with [${it.size}] items")
listViewModel.fetchInProgress.value = false listViewModel.fetchInProgress.value = false
} }

View file

@ -119,10 +119,6 @@ class MeetingsListFragment : AbstractMainFragment() {
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter) val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter)
binding.meetingsList.addItemDecoration(headerItemDecoration) binding.meetingsList.addItemDecoration(headerItemDecoration)
if (binding.meetingsList.adapter != adapter) {
binding.meetingsList.adapter = adapter
}
binding.setNewMeetingClicked { binding.setNewMeetingClicked {
if (findNavController().currentDestination?.id == R.id.meetingsListFragment) { if (findNavController().currentDestination?.id == R.id.meetingsListFragment) {
Log.i("$TAG Navigating to schedule meeting fragment") Log.i("$TAG Navigating to schedule meeting fragment")
@ -153,6 +149,13 @@ class MeetingsListFragment : AbstractMainFragment() {
val currentCount = adapter.itemCount val currentCount = adapter.itemCount
val newCount = it.size val newCount = it.size
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.meetingsList.adapter != adapter) {
binding.meetingsList.adapter = adapter
}
Log.i("$TAG Meetings list ready with [$newCount] items") Log.i("$TAG Meetings list ready with [$newCount] items")
listViewModel.fetchInProgress.value = false listViewModel.fetchInProgress.value = false
} }

View file

@ -94,13 +94,16 @@ class RecordingsListFragment : GenericMainFragment() {
val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter) val headerItemDecoration = RecyclerViewHeaderDecoration(requireContext(), adapter)
binding.recordingsList.addItemDecoration(headerItemDecoration) binding.recordingsList.addItemDecoration(headerItemDecoration)
if (binding.recordingsList.adapter != adapter) {
binding.recordingsList.adapter = adapter
}
listViewModel.recordings.observe(viewLifecycleOwner) { listViewModel.recordings.observe(viewLifecycleOwner) {
val count = it.size val count = it.size
adapter.submitList(it) adapter.submitList(it)
// Wait for adapter to have items before setting it in the RecyclerView,
// otherwise scroll position isn't retained
if (binding.recordingsList.adapter != adapter) {
binding.recordingsList.adapter = adapter
}
Log.i("$TAG Recordings list ready with [$count] items") Log.i("$TAG Recordings list ready with [$count] items")
listViewModel.fetchInProgress.value = false listViewModel.fetchInProgress.value = false
} }