mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 08:20:32 +05:30
commit
fd7dcf1af4
@ -0,0 +1,49 @@
|
|||||||
|
package com.github.libretube.extensions
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.github.libretube.R
|
||||||
|
import com.github.libretube.api.SubscriptionHelper
|
||||||
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
fun TextView.setupSubscriptionButton(
|
||||||
|
channelId: String?,
|
||||||
|
channelName: String?,
|
||||||
|
notificationBell: MaterialButton? = null,
|
||||||
|
isSubscribed: Boolean? = null
|
||||||
|
) {
|
||||||
|
if (channelId == null) return
|
||||||
|
|
||||||
|
var subscribed: Boolean? = false
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
subscribed = isSubscribed ?: SubscriptionHelper.isSubscribed(channelId)
|
||||||
|
if (subscribed == true) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
this@setupSubscriptionButton.text = context.getString(R.string.unsubscribe)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
notificationBell?.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationBell?.setupNotificationBell(channelId)
|
||||||
|
this.setOnClickListener {
|
||||||
|
if (subscribed == true) {
|
||||||
|
SubscriptionHelper.handleUnsubscribe(context, channelId, channelName) {
|
||||||
|
this.text = context.getString(R.string.subscribe)
|
||||||
|
notificationBell?.visibility = View.GONE
|
||||||
|
subscribed = false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SubscriptionHelper.subscribe(channelId)
|
||||||
|
this.text = context.getString(R.string.unsubscribe)
|
||||||
|
notificationBell?.visibility = View.VISIBLE
|
||||||
|
subscribed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,12 @@
|
|||||||
package com.github.libretube.ui.adapters
|
package com.github.libretube.ui.adapters
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
|
||||||
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.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.api.SubscriptionHelper
|
|
||||||
import com.github.libretube.api.obj.ContentItem
|
import com.github.libretube.api.obj.ContentItem
|
||||||
import com.github.libretube.databinding.ChannelRowBinding
|
import com.github.libretube.databinding.ChannelRowBinding
|
||||||
import com.github.libretube.databinding.PlaylistsRowBinding
|
import com.github.libretube.databinding.PlaylistsRowBinding
|
||||||
@ -16,15 +14,13 @@ import com.github.libretube.databinding.VideoRowBinding
|
|||||||
import com.github.libretube.extensions.formatShort
|
import com.github.libretube.extensions.formatShort
|
||||||
import com.github.libretube.extensions.setFormattedDuration
|
import com.github.libretube.extensions.setFormattedDuration
|
||||||
import com.github.libretube.extensions.setWatchProgressLength
|
import com.github.libretube.extensions.setWatchProgressLength
|
||||||
|
import com.github.libretube.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||||
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||||
import com.github.libretube.ui.viewholders.SearchViewHolder
|
import com.github.libretube.ui.viewholders.SearchViewHolder
|
||||||
import com.github.libretube.util.ImageHelper
|
import com.github.libretube.util.ImageHelper
|
||||||
import com.github.libretube.util.NavigationHelper
|
import com.github.libretube.util.NavigationHelper
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class SearchAdapter(
|
class SearchAdapter(
|
||||||
private val searchItems: MutableList<ContentItem>,
|
private val searchItems: MutableList<ContentItem>,
|
||||||
@ -130,37 +126,7 @@ class SearchAdapter(
|
|||||||
NavigationHelper.navigateChannel(root.context, item.url)
|
NavigationHelper.navigateChannel(root.context, item.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
isSubscribed(root.context, item, binding)
|
binding.searchSubButton.setupSubscriptionButton(item.url?.toID(), item.name?.toID())
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isSubscribed(context: Context, streamItem: ContentItem, binding: ChannelRowBinding) {
|
|
||||||
val channelId = streamItem.url!!.toID()
|
|
||||||
// check whether the user subscribed to the channel
|
|
||||||
CoroutineScope(Dispatchers.Main).launch {
|
|
||||||
var isSubscribed = SubscriptionHelper.isSubscribed(channelId)
|
|
||||||
|
|
||||||
// if subscribed change text to unsubscribe
|
|
||||||
if (isSubscribed == true) {
|
|
||||||
binding.searchSubButton.text = binding.root.context.getString(R.string.unsubscribe)
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sub button visible and set the on click listeners to (un)subscribe
|
|
||||||
if (isSubscribed == null) return@launch
|
|
||||||
binding.searchSubButton.visibility = View.VISIBLE
|
|
||||||
|
|
||||||
binding.searchSubButton.setOnClickListener {
|
|
||||||
if (isSubscribed == false) {
|
|
||||||
SubscriptionHelper.subscribe(channelId)
|
|
||||||
binding.searchSubButton.text = binding.root.context.getString(R.string.unsubscribe)
|
|
||||||
isSubscribed = true
|
|
||||||
} else {
|
|
||||||
SubscriptionHelper.handleUnsubscribe(context, channelId, streamItem.uploaderName) {
|
|
||||||
binding.searchSubButton.text = binding.root.context.getString(R.string.subscribe)
|
|
||||||
isSubscribed = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package com.github.libretube.ui.adapters
|
package com.github.libretube.ui.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.github.libretube.R
|
|
||||||
import com.github.libretube.api.SubscriptionHelper
|
|
||||||
import com.github.libretube.api.obj.Subscription
|
import com.github.libretube.api.obj.Subscription
|
||||||
import com.github.libretube.databinding.ChannelSubscriptionRowBinding
|
import com.github.libretube.databinding.ChannelSubscriptionRowBinding
|
||||||
import com.github.libretube.extensions.setupNotificationBell
|
import com.github.libretube.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder
|
import com.github.libretube.ui.viewholders.SubscriptionChannelViewHolder
|
||||||
import com.github.libretube.util.ImageHelper
|
import com.github.libretube.util.ImageHelper
|
||||||
@ -31,32 +28,20 @@ class SubscriptionChannelAdapter(
|
|||||||
|
|
||||||
override fun onBindViewHolder(holder: SubscriptionChannelViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: SubscriptionChannelViewHolder, position: Int) {
|
||||||
val subscription = subscriptions[position]
|
val subscription = subscriptions[position]
|
||||||
var isSubscribed = true
|
|
||||||
|
|
||||||
holder.binding.apply {
|
holder.binding.apply {
|
||||||
subscriptionChannelName.text = subscription.name
|
subscriptionChannelName.text = subscription.name
|
||||||
ImageHelper.loadImage(subscription.avatar, subscriptionChannelImage)
|
ImageHelper.loadImage(subscription.avatar, subscriptionChannelImage)
|
||||||
|
|
||||||
subscription.url?.toID()?.let { notificationBell.setupNotificationBell(it) }
|
|
||||||
|
|
||||||
root.setOnClickListener {
|
root.setOnClickListener {
|
||||||
NavigationHelper.navigateChannel(root.context, subscription.url)
|
NavigationHelper.navigateChannel(root.context, subscription.url)
|
||||||
}
|
}
|
||||||
subscriptionSubscribe.setOnClickListener {
|
subscriptionSubscribe.setupSubscriptionButton(
|
||||||
val channelId = subscription.url!!.toID()
|
subscription.url?.toID(),
|
||||||
if (isSubscribed) {
|
subscription.name,
|
||||||
SubscriptionHelper.handleUnsubscribe(root.context, channelId, subscription.name ?: "") {
|
notificationBell,
|
||||||
subscriptionSubscribe.text = root.context.getString(R.string.subscribe)
|
true
|
||||||
notificationBell.visibility = View.GONE
|
)
|
||||||
isSubscribed = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SubscriptionHelper.subscribe(channelId)
|
|
||||||
subscriptionSubscribe.text = root.context.getString(R.string.unsubscribe)
|
|
||||||
notificationBell.visibility = View.VISIBLE
|
|
||||||
isSubscribed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import com.github.libretube.databinding.FragmentChannelBinding
|
|||||||
import com.github.libretube.enums.ShareObjectType
|
import com.github.libretube.enums.ShareObjectType
|
||||||
import com.github.libretube.extensions.TAG
|
import com.github.libretube.extensions.TAG
|
||||||
import com.github.libretube.extensions.formatShort
|
import com.github.libretube.extensions.formatShort
|
||||||
import com.github.libretube.extensions.setupNotificationBell
|
import com.github.libretube.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.obj.ShareData
|
import com.github.libretube.obj.ShareData
|
||||||
import com.github.libretube.ui.adapters.SearchAdapter
|
import com.github.libretube.ui.adapters.SearchAdapter
|
||||||
@ -125,27 +125,7 @@ class ChannelFragment : BaseFragment() {
|
|||||||
if (isSubscribed == null) return@launchWhenCreated
|
if (isSubscribed == null) return@launchWhenCreated
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
if (isSubscribed == true) {
|
binding.channelSubscribe.setupSubscriptionButton(channelId, channelName, binding.notificationBell)
|
||||||
binding.channelSubscribe.text = getString(R.string.unsubscribe)
|
|
||||||
}
|
|
||||||
|
|
||||||
channelId?.let { binding.notificationBell.setupNotificationBell(it) }
|
|
||||||
if (isSubscribed == false) binding.notificationBell.visibility = View.GONE
|
|
||||||
|
|
||||||
binding.channelSubscribe.setOnClickListener {
|
|
||||||
if (isSubscribed == true) {
|
|
||||||
SubscriptionHelper.handleUnsubscribe(requireContext(), channelId!!, channelName) {
|
|
||||||
isSubscribed = false
|
|
||||||
binding.channelSubscribe.text = getString(R.string.subscribe)
|
|
||||||
binding.notificationBell.visibility = View.GONE
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SubscriptionHelper.subscribe(channelId!!)
|
|
||||||
isSubscribed = true
|
|
||||||
binding.channelSubscribe.text = getString(R.string.unsubscribe)
|
|
||||||
binding.notificationBell.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.channelShare.setOnClickListener {
|
binding.channelShare.setOnClickListener {
|
||||||
val shareDialog = ShareDialog(
|
val shareDialog = ShareDialog(
|
||||||
|
@ -37,7 +37,6 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
|||||||
import com.github.libretube.R
|
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.SubscriptionHelper
|
|
||||||
import com.github.libretube.api.obj.ChapterSegment
|
import com.github.libretube.api.obj.ChapterSegment
|
||||||
import com.github.libretube.api.obj.SegmentData
|
import com.github.libretube.api.obj.SegmentData
|
||||||
import com.github.libretube.constants.IntentData
|
import com.github.libretube.constants.IntentData
|
||||||
@ -53,6 +52,7 @@ import com.github.libretube.extensions.awaitQuery
|
|||||||
import com.github.libretube.extensions.formatShort
|
import com.github.libretube.extensions.formatShort
|
||||||
import com.github.libretube.extensions.hideKeyboard
|
import com.github.libretube.extensions.hideKeyboard
|
||||||
import com.github.libretube.extensions.query
|
import com.github.libretube.extensions.query
|
||||||
|
import com.github.libretube.extensions.setupSubscriptionButton
|
||||||
import com.github.libretube.extensions.toID
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.extensions.toStreamItem
|
import com.github.libretube.extensions.toStreamItem
|
||||||
import com.github.libretube.models.PlayerViewModel
|
import com.github.libretube.models.PlayerViewModel
|
||||||
@ -118,7 +118,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
*/
|
*/
|
||||||
private var videoId: String? = null
|
private var videoId: String? = null
|
||||||
private var playlistId: String? = null
|
private var playlistId: String? = null
|
||||||
private var isSubscribed: Boolean? = false
|
|
||||||
private var isLive = false
|
private var isLive = false
|
||||||
private lateinit var streams: com.github.libretube.api.obj.Streams
|
private lateinit var streams: com.github.libretube.api.obj.Streams
|
||||||
|
|
||||||
@ -935,7 +934,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update the subscribed state
|
// update the subscribed state
|
||||||
isSubscribed()
|
binding.playerSubscribe.setupSubscriptionButton(streams.uploaderUrl?.toID(), streams.uploader)
|
||||||
|
|
||||||
if (token != "") {
|
if (token != "") {
|
||||||
binding.relPlayerSave.setOnClickListener {
|
binding.relPlayerSave.setOnClickListener {
|
||||||
@ -1261,33 +1260,6 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
|||||||
nowPlayingNotification.updatePlayerNotification(videoId!!, streams)
|
nowPlayingNotification.updatePlayerNotification(videoId!!, streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSubscribed() {
|
|
||||||
val channelId = streams.uploaderUrl!!.toID()
|
|
||||||
lifecycleScope.launchWhenCreated {
|
|
||||||
isSubscribed = SubscriptionHelper.isSubscribed(channelId)
|
|
||||||
|
|
||||||
if (isSubscribed == null) return@launchWhenCreated
|
|
||||||
|
|
||||||
runOnUiThread {
|
|
||||||
if (isSubscribed == true) {
|
|
||||||
binding.playerSubscribe.text = getString(R.string.unsubscribe)
|
|
||||||
}
|
|
||||||
binding.playerSubscribe.setOnClickListener {
|
|
||||||
if (isSubscribed == true) {
|
|
||||||
SubscriptionHelper.handleUnsubscribe(requireContext(), channelId, streams.uploader) {
|
|
||||||
binding.playerSubscribe.text = getString(R.string.subscribe)
|
|
||||||
isSubscribed = false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
SubscriptionHelper.subscribe(channelId)
|
|
||||||
binding.playerSubscribe.text = getString(R.string.unsubscribe)
|
|
||||||
isSubscribed = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun fetchComments() {
|
private fun fetchComments() {
|
||||||
lifecycleScope.launchWhenCreated {
|
lifecycleScope.launchWhenCreated {
|
||||||
val commentsResponse = try {
|
val commentsResponse = try {
|
||||||
|
@ -38,7 +38,7 @@ class MarkableTimeBar(
|
|||||||
canvas.save()
|
canvas.save()
|
||||||
length = canvas.width - 2 * HORIZONTAL_OFFSET
|
length = canvas.width - 2 * HORIZONTAL_OFFSET
|
||||||
|
|
||||||
val marginY = canvas.height / 2 - PROGRESS_HEIGHT / 2
|
val marginY = canvas.height / 2 - PROGRESS_BAR_HEIGHT / 2
|
||||||
|
|
||||||
segments.forEach {
|
segments.forEach {
|
||||||
canvas.drawRect(
|
canvas.drawRect(
|
||||||
@ -46,7 +46,7 @@ class MarkableTimeBar(
|
|||||||
(it.segment.first() + HORIZONTAL_OFFSET).toLength(),
|
(it.segment.first() + HORIZONTAL_OFFSET).toLength(),
|
||||||
marginY,
|
marginY,
|
||||||
(it.segment.last() + HORIZONTAL_OFFSET).toLength(),
|
(it.segment.last() + HORIZONTAL_OFFSET).toLength(),
|
||||||
canvas.height - marginY - 1
|
canvas.height - marginY
|
||||||
),
|
),
|
||||||
Paint().apply {
|
Paint().apply {
|
||||||
color = ThemeHelper.getThemeColor(context, R.attr.colorError)
|
color = ThemeHelper.getThemeColor(context, R.attr.colorError)
|
||||||
@ -74,6 +74,6 @@ class MarkableTimeBar(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val HORIZONTAL_OFFSET = 10
|
const val HORIZONTAL_OFFSET = 10
|
||||||
const val PROGRESS_HEIGHT = 6
|
const val PROGRESS_BAR_HEIGHT = 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,16 +38,18 @@
|
|||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:paddingHorizontal="15dp"
|
android:paddingHorizontal="15dp">
|
||||||
android:layout_marginTop="8dp">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/playlist_name"
|
android:id="@+id/playlist_name"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_weight="1"
|
android:layout_weight="1"
|
||||||
android:textSize="24sp"
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:textSize="20sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -32,30 +32,31 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:srcCompat="@tools:sample/backgrounds/scenic" />
|
tools:srcCompat="@tools:sample/backgrounds/scenic" />
|
||||||
|
|
||||||
<RelativeLayout
|
<LinearLayout
|
||||||
android:layout_width="90dp"
|
android:layout_width="90dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:background="#CC000000">
|
android:background="#CC000000"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/video_count"
|
android:id="@+id/video_count"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerInParent="true"
|
android:layout_gravity="center"
|
||||||
android:layout_centerVertical="true"
|
android:layout_marginTop="5dp"
|
||||||
android:textColor="#ECE4E4" />
|
android:textColor="#ECE4E4" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@+id/video_count"
|
android:layout_gravity="center"
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:paddingStart="5dp"
|
android:paddingStart="5dp"
|
||||||
app:srcCompat="@drawable/ic_playlist"
|
app:srcCompat="@drawable/ic_playlist"
|
||||||
tools:ignore="RtlSymmetry" />
|
tools:ignore="RtlSymmetry" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</LinearLayout>
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -63,6 +64,8 @@
|
|||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="8dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/delete_playlist"
|
app:layout_constraintEnd_toStartOf="@+id/delete_playlist"
|
||||||
app:layout_constraintStart_toEndOf="@+id/card_playlist_thumbnail"
|
app:layout_constraintStart_toEndOf="@+id/card_playlist_thumbnail"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
Loading…
x
Reference in New Issue
Block a user