mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 16:30:31 +05:30
Merge pull request #4979 from Bnyro/master
refactor: move description layout into its own view
This commit is contained in:
commit
a59633a726
@ -14,11 +14,9 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.PowerManager
|
||||
import android.text.format.DateUtils
|
||||
import android.text.util.Linkify
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||
import androidx.constraintlayout.motion.widget.TransitionAdapter
|
||||
@ -27,8 +25,6 @@ import androidx.core.graphics.drawable.toDrawable
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.os.postDelayed
|
||||
import androidx.core.text.method.LinkMovementMethodCompat
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.core.view.WindowCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isInvisible
|
||||
@ -76,7 +72,6 @@ import com.github.libretube.extensions.seekBy
|
||||
import com.github.libretube.extensions.serializableExtra
|
||||
import com.github.libretube.extensions.setMetadata
|
||||
import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.extensions.toLocalDateSafe
|
||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||
import com.github.libretube.extensions.togglePlayPauseState
|
||||
import com.github.libretube.extensions.updateParameters
|
||||
@ -95,7 +90,6 @@ import com.github.libretube.obj.ShareData
|
||||
import com.github.libretube.obj.VideoResolution
|
||||
import com.github.libretube.parcelable.PlayerData
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.activities.VideoTagsAdapter
|
||||
import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.dialogs.AddToPlaylistDialog
|
||||
import com.github.libretube.ui.dialogs.DownloadDialog
|
||||
@ -110,8 +104,6 @@ import com.github.libretube.ui.sheets.ChaptersBottomSheet
|
||||
import com.github.libretube.ui.sheets.CommentsSheet
|
||||
import com.github.libretube.ui.sheets.PlayingQueueSheet
|
||||
import com.github.libretube.ui.sheets.StatsSheet
|
||||
import com.github.libretube.util.HtmlParser
|
||||
import com.github.libretube.util.LinkHandler
|
||||
import com.github.libretube.util.NowPlayingNotification
|
||||
import com.github.libretube.util.OnlineTimeFrameReceiver
|
||||
import com.github.libretube.util.PlayingQueue
|
||||
@ -391,11 +383,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
exoPlayer.togglePlayPauseState()
|
||||
}
|
||||
|
||||
// video description and chapters toggle
|
||||
binding.playerTitleLayout.setOnClickListener {
|
||||
if (this::streams.isInitialized) toggleDescription()
|
||||
}
|
||||
|
||||
binding.commentsToggle.setOnClickListener {
|
||||
// set the max height to not cover the currently playing video
|
||||
commentsViewModel.handleLink = this::handleLink
|
||||
@ -489,6 +476,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
|
||||
binding.descriptionLayout.handleLink = this::handleLink
|
||||
}
|
||||
|
||||
private fun updateMaxSheetHeight() {
|
||||
@ -577,37 +566,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
updateResolutionOnFullscreenChange(false)
|
||||
}
|
||||
|
||||
private fun toggleDescription() {
|
||||
val views = if (binding.descLinLayout.isVisible) {
|
||||
// show formatted short view count
|
||||
streams.views.formatShort()
|
||||
} else {
|
||||
// show exact view count
|
||||
"%,d".format(streams.views)
|
||||
}
|
||||
val viewInfo = getString(R.string.normal_views, views, localizeDate(streams))
|
||||
if (binding.descLinLayout.isVisible) {
|
||||
// hide the description and chapters
|
||||
binding.playerDescriptionArrow.animate().rotation(0F).setDuration(250).start()
|
||||
binding.descLinLayout.isGone = true
|
||||
|
||||
// limit the title height to two lines
|
||||
binding.playerTitle.maxLines = 2
|
||||
} else {
|
||||
// show the description and chapters
|
||||
binding.playerDescriptionArrow.animate().rotation(180F).setDuration(250).start()
|
||||
binding.descLinLayout.isVisible = true
|
||||
|
||||
// show the whole title
|
||||
binding.playerTitle.maxLines = Int.MAX_VALUE
|
||||
}
|
||||
binding.playerViewsInfo.text = viewInfo
|
||||
|
||||
if (viewModel.chapters.isNotEmpty()) {
|
||||
setCurrentChapterName(forceUpdate = true, enqueueNew = false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
// check whether the screen is on
|
||||
val isInteractive = requireContext().getSystemService<PowerManager>()!!.isInteractive
|
||||
@ -766,7 +724,14 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
|
||||
// set media sources for the player
|
||||
initStreamSources()
|
||||
prepareExoPlayerView()
|
||||
|
||||
binding.player.apply {
|
||||
useController = false
|
||||
player = exoPlayer
|
||||
}
|
||||
|
||||
playerBinding.exoProgress.setPlayer(exoPlayer)
|
||||
|
||||
initializePlayerView()
|
||||
setupSeekbarPreview()
|
||||
|
||||
@ -862,59 +827,21 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
chaptersBottomSheet = null
|
||||
}
|
||||
|
||||
private fun prepareExoPlayerView() {
|
||||
binding.player.apply {
|
||||
useController = false
|
||||
player = exoPlayer
|
||||
}
|
||||
|
||||
playerBinding.exoProgress.setPlayer(exoPlayer)
|
||||
}
|
||||
|
||||
private fun localizeDate(streams: Streams): String {
|
||||
if (streams.livestream) return ""
|
||||
|
||||
return TextUtils.SEPARATOR + TextUtils.localizeDate(streams.uploadDate.toLocalDateSafe())
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private fun initializePlayerView() {
|
||||
// initialize the player view actions
|
||||
binding.player.initialize(doubleTapOverlayBinding, playerGestureControlsViewBinding)
|
||||
binding.player.initPlayerOptions(viewModel, viewLifecycleOwner, trackSelector, this)
|
||||
binding.descriptionLayout.setStreams(streams)
|
||||
|
||||
binding.apply {
|
||||
val views = streams.views.formatShort()
|
||||
playerViewsInfo.text = getString(R.string.normal_views, views, localizeDate(streams))
|
||||
|
||||
textLike.text = streams.likes.formatShort()
|
||||
textDislike.isVisible = streams.dislikes >= 0
|
||||
textDislike.text = streams.dislikes.formatShort()
|
||||
|
||||
ImageHelper.loadImage(streams.uploaderAvatar, binding.playerChannelImage)
|
||||
playerChannelName.text = streams.uploader
|
||||
|
||||
titleTextView.text = streams.title
|
||||
|
||||
playerTitle.text = streams.title
|
||||
playerDescription.text = streams.description
|
||||
|
||||
metaInfo.isVisible = streams.metaInfo.isNotEmpty()
|
||||
// generate a meta info text with clickable links using html
|
||||
val metaInfoText = streams.metaInfo.joinToString("\n\n") { info ->
|
||||
val text = info.description.takeIf { it.isNotBlank() } ?: info.title
|
||||
val links = info.urls.mapIndexed { index, url ->
|
||||
"<a href=\"$url\">${info.urlTexts.getOrNull(index).orEmpty()}</a>"
|
||||
}.joinToString(", ")
|
||||
"$text $links"
|
||||
}
|
||||
metaInfo.text = metaInfoText.parseAsHtml()
|
||||
|
||||
playerChannelSubCount.text = context?.getString(
|
||||
R.string.subscribers,
|
||||
streams.uploaderSubscriberCount.formatShort()
|
||||
)
|
||||
|
||||
player.isLive = streams.livestream
|
||||
}
|
||||
playerBinding.exoTitle.text = streams.title
|
||||
@ -1034,29 +961,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
PictureInPictureCompat.enterPictureInPictureMode(requireActivity(), pipParams)
|
||||
}
|
||||
initializeRelatedVideos(streams.relatedStreams.filter { !it.title.isNullOrBlank() })
|
||||
// set video description
|
||||
val description = streams.description
|
||||
|
||||
setupDescription(binding.playerDescription, description)
|
||||
val visibility = when (streams.visibility) {
|
||||
"public" -> context?.getString(R.string.visibility_public)
|
||||
"unlisted" -> context?.getString(R.string.visibility_unlisted)
|
||||
// currently no other visibility could be returned, might change in the future however
|
||||
else -> streams.visibility.replaceFirstChar {
|
||||
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
|
||||
}
|
||||
}.orEmpty()
|
||||
binding.additionalVideoInfo.text =
|
||||
"${context?.getString(R.string.category)}: ${streams.category}\n" +
|
||||
"${context?.getString(R.string.license)}: ${streams.license}\n" +
|
||||
"${context?.getString(R.string.visibility)}: $visibility"
|
||||
|
||||
if (streams.tags.isNotEmpty()) {
|
||||
binding.tagsRecycler.layoutManager =
|
||||
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.tagsRecycler.adapter = VideoTagsAdapter(streams.tags)
|
||||
}
|
||||
binding.tagsRecycler.isVisible = streams.tags.isNotEmpty()
|
||||
|
||||
binding.playerChannel.setOnClickListener {
|
||||
val activity = view?.context as MainActivity
|
||||
@ -1108,22 +1012,6 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the description text with video links and timestamps
|
||||
*/
|
||||
private fun setupDescription(descTextView: TextView, description: String) {
|
||||
// detect whether the description is html formatted
|
||||
if (description.contains("<") && description.contains(">")) {
|
||||
descTextView.movementMethod = LinkMovementMethodCompat.getInstance()
|
||||
descTextView.text = description.replace("</a>", "</a> ")
|
||||
.parseAsHtml(tagHandler = HtmlParser(LinkHandler(this::handleLink)))
|
||||
} else {
|
||||
// Links can be present as plain text
|
||||
descTextView.autoLinkMask = Linkify.WEB_URLS
|
||||
descTextView.text = description
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a link clicked in the description
|
||||
*/
|
||||
|
@ -0,0 +1,144 @@
|
||||
package com.github.libretube.ui.views
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.text.util.Linkify
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.text.method.LinkMovementMethodCompat
|
||||
import androidx.core.text.parseAsHtml
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import com.github.libretube.databinding.DescriptionLayoutBinding
|
||||
import com.github.libretube.extensions.formatShort
|
||||
import com.github.libretube.extensions.toLocalDateSafe
|
||||
import com.github.libretube.ui.activities.VideoTagsAdapter
|
||||
import com.github.libretube.util.HtmlParser
|
||||
import com.github.libretube.util.LinkHandler
|
||||
import com.github.libretube.util.TextUtils
|
||||
import java.util.Locale
|
||||
|
||||
class DescriptionLayout(
|
||||
context: Context,
|
||||
attributeSet: AttributeSet?
|
||||
): LinearLayout(context, attributeSet) {
|
||||
val binding = DescriptionLayoutBinding.inflate(LayoutInflater.from(context), this, true)
|
||||
private var streams: Streams? = null
|
||||
var handleLink: (link: String) -> Unit = {}
|
||||
|
||||
init {
|
||||
binding.playerTitleLayout.setOnClickListener {
|
||||
toggleDescription()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun setStreams(streams: Streams) {
|
||||
this.streams = streams
|
||||
|
||||
val views = streams.views.formatShort()
|
||||
binding.run {
|
||||
playerViewsInfo.text = context.getString(R.string.normal_views, views, localizeDate(streams))
|
||||
|
||||
textLike.text = streams.likes.formatShort()
|
||||
textDislike.isVisible = streams.dislikes >= 0
|
||||
textDislike.text = streams.dislikes.formatShort()
|
||||
|
||||
playerTitle.text = streams.title
|
||||
playerDescription.text = streams.description
|
||||
|
||||
metaInfo.isVisible = streams.metaInfo.isNotEmpty()
|
||||
// generate a meta info text with clickable links using html
|
||||
val metaInfoText = streams.metaInfo.joinToString("\n\n") { info ->
|
||||
val text = info.description.takeIf { it.isNotBlank() } ?: info.title
|
||||
val links = info.urls.mapIndexed { index, url ->
|
||||
"<a href=\"$url\">${info.urlTexts.getOrNull(index).orEmpty()}</a>"
|
||||
}.joinToString(", ")
|
||||
"$text $links"
|
||||
}
|
||||
metaInfo.text = metaInfoText.parseAsHtml()
|
||||
|
||||
val visibility = when (streams.visibility) {
|
||||
"public" -> context?.getString(R.string.visibility_public)
|
||||
"unlisted" -> context?.getString(R.string.visibility_unlisted)
|
||||
// currently no other visibility could be returned, might change in the future however
|
||||
else -> streams.visibility.replaceFirstChar {
|
||||
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
|
||||
}
|
||||
}.orEmpty()
|
||||
additionalVideoInfo.text =
|
||||
"${context?.getString(R.string.category)}: ${streams.category}\n" +
|
||||
"${context?.getString(R.string.license)}: ${streams.license}\n" +
|
||||
"${context?.getString(R.string.visibility)}: $visibility"
|
||||
|
||||
if (streams.tags.isNotEmpty()) {
|
||||
binding.tagsRecycler.layoutManager =
|
||||
LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.tagsRecycler.adapter = VideoTagsAdapter(streams.tags)
|
||||
}
|
||||
binding.tagsRecycler.isVisible = streams.tags.isNotEmpty()
|
||||
|
||||
setupDescription(streams.description)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the description text with video links and timestamps
|
||||
*/
|
||||
private fun setupDescription(description: String) {
|
||||
val descTextView = binding.playerDescription
|
||||
// detect whether the description is html formatted
|
||||
if (description.contains("<") && description.contains(">")) {
|
||||
descTextView.movementMethod = LinkMovementMethodCompat.getInstance()
|
||||
descTextView.text = description.replace("</a>", "</a> ")
|
||||
.parseAsHtml(tagHandler = HtmlParser(LinkHandler(handleLink)))
|
||||
} else {
|
||||
// Links can be present as plain text
|
||||
descTextView.autoLinkMask = Linkify.WEB_URLS
|
||||
descTextView.text = description
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleDescription() {
|
||||
val streams = streams ?: return
|
||||
|
||||
val views = if (binding.descLinLayout.isVisible) {
|
||||
// show formatted short view count
|
||||
streams.views.formatShort()
|
||||
} else {
|
||||
// show exact view count
|
||||
"%,d".format(streams.views)
|
||||
}
|
||||
val viewInfo = context.getString(R.string.normal_views, views, localizeDate(streams))
|
||||
if (binding.descLinLayout.isVisible) {
|
||||
// hide the description and chapters
|
||||
binding.playerDescriptionArrow.animate().rotation(0F).setDuration(ANIMATION_DURATION).start()
|
||||
binding.descLinLayout.isGone = true
|
||||
|
||||
// limit the title height to two lines
|
||||
binding.playerTitle.maxLines = 2
|
||||
} else {
|
||||
// show the description and chapters
|
||||
binding.playerDescriptionArrow.animate().rotation(180F).setDuration(ANIMATION_DURATION).start()
|
||||
binding.descLinLayout.isVisible = true
|
||||
|
||||
// show the whole title
|
||||
binding.playerTitle.maxLines = Int.MAX_VALUE
|
||||
}
|
||||
binding.playerViewsInfo.text = viewInfo
|
||||
}
|
||||
|
||||
private fun localizeDate(streams: Streams): String {
|
||||
if (streams.livestream) return ""
|
||||
|
||||
return TextUtils.SEPARATOR + TextUtils.localizeDate(streams.uploadDate.toLocalDateSafe())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ANIMATION_DURATION = 250L
|
||||
}
|
||||
}
|
124
app/src/main/res/layout/description_layout.xml
Normal file
124
app/src/main/res/layout/description_layout.xml
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_title_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
android:textSize="18sp"
|
||||
tools:text="Video Title" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_description_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:src="@drawable/ic_arrow_down" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_views_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="1"
|
||||
tools:text="10M views 2 days ago " />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/textLike"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:drawablePadding="5dp"
|
||||
app:drawableStartCompat="@drawable/ic_like"
|
||||
app:drawableStartDimen="12dp"
|
||||
tools:text="4.2K" />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/textDislike"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:drawablePadding="5dp"
|
||||
android:visibility="gone"
|
||||
app:drawableStartCompat="@drawable/ic_dislike"
|
||||
app:drawableStartDimen="12dp"
|
||||
tools:text="1.3K" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/desc_linLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/meta_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/additional_video_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tags_recycler"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
@ -22,122 +22,13 @@
|
||||
android:id="@+id/linLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/player_title_layout"
|
||||
<com.github.libretube.ui.views.DescriptionLayout
|
||||
android:id="@+id/descriptionLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginVertical="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="2"
|
||||
android:textSize="18sp"
|
||||
tools:text="Video Title" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/player_description_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:src="@drawable/ic_arrow_down" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="10dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_views_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_weight="1"
|
||||
tools:text="10M views 2 days ago " />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/textLike"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:drawablePadding="5dp"
|
||||
app:drawableStartCompat="@drawable/ic_like"
|
||||
app:drawableStartDimen="12dp"
|
||||
tools:text="4.2K" />
|
||||
|
||||
<com.github.libretube.ui.views.DrawableTextView
|
||||
android:id="@+id/textDislike"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:drawablePadding="5dp"
|
||||
app:drawableStartCompat="@drawable/ic_dislike"
|
||||
app:drawableStartDimen="12dp"
|
||||
android:visibility="gone"
|
||||
tools:text="1.3K" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/desc_linLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="5dp"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/meta_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textSize="14sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/player_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/additional_video_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/tags_recycler"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
android:animateLayoutChanges="true"/>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="@style/Widget.Material3.CardView.Elevated"
|
||||
|
Loading…
x
Reference in New Issue
Block a user