refactor: remove callbacks on CommentsSheet

storing fragment callbacks in viewmodels is considered a bad practice because
view models survive longer than fragments
This commit is contained in:
Bnyro 2024-05-20 15:59:17 +02:00
parent 131d2a39cc
commit dc6563800f
7 changed files with 47 additions and 25 deletions

View File

@ -8,6 +8,7 @@ object IntentData {
const val videoIds = "videoIds" const val videoIds = "videoIds"
const val channelId = "channelId" const val channelId = "channelId"
const val channelName = "channelName" const val channelName = "channelName"
const val channelAvatar = "channelAvatar"
const val playlistId = "playlistId" const val playlistId = "playlistId"
const val timeStamp = "timeStamp" const val timeStamp = "timeStamp"
const val playlistType = "playlistType" const val playlistType = "playlistType"

View File

@ -47,7 +47,11 @@ class CommentPagingAdapter(
return return
} }
val args = bundleOf(IntentData.videoId to videoId, IntentData.comment to comment) val args = bundleOf(
IntentData.videoId to videoId,
IntentData.comment to comment,
IntentData.channelAvatar to channelAvatar
)
fragment!!.parentFragmentManager.commit { fragment!!.parentFragmentManager.commit {
replace<CommentsRepliesFragment>(R.id.commentFragContainer, args = args) replace<CommentsRepliesFragment>(R.id.commentFragContainer, args = args)
addToBackStack(null) addToBackStack(null)

View File

@ -5,15 +5,18 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import androidx.core.os.bundleOf
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
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import androidx.paging.LoadState import androidx.paging.LoadState
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.FragmentCommentsBinding import com.github.libretube.databinding.FragmentCommentsBinding
import com.github.libretube.extensions.formatShort import com.github.libretube.extensions.formatShort
import com.github.libretube.ui.adapters.CommentPagingAdapter import com.github.libretube.ui.adapters.CommentPagingAdapter
@ -68,10 +71,12 @@ class CommentsMainFragment : Fragment() {
val commentPagingAdapter = CommentPagingAdapter( val commentPagingAdapter = CommentPagingAdapter(
this, this,
viewModel.videoIdLiveData.value ?: return, viewModel.videoIdLiveData.value ?: return,
viewModel.channelAvatar ?: return, requireArguments().getString(IntentData.channelAvatar) ?: return,
handleLink = viewModel.handleLink handleLink = {
setFragmentResult(CommentsSheet.HANDLE_LINK_REQUEST_KEY, bundleOf(IntentData.url to it))
}
) { ) {
viewModel.commentsSheetDismiss?.invoke() setFragmentResult(CommentsSheet.DISMISS_SHEET_REQUEST_KEY, bundleOf())
} }
binding.commentsRV.adapter = commentPagingAdapter binding.commentsRV.adapter = commentPagingAdapter

View File

@ -5,11 +5,13 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import androidx.core.os.bundleOf
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
@ -60,13 +62,15 @@ class CommentsRepliesFragment : Fragment() {
val repliesAdapter = CommentPagingAdapter( val repliesAdapter = CommentPagingAdapter(
null, null,
videoId, videoId,
viewModel.channelAvatar, requireArguments().getString(IntentData.channelAvatar) ?: return,
isRepliesAdapter = true, isRepliesAdapter = true,
handleLink = viewModel.handleLink handleLink = {
setFragmentResult(CommentsSheet.HANDLE_LINK_REQUEST_KEY, bundleOf(IntentData.url to it))
}
) { ) {
viewModel.commentsSheetDismiss?.invoke() setFragmentResult(CommentsSheet.DISMISS_SHEET_REQUEST_KEY, bundleOf())
} }
(parentFragment as CommentsSheet).updateFragmentInfo( commentsSheet?.updateFragmentInfo(
true, true,
"${getString(R.string.replies)} (${comment.replyCount.formatShort()})" "${getString(R.string.replies)} (${comment.replyCount.formatShort()})"
) )

View File

@ -525,14 +525,19 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
exoPlayer.togglePlayPauseState() exoPlayer.togglePlayPauseState()
} }
activity?.supportFragmentManager
?.setFragmentResultListener(CommentsSheet.HANDLE_LINK_REQUEST_KEY, viewLifecycleOwner) { _, bundle ->
bundle.getString(IntentData.url)?.let { handleLink(it) }
}
binding.commentsToggle.setOnClickListener { binding.commentsToggle.setOnClickListener {
if (!this::streams.isInitialized) return@setOnClickListener if (!this::streams.isInitialized) return@setOnClickListener
// set the max height to not cover the currently playing video // set the max height to not cover the currently playing video
commentsViewModel.handleLink = this::handleLink
updateMaxSheetHeight() updateMaxSheetHeight()
commentsViewModel.videoIdLiveData.updateIfChanged(videoId) commentsViewModel.videoIdLiveData.updateIfChanged(videoId)
commentsViewModel.channelAvatar = streams.uploaderAvatar CommentsSheet()
CommentsSheet().show(childFragmentManager) .apply { arguments = bundleOf(IntentData.channelAvatar to streams.uploaderAvatar) }
.show(childFragmentManager)
} }
// FullScreen button trigger // FullScreen button trigger
@ -639,7 +644,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
private fun updateMaxSheetHeight() { private fun updateMaxSheetHeight() {
val maxHeight = binding.root.height - binding.player.height val maxHeight = binding.root.height - binding.player.height
viewModel.maxSheetHeightPx = viewModel.maxSheetHeightPx viewModel.maxSheetHeightPx = maxHeight
chaptersViewModel.maxSheetHeightPx = maxHeight chaptersViewModel.maxSheetHeightPx = maxHeight
} }
@ -1022,7 +1027,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
playVideo() playVideo()
// close comment bottom sheet if opened for next video // close comment bottom sheet if opened for next video
runCatching { commentsViewModel.commentsSheetDismiss?.invoke() } activity?.supportFragmentManager?.fragments?.filterIsInstance<CommentsSheet>()
?.firstOrNull()?.dismiss()
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")

View File

@ -26,17 +26,12 @@ class CommentsViewModel : ViewModel() {
val commentSheetExpand = MutableLiveData<Boolean?>() val commentSheetExpand = MutableLiveData<Boolean?>()
var channelAvatar: String? = null
var handleLink: ((url: String) -> Unit)? = null
private val _currentCommentsPosition = MutableLiveData(0) private val _currentCommentsPosition = MutableLiveData(0)
val currentCommentsPosition: LiveData<Int> = _currentCommentsPosition val currentCommentsPosition: LiveData<Int> = _currentCommentsPosition
private val _currentRepliesPosition = MutableLiveData(0) private val _currentRepliesPosition = MutableLiveData(0)
val currentRepliesPosition: LiveData<Int> = _currentRepliesPosition val currentRepliesPosition: LiveData<Int> = _currentRepliesPosition
var commentsSheetDismiss: (() -> Unit)? = null
fun setCommentSheetExpand(value: Boolean?) { fun setCommentSheetExpand(value: Boolean?) {
if (commentSheetExpand.value != value) { if (commentSheetExpand.value != value) {
commentSheetExpand.value = value commentSheetExpand.value = value

View File

@ -1,6 +1,5 @@
package com.github.libretube.ui.sheets package com.github.libretube.ui.sheets
import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -9,6 +8,7 @@ import androidx.core.view.isVisible
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.fragment.app.commit import androidx.fragment.app.commit
import androidx.fragment.app.replace import androidx.fragment.app.replace
import androidx.fragment.app.setFragmentResult
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.databinding.CommentsSheetBinding import com.github.libretube.databinding.CommentsSheetBinding
import com.github.libretube.ui.fragments.CommentsMainFragment import com.github.libretube.ui.fragments.CommentsMainFragment
@ -34,10 +34,17 @@ class CommentsSheet : UndimmedBottomSheet() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
commentsViewModel.commentsSheetDismiss = this::dismiss
val binding = binding val binding = binding
childFragmentManager.setFragmentResultListener(DISMISS_SHEET_REQUEST_KEY, viewLifecycleOwner) { _, _ ->
dismiss()
}
// forward requests to open links to the parent fragment
childFragmentManager.setFragmentResultListener(HANDLE_LINK_REQUEST_KEY, viewLifecycleOwner) { key, result ->
parentFragment?.setFragmentResult(key, result)
}
binding.btnBack.setOnClickListener { binding.btnBack.setOnClickListener {
if (childFragmentManager.backStackEntryCount > 0) { if (childFragmentManager.backStackEntryCount > 0) {
childFragmentManager.popBackStack() childFragmentManager.popBackStack()
@ -47,7 +54,7 @@ class CommentsSheet : UndimmedBottomSheet() {
binding.btnClose.setOnClickListener { dismiss() } binding.btnClose.setOnClickListener { dismiss() }
childFragmentManager.commit { childFragmentManager.commit {
replace<CommentsMainFragment>(R.id.commentFragContainer) replace<CommentsMainFragment>(R.id.commentFragContainer, args = arguments)
} }
commentsViewModel.setCommentSheetExpand(true) commentsViewModel.setCommentSheetExpand(true)
@ -76,8 +83,8 @@ class CommentsSheet : UndimmedBottomSheet() {
binding.commentsTitle.text = title binding.commentsTitle.text = title
} }
override fun onDismiss(dialog: DialogInterface) { companion object {
super.onDismiss(dialog) const val HANDLE_LINK_REQUEST_KEY = "handle_link_request_key"
commentsViewModel.commentsSheetDismiss = null const val DISMISS_SHEET_REQUEST_KEY = "dismiss_sheet_request_key"
} }
} }