mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Minor performance optimization and split to new class file and cleanup
This commit is contained in:
parent
34c5c9f621
commit
3ceabb4de3
2 changed files with 179 additions and 159 deletions
|
@ -4,23 +4,15 @@ 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.Path
|
|
||||||
import android.graphics.RectF
|
|
||||||
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
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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
|
||||||
|
@ -32,7 +24,6 @@ import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding
|
import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding
|
||||||
import com.lagradost.cloudstream3.databinding.StreamInputBinding
|
import com.lagradost.cloudstream3.databinding.StreamInputBinding
|
||||||
import com.lagradost.cloudstream3.isEpisodeBased
|
|
||||||
import com.lagradost.cloudstream3.isMovieType
|
import com.lagradost.cloudstream3.isMovieType
|
||||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
|
@ -46,7 +37,6 @@ import com.lagradost.cloudstream3.ui.settings.Globals.TV
|
||||||
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
import com.lagradost.cloudstream3.ui.settings.Globals.isLayout
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
|
|
||||||
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
|
||||||
import com.lagradost.cloudstream3.utils.DataStore
|
import com.lagradost.cloudstream3.utils.DataStore
|
||||||
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
|
||||||
|
@ -215,7 +205,12 @@ class DownloadFragment : Fragment() {
|
||||||
)
|
)
|
||||||
//layoutManager = GridLayoutManager(context, 1)
|
//layoutManager = GridLayoutManager(context, 1)
|
||||||
|
|
||||||
val itemTouchHelper = ItemTouchHelper(SwipeToDeleteCallback(this.adapter as DownloadHeaderAdapter))
|
val itemTouchHelper = ItemTouchHelper(
|
||||||
|
DownloadSwipeToDeleteCallback(
|
||||||
|
this.adapter as DownloadHeaderAdapter,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
)
|
||||||
itemTouchHelper.attachToRecyclerView(binding?.downloadList)
|
itemTouchHelper.attachToRecyclerView(binding?.downloadList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,152 +292,4 @@ class DownloadFragment : Fragment() {
|
||||||
|
|
||||||
fixPaddingStatusbar(binding?.downloadRoot)
|
fixPaddingStatusbar(binding?.downloadRoot)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class SwipeToDeleteCallback(private val adapter: DownloadHeaderAdapter) : ItemTouchHelper.Callback() {
|
|
||||||
|
|
||||||
private val swipeOpenItems: MutableSet<Int> = mutableSetOf()
|
|
||||||
|
|
||||||
override fun getMovementFlags(
|
|
||||||
recyclerView: RecyclerView,
|
|
||||||
viewHolder: RecyclerView.ViewHolder
|
|
||||||
): Int {
|
|
||||||
val position = viewHolder.bindingAdapterPosition
|
|
||||||
val item = adapter.cardList[position]
|
|
||||||
if (item.data.type.isEpisodeBased()) return 0
|
|
||||||
return makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isLongPressDragEnabled(): Boolean = false
|
|
||||||
|
|
||||||
override fun isItemViewSwipeEnabled(): Boolean = true
|
|
||||||
|
|
||||||
override fun onMove(
|
|
||||||
recyclerView: RecyclerView,
|
|
||||||
viewHolder: RecyclerView.ViewHolder,
|
|
||||||
target: RecyclerView.ViewHolder
|
|
||||||
): Boolean = false
|
|
||||||
|
|
||||||
override fun onSwiped(
|
|
||||||
viewHolder: RecyclerView.ViewHolder,
|
|
||||||
direction: Int
|
|
||||||
) {}
|
|
||||||
|
|
||||||
private fun handleDelete(position: Int) {
|
|
||||||
val item = adapter.cardList[position]
|
|
||||||
|
|
||||||
runOnMainThread {
|
|
||||||
item.child?.let { clickEvent ->
|
|
||||||
handleDownloadClick(
|
|
||||||
DownloadClickEvent(
|
|
||||||
DOWNLOAD_ACTION_DELETE_FILE,
|
|
||||||
clickEvent
|
|
||||||
)
|
|
||||||
) { adapter.notifyItemRemoved(position) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
|
||||||
override fun onChildDraw(
|
|
||||||
c: Canvas,
|
|
||||||
recyclerView: RecyclerView,
|
|
||||||
viewHolder: RecyclerView.ViewHolder,
|
|
||||||
dX: Float,
|
|
||||||
dY: Float,
|
|
||||||
actionState: Int,
|
|
||||||
isCurrentlyActive: Boolean
|
|
||||||
) {
|
|
||||||
if (dX == 0f) {
|
|
||||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val position = viewHolder.bindingAdapterPosition
|
|
||||||
|
|
||||||
val deleteIcon: Drawable = ContextCompat.getDrawable(
|
|
||||||
recyclerView.context,
|
|
||||||
R.drawable.ic_baseline_delete_outline_24
|
|
||||||
) ?: return
|
|
||||||
|
|
||||||
val background = ColorDrawable(Color.RED)
|
|
||||||
background.alpha = 160
|
|
||||||
|
|
||||||
val itemView = viewHolder.itemView
|
|
||||||
|
|
||||||
val scaleFactor = 1.25f
|
|
||||||
val iconWidth = (deleteIcon.intrinsicWidth * scaleFactor).toInt()
|
|
||||||
val iconHeight = (deleteIcon.intrinsicHeight * scaleFactor).toInt()
|
|
||||||
|
|
||||||
val iconTop = itemView.top + (itemView.height - iconHeight) / 2
|
|
||||||
val iconBottom = iconTop + iconHeight
|
|
||||||
|
|
||||||
val maxSwipeDistance = 230f
|
|
||||||
val minSwipeDistance = itemView.width / 4.5f
|
|
||||||
val swipeDistance = minOf(minSwipeDistance, maxSwipeDistance)
|
|
||||||
|
|
||||||
val limitedDX = if (dX < -swipeDistance) -swipeDistance else if (dX >= 0) 0f else dX
|
|
||||||
|
|
||||||
if (limitedDX < 0) { // Swiping to the left
|
|
||||||
val backgroundLeft = itemView.right + limitedDX.toInt()
|
|
||||||
val backgroundRight = itemView.right
|
|
||||||
val backgroundTop = itemView.top
|
|
||||||
val backgroundBottom = itemView.bottom
|
|
||||||
|
|
||||||
val iconLeft = backgroundLeft + (backgroundRight - backgroundLeft - iconWidth) / 2
|
|
||||||
val iconRight = iconLeft + iconWidth
|
|
||||||
deleteIcon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
|
|
||||||
|
|
||||||
val path = Path()
|
|
||||||
val rectF = RectF(
|
|
||||||
backgroundLeft.toFloat(),
|
|
||||||
backgroundTop.toFloat(),
|
|
||||||
backgroundRight.toFloat(),
|
|
||||||
backgroundBottom.toFloat()
|
|
||||||
)
|
|
||||||
|
|
||||||
val radii = floatArrayOf(0f, 0f, 20f, 20f, 20f, 20f, 0f, 0f)
|
|
||||||
path.addRoundRect(rectF, radii, Path.Direction.CW)
|
|
||||||
c.clipPath(path)
|
|
||||||
|
|
||||||
background.setBounds(backgroundLeft, backgroundTop, backgroundRight, backgroundBottom)
|
|
||||||
} else background.setBounds(0, 0, 0, 0)
|
|
||||||
|
|
||||||
background.draw(c)
|
|
||||||
deleteIcon.draw(c)
|
|
||||||
|
|
||||||
if (dX <= -swipeDistance && !isCurrentlyActive) {
|
|
||||||
swipeOpenItems.add(position)
|
|
||||||
} else {
|
|
||||||
swipeOpenItems.remove(position)
|
|
||||||
super.onChildDraw(c, recyclerView, viewHolder, limitedDX, dY, actionState, isCurrentlyActive)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swipeOpenItems.isNotEmpty()) {
|
|
||||||
recyclerView.setOnTouchListener { _, event ->
|
|
||||||
if (event.action == MotionEvent.ACTION_UP) {
|
|
||||||
val x = event.x.toInt()
|
|
||||||
val y = event.y.toInt()
|
|
||||||
var handled = false
|
|
||||||
|
|
||||||
swipeOpenItems.forEach { pos ->
|
|
||||||
val vh = recyclerView.findViewHolderForAdapterPosition(pos)
|
|
||||||
if (vh != null) {
|
|
||||||
val swipeItemView = vh.itemView
|
|
||||||
val backgroundLeft = swipeItemView.right - swipeDistance.toInt()
|
|
||||||
val backgroundRight = swipeItemView.right
|
|
||||||
val backgroundTop = swipeItemView.top
|
|
||||||
val backgroundBottom = swipeItemView.bottom
|
|
||||||
|
|
||||||
if (x in backgroundLeft..backgroundRight && y in backgroundTop..backgroundBottom) {
|
|
||||||
handleDelete(pos)
|
|
||||||
handled = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handled
|
|
||||||
} else false
|
|
||||||
}
|
|
||||||
} else recyclerView.setOnTouchListener(null)
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
package com.lagradost.cloudstream3.ui.download
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.graphics.Path
|
||||||
|
import android.graphics.RectF
|
||||||
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.isEpisodeBased
|
||||||
|
import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread
|
||||||
|
|
||||||
|
class DownloadSwipeToDeleteCallback(
|
||||||
|
private val adapter: DownloadHeaderAdapter,
|
||||||
|
private val context: Context
|
||||||
|
) : ItemTouchHelper.Callback() {
|
||||||
|
|
||||||
|
private val swipeOpenItems: MutableSet<Int> = mutableSetOf()
|
||||||
|
private val deleteIcon: Drawable? by lazy {
|
||||||
|
ContextCompat.getDrawable(context, R.drawable.ic_baseline_delete_outline_24)
|
||||||
|
}
|
||||||
|
private val background: ColorDrawable by lazy {
|
||||||
|
ColorDrawable(Color.RED).apply { alpha = 160 }
|
||||||
|
}
|
||||||
|
private val scaleFactor = 1.25f
|
||||||
|
private val maxSwipeDistance = 230f
|
||||||
|
|
||||||
|
override fun getMovementFlags(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder
|
||||||
|
): Int {
|
||||||
|
val position = viewHolder.bindingAdapterPosition
|
||||||
|
val item = adapter.cardList[position]
|
||||||
|
return if (item.data.type.isEpisodeBased()) 0 else {
|
||||||
|
makeMovementFlags(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isLongPressDragEnabled(): Boolean = false
|
||||||
|
|
||||||
|
override fun isItemViewSwipeEnabled(): Boolean = true
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean = false
|
||||||
|
|
||||||
|
override fun onSwiped(
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
direction: Int
|
||||||
|
) {}
|
||||||
|
|
||||||
|
override fun onChildDraw(
|
||||||
|
c: Canvas,
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
dX: Float,
|
||||||
|
dY: Float,
|
||||||
|
actionState: Int,
|
||||||
|
isCurrentlyActive: Boolean
|
||||||
|
) {
|
||||||
|
if (dX == 0f) {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val itemView = viewHolder.itemView
|
||||||
|
|
||||||
|
val minSwipeDistance = itemView.width / 4.5f
|
||||||
|
val swipeDistance = minOf(minSwipeDistance, maxSwipeDistance)
|
||||||
|
val limitedDX = if (dX < -swipeDistance) -swipeDistance else if (dX >= 0) 0f else dX
|
||||||
|
|
||||||
|
if (limitedDX < 0) { // Swiping to the left
|
||||||
|
val icon = deleteIcon ?: return
|
||||||
|
|
||||||
|
val backgroundLeft = itemView.right + limitedDX.toInt()
|
||||||
|
|
||||||
|
val iconWidth = (icon.intrinsicWidth * scaleFactor).toInt()
|
||||||
|
val iconHeight = (icon.intrinsicHeight * scaleFactor).toInt()
|
||||||
|
|
||||||
|
val iconTop = itemView.top + (itemView.height - iconHeight) / 2
|
||||||
|
val iconBottom = iconTop + iconHeight
|
||||||
|
|
||||||
|
val iconLeft = backgroundLeft + (itemView.right - backgroundLeft - iconWidth) / 2
|
||||||
|
val iconRight = iconLeft + iconWidth
|
||||||
|
|
||||||
|
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
|
||||||
|
|
||||||
|
val path = Path().apply {
|
||||||
|
addRoundRect(
|
||||||
|
RectF(
|
||||||
|
backgroundLeft.toFloat(),
|
||||||
|
itemView.top.toFloat(),
|
||||||
|
itemView.right.toFloat(),
|
||||||
|
itemView.bottom.toFloat()
|
||||||
|
),
|
||||||
|
floatArrayOf(0f, 0f, 20f, 20f, 20f, 20f, 0f, 0f),
|
||||||
|
Path.Direction.CW
|
||||||
|
)
|
||||||
|
}
|
||||||
|
c.clipPath(path)
|
||||||
|
background.setBounds(
|
||||||
|
backgroundLeft,
|
||||||
|
itemView.top,
|
||||||
|
itemView.right,
|
||||||
|
itemView.bottom
|
||||||
|
)
|
||||||
|
background.draw(c)
|
||||||
|
icon.draw(c)
|
||||||
|
} else background.setBounds(0, 0, 0, 0)
|
||||||
|
|
||||||
|
if (dX <= -swipeDistance && !isCurrentlyActive) {
|
||||||
|
swipeOpenItems.add(viewHolder.bindingAdapterPosition)
|
||||||
|
setRecyclerViewTouchListener(recyclerView, swipeDistance)
|
||||||
|
} else {
|
||||||
|
swipeOpenItems.remove(viewHolder.bindingAdapterPosition)
|
||||||
|
if (swipeOpenItems.isEmpty()) removeRecyclerViewTouchListener(recyclerView)
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, limitedDX, dY, actionState, isCurrentlyActive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
private fun setRecyclerViewTouchListener(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
swipeDistance: Float
|
||||||
|
) {
|
||||||
|
recyclerView.setOnTouchListener { _, event ->
|
||||||
|
if (event.action == MotionEvent.ACTION_UP) {
|
||||||
|
val x = event.x.toInt()
|
||||||
|
val y = event.y.toInt()
|
||||||
|
swipeOpenItems.forEach { pos ->
|
||||||
|
val vh = recyclerView.findViewHolderForAdapterPosition(pos)
|
||||||
|
vh?.itemView?.let { swipeItemView ->
|
||||||
|
val backgroundLeft: Int = swipeItemView.right - swipeDistance.toInt()
|
||||||
|
val backgroundXRange: IntRange = backgroundLeft..swipeItemView.right
|
||||||
|
val backgroundYRange: IntRange = swipeItemView.top..swipeItemView.bottom
|
||||||
|
if (x in backgroundXRange && y in backgroundYRange) {
|
||||||
|
handleDelete(pos)
|
||||||
|
return@setOnTouchListener true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
} else false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
private fun removeRecyclerViewTouchListener(
|
||||||
|
recyclerView: RecyclerView
|
||||||
|
): Unit = recyclerView.setOnTouchListener(null)
|
||||||
|
|
||||||
|
private fun handleDelete(position: Int) {
|
||||||
|
val item = adapter.cardList[position]
|
||||||
|
runOnMainThread {
|
||||||
|
item.child?.let { clickEvent ->
|
||||||
|
DownloadButtonSetup.handleDownloadClick(
|
||||||
|
DownloadClickEvent(
|
||||||
|
DOWNLOAD_ACTION_DELETE_FILE,
|
||||||
|
clickEvent
|
||||||
|
)
|
||||||
|
) { adapter.notifyItemRemoved(position) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue