mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 15:30:31 +05:30
refactor: split video and trending layout into different adapters
This commit is contained in:
parent
ca56ab6a11
commit
77515bf55a
@ -0,0 +1,119 @@
|
||||
package com.github.libretube.ui.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.AllCaughtUpRowBinding
|
||||
import com.github.libretube.databinding.TrendingRowBinding
|
||||
import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
import com.github.libretube.ui.adapters.callbacks.DiffUtilItemCallback
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.extensions.setFormattedDuration
|
||||
import com.github.libretube.ui.extensions.setWatchProgressLength
|
||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.VideoCardsViewHolder
|
||||
import com.github.libretube.util.TextUtils
|
||||
|
||||
class VideoCardsAdapter(private val columnWidthDp: Float? = null) :
|
||||
ListAdapter<StreamItem, VideoCardsViewHolder>(DiffUtilItemCallback()) {
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (currentList[position].type == CAUGHT_UP_STREAM_TYPE) CAUGHT_UP_TYPE else NORMAL_TYPE
|
||||
}
|
||||
|
||||
fun removeItemById(videoId: String) {
|
||||
val index = currentList.indexOfFirst {
|
||||
it.url?.toID() == videoId
|
||||
}.takeIf { it > 0 } ?: return
|
||||
val updatedList = currentList.toMutableList().also {
|
||||
it.removeAt(index)
|
||||
}
|
||||
|
||||
submitList(updatedList)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideoCardsViewHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
return when {
|
||||
viewType == CAUGHT_UP_TYPE -> VideoCardsViewHolder(
|
||||
AllCaughtUpRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
|
||||
else -> VideoCardsViewHolder(
|
||||
TrendingRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onBindViewHolder(holder: VideoCardsViewHolder, position: Int) {
|
||||
val video = getItem(holder.bindingAdapterPosition)
|
||||
val videoId = video.url.orEmpty().toID()
|
||||
|
||||
val context = (holder.trendingRowBinding ?: holder.allCaughtUpBinding)!!.root.context
|
||||
val activity = (context as BaseActivity)
|
||||
val fragmentManager = activity.supportFragmentManager
|
||||
|
||||
holder.trendingRowBinding?.apply {
|
||||
// set a fixed width for better visuals
|
||||
if (columnWidthDp != null) {
|
||||
root.updateLayoutParams {
|
||||
width = columnWidthDp.dpToPx()
|
||||
}
|
||||
}
|
||||
watchProgress.setWatchProgressLength(videoId, video.duration ?: 0L)
|
||||
|
||||
textViewTitle.text = video.title
|
||||
textViewChannel.text = TextUtils.formatViewsString(
|
||||
root.context,
|
||||
video.views ?: -1,
|
||||
video.uploaded,
|
||||
video.uploaderName
|
||||
)
|
||||
|
||||
video.duration?.let {
|
||||
thumbnailDuration.setFormattedDuration(
|
||||
it,
|
||||
video.isShort,
|
||||
video.uploaded
|
||||
)
|
||||
}
|
||||
channelImage.setOnClickListener {
|
||||
NavigationHelper.navigateChannel(root.context, video.uploaderUrl)
|
||||
}
|
||||
ImageHelper.loadImage(video.thumbnail, thumbnail)
|
||||
ImageHelper.loadImage(video.uploaderAvatar, channelImage, true)
|
||||
root.setOnClickListener {
|
||||
NavigationHelper.navigateVideo(root.context, videoId)
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
fragmentManager.setFragmentResultListener(
|
||||
VideoOptionsBottomSheet.VIDEO_OPTIONS_SHEET_REQUEST_KEY,
|
||||
activity
|
||||
) { _, _ ->
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
val sheet = VideoOptionsBottomSheet()
|
||||
sheet.arguments = bundleOf(IntentData.streamItem to video)
|
||||
sheet.show(fragmentManager, VideoCardsAdapter::class.java.name)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NORMAL_TYPE = 0
|
||||
private const val CAUGHT_UP_TYPE = 1
|
||||
|
||||
const val CAUGHT_UP_STREAM_TYPE = "caught"
|
||||
}
|
||||
}
|
@ -6,15 +6,11 @@ import android.view.ViewGroup
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.constants.IntentData
|
||||
import com.github.libretube.databinding.AllCaughtUpRowBinding
|
||||
import com.github.libretube.databinding.TrendingRowBinding
|
||||
import com.github.libretube.databinding.VideoRowBinding
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.extensions.dpToPx
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.helpers.ImageHelper
|
||||
import com.github.libretube.helpers.NavigationHelper
|
||||
@ -31,13 +27,9 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class VideosAdapter(
|
||||
private val forceMode: LayoutMode = LayoutMode.RESPECT_PREF
|
||||
private val showChannelInfo: Boolean = true
|
||||
) : ListAdapter<StreamItem, VideosViewHolder>(DiffUtilItemCallback()) {
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (currentList[position].type == CAUGHT_UP_STREAM_TYPE) CAUGHT_UP_TYPE else NORMAL_TYPE
|
||||
}
|
||||
|
||||
fun insertItems(newItems: List<StreamItem>) {
|
||||
val updatedList = currentList.toMutableList().also {
|
||||
it.addAll(newItems)
|
||||
@ -46,37 +38,10 @@ class VideosAdapter(
|
||||
submitList(updatedList)
|
||||
}
|
||||
|
||||
fun removeItemById(videoId: String) {
|
||||
val index = currentList.indexOfFirst {
|
||||
it.url?.toID() == videoId
|
||||
}.takeIf { it > 0 } ?: return
|
||||
val updatedList = currentList.toMutableList().also {
|
||||
it.removeAt(index)
|
||||
}
|
||||
|
||||
submitList(updatedList)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
return when {
|
||||
viewType == CAUGHT_UP_TYPE -> VideosViewHolder(
|
||||
AllCaughtUpRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
|
||||
forceMode in listOf(
|
||||
LayoutMode.TRENDING_ROW,
|
||||
LayoutMode.RELATED_COLUMN
|
||||
) -> VideosViewHolder(
|
||||
TrendingRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
|
||||
forceMode == LayoutMode.CHANNEL_ROW -> VideosViewHolder(
|
||||
VideoRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
|
||||
else -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false))
|
||||
}
|
||||
val binding = VideoRowBinding.inflate(layoutInflater, parent, false)
|
||||
return VideosViewHolder(binding)
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@ -84,51 +49,11 @@ class VideosAdapter(
|
||||
val video = getItem(holder.bindingAdapterPosition)
|
||||
val videoId = video.url.orEmpty().toID()
|
||||
|
||||
val context = (
|
||||
holder.videoRowBinding ?: holder.trendingRowBinding ?: holder.allCaughtUpBinding
|
||||
)!!.root.context
|
||||
val context = holder.binding.root.context
|
||||
val activity = (context as BaseActivity)
|
||||
val fragmentManager = activity.supportFragmentManager
|
||||
|
||||
// Trending layout
|
||||
holder.trendingRowBinding?.apply {
|
||||
// set a fixed width for better visuals
|
||||
if (forceMode == LayoutMode.RELATED_COLUMN) {
|
||||
root.updateLayoutParams {
|
||||
width = 250f.dpToPx()
|
||||
}
|
||||
}
|
||||
watchProgress.setWatchProgressLength(videoId, video.duration ?: 0L)
|
||||
|
||||
textViewTitle.text = video.title
|
||||
textViewChannel.text = TextUtils.formatViewsString(root.context, video.views ?: -1, video.uploaded, video.uploaderName)
|
||||
|
||||
video.duration?.let { thumbnailDuration.setFormattedDuration(it, video.isShort, video.uploaded) }
|
||||
channelImage.setOnClickListener {
|
||||
NavigationHelper.navigateChannel(root.context, video.uploaderUrl)
|
||||
}
|
||||
ImageHelper.loadImage(video.thumbnail, thumbnail)
|
||||
ImageHelper.loadImage(video.uploaderAvatar, channelImage, true)
|
||||
root.setOnClickListener {
|
||||
NavigationHelper.navigateVideo(root.context, videoId)
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
fragmentManager.setFragmentResultListener(
|
||||
VideoOptionsBottomSheet.VIDEO_OPTIONS_SHEET_REQUEST_KEY,
|
||||
activity
|
||||
) { _, _ ->
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
val sheet = VideoOptionsBottomSheet()
|
||||
sheet.arguments = bundleOf(IntentData.streamItem to video)
|
||||
sheet.show(fragmentManager, VideosAdapter::class.java.name)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
// Normal videos row layout
|
||||
holder.videoRowBinding?.apply {
|
||||
with(holder.binding) {
|
||||
videoTitle.text = video.title
|
||||
videoInfo.text = TextUtils.formatViewsString(root.context, video.views ?: -1, video.uploaded)
|
||||
|
||||
@ -136,7 +61,7 @@ class VideosAdapter(
|
||||
watchProgress.setWatchProgressLength(videoId, video.duration ?: 0L)
|
||||
ImageHelper.loadImage(video.thumbnail, thumbnail)
|
||||
|
||||
if (forceMode != LayoutMode.CHANNEL_ROW) {
|
||||
if (showChannelInfo) {
|
||||
ImageHelper.loadImage(video.uploaderAvatar, channelImage, true)
|
||||
channelName.text = video.uploaderName
|
||||
|
||||
@ -174,19 +99,4 @@ class VideosAdapter(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
enum class LayoutMode {
|
||||
RESPECT_PREF,
|
||||
TRENDING_ROW,
|
||||
VIDEO_ROW,
|
||||
CHANNEL_ROW,
|
||||
RELATED_COLUMN
|
||||
}
|
||||
|
||||
private const val NORMAL_TYPE = 0
|
||||
private const val CAUGHT_UP_TYPE = 1
|
||||
|
||||
const val CAUGHT_UP_STREAM_TYPE = "caught"
|
||||
}
|
||||
}
|
||||
|
@ -60,9 +60,7 @@ class ChannelContentFragment : DynamicLayoutManagerFragment(R.layout.fragment_ch
|
||||
var nextPage = arguments.getString(IntentData.nextPage)
|
||||
var isLoading = false
|
||||
|
||||
val channelAdapter = VideosAdapter(
|
||||
forceMode = VideosAdapter.Companion.LayoutMode.CHANNEL_ROW
|
||||
).also {
|
||||
val channelAdapter = VideosAdapter(showChannelInfo = false).also {
|
||||
it.submitList(arguments.parcelableArrayList<StreamItem>(IntentData.videoList)!!)
|
||||
}
|
||||
binding.channelRecView.adapter = channelAdapter
|
||||
|
@ -234,9 +234,7 @@ class ChannelFragment : Fragment(R.layout.fragment_channel) {
|
||||
tab.text = tabList[position].name
|
||||
}.attach()
|
||||
|
||||
channelAdapter = VideosAdapter(
|
||||
forceMode = VideosAdapter.Companion.LayoutMode.CHANNEL_ROW
|
||||
).also {
|
||||
channelAdapter = VideosAdapter(showChannelInfo = false).also {
|
||||
it.submitList(response.relatedStreams)
|
||||
}
|
||||
tabList.clear()
|
||||
|
@ -23,8 +23,7 @@ import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
|
||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter.Companion.LayoutMode
|
||||
import com.github.libretube.ui.adapters.VideoCardsAdapter
|
||||
import com.github.libretube.ui.extensions.setupFragmentAnimation
|
||||
import com.github.libretube.ui.models.HomeViewModel
|
||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||
@ -38,9 +37,9 @@ class HomeFragment : Fragment(R.layout.fragment_home) {
|
||||
private val subscriptionsViewModel: SubscriptionsViewModel by activityViewModels()
|
||||
private val homeViewModel: HomeViewModel by activityViewModels()
|
||||
|
||||
private val trendingAdapter = VideosAdapter(forceMode = LayoutMode.TRENDING_ROW)
|
||||
private val feedAdapter = VideosAdapter(forceMode = LayoutMode.RELATED_COLUMN)
|
||||
private val watchingAdapter = VideosAdapter(forceMode = LayoutMode.RELATED_COLUMN)
|
||||
private val trendingAdapter = VideoCardsAdapter()
|
||||
private val feedAdapter = VideoCardsAdapter(columnWidthDp = 250f)
|
||||
private val watchingAdapter = VideoCardsAdapter(columnWidthDp = 250f)
|
||||
private val bookmarkAdapter = PlaylistBookmarkAdapter(PlaylistBookmarkAdapter.Companion.BookmarkMode.HOME)
|
||||
private val playlistAdapter = PlaylistsAdapter(playlistType = PlaylistsHelper.getPrivatePlaylistType())
|
||||
|
||||
|
@ -89,7 +89,7 @@ import com.github.libretube.parcelable.PlayerData
|
||||
import com.github.libretube.services.AbstractPlayerService
|
||||
import com.github.libretube.services.OnlinePlayerService
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.adapters.VideoCardsAdapter
|
||||
import com.github.libretube.ui.base.BaseActivity
|
||||
import com.github.libretube.ui.dialogs.AddToPlaylistDialog
|
||||
import com.github.libretube.ui.dialogs.PlayOfflineDialog
|
||||
@ -1127,12 +1127,8 @@ class PlayerFragment : Fragment(R.layout.fragment_player), OnlinePlayerOptions {
|
||||
|
||||
if (PlayerHelper.relatedStreamsEnabled) {
|
||||
val relatedLayoutManager = binding.relatedRecView.layoutManager as LinearLayoutManager
|
||||
binding.relatedRecView.adapter = VideosAdapter(
|
||||
forceMode = if (relatedLayoutManager.orientation == LinearLayoutManager.HORIZONTAL) {
|
||||
VideosAdapter.Companion.LayoutMode.RELATED_COLUMN
|
||||
} else {
|
||||
VideosAdapter.Companion.LayoutMode.TRENDING_ROW
|
||||
}
|
||||
binding.relatedRecView.adapter = VideoCardsAdapter(
|
||||
columnWidthDp = if (relatedLayoutManager.orientation == LinearLayoutManager.HORIZONTAL) 250f else null
|
||||
).also { adapter ->
|
||||
adapter.submitList(streams.relatedStreams.filter { !it.title.isNullOrBlank() })
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ import com.github.libretube.helpers.PreferenceHelper
|
||||
import com.github.libretube.obj.SelectableOption
|
||||
import com.github.libretube.ui.adapters.LegacySubscriptionAdapter
|
||||
import com.github.libretube.ui.adapters.SubscriptionChannelAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.adapters.VideoCardsAdapter
|
||||
import com.github.libretube.ui.base.DynamicLayoutManagerFragment
|
||||
import com.github.libretube.ui.extensions.addOnBottomReachedListener
|
||||
import com.github.libretube.ui.extensions.setupFragmentAnimation
|
||||
@ -62,7 +62,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
||||
|
||||
private var isAppBarFullyExpanded = true
|
||||
|
||||
private var feedAdapter = VideosAdapter()
|
||||
private var feedAdapter = VideoCardsAdapter()
|
||||
private var selectedSortOrder = PreferenceHelper.getInt(PreferenceKeys.FEED_SORT_ORDER, 0)
|
||||
set(value) {
|
||||
PreferenceHelper.putInt(PreferenceKeys.FEED_SORT_ORDER, value)
|
||||
@ -393,7 +393,7 @@ class SubscriptionsFragment : DynamicLayoutManagerFragment(R.layout.fragment_sub
|
||||
if (caughtUpIndex > 0 && !feed[caughtUpIndex-1].isUpcoming) {
|
||||
sorted.add(
|
||||
caughtUpIndex,
|
||||
StreamItem(type = VideosAdapter.CAUGHT_UP_STREAM_TYPE)
|
||||
StreamItem(type = VideoCardsAdapter.CAUGHT_UP_STREAM_TYPE)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import com.github.libretube.R
|
||||
import com.github.libretube.databinding.FragmentTrendsBinding
|
||||
import com.github.libretube.helpers.NavBarHelper
|
||||
import com.github.libretube.ui.activities.SettingsActivity
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.adapters.VideoCardsAdapter
|
||||
import com.github.libretube.ui.base.DynamicLayoutManagerFragment
|
||||
import com.github.libretube.ui.extensions.setupFragmentAnimation
|
||||
import com.github.libretube.ui.models.TrendsViewModel
|
||||
@ -31,7 +31,7 @@ class TrendsFragment : DynamicLayoutManagerFragment(R.layout.fragment_trends) {
|
||||
_binding = FragmentTrendsBinding.bind(view)
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val adapter = VideosAdapter()
|
||||
val adapter = VideoCardsAdapter()
|
||||
binding.recview.adapter = adapter
|
||||
binding.recview.layoutManager?.onRestoreInstanceState(viewModel.recyclerViewState)
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.github.libretube.ui.viewholders
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.AllCaughtUpRowBinding
|
||||
import com.github.libretube.databinding.TrendingRowBinding
|
||||
|
||||
class VideoCardsViewHolder : RecyclerView.ViewHolder {
|
||||
var trendingRowBinding: TrendingRowBinding? = null
|
||||
var allCaughtUpBinding: AllCaughtUpRowBinding? = null
|
||||
|
||||
constructor(binding: TrendingRowBinding) : super(binding.root) {
|
||||
trendingRowBinding = binding
|
||||
}
|
||||
|
||||
constructor(binding: AllCaughtUpRowBinding) : super(binding.root) {
|
||||
allCaughtUpBinding = binding
|
||||
}
|
||||
}
|
@ -1,24 +1,6 @@
|
||||
package com.github.libretube.ui.viewholders
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.github.libretube.databinding.AllCaughtUpRowBinding
|
||||
import com.github.libretube.databinding.TrendingRowBinding
|
||||
import com.github.libretube.databinding.VideoRowBinding
|
||||
|
||||
class VideosViewHolder : RecyclerView.ViewHolder {
|
||||
var trendingRowBinding: TrendingRowBinding? = null
|
||||
var videoRowBinding: VideoRowBinding? = null
|
||||
var allCaughtUpBinding: AllCaughtUpRowBinding? = null
|
||||
|
||||
constructor(binding: TrendingRowBinding) : super(binding.root) {
|
||||
trendingRowBinding = binding
|
||||
}
|
||||
|
||||
constructor(binding: VideoRowBinding) : super(binding.root) {
|
||||
videoRowBinding = binding
|
||||
}
|
||||
|
||||
constructor(binding: AllCaughtUpRowBinding) : super(binding.root) {
|
||||
allCaughtUpBinding = binding
|
||||
}
|
||||
}
|
||||
class VideosViewHolder(val binding: VideoRowBinding) : RecyclerView.ViewHolder(binding.root)
|
Loading…
x
Reference in New Issue
Block a user