mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 00:10:32 +05:30
Use a ViewModel for the CommentsSheet
This commit is contained in:
parent
39a21ddab4
commit
0045e41902
@ -4,7 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
|||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
data class CommentsPage(
|
data class CommentsPage(
|
||||||
val comments: MutableList<Comment> = arrayListOf(),
|
var comments: MutableList<Comment> = arrayListOf(),
|
||||||
val disabled: Boolean? = null,
|
val disabled: Boolean? = null,
|
||||||
val nextpage: String? = null
|
val nextpage: String? = null
|
||||||
)
|
)
|
||||||
|
@ -36,7 +36,6 @@ import com.github.libretube.R
|
|||||||
import com.github.libretube.api.CronetHelper
|
import com.github.libretube.api.CronetHelper
|
||||||
import com.github.libretube.api.RetrofitInstance
|
import com.github.libretube.api.RetrofitInstance
|
||||||
import com.github.libretube.api.obj.ChapterSegment
|
import com.github.libretube.api.obj.ChapterSegment
|
||||||
import com.github.libretube.api.obj.Comment
|
|
||||||
import com.github.libretube.api.obj.PipedStream
|
import com.github.libretube.api.obj.PipedStream
|
||||||
import com.github.libretube.api.obj.Segment
|
import com.github.libretube.api.obj.Segment
|
||||||
import com.github.libretube.api.obj.SegmentData
|
import com.github.libretube.api.obj.SegmentData
|
||||||
@ -76,6 +75,7 @@ import com.github.libretube.ui.extensions.setFormattedHtml
|
|||||||
import com.github.libretube.ui.extensions.setInvisible
|
import com.github.libretube.ui.extensions.setInvisible
|
||||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.ui.interfaces.OnlinePlayerOptions
|
import com.github.libretube.ui.interfaces.OnlinePlayerOptions
|
||||||
|
import com.github.libretube.ui.models.CommentsViewModel
|
||||||
import com.github.libretube.ui.models.PlayerViewModel
|
import com.github.libretube.ui.models.PlayerViewModel
|
||||||
import com.github.libretube.ui.sheets.BaseBottomSheet
|
import com.github.libretube.ui.sheets.BaseBottomSheet
|
||||||
import com.github.libretube.ui.sheets.CommentsSheet
|
import com.github.libretube.ui.sheets.CommentsSheet
|
||||||
@ -124,6 +124,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
private lateinit var doubleTapOverlayBinding: DoubleTapOverlayBinding
|
private lateinit var doubleTapOverlayBinding: DoubleTapOverlayBinding
|
||||||
private lateinit var playerGestureControlsViewBinding: PlayerGestureControlsViewBinding
|
private lateinit var playerGestureControlsViewBinding: PlayerGestureControlsViewBinding
|
||||||
private val viewModel: PlayerViewModel by activityViewModels()
|
private val viewModel: PlayerViewModel by activityViewModels()
|
||||||
|
private val commentsViewModel: CommentsViewModel by activityViewModels()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* video information
|
* video information
|
||||||
@ -152,8 +153,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
* Chapters and comments
|
* Chapters and comments
|
||||||
*/
|
*/
|
||||||
private lateinit var chapters: List<ChapterSegment>
|
private lateinit var chapters: List<ChapterSegment>
|
||||||
private val comments: MutableList<Comment> = mutableListOf()
|
|
||||||
private var commentsNextPage: String? = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* for the player view
|
* for the player view
|
||||||
@ -330,15 +329,11 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.commentsToggle.setOnClickListener {
|
binding.commentsToggle.setOnClickListener {
|
||||||
CommentsSheet(
|
videoId ?: return@setOnClickListener
|
||||||
videoId!!,
|
// set the max height to not cover the currently playing video
|
||||||
comments,
|
commentsViewModel.maxHeight = binding.root.height - binding.player.height
|
||||||
commentsNextPage,
|
commentsViewModel.videoId = videoId
|
||||||
binding.root.height - binding.player.height
|
CommentsSheet().show(childFragmentManager)
|
||||||
) { comments, nextPage ->
|
|
||||||
this.comments.addAll(comments)
|
|
||||||
this.commentsNextPage = nextPage
|
|
||||||
}.show(childFragmentManager)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playerBinding.queueToggle.visibility = View.VISIBLE
|
playerBinding.queueToggle.visibility = View.VISIBLE
|
||||||
@ -604,6 +599,9 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
playerBinding.exoProgress.clearSegments()
|
playerBinding.exoProgress.clearSegments()
|
||||||
playerBinding.sbToggle.visibility = View.GONE
|
playerBinding.sbToggle.visibility = View.GONE
|
||||||
|
|
||||||
|
// reset the comments to become reloaded later
|
||||||
|
commentsViewModel.reset()
|
||||||
|
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
streams = try {
|
streams = try {
|
||||||
RetrofitInstance.api.getStreams(videoId!!)
|
RetrofitInstance.api.getStreams(videoId!!)
|
||||||
@ -754,10 +752,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
if (nextVideoId != null) {
|
if (nextVideoId != null) {
|
||||||
videoId = nextVideoId
|
videoId = nextVideoId
|
||||||
|
|
||||||
// reset the comments to be reloaded later
|
|
||||||
comments.clear()
|
|
||||||
commentsNextPage = null
|
|
||||||
|
|
||||||
// play the next video
|
// play the next video
|
||||||
playVideo()
|
playVideo()
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.github.libretube.ui.models
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.github.libretube.api.RetrofitInstance
|
||||||
|
import com.github.libretube.api.obj.CommentsPage
|
||||||
|
import com.github.libretube.extensions.TAG
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class CommentsViewModel : ViewModel() {
|
||||||
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
|
private var isLoading = false
|
||||||
|
|
||||||
|
val commentsPage = MutableLiveData<CommentsPage?>()
|
||||||
|
|
||||||
|
private var nextPage: String? = null
|
||||||
|
|
||||||
|
var videoId: String? = null
|
||||||
|
var maxHeight: Int = 0
|
||||||
|
|
||||||
|
fun fetchComments() {
|
||||||
|
videoId ?: return
|
||||||
|
scope.launch {
|
||||||
|
isLoading = true
|
||||||
|
val response = try {
|
||||||
|
RetrofitInstance.api.getComments(videoId!!)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG(), e.toString())
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
nextPage = response.nextpage
|
||||||
|
commentsPage.postValue(response)
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fetchNextComments() {
|
||||||
|
if (isLoading || nextPage == null || videoId == null) return
|
||||||
|
scope.launch {
|
||||||
|
isLoading = true
|
||||||
|
val response = try {
|
||||||
|
RetrofitInstance.api.getCommentsNextPage(videoId!!, nextPage!!)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG(), e.toString())
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
val updatedPage = commentsPage.value?.apply {
|
||||||
|
comments = comments.plus(response.comments).toMutableList()
|
||||||
|
}
|
||||||
|
nextPage = response.nextpage
|
||||||
|
commentsPage.postValue(updatedPage)
|
||||||
|
isLoading = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
isLoading = false
|
||||||
|
nextPage = null
|
||||||
|
commentsPage.value = null
|
||||||
|
videoId = null
|
||||||
|
}
|
||||||
|
}
|
@ -1,32 +1,22 @@
|
|||||||
package com.github.libretube.ui.sheets
|
package com.github.libretube.ui.sheets
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
|
||||||
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.lifecycle.lifecycleScope
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.RetrofitInstance
|
|
||||||
import com.github.libretube.api.obj.Comment
|
|
||||||
import com.github.libretube.databinding.CommentsSheetBinding
|
import com.github.libretube.databinding.CommentsSheetBinding
|
||||||
import com.github.libretube.extensions.TAG
|
|
||||||
import com.github.libretube.ui.adapters.CommentsAdapter
|
import com.github.libretube.ui.adapters.CommentsAdapter
|
||||||
import kotlinx.coroutines.Dispatchers
|
import com.github.libretube.ui.models.CommentsViewModel
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
class CommentsSheet(
|
class CommentsSheet : ExpandedBottomSheet() {
|
||||||
private val videoId: String,
|
|
||||||
private val comments: List<Comment>,
|
|
||||||
private var nextPage: String?,
|
|
||||||
private val maxHeight: Int,
|
|
||||||
private val onMoreComments: (comments: List<Comment>, nextPage: String?) -> Unit
|
|
||||||
) : ExpandedBottomSheet() {
|
|
||||||
private lateinit var binding: CommentsSheetBinding
|
private lateinit var binding: CommentsSheetBinding
|
||||||
|
|
||||||
private lateinit var commentsAdapter: CommentsAdapter
|
private lateinit var commentsAdapter: CommentsAdapter
|
||||||
private var isLoading = false
|
|
||||||
|
private val viewModel: CommentsViewModel by activityViewModels()
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -35,7 +25,7 @@ class CommentsSheet(
|
|||||||
): View {
|
): View {
|
||||||
binding = CommentsSheetBinding.inflate(layoutInflater)
|
binding = CommentsSheetBinding.inflate(layoutInflater)
|
||||||
// set a fixed maximum height
|
// set a fixed maximum height
|
||||||
binding.root.maxHeight = maxHeight
|
binding.root.maxHeight = viewModel.maxHeight
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,62 +38,40 @@ class CommentsSheet(
|
|||||||
binding.commentsRV.viewTreeObserver
|
binding.commentsRV.viewTreeObserver
|
||||||
.addOnScrollChangedListener {
|
.addOnScrollChangedListener {
|
||||||
if (!binding.commentsRV.canScrollVertically(1)) {
|
if (!binding.commentsRV.canScrollVertically(1)) {
|
||||||
fetchNextComments()
|
viewModel.fetchNextComments()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commentsAdapter = CommentsAdapter(videoId, comments.toMutableList()) {
|
commentsAdapter = CommentsAdapter(
|
||||||
|
viewModel.videoId!!,
|
||||||
|
viewModel.commentsPage.value?.comments.orEmpty().toMutableList()
|
||||||
|
) {
|
||||||
dialog?.dismiss()
|
dialog?.dismiss()
|
||||||
}
|
}
|
||||||
binding.commentsRV.adapter = commentsAdapter
|
binding.commentsRV.adapter = commentsAdapter
|
||||||
|
|
||||||
if (comments.isEmpty()) fetchComments()
|
if (viewModel.commentsPage.value?.comments.orEmpty().isEmpty()) {
|
||||||
}
|
binding.progress.visibility = View.VISIBLE
|
||||||
|
viewModel.fetchComments()
|
||||||
private fun fetchComments() {
|
|
||||||
binding.progress.visibility = View.VISIBLE
|
|
||||||
lifecycleScope.launchWhenCreated {
|
|
||||||
isLoading = true
|
|
||||||
val response = try {
|
|
||||||
RetrofitInstance.api.getComments(videoId)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
return@launchWhenCreated
|
|
||||||
}
|
|
||||||
binding.progress.visibility = View.GONE
|
|
||||||
if (response.disabled == true) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
binding.errorTV.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
return@launchWhenCreated
|
|
||||||
}
|
|
||||||
if (response.comments.isEmpty()) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
binding.errorTV.text = getString(R.string.no_comments_available)
|
|
||||||
binding.errorTV.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
return@launchWhenCreated
|
|
||||||
}
|
|
||||||
commentsAdapter.updateItems(response.comments)
|
|
||||||
nextPage = response.nextpage
|
|
||||||
onMoreComments.invoke(response.comments, response.nextpage)
|
|
||||||
isLoading = false
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchNextComments() {
|
// listen for new comments to be loaded
|
||||||
if (isLoading || nextPage == null) return
|
viewModel.commentsPage.observe(viewLifecycleOwner) {
|
||||||
lifecycleScope.launchWhenCreated {
|
it ?: return@observe
|
||||||
isLoading = true
|
binding.progress.visibility = View.GONE
|
||||||
val response = try {
|
if (it.disabled == true) {
|
||||||
RetrofitInstance.api.getCommentsNextPage(videoId, nextPage!!)
|
binding.errorTV.visibility = View.VISIBLE
|
||||||
} catch (e: Exception) {
|
return@observe
|
||||||
Log.e(TAG(), e.toString())
|
|
||||||
return@launchWhenCreated
|
|
||||||
}
|
}
|
||||||
nextPage = response.nextpage
|
if (it.comments.isEmpty()) {
|
||||||
commentsAdapter.updateItems(response.comments)
|
binding.errorTV.text = getString(R.string.no_comments_available)
|
||||||
onMoreComments.invoke(response.comments, response.nextpage)
|
binding.errorTV.visibility = View.VISIBLE
|
||||||
isLoading = false
|
return@observe
|
||||||
|
}
|
||||||
|
commentsAdapter.updateItems(
|
||||||
|
// only add the new comments to the recycler view
|
||||||
|
it.comments.subList(commentsAdapter.itemCount, it.comments.size)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user