) = pref.get()
.distinctUntilChanged()
.map { it.createHandler(launcher) }
.shareIn(
diff --git a/lawnchair/src/app/lawnchair/icons/shape/IconShapeManager.kt b/lawnchair/src/app/lawnchair/icons/shape/IconShapeManager.kt
index d35b331913..a95df2d3df 100644
--- a/lawnchair/src/app/lawnchair/icons/shape/IconShapeManager.kt
+++ b/lawnchair/src/app/lawnchair/icons/shape/IconShapeManager.kt
@@ -28,7 +28,7 @@ import com.android.launcher3.Utilities
import com.android.launcher3.icons.GraphicsUtils
import com.android.launcher3.icons.IconProvider
import com.android.launcher3.util.MainThreadInitializedObject
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.firstBlocking
class IconShapeManager(private val context: Context) {
diff --git a/lawnchair/src/app/lawnchair/nexuslauncher/OverlayCallbackImpl.java b/lawnchair/src/app/lawnchair/nexuslauncher/OverlayCallbackImpl.java
index 9dcc1ff1d1..dc5708c132 100644
--- a/lawnchair/src/app/lawnchair/nexuslauncher/OverlayCallbackImpl.java
+++ b/lawnchair/src/app/lawnchair/nexuslauncher/OverlayCallbackImpl.java
@@ -15,7 +15,7 @@ import com.google.android.libraries.launcherclient.ISerializableScrollCallback;
import com.google.android.libraries.launcherclient.LauncherClient;
import com.google.android.libraries.launcherclient.LauncherClientCallbacks;
import com.google.android.libraries.launcherclient.StaticInteger;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import app.lawnchair.FeedBridge;
import app.lawnchair.LawnchairLauncher;
diff --git a/lawnchair/src/app/lawnchair/preferences/PreferenceAdapter.kt b/lawnchair/src/app/lawnchair/preferences/PreferenceAdapter.kt
index 4541d0cffb..73ae36a5f4 100644
--- a/lawnchair/src/app/lawnchair/preferences/PreferenceAdapter.kt
+++ b/lawnchair/src/app/lawnchair/preferences/PreferenceAdapter.kt
@@ -22,7 +22,7 @@ import app.lawnchair.preferences2.IdpPreference
import app.lawnchair.preferences2.asState
import app.lawnchair.preferences2.firstBlocking
import com.android.launcher3.InvariantDeviceProfile
-import com.patrykmichalik.preferencemanager.Preference
+import com.patrykmichalik.opto.domain.Preference
import kotlinx.coroutines.launch
import kotlin.reflect.KProperty
@@ -109,7 +109,7 @@ private fun getAdapter(
}
@Composable
-fun Preference.getAdapter(): PreferenceAdapter {
+fun Preference.getAdapter(): PreferenceAdapter {
return createStateAdapter(state = asState(), set = this::set)
}
diff --git a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
index 392fc9051e..a78a8e785e 100644
--- a/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
+++ b/lawnchair/src/app/lawnchair/preferences2/PreferenceManager2.kt
@@ -35,8 +35,8 @@ import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.util.DynamicResource
import com.android.launcher3.util.MainThreadInitializedObject
-import com.patrykmichalik.preferencemanager.PreferenceManager
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.PreferenceManager
+import com.patrykmichalik.opto.core.firstBlocking
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.drop
@@ -347,12 +347,12 @@ class PreferenceManager2(private val context: Context) : PreferenceManager {
private inline fun serializablePreference(
key: Preferences.Key,
- defaultValue: T
+ defaultValue: T,
) = preference(
key = key,
defaultValue = defaultValue,
- parse = { Json.decodeFromString(it) },
- save = { Json.encodeToString(it) }
+ parse = Json::decodeFromString,
+ save = Json::encodeToString,
)
init {
diff --git a/lawnchair/src/app/lawnchair/preferences2/PreferenceUtils.kt b/lawnchair/src/app/lawnchair/preferences2/PreferenceUtils.kt
index 4a8cfe0b78..710f37646f 100644
--- a/lawnchair/src/app/lawnchair/preferences2/PreferenceUtils.kt
+++ b/lawnchair/src/app/lawnchair/preferences2/PreferenceUtils.kt
@@ -3,14 +3,14 @@ package app.lawnchair.preferences2
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import app.lawnchair.util.subscribeBlocking
-import com.patrykmichalik.preferencemanager.Preference
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.firstBlocking
+import com.patrykmichalik.opto.domain.Preference
import kotlinx.coroutines.CoroutineScope
@Composable
-fun Preference.asState() = get().collectAsState(initial = firstBlocking())
+fun Preference.asState() = get().collectAsState(initial = firstBlocking())
-fun Preference.subscribeBlocking(
+fun Preference.subscribeBlocking(
scope: CoroutineScope,
block: (C) -> Unit,
) {
diff --git a/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt b/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt
index f6015e04b9..60ba249d37 100644
--- a/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt
+++ b/lawnchair/src/app/lawnchair/qsb/QsbLayout.kt
@@ -34,7 +34,7 @@ import com.android.launcher3.R
import com.android.launcher3.qsb.QsbContainerView
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.firstBlocking
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flatMapLatest
diff --git a/lawnchair/src/app/lawnchair/qsb/providers/AppSearch.kt b/lawnchair/src/app/lawnchair/qsb/providers/AppSearch.kt
index 5143560db8..ade4319ad2 100644
--- a/lawnchair/src/app/lawnchair/qsb/providers/AppSearch.kt
+++ b/lawnchair/src/app/lawnchair/qsb/providers/AppSearch.kt
@@ -11,7 +11,8 @@ object AppSearch : QsbSearchProvider(
icon = R.drawable.ic_qsb_search,
themingMethod = ThemingMethod.TINT,
packageName = "",
- website = ""
+ website = "",
+ type = QsbSearchProviderType.LOCAL
) {
override suspend fun launch(launcher: Launcher, forceWebsite: Boolean) {
launcher.animateToAllApps()
diff --git a/lawnchair/src/app/lawnchair/qsb/providers/GoogleGo.kt b/lawnchair/src/app/lawnchair/qsb/providers/GoogleGo.kt
index e94e129f7d..a156c319ca 100644
--- a/lawnchair/src/app/lawnchair/qsb/providers/GoogleGo.kt
+++ b/lawnchair/src/app/lawnchair/qsb/providers/GoogleGo.kt
@@ -12,7 +12,8 @@ object GoogleGo : QsbSearchProvider(
packageName = "com.google.android.apps.searchlite",
action = "android.search.action.GLOBAL_SEARCH",
supportVoiceIntent = true,
- website = "https://www.google.com/"
+ website = "https://www.google.com/",
+ type = QsbSearchProviderType.APP
) {
override fun handleCreateVoiceIntent(): Intent =
diff --git a/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt b/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt
index 1c11e0f3b9..23e94a61df 100644
--- a/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt
+++ b/lawnchair/src/app/lawnchair/qsb/providers/QsbSearchProvider.kt
@@ -1,17 +1,20 @@
package app.lawnchair.qsb.providers
+import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
+import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import app.lawnchair.preferences2.PreferenceManager2
import app.lawnchair.qsb.QsbLayout
import app.lawnchair.qsb.ThemingMethod
import app.lawnchair.resolveIntent
+import app.lawnchair.util.isPackageInstalled
import com.android.launcher3.Launcher
import com.android.launcher3.R
-import com.patrykmichalik.preferencemanager.first
+import com.patrykmichalik.opto.core.first
open class QsbSearchProvider(
val id: String,
@@ -20,10 +23,11 @@ open class QsbSearchProvider(
@DrawableRes val themedIcon: Int = icon,
val themingMethod: ThemingMethod = ThemingMethod.TINT,
val packageName: String,
- val className: String = "",
+ val className: String? = null,
val action: String? = null,
val supportVoiceIntent: Boolean = false,
- val website: String
+ val website: String,
+ val type: QsbSearchProviderType = QsbSearchProviderType.APP_AND_WEBSITE,
) {
suspend fun launch(launcher: Launcher) {
@@ -49,7 +53,10 @@ open class QsbSearchProvider(
fun createSearchIntent() = Intent(action)
.addFlags(INTENT_FLAGS)
- .setClassName(packageName, className)
+ .apply {
+ if (className != null) setClassName(packageName, className)
+ else setPackage(packageName)
+ }
fun createVoiceIntent(): Intent = if (supportVoiceIntent) {
handleCreateVoiceIntent()
@@ -65,6 +72,44 @@ open class QsbSearchProvider(
.addFlags(INTENT_FLAGS)
.setPackage(packageName)
+ /**
+ * Checks if the search provider is downloaded.
+ * Should only be used for [QsbSearchProviderType]s that are downloadable.
+ */
+ fun isDownloaded(context: Context) = context.packageManager.isPackageInstalled(packageName)
+
+ /**
+ * Launches the search provider's page on an app market.
+ * If no app market is installed, it tries to launch the provider's page on Google Play Store.
+ *
+ * Should only be used for [QsbSearchProviderType]s that are downloadable.
+ */
+ fun launchOnAppMarket(context: Context) {
+ try {
+ context.startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse("market://details?id=$packageName")
+ )
+ )
+ } catch (e: ActivityNotFoundException) {
+ try {
+ context.startActivity(
+ Intent(
+ Intent.ACTION_VIEW,
+ Uri.parse("https://play.google.com/store/apps/details?id=$packageName")
+ )
+ )
+ } catch (e: Exception) {
+ Toast.makeText(
+ context,
+ context.getString(R.string.error_no_market_or_browser_installed),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+
companion object {
internal const val INTENT_FLAGS =
@@ -77,7 +122,8 @@ open class QsbSearchProvider(
DuckDuckGo,
Presearch,
Wikipedia,
- Bing
+ Bing,
+ Sesame
)
/**
@@ -90,14 +136,17 @@ open class QsbSearchProvider(
* Resolve the default search provider.
*/
fun resolveDefault(context: Context): QsbSearchProvider {
- val defaultProviderId = context.getString(R.string.config_default_qsb_search_provider_id)
+ val defaultProviderId =
+ context.getString(R.string.config_default_qsb_search_provider_id)
val defaultProvider = fromId(defaultProviderId)
- val isDefaultProviderIntentResolved = QsbLayout.resolveIntent(context, defaultProvider.createSearchIntent())
+ val isDefaultProviderIntentResolved =
+ QsbLayout.resolveIntent(context, defaultProvider.createSearchIntent())
// Return the default value from config.xml if the value is valid
if (isDefaultProviderIntentResolved) {
if (defaultProvider != AppSearch ||
- (defaultProvider == AppSearch && defaultProviderId == AppSearch.id)) {
+ (defaultProvider == AppSearch && defaultProviderId == AppSearch.id)
+ ) {
return defaultProvider
}
}
@@ -111,4 +160,11 @@ open class QsbSearchProvider(
}
}
-}
\ No newline at end of file
+}
+
+enum class QsbSearchProviderType(val downloadable: Boolean) {
+ APP_AND_WEBSITE(downloadable = true),
+ WEBSITE(downloadable = false),
+ APP(downloadable = true),
+ LOCAL(downloadable = false)
+}
diff --git a/lawnchair/src/app/lawnchair/qsb/providers/Sesame.kt b/lawnchair/src/app/lawnchair/qsb/providers/Sesame.kt
new file mode 100644
index 0000000000..336260fa2c
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/qsb/providers/Sesame.kt
@@ -0,0 +1,15 @@
+package app.lawnchair.qsb.providers
+
+import app.lawnchair.qsb.ThemingMethod
+import com.android.launcher3.R
+
+object Sesame : QsbSearchProvider(
+ id = "sesame",
+ name = R.string.search_provider_sesame,
+ icon = R.drawable.ic_sesame,
+ themingMethod = ThemingMethod.TINT,
+ packageName = "ninja.sesame.app.edge",
+ className = "ninja.sesame.app.edge.omni.OmniActivity",
+ website = "https://play.google.com/store/apps/details?id=ninja.sesame.app.edge",
+ type = QsbSearchProviderType.APP
+)
\ No newline at end of file
diff --git a/lawnchair/src/app/lawnchair/search/LawnchairAppSearchAlgorithm.kt b/lawnchair/src/app/lawnchair/search/LawnchairAppSearchAlgorithm.kt
index 81f28d35ec..bef33d38c1 100644
--- a/lawnchair/src/app/lawnchair/search/LawnchairAppSearchAlgorithm.kt
+++ b/lawnchair/src/app/lawnchair/search/LawnchairAppSearchAlgorithm.kt
@@ -23,7 +23,7 @@ import com.android.launcher3.shortcuts.ShortcutRequest
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.Executors
import com.android.launcher3.util.PackageManagerHelper
-import com.patrykmichalik.preferencemanager.onEach
+import com.patrykmichalik.opto.core.onEach
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import me.xdrop.fuzzywuzzy.FuzzySearch
diff --git a/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt b/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
index 3d958845e8..7f669b7a93 100644
--- a/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
+++ b/lawnchair/src/app/lawnchair/smartspace/IcuDateTextView.kt
@@ -13,7 +13,7 @@ import app.lawnchair.util.broadcastReceiverFlow
import app.lawnchair.util.repeatOnAttached
import app.lawnchair.util.subscribeBlocking
import com.android.launcher3.R
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.firstBlocking
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
diff --git a/lawnchair/src/app/lawnchair/smartspace/provider/SmartspaceDataSource.kt b/lawnchair/src/app/lawnchair/smartspace/provider/SmartspaceDataSource.kt
index 7b710aa976..923d364041 100644
--- a/lawnchair/src/app/lawnchair/smartspace/provider/SmartspaceDataSource.kt
+++ b/lawnchair/src/app/lawnchair/smartspace/provider/SmartspaceDataSource.kt
@@ -5,14 +5,14 @@ import android.content.Context
import android.util.Log
import app.lawnchair.preferences2.PreferenceManager2
import app.lawnchair.smartspace.model.SmartspaceTarget
-import com.patrykmichalik.preferencemanager.Preference
+import com.patrykmichalik.opto.domain.Preference
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.*
abstract class SmartspaceDataSource(
val context: Context,
val providerName: Int,
- getEnabledPref: PreferenceManager2.() -> Preference
+ getEnabledPref: PreferenceManager2.() -> Preference
) {
val enabledPref = getEnabledPref(PreferenceManager2.getInstance(context))
open val isAvailable: Boolean = true
diff --git a/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt b/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt
index c5abf9c2ca..9c4eb34d9c 100644
--- a/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt
+++ b/lawnchair/src/app/lawnchair/theme/ThemeProvider.kt
@@ -18,8 +18,8 @@ import app.lawnchair.ui.theme.getSystemAccent
import app.lawnchair.wallpaper.WallpaperManagerCompat
import com.android.launcher3.Utilities
import com.android.launcher3.util.MainThreadInitializedObject
-import com.patrykmichalik.preferencemanager.firstBlocking
-import com.patrykmichalik.preferencemanager.onEach
+import com.patrykmichalik.opto.core.firstBlocking
+import com.patrykmichalik.opto.core.onEach
import dev.kdrag0n.colorkt.Color
import dev.kdrag0n.colorkt.conversion.ConversionGraph.convert
import dev.kdrag0n.colorkt.rgb.Srgb
diff --git a/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt b/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt
index e6e1b3f26e..74aad48a6b 100644
--- a/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt
+++ b/lawnchair/src/app/lawnchair/ui/popup/LawnchairShortcut.kt
@@ -17,7 +17,7 @@ import com.android.launcher3.model.data.AppInfo as ModelAppInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.popup.SystemShortcut
import com.android.launcher3.util.ComponentKey
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.firstBlocking
class LawnchairShortcut {
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/DebugMenuPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/DebugMenuPreferences.kt
index c55dbdc96b..f869bfd3ca 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/DebugMenuPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/DebugMenuPreferences.kt
@@ -4,6 +4,7 @@ import android.content.Intent
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
+import androidx.datastore.preferences.core.Preferences
import androidx.navigation.NavGraphBuilder
import app.lawnchair.preferences.PreferenceManager
import app.lawnchair.preferences.getAdapter
@@ -13,7 +14,7 @@ import app.lawnchair.preferences2.preferenceManager2
import app.lawnchair.ui.preferences.components.*
import com.android.launcher3.settings.DeveloperOptionsFragment
import com.android.launcher3.settings.SettingsActivity
-import com.patrykmichalik.preferencemanager.Preference
+import com.patrykmichalik.opto.domain.Preference
fun NavGraphBuilder.debugMenuGraph(route: String) {
preferenceGraph(route, { DebugMenuPreferences() })
@@ -75,10 +76,10 @@ fun DebugMenuPreferences() {
}
}
-private val PreferenceManager2.debugFlags: List>
+private val PreferenceManager2.debugFlags: List>>
get() = listOf(showComponentNames)
-private val PreferenceManager2.textFlags: List>
+private val PreferenceManager2.textFlags: List>>
get() = listOf(additionalFonts)
private val PreferenceManager.debugFlags
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt
index 67ecef2cc5..23aebd28ac 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/DockPreferences.kt
@@ -16,18 +16,30 @@
package app.lawnchair.ui.preferences
-import androidx.compose.animation.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavGraphBuilder
import app.lawnchair.preferences.getAdapter
import app.lawnchair.preferences.preferenceManager
import app.lawnchair.preferences2.preferenceManager2
-import app.lawnchair.ui.preferences.components.*
+import app.lawnchair.qsb.providers.QsbSearchProvider
+import app.lawnchair.ui.preferences.components.DividerColumn
+import app.lawnchair.ui.preferences.components.ExpandAndShrink
+import app.lawnchair.ui.preferences.components.NavigationActionPreference
+import app.lawnchair.ui.preferences.components.PreferenceGroup
+import app.lawnchair.ui.preferences.components.PreferenceLayout
+import app.lawnchair.ui.preferences.components.SliderPreference
+import app.lawnchair.ui.preferences.components.SwitchPreference
import com.android.launcher3.R
+object DockRoutes {
+ const val SEARCH_PROVIDER = "searchProvider"
+}
+
fun NavGraphBuilder.dockGraph(route: String) {
- preferenceGraph(route, { DockPreferences() })
+ preferenceGraph(route, { DockPreferences() }) { subRoute ->
+ searchProviderGraph(subRoute(DockRoutes.SEARCH_PROVIDER))
+ }
}
@Composable
@@ -54,11 +66,15 @@ fun DockPreferences() {
valueRange = 0F..1F,
showAsPercentage = true,
)
- QsbProviderPreference()
- SwitchPreference(
- adapter = prefs2.hotseatQsbForceWebsite.getAdapter(),
- label = stringResource(R.string.always_open_website_label),
- description = stringResource(R.string.always_open_website_description),
+ val hotseatQsbProviderAdapter by preferenceManager2().hotseatQsbProvider.getAdapter()
+ NavigationActionPreference(
+ label = stringResource(R.string.search_provider),
+ destination = subRoute(DockRoutes.SEARCH_PROVIDER),
+ subtitle = stringResource(
+ id = QsbSearchProvider.values()
+ .first { it == hotseatQsbProviderAdapter }
+ .name,
+ ),
)
}
}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/PreferencesDashboard.kt b/lawnchair/src/app/lawnchair/ui/preferences/PreferencesDashboard.kt
index cee4295345..d71c8ca1c1 100644
--- a/lawnchair/src/app/lawnchair/ui/preferences/PreferencesDashboard.kt
+++ b/lawnchair/src/app/lawnchair/ui/preferences/PreferencesDashboard.kt
@@ -84,7 +84,8 @@ fun PreferencesDashboard() {
PreferenceCategory(
label = stringResource(id = R.string.gestures_label),
- iconResource = R.drawable.ic_general,
+ description = stringResource(R.string.gestures_description),
+ iconResource = R.drawable.ic_gestures,
route = Routes.GESTURES,
)
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt b/lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt
new file mode 100644
index 0000000000..b5d2ca7834
--- /dev/null
+++ b/lawnchair/src/app/lawnchair/ui/preferences/SearchProviderPreferences.kt
@@ -0,0 +1,168 @@
+package app.lawnchair.ui.preferences
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.RadioButton
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavGraphBuilder
+import app.lawnchair.preferences.getAdapter
+import app.lawnchair.preferences2.preferenceManager2
+import app.lawnchair.qsb.providers.QsbSearchProvider
+import app.lawnchair.qsb.providers.QsbSearchProviderType
+import app.lawnchair.ui.preferences.components.ClickableIcon
+import app.lawnchair.ui.preferences.components.DividerColumn
+import app.lawnchair.ui.preferences.components.ExpandAndShrink
+import app.lawnchair.ui.preferences.components.PreferenceDivider
+import app.lawnchair.ui.preferences.components.PreferenceGroup
+import app.lawnchair.ui.preferences.components.PreferenceLayout
+import app.lawnchair.ui.preferences.components.PreferenceTemplate
+import com.android.launcher3.R
+
+fun NavGraphBuilder.searchProviderGraph(route: String) {
+ preferenceGraph(route, { SearchProviderPreferences() })
+}
+
+@Composable
+fun SearchProviderPreferences() {
+ val context = LocalContext.current
+ val adapter = preferenceManager2().hotseatQsbProvider.getAdapter()
+ val forceWebsiteAdapter = preferenceManager2().hotseatQsbForceWebsite.getAdapter()
+ PreferenceLayout(label = stringResource(R.string.search_provider)) {
+ PreferenceGroup {
+ QsbSearchProvider.values().forEach { qsbSearchProvider ->
+ val appInstalled = qsbSearchProvider.isDownloaded(context)
+ val selected = adapter.state.value == qsbSearchProvider
+ val hasAppAndWebsite = qsbSearchProvider.type == QsbSearchProviderType.APP_AND_WEBSITE
+ val showDownloadButton = qsbSearchProvider.type == QsbSearchProviderType.APP && !appInstalled
+ Column {
+ ListItem(
+ title = stringResource(id = qsbSearchProvider.name),
+ showDownloadButton = showDownloadButton,
+ enabled = qsbSearchProvider.type != QsbSearchProviderType.APP || appInstalled,
+ selected = selected,
+ onClick = { adapter.onChange(newValue = qsbSearchProvider) },
+ onDownloadClick = { qsbSearchProvider.launchOnAppMarket(context = context) },
+ description = if (showDownloadButton) {
+ stringResource(id = R.string.qsb_search_provider_app_required)
+ } else null,
+ )
+ ExpandAndShrink(visible = selected && hasAppAndWebsite) {
+ Options(
+ appEnabled = appInstalled,
+ appSelected = !forceWebsiteAdapter.state.value && appInstalled,
+ onAppClick = { forceWebsiteAdapter.onChange(newValue = false) },
+ onAppDownloadClick = { qsbSearchProvider.launchOnAppMarket(context = context) },
+ onWebsiteClick = { forceWebsiteAdapter.onChange(newValue = true) },
+ showAppDownloadButton = !appInstalled,
+ )
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+private fun ListItem(
+ title: String,
+ description: String?,
+ showDownloadButton: Boolean,
+ enabled: Boolean,
+ selected: Boolean,
+ onClick: () -> Unit,
+ onDownloadClick: () -> Unit,
+) {
+ Column {
+ PreferenceTemplate(
+ title = { Text(text = title) },
+ verticalPadding = if (showDownloadButton) 12.dp else 16.dp,
+ horizontalPadding = 0.dp,
+ enabled = enabled,
+ modifier = Modifier.clickable(enabled = enabled, onClick = onClick),
+ description = { if (description != null) Text(text = description) },
+ startWidget = {
+ RadioButton(
+ selected = selected,
+ onClick = null,
+ enabled = enabled,
+ modifier = Modifier.padding(start = 16.dp)
+ )
+ },
+ endWidget = {
+ if (showDownloadButton) {
+ ClickableIcon(
+ painter = painterResource(id = R.drawable.ic_download),
+ onClick = onDownloadClick,
+ tint = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.padding(end = 4.dp),
+ )
+ }
+ },
+ )
+ }
+}
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+private fun Options(
+ appEnabled: Boolean,
+ appSelected: Boolean,
+ showAppDownloadButton: Boolean,
+ onAppClick: () -> Unit,
+ onAppDownloadClick: () -> Unit,
+ onWebsiteClick: () -> Unit,
+) {
+ PreferenceDivider(startIndent = 40.dp)
+ DividerColumn(startIndent = 40.dp) {
+ PreferenceTemplate(
+ title = { Text(stringResource(id = R.string.app_label)) },
+ enabled = appEnabled,
+ verticalPadding = if (!appEnabled) 4.dp else 16.dp,
+ horizontalPadding = 0.dp,
+ modifier = Modifier.clickable(
+ enabled = appEnabled,
+ onClick = onAppClick,
+ ),
+ startWidget = {
+ RadioButton(
+ selected = appSelected,
+ onClick = null,
+ enabled = appEnabled,
+ modifier = Modifier.padding(start = 56.dp),
+ )
+ },
+ endWidget = {
+ if (showAppDownloadButton) {
+ ClickableIcon(
+ painter = painterResource(R.drawable.ic_download),
+ onClick = onAppDownloadClick,
+ tint = MaterialTheme.colorScheme.primary,
+ modifier = Modifier.padding(end = 4.dp),
+ )
+ }
+ },
+ )
+ PreferenceTemplate(
+ title = { Text(text = stringResource(id = R.string.website_label)) },
+ modifier = Modifier.clickable(onClick = onWebsiteClick),
+ horizontalPadding = 0.dp,
+ startWidget = {
+ RadioButton(
+ selected = !appSelected,
+ onClick = null,
+ modifier = Modifier.padding(start = 56.dp),
+ )
+ },
+ )
+ }
+}
diff --git a/lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt b/lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt
deleted file mode 100644
index 39758d7007..0000000000
--- a/lawnchair/src/app/lawnchair/ui/preferences/components/QsbProviderPreference.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package app.lawnchair.ui.preferences.components
-
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.remember
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import app.lawnchair.preferences.getAdapter
-import app.lawnchair.preferences2.preferenceManager2
-import app.lawnchair.qsb.QsbLayout
-import app.lawnchair.qsb.providers.GoogleGo
-import app.lawnchair.qsb.providers.QsbSearchProvider
-import com.android.launcher3.R
-
-@Composable
-fun QsbProviderPreference() {
- val adapter = preferenceManager2().hotseatQsbProvider.getAdapter()
- val context = LocalContext.current
- val entries = remember {
- QsbSearchProvider.values().map {
- // Enabled is true if provider is anything but Google Go,
- // or if it is Google Go and the intent can be resolved.
- val enabled = it != GoogleGo || QsbLayout.resolveIntent(context, it.createSearchIntent())
- ListPreferenceEntry(it, enabled) { stringResource(id = it.name) }
- }
- }
-
- ListPreference(
- adapter = adapter,
- entries = entries,
- label = stringResource(R.string.search_provider),
- )
-}
diff --git a/lawnchair/src/app/lawnchair/util/LawnchairUtils.kt b/lawnchair/src/app/lawnchair/util/LawnchairUtils.kt
index 83c5d92346..21b6b07f5f 100644
--- a/lawnchair/src/app/lawnchair/util/LawnchairUtils.kt
+++ b/lawnchair/src/app/lawnchair/util/LawnchairUtils.kt
@@ -44,7 +44,7 @@ import com.android.launcher3.R
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Themes
import com.android.systemui.shared.system.QuickStepContract
-import com.patrykmichalik.preferencemanager.firstBlocking
+import com.patrykmichalik.opto.core.firstBlocking
import org.json.JSONArray
import java.util.concurrent.Callable
import java.util.concurrent.ExecutionException
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
index a025e2a189..1759bfe73d 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java
@@ -33,6 +33,8 @@ import android.view.View;
import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
+import androidx.datastore.preferences.core.Preferences;
+
import com.android.launcher3.BaseActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
@@ -43,8 +45,8 @@ import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.WallpaperManagerCompat;
-import com.patrykmichalik.preferencemanager.Preference;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.domain.Preference;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import app.lawnchair.preferences.BasePreferenceManager;
import app.lawnchair.preferences.PreferenceManager;
@@ -172,7 +174,7 @@ public class DepthController implements StateHandler,
public DepthController(Launcher l) {
mLauncher = l;
- Preference depthPref = PreferenceManager2.getInstance(l).getWallpaperDepthEffect();
+ Preference depthPref = PreferenceManager2.getInstance(l).getWallpaperDepthEffect();
mEnableDepth = PreferenceExtensionsKt.firstBlocking(depthPref);
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0cffaadcff..487e0ce5aa 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -46,7 +46,7 @@ import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.WindowBounds;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.io.PrintWriter;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 15e9b6c939..9ca306daa6 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -31,7 +31,7 @@ import android.widget.FrameLayout;
import androidx.annotation.Nullable;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.function.Consumer;
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 9f6b7deaa4..ee5447ab1b 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -19,7 +19,7 @@ import androidx.annotation.RequiresApi;
import com.android.launcher3.graphics.SysUiScrim;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.uioverrides.ApiWrapper;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.Collections;
import java.util.List;
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index 4efa798909..c8d56b9b52 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -31,7 +31,7 @@ import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.util.Executors;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import app.lawnchair.preferences2.PreferenceManager2;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 8dd93cac46..dd13c8bd02 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -122,7 +122,7 @@ import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
import com.android.launcher3.widget.util.WidgetSizes;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 58b02291e7..b42d02a210 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -22,7 +22,7 @@ import com.android.launcher3.BuildConfig;
import com.android.launcher3.Utilities;
import com.android.launcher3.uioverrides.DeviceFlag;
import com.android.systemui.shared.system.BlurUtils;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/src/com/android/launcher3/folder/FolderNameEditText.java b/src/com/android/launcher3/folder/FolderNameEditText.java
index de5e1fde3e..b87207900f 100644
--- a/src/com/android/launcher3/folder/FolderNameEditText.java
+++ b/src/com/android/launcher3/folder/FolderNameEditText.java
@@ -27,7 +27,7 @@ import android.view.inputmethod.InputConnectionWrapper;
import android.view.inputmethod.InputMethodManager;
import com.android.launcher3.ExtendedEditText;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.List;
diff --git a/src/com/android/launcher3/graphics/IconShape.java b/src/com/android/launcher3/graphics/IconShape.java
index 87eed19527..da18c0cba7 100644
--- a/src/com/android/launcher3/graphics/IconShape.java
+++ b/src/com/android/launcher3/graphics/IconShape.java
@@ -47,7 +47,7 @@ import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.views.ClipPathView;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index 22b60202db..67e6dc7033 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -51,7 +51,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.Themes;
import com.android.systemui.plugins.ResourceProvider;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import app.lawnchair.preferences2.PreferenceManager2;
import app.lawnchair.util.ViewExtensionsKt;
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index eabee75cea..93279d18e8 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -68,7 +68,7 @@ import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.ShortcutUtil;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.ArrayList;
import java.util.Arrays;
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 81598a79bb..cf88016109 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -27,7 +27,7 @@ import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.WidgetsBottomSheet;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.List;
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
index a194a630cd..f52708f46e 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
@@ -28,7 +28,7 @@ import android.widget.Toast;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import app.lawnchair.preferences2.PreferenceManager2;
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 0b4f2e53cd..797c68e597 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -52,8 +52,8 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
-import com.patrykmichalik.preferencemanager.Preference;
-import com.patrykmichalik.preferencemanager.PreferenceExtensionsKt;
+import com.patrykmichalik.opto.domain.Preference;
+import com.patrykmichalik.opto.core.PreferenceExtensionsKt;
import java.util.ArrayList;
import java.util.List;