rewrite the Directory adapter, prepare it for drag-selection

This commit is contained in:
tibbi 2017-05-13 17:39:07 +02:00
parent 09d4793e75
commit 44a71c032b
2 changed files with 96 additions and 59 deletions

View file

@ -124,6 +124,7 @@ class MainActivity : SimpleActivity(), DirectoryAdapter.DirOperationsListener {
override fun onStop() { override fun onStop() {
super.onStop() super.onStop()
config.temporarilyShowHidden = false config.temporarilyShowHidden = false
DirectoryAdapter.cleanup()
} }
private fun tryloadGallery() { private fun tryloadGallery() {

View file

@ -29,29 +29,36 @@ import java.util.*
class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Directory>, val listener: DirOperationsListener?, val itemClick: (Directory) -> Unit) : class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Directory>, val listener: DirOperationsListener?, val itemClick: (Directory) -> Unit) :
RecyclerView.Adapter<DirectoryAdapter.ViewHolder>() { RecyclerView.Adapter<DirectoryAdapter.ViewHolder>() {
val multiSelector = MultiSelector()
val views = ArrayList<View>() val views = ArrayList<View>()
val config = activity.config val config = activity.config
var pinnedFolders = config.pinnedFolders var pinnedFolders = config.pinnedFolders
companion object { companion object {
val multiSelector = MultiSelector()
var actMode: ActionMode? = null var actMode: ActionMode? = null
val markedItems = HashSet<Int>()
var foregroundColor = 0 var foregroundColor = 0
var backgroundColor = 0 var backgroundColor = 0
var animateGifs = true var animateGifs = true
var itemCnt = 0 var itemCnt = 0
var itemViews: HashMap<Int, View> = HashMap()
val selectedPositions: HashSet<Int> = HashSet()
fun toggleItemSelection(itemView: View, select: Boolean, pos: Int = -1) { fun toggleItemSelection(select: Boolean, pos: Int) {
getProperView(itemView).isSelected = select if (itemViews[pos] != null)
getProperView(itemViews[pos]!!).isSelected = select
if (pos == -1)
return
if (select) if (select)
markedItems.add(pos) selectedPositions.add(pos)
else else
markedItems.remove(pos) selectedPositions.remove(pos)
if (selectedPositions.isEmpty()) {
actMode?.finish()
return
}
updateTitle(selectedPositions.size)
actMode?.invalidate()
} }
fun getProperView(itemView: View): View { fun getProperView(itemView: View): View {
@ -64,6 +71,11 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
fun updateTitle(cnt: Int) { fun updateTitle(cnt: Int) {
actMode?.title = "$cnt / $itemCnt" actMode?.title = "$cnt / $itemCnt"
} }
fun cleanup() {
itemViews.clear()
selectedPositions.clear()
}
} }
init { init {
@ -100,26 +112,27 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
} }
override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean { override fun onPrepareActionMode(actionMode: ActionMode?, menu: Menu): Boolean {
val positions = multiSelector.selectedPositions menu.findItem(R.id.cab_rename).isVisible = selectedPositions.size <= 1
menu.findItem(R.id.cab_rename).isVisible = positions.size <= 1
checkHideBtnVisibility(menu, positions) checkHideBtnVisibility(menu)
checkPinBtnVisibility(menu, positions) checkPinBtnVisibility(menu)
return true return true
} }
override fun onDestroyActionMode(actionMode: ActionMode?) { override fun onDestroyActionMode(actionMode: ActionMode?) {
super.onDestroyActionMode(actionMode) super.onDestroyActionMode(actionMode)
views.forEach { toggleItemSelection(it, false) } selectedPositions.forEach {
markedItems.clear() getProperView(itemViews[it]!!).isSelected = false
}
selectedPositions.clear()
actMode = null actMode = null
} }
fun checkHideBtnVisibility(menu: Menu, positions: List<Int>) { fun checkHideBtnVisibility(menu: Menu) {
var hiddenCnt = 0 var hiddenCnt = 0
var unhiddenCnt = 0 var unhiddenCnt = 0
positions.map { dirs[it].path }.forEach { selectedPositions.map { dirs[it].path }.forEach {
if (File(it).containsNoMedia()) if (File(it).containsNoMedia())
hiddenCnt++ hiddenCnt++
else else
@ -130,11 +143,11 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0 menu.findItem(R.id.cab_unhide).isVisible = hiddenCnt > 0
} }
fun checkPinBtnVisibility(menu: Menu, positions: List<Int>) { fun checkPinBtnVisibility(menu: Menu) {
val pinnedFolders = config.pinnedFolders val pinnedFolders = config.pinnedFolders
var pinnedCnt = 0 var pinnedCnt = 0
var unpinnedCnt = 0 var unpinnedCnt = 0
positions.map { dirs[it].path }.forEach { selectedPositions.map { dirs[it].path }.forEach {
if (pinnedFolders.contains(it)) if (pinnedFolders.contains(it))
pinnedCnt++ pinnedCnt++
else else
@ -147,18 +160,17 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
} }
private fun showProperties() { private fun showProperties() {
val selections = multiSelector.selectedPositions if (selectedPositions.size <= 1) {
if (selections.size <= 1) { PropertiesDialog(activity, dirs[selectedPositions.first()].path, config.shouldShowHidden)
PropertiesDialog(activity, dirs[selections[0]].path, config.shouldShowHidden)
} else { } else {
val paths = ArrayList<String>() val paths = ArrayList<String>()
selections.forEach { paths.add(dirs[it].path) } selectedPositions.forEach { paths.add(dirs[it].path) }
PropertiesDialog(activity, paths, config.shouldShowHidden) PropertiesDialog(activity, paths, config.shouldShowHidden)
} }
} }
private fun renameDir() { private fun renameDir() {
val path = dirs[multiSelector.selectedPositions[0]].path val path = dirs[selectedPositions.first()].path
val dir = File(path) val dir = File(path)
if (activity.isAStorageRootFolder(dir.absolutePath)) { if (activity.isAStorageRootFolder(dir.absolutePath)) {
activity.toast(R.string.rename_folder_root) activity.toast(R.string.rename_folder_root)
@ -167,8 +179,8 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
RenameItemDialog(activity, dir.absolutePath) { RenameItemDialog(activity, dir.absolutePath) {
activity.runOnUiThread { activity.runOnUiThread {
actMode?.finish()
listener?.refreshItems() listener?.refreshItems()
actMode?.finish()
} }
} }
} }
@ -226,11 +238,10 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
private fun copyMoveTo(isCopyOperation: Boolean) { private fun copyMoveTo(isCopyOperation: Boolean) {
val files = ArrayList<File>() val files = ArrayList<File>()
val positions = multiSelector.selectedPositions if (selectedPositions.isEmpty())
if (positions.isEmpty())
return return
positions.forEach { selectedPositions.forEach {
val dir = File(dirs[it].path) val dir = File(dirs[it].path)
files.addAll(dir.listFiles().filter { it.isFile && it.isImageVideoGif() }) files.addAll(dir.listFiles().filter { it.isFile && it.isImageVideoGif() })
} }
@ -246,8 +257,7 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
fun selectAll() { fun selectAll() {
val cnt = dirs.size val cnt = dirs.size
for (i in 0..cnt - 1) { for (i in 0..cnt - 1) {
markedItems.add(i) selectedPositions.add(i)
multiSelector.setSelected(i, 0, true)
notifyItemChanged(i) notifyItemChanged(i)
} }
updateTitle(cnt) updateTitle(cnt)
@ -256,18 +266,17 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
private fun askConfirmDelete() { private fun askConfirmDelete() {
ConfirmationDialog(activity) { ConfirmationDialog(activity) {
actMode?.finish()
deleteFiles() deleteFiles()
actMode?.finish()
} }
} }
private fun deleteFiles() { private fun deleteFiles() {
val selections = multiSelector.selectedPositions val folders = ArrayList<File>(selectedPositions.size)
val folders = ArrayList<File>(selections.size) val removeFolders = ArrayList<Directory>(selectedPositions.size)
val removeFolders = ArrayList<Directory>(selections.size)
var needPermissionForPath = "" var needPermissionForPath = ""
selections.forEach { selectedPositions.forEach {
val path = dirs[it].path val path = dirs[it].path
if (activity.needsStupidWritePermissions(path) && activity.config.treeUri.isEmpty()) { if (activity.needsStupidWritePermissions(path) && activity.config.treeUri.isEmpty()) {
needPermissionForPath = path needPermissionForPath = path
@ -275,8 +284,7 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
} }
activity.handleSAFDialog(File(needPermissionForPath)) { activity.handleSAFDialog(File(needPermissionForPath)) {
selections.reverse() selectedPositions.reversed().forEach {
selections.forEach {
val directory = dirs[it] val directory = dirs[it]
folders.add(File(directory.path)) folders.add(File(directory.path))
removeFolders.add(directory) removeFolders.add(directory)
@ -284,16 +292,14 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
} }
dirs.removeAll(removeFolders) dirs.removeAll(removeFolders)
markedItems.clear()
listener?.tryDeleteFolders(folders) listener?.tryDeleteFolders(folders)
itemCnt = dirs.size itemCnt = dirs.size
} }
} }
private fun getSelectedPaths(): HashSet<String> { private fun getSelectedPaths(): HashSet<String> {
val positions = multiSelector.selectedPositions val paths = HashSet<String>(selectedPositions.size)
val paths = HashSet<String>(positions.size) selectedPositions.forEach { paths.add(dirs[it].path) }
positions.forEach { paths.add(dirs[it].path) }
return paths return paths
} }
@ -304,7 +310,8 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val dir = dirs[position] val dir = dirs[position]
views.add(holder.bindView(activity, multiSelectorMode, multiSelector, dir, position, pinnedFolders.contains(dir.path))) views.add(holder.bindView(activity, multiSelectorMode, dir, position, pinnedFolders.contains(dir.path), listener))
holder.itemView.tag = holder
} }
override fun onViewRecycled(holder: ViewHolder?) { override fun onViewRecycled(holder: ViewHolder?) {
@ -314,25 +321,61 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
override fun getItemCount() = dirs.size override fun getItemCount() = dirs.size
fun selectRange(from: Int, to: Int, min: Int, max: Int) {
if (from == to) {
(min..max).filter { it != from }
.forEach { toggleItemSelection(false, it) }
return
}
if (to < from) {
for (i in to..from)
toggleItemSelection(true, i)
if (min > -1 && min < to) {
(min..to - 1).filter { it != from }
.forEach { toggleItemSelection(false, it) }
}
if (max > -1) {
for (i in from + 1..max)
toggleItemSelection(false, i)
}
} else {
for (i in from..to)
toggleItemSelection(true, i)
if (max > -1 && max > to) {
(to + 1..max).filter { it != from }
.forEach { toggleItemSelection(false, it) }
}
if (min > -1) {
for (i in min..from - 1)
toggleItemSelection(false, i)
}
}
}
class ViewHolder(val view: View, val itemClick: (Directory) -> (Unit)) : SwappingHolder(view, MultiSelector()) { class ViewHolder(val view: View, val itemClick: (Directory) -> (Unit)) : SwappingHolder(view, MultiSelector()) {
fun bindView(activity: SimpleActivity, multiSelectorCallback: ModalMultiSelectorCallback, multiSelector: MultiSelector, directory: Directory, pos: Int, isPinned: Boolean) fun bindView(activity: SimpleActivity, multiSelectorCallback: ModalMultiSelectorCallback, directory: Directory, pos: Int,
: View { isPinned: Boolean, listener: DirOperationsListener?): View {
itemViews.put(pos, itemView)
itemView.apply { itemView.apply {
dir_name.text = directory.name dir_name.text = directory.name
photo_cnt.text = directory.mediaCnt.toString() photo_cnt.text = directory.mediaCnt.toString()
dir_pin.visibility = if (isPinned) View.VISIBLE else View.GONE dir_pin.visibility = if (isPinned) View.VISIBLE else View.GONE
toggleItemSelection(this, markedItems.contains(pos), pos) toggleItemSelection(selectedPositions.contains(pos), pos)
activity.loadImage(directory.tmb, dir_thumbnail) activity.loadImage(directory.tmb, dir_thumbnail)
setOnClickListener { viewClicked(multiSelector, directory, pos) } setOnClickListener { viewClicked(multiSelector, directory, pos) }
setOnLongClickListener { setOnLongClickListener {
if (!multiSelector.isSelectable) { if (!multiSelector.isSelectable) {
activity.startSupportActionMode(multiSelectorCallback) activity.startSupportActionMode(multiSelectorCallback)
multiSelector.setSelected(this@ViewHolder, true) toggleItemSelection(true, pos)
updateTitle(multiSelector.selectedPositions.size)
toggleItemSelection(this, true, pos)
actMode?.invalidate() actMode?.invalidate()
} }
listener!!.itemLongClicked(pos)
true true
} }
@ -346,17 +389,8 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
fun viewClicked(multiSelector: MultiSelector, directory: Directory, pos: Int) { fun viewClicked(multiSelector: MultiSelector, directory: Directory, pos: Int) {
if (multiSelector.isSelectable) { if (multiSelector.isSelectable) {
val isSelected = multiSelector.selectedPositions.contains(layoutPosition) val isSelected = selectedPositions.contains(layoutPosition)
multiSelector.setSelected(this, !isSelected) toggleItemSelection(!isSelected, pos)
toggleItemSelection(itemView, !isSelected, pos)
val selectedCnt = multiSelector.selectedPositions.size
if (selectedCnt == 0) {
actMode?.finish()
} else {
updateTitle(selectedCnt)
}
actMode?.invalidate()
} else { } else {
itemClick(directory) itemClick(directory)
} }
@ -371,5 +405,7 @@ class DirectoryAdapter(val activity: SimpleActivity, val dirs: MutableList<Direc
fun refreshItems() fun refreshItems()
fun tryDeleteFolders(folders: ArrayList<File>) fun tryDeleteFolders(folders: ArrayList<File>)
fun itemLongClicked(position: Int)
} }
} }