mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Downloads: performance improvements and merge adapters (#1145)
This commit is contained in:
parent
b9746c2b17
commit
b06d9f224d
13 changed files with 488 additions and 527 deletions
|
@ -0,0 +1,223 @@
|
|||
package com.lagradost.cloudstream3.ui.download
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.format.Formatter.formatShortFileSize
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.DownloadChildEpisodeBinding
|
||||
import com.lagradost.cloudstream3.databinding.DownloadHeaderEpisodeBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.getNameFull
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
|
||||
const val DOWNLOAD_ACTION_PLAY_FILE = 0
|
||||
const val DOWNLOAD_ACTION_DELETE_FILE = 1
|
||||
const val DOWNLOAD_ACTION_RESUME_DOWNLOAD = 2
|
||||
const val DOWNLOAD_ACTION_PAUSE_DOWNLOAD = 3
|
||||
const val DOWNLOAD_ACTION_DOWNLOAD = 4
|
||||
const val DOWNLOAD_ACTION_LONG_CLICK = 5
|
||||
|
||||
abstract class VisualDownloadCached(
|
||||
open val currentBytes: Long,
|
||||
open val totalBytes: Long,
|
||||
open val data: VideoDownloadHelper.DownloadCached
|
||||
) {
|
||||
|
||||
// Just to be extra-safe with areContentsTheSame
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is VisualDownloadCached) return false
|
||||
|
||||
if (currentBytes != other.currentBytes) return false
|
||||
if (totalBytes != other.totalBytes) return false
|
||||
if (data != other.data) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = currentBytes.hashCode()
|
||||
result = 31 * result + totalBytes.hashCode()
|
||||
result = 31 * result + data.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
data class VisualDownloadChildCached(
|
||||
override val currentBytes: Long,
|
||||
override val totalBytes: Long,
|
||||
override val data: VideoDownloadHelper.DownloadEpisodeCached,
|
||||
): VisualDownloadCached(currentBytes, totalBytes, data)
|
||||
|
||||
data class VisualDownloadHeaderCached(
|
||||
override val currentBytes: Long,
|
||||
override val totalBytes: Long,
|
||||
override val data: VideoDownloadHelper.DownloadHeaderCached,
|
||||
val child: VideoDownloadHelper.DownloadEpisodeCached?,
|
||||
val currentOngoingDownloads: Int,
|
||||
val totalDownloads: Int,
|
||||
): VisualDownloadCached(currentBytes, totalBytes, data)
|
||||
|
||||
data class DownloadClickEvent(
|
||||
val action: Int,
|
||||
val data: VideoDownloadHelper.DownloadEpisodeCached
|
||||
)
|
||||
|
||||
data class DownloadHeaderClickEvent(
|
||||
val action: Int,
|
||||
val data: VideoDownloadHelper.DownloadHeaderCached
|
||||
)
|
||||
|
||||
class DownloadAdapter(
|
||||
private val clickCallback: (DownloadHeaderClickEvent) -> Unit,
|
||||
private val mediaClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : ListAdapter<VisualDownloadCached, DownloadAdapter.DownloadViewHolder>(DiffCallback()) {
|
||||
|
||||
companion object {
|
||||
private const val VIEW_TYPE_HEADER = 0
|
||||
private const val VIEW_TYPE_CHILD = 1
|
||||
}
|
||||
|
||||
inner class DownloadViewHolder(
|
||||
private val binding: ViewBinding,
|
||||
private val clickCallback: (DownloadHeaderClickEvent) -> Unit,
|
||||
private val mediaClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: VisualDownloadCached?) {
|
||||
when (binding) {
|
||||
is DownloadHeaderEpisodeBinding -> binding.apply {
|
||||
if (card == null || card !is VisualDownloadHeaderCached) return@apply
|
||||
val d = card.data
|
||||
|
||||
downloadHeaderPoster.apply {
|
||||
setImage(d.poster)
|
||||
setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(1, d))
|
||||
}
|
||||
}
|
||||
|
||||
downloadHeaderTitle.text = d.name
|
||||
val mbString = formatShortFileSize(itemView.context, card.totalBytes)
|
||||
|
||||
if (card.child != null) {
|
||||
downloadHeaderGotoChild.isVisible = false
|
||||
|
||||
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, mediaClickCallback)
|
||||
downloadButton.isVisible = true
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
mediaClickCallback.invoke(
|
||||
DownloadClickEvent(
|
||||
DOWNLOAD_ACTION_PLAY_FILE,
|
||||
card.child
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
downloadButton.isVisible = false
|
||||
downloadHeaderGotoChild.isVisible = true
|
||||
|
||||
try {
|
||||
downloadHeaderInfo.text =
|
||||
downloadHeaderInfo.context.getString(R.string.extra_info_format)
|
||||
.format(
|
||||
card.totalDownloads,
|
||||
if (card.totalDownloads == 1) downloadHeaderInfo.context.getString(
|
||||
R.string.episode
|
||||
) else downloadHeaderInfo.context.getString(
|
||||
R.string.episodes
|
||||
),
|
||||
mbString
|
||||
)
|
||||
} catch (t: Throwable) {
|
||||
// You probably formatted incorrectly
|
||||
downloadHeaderInfo.text = "Error"
|
||||
logError(t)
|
||||
}
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(0, d))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is DownloadChildEpisodeBinding -> binding.apply {
|
||||
if (card == null || card !is VisualDownloadChildCached) return@apply
|
||||
val d = card.data
|
||||
|
||||
val posDur = DataStoreHelper.getViewPos(d.id)
|
||||
downloadChildEpisodeProgress.apply {
|
||||
if (posDur != null) {
|
||||
val visualPos = posDur.fixVisual()
|
||||
max = (visualPos.duration / 1000).toInt()
|
||||
progress = (visualPos.position / 1000).toInt()
|
||||
isVisible = true
|
||||
} else isVisible = false
|
||||
}
|
||||
|
||||
downloadButton.setDefaultClickListener(card.data, downloadChildEpisodeTextExtra, mediaClickCallback)
|
||||
|
||||
downloadChildEpisodeText.apply {
|
||||
text = context.getNameFull(d.name, d.episode, d.season)
|
||||
isSelected = true // Needed for text repeating
|
||||
}
|
||||
|
||||
downloadChildEpisodeHolder.setOnClickListener {
|
||||
mediaClickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadViewHolder {
|
||||
val binding = when (viewType) {
|
||||
VIEW_TYPE_HEADER -> {
|
||||
DownloadHeaderEpisodeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
VIEW_TYPE_CHILD -> {
|
||||
DownloadChildEpisodeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Invalid view type")
|
||||
}
|
||||
return DownloadViewHolder(binding, clickCallback, mediaClickCallback)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: DownloadViewHolder, position: Int) {
|
||||
holder.bind(getItem(position))
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
val card = getItem(position)
|
||||
return if (card is VisualDownloadChildCached) VIEW_TYPE_CHILD else VIEW_TYPE_HEADER
|
||||
}
|
||||
|
||||
class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {
|
||||
override fun areItemsTheSame(oldItem: VisualDownloadCached, newItem: VisualDownloadCached): Boolean {
|
||||
return oldItem.data.id == newItem.data.id
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(oldItem: VisualDownloadCached, newItem: VisualDownloadCached): Boolean {
|
||||
return oldItem == newItem
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.lagradost.cloudstream3.ui.download
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
|
@ -22,7 +21,6 @@ import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
|||
object DownloadButtonSetup {
|
||||
fun handleDownloadClick(click: DownloadClickEvent) {
|
||||
val id = click.data.id
|
||||
if (click.data !is VideoDownloadHelper.DownloadEpisodeCached) return
|
||||
when (click.action) {
|
||||
DOWNLOAD_ACTION_DELETE_FILE -> {
|
||||
activity?.let { ctx ->
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
package com.lagradost.cloudstream3.ui.download
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.databinding.DownloadChildEpisodeBinding
|
||||
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
|
||||
|
||||
const val DOWNLOAD_ACTION_PLAY_FILE = 0
|
||||
const val DOWNLOAD_ACTION_DELETE_FILE = 1
|
||||
const val DOWNLOAD_ACTION_RESUME_DOWNLOAD = 2
|
||||
const val DOWNLOAD_ACTION_PAUSE_DOWNLOAD = 3
|
||||
const val DOWNLOAD_ACTION_DOWNLOAD = 4
|
||||
const val DOWNLOAD_ACTION_LONG_CLICK = 5
|
||||
|
||||
data class VisualDownloadChildCached(
|
||||
val currentBytes: Long,
|
||||
val totalBytes: Long,
|
||||
val data: VideoDownloadHelper.DownloadEpisodeCached,
|
||||
)
|
||||
|
||||
data class DownloadClickEvent(val action: Int, val data: VideoDownloadHelper.DownloadEpisodeCached)
|
||||
|
||||
class DownloadChildAdapter(
|
||||
var cardList: List<VisualDownloadChildCached>,
|
||||
private val clickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return DownloadChildViewHolder(
|
||||
DownloadChildEpisodeBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
clickCallback
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is DownloadChildViewHolder -> {
|
||||
holder.bind(cardList[position])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return cardList.size
|
||||
}
|
||||
|
||||
class DownloadChildViewHolder
|
||||
constructor(
|
||||
val binding: DownloadChildEpisodeBinding,
|
||||
private val clickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
/*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*/
|
||||
|
||||
|
||||
fun bind(card: VisualDownloadChildCached) {
|
||||
val d = card.data
|
||||
|
||||
val posDur = getViewPos(d.id)
|
||||
binding.downloadChildEpisodeProgress.apply {
|
||||
if (posDur != null) {
|
||||
val visualPos = posDur.fixVisual()
|
||||
max = (visualPos.duration / 1000).toInt()
|
||||
progress = (visualPos.position / 1000).toInt()
|
||||
visibility = View.VISIBLE
|
||||
} else {
|
||||
visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
binding.downloadButton.setDefaultClickListener(card.data, binding.downloadChildEpisodeTextExtra, clickCallback)
|
||||
|
||||
binding.downloadChildEpisodeText.apply {
|
||||
text = context.getNameFull(d.name, d.episode, d.season)
|
||||
isSelected = true // is needed for text repeating
|
||||
}
|
||||
|
||||
|
||||
binding.downloadChildEpisodeHolder.setOnClickListener {
|
||||
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, d))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentChildDownloadsBinding
|
||||
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
|
||||
|
@ -40,7 +39,8 @@ class DownloadChildFragment : Fragment() {
|
|||
super.onDestroyView()
|
||||
}
|
||||
|
||||
var binding: FragmentChildDownloadsBinding? = null
|
||||
private var binding: FragmentChildDownloadsBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -48,7 +48,7 @@ class DownloadChildFragment : Fragment() {
|
|||
): View {
|
||||
val localBinding = FragmentChildDownloadsBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root//inflater.inflate(R.layout.fragment_child_downloads, container, false)
|
||||
return localBinding.root
|
||||
}
|
||||
|
||||
private fun updateList(folder: String) = main {
|
||||
|
@ -60,7 +60,11 @@ class DownloadChildFragment : Fragment() {
|
|||
}.mapNotNull {
|
||||
val info = VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(ctx, it.id)
|
||||
?: return@mapNotNull null
|
||||
VisualDownloadChildCached(info.fileLength, info.totalBytes, it)
|
||||
VisualDownloadChildCached(
|
||||
currentBytes = info.fileLength,
|
||||
totalBytes = info.totalBytes,
|
||||
data = it,
|
||||
)
|
||||
}
|
||||
}.sortedBy { it.data.episode + (it.data.season ?: 0) * 100000 }
|
||||
if (eps.isEmpty()) {
|
||||
|
@ -68,9 +72,7 @@ class DownloadChildFragment : Fragment() {
|
|||
return@main
|
||||
}
|
||||
|
||||
(binding?.downloadChildList?.adapter as DownloadChildAdapter? ?: return@main).cardList =
|
||||
eps
|
||||
binding?.downloadChildList?.adapter?.notifyDataSetChanged()
|
||||
(binding?.downloadChildList?.adapter as? DownloadAdapter)?.submitList(eps)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,31 +100,39 @@ class DownloadChildFragment : Fragment() {
|
|||
setAppBarNoScrollFlagsOnTV()
|
||||
}
|
||||
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||
DownloadChildAdapter(
|
||||
ArrayList(),
|
||||
) { click ->
|
||||
handleDownloadClick(click)
|
||||
val adapter = DownloadAdapter(
|
||||
{},
|
||||
{ downloadClickEvent ->
|
||||
handleDownloadClick(downloadClickEvent)
|
||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) {
|
||||
setUpDownloadDeleteListener(folder)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
binding?.downloadChildList?.apply {
|
||||
setHasFixedSize(true)
|
||||
setItemViewCacheSize(20)
|
||||
this.adapter = adapter
|
||||
setLinearListLayout(
|
||||
isHorizontal = false,
|
||||
nextRight = FOCUS_SELF,
|
||||
nextDown = FOCUS_SELF,
|
||||
)
|
||||
}
|
||||
|
||||
updateList(folder)
|
||||
}
|
||||
|
||||
private fun setUpDownloadDeleteListener(folder: String) {
|
||||
downloadDeleteEventListener = { id: Int ->
|
||||
val list = (binding?.downloadChildList?.adapter as DownloadChildAdapter?)?.cardList
|
||||
val list = (binding?.downloadChildList?.adapter as? DownloadAdapter)?.currentList
|
||||
if (list != null) {
|
||||
if (list.any { it.data.id == id }) {
|
||||
updateList(folder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||
|
||||
binding?.downloadChildList?.adapter = adapter
|
||||
binding?.downloadChildList?.setLinearListLayout(
|
||||
isHorizontal = false,
|
||||
nextDown = FOCUS_SELF,
|
||||
nextRight = FOCUS_SELF
|
||||
)//layoutManager = GridLayoutManager(context, 1)
|
||||
|
||||
updateList(folder)
|
||||
}
|
||||
}
|
|
@ -10,14 +10,15 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding
|
||||
|
@ -42,11 +43,9 @@ import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setAppBarNoScrollFlagsOnTV
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import java.net.URI
|
||||
|
||||
|
||||
const val DOWNLOAD_NAVIGATE_TO = "downloadpage"
|
||||
|
||||
class DownloadFragment : Fragment() {
|
||||
|
@ -63,33 +62,30 @@ class DownloadFragment : Fragment() {
|
|||
|
||||
private fun setList(list: List<VisualDownloadHeaderCached>) {
|
||||
main {
|
||||
(binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.cardList = list
|
||||
binding?.downloadList?.adapter?.notifyDataSetChanged()
|
||||
(binding?.downloadList?.adapter as? DownloadAdapter)?.submitList(list)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
if (downloadDeleteEventListener != null) {
|
||||
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
|
||||
downloadDeleteEventListener = null
|
||||
downloadDeleteEventListener?.let {
|
||||
VideoDownloadManager.downloadDeleteEvent -= it
|
||||
}
|
||||
downloadDeleteEventListener = null
|
||||
binding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
var binding: FragmentDownloadsBinding? = null
|
||||
private var binding: FragmentDownloadsBinding? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
downloadsViewModel =
|
||||
ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
|
||||
): View {
|
||||
downloadsViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||
val localBinding = FragmentDownloadsBinding.inflate(inflater, container, false)
|
||||
binding = localBinding
|
||||
return localBinding.root//inflater.inflate(R.layout.fragment_downloads, container, false)
|
||||
return localBinding.root
|
||||
}
|
||||
|
||||
private var downloadDeleteEventListener: ((Int) -> Unit)? = null
|
||||
|
@ -97,7 +93,6 @@ class DownloadFragment : Fragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
hideKeyboard()
|
||||
|
||||
binding?.downloadStorageAppbar?.setAppBarNoScrollFlagsOnTV()
|
||||
|
||||
observe(downloadsViewModel.noDownloadsText) {
|
||||
|
@ -108,176 +103,148 @@ class DownloadFragment : Fragment() {
|
|||
binding?.downloadLoading?.isVisible = false
|
||||
}
|
||||
observe(downloadsViewModel.availableBytes) {
|
||||
binding?.downloadFreeTxt?.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.free_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
binding?.downloadFree?.setLayoutWidth(it)
|
||||
updateStorageInfo(view.context, it, R.string.free_storage, binding?.downloadFreeTxt, binding?.downloadFree)
|
||||
}
|
||||
observe(downloadsViewModel.usedBytes) {
|
||||
binding?.apply {
|
||||
downloadUsedTxt.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.used_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
downloadUsed.setLayoutWidth(it)
|
||||
downloadStorageAppbar.isVisible = it > 0
|
||||
}
|
||||
updateStorageInfo(view.context, it, R.string.used_storage, binding?.downloadUsedTxt, binding?.downloadUsed)
|
||||
binding?.downloadStorageAppbar?.isVisible = it > 0
|
||||
}
|
||||
observe(downloadsViewModel.downloadBytes) {
|
||||
binding?.apply {
|
||||
downloadAppTxt.text =
|
||||
getString(R.string.storage_size_format).format(
|
||||
getString(R.string.app_storage),
|
||||
formatShortFileSize(view.context, it)
|
||||
)
|
||||
downloadApp.setLayoutWidth(it)
|
||||
}
|
||||
updateStorageInfo(view.context, it, R.string.app_storage, binding?.downloadAppTxt, binding?.downloadApp)
|
||||
}
|
||||
|
||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
|
||||
DownloadHeaderAdapter(
|
||||
ArrayList(),
|
||||
{ click ->
|
||||
when (click.action) {
|
||||
0 -> {
|
||||
if (click.data.type.isMovieType()) {
|
||||
//wont be called
|
||||
} else {
|
||||
val folder = DataStore.getFolderName(
|
||||
DOWNLOAD_EPISODE_CACHE,
|
||||
click.data.id.toString()
|
||||
)
|
||||
activity?.navigate(
|
||||
R.id.action_navigation_downloads_to_navigation_download_child,
|
||||
DownloadChildFragment.newInstance(click.data.name, folder)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
1 -> {
|
||||
(activity as AppCompatActivity?)?.loadResult(
|
||||
click.data.url,
|
||||
click.data.apiName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
{ downloadClickEvent ->
|
||||
if (downloadClickEvent.data !is VideoDownloadHelper.DownloadEpisodeCached) return@DownloadHeaderAdapter
|
||||
handleDownloadClick(downloadClickEvent)
|
||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) {
|
||||
context?.let { ctx ->
|
||||
downloadsViewModel.updateList(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
downloadDeleteEventListener = { id ->
|
||||
val list = (binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.cardList
|
||||
if (list != null) {
|
||||
if (list.any { it.data.id == id }) {
|
||||
context?.let { ctx ->
|
||||
setList(ArrayList())
|
||||
downloadsViewModel.updateList(ctx)
|
||||
}
|
||||
val adapter = DownloadAdapter(
|
||||
{ click ->
|
||||
handleItemClick(click)
|
||||
},
|
||||
{ downloadClickEvent ->
|
||||
handleDownloadClick(downloadClickEvent)
|
||||
if (downloadClickEvent.action == DOWNLOAD_ACTION_DELETE_FILE) {
|
||||
setUpDownloadDeleteListener()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||
)
|
||||
|
||||
binding?.downloadList?.apply {
|
||||
setHasFixedSize(true)
|
||||
setItemViewCacheSize(20)
|
||||
this.adapter = adapter
|
||||
setLinearListLayout(
|
||||
isHorizontal = false,
|
||||
nextRight = FOCUS_SELF,
|
||||
nextUp = FOCUS_SELF,
|
||||
nextDown = FOCUS_SELF
|
||||
nextDown = FOCUS_SELF,
|
||||
)
|
||||
//layoutManager = GridLayoutManager(context, 1)
|
||||
}
|
||||
|
||||
// Should be visible in emulator layout
|
||||
binding?.downloadStreamButton?.isGone = isLayout(TV)
|
||||
binding?.downloadStreamButton?.setOnClickListener {
|
||||
val dialog =
|
||||
Dialog(it.context ?: return@setOnClickListener, R.style.AlertDialogCustom)
|
||||
|
||||
val binding = StreamInputBinding.inflate(dialog.layoutInflater)
|
||||
|
||||
dialog.setContentView(binding.root)
|
||||
|
||||
dialog.show()
|
||||
|
||||
// If user has clicked the switch do not interfere
|
||||
var preventAutoSwitching = false
|
||||
binding.hlsSwitch.setOnClickListener {
|
||||
preventAutoSwitching = true
|
||||
}
|
||||
|
||||
fun activateSwitchOnHls(text: String?) {
|
||||
binding.hlsSwitch.isChecked = normalSafeApiCall {
|
||||
URI(text).path?.substringAfterLast(".")?.contains("m3u")
|
||||
} == true
|
||||
}
|
||||
|
||||
binding.streamReferer.doOnTextChanged { text, _, _, _ ->
|
||||
if (!preventAutoSwitching)
|
||||
activateSwitchOnHls(text?.toString())
|
||||
}
|
||||
|
||||
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?)?.primaryClip?.getItemAt(
|
||||
0
|
||||
)?.text?.toString()?.let { copy ->
|
||||
val fixedText = copy.trim()
|
||||
binding.streamUrl.setText(fixedText)
|
||||
activateSwitchOnHls(fixedText)
|
||||
}
|
||||
|
||||
binding.applyBtt.setOnClickListener {
|
||||
val url = binding.streamUrl.text?.toString()
|
||||
if (url.isNullOrEmpty()) {
|
||||
showToast(R.string.error_invalid_url, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
val referer = binding.streamReferer.text?.toString()
|
||||
|
||||
activity?.navigate(
|
||||
R.id.global_to_navigation_player,
|
||||
GeneratorPlayer.newInstance(
|
||||
LinkGenerator(
|
||||
listOf(BasicLink(url)),
|
||||
extract = true,
|
||||
referer = referer,
|
||||
isM3u8 = binding.hlsSwitch.isChecked
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
dialog.dismissSafe(activity)
|
||||
}
|
||||
}
|
||||
|
||||
binding.cancelBtt.setOnClickListener {
|
||||
dialog.dismissSafe(activity)
|
||||
}
|
||||
binding?.downloadStreamButton?.apply {
|
||||
isGone = isLayout(TV)
|
||||
setOnClickListener { showStreamInputDialog(it.context) }
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
binding?.downloadList?.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) { //check for scroll down
|
||||
binding?.downloadStreamButton?.shrink() // hide
|
||||
} else if (dy < -5) {
|
||||
binding?.downloadStreamButton?.extend() // show
|
||||
}
|
||||
handleScroll(scrollY - oldScrollY)
|
||||
}
|
||||
}
|
||||
downloadsViewModel.updateList(requireContext())
|
||||
|
||||
fixPaddingStatusbar(binding?.downloadRoot)
|
||||
}
|
||||
|
||||
private fun handleItemClick(click: DownloadHeaderClickEvent) {
|
||||
when (click.action) {
|
||||
0 -> {
|
||||
if (!click.data.type.isMovieType()) {
|
||||
val folder = DataStore.getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString())
|
||||
activity?.navigate(
|
||||
R.id.action_navigation_downloads_to_navigation_download_child,
|
||||
DownloadChildFragment.newInstance(click.data.name, folder)
|
||||
)
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
(activity as AppCompatActivity?)?.loadResult(click.data.url, click.data.apiName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpDownloadDeleteListener() {
|
||||
downloadDeleteEventListener = { id ->
|
||||
val list = (binding?.downloadList?.adapter as? DownloadAdapter)?.currentList
|
||||
if (list?.any { it.data.id == id } == true) {
|
||||
context?.let { downloadsViewModel.updateList(it) }
|
||||
}
|
||||
}
|
||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||
}
|
||||
|
||||
private fun updateStorageInfo(
|
||||
context: Context,
|
||||
bytes: Long,
|
||||
@StringRes stringRes: Int,
|
||||
textView: TextView?,
|
||||
view: View?
|
||||
) {
|
||||
textView?.text = getString(R.string.storage_size_format).format(getString(stringRes), formatShortFileSize(context, bytes))
|
||||
view?.setLayoutWidth(bytes)
|
||||
}
|
||||
|
||||
private fun showStreamInputDialog(context: Context) {
|
||||
val dialog = Dialog(context, R.style.AlertDialogCustom)
|
||||
val binding = StreamInputBinding.inflate(dialog.layoutInflater)
|
||||
dialog.setContentView(binding.root)
|
||||
dialog.show()
|
||||
|
||||
var preventAutoSwitching = false
|
||||
binding.hlsSwitch.setOnClickListener { preventAutoSwitching = true }
|
||||
|
||||
binding.streamReferer.doOnTextChanged { text, _, _, _ ->
|
||||
if (!preventAutoSwitching) activateSwitchOnHls(text?.toString(), binding)
|
||||
}
|
||||
|
||||
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager)?.primaryClip?.getItemAt(0)?.text?.toString()?.let { copy ->
|
||||
val fixedText = copy.trim()
|
||||
binding.streamUrl.setText(fixedText)
|
||||
activateSwitchOnHls(fixedText, binding)
|
||||
}
|
||||
|
||||
binding.applyBtt.setOnClickListener {
|
||||
val url = binding.streamUrl.text?.toString()
|
||||
if (url.isNullOrEmpty()) {
|
||||
showToast(R.string.error_invalid_url, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
val referer = binding.streamReferer.text?.toString()
|
||||
activity?.navigate(
|
||||
R.id.global_to_navigation_player,
|
||||
GeneratorPlayer.newInstance(
|
||||
LinkGenerator(
|
||||
listOf(BasicLink(url)),
|
||||
extract = true,
|
||||
referer = referer,
|
||||
isM3u8 = binding.hlsSwitch.isChecked
|
||||
)
|
||||
)
|
||||
)
|
||||
dialog.dismissSafe(activity)
|
||||
}
|
||||
}
|
||||
|
||||
binding.cancelBtt.setOnClickListener {
|
||||
dialog.dismissSafe(activity)
|
||||
}
|
||||
}
|
||||
|
||||
private fun activateSwitchOnHls(text: String?, binding: StreamInputBinding) {
|
||||
binding.hlsSwitch.isChecked = normalSafeApiCall {
|
||||
URI(text).path?.substringAfterLast(".")?.contains("m3u")
|
||||
} == true
|
||||
}
|
||||
|
||||
private fun handleScroll(dy: Int) {
|
||||
if (dy > 0) {
|
||||
binding?.downloadStreamButton?.shrink()
|
||||
} else if (dy < -5) {
|
||||
binding?.downloadStreamButton?.extend()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
package com.lagradost.cloudstream3.ui.download
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.text.format.Formatter.formatShortFileSize
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.DownloadHeaderEpisodeBinding
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||
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?,
|
||||
)
|
||||
|
||||
data class DownloadHeaderClickEvent(
|
||||
val action: Int,
|
||||
val data: VideoDownloadHelper.DownloadHeaderCached
|
||||
)
|
||||
|
||||
class DownloadHeaderAdapter(
|
||||
var cardList: List<VisualDownloadHeaderCached>,
|
||||
private val clickCallback: (DownloadHeaderClickEvent) -> Unit,
|
||||
private val movieClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return DownloadHeaderViewHolder(
|
||||
DownloadHeaderEpisodeBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
),
|
||||
clickCallback,
|
||||
movieClickCallback
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is DownloadHeaderViewHolder -> {
|
||||
holder.bind(cardList[position])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return cardList.size
|
||||
}
|
||||
|
||||
class DownloadHeaderViewHolder
|
||||
constructor(
|
||||
val binding: DownloadHeaderEpisodeBinding,
|
||||
private val clickCallback: (DownloadHeaderClickEvent) -> Unit,
|
||||
private val movieClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
/*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*/
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun bind(card: VisualDownloadHeaderCached) {
|
||||
val d = card.data
|
||||
|
||||
binding.downloadHeaderPoster.apply {
|
||||
setImage(d.poster)
|
||||
setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(1, d))
|
||||
}
|
||||
}
|
||||
|
||||
binding.apply {
|
||||
|
||||
binding.downloadHeaderTitle.text = d.name
|
||||
val mbString = formatShortFileSize(itemView.context, card.totalBytes)
|
||||
|
||||
//val isMovie = d.type.isMovieType()
|
||||
if (card.child != null) {
|
||||
//downloadHeaderProgressDownloaded.visibility = View.VISIBLE
|
||||
|
||||
// downloadHeaderEpisodeDownload.visibility = View.VISIBLE
|
||||
binding.downloadHeaderGotoChild.visibility = View.GONE
|
||||
|
||||
downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, movieClickCallback)
|
||||
downloadButton.isVisible = true
|
||||
/*setUpButton(
|
||||
card.currentBytes,
|
||||
card.totalBytes,
|
||||
downloadBar,
|
||||
downloadImage,
|
||||
extraInfo,
|
||||
card.child,
|
||||
movieClickCallback
|
||||
)*/
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
movieClickCallback.invoke(
|
||||
DownloadClickEvent(
|
||||
DOWNLOAD_ACTION_PLAY_FILE,
|
||||
card.child
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
downloadButton.isVisible = false
|
||||
// downloadHeaderProgressDownloaded.visibility = View.GONE
|
||||
// downloadHeaderEpisodeDownload.visibility = View.GONE
|
||||
binding.downloadHeaderGotoChild.visibility = View.VISIBLE
|
||||
|
||||
try {
|
||||
downloadHeaderInfo.text =
|
||||
downloadHeaderInfo.context.getString(R.string.extra_info_format).format(
|
||||
card.totalDownloads,
|
||||
if (card.totalDownloads == 1) downloadHeaderInfo.context.getString(R.string.episode) else downloadHeaderInfo.context.getString(
|
||||
R.string.episodes
|
||||
),
|
||||
mbString
|
||||
)
|
||||
} catch (t: Throwable) {
|
||||
// you probably formatted incorrectly
|
||||
downloadHeaderInfo.text = "Error"
|
||||
logError(t)
|
||||
}
|
||||
|
||||
|
||||
episodeHolder.setOnClickListener {
|
||||
clickCallback.invoke(DownloadHeaderClickEvent(0, d))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,6 +39,8 @@ class DownloadViewModel : ViewModel() {
|
|||
val availableBytes: LiveData<Long> = _availableBytes
|
||||
val downloadBytes: LiveData<Long> = _downloadBytes
|
||||
|
||||
private var previousVisual: List<VisualDownloadHeaderCached>? = null
|
||||
|
||||
fun updateList(context: Context) = viewModelScope.launchSafe {
|
||||
val children = withContext(Dispatchers.IO) {
|
||||
val headers = context.getKeys(DOWNLOAD_EPISODE_CACHE)
|
||||
|
@ -53,7 +55,6 @@ class DownloadViewModel : ViewModel() {
|
|||
// parentId : downloadsCount
|
||||
val totalDownloads = HashMap<Int, Int>()
|
||||
|
||||
|
||||
// Gets all children downloads
|
||||
withContext(Dispatchers.IO) {
|
||||
for (c in children) {
|
||||
|
@ -69,7 +70,7 @@ class DownloadViewModel : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
val cached = withContext(Dispatchers.IO) { // wont fetch useless keys
|
||||
val cached = withContext(Dispatchers.IO) { // Won't fetch useless keys
|
||||
totalDownloads.entries.filter { it.value > 0 }.mapNotNull {
|
||||
context.getKey<VideoDownloadHelper.DownloadHeaderCached>(
|
||||
DOWNLOAD_HEADER_CACHE,
|
||||
|
@ -79,7 +80,7 @@ class DownloadViewModel : ViewModel() {
|
|||
}
|
||||
|
||||
val visual = withContext(Dispatchers.IO) {
|
||||
cached.mapNotNull { // TODO FIX
|
||||
cached.mapNotNull {
|
||||
val downloads = totalDownloads[it.id] ?: 0
|
||||
val bytes = totalBytesUsedByChild[it.id] ?: 0
|
||||
val currentBytes = currentBytesUsedByChild[it.id] ?: 0
|
||||
|
@ -91,32 +92,37 @@ class DownloadViewModel : ViewModel() {
|
|||
getFolderName(it.id.toString(), it.id.toString())
|
||||
)
|
||||
VisualDownloadHeaderCached(
|
||||
0,
|
||||
downloads,
|
||||
bytes,
|
||||
currentBytes,
|
||||
it,
|
||||
movieEpisode
|
||||
currentBytes = currentBytes,
|
||||
totalBytes = bytes,
|
||||
data = it,
|
||||
child = movieEpisode,
|
||||
currentOngoingDownloads = 0,
|
||||
totalDownloads = downloads,
|
||||
)
|
||||
}.sortedBy {
|
||||
(it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0)
|
||||
} // episode sorting by episode, lowest to highest
|
||||
}
|
||||
try {
|
||||
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
||||
|
||||
val localBytesAvailable = stat.availableBytes//stat.blockSizeLong * stat.blockCountLong
|
||||
val localTotalBytes = stat.blockSizeLong * stat.blockCountLong
|
||||
val localDownloadedBytes = visual.sumOf { it.totalBytes }
|
||||
|
||||
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
|
||||
_availableBytes.postValue(localBytesAvailable)
|
||||
_downloadBytes.postValue(localDownloadedBytes)
|
||||
} catch (t : Throwable) {
|
||||
_downloadBytes.postValue(0)
|
||||
logError(t)
|
||||
} // Episode sorting by episode, lowest to highest
|
||||
}
|
||||
|
||||
_headerCards.postValue(visual)
|
||||
// Only update list if different from the previous one to prevent duplicate initialization
|
||||
if (visual != previousVisual) {
|
||||
previousVisual = visual
|
||||
|
||||
try {
|
||||
val stat = StatFs(Environment.getExternalStorageDirectory().path)
|
||||
val localBytesAvailable = stat.availableBytes
|
||||
val localTotalBytes = stat.blockSizeLong * stat.blockCountLong
|
||||
val localDownloadedBytes = visual.sumOf { it.totalBytes }
|
||||
|
||||
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
|
||||
_availableBytes.postValue(localBytesAvailable)
|
||||
_downloadBytes.postValue(localDownloadedBytes)
|
||||
} catch (t: Throwable) {
|
||||
_downloadBytes.postValue(0)
|
||||
logError(t)
|
||||
}
|
||||
|
||||
_headerCards.postValue(visual)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -192,15 +192,15 @@ class EpisodeAdapter(
|
|||
downloadButton.isVisible = hasDownloadSupport
|
||||
downloadButton.setDefaultClickListener(
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
card.name,
|
||||
card.poster,
|
||||
card.episode,
|
||||
card.season,
|
||||
card.id,
|
||||
card.parentId,
|
||||
card.rating,
|
||||
card.description,
|
||||
System.currentTimeMillis(),
|
||||
name = card.name,
|
||||
poster = card.poster,
|
||||
episode = card.episode,
|
||||
season = card.season,
|
||||
id = card.id,
|
||||
parentId = card.parentId,
|
||||
rating = card.rating,
|
||||
description = card.description,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
), null
|
||||
) {
|
||||
when (it.action) {
|
||||
|
@ -343,15 +343,15 @@ class EpisodeAdapter(
|
|||
downloadButton.isVisible = hasDownloadSupport
|
||||
downloadButton.setDefaultClickListener(
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
card.name,
|
||||
card.poster,
|
||||
card.episode,
|
||||
card.season,
|
||||
card.id,
|
||||
card.parentId,
|
||||
card.rating,
|
||||
card.description,
|
||||
System.currentTimeMillis(),
|
||||
name = card.name,
|
||||
poster = card.poster,
|
||||
episode = card.episode,
|
||||
season = card.season,
|
||||
id = card.id,
|
||||
parentId = card.parentId,
|
||||
rating = card.rating,
|
||||
description = card.description,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
), null
|
||||
) {
|
||||
when (it.action) {
|
||||
|
|
|
@ -185,8 +185,6 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
}
|
||||
binding?.resultFullscreenHolder?.isVisible = !isSuccess && isFullScreenPlayer
|
||||
}
|
||||
|
||||
|
||||
//player_view?.apply {
|
||||
//alpha = 0.0f
|
||||
//ObjectAnimator.ofFloat(player_view, "alpha", 1f).apply {
|
||||
|
@ -200,9 +198,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
// fillAfter = true
|
||||
//}
|
||||
//startAnimation(fadeIn)
|
||||
// }
|
||||
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
private fun setTrailers(trailers: List<ExtractorLink>?) {
|
||||
|
@ -630,15 +626,15 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
}
|
||||
downloadButton.setDefaultClickListener(
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
ep.name,
|
||||
ep.poster,
|
||||
0,
|
||||
null,
|
||||
ep.id,
|
||||
ep.id,
|
||||
null,
|
||||
null,
|
||||
System.currentTimeMillis(),
|
||||
name = ep.name,
|
||||
poster = ep.poster,
|
||||
episode = 0,
|
||||
season = null,
|
||||
id = ep.id,
|
||||
parentId = ep.id,
|
||||
rating = null,
|
||||
description = null,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
),
|
||||
null
|
||||
) { click ->
|
||||
|
|
|
@ -705,13 +705,13 @@ class ResultViewModel2 : ViewModel() {
|
|||
DOWNLOAD_HEADER_CACHE,
|
||||
parentId.toString(),
|
||||
VideoDownloadHelper.DownloadHeaderCached(
|
||||
apiName,
|
||||
url,
|
||||
currentType,
|
||||
currentHeaderName,
|
||||
currentPoster,
|
||||
parentId,
|
||||
System.currentTimeMillis(),
|
||||
apiName = apiName,
|
||||
url = url,
|
||||
type = currentType,
|
||||
name = currentHeaderName,
|
||||
poster = currentPoster,
|
||||
id = parentId,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -722,15 +722,15 @@ class ResultViewModel2 : ViewModel() {
|
|||
), // 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(),
|
||||
name = episode.name,
|
||||
poster = episode.poster,
|
||||
episode = episode.episode,
|
||||
season = episode.season,
|
||||
id = episode.id,
|
||||
parentId = parentId,
|
||||
rating = episode.rating,
|
||||
description = episode.description,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -2776,13 +2776,13 @@ class ResultViewModel2 : ViewModel() {
|
|||
DOWNLOAD_HEADER_CACHE,
|
||||
mainId.toString(),
|
||||
VideoDownloadHelper.DownloadHeaderCached(
|
||||
apiName,
|
||||
validUrl,
|
||||
loadResponse.type,
|
||||
loadResponse.name,
|
||||
loadResponse.posterUrl,
|
||||
mainId,
|
||||
System.currentTimeMillis(),
|
||||
apiName = apiName,
|
||||
url = validUrl,
|
||||
type = loadResponse.type,
|
||||
name = loadResponse.name,
|
||||
poster = loadResponse.posterUrl,
|
||||
id = mainId,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
if (loadTrailers)
|
||||
|
|
|
@ -25,7 +25,7 @@ object SearchHelper {
|
|||
SEARCH_ACTION_PLAY_FILE -> {
|
||||
if (card is DataStoreHelper.ResumeWatchingResult) {
|
||||
val id = card.id
|
||||
if(id == null) {
|
||||
if (id == null) {
|
||||
showToast(R.string.error_invalid_id, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
if (card.isFromDownload) {
|
||||
|
@ -33,15 +33,15 @@ object SearchHelper {
|
|||
DownloadClickEvent(
|
||||
DOWNLOAD_ACTION_PLAY_FILE,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
card.name,
|
||||
card.posterUrl,
|
||||
card.episode ?: 0,
|
||||
card.season,
|
||||
id,
|
||||
card.parentId ?: return,
|
||||
null,
|
||||
null,
|
||||
System.currentTimeMillis()
|
||||
name = card.name,
|
||||
poster = card.posterUrl,
|
||||
episode = card.episode ?: 0,
|
||||
season = card.season,
|
||||
id = id,
|
||||
parentId = card.parentId ?: return,
|
||||
rating = null,
|
||||
description = null,
|
||||
cacheTime = System.currentTimeMillis(),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -3,17 +3,21 @@ package com.lagradost.cloudstream3.utils
|
|||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
object VideoDownloadHelper {
|
||||
abstract class DownloadCached(
|
||||
@JsonProperty("id") open val id: Int,
|
||||
)
|
||||
|
||||
data class DownloadEpisodeCached(
|
||||
@JsonProperty("name") val name: String?,
|
||||
@JsonProperty("poster") val poster: String?,
|
||||
@JsonProperty("episode") val episode: Int,
|
||||
@JsonProperty("season") val season: Int?,
|
||||
@JsonProperty("id") val id: Int,
|
||||
@JsonProperty("parentId") val parentId: Int,
|
||||
@JsonProperty("rating") val rating: Int?,
|
||||
@JsonProperty("description") val description: String?,
|
||||
@JsonProperty("cacheTime") val cacheTime: Long,
|
||||
)
|
||||
override val id: Int,
|
||||
): DownloadCached(id)
|
||||
|
||||
data class DownloadHeaderCached(
|
||||
@JsonProperty("apiName") val apiName: String,
|
||||
|
@ -21,9 +25,9 @@ object VideoDownloadHelper {
|
|||
@JsonProperty("type") val type: TvType,
|
||||
@JsonProperty("name") val name: String,
|
||||
@JsonProperty("poster") val poster: String?,
|
||||
@JsonProperty("id") val id: Int,
|
||||
@JsonProperty("cacheTime") val cacheTime: Long,
|
||||
)
|
||||
override val id: Int,
|
||||
): DownloadCached(id)
|
||||
|
||||
data class ResumeWatching(
|
||||
@JsonProperty("parentId") val parentId: Int,
|
||||
|
|
|
@ -59,12 +59,12 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/download_header_goto_child"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="@dimen/download_size"
|
||||
android:layout_height="@dimen/download_size"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginStart="-50dp"
|
||||
android:contentDescription="@string/download"
|
||||
android:padding="50dp"
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/ic_baseline_keyboard_arrow_right_24" />
|
||||
|
||||
<com.lagradost.cloudstream3.ui.download.button.PieFetchButton
|
||||
|
|
Loading…
Reference in a new issue