Merge branch '12.1-dev' into feature/widget/allow-overlap

This commit is contained in:
Yasan Ghaffarian
2022-06-18 11:17:26 +04:30
46 changed files with 373 additions and 108 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
Copyright (c) 2005-2008, The Android Open Source Project
Copyright (c) 2021, Lawnchair
Copyright (c) 2022, Lawnchair
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+6 -6
View File
@@ -1,8 +1,8 @@
buildscript {
ext {
kotlin_version = '1.6.21'
compose_version = '1.2.0-beta02'
accompanist_version = '0.24.9-beta'
compose_version = '1.2.0-rc01'
accompanist_version = '0.24.10-beta'
libsu_version = '3.1.2'
protocVersion = '3.18.0'
room_version = '2.4.2'
@@ -78,7 +78,7 @@ allprojects {
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions {
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
}
}
}
@@ -355,7 +355,7 @@ dependencies {
implementation "androidx.compose.ui:ui-text-google-fonts:$compose_version"
implementation "androidx.compose.foundation:foundation:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.material3:material3:1.0.0-alpha12"
implementation "androidx.compose.material3:material3:1.0.0-alpha13"
implementation "androidx.compose.runtime:runtime-livedata:$compose_version"
implementation "androidx.compose.runtime:runtime-rxjava2:$compose_version"
implementation "androidx.compose.compiler:compiler:$compose_version"
@@ -372,12 +372,12 @@ dependencies {
implementation "com.google.accompanist:accompanist-pager:$accompanist_version"
implementation "com.google.accompanist:accompanist-placeholder-material:$accompanist_version"
implementation "com.google.accompanist:accompanist-systemuicontroller:$accompanist_version"
implementation 'com.google.android.material:material:1.6.0'
implementation "com.google.android.material:material:1.6.1"
implementation "io.github.fornewid:material-motion-compose-core:0.8.4"
implementation 'dev.kdrag0n:colorkt:1.0.5'
implementation 'io.coil-kt:coil-compose:2.0.0'
implementation 'me.xdrop:fuzzywuzzy:1.4.0'
implementation "com.patrykmichalik:preference-manager:1.0.7"
implementation "com.patrykmichalik:opto:1.0.12"
implementation "androidx.datastore:datastore-preferences:1.0.0"
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
+5
View File
@@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="48" android:viewportWidth="48"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M24,31.75Q23.7,31.75 23.45,31.65Q23.2,31.55 22.95,31.3L15.4,23.75Q14.95,23.3 14.975,22.675Q15,22.05 15.45,21.6Q15.9,21.15 16.525,21.15Q17.15,21.15 17.6,21.6L22.5,26.55V9.5Q22.5,8.85 22.925,8.425Q23.35,8 24,8Q24.65,8 25.075,8.425Q25.5,8.85 25.5,9.5V26.55L30.45,21.6Q30.9,21.15 31.525,21.15Q32.15,21.15 32.6,21.6Q33.05,22.05 33.05,22.675Q33.05,23.3 32.6,23.75L25.05,31.3Q24.8,31.55 24.55,31.65Q24.3,31.75 24,31.75ZM11,40Q9.8,40 8.9,39.1Q8,38.2 8,37V31.35Q8,30.7 8.425,30.275Q8.85,29.85 9.5,29.85Q10.15,29.85 10.575,30.275Q11,30.7 11,31.35V37Q11,37 11,37Q11,37 11,37H37Q37,37 37,37Q37,37 37,37V31.35Q37,30.7 37.425,30.275Q37.85,29.85 38.5,29.85Q39.15,29.85 39.575,30.275Q40,30.7 40,31.35V37Q40,38.2 39.1,39.1Q38.2,40 37,40Z"/>
</vector>
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dip"
android:height="24.0dip"
android:viewportWidth="96.0"
android:viewportHeight="96.0">
<path
android:fillAlpha="0.6"
android:fillColor="#ffffffff"
android:pathData="M47.6461538 37.3846154L25.7076923 37.3846154L25.7076923 94L47.6461538 94C60.0307692 91.8769231 71 79.8461538 71 65.3384615C71 50.8307692 58.9692308 39.1538462 47.6461538 37.3846154z"
android:strokeWidth="0.0"
android:strokeColor="#00000000" />
<path
android:fillAlpha="1.0"
android:fillColor="#ff000000"
android:pathData="M48.3538462 2L70.2923077 2L70.2923077 58.6153846L48.3538462 58.6153846C35.9692308 56.4923077 25 44.4615385 25 29.9538462C25 15.4461538 37.0307692 3.76923077 48.3538462 2z"
android:strokeWidth="0.0"
android:strokeColor="#00000000" />
<path
android:fillAlpha="1.0"
android:fillColor="#ffffffff"
android:pathData="M48.3538462 2L70.2923077 2L70.2923077 58.6153846L48.3538462 58.6153846C35.9692308 56.4923077 25 44.4615385 25 29.9538462C25 15.4461538 37.0307692 3.76923077 48.3538462 2z"
android:strokeWidth="0.0"
android:strokeColor="#00000000" />
</vector>
+5
View File
@@ -88,6 +88,7 @@
</plurals>
<string name="hotseat_qsb_label">Show Search Bar</string>
<string name="qsb_search_provider_app_required">App required.</string>
<string name="dt2s_admin_hint_title">Admin Permissions Required</string>
<string name="dt2s_admin_hint">To use Double-Tap to Sleep, set Lawnchair as a device admin app. Tap Open Settings, then tap “Activate this device admin app.”</string>
<string name="dt2s_admin_warning">Double-Tap to Sleep will be turned off.</string>
@@ -231,6 +232,7 @@
<string name="search_provider_wikipedia" translatable="false">Wikipedia</string>
<string name="search_provider_presearch" translatable="false">Presearch</string>
<string name="search_provider_bing" translatable="false">Bing</string>
<string name="search_provider_sesame" translatable="false">Sesame</string>
<string name="always_open_website_label">Always Open Website</string>
<string name="always_open_website_description">Open search providers website even if their app is installed.</string>
<string name="search_provider">Search Provider</string>
@@ -241,6 +243,7 @@
<string name="reset_custom_icons_confirmation">All custom icons will be reset. Do you want to continue?</string>
<string name="taskbar_label">Taskbar</string>
<string name="enable_taskbar_experimental">Enable Taskbar (Experimental)</string>
<string name="error_no_market_or_browser_installed">No app market or browser installed.</string>
<!-- Smartspace -->
<string name="generic_smartspace_concatenated_desc">%1$s, %2$s</string>
@@ -317,4 +320,6 @@
<string name="gesture_home_tap">Home Button Tap</string>
<string name="gesture_back_tap">Back Button Tap</string>
<string name="x_and_y">%s &amp; %s</string>
<string name="app_label">App</string>
<string name="website_label">Website</string>
</resources>
@@ -12,7 +12,7 @@ import com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE
import com.android.launcher3.InvariantDeviceProfile.INDEX_ALL_APPS
import com.android.launcher3.Utilities
import com.android.launcher3.util.MainThreadInitializedObject
import com.patrykmichalik.preferencemanager.firstBlocking
import com.patrykmichalik.opto.core.firstBlocking
class DeviceProfileOverrides(context: Context) {
private val prefs = PreferenceManager.getInstance(context)
@@ -67,7 +67,7 @@ import com.android.launcher3.util.TouchController
import com.android.launcher3.widget.RoundedCornerEnforcement
import com.android.systemui.plugins.shared.LauncherOverlayManager
import com.android.systemui.shared.system.QuickStepContract
import com.patrykmichalik.preferencemanager.onEach
import com.patrykmichalik.opto.core.onEach
import dev.kdrag0n.monet.theme.ColorScheme
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
@@ -13,7 +13,7 @@ import com.android.launcher3.anim.PendingAnimation
import com.android.launcher3.statemanager.StateManager
import com.android.launcher3.states.StateAnimationConfig
import com.android.quickstep.AnimatedFloat
import com.patrykmichalik.preferencemanager.onEach
import com.patrykmichalik.opto.core.onEach
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -34,7 +34,7 @@ import com.android.launcher3.allapps.*
import com.android.launcher3.allapps.search.AllAppsSearchBarController
import com.android.launcher3.search.SearchCallback
import com.android.launcher3.util.Themes
import com.patrykmichalik.preferencemanager.firstBlocking
import com.patrykmichalik.opto.core.firstBlocking
import java.util.*
import kotlin.math.max
@@ -8,9 +8,8 @@ import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.allapps.AlphabeticalAppsList
import com.android.launcher3.allapps.WorkAdapterProvider
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.ItemInfoMatcher
import com.patrykmichalik.preferencemanager.onEach
import com.patrykmichalik.opto.core.onEach
class LawnchairAlphabeticalAppsList(
context: Context,
@@ -23,7 +23,7 @@ import app.lawnchair.gestures.config.GestureHandlerConfig
import app.lawnchair.preferences2.PreferenceManager2
import com.android.quickstep.SysUINavigationMode
import com.android.quickstep.util.VibratorWrapper
import com.patrykmichalik.preferencemanager.Preference
import com.patrykmichalik.opto.domain.Preference
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@@ -72,7 +72,7 @@ class GestureController(private val launcher: LawnchairLauncher) {
}
}
private fun handler(pref: Preference<GestureHandlerConfig, String>) = pref.get()
private fun handler(pref: Preference<GestureHandlerConfig, String, *>) = pref.get()
.distinctUntilChanged()
.map { it.createHandler(launcher) }
.shareIn(
@@ -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) {
@@ -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;
@@ -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 <P, T> getAdapter(
}
@Composable
fun <T> Preference<T, *>.getAdapter(): PreferenceAdapter<T> {
fun <T> Preference<T, *, *>.getAdapter(): PreferenceAdapter<T> {
return createStateAdapter(state = asState(), set = this::set)
}
@@ -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
@@ -353,12 +353,12 @@ class PreferenceManager2(private val context: Context) : PreferenceManager {
private inline fun <reified T> serializablePreference(
key: Preferences.Key<String>,
defaultValue: T
defaultValue: T,
) = preference(
key = key,
defaultValue = defaultValue,
parse = { Json.decodeFromString(it) },
save = { Json.encodeToString(it) }
parse = Json::decodeFromString,
save = Json::encodeToString,
)
init {
@@ -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 <C, S> Preference<C, S>.asState() = get().collectAsState(initial = firstBlocking())
fun <C, S> Preference<C, S, *>.asState() = get().collectAsState(initial = firstBlocking())
fun <C, S> Preference<C, S>.subscribeBlocking(
fun <C, S> Preference<C, S, *>.subscribeBlocking(
scope: CoroutineScope,
block: (C) -> Unit,
) {
+1 -1
View File
@@ -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
@@ -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()
@@ -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 =
@@ -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(
}
}
}
}
enum class QsbSearchProviderType(val downloadable: Boolean) {
APP_AND_WEBSITE(downloadable = true),
WEBSITE(downloadable = false),
APP(downloadable = true),
LOCAL(downloadable = false)
}
@@ -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
)
@@ -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
@@ -3,6 +3,7 @@ package app.lawnchair.smartspace
import android.content.Context
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
@@ -128,6 +129,8 @@ class BcSmartspaceCard @JvmOverloads constructor(
fun setTitle(title: CharSequence?, contentDescription: CharSequence?, hasIcon: Boolean) {
val titleView = titleTextView ?: return
val isRTL = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL
titleView.textAlignment = if (isRTL) TEXT_ALIGNMENT_TEXT_END else TEXT_ALIGNMENT_TEXT_START
titleView.text = title
titleView.setCompoundDrawablesRelative(
if (hasIcon) iconDrawable else null, null,
@@ -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
@@ -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<Boolean, Boolean>
getEnabledPref: PreferenceManager2.() -> Preference<Boolean, Boolean, *>
) {
val enabledPref = getEnabledPref(PreferenceManager2.getInstance(context))
open val isAvailable: Boolean = true
@@ -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
@@ -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 {
@@ -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<Preference<Boolean, Boolean>>
private val PreferenceManager2.debugFlags: List<Preference<Boolean, Boolean, Preferences.Key<Boolean>>>
get() = listOf(showComponentNames)
private val PreferenceManager2.textFlags: List<Preference<String, String>>
private val PreferenceManager2.textFlags: List<Preference<String, String, Preferences.Key<String>>>
get() = listOf(additionalFonts)
private val PreferenceManager.debugFlags
@@ -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,
),
)
}
}
@@ -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),
)
},
)
}
}
@@ -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),
)
}
@@ -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
@@ -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<LauncherState>,
public DepthController(Launcher l) {
mLauncher = l;
Preference<Boolean, Boolean> depthPref = PreferenceManager2.getInstance(l).getWallpaperDepthEffect();
Preference<Boolean, Boolean, ?> depthPref = PreferenceManager2.getInstance(l).getWallpaperDepthEffect();
mEnableDepth = PreferenceExtensionsKt.firstBlocking(depthPref);
}
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
@@ -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;
@@ -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;
+1 -1
View File
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -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;