[PATCH] feat: add search to app list
Stepan Rabotkin
epicstyt at gmail.com
Wed Jun 15 16:07:05 UTC 2022
---
.../android/fragment/AppListDialogFragment.kt | 39 +++++++++++++------
.../res/layout/app_list_dialog_fragment.xml | 15 +++++++
ui/src/main/res/values/strings.xml | 1 +
3 files changed, 44 insertions(+), 11 deletions(-)
diff --git a/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt b/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt
index 1a40a1c..e9b4cf6 100644
--- a/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt
+++ b/ui/src/main/java/com/wireguard/android/fragment/AppListDialogFragment.kt
@@ -11,6 +11,7 @@ import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.os.bundleOf
+import androidx.core.widget.doAfterTextChanged
import androidx.databinding.Observable
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
@@ -28,7 +29,8 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class AppListDialogFragment : DialogFragment() {
- private val appData = ObservableKeyedArrayList<String, ApplicationData>()
+ private val appList: MutableList<ApplicationData> = ArrayList()
+ private val appListFiltered = ObservableKeyedArrayList<String, ApplicationData>()
private var currentlySelectedApps = emptyList<String>()
private var initiallyExcluded = false
private var button: Button? = null
@@ -39,14 +41,13 @@ class AppListDialogFragment : DialogFragment() {
val pm = activity.packageManager
lifecycleScope.launch(Dispatchers.Default) {
try {
- val applicationData: MutableList<ApplicationData> = ArrayList()
withContext(Dispatchers.IO) {
val packageInfos = pm.getPackagesHoldingPermissions(arrayOf(Manifest.permission.INTERNET), 0)
packageInfos.forEach {
val packageName = it.packageName
val appInfo = it.applicationInfo
val appData = ApplicationData(appInfo.loadIcon(pm), appInfo.loadLabel(pm).toString(), packageName, currentlySelectedApps.contains(packageName))
- applicationData.add(appData)
+ appList.add(appData)
appData.addOnPropertyChangedCallback(object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?, propertyId: Int) {
if (propertyId == BR.selected)
@@ -55,10 +56,10 @@ class AppListDialogFragment : DialogFragment() {
})
}
}
- applicationData.sortWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
+ appList.sortWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.name })
withContext(Dispatchers.Main.immediate) {
- appData.clear()
- appData.addAll(applicationData)
+ appListFiltered.clear()
+ appListFiltered.addAll(appList)
}
} catch (e: Throwable) {
withContext(Dispatchers.Main.immediate) {
@@ -78,7 +79,7 @@ class AppListDialogFragment : DialogFragment() {
}
private fun setButtonText() {
- val numSelected = appData.count { it.isSelected }
+ val numSelected = appList.count { it.isSelected }
button?.text = if (numSelected == 0)
getString(R.string.use_all_applications)
else when (tabs?.selectedTabPosition) {
@@ -106,15 +107,19 @@ class AppListDialogFragment : DialogFragment() {
alertDialogBuilder.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
alertDialogBuilder.setNeutralButton(R.string.toggle_all) { _, _ -> }
binding.fragment = this
- binding.appData = appData
+ binding.appData = appListFiltered
loadData()
+ binding.appSearchText.doAfterTextChanged {
+ appListFiltered.clear()
+ appListFiltered.addAll(filter(it.toString()))
+ }
val dialog = alertDialogBuilder.create()
dialog.setOnShowListener {
button = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
setButtonText()
dialog.getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener { _ ->
- val selectAll = appData.none { it.isSelected }
- appData.forEach {
+ val selectAll = appList.none { it.isSelected }
+ appList.forEach {
it.isSelected = selectAll
}
}
@@ -122,9 +127,21 @@ class AppListDialogFragment : DialogFragment() {
return dialog
}
+ private fun filter(s: String): MutableList<ApplicationData> {
+ val resultData: MutableList<ApplicationData> = ArrayList()
+
+ for (app in appList) {
+ if (app.name.lowercase().contains(s)) {
+ resultData.add(app)
+ }
+ }
+
+ return resultData
+ }
+
private fun setSelectionAndDismiss() {
val selectedApps: MutableList<String> = ArrayList()
- for (data in appData) {
+ for (data in appList) {
if (data.isSelected) {
selectedApps.add(data.packageName)
}
diff --git a/ui/src/main/res/layout/app_list_dialog_fragment.xml b/ui/src/main/res/layout/app_list_dialog_fragment.xml
index 4503de1..572996d 100644
--- a/ui/src/main/res/layout/app_list_dialog_fragment.xml
+++ b/ui/src/main/res/layout/app_list_dialog_fragment.xml
@@ -40,6 +40,21 @@
android:text="@string/include_in_tunnel" />
</com.google.android.material.tabs.TabLayout>
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/app_search_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dp">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/app_search_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/search"
+ android:imeOptions="actionDone" />
+
+ </com.google.android.material.textfield.TextInputLayout>
+
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/ui/src/main/res/values/strings.xml b/ui/src/main/res/values/strings.xml
index 6c09019..80967ad 100644
--- a/ui/src/main/res/values/strings.xml
+++ b/ui/src/main/res/values/strings.xml
@@ -237,4 +237,5 @@
<string name="biometric_prompt_private_key_title">Authenticate to view private key</string>
<string name="biometric_auth_error">Authentication failure</string>
<string name="biometric_auth_error_reason">Authentication failure: %s</string>
+ <string name="search">Search</string>
</resources>
--
2.32.0.windows.2
More information about the WireGuard
mailing list