From 3b6ccdb91dba259451198a0d13f8c16e1ecf8252 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Sun, 5 Feb 2023 06:01:12 +0530 Subject: [PATCH] Convert SearchAdapter to a ListAdapter. --- .../libretube/ui/adapters/SearchAdapter.kt | 47 ++++++++----------- .../libretube/ui/fragments/ChannelFragment.kt | 32 ++++++------- .../ui/fragments/SearchResultFragment.kt | 33 +++++++------ 3 files changed, 53 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt index 03c983b24..05f5f11f1 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt @@ -4,7 +4,8 @@ import android.annotation.SuppressLint import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter import com.github.libretube.R import com.github.libretube.api.obj.ContentItem import com.github.libretube.databinding.ChannelRowBinding @@ -25,21 +26,7 @@ import com.github.libretube.ui.sheets.VideoOptionsBottomSheet import com.github.libretube.ui.viewholders.SearchViewHolder import com.github.libretube.util.TextUtils -class SearchAdapter( - private val searchItems: MutableList -) : - RecyclerView.Adapter() { - - fun updateItems(newItems: List) { - val searchItemsSize = searchItems.size - searchItems.addAll(newItems) - notifyItemRangeInserted(searchItemsSize, newItems.size) - } - - override fun getItemCount(): Int { - return searchItems.size - } - +class SearchAdapter : ListAdapter(SearchCallback) { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder { val layoutInflater = LayoutInflater.from(parent.context) @@ -58,7 +45,7 @@ class SearchAdapter( } override fun onBindViewHolder(holder: SearchViewHolder, position: Int) { - val searchItem = searchItems[position] + val searchItem = currentList[position] val videoRowBinding = holder.videoRowBinding val channelRowBinding = holder.channelRowBinding @@ -68,11 +55,13 @@ class SearchAdapter( bindWatch(searchItem, videoRowBinding) } else if (channelRowBinding != null) { bindChannel(searchItem, channelRowBinding) - } else if (playlistRowBinding != null) bindPlaylist(searchItem, playlistRowBinding) + } else if (playlistRowBinding != null) { + bindPlaylist(searchItem, playlistRowBinding) + } } override fun getItemViewType(position: Int): Int { - return when (searchItems[position].type) { + return when (currentList[position].type) { "stream" -> 0 "channel" -> 1 "playlist" -> 2 @@ -116,10 +105,7 @@ class SearchAdapter( } @SuppressLint("SetTextI18n") - private fun bindChannel( - item: ContentItem, - binding: ChannelRowBinding - ) { + private fun bindChannel(item: ContentItem, binding: ChannelRowBinding) { binding.apply { ImageHelper.loadImage(item.thumbnail, searchChannelImage) searchChannelName.text = item.name @@ -144,10 +130,7 @@ class SearchAdapter( } } - private fun bindPlaylist( - item: ContentItem, - binding: PlaylistsRowBinding - ) { + private fun bindPlaylist(item: ContentItem, binding: PlaylistsRowBinding) { binding.apply { ImageHelper.loadImage(item.thumbnail, playlistThumbnail) if (item.videos != -1L) videoCount.text = item.videos.toString() @@ -169,4 +152,14 @@ class SearchAdapter( } } } + + private object SearchCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: ContentItem, newItem: ContentItem): Boolean { + return oldItem.url == newItem.url + } + + override fun areContentsTheSame(oldItem: ContentItem, newItem: ContentItem): Boolean { + return true + } + } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt index af260aa24..b0cf372dd 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt @@ -28,9 +28,9 @@ import com.github.libretube.ui.base.BaseFragment import com.github.libretube.ui.dialogs.ShareDialog import com.github.libretube.ui.extensions.setupSubscriptionButton import java.io.IOException -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import retrofit2.HttpException class ChannelFragment : BaseFragment() { @@ -45,8 +45,6 @@ class ChannelFragment : BaseFragment() { private var onScrollEnd: () -> Unit = {} - private val scope = CoroutineScope(Dispatchers.IO) - val possibleTabs = listOf( ChannelTabs.Channels, ChannelTabs.Playlists, @@ -227,18 +225,18 @@ class ChannelFragment : BaseFragment() { } private fun loadTab(tab: ChannelTab) { - scope.launch { + lifecycleScope.launch { val response = try { - RetrofitInstance.api.getChannelTab(tab.data) + withContext(Dispatchers.IO) { + RetrofitInstance.api.getChannelTab(tab.data) + } } catch (e: Exception) { return@launch } - val adapter = SearchAdapter(response.content.toMutableList()) - - runOnUiThread { - binding.channelRecView.adapter = adapter - } + val adapter = SearchAdapter() + binding.channelRecView.adapter = adapter + adapter.submitList(response.content) var tabNextPage = response.nextpage onScrollEnd = { @@ -284,18 +282,18 @@ class ChannelFragment : BaseFragment() { adapter: SearchAdapter, onNewNextPage: (String?) -> Unit ) { - scope.launch { + lifecycleScope.launch { val newContent = try { - RetrofitInstance.api.getChannelTab(tab.data, nextPage) + withContext(Dispatchers.IO) { + RetrofitInstance.api.getChannelTab(tab.data, nextPage) + } } catch (e: Exception) { Log.e(TAG(), "Exception: $e") null } - onNewNextPage.invoke(newContent?.nextpage) - runOnUiThread { - newContent?.content?.let { - adapter.updateItems(it) - } + onNewNextPage(newContent?.nextpage) + newContent?.content?.let { + adapter.submitList(adapter.currentList + it) } } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt index e44b0dae6..860b019cd 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt @@ -19,6 +19,8 @@ import com.github.libretube.extensions.hideKeyboard import com.github.libretube.helpers.PreferenceHelper import com.github.libretube.ui.adapters.SearchAdapter import com.github.libretube.ui.base.BaseFragment +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import java.io.IOException import retrofit2.HttpException @@ -85,7 +87,9 @@ class SearchResultFragment : BaseFragment() { lifecycleScope.launchWhenCreated { view?.let { context?.hideKeyboard(it) } val response = try { - RetrofitInstance.api.getSearchResults(query, apiSearchFilter) + withContext(Dispatchers.IO) { + RetrofitInstance.api.getSearchResults(query, apiSearchFilter) + } } catch (e: IOException) { println(e) Log.e(TAG(), "IOException, you might not have internet connection $e") @@ -94,11 +98,10 @@ class SearchResultFragment : BaseFragment() { Log.e(TAG(), "HttpException, unexpected response") return@launchWhenCreated } - runOnUiThread { - searchAdapter = SearchAdapter(response.items.toMutableList()) - binding.searchRecycler.adapter = searchAdapter - binding.noSearchResult.isVisible = response.items.isEmpty() - } + searchAdapter = SearchAdapter() + binding.searchRecycler.adapter = searchAdapter + searchAdapter.submitList(response.items) + binding.noSearchResult.isVisible = response.items.isEmpty() nextPage = response.nextpage } } @@ -106,11 +109,13 @@ class SearchResultFragment : BaseFragment() { private fun fetchNextSearchItems() { lifecycleScope.launchWhenCreated { val response = try { - RetrofitInstance.api.getSearchResultsNextPage( - query, - apiSearchFilter, - nextPage!! - ) + withContext(Dispatchers.IO) { + RetrofitInstance.api.getSearchResultsNextPage( + query, + apiSearchFilter, + nextPage!! + ) + } } catch (e: IOException) { println(e) Log.e(TAG(), "IOException, you might not have internet connection") @@ -120,10 +125,8 @@ class SearchResultFragment : BaseFragment() { return@launchWhenCreated } nextPage = response.nextpage!! - kotlin.runCatching { - if (response.items.isNotEmpty()) { - searchAdapter.updateItems(response.items) - } + if (response.items.isNotEmpty()) { + searchAdapter.submitList(searchAdapter.currentList + response.items) } } }