From 656c1aaf5a8ddd16dfdc913335ce5259fde7a0f8 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 24 Apr 2026 12:06:25 -0300 Subject: [PATCH] Add setting to auto-show search keyboard --- .../org/fdroid/settings/SettingsConstants.kt | 3 ++ .../org/fdroid/settings/SettingsManager.kt | 11 +++++++ app/src/main/kotlin/org/fdroid/ui/Main.kt | 2 ++ .../org/fdroid/ui/search/GlobalSearch.kt | 33 ++++++++++++++++++- .../kotlin/org/fdroid/ui/search/SearchInfo.kt | 3 ++ .../org/fdroid/ui/search/SearchViewModel.kt | 13 ++++++-- .../org/fdroid/ui/utils/PreviewUtils.kt | 3 ++ app/src/main/res/values/strings.xml | 1 + .../GlobalSearchEmptyStateTest_2ed8e27d_0.png | 4 +-- .../GlobalSearchEmptyTest_2ed8e27d_0.png | 4 +-- 10 files changed, 70 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt b/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt index f6f1423e6..51e4a0ee0 100644 --- a/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt +++ b/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt @@ -58,6 +58,9 @@ object SettingsConstants { const val PREF_KEY_WARN_WHEN_METERED = "warnWhenMetered" const val PREF_DEFAULT_WARN_WHEN_METERED = true + const val PREF_KEY_SHOW_SEARCH_KEYBOARD = "showSearchKeyboard" + const val PREF_DEFAULT_SHOW_SEARCH_KEYBOARD = false + const val PREF_KEY_SHOW_INCOMPATIBLE = "incompatibleVersions" const val PREF_DEFAULT_SHOW_INCOMPATIBLE = true diff --git a/app/src/main/kotlin/org/fdroid/settings/SettingsManager.kt b/app/src/main/kotlin/org/fdroid/settings/SettingsManager.kt index 2c3ac978a..215eeb172 100644 --- a/app/src/main/kotlin/org/fdroid/settings/SettingsManager.kt +++ b/app/src/main/kotlin/org/fdroid/settings/SettingsManager.kt @@ -33,6 +33,7 @@ import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_PREVENT_SCREENSHOTS import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_PROXY import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_REPO_UPDATES import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_SHOW_INCOMPATIBLE +import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_SHOW_SEARCH_KEYBOARD import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_THEME import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_WARN_WHEN_METERED import org.fdroid.settings.SettingsConstants.PREF_DNS_CACHE @@ -50,6 +51,7 @@ import org.fdroid.settings.SettingsConstants.PREF_KEY_PREVENT_SCREENSHOTS import org.fdroid.settings.SettingsConstants.PREF_KEY_PROXY import org.fdroid.settings.SettingsConstants.PREF_KEY_REPO_UPDATES import org.fdroid.settings.SettingsConstants.PREF_KEY_SHOW_INCOMPATIBLE +import org.fdroid.settings.SettingsConstants.PREF_KEY_SHOW_SEARCH_KEYBOARD import org.fdroid.settings.SettingsConstants.PREF_KEY_THEME import org.fdroid.settings.SettingsConstants.PREF_KEY_WARN_WHEN_METERED import org.fdroid.settings.SettingsConstants.PREF_USE_DNS_CACHE @@ -194,6 +196,10 @@ class SettingsManager @Inject constructor(@param:ApplicationContext private val MutableStateFlow(prefs.getBoolean(PREF_KEY_WARN_WHEN_METERED, PREF_DEFAULT_WARN_WHEN_METERED)) val warnWhenMeteredFlow = _warnWhenMeteredFlow.asStateFlow() + private val _showSearchKeyboardFlow = + MutableStateFlow(prefs.getBoolean(PREF_KEY_SHOW_SEARCH_KEYBOARD, PREF_DEFAULT_SHOW_SEARCH_KEYBOARD)) + val showSearchKeyboardFlow = _showSearchKeyboardFlow.asStateFlow() + val filterIncompatible: Boolean get() = !prefs.getBoolean(PREF_KEY_SHOW_INCOMPATIBLE, PREF_DEFAULT_SHOW_INCOMPATIBLE) @@ -217,6 +223,11 @@ class SettingsManager @Inject constructor(@param:ApplicationContext private val _warnWhenMeteredFlow.update { false } } + fun setShowSearchKeyboard(show: Boolean) { + prefs.edit { putBoolean(PREF_KEY_SHOW_SEARCH_KEYBOARD, show) } + _showSearchKeyboardFlow.update { show } + } + fun saveAppListFilter(sortOrder: AppListSortOrder, filterIncompatible: Boolean) { prefs.edit { putBoolean(PREF_KEY_SHOW_INCOMPATIBLE, !filterIncompatible) diff --git a/app/src/main/kotlin/org/fdroid/ui/Main.kt b/app/src/main/kotlin/org/fdroid/ui/Main.kt index 6e8c7bf33..99b9bd33a 100644 --- a/app/src/main/kotlin/org/fdroid/ui/Main.kt +++ b/app/src/main/kotlin/org/fdroid/ui/Main.kt @@ -86,6 +86,8 @@ fun Main(onListeningForIntent: () -> Unit = {}) { viewModel.savedSearchesFlow.collectAsStateWithLifecycle().value override val categories: List? = viewModel.categories.collectAsStateWithLifecycle(null).value + override val autoShowKeyboard: Boolean = + viewModel.autoShowKeyboard.collectAsStateWithLifecycle().value override val showKeyboard: Boolean = showSearchKeyboard override val actions: SearchActions = viewModel diff --git a/app/src/main/kotlin/org/fdroid/ui/search/GlobalSearch.kt b/app/src/main/kotlin/org/fdroid/ui/search/GlobalSearch.kt index 71256c600..8a489e492 100644 --- a/app/src/main/kotlin/org/fdroid/ui/search/GlobalSearch.kt +++ b/app/src/main/kotlin/org/fdroid/ui/search/GlobalSearch.kt @@ -7,18 +7,27 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.text.input.TextFieldState import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Keyboard +import androidx.compose.material3.Checkbox +import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.SearchBarDefaults +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview +import org.fdroid.R import org.fdroid.search.SavedSearch import org.fdroid.ui.FDroidContent import org.fdroid.ui.navigation.NavigationKey +import org.fdroid.ui.utils.TopAppBarOverflowButton import org.fdroid.ui.utils.appListItems import org.fdroid.ui.utils.categoryItems import org.fdroid.ui.utils.getSearchInfo @@ -36,14 +45,36 @@ fun GlobalSearch( if (info.showKeyboard) info.onKeyboardShown() } val searchResults = info.searchResults + val showKeyboard = + info.showKeyboard || // either show keyboard because user double tapped the search icon + (info.autoShowKeyboard && // or auto-show is activated + (searchResults == null || // but only if no search results are shown + searchResults.apps.isEmpty() && searchResults.categories.isEmpty())) Scaffold( topBar = { TopSearchBar( searchFieldState = textFieldState, - shouldRequestFocus = info.showKeyboard, + shouldRequestFocus = showKeyboard, onSearch = info.actions::onSearch, onSearchCleared = info.actions::onSearchCleared, onHideSearch = onBack, + actions = { + if (textFieldState.text.isEmpty()) { + TopAppBarOverflowButton { onDismiss -> + DropdownMenuItem( + leadingIcon = { Icon(Icons.Default.Keyboard, null) }, + text = { Text(stringResource(R.string.search_auto_keyboard)) }, + trailingIcon = { + Checkbox(checked = info.autoShowKeyboard, onCheckedChange = null) + }, + onClick = { + info.actions.setAutoShowKeyboard(!info.autoShowKeyboard) + onDismiss() + }, + ) + } + } + }, ) } ) { paddingValues -> diff --git a/app/src/main/kotlin/org/fdroid/ui/search/SearchInfo.kt b/app/src/main/kotlin/org/fdroid/ui/search/SearchInfo.kt index 428dc3a23..6b501fa23 100644 --- a/app/src/main/kotlin/org/fdroid/ui/search/SearchInfo.kt +++ b/app/src/main/kotlin/org/fdroid/ui/search/SearchInfo.kt @@ -7,6 +7,7 @@ interface SearchInfo { val searchResults: SearchResults? val savedSearches: List? val categories: List? + val autoShowKeyboard: Boolean val showKeyboard: Boolean val actions: SearchActions fun onKeyboardShown() @@ -18,4 +19,6 @@ interface SearchActions { fun onSearchCleared() fun onClearSearchHistory() + + fun setAutoShowKeyboard(autoShow: Boolean) } diff --git a/app/src/main/kotlin/org/fdroid/ui/search/SearchViewModel.kt b/app/src/main/kotlin/org/fdroid/ui/search/SearchViewModel.kt index 25ba59b17..4c3c97423 100644 --- a/app/src/main/kotlin/org/fdroid/ui/search/SearchViewModel.kt +++ b/app/src/main/kotlin/org/fdroid/ui/search/SearchViewModel.kt @@ -8,16 +8,21 @@ import jakarta.inject.Inject import kotlinx.coroutines.launch import org.fdroid.search.SearchHelper.isSearchable import org.fdroid.search.SearchManager +import org.fdroid.settings.SettingsManager @HiltViewModel class SearchViewModel @Inject -constructor(app: Application, private val searchManager: SearchManager) : - AndroidViewModel(app), SearchActions { +constructor( + app: Application, + private val searchManager: SearchManager, + private val settingsManager: SettingsManager, +) : AndroidViewModel(app), SearchActions { val searchResults = searchManager.searchResults val savedSearchesFlow = searchManager.savedSearches val categories = searchManager.categories + val autoShowKeyboard = settingsManager.showSearchKeyboardFlow override suspend fun onSearch(term: String) { if (term.isSearchable()) searchManager.search(term) @@ -28,4 +33,8 @@ constructor(app: Application, private val searchManager: SearchManager) : override fun onClearSearchHistory() { viewModelScope.launch { searchManager.onClearSearchHistory() } } + + override fun setAutoShowKeyboard(autoShow: Boolean) { + settingsManager.setShowSearchKeyboard(autoShow) + } } diff --git a/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt b/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt index 9a9db89fc..21b55121f 100644 --- a/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt +++ b/app/src/main/kotlin/org/fdroid/ui/utils/PreviewUtils.kt @@ -650,6 +650,7 @@ fun getSearchInfo( override val savedSearches: List? = savedSearches override val categories: List? = categories + override val autoShowKeyboard: Boolean = false override val showKeyboard: Boolean = false override val actions: SearchActions = @@ -659,6 +660,8 @@ fun getSearchInfo( override fun onSearchCleared() {} override fun onClearSearchHistory() {} + + override fun setAutoShowKeyboard(autoShow: Boolean) {} } override fun onKeyboardShown() {} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a0132f570..aec885105 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -38,6 +38,7 @@ No apps found\n\nTry using fewer search terms or add more repositories No matching apps\n\nTry using fewer search terms or remove filters No matching apps\n\nTry using fewer search terms + Automatically open keyboard Sorting and compatibility Sort by name Sort by last update diff --git a/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyStateTest_2ed8e27d_0.png b/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyStateTest_2ed8e27d_0.png index 0d65142d8..3c1e33fd3 100644 --- a/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyStateTest_2ed8e27d_0.png +++ b/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyStateTest_2ed8e27d_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e926d11d01b2d8786e9af5077f60d47b51d23605e016559c94b998c85edd44f0 -size 119038 +oid sha256:9d61085047b8397d4f99513c930fac8bf4b5e6fcdd6f38a5c6aa177eb8a294be +size 119701 diff --git a/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyTest_2ed8e27d_0.png b/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyTest_2ed8e27d_0.png index 90a354891..262aeb078 100644 --- a/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyTest_2ed8e27d_0.png +++ b/app/src/screenshotTestBasicDefaultDebug/reference/org/fdroid/ui/search/GlobalSearchTestKt/GlobalSearchEmptyTest_2ed8e27d_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b84731273d6b914154b20cd44c6a0ef56b6d5fd0815d0585e6d39da75b75760b -size 31966 +oid sha256:119b1d10a0e9926c96197938152d5ef6e2e15c71017064e48af612a794e82082 +size 32593