download UI fixes

This commit is contained in:
reduplicated 2022-10-30 22:41:26 +01:00
parent fa399cd350
commit a1165344d3
10 changed files with 248 additions and 294 deletions

View File

@ -168,8 +168,8 @@ object CommonActivity {
Aria2Settings(
"1337", //UUID.randomUUID().toString()
4337,
act.filesDir.path, //"/storage/emulated/0/Download",//
"${act.filesDir.path}/session"
act.filesDir.path + "/download", //"/storage/emulated/0/Download",//
null//"${act.filesDir.path}/session"
)
)
}

View File

@ -16,7 +16,10 @@ object Aria2cHelper {
VideoDownloadManager.downloadDeleteEvent.invoke(id.toInt())
getMetadata(id)?.let { data ->
Aria2Starter.deleteFiles(data.items.flatMap { it.files })
Aria2Starter.delete(
DownloadListener.sessionIdToGid[id],
id,
data.items.flatMap { it.files })
}
removeMetadata(id)
AcraApplication.removeKey(KEY_DOWNLOAD_INFO, id.toString())

View File

@ -2,23 +2,160 @@ package com.lagradost.cloudstream3.ui.download
import android.app.Activity
import android.content.DialogInterface
import android.text.format.Formatter
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.view.doOnAttach
import androidx.lifecycle.findViewTreeLifecycleOwner
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.player.DownloadFileGenerator
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
import com.lagradost.cloudstream3.ui.result.DownloadHelper.play
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
import com.lagradost.cloudstream3.utils.ExtractorUri
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import com.lagradost.fetchbutton.aria2c.Aria2Starter
import com.lagradost.fetchbutton.aria2c.DownloadListener
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
import com.lagradost.fetchbutton.ui.PieFetchButton
object DownloadButtonSetup {
fun bind(
card: IVisualDownloadChildCached,
downloadButton: PieFetchButton,
extraInfo: TextView,
clickCallback: (DownloadClickEvent) -> Unit
) {
val d = card.data ?: return
fun updateText(downloadBytes: Long, totalBytes: Long) {
extraInfo?.apply {
text =
context.getString(R.string.download_size_format).format(
Formatter.formatShortFileSize(context, downloadBytes),
Formatter.formatShortFileSize(context, totalBytes)
)
}
}
updateText(card.currentBytes, card.totalBytes)
downloadButton.apply {
val play =
if (card is VisualDownloadChildCached) R.string.play_episode else R.string.play_movie_button//if (card.episode <= 0) R.string.play_movie_button else R.string.play_episode
setPersistentId(d.id.toLong())
doOnAttach { view ->
view.findViewTreeLifecycleOwner()?.let { life ->
DownloadListener.observe(life) {
gid?.let { realGId ->
val meta = DownloadListener.getInfo(realGId)
updateText(meta.downloadedLength, meta.totalLength)
}
}
}
}
val isValid = when (downloadButton.currentStatus) {
null, DownloadStatusTell.Removed -> false
else -> true
}
downloadButton.setOnClickListener {
val view = downloadButton
fun delete() {
// view.deleteAllFiles()
clickCallback.invoke(
DownloadClickEvent(
DOWNLOAD_ACTION_DELETE_FILE,
d
)
)
}
//if (view !is PieFetchButton) return@setOnClickListener
when (view.currentStatus) {
/*null, DownloadStatusTell.Removed -> {
view.setStatus(DownloadStatusTell.Waiting)
downloadClickCallback.invoke(
DownloadEpisodeClickEvent(
DOWNLOAD_ACTION_DOWNLOAD,
card
)
)
}*/
DownloadStatusTell.Paused -> {
view.popupMenuNoIcons(
if (isValid) listOf(
1 to R.string.resume,
2 to play,
3 to R.string.delete
) else listOf(2 to play, 3 to R.string.delete)
) {
when (itemId) {
1 -> if (!view.resumeDownload()) {
/*downloadClickCallback.invoke(
DownloadEpisodeClickEvent(
DOWNLOAD_ACTION_DOWNLOAD,
card
)
)*/
}
2 -> play(d)
3 -> delete()
}
}
}
DownloadStatusTell.Complete -> {
view.popupMenuNoIcons(
listOf(
2 to play,
3 to R.string.delete
)
) {
when (itemId) {
2 -> play(d)
3 -> delete()
}
}
}
DownloadStatusTell.Active -> {
view.popupMenuNoIcons(
if (isValid) listOf(
4 to R.string.pause,
2 to play,
3 to R.string.delete
) else listOf(
2 to play,
3 to R.string.delete
)
) {
when (itemId) {
4 -> view.pauseDownload()
2 -> play(d)
3 -> delete()
}
}
}
DownloadStatusTell.Error -> {
view.redownload()
}
DownloadStatusTell.Waiting -> {
}
else -> {}
}
}
}
}
fun handleDownloadClick(activity: Activity?, click: DownloadClickEvent) {
val id = click.data.id
if (click.data !is VideoDownloadHelper.DownloadEpisodeCached) return
@ -90,7 +227,8 @@ object DownloadButtonSetup {
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
act,
click.data.id
)?.fileLength ?: Aria2cHelper.getMetadata(click.data.id.toLong())?.downloadedLength
)?.fileLength
?: Aria2cHelper.getMetadata(click.data.id.toLong())?.downloadedLength
?: 0
if (length > 0) {
showToast(act, R.string.delete, Toast.LENGTH_LONG)

View File

@ -1,15 +1,12 @@
package com.lagradost.cloudstream3.ui.download
import android.text.format.Formatter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.core.view.doOnAttach
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.lifecycle.findViewTreeLifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.result.DownloadHelper.play
@ -17,10 +14,7 @@ import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.fetchbutton.aria2c.DownloadListener
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
import com.lagradost.fetchbutton.ui.PieFetchButton
import kotlinx.android.synthetic.main.download_child_episode.view.*
@ -31,11 +25,17 @@ const val DOWNLOAD_ACTION_PAUSE_DOWNLOAD = 3
const val DOWNLOAD_ACTION_DOWNLOAD = 4
const val DOWNLOAD_ACTION_LONG_CLICK = 5
interface IVisualDownloadChildCached{
val currentBytes: Long
val totalBytes: Long
val data: VideoDownloadHelper.DownloadEpisodeCached?
}
data class VisualDownloadChildCached(
val currentBytes: Long,
val totalBytes: Long,
val data: VideoDownloadHelper.DownloadEpisodeCached,
)
override val currentBytes: Long,
override val totalBytes: Long,
override val data: VideoDownloadHelper.DownloadEpisodeCached,
) : IVisualDownloadChildCached
data class DownloadClickEvent(val action: Int, val data: EasyDownloadButton.IMinimumData)
data class DownloadEpisodeClickEvent(val action: Int, val data: ResultEpisode)
@ -97,124 +97,8 @@ class DownloadChildAdapter(
title.text = title.context.getNameFull(d.name, d.episode, d.season)
title.isSelected = true // is needed for text repeating
//extraInfo.text = card.currentBytes
DownloadButtonSetup.bind(card, downloadButton, extraInfo, clickCallback)
fun updateText(downloadBytes: Long, totalBytes: Long) {
extraInfo?.apply {
text =
context.getString(R.string.download_size_format).format(
Formatter.formatShortFileSize(context, downloadBytes),
Formatter.formatShortFileSize(context, totalBytes)
)
}
}
updateText(card.currentBytes, card.totalBytes)
downloadButton.apply {
val play =
R.string.play_episode//if (card.episode <= 0) R.string.play_movie_button else R.string.play_episode
setPersistentId(d.id.toLong())
doOnAttach { view ->
view.findViewTreeLifecycleOwner()?.let { life ->
DownloadListener.observe(life) {
gid?.let { realGId ->
val meta = DownloadListener.getInfo(realGId)
updateText(meta.downloadedLength, meta.totalLength)
}
}
}
}
downloadButton.isVisible = when (downloadButton.currentStatus) {
null, DownloadStatusTell.Removed -> false
else -> true
}
downloadButton.setOnClickListener {
val view = downloadButton
fun delete() {
// view.deleteAllFiles()
clickCallback.invoke(
DownloadClickEvent(
DOWNLOAD_ACTION_DELETE_FILE,
d
)
)
}
//if (view !is PieFetchButton) return@setOnClickListener
when (view.currentStatus) {
/*null, DownloadStatusTell.Removed -> {
view.setStatus(DownloadStatusTell.Waiting)
downloadClickCallback.invoke(
DownloadEpisodeClickEvent(
DOWNLOAD_ACTION_DOWNLOAD,
card
)
)
}*/
DownloadStatusTell.Paused -> {
view.popupMenuNoIcons(
listOf(
1 to R.string.resume,
2 to play,
3 to R.string.delete
)
) {
when (itemId) {
1 -> if (!view.resumeDownload()) {
/*downloadClickCallback.invoke(
DownloadEpisodeClickEvent(
DOWNLOAD_ACTION_DOWNLOAD,
card
)
)*/
}
2 -> play(d)
3 -> delete()
}
}
}
DownloadStatusTell.Complete -> {
view.popupMenuNoIcons(
listOf(
2 to play,
3 to R.string.delete
)
) {
when (itemId) {
2 -> play(d)
3 -> delete()
}
}
}
DownloadStatusTell.Active -> {
view.popupMenuNoIcons(
listOf(
4 to R.string.pause,
2 to play,
3 to R.string.delete
)
) {
when (itemId) {
4 -> view.pauseDownload()
2 -> play(d)
3 -> delete()
}
}
}
DownloadStatusTell.Error -> {
view.redownload()
}
DownloadStatusTell.Waiting -> {
}
else -> {}
}
}
}
holder.setOnClickListener {
if (downloadButton.isVisible) {
downloadButton.play(d)

View File

@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey
import com.lagradost.cloudstream3.utils.DataStore.getKeys
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import kotlinx.android.synthetic.main.fragment_child_downloads.*
@ -41,7 +42,7 @@ class DownloadChildFragment : Fragment() {
): View? {
return inflater.inflate(R.layout.fragment_child_downloads, container, false)
}
private var hasPopped = false // fix stupid bug
private fun updateList(folder: String) = main {
context?.let { ctx ->
val data = withContext(Dispatchers.IO) { ctx.getKeys(folder) }
@ -54,8 +55,10 @@ class DownloadChildFragment : Fragment() {
VisualDownloadChildCached(info.fileLength, info.totalBytes, it)
}
}.sortedBy { it.data.episode + (it.data.season ?: 0) * 100000 }
if (eps.isEmpty()) {
activity?.onBackPressed()
if (eps.isEmpty() && !hasPopped) {
hasPopped = true
activity?.popCurrentPage()
return@main
}

View File

@ -69,7 +69,6 @@ class DownloadFragment : Fragment() {
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
downloadDeleteEventListener = null
}
(download_list?.adapter as DownloadHeaderAdapter?)?.killAdapter()
super.onDestroyView()
}
@ -165,7 +164,7 @@ class DownloadFragment : Fragment() {
downloadDeleteEventListener = { id ->
val list = (download_list?.adapter as DownloadHeaderAdapter?)?.cardList
if (list != null) {
if (list.any { it.data.id == id }) {
if (list.any { it.data?.id == id }) {
context?.let { ctx ->
setList(ArrayList())
downloadsViewModel.updateList(ctx)

View File

@ -8,23 +8,25 @@ import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.cardview.widget.CardView
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.fetchbutton.ui.PieFetchButton
import kotlinx.android.synthetic.main.download_header_episode.view.*
import java.util.*
data class VisualDownloadHeaderCached(
val currentOngoingDownloads: Int,
val totalDownloads: Int,
val totalBytes: Long,
val currentBytes: Long,
val data: VideoDownloadHelper.DownloadHeaderCached,
val child: VideoDownloadHelper.DownloadEpisodeCached?,
)
override val totalBytes: Long,
override val currentBytes: Long,
val header: VideoDownloadHelper.DownloadHeaderCached,
override val data: VideoDownloadHelper.DownloadEpisodeCached?,
) : IVisualDownloadChildCached
data class DownloadHeaderClickEvent(val action: Int, val data: VideoDownloadHelper.DownloadHeaderCached)
@ -34,35 +36,6 @@ class DownloadHeaderAdapter(
private val movieClickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
private fun getAllBoundViewHolders(): Set<DownloadButtonViewHolder?>? {
return Collections.unmodifiableSet(mBoundViewHolders)
}
fun killAdapter() {
getAllBoundViewHolders()?.forEach { view ->
view?.downloadButton?.dispose()
}
}
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
if (holder is DownloadButtonViewHolder) {
holder.downloadButton.dispose()
}
}
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
if (holder is DownloadButtonViewHolder) {
holder.downloadButton.dispose()
mBoundViewHolders.remove(holder)
}
}
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
if (holder is DownloadButtonViewHolder) {
holder.reattachDownloadButton()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return DownloadHeaderViewHolder(
@ -76,7 +49,6 @@ class DownloadHeaderAdapter(
when (holder) {
is DownloadHeaderViewHolder -> {
holder.bind(cardList[position])
mBoundViewHolders.add(holder)
}
}
}
@ -90,23 +62,17 @@ class DownloadHeaderAdapter(
itemView: View,
private val clickCallback: (DownloadHeaderClickEvent) -> Unit,
private val movieClickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
override var downloadButton = EasyDownloadButton()
) : RecyclerView.ViewHolder(itemView) {
private val poster: ImageView? = itemView.download_header_poster
private val title: TextView = itemView.download_header_title
private val extraInfo: TextView = itemView.download_header_info
private val holder: CardView = itemView.episode_holder
private val downloadBar: ContentLoadingProgressBar = itemView.download_header_progress_downloaded
private val downloadImage: ImageView = itemView.download_header_episode_download
private val normalImage: ImageView = itemView.download_header_goto_child
private var localCard: VisualDownloadHeaderCached? = null
private val downloadButton: PieFetchButton = itemView.download_header_download
@SuppressLint("SetTextI18n")
fun bind(card: VisualDownloadHeaderCached) {
localCard = card
val d = card.data
val d = card.header
poster?.setImage(d.poster)
poster?.setOnClickListener {
@ -117,10 +83,8 @@ class DownloadHeaderAdapter(
val mbString = formatShortFileSize(itemView.context, card.totalBytes)
//val isMovie = d.type.isMovieType()
if (card.child != null) {
downloadBar.visibility = View.VISIBLE
downloadImage.visibility = View.VISIBLE
normalImage.visibility = View.GONE
if (card.data != null) {
downloadButton.isVisible = true
/*setUpButton(
card.currentBytes,
card.totalBytes,
@ -130,14 +94,15 @@ class DownloadHeaderAdapter(
card.child,
movieClickCallback
)*/
DownloadButtonSetup.bind(card, downloadButton, extraInfo) { click ->
movieClickCallback.invoke(DownloadClickEvent(click.action, card.data))
}
holder.setOnClickListener {
movieClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.child))
movieClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, card.data))
}
} else {
downloadBar.visibility = View.GONE
downloadImage.visibility = View.GONE
normalImage.visibility = View.VISIBLE
downloadButton.isVisible = false
try {
extraInfo.text =
@ -160,21 +125,5 @@ class DownloadHeaderAdapter(
}
}
}
override fun reattachDownloadButton() {
downloadButton.dispose()
val card = localCard
if (card?.child != null) {
downloadButton.setUpButton(
card.currentBytes,
card.totalBytes,
downloadBar,
downloadImage,
extraInfo,
card.child,
movieClickCallback
)
}
}
}
}

View File

@ -49,6 +49,8 @@ class DownloadViewModel : ViewModel() {
.distinctBy { it.id } // Remove duplicates
}
println("CHILDRE:$children")
// parentId : bytes
val totalBytesUsedByChild = HashMap<Int, Long>()
// parentId : bytes
@ -69,7 +71,8 @@ class DownloadViewModel : ViewModel() {
totalDownloads[c.parentId] = totalDownloads[c.parentId]?.plus(1) ?: 1
}
}
println("FIXED: $totalDownloads")
println("TotalDownloads:$totalDownloads")
//println("FIXED: $totalDownloads")
val cached = withContext(Dispatchers.IO) { // wont fetch useless keys
totalDownloads.entries.filter { it.value > 0 }.mapNotNull {
context.getKey<VideoDownloadHelper.DownloadHeaderCached>(
@ -78,6 +81,7 @@ class DownloadViewModel : ViewModel() {
)
}
}
println("Cached:$cached")
val visual = withContext(Dispatchers.IO) {
cached.mapNotNull { // TODO FIX
@ -100,7 +104,7 @@ class DownloadViewModel : ViewModel() {
movieEpisode
)
}.sortedBy {
(it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0)
(it.data?.episode ?: 0) + (it.data?.season?.times(10000) ?: 0)
} // episode sorting by episode, lowest to highest
}
try {

View File

@ -530,6 +530,7 @@ object VideoDownloadManager {
MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY),
projection, selection, null, null
)
println("result:$result ${result?.count}")
result.use { c ->
if (c != null && c.count >= 1) {
@ -1505,21 +1506,31 @@ object VideoDownloadManager {
private fun getDownloadFileInfo(context: Context, id: Int): DownloadedFileInfoResult? {
try {
println("getDownloadFileInfo:$id")
val info =
context.getKey<DownloadedFileInfo>(KEY_DOWNLOAD_INFO, id.toString()) ?: return null
val base = basePathToFile(context, info.basePath)
println("BASE:$info")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && base.isDownloadDir()) {
val cr = context.contentResolver ?: return null
println("CR:$cr")
val fileUri =
cr.getExistingDownloadUriOrNullQ(info.relativePath, info.displayName)
?: return null
println("FILEURI:$fileUri")
val fileLength = cr.getFileLength(fileUri) ?: return null
println("fileLength:$fileLength")
if (fileLength == 0L) return null
return DownloadedFileInfoResult(fileLength, info.totalBytes, fileUri)
} else {
println("STUFF:$base")
val file = base?.gotoDir(info.relativePath, false)?.findFile(info.displayName)
println("file:$file")
// val normalPath = context.getNormalPath(getFile(info.relativePath), info.displayName)
// val dFile = File(normalPath)

View File

@ -1,103 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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"
app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="?attr/boxItemBackground"
android:id="@+id/episode_holder"
android:foreground="@drawable/outline_drawable"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginTop="10dp">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/episode_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="10dp"
android:foreground="@drawable/outline_drawable"
app:cardBackgroundColor="?attr/boxItemBackground"
app:cardCornerRadius="@dimen/rounded_image_radius">
<LinearLayout
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:orientation="horizontal">
<!--app:cardCornerRadius="@dimen/roundedImageRadius"-->
<androidx.cardview.widget.CardView
android:layout_width="70dp"
android:layout_height="104dp">
android:layout_width="70dp"
android:layout_height="104dp">
<ImageView
android:id="@+id/download_header_poster"
tools:src="@drawable/example_poster"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/episode_poster_img_des" />
android:id="@+id/download_header_poster"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/episode_poster_img_des"
android:scaleType="centerCrop"
tools:src="@drawable/example_poster" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_marginStart="15dp"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_marginEnd="70dp"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="15dp"
android:layout_marginEnd="50dp"
android:orientation="vertical">
<TextView
android:id="@+id/download_header_title"
tools:text="Perfect Run"
android:textStyle="bold"
android:textColor="?attr/textColor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/download_header_info"
tools:text="1 episode | 285MB"
android:textColor="?attr/grayTextColor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<ImageView
android:layout_marginStart="-50dp"
android:layout_height="match_parent"
android:padding="50dp"
android:layout_width="50dp"
android:id="@+id/download_header_goto_child"
android:layout_gravity="center_vertical|end"
android:src="@drawable/ic_baseline_keyboard_arrow_right_24"
android:contentDescription="@string/download" />
<FrameLayout
android:layout_marginStart="-50dp"
android:layout_gravity="end"
android:id="@+id/download_header_title"
android:layout_width="wrap_content"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:textColor="?attr/textColor"
android:textStyle="bold"
tools:text="Perfect Run" />
<androidx.core.widget.ContentLoadingProgressBar
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/download_header_progress_downloaded"
android:indeterminate="false"
android:progressDrawable="@drawable/circular_progress_bar_cs3"
android:background="@drawable/circle_shape_cs3"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:layout_margin="5dp"
android:layout_gravity="center_vertical"
android:progress="0"
android:visibility="visible" />
<ImageView
android:visibility="visible"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_width="50dp"
android:id="@+id/download_header_episode_download"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_play_arrow_24"
android:contentDescription="@string/download"
app:tint="?attr/white" />
</FrameLayout>
<TextView
android:id="@+id/download_header_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/grayTextColor"
tools:text="1 episode | 285MB" />
</LinearLayout>
</LinearLayout>
<com.lagradost.fetchbutton.ui.PieFetchButton
android:id="@+id/download_header_download"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_vertical|end"
android:background="?selectableItemBackgroundBorderless"
android:padding="10dp" />
</androidx.cardview.widget.CardView>