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