RemoteFileBrowser: move selected paths from activity to viewmodel

Signed-off-by: Álvaro Brey <alvaro.brey@nextcloud.com>
This commit is contained in:
Álvaro Brey 2022-06-06 18:38:45 +02:00 committed by Andy Scherzinger
parent ffdadc6c01
commit eba697b8f2
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
2 changed files with 95 additions and 62 deletions

View File

@ -40,15 +40,11 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.ActivityRemoteFileBrowserBinding
import com.nextcloud.talk.interfaces.SelectionInterface
import com.nextcloud.talk.remotefilebrowser.adapters.RemoteFileBrowserItemsAdapter
import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem
import com.nextcloud.talk.remotefilebrowser.viewmodels.RemoteFileBrowserItemsViewModel
import com.nextcloud.talk.ui.dialog.SortingOrderDialogFragment
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.FileSortOrder
import com.nextcloud.talk.utils.database.user.UserUtils
import java.io.File
import java.util.Collections
import java.util.TreeSet
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
@ -66,8 +62,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
private var filesSelectionDoneMenuItem: MenuItem? = null
private val selectedPaths: MutableSet<String> = Collections.synchronizedSet(TreeSet())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
@ -132,13 +126,10 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
showGrid = showGrid,
mimeTypeSelectionFilter = mimeTypeSelectionFilter,
userEntity = userUtils.currentUser!!,
selectionInterface = this
) { remoteFileBrowserItem ->
onItemClicked(remoteFileBrowserItem)
}
.apply {
items = remoteFileBrowserItems
}
selectionInterface = this,
onItemClicked = viewModel::onItemClicked
)
adapter.items = remoteFileBrowserItems
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = layoutManager
@ -146,6 +137,9 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
showList()
}
is RemoteFileBrowserItemsViewModel.FinishState -> {
finishWithResult(state.selectedPaths)
}
}
}
@ -160,24 +154,20 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
supportActionBar?.title = path
}
}
viewModel.selectedPaths.observe(this) { selectedPaths ->
filesSelectionDoneMenuItem?.isVisible = !selectedPaths.isNullOrEmpty()
binding.recyclerView.adapter?.notifyDataSetChanged()
}
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.menu_share_files, menu)
filesSelectionDoneMenuItem = menu?.findItem(R.id.files_selection_done)
filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0
return true
}
private fun onItemClicked(remoteFileBrowserItem: RemoteFileBrowserItem) {
if ("inode/directory" == remoteFileBrowserItem.mimeType) {
viewModel.changePath(remoteFileBrowserItem.path!!)
} else {
toggleBrowserItemSelection(remoteFileBrowserItem.path!!)
}
}
override fun onResume() {
super.onResume()
refreshCurrentPath()
@ -199,7 +189,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
true
}
R.id.files_selection_done -> {
onFileSelectionDone()
viewModel.onSelectionDone()
true
}
else -> {
@ -208,7 +198,7 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
}
}
private fun onFileSelectionDone() {
private fun finishWithResult(selectedPaths: Set<String>) {
val data = Intent()
data.putStringArrayListExtra(EXTRA_SELECTED_PATHS, ArrayList(selectedPaths))
setResult(Activity.RESULT_OK, data)
@ -243,35 +233,6 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
viewModel.loadItems()
}
private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean {
var file = File(currentPath)
if (selectedPaths.size > 0 && file.parent != "/") {
while (file.parent != null) {
var parent = file.parent!!
if (File(file.parent!!).parent != null) {
parent += "/"
}
if (selectedPaths.contains(parent)) {
return true
}
file = File(file.parent!!)
}
}
return false
}
private fun checkAndRemoveAnySelectedParents(currentPath: String) {
var file = File(currentPath)
selectedPaths.remove(currentPath)
while (file.parent != null) {
selectedPaths.remove(file.parent!! + "/")
file = File(file.parent!!)
}
runOnUiThread {
binding.recyclerView.adapter!!.notifyDataSetChanged()
}
}
companion object {
private val TAG = RemoteFileBrowserActivity::class.simpleName
const val SPAN_COUNT: Int = 4
@ -280,20 +241,15 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
}
override fun toggleBrowserItemSelection(path: String) {
if (selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)) {
checkAndRemoveAnySelectedParents(path)
} else {
// TODO if it's a folder, remove all the children we added manually
selectedPaths.add(path)
}
filesSelectionDoneMenuItem?.isVisible = selectedPaths.size > 0
// unused, viewmodel gets called directly
}
override fun isPathSelected(path: String): Boolean {
return selectedPaths.contains(path) || shouldPathBeSelectedDueToParent(path)
// TODO figure out a better way to do this. Narrower interface?
return viewModel.isPathSelected(path)
}
override fun shouldOnlySelectOneImageFile(): Boolean {
return true
return true // unused
}
}

