package org.mosad.teapod.ui.activity.main.fragments import android.annotation.SuppressLint import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.widget.SearchView import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlinx.coroutines.launch import org.mosad.teapod.databinding.FragmentLibraryBinding import org.mosad.teapod.ui.activity.main.viewmodel.LibraryFragmentViewModel import org.mosad.teapod.util.adapter.MediaItemListAdapter import org.mosad.teapod.util.showFragment class LibraryFragment : Fragment() { private lateinit var binding: FragmentLibraryBinding private lateinit var adapter: MediaItemListAdapter private val model: LibraryFragmentViewModel by viewModels() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { binding = FragmentLibraryBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // TODO replace with pagination3 // https://medium.com/swlh/paging3-recyclerview-pagination-made-easy-333c7dfa8797 binding.recyclerMediaSearch.addOnScrollListener(PaginationScrollListener()) adapter = MediaItemListAdapter(MediaItemListAdapter.OnClickListener { binding.searchText.clearFocus() activity?.showFragment(MediaFragment(it.id)) }) binding.recyclerMediaSearch.adapter = adapter binding.searchText.setOnQueryTextListener(object : SearchView.OnQueryTextListener { override fun onQueryTextSubmit(query: String?): Boolean { query?.let { model.search(it) } return false // return false to dismiss the keyboard } override fun onQueryTextChange(newText: String?): Boolean { newText?.let { model.search(it) } return false // return false to dismiss the keyboard } }) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { model.onUiState(viewLifecycleOwner.lifecycleScope) { uiState -> when (uiState) { is LibraryFragmentViewModel.UiState.Browse -> bindUiStateBrowse(uiState) is LibraryFragmentViewModel.UiState.Search -> bindUiStateSearch(uiState) is LibraryFragmentViewModel.UiState.Loading -> bindUiStateLoading() is LibraryFragmentViewModel.UiState.Error -> bindUiStateError(uiState) } } } } } private fun bindUiStateBrowse(uiState: LibraryFragmentViewModel.UiState.Browse) { adapter.submitList(uiState.itemList) } @SuppressLint("NotifyDataSetChanged") private fun bindUiStateSearch(uiState: LibraryFragmentViewModel.UiState.Search) { adapter.submitList(uiState.itemList) adapter.notifyDataSetChanged() // this is needed, else the adapter will not update } private fun bindUiStateLoading() { // currently not used } private fun bindUiStateError(uiState: LibraryFragmentViewModel.UiState.Error) { // currently not used Log.e(javaClass.name, "A error occurred while loading a UiState: ${uiState.message}") } inner class PaginationScrollListener: RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) if (!model.isLazyLoading) { val layoutManager = recyclerView.layoutManager as? GridLayoutManager layoutManager?.let { // adapter.itemCount - 10 to start loading a bit earlier than the actual end if (layoutManager.findLastCompletelyVisibleItemPosition() >= (adapter.itemCount - 10)) { model.onLazyLoad().invokeOnCompletion { adapter.notifyItemRangeInserted(adapter.itemCount, model.PAGESIZE) } } } } } } }