diff --git a/app/src/main/java/com/github/libretube/ui/adapters/VideoCardsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/VideoCardsAdapter.kt new file mode 100644 index 000000000..213a6105a --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/adapters/VideoCardsAdapter.kt @@ -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(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" + } +} diff --git a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt index fedd3da7a..aa3fd4d64 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/VideosAdapter.kt @@ -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(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) { 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" - } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/ChannelContentFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/ChannelContentFragment.kt index 1e005c9e1..d7f2a2b60 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/ChannelContentFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/ChannelContentFragment.kt @@ -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(IntentData.videoList)!!) } binding.channelRecView.adapter = channelAdapter 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 59ff76352..cc9f44219 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 @@ -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() diff --git a/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt index 520ffff4c..2f8056c92 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/HomeFragment.kt @@ -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()) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 448f7debd..0638d4f87 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -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() }) } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt index 2877c358a..9b157ed09 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/SubscriptionsFragment.kt @@ -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) ) } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/TrendsFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/TrendsFragment.kt index 4d38e0c12..c06d052cb 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/TrendsFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/TrendsFragment.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/ui/viewholders/VideoCardsViewHolder.kt b/app/src/main/java/com/github/libretube/ui/viewholders/VideoCardsViewHolder.kt new file mode 100644 index 000000000..5eddd3bbe --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/viewholders/VideoCardsViewHolder.kt @@ -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 + } +} diff --git a/app/src/main/java/com/github/libretube/ui/viewholders/VideosViewHolder.kt b/app/src/main/java/com/github/libretube/ui/viewholders/VideosViewHolder.kt index 2f1a285c2..ba6c5c04e 100644 --- a/app/src/main/java/com/github/libretube/ui/viewholders/VideosViewHolder.kt +++ b/app/src/main/java/com/github/libretube/ui/viewholders/VideosViewHolder.kt @@ -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) \ No newline at end of file