diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml
index d059f51d..b583ade8 100644
--- a/i18n/src/main/res/values-de/strings.xml
+++ b/i18n/src/main/res/values-de/strings.xml
@@ -459,6 +459,8 @@
Google Drive
Sie sind im Moment nicht angemeldet
%1$ss Dateien auf Google Drive durchsuchen
+ Stil
+ Erscheinungsbild der Suchleiste anpassen
Wikipedia-URL
diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml
index 2aedad7a..1efe0556 100644
--- a/i18n/src/main/res/values/strings.xml
+++ b/i18n/src/main/res/values/strings.xml
@@ -502,6 +502,9 @@
Restrict to music apps
Ignore media sessions of apps that are not music apps
+ Style
+ Customize search bar appearance
+
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 be3e5834..d0e3060f 100644
--- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt
+++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt
@@ -101,5 +101,10 @@ fun createFactorySettings(context: Context): Settings {
.setColumnCount(context.resources.getInteger(R.integer.config_columnCount))
.build()
)
+ .setSearchBar(
+ Settings.SearchBarSettings.newBuilder()
+ .setSearchBarStyle(Settings.SearchBarSettings.SearchBarStyle.Transparent)
+ .build()
+ )
.build()
}
\ No newline at end of file
diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto
index a0f904c2..4f17cd3a 100644
--- a/preferences/src/main/proto/settings.proto
+++ b/preferences/src/main/proto/settings.proto
@@ -123,4 +123,14 @@ message Settings {
}
GridSettings grid = 19;
+ message SearchBarSettings {
+ enum SearchBarStyle {
+ Transparent = 0;
+ Solid = 1;
+ Hidden = 2;
+ }
+ SearchBarStyle search_bar_style = 1;
+ }
+ SearchBarSettings search_bar = 20;
+
}
\ 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 90e6885a..89c29369 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
@@ -30,6 +30,7 @@ import androidx.compose.runtime.*
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.onFocusChanged
import androidx.compose.ui.focus.onFocusEvent
@@ -41,11 +42,16 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.rememberImagePainter
import de.mm20.launcher2.ktx.tryStartActivity
+import de.mm20.launcher2.preferences.LauncherDataStore
+import de.mm20.launcher2.preferences.Settings
+import de.mm20.launcher2.preferences.Settings.SearchBarSettings
import de.mm20.launcher2.search.data.Websearch
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.LauncherCard
import de.mm20.launcher2.ui.launcher.LauncherActivityVM
import de.mm20.launcher2.ui.settings.SettingsActivity
+import kotlinx.coroutines.flow.map
+import org.koin.androidx.compose.inject
import java.io.File
@Composable
@@ -56,6 +62,11 @@ fun SearchBar(
val searchViewModel: SearchVM = viewModel()
val activityViewModel: LauncherActivityVM = viewModel()
+ val dataStore: LauncherDataStore by inject()
+
+ val style by remember { dataStore.data.map { it.searchBar.searchBarStyle } }
+ .collectAsState(SearchBarSettings.SearchBarStyle.Hidden)
+
val context = LocalContext.current
val query by searchViewModel.searchQuery.observeAsState("")
@@ -69,6 +80,7 @@ fun SearchBar(
onValueChange = {
searchViewModel.search(it)
},
+ style = style,
overflowMenu = { show, onDismissRequest ->
DropdownMenu(expanded = show, onDismissRequest = onDismissRequest) {
DropdownMenuItem(onClick = {
@@ -125,6 +137,7 @@ fun SearchBar(
websearches: List,
overflowMenu: @Composable (show: Boolean, onDismissRequest: () -> Unit) -> Unit = { _, _ -> },
value: String,
+ style: SearchBarSettings.SearchBarStyle,
onValueChange: (String) -> Unit,
onFocus: () -> Unit = {}
) {
@@ -148,10 +161,10 @@ fun SearchBar(
}
}
) {
- when (it) {
- SearchBarLevel.Resting -> 0.dp
- SearchBarLevel.Active -> 2.dp
- SearchBarLevel.Raised -> 8.dp
+ when {
+ it == SearchBarLevel.Resting && style != SearchBarSettings.SearchBarStyle.Solid -> 0.dp
+ it == SearchBarLevel.Raised -> 8.dp
+ else -> 2.dp
}
}
@@ -166,7 +179,11 @@ fun SearchBar(
else -> tween(durationMillis = 500)
}
}) {
- if (it == SearchBarLevel.Resting) 0f else 1f
+ when {
+ style != SearchBarSettings.SearchBarStyle.Transparent -> 1f
+ it == SearchBarLevel.Resting -> 0f
+ else -> 1f
+ }
}
val contentColor by transition.animateColor(label = "textColor",
@@ -180,7 +197,16 @@ fun SearchBar(
else -> tween(durationMillis = 500)
}
}) {
- if (it == SearchBarLevel.Resting) Color.White else LocalContentColor.current
+ when {
+ style != SearchBarSettings.SearchBarStyle.Transparent -> LocalContentColor.current
+ it == SearchBarLevel.Resting -> Color.White
+ else -> LocalContentColor.current
+ }
+ }
+
+ val opacity by transition.animateFloat(label = "opacity") {
+ if (style == SearchBarSettings.SearchBarStyle.Hidden && it == SearchBarLevel.Resting) 0f
+ else 1f
}
val rightIcon = AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_menu_clear)
@@ -189,6 +215,7 @@ fun SearchBar(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
+ .alpha(opacity)
.padding(8.dp),
backgroundOpacity = backgroundOpacity,
elevation = elevation
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt
index e28ee44e..5820fc8d 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt
@@ -1,15 +1,33 @@
package de.mm20.launcher2.ui.settings.appearance
import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.AlertDialog
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.google.accompanist.pager.ExperimentalPagerApi
+import com.google.accompanist.pager.HorizontalPager
+import com.google.accompanist.pager.HorizontalPagerIndicator
+import com.google.accompanist.pager.rememberPagerState
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
+import de.mm20.launcher2.preferences.Settings.SearchBarSettings
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.*
+import de.mm20.launcher2.ui.launcher.search.SearchBar
+import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.isActive
@Composable
fun AppearanceSettingsScreen() {
@@ -78,6 +96,96 @@ fun AppearanceSettingsScreen() {
}
)
}
+ PreferenceCategory(stringResource(R.string.preference_category_searchbar)) {
+ val searchBarStyle by viewModel.searchBarStyle.observeAsState()
+ SearchBarStylePreference(
+ title = stringResource(R.string.preference_search_bar_style),
+ summary = stringResource(R.string.preference_search_bar_style_summary),
+ value = searchBarStyle,
+ onValueChanged = {
+ viewModel.setSearchBarStyle(it)
+ }
+ )
+ }
}
}
+}
+
+@OptIn(ExperimentalPagerApi::class)
+@Composable
+fun SearchBarStylePreference(
+ title: String,
+ summary: String? = null,
+ value: SearchBarSettings.SearchBarStyle?,
+ onValueChanged: (SearchBarSettings.SearchBarStyle) -> Unit
+) {
+ var showDialog by remember { mutableStateOf(false) }
+ Preference(title = title, summary = summary, onClick = { showDialog = true })
+ if (showDialog && value != null) {
+ val styles = remember {
+ SearchBarSettings.SearchBarStyle.values().filter { it != SearchBarSettings.SearchBarStyle.UNRECOGNIZED }
+ }
+ val pagerState = rememberPagerState(styles.indexOf(value))
+
+ var level by remember { mutableStateOf(SearchBarLevel.Resting) }
+ var previewSearchValue by remember { mutableStateOf("") }
+ LaunchedEffect(null) {
+ while(isActive) {
+ delay(2000)
+ level = SearchBarLevel.Active
+ delay(1000)
+ previewSearchValue = "A"
+ delay(100)
+ previewSearchValue = "AB"
+ delay(100)
+ previewSearchValue = "ABC"
+ delay(800)
+ level = SearchBarLevel.Raised
+ delay(2000)
+ level = SearchBarLevel.Resting
+ previewSearchValue = ""
+ }
+ }
+
+ AlertDialog(
+ onDismissRequest = { showDialog = false },
+ confirmButton = {
+ TextButton(onClick = {
+ showDialog = false
+ onValueChanged(styles[pagerState.currentPage])
+ }) {
+ Text(
+ text = stringResource(android.R.string.ok),
+ style = MaterialTheme.typography.labelLarge
+ )
+ }
+ },
+ dismissButton = {
+ TextButton(onClick = { showDialog = false }) {
+ Text(
+ text = stringResource(android.R.string.cancel),
+ style = MaterialTheme.typography.labelLarge
+ )
+ }
+ },
+
+ text = {
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ HorizontalPager(
+ count = styles.size,
+ state = pagerState,
+ modifier = Modifier
+ .height(150.dp)
+ .padding(bottom = 16.dp)
+ .background(MaterialTheme.colorScheme.secondary)
+ ) {
+ SearchBar(level = level, style = styles[it], websearches = emptyList(), value = previewSearchValue, onValueChange = {})
+ }
+ HorizontalPagerIndicator(pagerState = pagerState)
+ }
+ }
+ )
+ }
}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt
index 0fa2fc37..03f3dfdb 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt
@@ -8,6 +8,7 @@ import androidx.lifecycle.viewModelScope
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
+import de.mm20.launcher2.preferences.Settings.SearchBarSettings
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
@@ -63,4 +64,17 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
fun openWallpaperChooser(context: AppCompatActivity) {
context.startActivity(Intent.createChooser(Intent(Intent.ACTION_SET_WALLPAPER), null))
}
+
+ val searchBarStyle = dataStore.data.map { it.searchBar.searchBarStyle }.asLiveData()
+ fun setSearchBarStyle(searchBarStyle: SearchBarSettings.SearchBarStyle) {
+ viewModelScope.launch {
+ dataStore.updateData {
+ it.toBuilder()
+ .setSearchBar(it.searchBar.toBuilder()
+ .setSearchBarStyle(searchBarStyle)
+ )
+ .build()
+ }
+ }
+ }
}
\ No newline at end of file