Add option to automatically launch the keyboard when opening the search
Fixes #26
This commit is contained in:
parent
0d6d7f1764
commit
3c3cac83c8
@ -365,6 +365,8 @@
|
|||||||
<string name="preference_search_gdrive_summary">%1$ss Dateien auf Google Drive durchsuchen</string>
|
<string name="preference_search_gdrive_summary">%1$ss Dateien auf Google Drive durchsuchen</string>
|
||||||
<string name="preference_search_bar_style">Stil</string>
|
<string name="preference_search_bar_style">Stil</string>
|
||||||
<string name="preference_search_bar_style_summary">Erscheinungsbild der Suchleiste anpassen</string>
|
<string name="preference_search_bar_style_summary">Erscheinungsbild der Suchleiste anpassen</string>
|
||||||
|
<string name="preference_search_bar_auto_focus">Tastatur öffnen</string>
|
||||||
|
<string name="preference_search_bar_auto_focus_summary">Bildschirmtastatur beim Öffnen der Suche automatisch einblenden</string>
|
||||||
|
|
||||||
<string name="preference_wikipedia_customurl">Wikipedia-URL</string>
|
<string name="preference_wikipedia_customurl">Wikipedia-URL</string>
|
||||||
|
|
||||||
|
|||||||
@ -410,6 +410,9 @@
|
|||||||
<string name="preference_search_bar_style">Style</string>
|
<string name="preference_search_bar_style">Style</string>
|
||||||
<string name="preference_search_bar_style_summary">Customize search bar appearance</string>
|
<string name="preference_search_bar_style_summary">Customize search bar appearance</string>
|
||||||
|
|
||||||
|
<string name="preference_search_bar_auto_focus">Launch keyboard</string>
|
||||||
|
<string name="preference_search_bar_auto_focus_summary">Automatically show the keyboard when opening the search</string>
|
||||||
|
|
||||||
<string name="preference_wikipedia_customurl">Wikipedia URL</string>
|
<string name="preference_wikipedia_customurl">Wikipedia URL</string>
|
||||||
|
|
||||||
<string name="music_widget_default_title">%1$s is playing media</string>
|
<string name="music_widget_default_title">%1$s is playing media</string>
|
||||||
|
|||||||
@ -104,6 +104,7 @@ fun createFactorySettings(context: Context): Settings {
|
|||||||
.setSearchBar(
|
.setSearchBar(
|
||||||
Settings.SearchBarSettings.newBuilder()
|
Settings.SearchBarSettings.newBuilder()
|
||||||
.setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
.setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent)
|
||||||
|
.setAutoFocus(false)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setIcons(
|
.setIcons(
|
||||||
|
|||||||
@ -10,5 +10,6 @@ class Migration_1_2: VersionedMigration(1, 2) {
|
|||||||
.setHideNavBar(false)
|
.setHideNavBar(false)
|
||||||
.setHideStatusBar(false)
|
.setHideStatusBar(false)
|
||||||
)
|
)
|
||||||
|
.setSearchBar(builder.searchBar.toBuilder().setAutoFocus(false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,6 +130,7 @@ message Settings {
|
|||||||
Hidden = 2;
|
Hidden = 2;
|
||||||
}
|
}
|
||||||
SearchBarStyle search_bar_style = 1;
|
SearchBarStyle search_bar_style = 1;
|
||||||
|
bool auto_focus = 2;
|
||||||
}
|
}
|
||||||
SearchBarSettings search_bar = 20;
|
SearchBarSettings search_bar = 20;
|
||||||
|
|
||||||
|
|||||||
@ -2,10 +2,15 @@ package de.mm20.launcher2.ui.launcher
|
|||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.asLiveData
|
||||||
import de.mm20.launcher2.ktx.isBrightColor
|
import de.mm20.launcher2.ktx.isBrightColor
|
||||||
|
import de.mm20.launcher2.preferences.LauncherDataStore
|
||||||
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
|
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 isSearchOpen = MutableLiveData(false)
|
||||||
val blurBackground = MutableLiveData(false)
|
val blurBackground = MutableLiveData(false)
|
||||||
|
|
||||||
@ -14,6 +19,10 @@ class LauncherScaffoldVM : ViewModel() {
|
|||||||
|
|
||||||
val searchBarLevel = MutableLiveData(SearchBarLevel.Resting)
|
val searchBarLevel = MutableLiveData(SearchBarLevel.Resting)
|
||||||
|
|
||||||
|
val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
|
val autoFocus = dataStore.data.map { it.searchBar.autoFocus }.asLiveData()
|
||||||
|
|
||||||
var scrollY = 0
|
var scrollY = 0
|
||||||
set(value) {
|
set(value) {
|
||||||
if (value == 0 && field != 0) {
|
if (value == 0 && field != 0) {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import de.mm20.launcher2.ktx.isAtLeastApiLevel
|
|||||||
import de.mm20.launcher2.transition.OneShotLayoutTransition
|
import de.mm20.launcher2.transition.OneShotLayoutTransition
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.databinding.ViewLauncherScaffoldBinding
|
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.search.SearchVM
|
||||||
import de.mm20.launcher2.ui.launcher.widgets.WidgetsVM
|
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 viewModel: LauncherScaffoldVM by (context as AppCompatActivity).viewModels()
|
||||||
private val widgetsViewModel: WidgetsVM 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 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 {
|
private val scrollViewOnTouchListener = object : OnTouchListener {
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
@ -146,6 +150,10 @@ class LauncherScaffoldView @JvmOverloads constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viewModel.autoFocus.observe(context) {
|
||||||
|
autoFocus = it == true
|
||||||
|
}
|
||||||
|
|
||||||
widgetsViewModel.isEditMode.observe(context) {
|
widgetsViewModel.isEditMode.observe(context) {
|
||||||
OneShotLayoutTransition.run(binding.scrollContainer)
|
OneShotLayoutTransition.run(binding.scrollContainer)
|
||||||
if (it) {
|
if (it) {
|
||||||
@ -190,8 +198,10 @@ class LauncherScaffoldView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.searchBar.onFocus = {
|
searchBarViewModel.focused.observe(context) {
|
||||||
viewModel.openSearch()
|
if (it) {
|
||||||
|
viewModel.openSearch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.blurBackground.observe(context) { blur ->
|
viewModel.blurBackground.observe(context) { blur ->
|
||||||
@ -271,5 +281,6 @@ class LauncherScaffoldView @JvmOverloads constructor(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
set.start()
|
set.start()
|
||||||
|
if (autoFocus) searchBarViewModel.setFocused(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,6 +26,8 @@ import androidx.compose.runtime.livedata.observeAsState
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
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.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@ -54,12 +56,23 @@ fun SearchBar(
|
|||||||
) {
|
) {
|
||||||
val searchViewModel: SearchVM = viewModel()
|
val searchViewModel: SearchVM = viewModel()
|
||||||
val activityViewModel: LauncherActivityVM = viewModel()
|
val activityViewModel: LauncherActivityVM = viewModel()
|
||||||
|
val viewModel: SearchBarVM = viewModel()
|
||||||
|
|
||||||
val dataStore: LauncherDataStore by inject()
|
val dataStore: LauncherDataStore by inject()
|
||||||
|
|
||||||
val style by remember { dataStore.data.map { it.searchBar.searchBarStyle } }
|
val style by remember { dataStore.data.map { it.searchBar.searchBarStyle } }
|
||||||
.collectAsState(SearchBarSettings.SearchBarStyle.Hidden)
|
.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 context = LocalContext.current
|
||||||
|
|
||||||
val query by searchViewModel.searchQuery.observeAsState("")
|
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,
|
value: String,
|
||||||
style: SearchBarSettings.SearchBarStyle,
|
style: SearchBarSettings.SearchBarStyle,
|
||||||
onValueChange: (String) -> Unit,
|
onValueChange: (String) -> Unit,
|
||||||
onFocus: () -> Unit = {}
|
onFocus: () -> Unit = {},
|
||||||
|
onUnfocus: () -> Unit = {},
|
||||||
|
focusRequester: FocusRequester = remember { FocusRequester() }
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
@ -237,13 +258,14 @@ fun SearchBar(
|
|||||||
}
|
}
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
LaunchedEffect(level) {
|
LaunchedEffect(level) {
|
||||||
if (level == SearchBarLevel.Resting) focusManager.clearFocus()
|
if (level == SearchBarLevel.Resting) onUnfocus()
|
||||||
}
|
}
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.onFocusChanged {
|
.onFocusChanged {
|
||||||
if (it.hasFocus) onFocus()
|
if (it.hasFocus) onFocus()
|
||||||
}
|
}
|
||||||
|
.focusRequester(focusRequester)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
textStyle = MaterialTheme.typography.bodyLarge.copy(
|
textStyle = MaterialTheme.typography.bodyLarge.copy(
|
||||||
color = contentColor
|
color = contentColor
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user