Show total number of selected items

This commit is contained in:
Matéo Duparc 2022-04-17 15:52:34 +02:00
parent 339309b00d
commit f1d4b07726
Signed by untrusted user: hardcoresushi
GPG Key ID: AFE384344A45E13A
8 changed files with 60 additions and 26 deletions

View File

@ -35,7 +35,7 @@ import java.io.File
import java.util.* import java.util.*
import kotlin.NoSuchElementException import kotlin.NoSuchElementException
class MainActivity : BaseActivity() { class MainActivity : BaseActivity(), VolumeAdapter.Listener {
companion object { companion object {
const val DEFAULT_VOLUME_KEY = "default_volume" const val DEFAULT_VOLUME_KEY = "default_volume"
@ -101,8 +101,7 @@ class MainActivity : BaseActivity() {
volumeDatabase, volumeDatabase,
!pickMode && !dropMode, !pickMode && !dropMode,
!dropMode, !dropMode,
::onVolumeItemClick, this,
::onVolumeItemLongClick,
) )
binding.recyclerViewVolumes.adapter = volumeAdapter binding.recyclerViewVolumes.adapter = volumeAdapter
binding.recyclerViewVolumes.layoutManager = LinearLayoutManager(this) binding.recyclerViewVolumes.layoutManager = LinearLayoutManager(this)
@ -147,14 +146,22 @@ class MainActivity : BaseActivity() {
defaultVolumeName = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null) defaultVolumeName = sharedPrefs.getString(DEFAULT_VOLUME_KEY, null)
} }
private fun onVolumeItemClick(volume: Volume, position: Int) { override fun onSelectionChanged(size: Int) {
title = if (size == 0) {
getString(R.string.app_name)
} else {
getString(R.string.elements_selected, size, volumeAdapter.volumes.size)
}
}
override fun onVolumeItemClick(volume: Volume, position: Int) {
if (volumeAdapter.selectedItems.isEmpty()) if (volumeAdapter.selectedItems.isEmpty())
openVolume(volume, position) openVolume(volume, position)
else else
invalidateOptionsMenu() invalidateOptionsMenu()
} }
private fun onVolumeItemLongClick() { override fun onVolumeItemLongClick() {
invalidateOptionsMenu() invalidateOptionsMenu()
} }
@ -174,6 +181,7 @@ class MainActivity : BaseActivity() {
private fun unselect(position: Int) { private fun unselect(position: Int) {
volumeAdapter.selectedItems.remove(position) volumeAdapter.selectedItems.remove(position)
volumeAdapter.onVolumeChanged(position) volumeAdapter.onVolumeChanged(position)
onSelectionChanged(0) // unselect() is always called when only one element is selected
invalidateOptionsMenu() invalidateOptionsMenu()
} }

View File

@ -26,10 +26,9 @@ import java.util.*
class ExplorerElementAdapter( class ExplorerElementAdapter(
val activity: AppCompatActivity, val activity: AppCompatActivity,
val gocryptfsVolume: GocryptfsVolume?, val gocryptfsVolume: GocryptfsVolume?,
val onExplorerElementClick: (Int) -> Unit, private val listener: Listener,
val onExplorerElementLongClick: (Int) -> Unit,
val thumbnailMaxSize: Long, val thumbnailMaxSize: Long,
) : SelectableAdapter<ExplorerElement>() { ) : SelectableAdapter<ExplorerElement>(listener::onSelectionChanged) {
val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault()) val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())
var explorerElements = listOf<ExplorerElement>() var explorerElements = listOf<ExplorerElement>()
@SuppressLint("NotifyDataSetChanged") @SuppressLint("NotifyDataSetChanged")
@ -47,6 +46,12 @@ class ExplorerElementAdapter(
} }
} }
interface Listener {
fun onSelectionChanged(size: Int)
fun onExplorerElementClick(position: Int)
fun onExplorerElementLongClick(position: Int)
}
override fun getItems(): List<ExplorerElement> { override fun getItems(): List<ExplorerElement> {
return explorerElements return explorerElements
} }
@ -60,12 +65,12 @@ class ExplorerElementAdapter(
} }
override fun onItemClick(position: Int): Boolean { override fun onItemClick(position: Int): Boolean {
onExplorerElementClick(position) listener.onExplorerElementClick(position)
return super.onItemClick(position) return super.onItemClick(position)
} }
override fun onItemLongClick(position: Int): Boolean { override fun onItemLongClick(position: Int): Boolean {
onExplorerElementLongClick(position) listener.onExplorerElementLongClick(position)
return super.onItemLongClick(position) return super.onItemLongClick(position)
} }