View File

@ -36,6 +36,19 @@ import net.orange_box.storebox.listeners.OnPreferenceValueChangedListener
import java.io.File
import javax.inject.Inject
/**
* @startuml
* hide empty description
* [*] --> InitialState
* InitialState --> LoadingItemsState
* LoadingItemsState --> NoRemoteFileItemsState
* NoRemoteFileItemsState --> LoadingItemsState
* LoadingItemsState --> LoadedState
* LoadedState --> LoadingItemsState
* LoadedState --> FinishState
* FinishState --> [*]
* @enduml
*/
class RemoteFileBrowserItemsViewModel @Inject constructor(
private val repository: RemoteFileBrowserItemsRepository,
private val appPreferences: AppPreferences
@ -47,6 +60,7 @@ class RemoteFileBrowserItemsViewModel @Inject constructor(
object NoRemoteFileItemsState : ViewState
object LoadingItemsState : ViewState
class LoadedState(val items: List<RemoteFileBrowserItem>) : ViewState
class FinishState(val selectedPaths: Set<String>) : ViewState
private val initialSortOrder = FileSortOrderNew.getFileSortOrder(appPreferences.sorting)
private val sortingPrefListener: SortChangeListener = SortChangeListener()
@ -64,6 +78,10 @@ class RemoteFileBrowserItemsViewModel @Inject constructor(
val currentPath: LiveData<String>
get() = _currentPath
private val _selectedPaths: MutableLiveData<Set<String>> = MutableLiveData(emptySet())
val selectedPaths: LiveData<Set<String>>
get() = _selectedPaths
init {
appPreferences.registerSortingChangeListener(sortingPrefListener)
}
@ -144,6 +162,65 @@ class RemoteFileBrowserItemsViewModel @Inject constructor(
}
}
fun onSelectionDone() {
val selection = selectedPaths.value
if (!selection.isNullOrEmpty()) {
_viewState.value = FinishState(selection)
}
}
fun onItemClicked(remoteFileBrowserItem: RemoteFileBrowserItem) {
if (remoteFileBrowserItem.mimeType == MIME_DIRECTORY) {
changePath(remoteFileBrowserItem.path!!)
} else {
toggleBrowserItemSelection(remoteFileBrowserItem.path!!)
}
}
private fun toggleBrowserItemSelection(path: String) {
val paths = selectedPaths.value!!.toMutableSet()
if (paths.contains(path) || shouldPathBeSelectedDueToParent(path)) {
checkAndRemoveAnySelectedParents(path)
} else {
// TODO if it's a folder, remove all the children we added manually
paths.add(path)
_selectedPaths.value = paths
}
}
private fun checkAndRemoveAnySelectedParents(currentPath: String) {
var file = File(currentPath)
val paths = selectedPaths.value!!.toMutableSet()
paths.remove(currentPath)
while (file.parent != null) {
paths.remove(file.parent!! + File.pathSeparator)
file = File(file.parent!!)
}
_selectedPaths.value = paths
}
private fun shouldPathBeSelectedDueToParent(currentPath: String): Boolean {
var file = File(currentPath)
val paths = selectedPaths.value!!
if (paths.isNotEmpty() && file.parent != ROOT_PATH) {
while (file.parent != null) {
var parent = file.parent!!
if (File(file.parent!!).parent != null) {
parent += File.pathSeparator
}
if (paths.contains(parent)) {
return true
}
file = File(file.parent!!)
}
}
return false
}
fun isPathSelected(path: String): Boolean {
return selectedPaths.value?.contains(path) == true || shouldPathBeSelectedDueToParent(path)
}
companion object {
private val TAG = RemoteFileBrowserItemsViewModel::class.simpleName
private const val ROOT_PATH = "/"