Add option to automatically launch the keyboard when opening the search

Fixes #26
This commit is contained in:
MM20 2022-02-18 22:15:38 +01:00
parent 0d6d7f1764
commit 3c3cac83c8
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
11 changed files with 94 additions and 6 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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(

View File

@ -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))
} }
} }

View File

@ -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;

View File

@ -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) {

View File

@ -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)
} }
} }

View File

@ -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

View File

@ -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
}
}

View File

@ -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)
})
}
}
} }
} }

View File

@ -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()
}
}
}
} }