Compare commits

...

7 Commits

Author SHA1 Message Date
reduplicated a1165344d3 download UI fixes 2022-10-30 22:41:26 +01:00
reduplicated fa399cd350 play video and delete stuff 2022-10-30 02:35:37 +01:00
reduplicated 6a721941ac set keys things 2022-10-29 03:50:59 +02:00
reduplicated 572aa6de3e shit not working due to android storage fuckery 2022-09-23 22:05:06 +02:00
reduplicated 45ea1a8d8e testing movies 2022-09-22 00:23:26 +02:00
reduplicated 63e4e670c0 episode test 2022-09-18 13:25:17 +02:00
reduplicated 266a511cd7 testing aria2c UI 2022-09-18 00:05:28 +02:00
28 changed files with 1278 additions and 954 deletions

View File

@ -199,6 +199,9 @@ dependencies {
// Library/extensions searching with Levenshtein distance
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
// aria2c downloader
implementation 'com.github.LagradOst:Aria2cButton:v0.0.6'
}
task androidSourcesJar(type: Jar) {

View File

@ -17,6 +17,8 @@ import androidx.appcompat.widget.SearchView
import androidx.preference.PreferenceManager
import com.google.android.gms.cast.framework.CastSession
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.download.Aria2cHelper.removeMetadata
import com.lagradost.cloudstream3.ui.download.Aria2cHelper.saveMetadata
import com.lagradost.cloudstream3.ui.player.PlayerEventType
import com.lagradost.cloudstream3.ui.result.UiText
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.updateTv
@ -25,8 +27,13 @@ import com.lagradost.cloudstream3.utils.UIHelper
import com.lagradost.cloudstream3.utils.UIHelper.hasPIPPermission
import com.lagradost.cloudstream3.utils.UIHelper.shouldShowPIPMode
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import com.lagradost.fetchbutton.aria2c.Aria2Settings
import com.lagradost.fetchbutton.aria2c.Aria2Starter
import com.lagradost.fetchbutton.aria2c.DownloadListener
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
import org.schabi.newpipe.extractor.NewPipe
import java.util.*
import kotlin.concurrent.thread
object CommonActivity {
@MainThread
@ -129,6 +136,43 @@ object CommonActivity {
act.updateLocale()
act.updateTv()
NewPipe.init(DownloaderTestImpl.getInstance())
DownloadListener.mainListener = { (data, metadata) ->
//TODO FIX
DownloadListener.sessionGidToId[data.gid]?.let { id ->
if (metadata.status == DownloadStatusTell.Removed
|| metadata.status == DownloadStatusTell.Error
|| metadata.status == DownloadStatusTell.Waiting
|| metadata.status == null) {
removeMetadata(id)
} else {
saveMetadata(id, metadata)
}
/*val mainpath = metadata.items[0].files[0].path
AcraApplication.setKey(
VideoDownloadManager.KEY_DOWNLOAD_INFO,
id.toString(),
VideoDownloadManager.DownloadedFileInfo(
metadata.totalLength,
relativePath ?: "",
,
basePath = basePath.second
)
)*/
}
}
thread {
Aria2Starter.start(
act,
Aria2Settings(
"1337", //UUID.randomUUID().toString()
4337,
act.filesDir.path + "/download", //"/storage/emulated/0/Download",//
null//"${act.filesDir.path}/session"
)
)
}
}
private fun Activity.enterPIPMode() {

View File

@ -10,10 +10,10 @@ import android.view.KeyEvent
import android.view.Menu
import android.view.MenuItem
import android.view.WindowManager
import android.widget.Toast
import androidx.annotation.IdRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
import androidx.navigation.NavController
@ -107,6 +107,8 @@ const val VLC_EXTRA_POSITION_OUT = "extra_position"
const val VLC_EXTRA_DURATION_OUT = "extra_duration"
const val VLC_LAST_ID_KEY = "vlc_last_open_id"
const val DOWNLOAD_COUNT_KEY = "download_badge_count"
// Short name for requests client to make it nicer to use
var app = Requests(responseParser = object : ResponseParser {
@ -150,7 +152,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
* @return true if the str has launched an app task (be it successful or not)
* @param isWebview does not handle providers and opening download page if true. Can still add repos and login.
* */
fun handleAppIntentUrl(activity: FragmentActivity?, str: String?, isWebview: Boolean): Boolean =
fun handleAppIntentUrl(
activity: FragmentActivity?,
str: String?,
isWebview: Boolean
): Boolean =
with(activity) {
if (str != null && this != null) {
if (str.startsWith("https://cs.repo")) {
@ -191,7 +197,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
val url = str.replaceFirst(appStringRepo, "https")
loadRepository(url)
return true
} else if (!isWebview){
} else if (!isWebview) {
if (str.startsWith(DOWNLOAD_NAVIGATE_TO)) {
this.navigate(R.id.navigation_downloads)
return true
@ -267,6 +273,25 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
}
}
if (destination.id == R.id.navigation_download_child || destination.id == R.id.navigation_downloads) {
setKey(DOWNLOAD_COUNT_KEY, 0)
}
nav_view?.getOrCreateBadge(R.id.navigation_downloads)?.apply {
val count = getKey(DOWNLOAD_COUNT_KEY) ?: 0
if (count <= 0) {
clearNumber()
isVisible = false
} else {
this.backgroundColor =
getResourceColor(R.attr.colorPrimary)
this.badgeTextColor =
getResourceColor(R.attr.colorOnPrimary)
isVisible = true
number = count
}
}
nav_view?.isVisible = isNavVisible && !landscape
nav_rail_view?.isVisible = isNavVisible && landscape
}

View File

@ -0,0 +1,55 @@
package com.lagradost.cloudstream3.ui
import android.content.Context
import android.util.AttributeSet
import android.widget.TextView
import androidx.core.view.isVisible
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.R
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
import com.lagradost.fetchbutton.aria2c.Metadata
import com.lagradost.fetchbutton.ui.PieFetchButton
class DownloadButton(context: Context, attributeSet: AttributeSet) :
PieFetchButton(context, attributeSet) {
var progressText: TextView? = null
var mainText: TextView? = null
var bigButton: MaterialButton? = null
override fun onInflate() {
overrideLayout = R.layout.download_button_layout
super.onInflate()
progressText = findViewById(R.id.result_movie_download_text_precentage)
mainText = findViewById(R.id.result_movie_download_text)
bigButton = findViewById(R.id.download_big_button)
}
override fun setOnClickListener(l: OnClickListener?) {
bigButton?.setOnClickListener(l)
}
override fun setOnLongClickListener(l: OnLongClickListener?) {
bigButton?.setOnLongClickListener(l)
}
override fun setStatus(status: DownloadStatusTell?) {
super.setStatus(status)
val txt = when (status) {
DownloadStatusTell.Paused -> R.string.download_paused
DownloadStatusTell.Active -> R.string.downloading
DownloadStatusTell.Complete -> R.string.downloaded
else -> R.string.download
}
mainText?.setText(txt)
}
override fun updateViewOnDownload(metadata: Metadata) {
super.updateViewOnDownload(metadata)
val isVis = metadata.progressPercentage > 0
progressText?.isVisible = isVis
if (isVis)
progressText?.text = "${metadata.progressPercentage}%"
}
}

View File

@ -0,0 +1,68 @@
package com.lagradost.cloudstream3.ui.download
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import com.lagradost.cloudstream3.utils.VideoDownloadManager.KEY_DOWNLOAD_INFO
import com.lagradost.fetchbutton.aria2c.Aria2Starter
import com.lagradost.fetchbutton.aria2c.DownloadListener
import com.lagradost.fetchbutton.aria2c.Metadata
import java.io.File
const val KEY_DOWNLOAD_INFO_METADATA = "download_info_metadata"
object Aria2cHelper {
fun deleteId(id: Long) {
// backward compatibility
VideoDownloadManager.downloadDeleteEvent.invoke(id.toInt())
getMetadata(id)?.let { data ->
Aria2Starter.delete(
DownloadListener.sessionIdToGid[id],
id,
data.items.flatMap { it.files })
}
removeMetadata(id)
AcraApplication.removeKey(KEY_DOWNLOAD_INFO, id.toString())
}
fun saveMetadata(id: Long, meta: Metadata) {
AcraApplication.setKey(KEY_DOWNLOAD_INFO_METADATA, id.toString(), meta)
}
fun removeMetadata(id: Long) {
AcraApplication.removeKey(KEY_DOWNLOAD_INFO_METADATA, id.toString())
}
fun downloadExist(data: Metadata): Boolean {
return data.items.any {
it.files.any { file ->
try {
//println("TESTING PATH: ${file.path}")
File(file.path).exists()
} catch (e: Exception) {
false
}
}
}
}
fun downloadExist(id: Long): Boolean {
return downloadExist(getMetadata(id) ?: return false)
}
fun getMetadata(id: Long): Metadata? {
return AcraApplication.getKey(KEY_DOWNLOAD_INFO_METADATA, id.toString())
}
fun pause(id: Long) {
DownloadListener.sessionIdToGid[id]?.let { gid ->
Aria2Starter.pause(gid, all = true)
}
}
fun unpause(id: Long) {
DownloadListener.sessionIdToGid[id]?.let { gid ->
Aria2Starter.unpause(gid, all = true)
}
}
}

View File

@ -2,22 +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.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
@ -29,6 +167,7 @@ object DownloadButtonSetup {
DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
Aria2cHelper.deleteId(id.toLong())
VideoDownloadManager.deleteFileAndUpdateSettings(ctx, id)
}
DialogInterface.BUTTON_NEGATIVE -> {
@ -57,11 +196,14 @@ object DownloadButtonSetup {
}
}
DOWNLOAD_ACTION_PAUSE_DOWNLOAD -> {
Aria2cHelper.pause(click.data.id.toLong())
VideoDownloadManager.downloadEvent.invoke(
Pair(click.data.id, VideoDownloadManager.DownloadActionType.Pause)
)
}
DOWNLOAD_ACTION_RESUME_DOWNLOAD -> {
Aria2cHelper.unpause(click.data.id.toLong())
activity?.let { ctx ->
if (VideoDownloadManager.downloadStatus.containsKey(id) && VideoDownloadManager.downloadStatus[id] == VideoDownloadManager.DownloadType.IsPaused) {
VideoDownloadManager.downloadEvent.invoke(
@ -86,6 +228,7 @@ object DownloadButtonSetup {
act,
click.data.id
)?.fileLength
?: Aria2cHelper.getMetadata(click.data.id.toLong())?.downloadedLength
?: 0
if (length > 0) {
showToast(act, R.string.delete, Toast.LENGTH_LONG)

View File

@ -3,18 +3,20 @@ package com.lagradost.cloudstream3.ui.download
import android.view.LayoutInflater
import android.view.View
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.ui.result.DownloadHelper.play
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.VideoDownloadHelper
import com.lagradost.fetchbutton.ui.PieFetchButton
import kotlinx.android.synthetic.main.download_child_episode.view.*
import java.util.*
const val DOWNLOAD_ACTION_PLAY_FILE = 0
const val DOWNLOAD_ACTION_DELETE_FILE = 1
@ -23,52 +25,31 @@ 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)
class DownloadChildAdapter(
var cardList: List<VisualDownloadChildCached>,
private val clickCallback: (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 DownloadChildViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.download_child_episode, parent, false),
LayoutInflater.from(parent.context)
.inflate(R.layout.download_child_episode, parent, false),
clickCallback
)
}
@ -77,7 +58,6 @@ class DownloadChildAdapter(
when (holder) {
is DownloadChildViewHolder -> {
holder.bind(cardList[position])
mBoundViewHolders.add(holder)
}
}
}
@ -90,15 +70,13 @@ class DownloadChildAdapter(
constructor(
itemView: View,
private val clickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
override var downloadButton = EasyDownloadButton()
) : RecyclerView.ViewHolder(itemView) {
private val title: TextView = itemView.download_child_episode_text
private val extraInfo: TextView = itemView.download_child_episode_text_extra
private val holder: CardView = itemView.download_child_episode_holder
private val progressBar: ContentLoadingProgressBar = itemView.download_child_episode_progress
private val progressBarDownload: ContentLoadingProgressBar = itemView.download_child_episode_progress_downloaded
private val downloadImage: ImageView = itemView.download_child_episode_download
private val progressBar: ContentLoadingProgressBar =
itemView.download_child_episode_progress
private val downloadButton: PieFetchButton = itemView.download_child_episode_download
private var localCard: VisualDownloadChildCached? = null
@ -118,35 +96,17 @@ class DownloadChildAdapter(
title.text = title.context.getNameFull(d.name, d.episode, d.season)
title.isSelected = true // is needed for text repeating
downloadButton.setUpButton(
card.currentBytes,
card.totalBytes,
progressBarDownload,
downloadImage,
extraInfo,
card.data,
clickCallback
)
//extraInfo.text = card.currentBytes
DownloadButtonSetup.bind(card, downloadButton, extraInfo, clickCallback)
holder.setOnClickListener {
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d))
}
}
override fun reattachDownloadButton() {
downloadButton.dispose()
val card = localCard
if (card != null) {
downloadButton.setUpButton(
card.currentBytes,
card.totalBytes,
progressBarDownload,
downloadImage,
extraInfo,
card.data,
clickCallback
)
if (downloadButton.isVisible) {
downloadButton.play(d)
} else {
holder.setOnClickListener {
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, 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.*
@ -21,7 +22,7 @@ import kotlinx.coroutines.withContext
class DownloadChildFragment : Fragment() {
companion object {
fun newInstance(headerName: String, folder: String) : Bundle {
fun newInstance(headerName: String, folder: String): Bundle {
return Bundle().apply {
putString("folder", folder)
putString("name", headerName)
@ -30,15 +31,18 @@ class DownloadChildFragment : Fragment() {
}
override fun onDestroyView() {
(download_child_list?.adapter as DownloadChildAdapter?)?.killAdapter()
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
super.onDestroyView()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): 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) }
@ -50,9 +54,11 @@ class DownloadChildFragment : Fragment() {
?: return@mapNotNull null
VisualDownloadChildCached(info.fileLength, info.totalBytes, it)
}
}.sortedBy { it.data.episode + (it.data.season?: 0)*100000 }
if (eps.isEmpty()) {
activity?.onBackPressed()
}.sortedBy { it.data.episode + (it.data.season ?: 0) * 100000 }
if (eps.isEmpty() && !hasPopped) {
hasPopped = true
activity?.popCurrentPage()
return@main
}
@ -85,6 +91,13 @@ class DownloadChildFragment : Fragment() {
ArrayList(),
) { click ->
handleDownloadClick(activity, click)
/* println("HANDLE ACTION :${click.action}")
if (click.action == DOWNLOAD_ACTION_DELETE_FILE) {
val list = (download_child_list?.adapter as DownloadChildAdapter?)?.cardList
if (list != null) {
updateList(folder)
}
}*/
}
downloadDeleteEventListener = { id: Int ->

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

@ -1,12 +1,15 @@
package com.lagradost.cloudstream3.ui.download
import android.content.Context
import android.net.Uri
import android.os.Environment
import android.os.StatFs
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.isMovieType
import com.lagradost.cloudstream3.mvvm.launchSafe
import com.lagradost.cloudstream3.mvvm.logError
@ -46,6 +49,8 @@ class DownloadViewModel : ViewModel() {
.distinctBy { it.id } // Remove duplicates
}
println("CHILDRE:$children")
// parentId : bytes
val totalBytesUsedByChild = HashMap<Int, Long>()
// parentId : bytes
@ -53,12 +58,10 @@ class DownloadViewModel : ViewModel() {
// parentId : downloadsCount
val totalDownloads = HashMap<Int, Int>()
// Gets all children downloads
withContext(Dispatchers.IO) {
for (c in children) {
val childFile = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(context, c.id) ?: continue
if (childFile.fileLength <= 1) continue
val len = childFile.totalBytes
val flen = childFile.fileLength
@ -68,7 +71,8 @@ class DownloadViewModel : ViewModel() {
totalDownloads[c.parentId] = totalDownloads[c.parentId]?.plus(1) ?: 1
}
}
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>(
@ -77,6 +81,7 @@ class DownloadViewModel : ViewModel() {
)
}
}
println("Cached:$cached")
val visual = withContext(Dispatchers.IO) {
cached.mapNotNull { // TODO FIX
@ -99,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

@ -0,0 +1,166 @@
package com.lagradost.cloudstream3.ui.result
import androidx.core.net.toUri
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK
import com.lagradost.cloudstream3.ui.download.DownloadEpisodeClickEvent
import com.lagradost.cloudstream3.ui.player.DownloadFileGenerator
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
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.fetchbutton.aria2c.Aria2Starter
import com.lagradost.fetchbutton.aria2c.DownloadStatusTell
import com.lagradost.fetchbutton.ui.PieFetchButton
import java.io.File
object DownloadHelper {
fun PieFetchButton.play(card: VideoDownloadHelper.DownloadEpisodeCached) {
val files = this.getVideos()
// fucked af, but who cares
Aria2Starter.saveActivity.get()?.navigate(
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(DownloadFileGenerator(
files.map { path ->
val file = File(path)
ExtractorUri(
uri = file.toUri(),
id = card.id,
parentId = card.parentId,
name = context.getString(R.string.downloaded_file), //click.data.name ?: keyInfo.displayName
season = card.season,
episode = card.episode,
basePath = file.path,
displayName = file.name
//displayName = keyInfo.displayName,
//relativePath = keyInfo.relativePath,
)
}
)))
}
fun PieFetchButton.play(card: ResultEpisode) {
val files = this.getVideos()
// fucked af, but who cares
Aria2Starter.saveActivity.get()?.navigate(
R.id.global_to_navigation_player, GeneratorPlayer.newInstance(DownloadFileGenerator(
files.map { path ->
val file = File(path)
ExtractorUri(
uri = file.toUri(),
id = card.id,
parentId = card.parentId,
name = context.getString(R.string.downloaded_file), //click.data.name ?: keyInfo.displayName
season = card.season,
episode = card.episode,
headerName = card.headerName,
tvType = card.tvType,
basePath = file.path,
displayName = file.name,
//relativePath = keyInfo.relativePath,
)
}
)))
}
fun PieFetchButton.setUp(
card: ResultEpisode,
downloadClickCallback: (DownloadEpisodeClickEvent) -> Unit
) {
setPersistentId(card.id.toLong())
val play = if (card.episode <= 0) R.string.play_movie_button else R.string.play_episode
setOnLongClickListener { //Aria2Starter.saveActivity.get()
downloadClickCallback.invoke(
DownloadEpisodeClickEvent(
DOWNLOAD_ACTION_LONG_CLICK,
card
)
)
//showToast(it.context as? Activity, R.string.download, Toast.LENGTH_SHORT)
return@setOnLongClickListener true
}
setOnClickListener {
val view = this
//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(card)
3 -> view.deleteAllFiles()
}
}
}
DownloadStatusTell.Complete -> {
view.popupMenuNoIcons(
listOf(
2 to play,
3 to R.string.delete
)
) {
when (itemId) {
2 -> play(card)
3 -> view.deleteAllFiles()
}
}
}
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(card)
3 -> view.deleteAllFiles()
}
}
}
DownloadStatusTell.Error -> {
view.redownload()
}
DownloadStatusTell.Waiting -> {
}
else -> {}
}
}
}
}

View File

@ -13,23 +13,17 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.button.MaterialButton
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
import com.lagradost.cloudstream3.ui.download.DownloadButtonViewHolder
import com.lagradost.cloudstream3.ui.download.DownloadClickEvent
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
import com.lagradost.cloudstream3.ui.download.DownloadEpisodeClickEvent
import com.lagradost.cloudstream3.ui.result.DownloadHelper.setUp
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import kotlinx.android.synthetic.main.result_episode.view.*
import kotlinx.android.synthetic.main.result_episode.view.episode_text
import kotlinx.android.synthetic.main.result_episode_large.view.*
import kotlinx.android.synthetic.main.result_episode_large.view.episode_filler
import kotlinx.android.synthetic.main.result_episode_large.view.episode_progress
import kotlinx.android.synthetic.main.result_episode_large.view.result_episode_download
import kotlinx.android.synthetic.main.result_episode_large.view.result_episode_progress_downloaded
import java.util.*
import kotlinx.android.synthetic.main.result_episode_large_tv.view.*
const val ACTION_PLAY_EPISODE_IN_PLAYER = 1
const val ACTION_PLAY_EPISODE_IN_VLC_PLAYER = 2
@ -58,21 +52,10 @@ data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
class EpisodeAdapter(
private val hasDownloadSupport: Boolean,
private val clickCallback: (EpisodeClickEvent) -> Unit,
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
private val downloadClickCallback: (DownloadEpisodeClickEvent) -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var cardList: MutableList<ResultEpisode> = mutableListOf()
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.itemView.hasFocus()) {
holder.itemView.clearFocus()
@ -85,15 +68,6 @@ class EpisodeAdapter(
}
}
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
if (holder is DownloadButtonViewHolder) {
holder.downloadButton.dispose()
mBoundViewHolders.remove(holder)
//(holder.itemView as? FrameLayout?)?.descendantFocusability =
// ViewGroup.FOCUS_BLOCK_DESCENDANTS
}
}
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
if (holder is DownloadButtonViewHolder) {
//println("onViewAttachedToWindow = ${holder.absoluteAdapterPosition}")
@ -138,7 +112,6 @@ class EpisodeAdapter(
when (holder) {
is EpisodeCardViewHolder -> {
holder.bind(cardList[position])
mBoundViewHolders.add(holder)
}
}
}
@ -152,18 +125,12 @@ class EpisodeAdapter(
itemView: View,
private val hasDownloadSupport: Boolean,
private val clickCallback: (EpisodeClickEvent) -> Unit,
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView), DownloadButtonViewHolder {
override var downloadButton = EasyDownloadButton()
var episodeDownloadBar: ContentLoadingProgressBar? = null
var episodeDownloadImage: ImageView? = null
var localCard: ResultEpisode? = null
private val downloadClickCallback: (DownloadEpisodeClickEvent) -> Unit,
) : RecyclerView.ViewHolder(itemView) {
//override var downloadButton = EasyDownloadButton()
@SuppressLint("SetTextI18n")
fun bind(card: ResultEpisode) {
localCard = card
val isTrueTv = isTrueTvSettings()
val (parentView, otherView) = if (card.poster == null) {
@ -181,9 +148,10 @@ class EpisodeAdapter(
val episodeProgress: ContentLoadingProgressBar? = parentView.episode_progress
val episodePoster: ImageView? = parentView.episode_poster
episodeDownloadBar =
parentView.result_episode_progress_downloaded
episodeDownloadImage = parentView.result_episode_download
val downloadButton = parentView.result_episode_download
downloadButton.isVisible = hasDownloadSupport
downloadButton.setUp(card, downloadClickCallback)
val name =
if (card.name == null) "${episodeText.context.getString(R.string.episode)} ${card.episode}" else "${card.episode}. ${card.name}"
@ -242,49 +210,6 @@ class EpisodeAdapter(
return@setOnLongClickListener true
}
episodeDownloadImage?.isVisible = hasDownloadSupport
episodeDownloadBar?.isVisible = hasDownloadSupport
reattachDownloadButton()
}
override fun reattachDownloadButton() {
downloadButton.dispose()
val card = localCard
if (hasDownloadSupport && card != null) {
if (episodeDownloadBar == null ||
episodeDownloadImage == null
) return
val downloadInfo = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
itemView.context,
card.id
)
downloadButton.setUpButton(
downloadInfo?.fileLength,
downloadInfo?.totalBytes,
episodeDownloadBar ?: return,
episodeDownloadImage ?: return,
null,
VideoDownloadHelper.DownloadEpisodeCached(
card.name,
card.poster,
card.episode,
card.season,
card.id,
card.parentId,
card.rating,
card.description,
System.currentTimeMillis(),
)
) {
if (it.action == DOWNLOAD_ACTION_DOWNLOAD) {
clickCallback.invoke(EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, card))
} else {
downloadClickCallback.invoke(it)
}
}
}
}
}
}

View File

@ -35,20 +35,20 @@ import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK
import com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment
import com.lagradost.cloudstream3.ui.result.DownloadHelper.setUp
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.AppUtils.loadCache
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStoreHelper
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.UIHelper
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
@ -72,11 +72,6 @@ import kotlinx.android.synthetic.main.fragment_result.result_meta_rating
import kotlinx.android.synthetic.main.fragment_result.result_meta_site
import kotlinx.android.synthetic.main.fragment_result.result_meta_type
import kotlinx.android.synthetic.main.fragment_result.result_meta_year
import kotlinx.android.synthetic.main.fragment_result.result_movie_download_icon
import kotlinx.android.synthetic.main.fragment_result.result_movie_download_text
import kotlinx.android.synthetic.main.fragment_result.result_movie_download_text_precentage
import kotlinx.android.synthetic.main.fragment_result.result_movie_progress_downloaded
import kotlinx.android.synthetic.main.fragment_result.result_movie_progress_downloaded_holder
import kotlinx.android.synthetic.main.fragment_result.result_next_airing
import kotlinx.android.synthetic.main.fragment_result.result_next_airing_time
import kotlinx.android.synthetic.main.fragment_result.result_no_episodes
@ -253,11 +248,8 @@ open class ResultFragment : ResultTrailerPlayer() {
return inflater.inflate(resultLayout, container, false)
}
private var downloadButton: EasyDownloadButton? = null
override fun onDestroyView() {
updateUIListener = null
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
downloadButton?.dispose()
super.onDestroyView()
}
@ -344,7 +336,18 @@ open class ResultFragment : ResultTrailerPlayer() {
return@setOnLongClickListener true
}
main {
result_download_movie?.setUp(ep) {
when (it.action) {
DOWNLOAD_ACTION_DOWNLOAD -> viewModel.download(activity, it.data)
DOWNLOAD_ACTION_LONG_CLICK -> viewModel.handleAction(
activity,
EpisodeClickEvent(ACTION_DOWNLOAD_MIRROR, ep)
)
}
}
result_download_movie?.isVisible = true
/*main {
val file =
ioWorkSafe {
context?.let {
@ -389,11 +392,12 @@ open class ResultFragment : ResultTrailerPlayer() {
}
}
result_movie_progress_downloaded_holder?.isVisible = true
}
}*/
}
}
else -> {
result_movie_progress_downloaded_holder?.isVisible = false
//result_movie_progress_downloaded_holder?.isVisible = false
result_download_movie?.isVisible = false
result_play_movie?.isVisible = false
}
}
@ -458,7 +462,14 @@ open class ResultFragment : ResultTrailerPlayer() {
val storedData = getStoredData(activity ?: context ?: return) ?: return
//viewModel.clear()
viewModel.load(activity, storedData.url ?: return, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
viewModel.load(
activity,
storedData.url ?: return,
storedData.apiName,
storedData.showFillers,
storedData.dubStatus,
storedData.start
)
}
}
@ -507,8 +518,15 @@ open class ResultFragment : ResultTrailerPlayer() {
{ episodeClick ->
viewModel.handleAction(activity, episodeClick)
},
{ downloadClickEvent ->
handleDownloadClick(activity, downloadClickEvent)
{ clickEvent ->
when (clickEvent.action) {
DOWNLOAD_ACTION_DOWNLOAD -> viewModel.download(activity, clickEvent.data)
DOWNLOAD_ACTION_LONG_CLICK -> viewModel.handleAction(
activity,
EpisodeClickEvent(ACTION_DOWNLOAD_MIRROR, clickEvent.data)
)
}
//handleDownloadClick(activity, downloadClickEvent)
}
)
@ -916,7 +934,14 @@ open class ResultFragment : ResultTrailerPlayer() {
if (storedData?.url != null) {
result_reload_connectionerror.setOnClickListener {
viewModel.load(activity, storedData.url, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
viewModel.load(
activity,
storedData.url,
storedData.apiName,
storedData.showFillers,
storedData.dubStatus,
storedData.start
)
}
result_reload_connection_open_in_browser?.setOnClickListener {
@ -952,7 +977,14 @@ open class ResultFragment : ResultTrailerPlayer() {
if (restart || !viewModel.hasLoaded()) {
//viewModel.clear()
viewModel.load(activity, storedData.url, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
viewModel.load(
activity,
storedData.url,
storedData.apiName,
storedData.showFillers,
storedData.dubStatus,
storedData.start
)
}
}
}

View File

@ -16,6 +16,8 @@ import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getId
import com.lagradost.cloudstream3.APIHolder.unixTime
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity.getCastSession
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
@ -28,7 +30,6 @@ import com.lagradost.cloudstream3.syncproviders.SyncAPI
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
import com.lagradost.cloudstream3.ui.player.IGenerator
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
@ -53,8 +54,14 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.setDub
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultEpisode
import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason
import com.lagradost.cloudstream3.utils.UIHelper.checkWrite
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
import com.lagradost.fetchbutton.NotificationMetaData
import com.lagradost.fetchbutton.aria2c.Aria2Starter
import com.lagradost.fetchbutton.aria2c.UriRequest
import com.lagradost.fetchbutton.aria2c.newUriRequest
import com.lagradost.fetchbutton.utils.Coroutines.mainThread
import kotlinx.coroutines.*
import java.io.File
import java.lang.Math.abs
@ -529,24 +536,16 @@ class ResultViewModel2 : ViewModel() {
}
private fun downloadSubtitle(
context: Context?,
link: ExtractorSubtitleLink,
fileName: String,
folder: String
) {
ioSafe {
VideoDownloadManager.downloadThing(
context ?: return@ioSafe,
link,
"$fileName ${link.name}",
folder,
if (link.url.contains(".srt")) ".srt" else "vtt",
false,
null
) {
// no notification
}
}
Aria2Starter.download(
newUriRequest(
null, link.url, fileName, folder, link.headers,
USER_AGENT
)
)
}
private fun getFolder(currentType: TvType, titleName: String): String {
@ -576,7 +575,6 @@ class ResultViewModel2 : ViewModel() {
val fileName = VideoDownloadManager.getFileName(ctx, meta)
val folder = getFolder(meta.type ?: return, meta.mainName)
downloadSubtitle(
ctx,
ExtractorSubtitleLink(link.name, link.url, ""),
fileName,
folder
@ -584,8 +582,7 @@ class ResultViewModel2 : ViewModel() {
}
}
fun startDownload(
context: Context?,
fun getDownloadRequest(
episode: ResultEpisode,
currentIsMovie: Boolean,
currentHeaderName: String,
@ -596,93 +593,182 @@ class ResultViewModel2 : ViewModel() {
url: String,
links: List<ExtractorLink>,
subs: List<SubtitleData>?
) {
try {
if (context == null) return
val meta =
getMeta(
episode,
currentHeaderName,
apiName,
currentPoster,
currentIsMovie,
currentType
)
val folder = getFolder(currentType, currentHeaderName)
val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
// SET VISUAL KEYS
AcraApplication.setKey(
DOWNLOAD_HEADER_CACHE,
parentId.toString(),
VideoDownloadHelper.DownloadHeaderCached(
apiName,
url,
currentType,
currentHeaderName,
currentPoster,
parentId,
System.currentTimeMillis(),
)
): DownloadRequest? {
val meta =
getMeta(
episode,
currentHeaderName,
apiName,
currentPoster,
currentIsMovie,
currentType
)
AcraApplication.setKey(
DataStore.getFolderName(
DOWNLOAD_EPISODE_CACHE,
parentId.toString()
), // 3 deep folder for faster acess
episode.id.toString(),
VideoDownloadHelper.DownloadEpisodeCached(
episode.name,
episode.poster,
episode.episode,
episode.season,
episode.id,
parentId,
episode.rating,
episode.description,
System.currentTimeMillis(),
)
)
val topFolder = VideoDownloadManager.getDownloadDir()?.filePath
?: throw RuntimeException("FUCK YOU")//AcraApplication.context?.getBasePath()?.first //?.second?.also { println("URIIIIII: $it") } ?: throw RuntimeException("FUCK YOU")
//?: VideoDownloadManager.getDownloadDir()?.filePath ?: return null
// DOWNLOAD VIDEO
VideoDownloadManager.downloadEpisodeUsingWorker(
context,
src,//url ?: return,
folder,
meta,
links
)
val folder =
topFolder//topFolder?.gotoDir(getFolder(currentType, currentHeaderName).replace(".", ""), true)?.uri?.toString() ?: throw RuntimeException("FUCK YOU")
//val folder =
// topFolder + "/" + getFolder(currentType, currentHeaderName).replace(".", "")
//val src = "$DOWNLOAD_NAVIGATE_TO/$parentId" // url ?: return@let
// 1. Checks if the lang should be downloaded
// 2. Makes it into the download format
// 3. Downloads it as a .vtt file
val downloadList = SubtitlesFragment.getDownloadSubsLanguageISO639_1()
subs?.let { subsList ->
subsList.filter {
downloadList.contains(
SubtitleHelper.fromLanguageToTwoLetters(
it.name,
true
)
)
}
.map { ExtractorSubtitleLink(it.name, it.url, "") }
.forEach { link ->
val fileName = VideoDownloadManager.getFileName(context, meta)
downloadSubtitle(context, link, fileName, folder)
}
// SET VISUAL KEYS
AcraApplication.setKey(
DOWNLOAD_HEADER_CACHE,
parentId.toString(),
VideoDownloadHelper.DownloadHeaderCached(
apiName,
url,
currentType,
currentHeaderName,
currentPoster,
parentId,
System.currentTimeMillis(),
)
)
AcraApplication.setKey(
DataStore.getFolderName(
DOWNLOAD_EPISODE_CACHE,
parentId.toString()
), // 3 deep folder for faster acess
episode.id.toString(),
VideoDownloadHelper.DownloadEpisodeCached(
episode.name,
episode.poster,
episode.episode,
episode.season,
episode.id,
parentId,
episode.rating,
episode.description,
System.currentTimeMillis(),
)
)
val notification = AcraApplication.context?.let { ctx ->
val rowTwoExtra = if (episode.name != null) " - ${episode.name}\n" else ""
val rowTwo = if (episode.season != null && episode.episode > 0) {
"${ctx.getString(R.string.season_short)}${episode.season}:${ctx.getString(R.string.episode_short)}${episode.episode}" + rowTwoExtra
} else if (episode.episode > 0) {
"${ctx.getString(R.string.episode)} ${episode.episode}" + rowTwoExtra
} else {
(episode.name ?: "") + ""
}
} catch (e: Exception) {
logError(e)
NotificationMetaData(
episode.id,
iconColor = ctx.colorFromAttribute(R.attr.colorPrimary),
posterUrl = currentPoster,
contentTitle = currentHeaderName,
secondRow = rowTwo,
subText = null,
linkName = null,
)
}
val linkRequests = links.filter { link -> !link.isM3u8 }.map { link ->
newUriRequest(
episode.id.toLong(), link.url,
getFolder(currentType, currentHeaderName) + File.pathSeparator +
VideoDownloadManager.getDisplayName(
VideoDownloadManager.getFileName(
AcraApplication.context ?: return null,
meta
), "mp4"
), null, // we use the dir set at start
link.headers, USER_AGENT,
notificationMetaData = notification?.copy(
linkName = "${link.name} ${
Qualities.getStringByInt(
link.quality
)
}"
)
)
}
val downloadList = SubtitlesFragment.getDownloadSubsLanguageISO639_1()
val downloadSubsList = (subs ?: emptyList()).filter {
downloadList.contains(
SubtitleHelper.fromLanguageToTwoLetters(
it.name,
true
)
)
}.distinctBy { it.url }.groupBy { link ->
SubtitleHelper.fromLanguageToTwoLetters(
link.name,
true
)
}.map {
it.value.map { link ->
val fileName = VideoDownloadManager.getDisplayName(
VideoDownloadManager.getFileName(
AcraApplication.context ?: return null,
meta
), "vtt"
)
newUriRequest(null, link.url, fileName, folder, link.headers, USER_AGENT)
//downloadSubtitle(context, link, fileName, folder)
}
}
return DownloadRequest(linkRequests, downloadSubsList)
// DOWNLOAD VIDEO
//VideoDownloadManager.downloadEpisodeUsingWorker(
// context,
// src,//url ?: return,
// folder,
// meta,
// links
//)
// 1. Checks if the lang should be downloaded
// 2. Makes it into the download format
// 3. Downloads it as a .vtt file
//val downloadList = SubtitlesFragment.getDownloadSubsLanguageISO639_1()
//subs?.let { subsList ->
// subsList.filter {
// downloadList.contains(
// SubtitleHelper.fromLanguageToTwoLetters(
// it.name,
// true
// )
// )
// }
// .map { ExtractorSubtitleLink(it.name, it.url, "") }
// .forEach { link ->
// val fileName = VideoDownloadManager.getFileName(context, meta)
// downloadSubtitle(context, link, fileName, folder)
// }
//}
}
data class DownloadRequest(
val links: List<UriRequest>,
val subs: List<List<UriRequest>>,
)
/*suspend fun download(episode: ResultEpisode): DownloadRequest {
val generator = RepoLinkGenerator(listOf(episode))
val currentLinks = mutableSetOf<ExtractorLink>()
val currentSubs = mutableSetOf<SubtitleData>()
generator.generateLinks(clearCache = false, isCasting = false, callback = {
it.first?.let { link ->
currentLinks.add(link)
}
}, subtitleCallback = { sub ->
currentSubs.add(sub)
})
}*/
suspend fun downloadEpisode(
activity: Activity?,
episode: ResultEpisode,
currentIsMovie: Boolean,
currentHeaderName: String,
@ -691,52 +777,49 @@ class ResultViewModel2 : ViewModel() {
apiName: String,
parentId: Int,
url: String,
) {
ioSafe {
val generator = RepoLinkGenerator(listOf(episode))
val currentLinks = mutableSetOf<ExtractorLink>()
val currentSubs = mutableSetOf<SubtitleData>()
generator.generateLinks(clearCache = false, isCasting = false, callback = {
it.first?.let { link ->
currentLinks.add(link)
}
}, subtitleCallback = { sub ->
currentSubs.add(sub)
})
if (currentLinks.isEmpty()) {
main {
showToast(
activity,
R.string.no_links_found_toast,
Toast.LENGTH_SHORT
)
}
return@ioSafe
} else {
main {
showToast(
activity,
R.string.download_started,
Toast.LENGTH_SHORT
)
}
): DownloadRequest? {
val generator = RepoLinkGenerator(listOf(episode))
val currentLinks = mutableSetOf<ExtractorLink>()
val currentSubs = mutableSetOf<SubtitleData>()
generator.generateLinks(clearCache = false, isCasting = false, callback = {
it.first?.let { link ->
currentLinks.add(link)
}
}, subtitleCallback = { sub ->
currentSubs.add(sub)
})
startDownload(
activity,
episode,
currentIsMovie,
currentHeaderName,
currentType,
currentPoster,
apiName,
parentId,
url,
sortUrls(currentLinks),
sortSubs(currentSubs),
)
}
//if (currentLinks.isEmpty()) {
// main {
// showToast(
// activity,
// R.string.no_links_found_toast,
// Toast.LENGTH_SHORT
// )
// }
// return@ioSafe
//} else {
// main {
// showToast(
// activity,
// R.string.download_started,
// Toast.LENGTH_SHORT
// )
// }
//}
return getDownloadRequest(
episode,
currentIsMovie,
currentHeaderName,
currentType,
currentPoster,
apiName,
parentId,
url,
sortUrls(currentLinks),
sortSubs(currentSubs),
)
}
private fun getMeta(
@ -1021,6 +1104,42 @@ class ResultViewModel2 : ViewModel() {
handleEpisodeClickEvent(activity, click)
}
private fun downloadFromRequest(activity: Activity?, req: DownloadRequest) {
Aria2Starter.download(req.links)
for (sub in req.subs.take(4)) { // download max 4 langs to not block real download
Aria2Starter.download(sub)
}
val linksFound = req.links.isNotEmpty()
setKey(DOWNLOAD_COUNT_KEY, (getKey(DOWNLOAD_COUNT_KEY) ?: 0) + 1)
mainThread {
showToast(
activity,
if (linksFound) R.string.download_started else R.string.no_links_found_toast,
Toast.LENGTH_SHORT
)
}
}
fun download(activity: Activity?, card: ResultEpisode) = ioSafe {
getRequest(card)?.let { req ->
downloadFromRequest(activity, req)
}
}
suspend fun getRequest(card: ResultEpisode): DownloadRequest? {
val response = currentResponse ?: return null
return downloadEpisode(
card,
response.isMovie(),
response.name,
response.type,
response.posterUrl,
response.apiName,
response.getId(),
response.url
)
}
private suspend fun handleEpisodeClickEvent(activity: Activity?, click: EpisodeClickEvent) {
when (click.action) {
ACTION_SHOW_OPTIONS -> {
@ -1117,18 +1236,11 @@ class ResultViewModel2 : ViewModel() {
showToast(activity, R.string.play_episode_toast, Toast.LENGTH_SHORT)
}
ACTION_DOWNLOAD_EPISODE -> {
val response = currentResponse ?: return
downloadEpisode(
activity,
click.data,
response.isMovie(),
response.name,
response.type,
response.posterUrl,
response.apiName,
response.getId(),
response.url
)
ioSafe {
val response = currentResponse ?: return@ioSafe
val req = getRequest(click.data) ?: return@ioSafe
Aria2Starter.client?.downloadFailQueue(req.links) { _, _ -> }
}
}
ACTION_DOWNLOAD_MIRROR -> {
val response = currentResponse ?: return
@ -1138,8 +1250,7 @@ class ResultViewModel2 : ViewModel() {
txt(R.string.episode_action_download_mirror)
) { (result, index) ->
ioSafe {
startDownload(
activity,
val req = getDownloadRequest(
click.data,
response.isMovie(),
response.name,
@ -1150,13 +1261,9 @@ class ResultViewModel2 : ViewModel() {
response.url,
listOf(result.links[index]),
result.subs,
)
) ?: return@ioSafe
downloadFromRequest(activity, req)
}
showToast(
activity,
R.string.download_started,
Toast.LENGTH_SHORT
)
}
}
ACTION_RELOAD_EPISODE -> {
@ -1592,7 +1699,8 @@ class ResultViewModel2 : ViewModel() {
val idIndex = ep.key.id
for ((index, i) in ep.value.withIndex()) {
val episode = i.episode ?: (index + 1)
val id = mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000) ?: 0)
val id =
mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000) ?: 0)
if (!existingEpisodes.contains(id)) {
existingEpisodes.add(id)
val seasonData = loadResponse.seasonNames.getSeason(i.season)

View File

@ -22,15 +22,14 @@ import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import com.fasterxml.jackson.annotation.JsonProperty
import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
import com.lagradost.cloudstream3.services.VideoDownloadService
import com.lagradost.cloudstream3.ui.download.Aria2cHelper
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.DataStore.getKey
@ -426,7 +425,7 @@ object VideoDownloadManager {
}
private const val reservedChars = "|\\?*<\":>+[]/\'"
fun sanitizeFilename(name: String, removeSpaces: Boolean= false): String {
fun sanitizeFilename(name: String, removeSpaces: Boolean = false): String {
var tempName = name
for (c in reservedChars) {
tempName = tempName.replace(c, ' ')
@ -531,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) {
@ -941,7 +941,7 @@ object VideoDownloadManager {
* @param directoryName if null will use the current path.
* @return UniFile / null if createMissingDirectories = false and folder is not found.
* */
private fun UniFile.gotoDir(
fun UniFile.gotoDir(
directoryName: String?,
createMissingDirectories: Boolean = true
): UniFile? {
@ -995,7 +995,7 @@ object VideoDownloadManager {
}
}
private fun getDisplayName(name: String, extension: String): String {
fun getDisplayName(name: String, extension: String): String {
return "$name.$extension"
}
@ -1487,27 +1487,50 @@ object VideoDownloadManager {
fun getDownloadFileInfoAndUpdateSettings(context: Context, id: Int): DownloadedFileInfoResult? {
val res = getDownloadFileInfo(context, id)
if (res == null) context.removeKey(KEY_DOWNLOAD_INFO, id.toString())
if (res == null) {
Aria2cHelper.getMetadata(id.toLong())?.let { data ->
if (Aria2cHelper.downloadExist(data)) {
return DownloadedFileInfoResult(
data.downloadedLength,
data.totalLength,
Uri.EMPTY
)
}
}
Aria2cHelper.deleteId(id.toLong())
context.removeKey(KEY_DOWNLOAD_INFO, id.toString())
}
return res
}
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)
@ -1612,20 +1635,20 @@ object VideoDownloadManager {
.mapIndexed { index, any -> DownloadQueueResumePackage(index, any) }
.toTypedArray()
setKey(KEY_RESUME_QUEUE_PACKAGES, dQueue)
} catch (t : Throwable) {
} catch (t: Throwable) {
logError(t)
}
}
/*fun isMyServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager?
for (service in manager!!.getRunningServices(Int.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
return true
}
/*fun isMyServiceRunning(context: Context, serviceClass: Class<*>): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager?
for (service in manager!!.getRunningServices(Int.MAX_VALUE)) {
if (serviceClass.name == service.service.className) {
return true
}
return false
}*/
}
return false
}*/
fun downloadEpisode(
context: Context?,

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
style="@style/BlackButton"
android:id="@+id/download_big_button"
android:layout_width="match_parent"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:visibility="visible" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center">
<include
android:layout_gravity="center"
layout="@layout/download_button_view"
android:layout_width="35dp"
android:layout_height="35dp" />
<TextView
android:id="@+id/result_movie_download_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:letterSpacing="0.09"
android:textAllCaps="false"
android:textColor="?attr/textColor"
android:textSize="15sp"
android:textStyle="bold"
tools:text="Downloading" />
<TextView
android:id="@+id/result_movie_download_text_precentage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:letterSpacing="0.09"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textAllCaps="false"
android:textColor="?attr/textColor"
android:textSize="15sp"
android:textStyle="bold"
android:visibility="gone"
tools:text="68%"
tools:visibility="visible" />
</LinearLayout>
</FrameLayout>

View File

@ -1,118 +1,95 @@
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:nextFocusRight="@id/download_child_episode_download"
android:nextFocusLeft="@id/nav_rail_view"
android:id="@+id/download_child_episode_holder"
android:layout_width="match_parent"
android:id="@+id/download_child_episode_holder"
android:layout_width="match_parent"
android:layout_height="50dp"
app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="@color/transparent"
app:cardElevation="0dp"
android:foreground="@drawable/outline_drawable"
android:layout_marginBottom="5dp">
android:layout_height="50dp"
android:layout_marginBottom="5dp"
android:foreground="@drawable/outline_drawable"
android:nextFocusLeft="@id/nav_rail_view"
android:nextFocusRight="@id/download_child_episode_download"
app:cardBackgroundColor="@color/transparent"
app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardElevation="0dp">
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/download_child_episode_progress"
android:id="@+id/download_child_episode_progress"
android:layout_marginBottom="-1.5dp"
android:progressTint="?attr/colorPrimary"
android:progressBackgroundTint="?attr/colorPrimary"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
tools:progress="50"
android:layout_gravity="bottom"
android:layout_height="5dp" />
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_gravity="bottom"
android:layout_marginBottom="-1.5dp"
android:progressBackgroundTint="?attr/colorPrimary"
android:progressTint="?attr/colorPrimary"
tools:progress="50" />
<GridLayout
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless">
<ImageView
android:id="@+id/download_child_episode_play"
android:visibility="gone"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_baseline_play_arrow_24"
android:contentDescription="@string/episode_play_img_des" />
android:id="@+id/download_child_episode_play"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:contentDescription="@string/episode_play_img_des"
android:src="@drawable/ic_baseline_play_arrow_24"
android:visibility="gone" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="50dp"
android:orientation="vertical">
<TextView
android:id="@+id/download_child_episode_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="vertical"
android:layout_height="wrap_content"
android:layout_marginEnd="50dp"
android:layout_width="match_parent">
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="?attr/textColor"
tools:text="Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1" />
<TextView
android:id="@+id/download_child_episode_text"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
tools:text="Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1"
android:scrollHorizontally="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:textColor="?attr/textColor"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/download_child_episode_text_extra"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
tools:text="128MB / 237MB"
android:textColor="?attr/grayTextColor"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
android:id="@+id/download_child_episode_text_extra"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:gravity="center_vertical"
android:textColor="?attr/grayTextColor"
tools:text="128MB / 237MB" />
</LinearLayout>
<FrameLayout
android:layout_marginStart="-50dp"
android:layout_gravity="end"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/download_child_episode_progress_downloaded"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:indeterminate="false"
android:progressDrawable="@drawable/circular_progress_bar"
android:background="@drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:layout_margin="5dp"
android:layout_gravity="end|center_vertical"
android:progress="0"
android:visibility="visible" />
<ImageView
android:nextFocusRight="@id/download_child_episode_holder"
android:nextFocusLeft="@id/download_child_episode_holder"
android:id="@+id/download_child_episode_download"
android:visibility="visible"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:layout_width="50dp"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_play_arrow_24"
app:tint="?attr/textColor"
android:contentDescription="@string/download" />
</FrameLayout>
</GridLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end">
<com.lagradost.fetchbutton.ui.PieFetchButton
android:id="@+id/download_child_episode_download"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center"
android:background="?selectableItemBackgroundBorderless"
android:padding="10dp" />
</FrameLayout>
</androidx.cardview.widget.CardView>

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"
android:background="@drawable/circle_shape"
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>

View File

@ -569,90 +569,12 @@
android:clickable="true"
android:focusable="true"
android:layout_width="match_parent" />-->
<FrameLayout
android:id="@+id/result_movie_progress_downloaded_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.button.MaterialButton
android:id="@+id/result_download_movie"
style="@style/BlackButton"
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:clickable="true"
android:focusable="true"
android:nextFocusUp="@id/result_play_movie"
android:nextFocusDown="@id/result_season_button"
android:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/result_movie_progress_downloaded"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="end|center_vertical"
android:layout_margin="5dp"
android:background="@drawable/circle_shape"
android:indeterminate="false"
android:max="100"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:progress="30"
android:progressDrawable="@drawable/circular_progress_bar_filled"
android:visibility="visible" />
<ImageView
android:id="@+id/result_movie_download_icon"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/download"
android:src="@drawable/ic_baseline_play_arrow_24"
android:visibility="visible"
app:tint="?attr/white" />
<TextView
android:id="@+id/result_movie_download_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:letterSpacing="0.09"
android:textAllCaps="false"
android:textColor="?attr/textColor"
android:textSize="15sp"
android:textStyle="bold"
tools:text="Downloading" />
<TextView
android:id="@+id/result_movie_download_text_precentage"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:letterSpacing="0.09"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textAllCaps="false"
android:textColor="?attr/textColor"
android:textSize="15sp"
android:textStyle="bold"
android:visibility="gone"
tools:text="68%" />
</LinearLayout>
</FrameLayout>
<com.lagradost.cloudstream3.ui.DownloadButton
android:id="@+id/result_download_movie"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
app:aria2c_layout="@layout/download_button_layout" />
<!--<androidx.core.widget.ContentLoadingProgressBar
android:layout_width="match_parent"

View File

@ -418,109 +418,25 @@
</com.google.android.material.button.MaterialButton>
<FrameLayout
android:nextFocusRight="@id/result_bookmark_button"
android:id="@+id/result_movie_progress_downloaded_holder"
<com.lagradost.cloudstream3.ui.DownloadButton
android:id="@+id/result_download_movie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_weight="1"
android:minWidth="250dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/result_download_movie"
style="@style/BlackButton"
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:clickable="true"
android:focusable="true"
android:nextFocusLeft="@id/result_play_movie"
android:nextFocusUp="@id/result_cast_items"
android:nextFocusDown="@id/result_resume_series_button_play"
android:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal">
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/result_movie_progress_downloaded"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="end|center_vertical"
android:layout_margin="5dp"
android:background="@drawable/circle_shape"
android:indeterminate="false"
android:max="100"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:progress="30"
android:progressDrawable="@drawable/circular_progress_bar_filled"
android:visibility="visible" />
<ImageView
android:id="@+id/result_movie_download_icon"
android:layout_width="30dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/download"
android:src="@drawable/ic_baseline_play_arrow_24"
android:visibility="visible"
app:tint="?attr/white" />
<TextView
android:id="@+id/result_movie_download_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:letterSpacing="0.09"
android:textAllCaps="false"
android:textColor="?attr/textColor"
android:textSize="15sp"
android:textStyle="bold"
tools:text="Downloading" />
<TextView
android:id="@+id/result_movie_download_text_precentage"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:letterSpacing="0.09"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:textAllCaps="false"
android:textColor="?attr/textColor"
android:textSize="15sp"
android:textStyle="bold"
android:visibility="gone"
tools:text="68%" />
</LinearLayout>
</FrameLayout>
android:minWidth="250dp"
android:layout_height="wrap_content" />
<com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
android:nextFocusDown="@id/result_resume_series_button_play"
android:id="@+id/result_bookmark_button"
style="@style/BlackButton"
android:layout_width="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="10dp"
android:layout_weight="1"
android:minWidth="250dp"
android:nextFocusLeft="@id/result_download_movie"
android:nextFocusDown="@id/result_resume_series_button_play"
android:text="@string/type_none"
android:visibility="visible" />
</LinearLayout>

View File

@ -95,35 +95,13 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">
<androidx.core.widget.ContentLoadingProgressBar
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/result_episode_progress_downloaded"
android:indeterminate="false"
android:progressDrawable="@drawable/circular_progress_bar"
android:background="@drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:layout_margin="5dp"
android:layout_gravity="end|center_vertical"
android:progress="0"
android:visibility="visible" />
<!--
android:nextFocusRight="@id/episode_holder"-->
<ImageView
android:nextFocusLeft="@id/episode_holder"
app:tint="?attr/white"
android:id="@+id/result_episode_download"
android:visibility="visible"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:layout_width="50dp"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_play_arrow_24"
android:contentDescription="@string/download" />
<com.lagradost.fetchbutton.ui.PieFetchButton
android:background="?selectableItemBackgroundBorderless"
android:id="@+id/result_episode_download"
android:layout_gravity="center"
android:padding="10dp"
android:layout_width="50dp"
android:layout_height="50dp">
</com.lagradost.fetchbutton.ui.PieFetchButton>
</FrameLayout>
</androidx.cardview.widget.CardView>

View File

@ -1,151 +1,130 @@
<?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"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:nextFocusRight="@id/result_episode_download"
android:id="@+id/episode_holder_large"
android:id="@+id/episode_holder_large"
android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/rounded_image_radius"
app:cardBackgroundColor="?attr/boxItemBackground"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:nextFocusRight="@id/result_episode_download"
app:cardBackgroundColor="?attr/boxItemBackground"
android:layout_marginBottom="10dp">
app:cardCornerRadius="@dimen/rounded_image_radius">
<LinearLayout
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="10dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!--app:cardCornerRadius="@dimen/roundedImageRadius"-->
<androidx.cardview.widget.CardView
android:layout_width="126dp"
android:layout_height="72dp"
android:foreground="@drawable/outline_drawable">
android:layout_width="126dp"
android:layout_height="72dp"
android:foreground="@drawable/outline_drawable">
<ImageView
android:nextFocusRight="@id/result_episode_download"
android:id="@+id/episode_poster"
android:id="@+id/episode_poster"
tools:src="@drawable/example_poster"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/episode_poster_img_des"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/episode_poster_img_des" />
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:nextFocusRight="@id/result_episode_download"
android:scaleType="centerCrop"
tools:src="@drawable/example_poster" />
<ImageView
android:src="@drawable/play_button"
android:layout_gravity="center"
android:layout_width="36dp"
android:layout_height="36dp"
android:contentDescription="@string/play_episode" />
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:contentDescription="@string/play_episode"
android:src="@drawable/play_button" />
<androidx.core.widget.ContentLoadingProgressBar
android:layout_marginBottom="-1.5dp"
android:id="@+id/episode_progress"
android:progressTint="?attr/colorPrimary"
android:progressBackgroundTint="?attr/colorPrimary"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
tools:progress="50"
android:layout_gravity="bottom"
android:layout_height="5dp" />
android:id="@+id/episode_progress"
style="@android:style/Widget.Material.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_gravity="bottom"
android:layout_marginBottom="-1.5dp"
android:progressBackgroundTint="?attr/colorPrimary"
android:progressTint="?attr/colorPrimary"
tools:progress="50" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_marginStart="15dp"
android:orientation="vertical"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_marginEnd="50dp"
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">
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:layout_gravity="start"
style="@style/SmallBlackButton"
android:layout_marginEnd="10dp"
android:text="@string/filler"
android:id="@+id/episode_filler" />
android:id="@+id/episode_filler"
style="@style/SmallBlackButton"
android:layout_gravity="start"
android:layout_marginEnd="10dp"
android:text="@string/filler" />
<TextView
android:layout_gravity="center_vertical"
android:id="@+id/episode_text"
tools:text="1. Jobless"
android:textStyle="bold"
android:textColor="?attr/textColor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:id="@+id/episode_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="?attr/textColor"
android:textStyle="bold"
tools:text="1. Jobless" />
</LinearLayout>
<TextView
android:id="@+id/episode_rating"
tools:text="Rated: 8.8"
android:textColor="?attr/grayTextColor"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
android:id="@+id/episode_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/grayTextColor"
tools:text="Rated: 8.8" />
</LinearLayout>
<FrameLayout
android:layout_marginStart="-50dp"
android:layout_gravity="end"
android:layout_width="wrap_content"
android:layout_height="match_parent">
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:layout_marginStart="-50dp">
<androidx.core.widget.ContentLoadingProgressBar
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:layout_width="40dp"
android:layout_height="40dp"
android:id="@+id/result_episode_progress_downloaded"
android:indeterminate="false"
android:progressDrawable="@drawable/circular_progress_bar"
android:background="@drawable/circle_shape"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:layout_margin="5dp"
android:layout_gravity="end|center_vertical"
android:progress="0"
android:visibility="visible" />
<ImageView
android:nextFocusLeft="@id/episode_poster"
android:id="@+id/result_episode_download"
android:visibility="visible"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:layout_width="50dp"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_play_arrow_24"
android:contentDescription="@string/download"
app:tint="?attr/white" />
<com.lagradost.fetchbutton.ui.PieFetchButton
android:background="?selectableItemBackgroundBorderless"
android:id="@+id/result_episode_download"
android:layout_gravity="center"
android:padding="5dp"
android:layout_width="50dp"
android:layout_height="50dp">
</com.lagradost.fetchbutton.ui.PieFetchButton>
</FrameLayout>
</LinearLayout>
<TextView
android:maxLines="4"
android:ellipsize="end"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:id="@+id/episode_descript"
android:textColor="?attr/grayTextColor"
tools:text="Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart. Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart."
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:id="@+id/episode_descript"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="4"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textColor="?attr/grayTextColor"
tools:text="Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart. Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart." />
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -22,6 +22,10 @@
<color name="white">#FFF</color>
<color name="black">#000</color>
<color name="whiteText">#FFF</color>
<color name="blackText">#000</color>
<color name="dubColor">#3d50fa</color> <!--3b65f5 f18c82 8294F1-->
<color name="amoledModeLight">#121213</color>

View File

@ -49,11 +49,14 @@
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<!--<item name="preferenceTheme">@style/PreferencesTheme</item>-->
<!-- DEF STYLE -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorOnPrimary">@color/whiteText</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="textColor">@color/textColor</item>
<item name="grayTextColor">@color/grayTextColor</item>
@ -65,6 +68,10 @@
<item name="white">#FFF</item>
<item name="preferenceTheme">@style/CustomPreferenceThemeOverlay</item>
<item name="aria2c_icon_color">?attr/white</item>
<item name="aria2c_fill_color">?attr/white</item>
<item name="aria2c_outline_color">?attr/white</item>
<item name="aria2c_icon_scale">0.7</item>
</style>
<style name="ListViewStyle" parent="Widget.AppCompat.ListView">
@ -100,7 +107,7 @@
<item name="android:colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="colorOnPrimary">@color/colorAccent</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorAccent</item>
</style>
@ -110,7 +117,7 @@
<item name="android:colorPrimary">@color/colorPrimaryBlue</item>
<item name="colorPrimaryDark">#4855A2</item>
<item name="colorAccent">#5A6BCB</item>
<item name="colorOnPrimary">#5A6BCB</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryBlue</item>
</style>
@ -120,7 +127,7 @@
<item name="android:colorPrimary">@color/colorPrimaryPurple</item>
<item name="colorPrimaryDark">#4704A3</item>
<item name="colorAccent">#7125DB</item>
<item name="colorOnPrimary">#7125DB</item>
<item name="colorOnPrimary">@color/whiteText</item>
<item name="android:colorAccent">@color/colorPrimaryPurple</item>
</style>
@ -129,7 +136,7 @@
<item name="android:colorPrimary">@color/colorPrimaryGreen</item>
<item name="colorPrimaryDark">#007363</item>
<item name="colorAccent">#39C1AE</item>
<item name="colorOnPrimary">#39C1AE</item>
<item name="colorOnPrimary">@color/blackText</item>
<item name="android:colorAccent">@color/colorPrimaryGreen</item>
</style>
@ -138,7 +145,7 @@
<item name="android:colorPrimary">@color/colorPrimaryGreenApple</item>
<item name="colorPrimaryDark">#319B5A</item>
<item name="colorAccent">#51C57E</item>
<item name="colorOnPrimary">#51C57E</item>
<item name="colorOnPrimary">@color/blackText</item>
<item name="android:colorAccent">@color/colorPrimaryGreenApple</item>
</style>
@ -147,7 +154,7 @@
<item name="android:colorPrimary">@color/colorPrimaryRed</item>
<item name="colorPrimaryDark">#B62B2B</item>
<item name="colorAccent">@color/colorPrimaryRed</item> <!--#F53B3B-->
<item name="colorOnPrimary">@color/colorPrimaryRed</item> <!--#EC3838-->
<item name="colorOnPrimary">@color/whiteText</item> <!--#EC3838-->
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryRed</item>
</style>
@ -157,7 +164,7 @@
<item name="android:colorPrimary">@color/colorPrimaryBanana</item>
<item name="colorPrimaryDark">#9B7D31</item>
<item name="colorAccent">#C5B251</item>
<item name="colorOnPrimary">#C5A851</item>
<item name="colorOnPrimary">@color/blackText</item>
<item name="android:colorAccent">@color/colorPrimaryBanana</item>
</style>
@ -166,7 +173,7 @@
<item name="android:colorPrimary">@color/colorPrimaryParty</item>
<item name="colorPrimaryDark">#C1495B</item>
<item name="colorAccent">#FD798C</item>
<item name="colorOnPrimary">#BF5968</item>
<item name="colorOnPrimary">@color/blackText</item>
<item name="android:colorAccent">@color/colorPrimaryParty</item>
</style>
@ -175,7 +182,7 @@
<item name="android:colorPrimary">@color/colorPrimaryPink</item>
<item name="colorPrimaryDark">#DD1280</item>
<item name="colorAccent">#FF4DAE</item>
<item name="colorOnPrimary">#DD1280</item>
<item name="colorOnPrimary">@color/blackText</item>
<item name="android:colorAccent">@color/colorPrimaryPink</item>
</style>
@ -184,7 +191,7 @@
<item name="android:colorPrimary">@color/colorPrimaryCarnationPink</item>
<item name="colorPrimaryDark">#83366f</item>
<item name="colorAccent">#BD5DA5</item>
<item name="colorOnPrimary">#BD5DA5</item>
<item name="colorOnPrimary">@color/blackText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryCarnationPink</item>
</style>
@ -194,7 +201,7 @@
<item name="android:colorPrimary">@color/colorPrimaryMaroon</item>
<item name="colorPrimaryDark">#370C0C</item>
<item name="colorAccent">#451010</item>
<item name="colorOnPrimary">#451010</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryMaroon</item>
</style>
@ -204,7 +211,7 @@
<item name="android:colorPrimary">@color/colorPrimaryDarkGreen</item>
<item name="colorPrimaryDark">#003d00</item>
<item name="colorAccent">#004500</item>
<item name="colorOnPrimary">#004500</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryDarkGreen</item>
</style>
@ -214,7 +221,7 @@
<item name="android:colorPrimary">@color/colorPrimaryNavyBlue</item>
<item name="colorPrimaryDark">#000073</item>
<item name="colorAccent">#000080</item>
<item name="colorOnPrimary">#000080</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryNavyBlue</item>
</style>
@ -224,7 +231,7 @@
<item name="android:colorPrimary">@color/colorPrimaryGrey</item>
<item name="colorPrimaryDark">#484848</item>
<item name="colorAccent">#515151</item>
<item name="colorOnPrimary">#515151</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryGrey</item>
</style>
@ -234,7 +241,7 @@
<item name="android:colorPrimary">@color/colorPrimaryWhite</item>
<item name="colorPrimaryDark">#CCCCCC</item>
<item name="colorAccent">#FFFFFF</item>
<item name="colorOnPrimary">#FFFFFF</item>
<item name="colorOnPrimary">@color/blackText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryWhite</item>
</style>
@ -244,7 +251,7 @@
<item name="android:colorPrimary">@color/colorPrimaryBrown</item>
<item name="colorPrimaryDark">#582700</item>
<item name="colorAccent">#622C00</item>
<item name="colorOnPrimary">#622C00</item>
<item name="colorOnPrimary">@color/whiteText</item>
<!-- Needed for leanback fuckery -->
<item name="android:colorAccent">@color/colorPrimaryBrown</item>
</style>