Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.annotation.MenuRes
import androidx.core.widget.addTextChangedListener
import androidx.hilt.navigation.fragment.hiltNavGraphViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
Expand Down Expand Up @@ -104,18 +105,11 @@ class TorrentProcessingFragment : UnchainedFragment(), TorrentContentListener {
)
findNavController().navigate(action)
} else {
val filesList = mutableListOf<TorrentFileItem>()
val torrentStructure: Node<TorrentFileItem> =
getFilesNodes(content.item, selectedOnly = false)
if (torrentStructure.children.isNotEmpty()) {
currentStructure = torrentStructure
Node.traverseDepthFirst(torrentStructure) { item ->
filesList.add(item)
}
(binding.rvTorrentFilePicker.adapter
as TorrentContentFilesSelectionAdapter)
.submitList(filesList)
binding.rvTorrentFilePicker.adapter?.notifyDataSetChanged()
updateFilesList()
}

binding.loadingLayout.visibility = View.INVISIBLE
Expand Down Expand Up @@ -169,13 +163,7 @@ class TorrentProcessingFragment : UnchainedFragment(), TorrentContentListener {
}

is TorrentEvent.SelectionUpdated -> {
currentStructure?.let { structure ->
val filesList = mutableListOf<TorrentFileItem>()
Node.traverseDepthFirst(structure) { item -> filesList.add(item) }
(binding.rvTorrentFilePicker.adapter as TorrentContentFilesSelectionAdapter)
.submitList(filesList)
binding.rvTorrentFilePicker.adapter?.notifyDataSetChanged()
}
updateFilesList()
}

else -> {
Expand Down Expand Up @@ -237,6 +225,18 @@ class TorrentProcessingFragment : UnchainedFragment(), TorrentContentListener {

binding.fabDownload.setOnClickListener { showMenu(it, R.menu.download_mode_picker) }

binding.tiFilter.addTextChangedListener {
// the selection checkbox refers to the currently visible files
binding.cbSelectAll.isChecked = false
updateFilesList()
}

binding.cbSelectAll.setOnClickListener {
val selected = binding.cbSelectAll.isChecked
getFilteredFiles().forEach { item -> item.selected = selected }
viewModel.updateTorrentStructure()
}

if (args.torrentID != null) {
// we are loading an already available torrent
args.torrentID?.let { viewModel.fetchTorrentDetails(it) }
Expand Down Expand Up @@ -266,6 +266,41 @@ class TorrentProcessingFragment : UnchainedFragment(), TorrentContentListener {
}
}

/**
* Returns the files matching the current filter. With an empty filter the whole structure is
* returned, folders included, otherwise only the matching files are listed, see #450
*/
private fun getFilteredFiles(): List<TorrentFileItem> {
if (_binding == null) return emptyList()
val structure = currentStructure ?: return emptyList()
Comment thread
LivingWithHippos marked this conversation as resolved.
Resolved
val query = binding.tiFilter.text?.toString()?.trim() ?: ""
val filesList = mutableListOf<TorrentFileItem>()
if (query.isEmpty()) {
Node.traverseDepthFirst(structure) { item -> filesList.add(item) }
} else {
// a query with wildcards must match the whole file name, a plain one any part of it
val regexQuery =
if (query.contains('*')) {
val pattern = query.split('*').joinToString(".*") { Regex.escape(it) }
Regex("^$pattern$", RegexOption.IGNORE_CASE)
} else {
Regex(Regex.escape(query), RegexOption.IGNORE_CASE)
}
Node.traverseDepthFirst(structure) { item ->
if (item.id != TYPE_FOLDER && regexQuery.containsMatchIn(item.name))
filesList.add(item)
}
}
return filesList
}

private fun updateFilesList() {
if (_binding == null) return
with(binding.rvTorrentFilePicker.adapter as TorrentContentFilesSelectionAdapter) {
submitList(getFilteredFiles())
notifyDataSetChanged()
}

private fun showMenu(v: View, @MenuRes menuRes: Int) {
val popup = PopupMenu(requireContext(), v)
popup.menuInflater.inflate(menuRes, popup.menu)
Expand Down
41 changes: 39 additions & 2 deletions app/app/src/main/res/layout/fragment_torrent_processing.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,48 @@
android:layout_marginTop="10dp"
android:text="@string/select_files"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@id/rvTorrentFilePicker"
app:layout_constraintBottom_toTopOf="@id/tfFilter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tfFilter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="10dp"
android:hint="@string/filter_files_hint"
android:importantForAutofill="no"
app:endIconMode="clear_text"
app:layout_constraintBottom_toTopOf="@id/rvTorrentFilePicker"
app:layout_constraintEnd_toStartOf="@id/cbSelectAll"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPickerTitle"
app:startIconDrawable="@drawable/icon_search">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tiFilter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionDone"
android:singleLine="true" />

</com.google.android.material.textfield.TextInputLayout>

<CheckBox
android:id="@+id/cbSelectAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="20dp"
android:checked="false"
android:contentDescription="@string/select_deselect_all"
android:tooltipText="@string/select_deselect_all"
app:layout_constraintBottom_toBottomOf="@id/tfFilter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tfFilter"
app:layout_constraintTop_toTopOf="@id/tfFilter" />

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvTorrentFilePicker"
Expand All @@ -86,7 +123,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvPickerTitle"
app:layout_constraintTop_toBottomOf="@id/tfFilter"
tools:listitem="@layout/item_list_torrent_selection_file" />
</androidx.constraintlayout.widget.ConstraintLayout>

Expand Down
1 change: 1 addition & 0 deletions app/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@
<string name="previous">Previous</string>
<string name="ready">Ready</string>
<string name="select_files">Select files</string>
<string name="filter_files_hint">Filter names, * supported</string>
<string name="total_files">Total files</string>
<string name="total_size">Total size</string>
<string name="loading_torrent_info">Loading torrent files. Use the download all button on the bottom if you want to download all the content.</string>
Expand Down
Loading