Minor performance optimization and split to new class file and cleanup

This commit is contained in:
Luna712 2024-06-14 12:39:52 -06:00 committed by GitHub
parent 34c5c9f621
commit 3ceabb4de3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 179 additions and 159 deletions

View file

@ -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)
} }
@ -298,151 +293,3 @@ 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)
}
}

View file

@ -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) }
}
}
}
}