mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Add swipe to delete downloads and minor performance improvements
This could honestly be a horrible way to impliment this (or maybe you don't want it at all) but figured I would give it a try as I often am used to you being able to on other apps so often out of habbit try like this and of course does not work. This also seems to fix an issue where downloaded icon becomes mixed with in progress and downloaded overlapping on scroll if you have inprogress downloads as well as size becoming inaccurate while scrolling (it used the wrong file's size sometimes) which seems to be fixed with `setItemViewCacheSize`. `setHasFixedSize` also improves performance by reducing the need to continue re-requesting layout when it does not need to (testing did not show any issues with it anyway, but not sure if this is the best way to do either of these things. Known issues: * Does not work for series/individual episodes * Delete icon UI needs improvements TODO (for further download improvements; maybe in follow-ups): * Show more information (IE synopsis/descriptions) for downloaded content * Further performance improvements for UI threads etc... If the entire concept of this idea is undesired I suppose we can close it and I will just do some of the other things to improve performance etc... (IE when having a moderate amount of downloads scroll is very laggy which this also seems to at least improve quite a lot.
This commit is contained in:
parent
7eec0eff02
commit
d0710596d4
2 changed files with 102 additions and 2 deletions
|
@ -1,6 +1,5 @@
|
||||||
package com.lagradost.cloudstream3.ui.download
|
package com.lagradost.cloudstream3.ui.download
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
@ -21,6 +20,10 @@ import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
|
|
||||||
object DownloadButtonSetup {
|
object DownloadButtonSetup {
|
||||||
fun handleDownloadClick(click: DownloadClickEvent) {
|
fun handleDownloadClick(click: DownloadClickEvent) {
|
||||||
|
handleDownloadClick(click) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun handleDownloadClick(click: DownloadClickEvent, deleteCallback: (Boolean) -> Unit) {
|
||||||
val id = click.data.id
|
val id = click.data.id
|
||||||
if (click.data !is VideoDownloadHelper.DownloadEpisodeCached) return
|
if (click.data !is VideoDownloadHelper.DownloadEpisodeCached) return
|
||||||
when (click.action) {
|
when (click.action) {
|
||||||
|
@ -32,8 +35,10 @@ object DownloadButtonSetup {
|
||||||
when (which) {
|
when (which) {
|
||||||
DialogInterface.BUTTON_POSITIVE -> {
|
DialogInterface.BUTTON_POSITIVE -> {
|
||||||
VideoDownloadManager.deleteFileAndUpdateSettings(ctx, id)
|
VideoDownloadManager.deleteFileAndUpdateSettings(ctx, id)
|
||||||
|
deleteCallback.invoke(true)
|
||||||
}
|
}
|
||||||
DialogInterface.BUTTON_NEGATIVE -> {
|
DialogInterface.BUTTON_NEGATIVE -> {
|
||||||
|
deleteCallback.invoke(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package com.lagradost.cloudstream3.ui.download
|
package com.lagradost.cloudstream3.ui.download
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.text.format.Formatter.formatShortFileSize
|
import android.text.format.Formatter.formatShortFileSize
|
||||||
|
@ -12,11 +17,13 @@ import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.doOnTextChanged
|
import androidx.core.widget.doOnTextChanged
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
@ -44,6 +51,9 @@ import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.setAppBarNoScrollFlagsOnTV
|
import com.lagradost.cloudstream3.utils.UIHelper.setAppBarNoScrollFlagsOnTV
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
|
||||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,6 +71,7 @@ class DownloadFragment : Fragment() {
|
||||||
this.layoutParams = param
|
this.layoutParams = param
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
private fun setList(list: List<VisualDownloadHeaderCached>) {
|
private fun setList(list: List<VisualDownloadHeaderCached>) {
|
||||||
main {
|
main {
|
||||||
(binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.cardList = list
|
(binding?.downloadList?.adapter as DownloadHeaderAdapter?)?.cardList = list
|
||||||
|
@ -182,7 +193,6 @@ class DownloadFragment : Fragment() {
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
if (list.any { it.data.id == id }) {
|
if (list.any { it.data.id == id }) {
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
setList(ArrayList())
|
|
||||||
downloadsViewModel.updateList(ctx)
|
downloadsViewModel.updateList(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,6 +202,8 @@ class DownloadFragment : Fragment() {
|
||||||
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent += it }
|
||||||
|
|
||||||
binding?.downloadList?.apply {
|
binding?.downloadList?.apply {
|
||||||
|
setHasFixedSize(true)
|
||||||
|
setItemViewCacheSize(20)
|
||||||
this.adapter = adapter
|
this.adapter = adapter
|
||||||
setLinearListLayout(
|
setLinearListLayout(
|
||||||
isHorizontal = false,
|
isHorizontal = false,
|
||||||
|
@ -200,6 +212,9 @@ class DownloadFragment : Fragment() {
|
||||||
nextDown = FOCUS_SELF
|
nextDown = FOCUS_SELF
|
||||||
)
|
)
|
||||||
//layoutManager = GridLayoutManager(context, 1)
|
//layoutManager = GridLayoutManager(context, 1)
|
||||||
|
|
||||||
|
val itemTouchHelper = ItemTouchHelper(SwipeToDeleteCallback(this.adapter as DownloadHeaderAdapter))
|
||||||
|
itemTouchHelper.attachToRecyclerView(binding?.downloadList)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should be visible in emulator layout
|
// Should be visible in emulator layout
|
||||||
|
@ -280,4 +295,84 @@ class DownloadFragment : Fragment() {
|
||||||
|
|
||||||
fixPaddingStatusbar(binding?.downloadRoot)
|
fixPaddingStatusbar(binding?.downloadRoot)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SwipeToDeleteCallback(private val adapter: DownloadHeaderAdapter) :
|
||||||
|
ItemTouchHelper.SimpleCallback(ItemTouchHelper.LEFT, 0) {
|
||||||
|
|
||||||
|
private var isActive = false
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||||
|
val position = viewHolder.bindingAdapterPosition
|
||||||
|
val item = adapter.cardList[position]
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
item.child?.let { clickEvent ->
|
||||||
|
handleDownloadClick(
|
||||||
|
DownloadClickEvent(
|
||||||
|
DOWNLOAD_ACTION_DELETE_FILE,
|
||||||
|
clickEvent
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (it) adapter.notifyItemRemoved(viewHolder.absoluteAdapterPosition)
|
||||||
|
isActive = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildDraw(
|
||||||
|
c: Canvas,
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
dX: Float,
|
||||||
|
dY: Float,
|
||||||
|
actionState: Int,
|
||||||
|
isCurrentlyActive: Boolean
|
||||||
|
) {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
|
|
||||||
|
val deleteIcon: Drawable? = ContextCompat.getDrawable(recyclerView.context, R.drawable.ic_baseline_delete_outline_24)
|
||||||
|
val background: ColorDrawable = ColorDrawable(Color.RED)
|
||||||
|
|
||||||
|
val itemView = viewHolder.itemView
|
||||||
|
val backgroundCornerOffset = 20
|
||||||
|
|
||||||
|
val iconMargin = (itemView.height - deleteIcon?.intrinsicHeight!!) / 2
|
||||||
|
val iconTop = itemView.top + (itemView.height - deleteIcon.intrinsicHeight) / 2
|
||||||
|
val iconBottom = iconTop + deleteIcon.intrinsicHeight
|
||||||
|
|
||||||
|
if (dX < 0) { // Swiping to the left
|
||||||
|
val iconLeft = itemView.right - iconMargin - deleteIcon.intrinsicWidth
|
||||||
|
val iconRight = itemView.right - iconMargin
|
||||||
|
deleteIcon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
|
||||||
|
|
||||||
|
background.setBounds(
|
||||||
|
itemView.right + dX.toInt() - backgroundCornerOffset,
|
||||||
|
itemView.top,
|
||||||
|
itemView.right,
|
||||||
|
itemView.bottom
|
||||||
|
)
|
||||||
|
} else background.setBounds(0, 0, 0, 0)
|
||||||
|
|
||||||
|
background.draw(c)
|
||||||
|
deleteIcon.draw(c)
|
||||||
|
|
||||||
|
val swipeDistance = itemView.width / 3
|
||||||
|
|
||||||
|
if (dX <= -swipeDistance && !isCurrentlyActive && !isActive) {
|
||||||
|
// If the item is dragged by at least one-third of its width to the left
|
||||||
|
// Trigger onSwiped action
|
||||||
|
onSwiped(viewHolder, ItemTouchHelper.LEFT)
|
||||||
|
isActive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue