refactor: simplify logic of loading comments and replies

This commit is contained in:
Bnyro 2023-11-17 15:10:02 +01:00
parent 73d12036f4
commit 155682bccc
4 changed files with 52 additions and 39 deletions

View File

@ -4,7 +4,6 @@ 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.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
@ -72,23 +71,26 @@ class CommentsMainFragment : Fragment() {
} }
binding.commentsRV.adapter = commentsAdapter binding.commentsRV.adapter = commentsAdapter
if (viewModel.commentsPage.value?.comments.orEmpty().isEmpty()) { if (viewModel.commentsPage.value?.comments.isNullOrEmpty()) {
binding.progress.isVisible = true
viewModel.fetchComments() viewModel.fetchComments()
} else { } else {
binding.commentsRV.scrollToPosition(viewModel.currentCommentsPosition) binding.commentsRV.scrollToPosition(viewModel.currentCommentsPosition)
} }
viewModel.isLoading.observe(viewLifecycleOwner) {
_binding?.progress?.isVisible = it == true
}
// listen for new comments to be loaded // listen for new comments to be loaded
viewModel.commentsPage.observe(viewLifecycleOwner) { viewModel.commentsPage.observe(viewLifecycleOwner) {
if (it == null) return@observe
val viewBinding = _binding ?: return@observe val viewBinding = _binding ?: return@observe
if (it == null) return@observe
viewBinding.progress.isGone = true
if (it.disabled) { if (it.disabled) {
viewBinding.errorTV.isVisible = true viewBinding.errorTV.isVisible = true
return@observe return@observe
} }
commentsSheet?.updateFragmentInfo( commentsSheet?.updateFragmentInfo(
false, false,
"${getString(R.string.comments)} (${it.commentCount.formatShort()})" "${getString(R.string.comments)} (${it.commentCount.formatShort()})"

View File

@ -82,13 +82,11 @@ class CommentsRepliesFragment : Fragment() {
::repliesPage.isInitialized && ::repliesPage.isInitialized &&
repliesPage.nextpage != null repliesPage.nextpage != null
) { ) {
fetchReplies(videoId, repliesPage.nextpage!!) { fetchReplies(videoId, repliesPage.nextpage!!)
repliesAdapter.updateItems(repliesPage.comments)
}
} }
} }
loadInitialReplies(videoId, comment.repliesPage.orEmpty(), repliesAdapter) loadInitialReplies(videoId, comment.repliesPage.orEmpty())
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -98,34 +96,32 @@ class CommentsRepliesFragment : Fragment() {
private fun loadInitialReplies( private fun loadInitialReplies(
videoId: String, videoId: String,
nextPage: String, nextPage: String
repliesAdapter: CommentsAdapter
) { ) {
_binding?.progress?.isVisible = true _binding?.progress?.isVisible = true
fetchReplies(videoId, nextPage) { fetchReplies(videoId, nextPage)
repliesAdapter.updateItems(it.comments)
_binding?.progress?.isGone = true
}
} }
private fun fetchReplies( private fun fetchReplies(videoId: String, nextPage: String) {
videoId: String, _binding?.progress?.isVisible = true
nextPage: String,
onFinished: (CommentsPage) -> Unit lifecycleScope.launch {
) {
lifecycleScope.launch(Dispatchers.IO) {
if (isLoading) return@launch if (isLoading) return@launch
isLoading = true isLoading = true
repliesPage = try { repliesPage = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getCommentsNextPage(videoId, nextPage) RetrofitInstance.api.getCommentsNextPage(videoId, nextPage)
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG(), "IOException, you might not have internet connection") Log.e(TAG(), "IOException, you might not have internet connection")
return@launch return@launch
} finally {
_binding?.progress?.isGone = true
} }
repliesPage.comments = repliesPage.comments.filterNonEmptyComments() repliesPage.comments = repliesPage.comments.filterNonEmptyComments()
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
onFinished.invoke(repliesPage) repliesAdapter.updateItems(repliesPage.comments)
} }
isLoading = false isLoading = false
} }