View File

@ -4,7 +4,7 @@ import android.view.View
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
abstract class SelectableAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHolder>() { abstract class SelectableAdapter<T>(private val onSelectionChanged: (Int) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var selectedItems: MutableSet<Int> = HashSet() var selectedItems: MutableSet<Int> = HashSet()
protected abstract fun getItems(): List<T> protected abstract fun getItems(): List<T>
@ -14,13 +14,15 @@ abstract class SelectableAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHold
} }
protected open fun toggleSelection(position: Int): Boolean { protected open fun toggleSelection(position: Int): Boolean {
return if (selectedItems.contains(position)) { val isSelected = if (selectedItems.contains(position)) {
selectedItems.remove(position) selectedItems.remove(position)
false false
} else { } else {
selectedItems.add(position) selectedItems.add(position)
true true
} }
onSelectionChanged(selectedItems.size)
return isSelected
} }
protected open fun onItemClick(position: Int): Boolean { protected open fun onItemClick(position: Int): Boolean {
@ -45,6 +47,7 @@ abstract class SelectableAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHold
notifyItemChanged(i) notifyItemChanged(i)
} }
} }
onSelectionChanged(selectedItems.size)
} }
fun unSelectAll(notifyChange: Boolean) { fun unSelectAll(notifyChange: Boolean) {
@ -57,6 +60,7 @@ abstract class SelectableAdapter<T> : RecyclerView.Adapter<RecyclerView.ViewHold
} else { } else {
selectedItems.clear() selectedItems.clear()
} }
onSelectionChanged(selectedItems.size)
} }
private fun setBackground(rootView: View, isSelected: Boolean) { private fun setBackground(rootView: View, isSelected: Boolean) {

View File

@ -17,9 +17,8 @@ class VolumeAdapter(
private val volumeDatabase: VolumeDatabase, private val volumeDatabase: VolumeDatabase,
private val allowSelection: Boolean, private val allowSelection: Boolean,
private val showReadOnly: Boolean, private val showReadOnly: Boolean,
private val onVolumeItemClick: (Volume, Int) -> Unit, private val listener: Listener,
private val onVolumeItemLongClick: () -> Unit, ) : SelectableAdapter<Volume>(listener::onSelectionChanged) {
) : SelectableAdapter<Volume>() {
private val inflater: LayoutInflater = LayoutInflater.from(context) private val inflater: LayoutInflater = LayoutInflater.from(context)
lateinit var volumes: List<Volume> lateinit var volumes: List<Volume>
@ -27,6 +26,12 @@ class VolumeAdapter(
reloadVolumes() reloadVolumes()
} }
interface Listener {
fun onSelectionChanged(size: Int)
fun onVolumeItemClick(volume: Volume, position: Int)
fun onVolumeItemLongClick()
}
override fun getItems(): List<Volume> { override fun getItems(): List<Volume> {
return volumes return volumes
} }
@ -40,7 +45,7 @@ class VolumeAdapter(
} }
override fun onItemClick(position: Int): Boolean { override fun onItemClick(position: Int): Boolean {
onVolumeItemClick(volumes[position], position) listener.onVolumeItemClick(volumes[position], position)
return if (allowSelection) { return if (allowSelection) {
super.onItemClick(position) super.onItemClick(position)
} else { } else {
@ -49,7 +54,7 @@ class VolumeAdapter(
} }
override fun onItemLongClick(position: Int): Boolean { override fun onItemLongClick(position: Int): Boolean {
onVolumeItemLongClick() listener.onVolumeItemLongClick()
return if (allowSelection) return if (allowSelection)
super.onItemLongClick(position) super.onItemLongClick(position)
else else

View File

@ -41,7 +41,7 @@ import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
import sushi.hardcore.droidfs.widgets.EditTextDialog import sushi.hardcore.droidfs.widgets.EditTextDialog
open class BaseExplorerActivity : BaseActivity() { open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listener {
private lateinit var sortOrderEntries: Array<String> private lateinit var sortOrderEntries: Array<String>
private lateinit var sortOrderValues: Array<String> private lateinit var sortOrderValues: Array<String>
private var foldersFirst = true private var foldersFirst = true
@ -100,7 +100,7 @@ open class BaseExplorerActivity : BaseActivity() {
titleText = customView.findViewById(R.id.title_text) titleText = customView.findViewById(R.id.title_text)
} }
title = "" title = ""
titleText.text = getString(R.string.volume, volumeName) setVolumeNameTitle()
explorerAdapter = ExplorerElementAdapter( explorerAdapter = ExplorerElementAdapter(
this, this,
if (sharedPrefs.getBoolean("thumbnails", true)) { if (sharedPrefs.getBoolean("thumbnails", true)) {
@ -108,8 +108,7 @@ open class BaseExplorerActivity : BaseActivity() {
} else { } else {
null null
}, },
::onExplorerItemClick, this,
::onExplorerItemLongClick,
sharedPrefs.getLong(ConstValues.THUMBNAIL_MAX_SIZE_KEY, ConstValues.DEFAULT_THUMBNAIL_MAX_SIZE)*1000, sharedPrefs.getLong(ConstValues.THUMBNAIL_MAX_SIZE_KEY, ConstValues.DEFAULT_THUMBNAIL_MAX_SIZE)*1000,
) )
explorerViewModel = ViewModelProvider(this).get(ExplorerViewModel::class.java) explorerViewModel = ViewModelProvider(this).get(ExplorerViewModel::class.java)
@ -209,7 +208,19 @@ open class BaseExplorerActivity : BaseActivity() {
.show() .show()
} }
protected open fun onExplorerItemClick(position: Int) { private fun setVolumeNameTitle() {
titleText.text = getString(R.string.volume, volumeName)
}
override fun onSelectionChanged(size: Int) {
if (size == 0) {
setVolumeNameTitle()
} else {
titleText.text = getString(R.string.elements_selected, size, explorerElements.count { !it.isParentFolder })
}
}
override fun onExplorerElementClick(position: Int) {
if (explorerAdapter.selectedItems.isEmpty()) { if (explorerAdapter.selectedItems.isEmpty()) {
val fullPath = explorerElements[position].fullPath val fullPath = explorerElements[position].fullPath
when { when {
@ -240,7 +251,7 @@ open class BaseExplorerActivity : BaseActivity() {
invalidateOptionsMenu() invalidateOptionsMenu()
} }
protected open fun onExplorerItemLongClick(position: Int) { override fun onExplorerElementLongClick(position: Int) {
invalidateOptionsMenu() invalidateOptionsMenu()
} }

View File

@ -217,8 +217,8 @@ class ExplorerActivity : BaseExplorerActivity() {
usf_share = sharedPrefs.getBoolean("usf_share", false) usf_share = sharedPrefs.getBoolean("usf_share", false)
} }
override fun onExplorerItemLongClick(position: Int) { override fun onExplorerElementLongClick(position: Int) {
super.onExplorerItemLongClick(position) super.onExplorerElementLongClick(position)
cancelItemAction() cancelItemAction()
} }

View File

@ -21,7 +21,7 @@ class ExplorerActivityPick : BaseExplorerActivity() {
//don't bind //don't bind
} }
override fun onExplorerItemClick(position: Int) { override fun onExplorerElementClick(position: Int) {
val wasSelecting = explorerAdapter.selectedItems.isNotEmpty() val wasSelecting = explorerAdapter.selectedItems.isNotEmpty()
if (explorerAdapter.selectedItems.isEmpty()) { if (explorerAdapter.selectedItems.isEmpty()) {
if (!wasSelecting) { if (!wasSelecting) {

View File

@ -239,4 +239,5 @@
<string name="multiple_folders">%d folders</string> <string name="multiple_folders">%d folders</string>
<string name="default_open">Open this volume when launching the application</string> <string name="default_open">Open this volume when launching the application</string>
<string name="remove_default_open">Don\'t open by default</string> <string name="remove_default_open">Don\'t open by default</string>
<string name="elements_selected">%d/%d selected</string>
</resources> </resources>