From 53a2b6b9fb513abee589de7703941b90fa844464 Mon Sep 17 00:00:00 2001 From: Titouan Thibaud Date: Mon, 31 Jul 2023 12:19:03 +0200 Subject: [PATCH 1/5] Bug 1842203: Implement of the final UX of FedCM Provider and Account dialogs in Compose --- .../gecko/prompt/GeckoPromptDelegate.kt | 9 +- .../concept/engine/prompt/PromptRequest.kt | 2 + .../concept/identitycredential/Provider.kt | 1 + .../components/feature/prompts/build.gradle | 17 ++ .../feature/prompts/PromptFeature.kt | 1 + .../BasicAccountsAdapter.kt | 77 -------- .../BasicProvidersAdapter.kt | 67 ------- .../IdentityCredentialItem.kt | 111 ++++++++++++ .../identitycredential/SelectAccountDialog.kt | 165 ++++++++++++++++++ .../SelectAccountDialogFragment.kt | 52 ++++-- .../SelectProviderDialog.kt | 131 ++++++++++++++ .../SelectProviderDialogFragment.kt | 42 ++--- ...prompts_choose_identity_account_dialog.xml | 12 -- ...ompts_choose_identity_provider_dialogs.xml | 12 -- ...mpts_identity_crendential_account_item.xml | 40 ----- ...pts_identity_crendential_provider_item.xml | 20 --- .../prompts/src/main/res/values/strings.xml | 6 +- 17 files changed, 493 insertions(+), 272 deletions(-) delete mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicAccountsAdapter.kt delete mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicProvidersAdapter.kt create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt delete mode 100644 android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_account_dialog.xml delete mode 100644 android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_provider_dialogs.xml delete mode 100644 android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_account_item.xml delete mode 100644 android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_provider_item.xml diff --git a/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt b/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt index a60b0c05f347..d2d839ea55ca 100644 --- a/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt +++ b/android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/prompt/GeckoPromptDelegate.kt @@ -63,6 +63,7 @@ typealias GECKO_AUTH_LEVEL = PromptDelegate.AuthPrompt.AuthOptions.Level typealias GECKO_PROMPT_FILE_TYPE = PromptDelegate.FilePrompt.Type typealias GECKO_PROMPT_PROVIDER_SELECTOR = ProviderSelectorPrompt.Provider typealias GECKO_PROMPT_ACCOUNT_SELECTOR = AccountSelectorPrompt.Account +typealias GECKO_PROMPT_ACCOUNT_SELECTOR_PROVIDER = AccountSelectorPrompt.Provider typealias GECKO_PROMPT_CHOICE_TYPE = PromptDelegate.ChoicePrompt.Type typealias GECKO_PROMPT_FILE_CAPTURE = PromptDelegate.FilePrompt.Capture typealias GECKO_PROMPT_SHARE_RESULT = PromptDelegate.SharePrompt.Result @@ -132,6 +133,7 @@ internal class GeckoPromptDelegate(private val geckoEngineSession: GeckoEngineSe onPromptRequest( PromptRequest.IdentityCredential.SelectAccount( accounts = prompt.accounts.map { it.toAccount() }, + provider = prompt.provider.let { it.toProvider() }, onConfirm = onConfirm, onDismiss = onDismiss, ), @@ -912,10 +914,15 @@ internal fun PromptDelegate.BasePrompt.dismissSafely(geckoResult: GeckoResult, + val provider: Provider, val onConfirm: (Account) -> Unit, override val onDismiss: () -> Unit, ) : IdentityCredential(onDismiss), Dismissible diff --git a/android-components/components/concept/engine/src/main/java/mozilla/components/concept/identitycredential/Provider.kt b/android-components/components/concept/engine/src/main/java/mozilla/components/concept/identitycredential/Provider.kt index 72f89f7cfb38..7ebc8521b81d 100644 --- a/android-components/components/concept/engine/src/main/java/mozilla/components/concept/identitycredential/Provider.kt +++ b/android-components/components/concept/engine/src/main/java/mozilla/components/concept/identitycredential/Provider.kt @@ -20,4 +20,5 @@ data class Provider( val id: Int, val icon: String?, val name: String, + val domain: String, ) : Parcelable diff --git a/android-components/components/feature/prompts/build.gradle b/android-components/components/feature/prompts/build.gradle index 71985b8bbe07..bc863b60fef7 100644 --- a/android-components/components/feature/prompts/build.gradle +++ b/android-components/components/feature/prompts/build.gradle @@ -21,6 +21,14 @@ android { } } + composeOptions { + kotlinCompilerExtensionVersion = Versions.compose_compiler + } + + buildFeatures { + compose true + } + namespace 'mozilla.components.feature.prompts' } @@ -40,11 +48,20 @@ dependencies { implementation project(':support-utils') implementation project(':ui-icons') implementation project(':ui-widgets') + implementation project(':ui-colors') implementation ComponentsDependencies.androidx_constraintlayout implementation ComponentsDependencies.androidx_core_ktx implementation ComponentsDependencies.google_material + implementation ComponentsDependencies.androidx_core_ktx + implementation ComponentsDependencies.androidx_compose_ui + implementation ComponentsDependencies.androidx_compose_ui_tooling_preview + implementation ComponentsDependencies.androidx_compose_foundation + implementation ComponentsDependencies.androidx_compose_material + + debugImplementation ComponentsDependencies.androidx_compose_ui_tooling + testImplementation ComponentsDependencies.androidx_test_core testImplementation ComponentsDependencies.androidx_test_junit testImplementation ComponentsDependencies.testing_coroutines diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt index 102a86153e51..73e0050f3b8c 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt @@ -921,6 +921,7 @@ class PromptFeature private constructor( promptRequestUID = promptRequest.uid, shouldDismissOnLoad = true, accounts = promptRequest.accounts, + provider = promptRequest.provider, ) } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicAccountsAdapter.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicAccountsAdapter.kt deleted file mode 100644 index b9f175a52cb3..000000000000 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicAccountsAdapter.kt +++ /dev/null @@ -1,77 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package mozilla.components.feature.prompts.identitycredential - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.TextView -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import mozilla.components.concept.identitycredential.Account -import mozilla.components.feature.prompts.R -import mozilla.components.support.ktx.kotlin.base64PngToBitmap - -private object AccountItemDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Account, newItem: Account) = - oldItem.id == newItem.id - - override fun areContentsTheSame(oldItem: Account, newItem: Account) = - oldItem == newItem -} - -/** - * RecyclerView adapter for displaying account items. - */ -internal class BasicAccountAdapter( - private val onAccountSelected: (Account) -> Unit, -) : ListAdapter(AccountItemDiffCallback) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder { - val view = LayoutInflater - .from(parent.context) - .inflate( - R.layout.mozac_feature_prompts_identity_crendential_account_item, - parent, - false, - ) - return AccountViewHolder(view, onAccountSelected) - } - - override fun onBindViewHolder(holder: AccountViewHolder, position: Int) { - holder.bind(getItem(position)) - } -} - -/** - * View holder for a account item. - */ -internal class AccountViewHolder( - itemView: View, - private val onAccountSelected: (Account) -> Unit, -) : RecyclerView.ViewHolder(itemView), View.OnClickListener { - internal lateinit var account: Account - - init { - itemView.setOnClickListener(this) - } - - fun bind(item: Account) { - account = item - - itemView.findViewById(R.id.fedcm_account_name).text = item.name - - account.icon?.let { - itemView.findViewById(R.id.fedcm_account_icon) - .setImageBitmap(it.base64PngToBitmap()) - } - } - - override fun onClick(v: View?) { - onAccountSelected(account) - } -} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicProvidersAdapter.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicProvidersAdapter.kt deleted file mode 100644 index 6ecbc17f538f..000000000000 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/BasicProvidersAdapter.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package mozilla.components.feature.prompts.identitycredential - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView -import mozilla.components.concept.identitycredential.Provider -import mozilla.components.feature.prompts.R - -private object ProviderItemDiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: Provider, newItem: Provider) = - oldItem.id == newItem.id - - override fun areContentsTheSame(oldItem: Provider, newItem: Provider) = - oldItem == newItem -} - -/** - * RecyclerView adapter for displaying [Provider] items. - */ -internal class BasicProviderAdapter( - private val onlProviderSelected: (Provider) -> Unit, -) : ListAdapter(ProviderItemDiffCallback) { - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProviderViewHolder { - val view = LayoutInflater - .from(parent.context) - .inflate(R.layout.mozac_feature_prompts_identity_crendential_provider_item, parent, false) - return ProviderViewHolder(view, onlProviderSelected) - } - - override fun onBindViewHolder(holder: ProviderViewHolder, position: Int) { - holder.bind(getItem(position)) - } -} - -/** - * View holder for a [Provider] item. - */ -internal class ProviderViewHolder( - itemView: View, - private val onProviderSelected: (Provider) -> Unit, -) : RecyclerView.ViewHolder(itemView), View.OnClickListener { - internal lateinit var provider: Provider - - init { - itemView.setOnClickListener(this) - } - - fun bind(item: Provider) { - provider = item - - (itemView as TextView) - .text = item.name - } - - override fun onClick(v: View?) { - onProviderSelected(provider) - } -} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt new file mode 100644 index 000000000000..3a0f4f549327 --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt @@ -0,0 +1,111 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.feature.prompts.identitycredential + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.Text +import androidx.compose.material.ripple.rememberRipple +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import mozilla.components.ui.colors.PhotonColors + +/** + * List item used to display an IdentityCredentials item that supports clicks + * + * @param title the Title of the item + * @param description The Description of the item. + * @param modifier The modifier to apply to this layout. + * @param onClick Invoked when the item is clicked. + * @param beforeItemContent An optional layout to display before the item. + * + */ +@Composable +internal fun IdentityCredentialItem( + title: String, + description: String, + modifier: Modifier = Modifier, + onClick: () -> Unit, + beforeItemContent: (@Composable () -> Unit)? = null, +) { + // Used to propagate the ripple effect to the whole row + val interactionSource = remember { MutableInteractionSource() } + + Row( + modifier = modifier + .fillMaxWidth() + .clickable( + onClick = onClick, + interactionSource = interactionSource, + indication = rememberRipple(color = PhotonColors.Black), + ) + .padding(horizontal = 16.dp, vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + beforeItemContent?.invoke() + + Column { + Text( + text = title, + style = TextStyle( + fontSize = 16.sp, + lineHeight = 24.sp, + color = PhotonColors.DarkGrey90, + letterSpacing = 0.15.sp, + ), + maxLines = 1, + ) + + Text( + text = description, + style = TextStyle( + fontSize = 14.sp, + lineHeight = 20.sp, + color = PhotonColors.DarkGrey05, + letterSpacing = 0.25.sp, + ), + maxLines = 1, + ) + } + } +} + +@Composable +@Preview(name = "Provider with no favicon") +private fun ProviderItemPreview() { + IdentityCredentialItem( + modifier = Modifier.background(Color.White), + title = "Title", + description = "Description", + onClick = {}, + ) +} + +@Composable +@Preview(name = "Provider with a start-spacer") +private fun ProviderItemPreviewWithSpacer() { + IdentityCredentialItem( + modifier = Modifier.background(Color.White), + title = "Title", + description = "Description", + onClick = {}, + ) { + Spacer(modifier = Modifier.size(24.dp)) + } +} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt new file mode 100644 index 000000000000..c92fc1bf0891 --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt @@ -0,0 +1,165 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.feature.prompts.identitycredential + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import mozilla.components.concept.identitycredential.Account +import mozilla.components.concept.identitycredential.Provider +import mozilla.components.feature.prompts.R +import mozilla.components.support.ktx.kotlin.base64PngToBitmap +import mozilla.components.ui.colors.PhotonColors + +/** + * A Federated Credential Management dialog for selecting an account. + * + * @param provider The [Provider] on which the user is logging in. + * @param accounts The list of available accounts for this provider. + * @param modifier [Modifier] to be applied to the layout. + * @param onAccountClick Invoked when the user clicks on an item. + */ +@Composable +fun SelectAccountDialog( + provider: Provider, + accounts: List, + modifier: Modifier = Modifier, + onAccountClick: (Account) -> Unit, +) { + Column( + modifier = modifier.fillMaxWidth(), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(16.dp), + ) { + provider.icon?.base64PngToBitmap()?.asImageBitmap()?.let { + Image( + bitmap = it, + contentDescription = null, + contentScale = ContentScale.FillWidth, + modifier = Modifier + .size(16.dp), + ) + + Spacer(Modifier.width(4.dp)) + } + + Text( + text = stringResource( + id = R.string.mozac_feature_prompts_identity_credentials_choose_account_for_provider, + provider.name, + ), + style = TextStyle( + fontSize = 16.sp, + lineHeight = 24.sp, + color = PhotonColors.DarkGrey90, + letterSpacing = 0.15.sp, + ), + ) + } + + accounts.forEach { account -> + AccountItem(account = account, onClick = onAccountClick) + } + + Spacer(modifier = Modifier.height(16.dp)) + } +} + +@Composable +private fun AccountItem( + account: Account, + modifier: Modifier = Modifier, + onClick: (Account) -> Unit, +) { + IdentityCredentialItem( + title = account.name, + description = account.email, + modifier = modifier, + onClick = { onClick(account) }, + ) { + account.icon?.base64PngToBitmap()?.asImageBitmap()?.let { bitmap -> + Image( + bitmap = bitmap, + contentDescription = null, + contentScale = ContentScale.FillWidth, + modifier = Modifier + .padding(horizontal = 16.dp) + .size(32.dp), + ) + } ?: Spacer( + Modifier + .padding(horizontal = 16.dp) + .width(32.dp), + ) + } +} + +@Composable +@Preview(name = "Provider with no favicon") +private fun AccountItemPreview() { + AccountItem( + modifier = Modifier.background(Color.White), + account = Account( + 0, + "user@mozilla.com", + "User", + USER_PICTURE, + ), + onClick = {}, + ) +} + +@Composable +@Preview +private fun SelectAccountDialogPreview() { + SelectAccountDialog( + provider = Provider(0, GOOGLE_FAVICON, "Google", "google.com"), + accounts = listOf( + Account( + 0, + "user@mozilla.com", + "User", + USER_PICTURE, + ), + Account( + 1, + "user2@mozilla.com", + "Google", + null, + ), + ), + modifier = Modifier.background(Color.White), + onAccountClick = { }, + ) +} + +@Suppress("MaxLineLength") +private const val GOOGLE_FAVICON = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAARCAYAAADUryzEAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAH+SURBVHgBhVO/b9NQEL5z7Bi1lWJUCYRYHBaWDh6SKhspAYnRoVO3SqxIbiUGEEIRQ1kbxB9AM7VISJiNoSUeI6DCYmSpt1ZUak2U0GLXuZ7dOnUsp73l+e593/343hkhZYePKqp/EhhAoLOrRkEEmwgd/mrd3PpmJvGYdPbvl1cJYQkuMQI085KwfP1Lxwl9Mb74Uyu/J4BFuMIEoKp/HCixHyXYf1BqEF2QuS13gPQ2P1OyQt//ta0CYgOBFApg7ob13R5ij9rX1P67uzuDv/k45ASBMHfLOmsxabvVipqOo78pNZls/Nu8Df7vAgRBrphFHmfhCPeEggdT8zvg2dNrk8/2Rsi1N12dx1OyyIjghgnUOCBrB5/TIAJhNYkZuSNwBT4vsiNlVrrEFJHf3UE6q7DtTfO5N4Jg5W3u1Um0pPBza+eeE4nIH8aHozvQ7M+4J3JQtOumO65kbaU33BfWwOK9IPN5dzYkRy1JntAYR3640tOSy8YatKJVLm3Mt/moJrAWEL7+sfDRCp3qJ13peYIxsft0SezPxjo5X19OFaMEGgOk/7mflK12OM5QXPlAB/mwDjjA+tarSXP4M1XWdXVCLrS7Xi8ryUhCsV9a7jx5sRbpkL4trz9eJBQMnlBLExncypHU7CxsOHEQx5WJ5j4WoyQiiE6SlLRTu5e/Z+DrlXsAAAAASUVORK5CYII=" + +@Suppress("MaxLineLength") +private const val USER_PICTURE = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAtfSURBVHgBnVdbbFv1Gf/Z52If28c+dnyLndgnl15D2iRNadrSNoUxAkgjTCBg08T6hrYHyrQXNE2UbdK0p5WnsT3Rt0p74DJQkabSZlxWCr3RdM2N1Ekcx3cf34/tc4732WiVmDpAi2Qlsezzff/v+93+JnzHn9nZWYnTq7O6YRxrqo0xk4mRg8F+yTDaaDYbisMhxSx2x3WfLzDXQuOtU6dOKd/luaZv+8DM9JTMW/gXXc6en8LMSI1mHWq9DrQN+Hx9YFm20wDMZgYw84hGBmG022ibzW9YbeZXX3755dj/1cDs9LRUN+qvaK3WSYblEQiGIPb4UFNrKBZyYM1m+AMRWK02qNUyqoUkBI6FzR2EwQjwB4NgWAuaevu0JoivnnrpxD0nYr538SlZNzWv8Qx7stNjm95rtFpgrQ44Pb2wii7oZhNcHh9EpwtGQ4GoZ6CXNwFlDVbeDLWpo6RWYZiNk1yrfu3U7/8k36sW899v/OxHT495fcFzkscrO0QnTVqnT7GwO50wTG3YnG7wdGrCALzeIDjOAqa8ilx6i1ahQ6moiAYlpDQWhpWBYLXAzFkk3dBmD91/eO7DDz9I/s8GZqbGZKvDeY7nGNnh8cLEcmgaBn2KAW+hBzEcbA4PgoEQ7DYRvGCnJnxobFzCRjwLtWGg0WzC0Ktw9IRRbrSgai3ksxlwbUj5XHbG5w2+vbKycHcd7H/+mJ4ek9SqcWFifK/cpkMvxTOwOkSIHgb52CLsNPZQWAZnFZGi025trEIe3oUjE8NYOVeCUmyCZXR0+q1Wq9gXFmGRp2CihxlNDRwdIpNKyt6A78IzzzwxfuLEV5i42wCqxisWwSZfuXoF49u9eGhPCDfWCHAtwOHyYWjbKNzuHsTia9hMrMMheVEvl6DGL0OnUzPmNvRWZ1gManU6gaFBDofgcDhQq9VgF2wYHh5CrVKSTTBeoYov3V3B1NhO2WQ2neU5Di3DBJvkRyaTwfcO7UR/wNM9XZBOrxTLuLO2BDeNXXK5EXTbYMlcRTpfpoJm1MoNWEkX7E4bJg5M4p0338TNG1dxZ2URiXiMfi/gy6UF5ArKlFsSz8zPzyvdBsLR6B9FURrroJ2hPavgqYAL6VQSOyIeHD2wC5OyFVG/gEy+BJNWR1Qy40CfgWuXPkYLApIZ0gdFJSoKNB0HgqEeCK4gPpi7iEq9SnQVsHTrChbmr2Bp8RbSWxumza30+8w08V3Xcdbl9qFKAlMoKSgoReJ8LwJ0Qq1agFsU0COaEe4N4Mj+/ZgeC2Hfdg8qW/OY+/gaYUXCnfUCWrTrjjKabAxabRajI8NYIHB2GNRPApXL5dDUDNRpZevJzM4yTH9mdV2f5fgOVfguvZLpTdRVAtQtKyZGZuCylBHqj0Bga2hXU2jVV9FRw1w6geRWGuFIH67djqParMDrFlBp6JjaF0CiUMJQr9jVBCcBuEp4qdVIsOhVVMoolUsSB32WtYnSMaI3iQ3tzuUhcfGj1+bs0q5S03Hg0afgMNN4N28CvB1NmlA2X8BmqoxclYdTcqPNV8HyTdhEBv1hK8qpLzE2KGMg2ofJPbtRUFkUiIolRUGrpRNd65g8PIFAKHiMfeDYzNjy8jzamgYrIdUpEvWcEiqVCoxWg0YGlLKrKKXpy80E0aaOIjVWbwCC04eA6McPiB0bGxu48sUKgd9As1LG9sB9xH0Vh/dsx7ufLGJ1dQEKTUGnOirpg6OjIR7PGOshxQOBoF6t0O7z1GELxVIZ5WIaIwNTqObTSN34HAyBq5hcIHES0DIJqGom0gQelVIBZpMJQ+Ee0MSJ6ylEfHQIdwCVxE2EXINIx26iWiyQqhpdBdV0DXMffATh0mWZXVmal5Jb67QDeqDF2pWEdCZB/DRgI5VYu/we4mtxOB08NHK8ldvLyClV+L1eEikvzBZijULqqhFWiLIj2/sw2OclCzHDYu9BKrZKwpWEw07PJnxUyjVomk56UCMdqUisXaCh1io0BB0i0wOfP0hfJi1gqNtcEklzGW6ngFI+gfNXV/HpigKWHM+9uowBXxxyrws8b4KVtHYjHoeFZDjsD8A7OAzOvxvZW/+g6dnIJ7SOpXSx1iYr76yqTWJlvm/bbqUvHCWV89ODBKptQl84QibD4pObC9g+so8ewON2LIv5LRqP1YWwy4L+HpF2rSC2vo5cJglVraNJrxYdJJ+Oo6VsUkEGh48ch42jE9dJrKi4QWsQSeL7w30YHxtXWLVciR2ePDR24fJH3WChtZoEQg9UwYWnH5mCvHs/gbFJjV3HzOQwMUNFu1FEs14CRzqRLRZpYla4nA5IPcNgmgVkie+h4jptgSgYlHF4YhTnb6ySXrjh9bUQ9Pq7IPRJnhjzwNEHD+4e2jam6QZWCKktKuYk/f7xE4/gwPgY1MImSpuLqFSb0CnpmIwqMSRLKcEgqvLw+0VEdoyibh9C77ZJcLT7jeWr8NpbCO08AsY9gB2DUSgN8griEEcOayO9iYT8GJZD77Ora3cuSoL9+am9E1iiBjL5DJ6aOYJtfh5K4l+o0P+KboFKWs/RnvcceZhKU9hQcsSALLjGJoK7D8IeHkfAG0DquooW7bdAvtDZu7VRgoOoHSB1zDts2LuTGg30wE/pSlObc8zIyM7YnbWtFyLhPuuAvA11SwBOYmZZyYCRImiLvVhYJaWrlLBj+ocwu0NdtjjDQ3CRXPOuQHevZvL9RrlAehFHYWuRdKUBv4uHKxilqGhFYW0BZ989T4ewkXNyuL2yCs7hPtHNhA89+OjpaLj/RZ3Q+bdz76Bf3olf/vq3IMcihyuS3daQWJknbDioWIPyIIki0S5J1iwQi+yip5sDGAqoxcQK2tkvoNfzCLhE3H//fgw9/iuiXAEv/PwX+Oh2gr5jQTK5+YZSUk903XBHdHjBYM0n+/oHEd+IYTASAjEPhloEQwU5E/k7acDHc3O49vln5Acl2GwcWHpfsNm7GeArerW7oZUnBWyS4Xg8bvT4I3CFd8PmCeHw3p04MOCGxDRwaXHtSVXVvrLjldiKsue+UbemN6dG9+7D+p1lpMm/K9kEaiQy5cwGFuevIyjxOHRwEgMDMiyUHSw8S/RqIpVMUgxnUFV1AirgpDim1XLknkECNWUxT5BknidtaZAy6tg3Mvjab/7y3tmvZUKf33uJxOhZXdek0fFJNIopCIzW3WUniDhFQq4c7Y46m02hohTI2VTyemogW0AimUeR1A2MBSwF1VAoAq3DfVaCpV0j2jEwtRSoZSVmZqrP/eHMRbVT92v3gunpGRnt5oVIdFiW5QHafQWRvih6JB/OvfdXVGis8a0kzESjo0cPIbX4z65rGkTh9fVNckSB3FFCb9AHod3C/bsG0CtZ4bAYBM5VygXumDscPd57/KXYPVNxjFbhc3vnElvxmeWFm1JHWjWDpVMSpRpqd8ciaUQmm8Xg2DHy+DxRqQKny0HaUAf1QVmiTvgQEB6eQKR/gDBA4+fbKNWNmJKvPTn63O8W8E33gkQykdw1IL9NCWVWtNukdDqFpeUFDG0fIRY48dj3H6fg4YGJlNJJ2WGLQGul7G+zW5BO5ij1ZAmUpBlWJzkixXeOTM3KxBgrc3z/T75e/J4NdCcRjytev/dMW2cEXrBMuaig1U45r7cPbl8veoJ9ECUP3Y5YLN++TVige4DNSoCkSFcg2zWx2P/Aw90swfHsaz67+Ny2h08k71XrWy+nszPPyg6v8xTHm563251d2nUuombBiYA8jE///ibUGtGS10gfdHz2yWViB6ccnH70jGESTr/++unYNz3/Wxu42whdz3NpZZbuiNNk/nt9kV3y1EOPSXfmP0OjXlUa5XTM7XZcv3Tx/Fy5xbwVi8W+0/X83zizJdeTv85mAAAAAElFTkSuQmCC" diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt index 163fd30d8827..696dc8304aec 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt @@ -8,37 +8,45 @@ import android.annotation.SuppressLint import android.app.Dialog import android.content.DialogInterface import android.os.Bundle -import android.view.LayoutInflater import android.view.View import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView import mozilla.components.concept.identitycredential.Account import mozilla.components.concept.identitycredential.Provider -import mozilla.components.feature.prompts.R +import mozilla.components.feature.prompts.dialog.AlertDialogFragment import mozilla.components.feature.prompts.dialog.KEY_PROMPT_UID import mozilla.components.feature.prompts.dialog.KEY_SESSION_ID import mozilla.components.feature.prompts.dialog.KEY_SHOULD_DISMISS_ON_LOAD import mozilla.components.feature.prompts.dialog.PromptDialogFragment import mozilla.components.support.utils.ext.getParcelableArrayListCompat +import mozilla.components.support.utils.ext.getParcelableCompat private const val KEY_ACCOUNTS = "KEY_ACCOUNTS" +private const val KEY_PROVIDER = "KEY_PROVIDER" /** * A Federated Credential Management dialog for selecting an account. */ internal class SelectAccountDialogFragment : PromptDialogFragment() { - private lateinit var listAdapter: BasicAccountAdapter internal val accounts: List by lazy { safeArguments.getParcelableArrayListCompat(KEY_ACCOUNTS, Account::class.java) ?: emptyList() } + internal val provider: Provider by lazy { + requireNotNull( + safeArguments.getParcelableCompat( + KEY_PROVIDER, + Provider::class.java, + ), + ) + } + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = AlertDialog.Builder(requireContext()) .setCancelable(true) - .setTitle(R.string.mozac_feature_prompts_identity_credentials_choose_account) .setView(createDialogContentView()) .create() @@ -49,20 +57,15 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { @SuppressLint("InflateParams") internal fun createDialogContentView(): View { - val view = LayoutInflater.from(requireContext()) - .inflate(R.layout.mozac_feature_prompts_choose_identity_account_dialog, null) - - setupRecyclerView(view) - return view - } - - private fun setupRecyclerView(view: View) { - listAdapter = BasicAccountAdapter(this::onAccountChange) - view.findViewById(R.id.recyclerView).apply { - layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) - adapter = listAdapter + return ComposeView(requireContext()).apply { + setContent { + SelectAccountDialog( + provider = provider, + accounts = accounts, + onAccountClick = ::onAccountChange, + ) + } } - listAdapter.submitList(accounts) } /** @@ -75,10 +78,20 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { } companion object { + + /** + * A builder method for creating a [SelectAccountDialogFragment] + * @param sessionId The id of the session for which this dialog will be created. + * @param promptRequestUID Identifier of the [PromptRequest] for which this dialog is shown. + * @param accounts The list of available accounts. + * @param provider The provider on which the user is logging in. + * @param shouldDismissOnLoad Whether or not the dialog should automatically be dismissed when a new page is loaded. + */ fun newInstance( sessionId: String, promptRequestUID: String, accounts: List, + provider: Provider, shouldDismissOnLoad: Boolean, ) = SelectAccountDialogFragment().apply { arguments = (arguments ?: Bundle()).apply { @@ -86,6 +99,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { putString(KEY_PROMPT_UID, promptRequestUID) putBoolean(KEY_SHOULD_DISMISS_ON_LOAD, shouldDismissOnLoad) putParcelableArrayList(KEY_ACCOUNTS, ArrayList(accounts)) + putParcelable(KEY_PROVIDER, provider) } } } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt new file mode 100644 index 000000000000..69ce3bf4d53e --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt @@ -0,0 +1,131 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.feature.prompts.identitycredential + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import mozilla.components.concept.identitycredential.Provider +import mozilla.components.feature.prompts.R +import mozilla.components.support.ktx.kotlin.base64PngToBitmap +import mozilla.components.ui.colors.PhotonColors + +/** + * A Federated Credential Management dialog for selecting a provider. + */ +@Composable +fun SelectProviderDialog( + providers: List, + modifier: Modifier = Modifier, + onProviderClick: (Provider) -> Unit, +) { + Column( + modifier = modifier.fillMaxWidth(), + ) { + Text( + text = stringResource(id = R.string.mozac_feature_prompts_identity_credentials_choose_provider), + style = TextStyle( + fontSize = 16.sp, + lineHeight = 24.sp, + color = PhotonColors.DarkGrey90, + letterSpacing = 0.15.sp, + ), + modifier = Modifier.padding(16.dp), + ) + + providers.forEach { provider -> + ProviderItem(provider = provider, onClick = onProviderClick) + } + + Spacer(modifier = Modifier.height(16.dp)) + } +} + +@Composable +private fun ProviderItem( + provider: Provider, + modifier: Modifier = Modifier, + onClick: (Provider) -> Unit, +) { + IdentityCredentialItem( + title = provider.name, + description = provider.domain, + modifier = modifier, + onClick = { onClick(provider) }, + ) { + provider.icon?.base64PngToBitmap()?.asImageBitmap()?.let { bitmap -> + Image( + bitmap = bitmap, + contentDescription = null, + contentScale = ContentScale.FillWidth, + modifier = Modifier + .padding(horizontal = 16.dp) + .size(24.dp), + ) + } ?: Spacer( + Modifier + .padding(horizontal = 16.dp) + .width(24.dp), + ) + } +} + +@Composable +@Preview(name = "Provider with no favicon") +private fun ProviderItemPreview() { + ProviderItem( + modifier = Modifier.background(Color.White), + provider = Provider( + 0, + null, + "Title", + "Description", + ), + onClick = {}, + ) +} + +@Composable +@Preview +private fun SelectProviderDialogPreview() { + SelectProviderDialog( + providers = listOf( + Provider( + 0, + null, + "Title", + "Description", + ), + Provider( + 0, + GOOGLE_FAVICON, + "Google", + "google.com", + ), + ), + modifier = Modifier.background(Color.White), + ) { } +} + +@Suppress("MaxLineLength") +private const val GOOGLE_FAVICON = + "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAARCAYAAADUryzEAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAH+SURBVHgBhVO/b9NQEL5z7Bi1lWJUCYRYHBaWDh6SKhspAYnRoVO3SqxIbiUGEEIRQ1kbxB9AM7VISJiNoSUeI6DCYmSpt1ZUak2U0GLXuZ7dOnUsp73l+e593/343hkhZYePKqp/EhhAoLOrRkEEmwgd/mrd3PpmJvGYdPbvl1cJYQkuMQI085KwfP1Lxwl9Mb74Uyu/J4BFuMIEoKp/HCixHyXYf1BqEF2QuS13gPQ2P1OyQt//ta0CYgOBFApg7ob13R5ij9rX1P67uzuDv/k45ASBMHfLOmsxabvVipqOo78pNZls/Nu8Df7vAgRBrphFHmfhCPeEggdT8zvg2dNrk8/2Rsi1N12dx1OyyIjghgnUOCBrB5/TIAJhNYkZuSNwBT4vsiNlVrrEFJHf3UE6q7DtTfO5N4Jg5W3u1Um0pPBza+eeE4nIH8aHozvQ7M+4J3JQtOumO65kbaU33BfWwOK9IPN5dzYkRy1JntAYR3640tOSy8YatKJVLm3Mt/moJrAWEL7+sfDRCp3qJ13peYIxsft0SezPxjo5X19OFaMEGgOk/7mflK12OM5QXPlAB/mwDjjA+tarSXP4M1XWdXVCLrS7Xi8ryUhCsV9a7jx5sRbpkL4trz9eJBQMnlBLExncypHU7CxsOHEQx5WJ5j4WoyQiiE6SlLRTu5e/Z+DrlXsAAAAASUVORK5CYII=" diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt index 6cec1297c24f..317d743c37f0 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt @@ -8,14 +8,11 @@ import android.annotation.SuppressLint import android.app.Dialog import android.content.DialogInterface import android.os.Bundle -import android.view.LayoutInflater import android.view.View import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView +import androidx.compose.ui.platform.ComposeView import mozilla.components.concept.identitycredential.Provider -import mozilla.components.feature.prompts.R import mozilla.components.feature.prompts.dialog.KEY_PROMPT_UID import mozilla.components.feature.prompts.dialog.KEY_SESSION_ID import mozilla.components.feature.prompts.dialog.KEY_SHOULD_DISMISS_ON_LOAD @@ -29,16 +26,14 @@ private const val KEY_PROVIDERS = "KEY_PROVIDERS" */ internal class SelectProviderDialogFragment : PromptDialogFragment() { - private lateinit var listAdapter: BasicProviderAdapter - - internal val providers: List by lazy { - safeArguments.getParcelableArrayListCompat(KEY_PROVIDERS, Provider::class.java) ?: emptyList() + private val providers: List by lazy { + safeArguments.getParcelableArrayListCompat(KEY_PROVIDERS, Provider::class.java) + ?: emptyList() } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = AlertDialog.Builder(requireContext()) .setCancelable(true) - .setTitle(R.string.mozac_feature_prompts_identity_credentials_choose_provider) .setView(createDialogContentView()) .create() @@ -49,21 +44,14 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { @SuppressLint("InflateParams") internal fun createDialogContentView(): View { - val view = LayoutInflater - .from(requireContext()) - .inflate(R.layout.mozac_feature_prompts_choose_identity_provider_dialogs, null) - - setupRecyclerView(view) - return view - } - - private fun setupRecyclerView(view: View) { - listAdapter = BasicProviderAdapter(this::onProviderChange) - view.findViewById(R.id.recyclerView).apply { - layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) - adapter = listAdapter + return ComposeView(requireContext()).apply { + setContent { + SelectProviderDialog( + providers = providers, + onProviderClick = ::onProviderChange, + ) + } } - listAdapter.submitList(providers) } /** @@ -76,6 +64,14 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { } companion object { + + /** + * A builder method for creating a [SelectAccountDialogFragment] + * @param sessionId The id of the session for which this dialog will be created. + * @param promptRequestUID Identifier of the [PromptRequest] for which this dialog is shown. + * @param providers The list of available providers. + * @param shouldDismissOnLoad Whether or not the dialog should automatically be dismissed when a new page is loaded. + */ fun newInstance( sessionId: String, promptRequestUID: String, diff --git a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_account_dialog.xml b/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_account_dialog.xml deleted file mode 100644 index 7c7e329fb887..000000000000 --- a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_account_dialog.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_provider_dialogs.xml b/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_provider_dialogs.xml deleted file mode 100644 index 7c7e329fb887..000000000000 --- a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_choose_identity_provider_dialogs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_account_item.xml b/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_account_item.xml deleted file mode 100644 index 2ec4eae9d751..000000000000 --- a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_account_item.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_provider_item.xml b/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_provider_item.xml deleted file mode 100644 index e9e48f7ad6f6..000000000000 --- a/android-components/components/feature/prompts/src/main/res/layout/mozac_feature_prompts_identity_crendential_provider_item.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/android-components/components/feature/prompts/src/main/res/values/strings.xml b/android-components/components/feature/prompts/src/main/res/values/strings.xml index 0c03fc0694ad..8a5f28996ba4 100644 --- a/android-components/components/feature/prompts/src/main/res/values/strings.xml +++ b/android-components/components/feature/prompts/src/main/res/values/strings.xml @@ -135,9 +135,13 @@ Choose a login provider - Choose an account + Choose an account + + Sign in with a %1$s account Use %1$s as a login provider Privacy Policy and Terms of Service]]> + + Continue From bb9e14e52edc674ed58c2e2a754a459f2ebef827 Mon Sep 17 00:00:00 2001 From: Titouan Thibaud Date: Wed, 30 Aug 2023 12:20:29 -0300 Subject: [PATCH 2/5] Bug 1847784: Provide a Theme to FedCM Provider Dialog --- .../feature/prompts/PromptFeature.kt | 8 ++++ .../IdentityCredentialColors.kt | 25 ++++++++++++ .../IdentityCredentialDefaults.kt | 39 +++++++++++++++++++ .../IdentityCredentialItem.kt | 10 ++--- .../identitycredential/SelectAccountDialog.kt | 12 +++++- .../SelectAccountDialogFragment.kt | 6 +++ .../SelectProviderDialog.kt | 15 ++++++- .../SelectProviderDialogFragment.kt | 6 +++ .../fenix/browser/BaseBrowserFragment.kt | 14 +++++++ 9 files changed, 126 insertions(+), 9 deletions(-) create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt index 73e0050f3b8c..52a1094efdfc 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt @@ -76,6 +76,9 @@ import mozilla.components.feature.prompts.facts.emitPromptDisplayedFact import mozilla.components.feature.prompts.facts.emitSuccessfulAddressAutofillFormDetectedFact import mozilla.components.feature.prompts.facts.emitSuccessfulCreditCardAutofillFormDetectedFact import mozilla.components.feature.prompts.file.FilePicker +import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColors +import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColorsProvider +import mozilla.components.feature.prompts.identitycredential.IdentityCredentialDefaults import mozilla.components.feature.prompts.identitycredential.PrivacyPolicyDialogFragment import mozilla.components.feature.prompts.identitycredential.SelectAccountDialogFragment import mozilla.components.feature.prompts.identitycredential.SelectProviderDialogFragment @@ -154,6 +157,7 @@ class PromptFeature private constructor( private val store: BrowserStore, private var customTabId: String?, private val fragmentManager: FragmentManager, + private val identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { IdentityCredentialDefaults.colors() }, private val tabsUseCases: TabsUseCases, private val shareDelegate: ShareDelegate, private val exitFullscreenUsecase: ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, @@ -197,6 +201,7 @@ class PromptFeature private constructor( customTabId: String? = null, fragmentManager: FragmentManager, tabsUseCases: TabsUseCases, + identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { IdentityCredentialDefaults.colors() }, shareDelegate: ShareDelegate = DefaultShareDelegate(), exitFullscreenUsecase: ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, creditCardValidationDelegate: CreditCardValidationDelegate? = null, @@ -215,6 +220,7 @@ class PromptFeature private constructor( customTabId = customTabId, fragmentManager = fragmentManager, tabsUseCases = tabsUseCases, + identityCredentialColorsProvider = identityCredentialColorsProvider, shareDelegate = shareDelegate, exitFullscreenUsecase = exitFullscreenUsecase, creditCardValidationDelegate = creditCardValidationDelegate, @@ -912,6 +918,7 @@ class PromptFeature private constructor( promptRequestUID = promptRequest.uid, shouldDismissOnLoad = true, providers = promptRequest.providers, + colorsProvider = identityCredentialColorsProvider ) } @@ -922,6 +929,7 @@ class PromptFeature private constructor( shouldDismissOnLoad = true, accounts = promptRequest.accounts, provider = promptRequest.provider, + colorsProvider = identityCredentialColorsProvider ) } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt new file mode 100644 index 000000000000..80f343de7b68 --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.feature.prompts.identitycredential + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +/** + * Represents the colors used by the IdentityCredential dialogs. + */ +data class IdentityCredentialColors( + val title: Color, + val description: Color, + val ripple: Color, +) + +/** + * An [IdentityCredentialColorsProvider] implementation can provide an [IdentityCredentialColors] + */ +fun interface IdentityCredentialColorsProvider { + @Composable + fun provideColors(): IdentityCredentialColors +} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt new file mode 100644 index 000000000000..5d28eec49eaa --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.feature.prompts.identitycredential + +import androidx.compose.material.ContentAlpha +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +/** + * Contains the default values used by the IdentityCredential dialogs. + */ +object IdentityCredentialDefaults { + + /** + * Creates an [IdentityCredentialColors] that represents the default colors used in an + * IdentityCredential dialog. + * + * @param background The background of the AwesomeBar. + * @param title The text color for the title of a suggestion. + * @param description The text color for the description of a suggestion. + */ + @Composable + fun colors( + title: Color = MaterialTheme.colors.onBackground, + description: Color = MaterialTheme.colors.onBackground.copy( + alpha = ContentAlpha.medium, + ), + ripple: Color = Color.Cyan, + ) = IdentityCredentialColors( + title, + description, + ripple, + ) + + fun provider() = IdentityCredentialColorsProvider { colors() } +} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt index 3a0f4f549327..f63073f78a1e 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt @@ -24,10 +24,9 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import mozilla.components.ui.colors.PhotonColors /** - * List item used to display an IdentityCredentials item that supports clicks + * List item used to display an IdentityCredential item that supports clicks * * @param title the Title of the item * @param description The Description of the item. @@ -41,6 +40,7 @@ internal fun IdentityCredentialItem( title: String, description: String, modifier: Modifier = Modifier, + colors: IdentityCredentialColors = IdentityCredentialDefaults.colors(), onClick: () -> Unit, beforeItemContent: (@Composable () -> Unit)? = null, ) { @@ -53,7 +53,7 @@ internal fun IdentityCredentialItem( .clickable( onClick = onClick, interactionSource = interactionSource, - indication = rememberRipple(color = PhotonColors.Black), + indication = rememberRipple(color = colors.ripple), ) .padding(horizontal = 16.dp, vertical = 6.dp), verticalAlignment = Alignment.CenterVertically, @@ -66,7 +66,7 @@ internal fun IdentityCredentialItem( style = TextStyle( fontSize = 16.sp, lineHeight = 24.sp, - color = PhotonColors.DarkGrey90, + color = colors.title, letterSpacing = 0.15.sp, ), maxLines = 1, @@ -77,7 +77,7 @@ internal fun IdentityCredentialItem( style = TextStyle( fontSize = 14.sp, lineHeight = 20.sp, - color = PhotonColors.DarkGrey05, + color = colors.description, letterSpacing = 0.25.sp, ), maxLines = 1, diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt index c92fc1bf0891..408597c3e769 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt @@ -36,6 +36,7 @@ import mozilla.components.ui.colors.PhotonColors * A Federated Credential Management dialog for selecting an account. * * @param provider The [Provider] on which the user is logging in. + * @param colorsProvider Provides [IdentityCredentialColors] that define the colors of the dialog * @param accounts The list of available accounts for this provider. * @param modifier [Modifier] to be applied to the layout. * @param onAccountClick Invoked when the user clicks on an item. @@ -43,10 +44,13 @@ import mozilla.components.ui.colors.PhotonColors @Composable fun SelectAccountDialog( provider: Provider, + colorsProvider: IdentityCredentialColorsProvider, accounts: List, modifier: Modifier = Modifier, onAccountClick: (Account) -> Unit, ) { + val colors = colorsProvider.provideColors() + Column( modifier = modifier.fillMaxWidth(), ) { @@ -74,14 +78,14 @@ fun SelectAccountDialog( style = TextStyle( fontSize = 16.sp, lineHeight = 24.sp, - color = PhotonColors.DarkGrey90, + color = colors.title, letterSpacing = 0.15.sp, ), ) } accounts.forEach { account -> - AccountItem(account = account, onClick = onAccountClick) + AccountItem(account = account, colors = colors, onClick = onAccountClick) } Spacer(modifier = Modifier.height(16.dp)) @@ -91,12 +95,14 @@ fun SelectAccountDialog( @Composable private fun AccountItem( account: Account, + colors: IdentityCredentialColors, modifier: Modifier = Modifier, onClick: (Account) -> Unit, ) { IdentityCredentialItem( title = account.name, description = account.email, + colors = colors, modifier = modifier, onClick = { onClick(account) }, ) { @@ -128,6 +134,7 @@ private fun AccountItemPreview() { "User", USER_PICTURE, ), + colors = IdentityCredentialDefaults.colors(), onClick = {}, ) } @@ -152,6 +159,7 @@ private fun SelectAccountDialogPreview() { ), ), modifier = Modifier.background(Color.White), + colorsProvider = IdentityCredentialDefaults.provider(), onAccountClick = { }, ) } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt index 696dc8304aec..8356ee039a1a 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt @@ -35,6 +35,8 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { safeArguments.getParcelableArrayListCompat(KEY_ACCOUNTS, Account::class.java) ?: emptyList() } + private var colorsProvider: IdentityCredentialColorsProvider = IdentityCredentialDefaults.provider() + internal val provider: Provider by lazy { requireNotNull( safeArguments.getParcelableCompat( @@ -62,6 +64,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { SelectAccountDialog( provider = provider, accounts = accounts, + colorsProvider = colorsProvider, onAccountClick = ::onAccountChange, ) } @@ -86,6 +89,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { * @param accounts The list of available accounts. * @param provider The provider on which the user is logging in. * @param shouldDismissOnLoad Whether or not the dialog should automatically be dismissed when a new page is loaded. + * @param colorsProvider Provides [IdentityCredentialColors] that define the colors in the Dialog */ fun newInstance( sessionId: String, @@ -93,6 +97,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { accounts: List, provider: Provider, shouldDismissOnLoad: Boolean, + colorsProvider: IdentityCredentialColorsProvider ) = SelectAccountDialogFragment().apply { arguments = (arguments ?: Bundle()).apply { putString(KEY_SESSION_ID, sessionId) @@ -101,6 +106,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { putParcelableArrayList(KEY_ACCOUNTS, ArrayList(accounts)) putParcelable(KEY_PROVIDER, provider) } + this.colorsProvider = colorsProvider } } } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt index 69ce3bf4d53e..65f53e03fa3e 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt @@ -31,13 +31,20 @@ import mozilla.components.ui.colors.PhotonColors /** * A Federated Credential Management dialog for selecting a provider. + * @param providers The list of available providers. + * @param colorsProvider Provides [IdentityCredentialColors] that define the colors of the dialog + * @param modifier [Modifier] to be applied to the layout. + * @param onProviderClick Called when the user clicks on an item. */ @Composable fun SelectProviderDialog( providers: List, + colorsProvider: IdentityCredentialColorsProvider, modifier: Modifier = Modifier, onProviderClick: (Provider) -> Unit, ) { + val colors = colorsProvider.provideColors() + Column( modifier = modifier.fillMaxWidth(), ) { @@ -46,14 +53,14 @@ fun SelectProviderDialog( style = TextStyle( fontSize = 16.sp, lineHeight = 24.sp, - color = PhotonColors.DarkGrey90, + color = colors.title, letterSpacing = 0.15.sp, ), modifier = Modifier.padding(16.dp), ) providers.forEach { provider -> - ProviderItem(provider = provider, onClick = onProviderClick) + ProviderItem(provider = provider, onClick = onProviderClick, colors = colors) } Spacer(modifier = Modifier.height(16.dp)) @@ -64,12 +71,14 @@ fun SelectProviderDialog( private fun ProviderItem( provider: Provider, modifier: Modifier = Modifier, + colors: IdentityCredentialColors, onClick: (Provider) -> Unit, ) { IdentityCredentialItem( title = provider.name, description = provider.domain, modifier = modifier, + colors = colors, onClick = { onClick(provider) }, ) { provider.icon?.base64PngToBitmap()?.asImageBitmap()?.let { bitmap -> @@ -100,6 +109,7 @@ private fun ProviderItemPreview() { "Title", "Description", ), + colors = IdentityCredentialDefaults.colors(), onClick = {}, ) } @@ -123,6 +133,7 @@ private fun SelectProviderDialogPreview() { ), ), modifier = Modifier.background(Color.White), + colorsProvider = IdentityCredentialDefaults.provider() ) { } } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt index 317d743c37f0..c1a2e23fd225 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt @@ -31,6 +31,8 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { ?: emptyList() } + private var colorsProvider: IdentityCredentialColorsProvider = IdentityCredentialDefaults.provider() + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = AlertDialog.Builder(requireContext()) .setCancelable(true) @@ -49,6 +51,7 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { SelectProviderDialog( providers = providers, onProviderClick = ::onProviderChange, + colorsProvider = colorsProvider ) } } @@ -71,12 +74,14 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { * @param promptRequestUID Identifier of the [PromptRequest] for which this dialog is shown. * @param providers The list of available providers. * @param shouldDismissOnLoad Whether or not the dialog should automatically be dismissed when a new page is loaded. + * @param colorsProvider Provides [IdentityCredentialColors] that define the colors in the Dialog */ fun newInstance( sessionId: String, promptRequestUID: String, providers: List, shouldDismissOnLoad: Boolean, + colorsProvider: IdentityCredentialColorsProvider ) = SelectProviderDialogFragment().apply { arguments = (arguments ?: Bundle()).apply { putString(KEY_SESSION_ID, sessionId) @@ -84,6 +89,7 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { putBoolean(KEY_SHOULD_DISMISS_ON_LOAD, shouldDismissOnLoad) putParcelableArrayList(KEY_PROVIDERS, ArrayList(providers)) } + this.colorsProvider = colorsProvider } } } diff --git a/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 93756465e368..371d588a5999 100644 --- a/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -22,6 +22,9 @@ import androidx.activity.result.ActivityResultLauncher import androidx.annotation.CallSuper import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.getSystemService import androidx.core.view.isVisible @@ -76,6 +79,8 @@ import mozilla.components.feature.prompts.PromptFeature import mozilla.components.feature.prompts.PromptFeature.Companion.PIN_REQUEST import mozilla.components.feature.prompts.address.AddressDelegate import mozilla.components.feature.prompts.creditcard.CreditCardDelegate +import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColors +import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColorsProvider import mozilla.components.feature.prompts.login.LoginDelegate import mozilla.components.feature.prompts.share.ShareDelegate import mozilla.components.feature.readerview.ReaderViewFeature @@ -669,12 +674,21 @@ abstract class BaseBrowserFragment : view = view, ) + val colorsProvider = IdentityCredentialColorsProvider { + IdentityCredentialColors( + title = ThemeManager.resolveAttributeColor(attribute = R.attr.textPrimary), + description = ThemeManager.resolveAttributeColor(attribute = R.attr.textSecondary), + ripple = ThemeManager.resolveAttributeColor(attribute = R.attr.textSecondary), + ) + } + promptsFeature.set( feature = PromptFeature( activity = activity, store = store, customTabId = customTabSessionId, fragmentManager = parentFragmentManager, + identityCredentialColorsProvider = colorsProvider, tabsUseCases = requireComponents.useCases.tabsUseCases, creditCardValidationDelegate = DefaultCreditCardValidationDelegate( context.components.core.lazyAutofillStorage, From 267cb8d6b1e002810fdc74039ca827b831612c23 Mon Sep 17 00:00:00 2001 From: Titouan Thibaud Date: Wed, 6 Sep 2023 15:17:09 -0300 Subject: [PATCH 3/5] Bug 1842203: First iteration of Theming fixes --- .../feature/prompts/PromptFeature.kt | 6 +-- .../identitycredential/DialogColors.kt | 47 +++++++++++++++++ .../IdentityCredentialColors.kt | 25 --------- .../IdentityCredentialDefaults.kt | 11 ++-- .../IdentityCredentialItem.kt | 34 ++++++------ .../identitycredential/SelectAccountDialog.kt | 10 ++-- .../SelectAccountDialogFragment.kt | 23 ++++---- .../SelectProviderDialog.kt | 52 ++++++++++--------- .../SelectProviderDialogFragment.kt | 19 ++++--- .../fenix/browser/BaseBrowserFragment.kt | 8 ++- 10 files changed, 133 insertions(+), 102 deletions(-) create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt delete mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt index 52a1094efdfc..c946ed57f29f 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt @@ -76,7 +76,7 @@ import mozilla.components.feature.prompts.facts.emitPromptDisplayedFact import mozilla.components.feature.prompts.facts.emitSuccessfulAddressAutofillFormDetectedFact import mozilla.components.feature.prompts.facts.emitSuccessfulCreditCardAutofillFormDetectedFact import mozilla.components.feature.prompts.file.FilePicker -import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColors +import mozilla.components.feature.prompts.identitycredential.DialogColors import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColorsProvider import mozilla.components.feature.prompts.identitycredential.IdentityCredentialDefaults import mozilla.components.feature.prompts.identitycredential.PrivacyPolicyDialogFragment @@ -157,7 +157,7 @@ class PromptFeature private constructor( private val store: BrowserStore, private var customTabId: String?, private val fragmentManager: FragmentManager, - private val identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { IdentityCredentialDefaults.colors() }, + private val identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { DialogColors.default() }, private val tabsUseCases: TabsUseCases, private val shareDelegate: ShareDelegate, private val exitFullscreenUsecase: ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, @@ -201,7 +201,7 @@ class PromptFeature private constructor( customTabId: String? = null, fragmentManager: FragmentManager, tabsUseCases: TabsUseCases, - identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { IdentityCredentialDefaults.colors() }, + identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { DialogColors.default() }, shareDelegate: ShareDelegate = DefaultShareDelegate(), exitFullscreenUsecase: ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, creditCardValidationDelegate: CreditCardValidationDelegate? = null, diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt new file mode 100644 index 000000000000..39747c0441a8 --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt @@ -0,0 +1,47 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package mozilla.components.feature.prompts.identitycredential + +import androidx.compose.material.ContentAlpha +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +/** + * Represents the colors used by the dialogs. + */ +data class DialogColors( + val title: Color, + val description: Color) { + + companion object { + + /** + * Creates an [DialogColors] that represents the default colors used in an + * IdentityCredential dialog. + * + * @param title The text color for the title of a suggestion. + * @param description The text color for the description of a suggestion. + */ + @Composable + fun default( + title: Color = MaterialTheme.colors.onBackground, + description: Color = MaterialTheme.colors.onBackground.copy( + alpha = ContentAlpha.medium, + ) + ) = DialogColors( + title, + description + ) + } +} + +/** + * An [IdentityCredentialColorsProvider] implementation can provide an [DialogColors] + */ +fun interface IdentityCredentialColorsProvider { + @Composable + fun provideColors(): DialogColors +} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt deleted file mode 100644 index 80f343de7b68..000000000000 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialColors.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package mozilla.components.feature.prompts.identitycredential - -import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color - -/** - * Represents the colors used by the IdentityCredential dialogs. - */ -data class IdentityCredentialColors( - val title: Color, - val description: Color, - val ripple: Color, -) - -/** - * An [IdentityCredentialColorsProvider] implementation can provide an [IdentityCredentialColors] - */ -fun interface IdentityCredentialColorsProvider { - @Composable - fun provideColors(): IdentityCredentialColors -} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt index 5d28eec49eaa..1c750be8a6bd 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt @@ -15,10 +15,9 @@ import androidx.compose.ui.graphics.Color object IdentityCredentialDefaults { /** - * Creates an [IdentityCredentialColors] that represents the default colors used in an + * Creates an [DialogColors] that represents the default colors used in an * IdentityCredential dialog. * - * @param background The background of the AwesomeBar. * @param title The text color for the title of a suggestion. * @param description The text color for the description of a suggestion. */ @@ -27,12 +26,10 @@ object IdentityCredentialDefaults { title: Color = MaterialTheme.colors.onBackground, description: Color = MaterialTheme.colors.onBackground.copy( alpha = ContentAlpha.medium, - ), - ripple: Color = Color.Cyan, - ) = IdentityCredentialColors( + ) + ) = DialogColors( title, - description, - ripple, + description ) fun provider() = IdentityCredentialColorsProvider { colors() } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt index f63073f78a1e..e9220289da91 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt @@ -4,16 +4,21 @@ package mozilla.components.feature.prompts.identitycredential +import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors import androidx.compose.material.ripple.rememberRipple import androidx.compose.runtime.Composable import androidx.compose.runtime.remember @@ -40,21 +45,14 @@ internal fun IdentityCredentialItem( title: String, description: String, modifier: Modifier = Modifier, - colors: IdentityCredentialColors = IdentityCredentialDefaults.colors(), + colors: DialogColors = DialogColors.default(), onClick: () -> Unit, beforeItemContent: (@Composable () -> Unit)? = null, ) { - // Used to propagate the ripple effect to the whole row - val interactionSource = remember { MutableInteractionSource() } - Row( modifier = modifier .fillMaxWidth() - .clickable( - onClick = onClick, - interactionSource = interactionSource, - indication = rememberRipple(color = colors.ripple), - ) + .clickable(onClick = onClick) .padding(horizontal = 16.dp, vertical = 6.dp), verticalAlignment = Alignment.CenterVertically, ) { @@ -87,14 +85,18 @@ internal fun IdentityCredentialItem( } @Composable -@Preview(name = "Provider with no favicon") +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Provider with no favicon") +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark - Provider with no favicon") private fun ProviderItemPreview() { - IdentityCredentialItem( - modifier = Modifier.background(Color.White), - title = "Title", - description = "Description", - onClick = {}, - ) + val colors = if (!isSystemInDarkTheme()) lightColors() else darkColors() + MaterialTheme(colors = colors) { + IdentityCredentialItem( + modifier = Modifier.background(MaterialTheme.colors.background), + title = "Title", + description = "Description", + onClick = {}, + ) + } } @Composable diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt index 408597c3e769..4e145854fb02 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt @@ -30,13 +30,12 @@ import mozilla.components.concept.identitycredential.Account import mozilla.components.concept.identitycredential.Provider import mozilla.components.feature.prompts.R import mozilla.components.support.ktx.kotlin.base64PngToBitmap -import mozilla.components.ui.colors.PhotonColors /** * A Federated Credential Management dialog for selecting an account. * * @param provider The [Provider] on which the user is logging in. - * @param colorsProvider Provides [IdentityCredentialColors] that define the colors of the dialog + * @param colors The colors of the dialog. * @param accounts The list of available accounts for this provider. * @param modifier [Modifier] to be applied to the layout. * @param onAccountClick Invoked when the user clicks on an item. @@ -44,12 +43,11 @@ import mozilla.components.ui.colors.PhotonColors @Composable fun SelectAccountDialog( provider: Provider, - colorsProvider: IdentityCredentialColorsProvider, accounts: List, modifier: Modifier = Modifier, + colors: DialogColors = DialogColors.default(), onAccountClick: (Account) -> Unit, ) { - val colors = colorsProvider.provideColors() Column( modifier = modifier.fillMaxWidth(), @@ -95,8 +93,8 @@ fun SelectAccountDialog( @Composable private fun AccountItem( account: Account, - colors: IdentityCredentialColors, modifier: Modifier = Modifier, + colors: DialogColors = DialogColors.default(), onClick: (Account) -> Unit, ) { IdentityCredentialItem( @@ -134,7 +132,6 @@ private fun AccountItemPreview() { "User", USER_PICTURE, ), - colors = IdentityCredentialDefaults.colors(), onClick = {}, ) } @@ -159,7 +156,6 @@ private fun SelectAccountDialogPreview() { ), ), modifier = Modifier.background(Color.White), - colorsProvider = IdentityCredentialDefaults.provider(), onAccountClick = { }, ) } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt index 8356ee039a1a..d3c502d741de 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt @@ -11,11 +11,13 @@ import android.os.Bundle import android.view.View import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog -import androidx.compose.ui.Modifier +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors import androidx.compose.ui.platform.ComposeView import mozilla.components.concept.identitycredential.Account import mozilla.components.concept.identitycredential.Provider -import mozilla.components.feature.prompts.dialog.AlertDialogFragment import mozilla.components.feature.prompts.dialog.KEY_PROMPT_UID import mozilla.components.feature.prompts.dialog.KEY_SESSION_ID import mozilla.components.feature.prompts.dialog.KEY_SHOULD_DISMISS_ON_LOAD @@ -61,12 +63,15 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { internal fun createDialogContentView(): View { return ComposeView(requireContext()).apply { setContent { - SelectAccountDialog( - provider = provider, - accounts = accounts, - colorsProvider = colorsProvider, - onAccountClick = ::onAccountChange, - ) + val colors = if (isSystemInDarkTheme()) darkColors() else lightColors() + MaterialTheme(colors) { + SelectAccountDialog( + provider = provider, + accounts = accounts, + colors = colorsProvider.provideColors(), + onAccountClick = ::onAccountChange, + ) + } } } } @@ -89,7 +94,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { * @param accounts The list of available accounts. * @param provider The provider on which the user is logging in. * @param shouldDismissOnLoad Whether or not the dialog should automatically be dismissed when a new page is loaded. - * @param colorsProvider Provides [IdentityCredentialColors] that define the colors in the Dialog + * @param colorsProvider Provides [DialogColors] that define the colors in the Dialog */ fun newInstance( sessionId: String, diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt index 65f53e03fa3e..82e6720f53a9 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt @@ -4,8 +4,10 @@ package mozilla.components.feature.prompts.identitycredential +import android.content.res.Configuration import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -13,7 +15,10 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.material.MaterialTheme import androidx.compose.material.Text +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -27,23 +32,21 @@ import androidx.compose.ui.unit.sp import mozilla.components.concept.identitycredential.Provider import mozilla.components.feature.prompts.R import mozilla.components.support.ktx.kotlin.base64PngToBitmap -import mozilla.components.ui.colors.PhotonColors /** * A Federated Credential Management dialog for selecting a provider. * @param providers The list of available providers. - * @param colorsProvider Provides [IdentityCredentialColors] that define the colors of the dialog + * @param colors The colors of the dialog. * @param modifier [Modifier] to be applied to the layout. * @param onProviderClick Called when the user clicks on an item. */ @Composable fun SelectProviderDialog( providers: List, - colorsProvider: IdentityCredentialColorsProvider, modifier: Modifier = Modifier, + colors: DialogColors = DialogColors.default(), onProviderClick: (Provider) -> Unit, ) { - val colors = colorsProvider.provideColors() Column( modifier = modifier.fillMaxWidth(), @@ -71,7 +74,7 @@ fun SelectProviderDialog( private fun ProviderItem( provider: Provider, modifier: Modifier = Modifier, - colors: IdentityCredentialColors, + colors: DialogColors = DialogColors.default(), onClick: (Provider) -> Unit, ) { IdentityCredentialItem( @@ -109,32 +112,33 @@ private fun ProviderItemPreview() { "Title", "Description", ), - colors = IdentityCredentialDefaults.colors(), onClick = {}, ) } @Composable -@Preview +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) private fun SelectProviderDialogPreview() { - SelectProviderDialog( - providers = listOf( - Provider( - 0, - null, - "Title", - "Description", + val colors = if (!isSystemInDarkTheme()) lightColors() else darkColors() + MaterialTheme(colors = colors) { + SelectProviderDialog( + providers = listOf( + Provider( + 0, + null, + "Title", + "Description", + ), + Provider( + 0, + GOOGLE_FAVICON, + "Google", + "google.com", + ), ), - Provider( - 0, - GOOGLE_FAVICON, - "Google", - "google.com", - ), - ), - modifier = Modifier.background(Color.White), - colorsProvider = IdentityCredentialDefaults.provider() - ) { } + modifier = Modifier.background(MaterialTheme.colors.background) + ) { } + } } @Suppress("MaxLineLength") diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt index c1a2e23fd225..352ca0ac1142 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt @@ -11,6 +11,10 @@ import android.os.Bundle import android.view.View import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors import androidx.compose.ui.platform.ComposeView import mozilla.components.concept.identitycredential.Provider import mozilla.components.feature.prompts.dialog.KEY_PROMPT_UID @@ -48,11 +52,14 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { internal fun createDialogContentView(): View { return ComposeView(requireContext()).apply { setContent { - SelectProviderDialog( - providers = providers, - onProviderClick = ::onProviderChange, - colorsProvider = colorsProvider - ) + val colors = if (isSystemInDarkTheme()) darkColors() else lightColors() + MaterialTheme(colors) { + SelectProviderDialog( + providers = providers, + onProviderClick = ::onProviderChange, + colors = DialogColors.default(), //change that later + ) + } } } } @@ -74,7 +81,7 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { * @param promptRequestUID Identifier of the [PromptRequest] for which this dialog is shown. * @param providers The list of available providers. * @param shouldDismissOnLoad Whether or not the dialog should automatically be dismissed when a new page is loaded. - * @param colorsProvider Provides [IdentityCredentialColors] that define the colors in the Dialog + * @param colorsProvider Provides [DialogColors] that define the colors in the Dialog */ fun newInstance( sessionId: String, diff --git a/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 371d588a5999..5bc084025f0d 100644 --- a/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -24,7 +24,6 @@ import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.colorResource import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.getSystemService import androidx.core.view.isVisible @@ -79,7 +78,7 @@ import mozilla.components.feature.prompts.PromptFeature import mozilla.components.feature.prompts.PromptFeature.Companion.PIN_REQUEST import mozilla.components.feature.prompts.address.AddressDelegate import mozilla.components.feature.prompts.creditcard.CreditCardDelegate -import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColors +import mozilla.components.feature.prompts.identitycredential.DialogColors import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColorsProvider import mozilla.components.feature.prompts.login.LoginDelegate import mozilla.components.feature.prompts.share.ShareDelegate @@ -675,10 +674,9 @@ abstract class BaseBrowserFragment : ) val colorsProvider = IdentityCredentialColorsProvider { - IdentityCredentialColors( + DialogColors( title = ThemeManager.resolveAttributeColor(attribute = R.attr.textPrimary), - description = ThemeManager.resolveAttributeColor(attribute = R.attr.textSecondary), - ripple = ThemeManager.resolveAttributeColor(attribute = R.attr.textSecondary), + description = ThemeManager.resolveAttributeColor(attribute = R.attr.textSecondary) ) } From e9984e8d1ca8444a48d3cb62fb4b085ff5159c82 Mon Sep 17 00:00:00 2001 From: Titouan Thibaud Date: Wed, 6 Sep 2023 15:26:29 -0300 Subject: [PATCH 4/5] Bug 1842203: Second iteration of Theming fixes --- .../feature/prompts/PromptFeature.kt | 7 ++-- .../identitycredential/DialogColors.kt | 7 ++-- .../IdentityCredentialDefaults.kt | 36 ------------------- .../SelectAccountDialogFragment.kt | 4 +-- .../SelectProviderDialogFragment.kt | 4 +-- .../fenix/browser/BaseBrowserFragment.kt | 6 ++-- 6 files changed, 14 insertions(+), 50 deletions(-) delete mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt index c946ed57f29f..a0f0a9f30c84 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/PromptFeature.kt @@ -77,8 +77,7 @@ import mozilla.components.feature.prompts.facts.emitSuccessfulAddressAutofillFor import mozilla.components.feature.prompts.facts.emitSuccessfulCreditCardAutofillFormDetectedFact import mozilla.components.feature.prompts.file.FilePicker import mozilla.components.feature.prompts.identitycredential.DialogColors -import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColorsProvider -import mozilla.components.feature.prompts.identitycredential.IdentityCredentialDefaults +import mozilla.components.feature.prompts.identitycredential.DialogColorsProvider import mozilla.components.feature.prompts.identitycredential.PrivacyPolicyDialogFragment import mozilla.components.feature.prompts.identitycredential.SelectAccountDialogFragment import mozilla.components.feature.prompts.identitycredential.SelectProviderDialogFragment @@ -157,7 +156,7 @@ class PromptFeature private constructor( private val store: BrowserStore, private var customTabId: String?, private val fragmentManager: FragmentManager, - private val identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { DialogColors.default() }, + private val identityCredentialColorsProvider: DialogColorsProvider = DialogColorsProvider { DialogColors.default() }, private val tabsUseCases: TabsUseCases, private val shareDelegate: ShareDelegate, private val exitFullscreenUsecase: ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, @@ -201,7 +200,7 @@ class PromptFeature private constructor( customTabId: String? = null, fragmentManager: FragmentManager, tabsUseCases: TabsUseCases, - identityCredentialColorsProvider: IdentityCredentialColorsProvider = IdentityCredentialColorsProvider { DialogColors.default() }, + identityCredentialColorsProvider: DialogColorsProvider = DialogColorsProvider { DialogColors.default() }, shareDelegate: ShareDelegate = DefaultShareDelegate(), exitFullscreenUsecase: ExitFullScreenUseCase = SessionUseCases(store).exitFullscreen, creditCardValidationDelegate: CreditCardValidationDelegate? = null, diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt index 39747c0441a8..0033b8d1e10d 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/DialogColors.kt @@ -35,13 +35,16 @@ data class DialogColors( title, description ) + + fun defaultProvider() = DialogColorsProvider { default() } + } } /** - * An [IdentityCredentialColorsProvider] implementation can provide an [DialogColors] + * An [DialogColorsProvider] implementation can provide an [DialogColors] */ -fun interface IdentityCredentialColorsProvider { +fun interface DialogColorsProvider { @Composable fun provideColors(): DialogColors } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt deleted file mode 100644 index 1c750be8a6bd..000000000000 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialDefaults.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package mozilla.components.feature.prompts.identitycredential - -import androidx.compose.material.ContentAlpha -import androidx.compose.material.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.graphics.Color - -/** - * Contains the default values used by the IdentityCredential dialogs. - */ -object IdentityCredentialDefaults { - - /** - * Creates an [DialogColors] that represents the default colors used in an - * IdentityCredential dialog. - * - * @param title The text color for the title of a suggestion. - * @param description The text color for the description of a suggestion. - */ - @Composable - fun colors( - title: Color = MaterialTheme.colors.onBackground, - description: Color = MaterialTheme.colors.onBackground.copy( - alpha = ContentAlpha.medium, - ) - ) = DialogColors( - title, - description - ) - - fun provider() = IdentityCredentialColorsProvider { colors() } -} diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt index d3c502d741de..36daf806a783 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialogFragment.kt @@ -37,7 +37,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { safeArguments.getParcelableArrayListCompat(KEY_ACCOUNTS, Account::class.java) ?: emptyList() } - private var colorsProvider: IdentityCredentialColorsProvider = IdentityCredentialDefaults.provider() + private var colorsProvider: DialogColorsProvider = DialogColors.defaultProvider() internal val provider: Provider by lazy { requireNotNull( @@ -102,7 +102,7 @@ internal class SelectAccountDialogFragment : PromptDialogFragment() { accounts: List, provider: Provider, shouldDismissOnLoad: Boolean, - colorsProvider: IdentityCredentialColorsProvider + colorsProvider: DialogColorsProvider ) = SelectAccountDialogFragment().apply { arguments = (arguments ?: Bundle()).apply { putString(KEY_SESSION_ID, sessionId) diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt index 352ca0ac1142..d8f5f2c3db12 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt @@ -35,7 +35,7 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { ?: emptyList() } - private var colorsProvider: IdentityCredentialColorsProvider = IdentityCredentialDefaults.provider() + private var colorsProvider: DialogColorsProvider = DialogColors.defaultProvider() override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = AlertDialog.Builder(requireContext()) @@ -88,7 +88,7 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { promptRequestUID: String, providers: List, shouldDismissOnLoad: Boolean, - colorsProvider: IdentityCredentialColorsProvider + colorsProvider: DialogColorsProvider ) = SelectProviderDialogFragment().apply { arguments = (arguments ?: Bundle()).apply { putString(KEY_SESSION_ID, sessionId) diff --git a/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt b/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt index 5bc084025f0d..39f5bf2b5dd8 100644 --- a/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt +++ b/fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt @@ -22,8 +22,6 @@ import androidx.activity.result.ActivityResultLauncher import androidx.annotation.CallSuper import androidx.annotation.VisibleForTesting import androidx.appcompat.app.AlertDialog -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.ui.graphics.Color import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.content.getSystemService import androidx.core.view.isVisible @@ -79,7 +77,7 @@ import mozilla.components.feature.prompts.PromptFeature.Companion.PIN_REQUEST import mozilla.components.feature.prompts.address.AddressDelegate import mozilla.components.feature.prompts.creditcard.CreditCardDelegate import mozilla.components.feature.prompts.identitycredential.DialogColors -import mozilla.components.feature.prompts.identitycredential.IdentityCredentialColorsProvider +import mozilla.components.feature.prompts.identitycredential.DialogColorsProvider import mozilla.components.feature.prompts.login.LoginDelegate import mozilla.components.feature.prompts.share.ShareDelegate import mozilla.components.feature.readerview.ReaderViewFeature @@ -673,7 +671,7 @@ abstract class BaseBrowserFragment : view = view, ) - val colorsProvider = IdentityCredentialColorsProvider { + val colorsProvider = DialogColorsProvider { DialogColors( title = ThemeManager.resolveAttributeColor(attribute = R.attr.textPrimary), description = ThemeManager.resolveAttributeColor(attribute = R.attr.textSecondary) From ea704d43795aa731e66ac65c1f2b2f0991177b3b Mon Sep 17 00:00:00 2001 From: Titouan Thibaud Date: Wed, 6 Sep 2023 15:54:14 -0300 Subject: [PATCH 5/5] Bug 1842203: Extract repeated code to helper classes and functions --- .../IdentityCredentialItem.kt | 8 ++-- .../identitycredential/SelectAccountDialog.kt | 42 ++++++++++--------- .../SelectProviderDialog.kt | 9 ++-- .../SelectProviderDialogFragment.kt | 2 +- .../previews/DialogPreviewMaterialTheme.kt | 16 +++++++ .../previews/LightDarkPreview.kt | 16 +++++++ 6 files changed, 65 insertions(+), 28 deletions(-) create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/DialogPreviewMaterialTheme.kt create mode 100644 android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/LightDarkPreview.kt diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt index e9220289da91..c1b1b7c5eb31 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/IdentityCredentialItem.kt @@ -29,6 +29,8 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import mozilla.components.feature.prompts.identitycredential.previews.DialogPreviewMaterialTheme +import org.mozilla.fenix.compose.annotation.LightDarkPreview /** * List item used to display an IdentityCredential item that supports clicks @@ -85,11 +87,9 @@ internal fun IdentityCredentialItem( } @Composable -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Provider with no favicon") -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark - Provider with no favicon") +@LightDarkPreview private fun ProviderItemPreview() { - val colors = if (!isSystemInDarkTheme()) lightColors() else darkColors() - MaterialTheme(colors = colors) { + DialogPreviewMaterialTheme { IdentityCredentialItem( modifier = Modifier.background(MaterialTheme.colors.background), title = "Title", diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt index 4e145854fb02..e0667805781f 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectAccountDialog.kt @@ -29,7 +29,9 @@ import androidx.compose.ui.unit.sp import mozilla.components.concept.identitycredential.Account import mozilla.components.concept.identitycredential.Provider import mozilla.components.feature.prompts.R +import mozilla.components.feature.prompts.identitycredential.previews.DialogPreviewMaterialTheme import mozilla.components.support.ktx.kotlin.base64PngToBitmap +import org.mozilla.fenix.compose.annotation.LightDarkPreview /** * A Federated Credential Management dialog for selecting an account. @@ -137,27 +139,29 @@ private fun AccountItemPreview() { } @Composable -@Preview +@LightDarkPreview private fun SelectAccountDialogPreview() { - SelectAccountDialog( - provider = Provider(0, GOOGLE_FAVICON, "Google", "google.com"), - accounts = listOf( - Account( - 0, - "user@mozilla.com", - "User", - USER_PICTURE, - ), - Account( - 1, - "user2@mozilla.com", - "Google", - null, + DialogPreviewMaterialTheme { + SelectAccountDialog( + provider = Provider(0, GOOGLE_FAVICON, "Google", "google.com"), + accounts = listOf( + Account( + 0, + "user@mozilla.com", + "User", + USER_PICTURE, + ), + Account( + 1, + "user2@mozilla.com", + "Google", + null, + ), ), - ), - modifier = Modifier.background(Color.White), - onAccountClick = { }, - ) + modifier = Modifier.background(Color.White), + onAccountClick = { }, + ) + } } @Suppress("MaxLineLength") diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt index 82e6720f53a9..d9c9d2325460 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialog.kt @@ -31,7 +31,9 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import mozilla.components.concept.identitycredential.Provider import mozilla.components.feature.prompts.R +import mozilla.components.feature.prompts.identitycredential.previews.DialogPreviewMaterialTheme import mozilla.components.support.ktx.kotlin.base64PngToBitmap +import org.mozilla.fenix.compose.annotation.LightDarkPreview /** * A Federated Credential Management dialog for selecting a provider. @@ -117,10 +119,9 @@ private fun ProviderItemPreview() { } @Composable -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@LightDarkPreview private fun SelectProviderDialogPreview() { - val colors = if (!isSystemInDarkTheme()) lightColors() else darkColors() - MaterialTheme(colors = colors) { + DialogPreviewMaterialTheme { SelectProviderDialog( providers = listOf( Provider( @@ -136,7 +137,7 @@ private fun SelectProviderDialogPreview() { "google.com", ), ), - modifier = Modifier.background(MaterialTheme.colors.background) + modifier = Modifier.background(MaterialTheme.colors.background), ) { } } } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt index d8f5f2c3db12..31b37c8aa843 100644 --- a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/SelectProviderDialogFragment.kt @@ -57,7 +57,7 @@ internal class SelectProviderDialogFragment : PromptDialogFragment() { SelectProviderDialog( providers = providers, onProviderClick = ::onProviderChange, - colors = DialogColors.default(), //change that later + colors = DialogColors.default(), ) } } diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/DialogPreviewMaterialTheme.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/DialogPreviewMaterialTheme.kt new file mode 100644 index 000000000000..77c76325321b --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/DialogPreviewMaterialTheme.kt @@ -0,0 +1,16 @@ +package mozilla.components.feature.prompts.identitycredential.previews + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +@Composable +fun DialogPreviewMaterialTheme(content: @Composable () -> Unit) { + val colors = if (!isSystemInDarkTheme()) lightColors() else darkColors(background = Color(0xFF42414D)) + MaterialTheme(colors = colors) { + content() + } +} \ No newline at end of file diff --git a/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/LightDarkPreview.kt b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/LightDarkPreview.kt new file mode 100644 index 000000000000..a074263a3cfe --- /dev/null +++ b/android-components/components/feature/prompts/src/main/java/mozilla/components/feature/prompts/identitycredential/previews/LightDarkPreview.kt @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.compose.annotation + +import android.content.res.Configuration +import androidx.compose.ui.tooling.preview.Preview + +/** + * A wrapper annotation for the two uiMode that are commonly used + * in Compose preview functions. + */ +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +annotation class LightDarkPreview