From 3c3cac83c825efe6f285f640575f1359e9cf456b Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Fri, 18 Feb 2022 22:15:38 +0100 Subject: [PATCH] Add option to automatically launch the keyboard when opening the search Fixes #26 --- i18n/src/main/res/values-de/strings.xml | 2 ++ i18n/src/main/res/values/strings.xml | 3 ++ .../de/mm20/launcher2/preferences/Defaults.kt | 1 + .../preferences/migrations/Migration_1_2.kt | 1 + preferences/src/main/proto/settings.proto | 1 + .../ui/launcher/LauncherScaffoldVM.kt | 11 +++++++- .../ui/launcher/LauncherScaffoldView.kt | 15 ++++++++-- .../launcher2/ui/launcher/search/SearchBar.kt | 28 +++++++++++++++++-- .../ui/launcher/search/SearchBarVM.kt | 12 ++++++++ .../settings/search/SearchSettingsScreen.kt | 12 ++++++++ .../settings/search/SearchSettingsScreenVM.kt | 14 ++++++++++ 11 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBarVM.kt diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index d17f3d68..77295680 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -365,6 +365,8 @@ %1$ss Dateien auf Google Drive durchsuchen Stil Erscheinungsbild der Suchleiste anpassen + Tastatur öffnen + Bildschirmtastatur beim Öffnen der Suche automatisch einblenden Wikipedia-URL diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 4ce89e8a..90ad5c5e 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -410,6 +410,9 @@ Style Customize search bar appearance + Launch keyboard + Automatically show the keyboard when opening the search + Wikipedia URL %1$s is playing media diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt index b5dbe5c7..bd0aed80 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt @@ -104,6 +104,7 @@ fun createFactorySettings(context: Context): Settings { .setSearchBar( Settings.SearchBarSettings.newBuilder() .setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent) + .setAutoFocus(false) .build() ) .setIcons( diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_1_2.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_1_2.kt index 31deca72..ca93bb7a 100644 --- a/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_1_2.kt +++ b/preferences/src/main/java/de/mm20/launcher2/preferences/migrations/Migration_1_2.kt @@ -10,5 +10,6 @@ class Migration_1_2: VersionedMigration(1, 2) { .setHideNavBar(false) .setHideStatusBar(false) ) + .setSearchBar(builder.searchBar.toBuilder().setAutoFocus(false)) } } \ No newline at end of file diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto index 7867d430..36424879 100644 --- a/preferences/src/main/proto/settings.proto +++ b/preferences/src/main/proto/settings.proto @@ -130,6 +130,7 @@ message Settings { Hidden = 2; } SearchBarStyle search_bar_style = 1; + bool auto_focus = 2; } SearchBarSettings search_bar = 20; diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt index defb88e8..a6889aab 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldVM.kt @@ -2,10 +2,15 @@ package de.mm20.launcher2.ui.launcher import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData import de.mm20.launcher2.ktx.isBrightColor +import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.ui.launcher.search.SearchBarLevel +import kotlinx.coroutines.flow.map +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject -class LauncherScaffoldVM : ViewModel() { +class LauncherScaffoldVM : ViewModel(), KoinComponent { val isSearchOpen = MutableLiveData(false) val blurBackground = MutableLiveData(false) @@ -14,6 +19,10 @@ class LauncherScaffoldVM : ViewModel() { val searchBarLevel = MutableLiveData(SearchBarLevel.Resting) + val dataStore: LauncherDataStore by inject() + + val autoFocus = dataStore.data.map { it.searchBar.autoFocus }.asLiveData() + var scrollY = 0 set(value) { if (value == 0 && field != 0) { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldView.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldView.kt index 21f60f58..dbabdb36 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldView.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherScaffoldView.kt @@ -25,6 +25,7 @@ import de.mm20.launcher2.ktx.isAtLeastApiLevel import de.mm20.launcher2.transition.OneShotLayoutTransition import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.databinding.ViewLauncherScaffoldBinding +import de.mm20.launcher2.ui.launcher.search.SearchBarVM import de.mm20.launcher2.ui.launcher.search.SearchVM import de.mm20.launcher2.ui.launcher.widgets.WidgetsVM @@ -38,6 +39,9 @@ class LauncherScaffoldView @JvmOverloads constructor( private val viewModel: LauncherScaffoldVM by (context as AppCompatActivity).viewModels() private val widgetsViewModel: WidgetsVM by (context as AppCompatActivity).viewModels() private val searchViewModel: SearchVM by (context as AppCompatActivity).viewModels() + private val searchBarViewModel: SearchBarVM by (context as AppCompatActivity).viewModels() + + private var autoFocus = false private val scrollViewOnTouchListener = object : OnTouchListener { @SuppressLint("ClickableViewAccessibility") @@ -146,6 +150,10 @@ class LauncherScaffoldView @JvmOverloads constructor( ) } + viewModel.autoFocus.observe(context) { + autoFocus = it == true + } + widgetsViewModel.isEditMode.observe(context) { OneShotLayoutTransition.run(binding.scrollContainer) if (it) { @@ -190,8 +198,10 @@ class LauncherScaffoldView @JvmOverloads constructor( } } - binding.searchBar.onFocus = { - viewModel.openSearch() + searchBarViewModel.focused.observe(context) { + if (it) { + viewModel.openSearch() + } } viewModel.blurBackground.observe(context) { blur -> @@ -271,5 +281,6 @@ class LauncherScaffoldView @JvmOverloads constructor( ) ) set.start() + if (autoFocus) searchBarViewModel.setFocused(true) } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBar.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBar.kt index f745dad9..057fc91e 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBar.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBar.kt @@ -26,6 +26,8 @@ import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -54,12 +56,23 @@ fun SearchBar( ) { val searchViewModel: SearchVM = viewModel() val activityViewModel: LauncherActivityVM = viewModel() + val viewModel: SearchBarVM = viewModel() val dataStore: LauncherDataStore by inject() val style by remember { dataStore.data.map { it.searchBar.searchBarStyle } } .collectAsState(SearchBarSettings.SearchBarStyle.Hidden) + val focused by viewModel.focused.observeAsState(false) + + val focusManager = LocalFocusManager.current + val focusRequester = remember { FocusRequester() } + + LaunchedEffect(focused) { + if (focused) focusRequester.requestFocus() + else focusManager.clearFocus() + } + val context = LocalContext.current val query by searchViewModel.searchQuery.observeAsState("") @@ -119,7 +132,13 @@ fun SearchBar( ) } }, - onFocus = onFocus, + focusRequester = focusRequester, + onFocus = { + viewModel.setFocused(true) + }, + onUnfocus = { + viewModel.setFocused(false) + } ) } @@ -132,7 +151,9 @@ fun SearchBar( value: String, style: SearchBarSettings.SearchBarStyle, onValueChange: (String) -> Unit, - onFocus: () -> Unit = {} + onFocus: () -> Unit = {}, + onUnfocus: () -> Unit = {}, + focusRequester: FocusRequester = remember { FocusRequester() } ) { val context = LocalContext.current @@ -237,13 +258,14 @@ fun SearchBar( } val focusManager = LocalFocusManager.current LaunchedEffect(level) { - if (level == SearchBarLevel.Resting) focusManager.clearFocus() + if (level == SearchBarLevel.Resting) onUnfocus() } BasicTextField( modifier = Modifier .onFocusChanged { if (it.hasFocus) onFocus() } + .focusRequester(focusRequester) .fillMaxWidth(), textStyle = MaterialTheme.typography.bodyLarge.copy( color = contentColor diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBarVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBarVM.kt new file mode 100644 index 00000000..045b5420 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/SearchBarVM.kt @@ -0,0 +1,12 @@ +package de.mm20.launcher2.ui.launcher.search + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel + +class SearchBarVM: ViewModel() { + val focused = MutableLiveData(false) + + fun setFocused(focused :Boolean) { + this.focused.value = focused + } +} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt index 1e7142b6..ca1c3d7e 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreen.kt @@ -156,5 +156,17 @@ fun SearchSettingsScreen() { ) } } + item { + val autoFocus by viewModel.autoFocus.observeAsState() + PreferenceCategory { + SwitchPreference( + title = stringResource(R.string.preference_search_bar_auto_focus), + summary = stringResource(R.string.preference_search_bar_auto_focus_summary), + value = autoFocus == true, + onValueChanged = { + viewModel.setAutoFocus(it) + }) + } + } } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt index af8ecd18..62720633 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/search/SearchSettingsScreenVM.kt @@ -136,4 +136,18 @@ class SearchSettingsScreenVM : ViewModel(), KoinComponent { } } } + + val autoFocus = dataStore.data.map { it.searchBar.autoFocus }.asLiveData() + fun setAutoFocus(autoFocus: Boolean) { + viewModelScope.launch { + dataStore.updateData { + it.toBuilder() + .setSearchBar( + it.searchBar.toBuilder() + .setAutoFocus(autoFocus) + ) + .build() + } + } + } } \ No newline at end of file