Skip to content

Commit b947f15

Browse files
committed
Add search & filter enhancements for Apps and Activity Launcher
1 parent fa34777 commit b947f15

File tree

4 files changed

+91
-11
lines changed

4 files changed

+91
-11
lines changed

app/src/main/java/com/appcontrolx/ui/ActivityLauncherBottomSheet.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.os.Bundle
99
import android.view.LayoutInflater
1010
import android.view.View
1111
import android.view.ViewGroup
12+
import android.util.Log
1213
import android.widget.Toast
1314
import androidx.lifecycle.lifecycleScope
1415
import androidx.recyclerview.widget.LinearLayoutManager
@@ -19,7 +20,6 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
1920
import kotlinx.coroutines.Dispatchers
2021
import kotlinx.coroutines.launch
2122
import kotlinx.coroutines.withContext
22-
import timber.log.Timber
2323

2424
class ActivityLauncherBottomSheet : BottomSheetDialogFragment() {
2525

@@ -156,7 +156,7 @@ class ActivityLauncherBottomSheet : BottomSheetDialogFragment() {
156156
}
157157

158158
b.progressBar.visibility = View.GONE
159-
Timber.d("Loaded ${allAppGroups.size} apps with activities")
159+
Log.d(TAG, "Loaded ${allAppGroups.size} apps with activities")
160160
filterActivities()
161161
}
162162
}
@@ -203,9 +203,9 @@ class ActivityLauncherBottomSheet : BottomSheetDialogFragment() {
203203
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
204204
}
205205
startActivity(intent)
206-
Timber.d("Launched activity: ${activity.activityName}")
206+
Log.d(TAG, "Launched activity: ${activity.activityName}")
207207
} catch (e: Exception) {
208-
Timber.e(e, "Failed to launch activity: ${activity.activityName}")
208+
Log.e(TAG, "Failed to launch activity: ${activity.activityName}", e)
209209
Toast.makeText(context, R.string.tools_activity_launch_failed, Toast.LENGTH_SHORT).show()
210210
}
211211
}