View File

@ -10,6 +10,7 @@ import com.github.libretube.extensions.TAG
import com.github.libretube.ui.extensions.filterNonEmptyComments import com.github.libretube.ui.extensions.filterNonEmptyComments
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class CommentsViewModel : ViewModel() { class CommentsViewModel : ViewModel() {
val commentsPage = MutableLiveData<CommentsPage?>() val commentsPage = MutableLiveData<CommentsPage?>()
@ -17,11 +18,12 @@ class CommentsViewModel : ViewModel() {
var videoId: String? = null var videoId: String? = null
var channelAvatar: String? = null var channelAvatar: String? = null
var handleLink: ((url: String) -> Unit)? = null
private var nextPage: String? = null private var nextPage: String? = null
private var isLoading = false var isLoading = MutableLiveData<Boolean>()
var currentCommentsPosition = 0 var currentCommentsPosition = 0
var commentsSheetDismiss: (() -> Unit)? = null var commentsSheetDismiss: (() -> Unit)? = null
var handleLink: ((url: String) -> Unit)? = null
fun setCommentSheetExpand(value: Boolean?) { fun setCommentSheetExpand(value: Boolean?) {
if (commentSheetExpand.value != value) { if (commentSheetExpand.value != value) {
@ -30,31 +32,43 @@ class CommentsViewModel : ViewModel() {
} }
fun fetchComments() { fun fetchComments() {
videoId ?: return val videoId = videoId ?: return
viewModelScope.launch(Dispatchers.IO) {
isLoading = true isLoading.value = true
viewModelScope.launch {
val response = try { val response = try {
RetrofitInstance.api.getComments(videoId!!) withContext(Dispatchers.IO) {
RetrofitInstance.api.getComments(videoId)
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG(), e.toString()) Log.e(TAG(), e.toString())
return@launch return@launch
} finally {
isLoading.value = false
} }
nextPage = response.nextpage nextPage = response.nextpage
response.comments = response.comments.filterNonEmptyComments() response.comments = response.comments.filterNonEmptyComments()
commentsPage.postValue(response) commentsPage.postValue(response)
isLoading = false
} }
} }
fun fetchNextComments() { fun fetchNextComments() {
if (isLoading || nextPage == null || videoId == null) return if (isLoading.value == true || nextPage == null || videoId == null) return
viewModelScope.launch(Dispatchers.IO) {
isLoading = true isLoading.value = true
viewModelScope.launch {
val response = try { val response = try {
withContext(Dispatchers.IO) {
RetrofitInstance.api.getCommentsNextPage(videoId!!, nextPage!!) RetrofitInstance.api.getCommentsNextPage(videoId!!, nextPage!!)
}
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG(), e.toString()) Log.e(TAG(), e.toString())
return@launch return@launch
} finally {
isLoading.value = false
} }
val updatedPage = commentsPage.value?.apply { val updatedPage = commentsPage.value?.apply {
@ -65,12 +79,11 @@ class CommentsViewModel : ViewModel() {
nextPage = response.nextpage nextPage = response.nextpage
commentsPage.postValue(updatedPage) commentsPage.postValue(updatedPage)
isLoading = false
} }
} }
fun reset() { fun reset() {
isLoading = false isLoading.value = false
nextPage = null nextPage = null
commentsPage.value = null commentsPage.value = null
videoId = null videoId = null

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/commentsRV" android:id="@+id/commentsRV"
@ -15,6 +16,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginTop="20dp"
android:visibility="gone" /> android:visibility="gone" />
<TextView <TextView
@ -26,4 +28,4 @@
android:text="@string/comments_disabled" android:text="@string/comments_disabled"
android:visibility="gone" /> android:visibility="gone" />
</FrameLayout> </LinearLayout>