forked from hardcoresushi/DroidFS
Thumbnails cache & Don't do full reload on selection change
This commit is contained in:
parent
4f9aa55dfe
commit
4de5b41102
@ -145,8 +145,8 @@ class MainActivity : BaseActivity() {
|
||||
binding.textNoVolumes.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun unselectAll() {
|
||||
volumeAdapter.unSelectAll()
|
||||
private fun unselectAll(notifyChange: Boolean = true) {
|
||||
volumeAdapter.unSelectAll(notifyChange)
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
@ -233,7 +233,7 @@ class MainActivity : BaseActivity() {
|
||||
if (volumeDatabase.removeHash(volumeAdapter.volumes[i]))
|
||||
volumeAdapter.onVolumeChanged(i)
|
||||
}
|
||||
unselectAll()
|
||||
unselectAll(false)
|
||||
true
|
||||
}
|
||||
R.id.change_password -> {
|
||||
|
@ -1,12 +1,16 @@
|
||||
package sushi.hardcore.droidfs.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.LruCache
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.target.DrawableImageViewTarget
|
||||
@ -18,6 +22,7 @@ import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
class ExplorerElementAdapter(
|
||||
val activity: AppCompatActivity,
|
||||
@ -28,8 +33,21 @@ class ExplorerElementAdapter(
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())
|
||||
var explorerElements = listOf<ExplorerElement>()
|
||||
val selectedItems: MutableList<Int> = ArrayList()
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
set(value) {
|
||||
field = value
|
||||
thumbnailsCache?.evictAll()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
var selectedItems: MutableSet<Int> = HashSet()
|
||||
var isUsingListLayout = true
|
||||
private var thumbnailsCache: LruCache<String, Bitmap>? = null
|
||||
|
||||
init {
|
||||
if (gocryptfsVolume != null) {
|
||||
thumbnailsCache = LruCache((Runtime.getRuntime().maxMemory() / 1024 / 8).toInt())
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return explorerElements.size
|
||||
@ -64,14 +82,21 @@ class ExplorerElementAdapter(
|
||||
for (i in explorerElements.indices) {
|
||||
if (!selectedItems.contains(i) && !explorerElements[i].isParentFolder) {
|
||||
selectedItems.add(i)
|
||||
notifyItemChanged(i)
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun unSelectAll() {
|
||||
selectedItems.clear()
|
||||
notifyDataSetChanged()
|
||||
fun unSelectAll(notifyChange: Boolean) {
|
||||
if (notifyChange) {
|
||||
val whatWasSelected = selectedItems
|
||||
selectedItems = HashSet()
|
||||
whatWasSelected.forEach {
|
||||
notifyItemChanged(it)
|
||||
}
|
||||
} else {
|
||||
selectedItems.clear()
|
||||
}
|
||||
}
|
||||
|
||||
open class ExplorerElementViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
@ -124,50 +149,69 @@ class ExplorerElementAdapter(
|
||||
var displayThumbnail = true
|
||||
var target: DrawableImageViewTarget? = null
|
||||
|
||||
private fun loadThumbnail(fullPath: String) {
|
||||
(bindingAdapter as ExplorerElementAdapter?)?.let { adapter ->
|
||||
adapter.gocryptfsVolume?.let { volume ->
|
||||
displayThumbnail = true
|
||||
Thread {
|
||||
volume.loadWholeFile(fullPath, maxSize = adapter.thumbnailMaxSize).first?.let {
|
||||
if (displayThumbnail) {
|
||||
adapter.activity.runOnUiThread {
|
||||
if (displayThumbnail) {
|
||||
target = Glide.with(adapter.activity).load(it).into(object : DrawableImageViewTarget(icon) {
|
||||
override fun onResourceReady(
|
||||
resource: Drawable,
|
||||
transition: Transition<in Drawable>?
|
||||
) {
|
||||
super.onResourceReady(resource, transition)
|
||||
target = null
|
||||
}
|
||||
})
|
||||
}
|
||||
private fun loadThumbnail(fullPath: String, adapter: ExplorerElementAdapter) {
|
||||
adapter.gocryptfsVolume?.let { volume ->
|
||||
displayThumbnail = true
|
||||
Thread {
|
||||
volume.loadWholeFile(fullPath, maxSize = adapter.thumbnailMaxSize).first?.let {
|
||||
if (displayThumbnail) {
|
||||
adapter.activity.runOnUiThread {
|
||||
if (displayThumbnail && !adapter.activity.isFinishing) {
|
||||
target = Glide.with(adapter.activity).load(it).skipMemoryCache(true).into(object : DrawableImageViewTarget(icon) {
|
||||
override fun onResourceReady(
|
||||
resource: Drawable,
|
||||
transition: Transition<in Drawable>?
|
||||
) {
|
||||
val bitmap = resource.toBitmap()
|
||||
adapter.thumbnailsCache!!.put(fullPath, bitmap.copy(bitmap.config, true))
|
||||
super.onResourceReady(resource, transition)
|
||||
target = null
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setThumbnailOrDefaultIcon(fullPath: String, defaultIconId: Int) {
|
||||
var setDefaultIcon = true
|
||||
(bindingAdapter as ExplorerElementAdapter?)?.let { adapter ->
|
||||
adapter.thumbnailsCache?.let {
|
||||
val thumbnail = it.get(fullPath)
|
||||
if (thumbnail != null) {
|
||||
icon.setImageBitmap(thumbnail)
|
||||
setDefaultIcon = false
|
||||
} else {
|
||||
loadThumbnail(fullPath, adapter)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setDefaultIcon) {
|
||||
icon.setImageResource(defaultIconId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bind(explorerElement: ExplorerElement, position: Int, isSelected: Boolean) {
|
||||
super.bind(explorerElement, position, isSelected)
|
||||
icon.setImageResource(
|
||||
when {
|
||||
ConstValues.isImage(explorerElement.name) -> {
|
||||
loadThumbnail(explorerElement.fullPath)
|
||||
R.drawable.icon_file_image
|
||||
}
|
||||
ConstValues.isVideo(explorerElement.name) -> {
|
||||
loadThumbnail(explorerElement.fullPath)
|
||||
R.drawable.icon_file_video
|
||||
}
|
||||
ConstValues.isText(explorerElement.name) -> R.drawable.icon_file_text
|
||||
ConstValues.isPDF(explorerElement.name) -> R.drawable.icon_file_pdf
|
||||
ConstValues.isAudio(explorerElement.name) -> R.drawable.icon_file_audio
|
||||
else -> R.drawable.icon_file_unknown
|
||||
when {
|
||||
ConstValues.isImage(explorerElement.name) -> {
|
||||
setThumbnailOrDefaultIcon(explorerElement.fullPath, R.drawable.icon_file_image)
|
||||
}
|
||||
)
|
||||
ConstValues.isVideo(explorerElement.name) -> {
|
||||
setThumbnailOrDefaultIcon(explorerElement.fullPath, R.drawable.icon_file_video)
|
||||
}
|
||||
else -> icon.setImageResource(
|
||||
when {
|
||||
ConstValues.isText(explorerElement.name) -> R.drawable.icon_file_text
|
||||
ConstValues.isPDF(explorerElement.name) -> R.drawable.icon_file_pdf
|
||||
ConstValues.isAudio(explorerElement.name) -> R.drawable.icon_file_audio
|
||||
else -> R.drawable.icon_file_unknown
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
package sushi.hardcore.droidfs.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@ -12,7 +11,6 @@ import androidx.recyclerview.widget.RecyclerView
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.Volume
|
||||
import sushi.hardcore.droidfs.VolumeDatabase
|
||||
import java.io.File
|
||||
|
||||
class VolumeAdapter(
|
||||
private val context: Context,
|
||||
@ -24,7 +22,7 @@ class VolumeAdapter(
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val inflater: LayoutInflater = LayoutInflater.from(context)
|
||||
lateinit var volumes: List<Volume>
|
||||
val selectedItems: MutableSet<Int> = HashSet()
|
||||
var selectedItems: MutableSet<Int> = HashSet()
|
||||
|
||||
init {
|
||||
reloadVolumes()
|
||||
@ -69,24 +67,30 @@ class VolumeAdapter(
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun selectAll() {
|
||||
for (i in volumes.indices) {
|
||||
if (!selectedItems.contains(i))
|
||||
if (!selectedItems.contains(i)) {
|
||||
selectedItems.add(i)
|
||||
notifyItemChanged(i)
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
fun unSelectAll() {
|
||||
selectedItems.clear()
|
||||
notifyDataSetChanged()
|
||||
fun unSelectAll(notifyChange: Boolean) {
|
||||
if (notifyChange) {
|
||||
val whatWasSelected = selectedItems
|
||||
selectedItems = HashSet()
|
||||
whatWasSelected.forEach {
|
||||
notifyItemChanged(it)
|
||||
}
|
||||
} else {
|
||||
selectedItems.clear()
|
||||
}
|
||||
}
|
||||
|
||||
fun refresh() {
|
||||
reloadVolumes()
|
||||
unSelectAll()
|
||||
unSelectAll(true)
|
||||
}
|
||||
|
||||
inner class VolumeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
@ -240,8 +240,8 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
protected fun unselectAll(){
|
||||
explorerAdapter.unSelectAll()
|
||||
protected fun unselectAll(notifyChange: Boolean = true) {
|
||||
explorerAdapter.unSelectAll(notifyChange)
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
@ -250,8 +250,8 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
synchronized(this) {
|
||||
ExplorerElement.sortBy(sortOrderValues[currentSortOrderIndex], foldersFirst, explorerElements)
|
||||
}
|
||||
unselectAll(false)
|
||||
explorerAdapter.explorerElements = explorerElements
|
||||
unselectAll()
|
||||
val sharedPrefsEditor = sharedPrefs.edit()
|
||||
sharedPrefsEditor.putString(ConstValues.SORT_ORDER_KEY, sortOrderValues[currentSortOrderIndex])
|
||||
sharedPrefsEditor.apply()
|
||||
@ -494,7 +494,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
if (!noItemSelected) {
|
||||
if (explorerAdapter.selectedItems.size == 1) {
|
||||
menu.findItem(R.id.rename).isVisible = true
|
||||
if (explorerElements[explorerAdapter.selectedItems[0]].isRegularFile) {
|
||||
if (explorerElements[explorerAdapter.selectedItems.first()].isRegularFile) {
|
||||
menu.findItem(R.id.open_as)?.isVisible = true
|
||||
if (usf_open) {
|
||||
menu.findItem(R.id.external_open)?.isVisible = true
|
||||
@ -523,7 +523,7 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
true
|
||||
}
|
||||
R.id.rename -> {
|
||||
val oldName = explorerElements[explorerAdapter.selectedItems[0]].name
|
||||
val oldName = explorerElements[explorerAdapter.selectedItems.first()].name
|
||||
with(EditTextDialog(this, R.string.rename_title) {
|
||||
rename(oldName, it)
|
||||
}) {
|
||||
@ -536,12 +536,22 @@ open class BaseExplorerActivity : BaseActivity() {
|
||||
true
|
||||
}
|
||||
R.id.open_as -> {
|
||||
showOpenAsDialog(PathUtils.pathJoin(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
|
||||
showOpenAsDialog(
|
||||
PathUtils.pathJoin(
|
||||
currentDirectoryPath,
|
||||
explorerElements[explorerAdapter.selectedItems.first()].name
|
||||
)
|
||||
)
|
||||
true
|
||||
}
|
||||
R.id.external_open -> {
|
||||
if (usf_open){
|
||||
openWithExternalApp(PathUtils.pathJoin(currentDirectoryPath, explorerElements[explorerAdapter.selectedItems[0]].name))
|
||||
openWithExternalApp(
|
||||
PathUtils.pathJoin(
|
||||
currentDirectoryPath,
|
||||
explorerElements[explorerAdapter.selectedItems.first()].name
|
||||
)
|
||||
)
|
||||
unselectAll()
|
||||
}
|
||||
true
|
||||
|
@ -362,7 +362,10 @@ class ExplorerActivity : BaseExplorerActivity() {
|
||||
if (size > 1) {
|
||||
dialog.setMessage(getString(R.string.multiple_delete_confirm, explorerAdapter.selectedItems.size.toString()))
|
||||
} else {
|
||||
dialog.setMessage(getString(R.string.single_delete_confirm, explorerAdapter.explorerElements[explorerAdapter.selectedItems[0]].name))
|
||||
dialog.setMessage(getString(
|
||||
R.string.single_delete_confirm,
|
||||
explorerAdapter.explorerElements[explorerAdapter.selectedItems.first()].name
|
||||
))
|
||||
}
|
||||
dialog.show()
|
||||
true
|
||||
|
Loading…
Reference in New Issue
Block a user