app/src/main/java/com/appcontrolx/ui/AppListFragment.kt

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@ import android.content.Context
55
import android.content.Intent
66
import android.content.IntentFilter
77
import android.os.Bundle
8+
import android.text.Editable
9+
import android.text.TextWatcher
810
import android.view.LayoutInflater
911
import android.view.View
1012
import android.view.ViewGroup
13+
import android.view.inputmethod.EditorInfo
1114
import android.widget.Toast
1215
import androidx.fragment.app.Fragment
1316
import androidx.lifecycle.lifecycleScope
@@ -45,6 +48,7 @@ class AppListFragment : Fragment() {
4548

4649
private var showSystemApps = false
4750
private var executionMode: ExecutionMode = ExecutionMode.None
51+
private var currentSearchQuery: String = ""
4852

4953
// App cache - persists until package change detected
5054
private var cachedUserApps: List<AppInfo>? = null
@@ -83,13 +87,51 @@ class AppListFragment : Fragment() {
8387
setupHeader()
8488
setupRecyclerView()
8589
setupSwipeRefresh()
90+
setupSearch()
8691
setupChips()
8792
setupSelectionBar()
8893
setupSelectAll()
8994
registerPackageReceiver()
9095
loadApps()
9196
}
9297

98+
private fun setupSearch() {
99+
val b = binding ?: return
100+
101+
b.etSearch.addTextChangedListener(object : TextWatcher {
102+
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
103+
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
104+
override fun afterTextChanged(s: Editable?) {
105+
currentSearchQuery = s?.toString()?.trim() ?: ""
106+
filterApps()
107+
}
108+
})
109+
110+
b.etSearch.setOnEditorActionListener { _, actionId, _ ->
111+
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
112+
filterApps()
113+
true
114+
} else false
115+
}
116+
}
117+
118+
private fun filterApps() {
119+
val cachedApps = if (showSystemApps) cachedSystemApps else cachedUserApps
120+
if (cachedApps == null) return
121+
122+
val filtered = if (currentSearchQuery.isBlank()) {
123+
cachedApps
124+
} else {
125+
val query = currentSearchQuery.lowercase()
126+
cachedApps.filter { app ->
127+
app.appName.lowercase().contains(query) ||
128+
app.packageName.lowercase().contains(query)
129+
}
130+
}
131+
132+
displayApps(filtered)
133+
}
134+
93135
private fun setupExecutionMode() {
94136
executionMode = PermissionBridge(requireContext()).detectMode()
95137

@@ -412,7 +454,7 @@ class AppListFragment : Fragment() {
412454
// Check cache first - only refresh on package change or manual refresh
413455
val cachedApps = if (showSystemApps) cachedSystemApps else cachedUserApps
414456
if (!forceRefresh && cachedApps != null) {
415-
displayApps(cachedApps)
457+
filterApps() // Apply current search filter
416458
b.swipeRefresh.isRefreshing = false
417459
return
418460
}
@@ -437,7 +479,7 @@ class AppListFragment : Fragment() {
437479
cachedUserApps = apps
438480
}
439481

440-
displayApps(apps)
482+
filterApps() // Apply current search filter
441483

442484
} catch (e: TimeoutCancellationException) {
443485
showEmptyState(
@@ -462,11 +504,21 @@ class AppListFragment : Fragment() {
462504
val b = binding ?: return
463505

464506
if (apps.isEmpty()) {
465-
showEmptyState(
466-
getString(R.string.empty_no_apps_title),
467-
getString(R.string.empty_no_apps_message)
468-
)
507+
if (currentSearchQuery.isNotBlank()) {
508+
// No search results
509+
showEmptyState(
510+
getString(R.string.search_no_results),
511+
"\"$currentSearchQuery\""
512+
)
513+
} else {
514+
showEmptyState(
515+
getString(R.string.empty_no_apps_title),
516+
getString(R.string.empty_no_apps_message)
517+
)
518+
}
469519
} else {
520+
b.emptyState.visibility = View.GONE
521+
b.recyclerView.visibility = View.VISIBLE
470522
adapter.submitList(apps)
471523
b.tvAppCount.text = getString(R.string.app_count, apps.size)
472524
}

app/src/main/res/layout/fragment_app_list.xml

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,40 @@
9494
style="@style/Widget.Material3.Button.TonalButton" />
9595
</LinearLayout>
9696

97+
<!-- Search Bar -->
98+
<com.google.android.material.textfield.TextInputLayout
99+
android:id="@+id/searchLayout"
100+
android:layout_width="match_parent"
101+
android:layout_height="wrap_content"
102+
android:layout_marginHorizontal="16dp"
103+
android:layout_marginTop="8dp"
104+
android:hint="@string/search_apps_hint"
105+
app:boxBackgroundMode="outline"
106+
app:boxCornerRadiusTopStart="24dp"
107+
app:boxCornerRadiusTopEnd="24dp"
108+
app:boxCornerRadiusBottomStart="24dp"
109+
app:boxCornerRadiusBottomEnd="24dp"
110+
app:startIconDrawable="@android:drawable/ic_menu_search"
111+
app:endIconMode="clear_text"
112+
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
113+
114+
<com.google.android.material.textfield.TextInputEditText
115+
android:id="@+id/etSearch"
116+
android:layout_width="match_parent"
117+
android:layout_height="wrap_content"
118+
android:inputType="text"
119+
android:imeOptions="actionSearch"
120+
android:maxLines="1" />
121+
</com.google.android.material.textfield.TextInputLayout>
122+
97123
<!-- Filter Section -->
98124
<LinearLayout
99125
android:layout_width="match_parent"
100126
android:layout_height="wrap_content"
101127
android:orientation="horizontal"
102128
android:gravity="center_vertical"
103129
android:paddingHorizontal="20dp"
104-
android:paddingVertical="12dp"
130+
android:paddingVertical="8dp"
105131
android:background="?attr/colorSurface">
106132

107133
<com.google.android.material.chip.ChipGroup

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@
267267
<string name="activity_launcher_subtitle">Tap app to expand, tap activity to launch</string>
268268
<string name="activity_launcher_count">%1$d apps • %2$d activities</string>
269269
<string name="search_hint">Search apps or activities…</string>
270+
<string name="search_apps_hint">Search apps…</string>
271+
<string name="search_no_results">No apps found</string>
270272
<string name="btn_expand">Expand</string>
271273

272274
<!-- Accessibility -->

0 commit comments

Comments
 (0)