From fdee7778adf95e6babadbc6bb1dd416aabf5fd5d Mon Sep 17 00:00:00 2001 From: Artem Chepurnoy Date: Mon, 28 Oct 2024 15:03:02 +0200 Subject: [PATCH] improvement: Add a note for Chrome users to enable native autofill #680 --- .../apppicker/AppPickerStateProducer.kt | 15 +++- .../settings/component/SettingAutofill.kt | 74 ++++++++++++++++++- .../composeResources/values/strings.xml | 4 + .../com/artemchep/keyguard/ui/SimpleNote.kt | 5 ++ 4 files changed, 92 insertions(+), 6 deletions(-) diff --git a/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/apppicker/AppPickerStateProducer.kt b/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/apppicker/AppPickerStateProducer.kt index ab60dd97..b8473d99 100644 --- a/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/apppicker/AppPickerStateProducer.kt +++ b/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/apppicker/AppPickerStateProducer.kt @@ -35,6 +35,7 @@ import com.artemchep.keyguard.res.* import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart @@ -316,7 +317,7 @@ fun produceAppPickerState( } } - val itemsFlow = getAppsFlow(context.context) + val itemsFlow = flowOfInstalledApps(context.context) .combine(sortSink) { items, sort -> val comparator = Comparator { a, b -> val result = sort.comparator.compare(a, b) @@ -370,7 +371,17 @@ fun produceAppPickerState( } } -private fun getAppsFlow( +fun flowOfInstalledAppsAnyOf( + context: Context, + packageNames: Iterable, +) = flowOfInstalledApps(context) + .map { installedApps -> + installedApps + .any { app -> app.packageName in packageNames } + } + .distinctUntilChanged() + +fun flowOfInstalledApps( context: Context, ) = broadcastFlow( context = context, diff --git a/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/home/settings/component/SettingAutofill.kt b/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/home/settings/component/SettingAutofill.kt index d5665223..05b03a77 100644 --- a/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/home/settings/component/SettingAutofill.kt +++ b/common/src/androidMain/kotlin/com/artemchep/keyguard/feature/home/settings/component/SettingAutofill.kt @@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.AutoAwesome +import androidx.compose.material.icons.outlined.OpenInBrowser import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -23,6 +24,10 @@ import arrow.core.partially1 import com.artemchep.keyguard.android.closestActivityOrNull import com.artemchep.keyguard.common.service.autofill.AutofillService import com.artemchep.keyguard.common.service.autofill.AutofillServiceStatus +import com.artemchep.keyguard.feature.apppicker.flowOfInstalledAppsAnyOf +import com.artemchep.keyguard.feature.navigation.LocalNavigationController +import com.artemchep.keyguard.feature.navigation.NavigationIntent +import com.artemchep.keyguard.platform.LeContext import com.artemchep.keyguard.res.Res import com.artemchep.keyguard.res.* import com.artemchep.keyguard.ui.ExpandedIfNotEmpty @@ -31,8 +36,9 @@ import com.artemchep.keyguard.ui.FlatSimpleNote import com.artemchep.keyguard.ui.SimpleNote import com.artemchep.keyguard.ui.icons.icon import com.artemchep.keyguard.ui.theme.Dimens +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import org.jetbrains.compose.resources.stringResource -import kotlinx.coroutines.flow.map import org.kodein.di.DirectDI import org.kodein.di.instance import java.io.BufferedReader @@ -43,13 +49,18 @@ actual fun settingAutofillProvider( directDI: DirectDI, ): SettingComponent = settingAutofillProvider( autofillService = directDI.instance(), + appContext = directDI.instance(), ) fun settingAutofillProvider( autofillService: AutofillService, -): SettingComponent = autofillService - .status() - .map { status -> + appContext: LeContext, +): SettingComponent = + combine( + autofillService + .status(), + flowOfIsChromiumInstalled(context = appContext.context), + ) { status, isChromeInstalled -> val platformWarning = when { isMiui() -> AutofillPlatformWarning.Miui else -> null @@ -88,6 +99,12 @@ fun settingAutofillProvider( }, platformWarning = platformWarning, ) + + ExpandedIfNotEmpty( + valueOrNull = isChromeInstalled.takeIf { it }, + ) { + SettingAutofillChromeNativeAutofillWarning() + } } } @@ -168,6 +185,37 @@ private fun SettingAutofillPlatformWarningMiui( ) } +@Composable +private fun SettingAutofillChromeNativeAutofillWarning( +) { + FlatSimpleNote( + modifier = Modifier + .padding( + top = 8.dp, + bottom = 8.dp, + start = Dimens.horizontalPadding * 1 + 24.dp, + ), + type = SimpleNote.Type.INFO, + title = stringResource(Res.string.pref_item_autofill_service_chrome_native_autofill_title), + text = stringResource(Res.string.pref_item_autofill_service_chrome_native_autofill_text), + trailing = { + val navController by rememberUpdatedState(LocalNavigationController.current) + IconButton( + onClick = { + val url = "https://android-developers.googleblog.com/2024/10/chrome-3p-autofill-services.html" + val intent = NavigationIntent.NavigateToBrowser(url) + navController.queue(intent) + }, + ) { + Icon( + imageVector = Icons.Outlined.OpenInBrowser, + contentDescription = null, + ) + } + }, + ) +} + private sealed interface AutofillPlatformWarning { data object Miui : AutofillPlatformWarning { fun launchPermissionSettings( @@ -196,6 +244,24 @@ private sealed interface AutofillPlatformWarning { } } +private fun flowOfIsChromiumInstalled( + context: Context, +): Flow { + val chromiumPackageNames = setOf( + "com.android.chrome", + "com.chrome.beta", + "com.chrome.canary", + "com.chrome.dev", + "com.google.android.apps.chrome", + "com.google.android.apps.chrome_dev", + "org.chromium.chrome", + ) + return flowOfInstalledAppsAnyOf( + context, + packageNames = chromiumPackageNames, + ) +} + private fun isMiui(): Boolean { return !getSystemProperty("ro.miui.ui.version.name").isNullOrBlank() } diff --git a/common/src/commonMain/composeResources/values/strings.xml b/common/src/commonMain/composeResources/values/strings.xml index d9c696f5..3ad8f741 100644 --- a/common/src/commonMain/composeResources/values/strings.xml +++ b/common/src/commonMain/composeResources/values/strings.xml @@ -1075,6 +1075,10 @@ Autofill service Use the Android Autofill Framework to assist in filling login information into other apps on the device Some Xiaomi devices require you to manually allow the "Display pop-up windows while running in the background" permission. Please open the settings and verify that it is granted. + Chrome to support third-party autofill services natively + 1. Open Chrome's Settings and tap Autofill Services +2. Choose Autofill using another service +3. Confirm and restart Chrome Auto-copy one-time passwords When filling a login information, automatically copy one-time passwords Inline suggestions diff --git a/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/SimpleNote.kt b/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/SimpleNote.kt index 7c0d2371..efb50ac3 100644 --- a/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/SimpleNote.kt +++ b/common/src/commonMain/kotlin/com/artemchep/keyguard/ui/SimpleNote.kt @@ -1,5 +1,6 @@ package com.artemchep.keyguard.ui +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.RowScope import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Check @@ -58,6 +59,7 @@ fun FlatSimpleNote( text: String? = null, leading: (@Composable RowScope.() -> Unit)? = null, trailing: (@Composable RowScope.() -> Unit)? = null, + content: (@Composable ColumnScope.() -> Unit)? = null, onClick: (() -> Unit)? = null, enabled: Boolean = true, ) { @@ -123,6 +125,9 @@ fun FlatSimpleNote( color = textColor, ) } + if (content != null) { + content() + } }, trailing = trailing, onClick = onClick,