From 47fc6921ae0338cc0fe4d3a3ad57d9a871eeb411 Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 18 Oct 2024 10:54:46 +0200 Subject: [PATCH 1/3] Update appearance of `TbOnboardingMigrationScreen` --- .../main/navigation/OnboardingNavHost.kt | 5 +- .../api/OnboardingMigrationManager.kt | 5 +- .../noop/NoOpOnboardingMigrationManager.kt | 5 +- .../TbOnboardingMigrationScreenPreview.kt | 5 +- .../TbOnboardingMigrationManager.kt | 10 +-- .../TbOnboardingMigrationScreen.kt | 62 +++++++++++++++---- .../src/main/res/values/strings.xml | 2 + .../TbOnboardingMigrationScreenKtTest.kt | 37 ++++++++--- 8 files changed, 97 insertions(+), 34 deletions(-) diff --git a/feature/onboarding/main/src/main/kotlin/app/k9mail/feature/onboarding/main/navigation/OnboardingNavHost.kt b/feature/onboarding/main/src/main/kotlin/app/k9mail/feature/onboarding/main/navigation/OnboardingNavHost.kt index 78e3dae0706..d820e058b5d 100644 --- a/feature/onboarding/main/src/main/kotlin/app/k9mail/feature/onboarding/main/navigation/OnboardingNavHost.kt +++ b/feature/onboarding/main/src/main/kotlin/app/k9mail/feature/onboarding/main/navigation/OnboardingNavHost.kt @@ -87,8 +87,9 @@ fun OnboardingNavHost( composable(route = NESTED_NAVIGATION_ROUTE_MIGRATION) { onboardingMigrationManager.OnboardingMigrationScreen( - onQrCodeScanClick = { navController.navigateToSettingsImportQrCode() }, - onAddAccountClick = { navController.navigateToAccountSetup() }, + onQrCodeScan = { navController.navigateToSettingsImportQrCode() }, + onAddAccount = { navController.navigateToAccountSetup() }, + onImport = { navController.navigateToSettingsImport() }, ) } diff --git a/feature/onboarding/migration/api/src/main/kotlin/app/k9mail/feature/onboarding/migration/api/OnboardingMigrationManager.kt b/feature/onboarding/migration/api/src/main/kotlin/app/k9mail/feature/onboarding/migration/api/OnboardingMigrationManager.kt index a750ef22457..1234da1bb07 100644 --- a/feature/onboarding/migration/api/src/main/kotlin/app/k9mail/feature/onboarding/migration/api/OnboardingMigrationManager.kt +++ b/feature/onboarding/migration/api/src/main/kotlin/app/k9mail/feature/onboarding/migration/api/OnboardingMigrationManager.kt @@ -7,7 +7,8 @@ interface OnboardingMigrationManager { @Composable fun OnboardingMigrationScreen( - onQrCodeScanClick: () -> Unit, - onAddAccountClick: () -> Unit, + onQrCodeScan: () -> Unit, + onAddAccount: () -> Unit, + onImport: () -> Unit, ) } diff --git a/feature/onboarding/migration/noop/src/main/kotlin/app/k9mail/feature/onboarding/migration/noop/NoOpOnboardingMigrationManager.kt b/feature/onboarding/migration/noop/src/main/kotlin/app/k9mail/feature/onboarding/migration/noop/NoOpOnboardingMigrationManager.kt index e535451905c..bc37a1b321e 100644 --- a/feature/onboarding/migration/noop/src/main/kotlin/app/k9mail/feature/onboarding/migration/noop/NoOpOnboardingMigrationManager.kt +++ b/feature/onboarding/migration/noop/src/main/kotlin/app/k9mail/feature/onboarding/migration/noop/NoOpOnboardingMigrationManager.kt @@ -8,7 +8,8 @@ class NoOpOnboardingMigrationManager : OnboardingMigrationManager { @Composable override fun OnboardingMigrationScreen( - onQrCodeScanClick: () -> Unit, - onAddAccountClick: () -> Unit, + onQrCodeScan: () -> Unit, + onAddAccount: () -> Unit, + onImport: () -> Unit, ) = Unit } diff --git a/feature/onboarding/migration/thunderbird/src/debug/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenPreview.kt b/feature/onboarding/migration/thunderbird/src/debug/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenPreview.kt index 67874ef9de3..63064a0b112 100644 --- a/feature/onboarding/migration/thunderbird/src/debug/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenPreview.kt +++ b/feature/onboarding/migration/thunderbird/src/debug/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenPreview.kt @@ -12,8 +12,9 @@ internal fun TbOnboardingMigrationScreenPreview() { ThunderbirdTheme2 { Surface { TbOnboardingMigrationScreen( - onQrCodeScanClick = {}, - onAddAccountClick = {}, + onQrCodeScan = {}, + onAddAccount = {}, + onImport = {}, brandNameProvider = object : BrandNameProvider { override val brandName: String = "Thunderbird" }, diff --git a/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationManager.kt b/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationManager.kt index ef4691f5e6b..fbd2c019058 100644 --- a/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationManager.kt +++ b/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationManager.kt @@ -8,12 +8,14 @@ class TbOnboardingMigrationManager : OnboardingMigrationManager { @Composable override fun OnboardingMigrationScreen( - onQrCodeScanClick: () -> Unit, - onAddAccountClick: () -> Unit, + onQrCodeScan: () -> Unit, + onAddAccount: () -> Unit, + onImport: () -> Unit, ) { TbOnboardingMigrationScreen( - onQrCodeScanClick, - onAddAccountClick, + onQrCodeScan, + onAddAccount, + onImport, ) } } diff --git a/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt b/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt index d2072184a62..048821b64b8 100644 --- a/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt +++ b/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import app.k9mail.core.common.provider.BrandNameProvider import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonFilled +import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonOutlined import app.k9mail.core.ui.compose.designsystem.atom.card.CardFilled import app.k9mail.core.ui.compose.designsystem.atom.text.TextBodyMedium import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium @@ -26,8 +27,9 @@ import org.koin.compose.koinInject @Composable internal fun TbOnboardingMigrationScreen( - onQrCodeScanClick: () -> Unit, - onAddAccountClick: () -> Unit, + onQrCodeScan: () -> Unit, + onAddAccount: () -> Unit, + onImport: () -> Unit, modifier: Modifier = Modifier, brandNameProvider: BrandNameProvider = koinInject(), ) { @@ -47,7 +49,11 @@ internal fun TbOnboardingMigrationScreen( title = brandNameProvider.brandName, ) - Spacer(modifier = Modifier.height(MainTheme.spacings.double)) + Spacer( + modifier = Modifier + .height(MainTheme.spacings.double) + .weight(1f), + ) TextCard(title = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_title)) { TextBodyMedium( @@ -58,26 +64,36 @@ internal fun TbOnboardingMigrationScreen( ButtonFilled( text = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_button_text), - onClick = onQrCodeScanClick, + onClick = onQrCodeScan, modifier = Modifier .testTag("QrCodeImportButton") .align(Alignment.CenterHorizontally), ) } - Spacer(modifier = Modifier.height(MainTheme.spacings.double)) + Spacer(modifier = Modifier.height(MainTheme.spacings.triple)) - TextCard(title = stringResource(R.string.onboarding_migration_thunderbird_new_account_title)) { - ButtonFilled( + TextGroup(title = stringResource(R.string.onboarding_migration_thunderbird_new_account_title)) { + ButtonOutlined( text = stringResource(R.string.onboarding_migration_thunderbird_new_account_button_text), - onClick = onAddAccountClick, - modifier = Modifier - .testTag("AddAccountButton") - .align(Alignment.CenterHorizontally), + onClick = onAddAccount, + modifier = Modifier.testTag("AddAccountButton"), ) } - Spacer(modifier = Modifier.height(MainTheme.spacings.double)) + TextGroup(title = stringResource(R.string.onboarding_migration_thunderbird_import_title)) { + ButtonOutlined( + text = stringResource(R.string.onboarding_migration_thunderbird_import_button_text), + onClick = onImport, + modifier = Modifier.testTag("ImportButton"), + ) + } + + Spacer( + modifier = Modifier + .height(MainTheme.spacings.double) + .weight(1f), + ) } } } @@ -108,3 +124,25 @@ private fun TextCard( } } } + +@Composable +private fun TextGroup( + title: String, + content: @Composable ColumnScope.() -> Unit, +) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier + .fillMaxWidth() + .padding(MainTheme.spacings.double), + ) { + TextTitleMedium( + text = title, + color = MainTheme.colors.primary, + modifier = Modifier + .padding(bottom = MainTheme.spacings.default), + ) + + content() + } +} diff --git a/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml b/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml index b907f8a426d..284327145e2 100644 --- a/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml +++ b/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml @@ -5,4 +5,6 @@ Import settings New to Thunderbird? Add an email account now + Moving from another app or device? + Import your account settings now diff --git a/feature/onboarding/migration/thunderbird/src/test/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenKtTest.kt b/feature/onboarding/migration/thunderbird/src/test/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenKtTest.kt index 2b0e8a22eef..395c0ba6ba2 100644 --- a/feature/onboarding/migration/thunderbird/src/test/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenKtTest.kt +++ b/feature/onboarding/migration/thunderbird/src/test/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreenKtTest.kt @@ -12,13 +12,13 @@ import org.junit.Test class TbOnboardingMigrationScreenKtTest : ComposeTest() { @Test - fun `pressing QrCodeImportButton should call onQrCodeScanClick`() = runComposeTest { + fun `pressing QrCodeImportButton should call onQrCodeScan`() = runComposeTest { var qrCodeScanClickCounter = 0 - var addAccountClickCounter = 0 setContentWithTheme { TbOnboardingMigrationScreen( - onQrCodeScanClick = { qrCodeScanClickCounter++ }, - onAddAccountClick = { addAccountClickCounter++ }, + onQrCodeScan = { qrCodeScanClickCounter++ }, + onAddAccount = { error("Should not be called") }, + onImport = { error("Should not be called") }, brandNameProvider = FakeBrandNameProvider, ) } @@ -28,17 +28,16 @@ class TbOnboardingMigrationScreenKtTest : ComposeTest() { .performClick() assertThat(qrCodeScanClickCounter).isEqualTo(1) - assertThat(addAccountClickCounter).isEqualTo(0) } @Test - fun `pressing AddAccountButton button should call onAddAccountClick`() = runComposeTest { - var qrCodeScanClickCounter = 0 + fun `pressing AddAccountButton button should call onAddAccount`() = runComposeTest { var addAccountClickCounter = 0 setContentWithTheme { TbOnboardingMigrationScreen( - onQrCodeScanClick = { qrCodeScanClickCounter++ }, - onAddAccountClick = { addAccountClickCounter++ }, + onQrCodeScan = { error("Should not be called") }, + onAddAccount = { addAccountClickCounter++ }, + onImport = { error("Should not be called") }, brandNameProvider = FakeBrandNameProvider, ) } @@ -48,7 +47,25 @@ class TbOnboardingMigrationScreenKtTest : ComposeTest() { .performClick() assertThat(addAccountClickCounter).isEqualTo(1) - assertThat(qrCodeScanClickCounter).isEqualTo(0) + } + + @Test + fun `pressing ImportButton button should call onImport`() = runComposeTest { + var importClickCounter = 0 + setContentWithTheme { + TbOnboardingMigrationScreen( + onQrCodeScan = { error("Should not be called") }, + onAddAccount = { error("Should not be called") }, + onImport = { importClickCounter++ }, + brandNameProvider = FakeBrandNameProvider, + ) + } + + composeTestRule.onNodeWithTag("ImportButton") + .performScrollTo() + .performClick() + + assertThat(importClickCounter).isEqualTo(1) } } From d21afd0324e52c551a41fddf87af5516ebad9e3c Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 18 Oct 2024 13:10:46 +0200 Subject: [PATCH 2/3] Update text in "Already using Thunderbird on desktop?" card --- .../designsystem/atom/text/TextBodyMedium.kt | 18 +++++ .../TbOnboardingMigrationScreen.kt | 80 +++++++++++++++---- .../src/main/res/values/strings.xml | 5 +- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt index 105c68bc0fd..129b8fdaab9 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/text/TextBodyMedium.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.style.LineHeightStyle import androidx.compose.ui.text.style.TextAlign import app.k9mail.core.ui.compose.theme2.MainTheme import androidx.compose.material3.Text as Material3Text @@ -39,3 +40,20 @@ fun TextBodyMedium( style = MainTheme.typography.bodyMedium, ) } + +@Composable +fun TextBodyMedium( + text: String, + lineHeightStyle: LineHeightStyle, + modifier: Modifier = Modifier, + color: Color = Color.Unspecified, + textAlign: TextAlign? = null, +) { + Material3Text( + text = text, + modifier = modifier, + color = color, + textAlign = textAlign, + style = MainTheme.typography.bodyMedium.copy(lineHeightStyle = lineHeightStyle), + ) +} diff --git a/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt b/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt index 048821b64b8..d2deab666c1 100644 --- a/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt +++ b/feature/onboarding/migration/thunderbird/src/main/kotlin/app/k9mail/feature/onboarding/migration/thunderbird/TbOnboardingMigrationScreen.kt @@ -2,6 +2,7 @@ package app.k9mail.feature.onboarding.migration.thunderbird import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth @@ -14,6 +15,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.LineHeightStyle import app.k9mail.core.common.provider.BrandNameProvider import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonFilled import app.k9mail.core.ui.compose.designsystem.atom.button.ButtonOutlined @@ -23,6 +25,8 @@ import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium import app.k9mail.core.ui.compose.designsystem.template.ResponsiveWidthContainer import app.k9mail.core.ui.compose.theme2.MainTheme import app.k9mail.feature.account.common.ui.AppTitleTopHeader +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import org.koin.compose.koinInject @Composable @@ -55,21 +59,7 @@ internal fun TbOnboardingMigrationScreen( .weight(1f), ) - TextCard(title = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_title)) { - TextBodyMedium( - text = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_description), - modifier = Modifier - .padding(bottom = MainTheme.spacings.double), - ) - - ButtonFilled( - text = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_button_text), - onClick = onQrCodeScan, - modifier = Modifier - .testTag("QrCodeImportButton") - .align(Alignment.CenterHorizontally), - ) - } + AlreadyUsingThunderbirdCard(onQrCodeScan) Spacer(modifier = Modifier.height(MainTheme.spacings.triple)) @@ -98,6 +88,38 @@ internal fun TbOnboardingMigrationScreen( } } +@Composable +private fun AlreadyUsingThunderbirdCard(onQrCodeScan: () -> Unit) { + TextCard(title = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_title)) { + TextBodyMedium( + text = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_text), + modifier = Modifier + .padding(bottom = MainTheme.spacings.double), + ) + + TextBodyMediumFullLineHeight( + text = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_instructions_intro), + ) + + BulletList( + items = persistentListOf( + stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_instructions_bullet_1), + stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_instructions_bullet_2), + ), + modifier = Modifier + .padding(bottom = MainTheme.spacings.double), + ) + + ButtonFilled( + text = stringResource(R.string.onboarding_migration_thunderbird_qr_code_import_button_text), + onClick = onQrCodeScan, + modifier = Modifier + .testTag("QrCodeImportButton") + .align(Alignment.CenterHorizontally), + ) + } +} + @Composable private fun TextCard( title: String, @@ -146,3 +168,31 @@ private fun TextGroup( content() } } + +@Composable +private fun BulletList( + items: ImmutableList, + modifier: Modifier = Modifier, +) { + Column(modifier = modifier) { + for (item in items) { + Row { + TextBodyMediumFullLineHeight(text = " \u2022 ") + TextBodyMediumFullLineHeight(text = item) + } + } + } +} + +@Composable +private fun TextBodyMediumFullLineHeight(text: String) { + // Disable line height trimming so that the space between TextBodyMediumFullLineHeight instances following each + // other is the same as the space between lines of text inside a single TextBodyMedium. + TextBodyMedium( + text = text, + lineHeightStyle = LineHeightStyle( + alignment = LineHeightStyle.Alignment.Proportional, + trim = LineHeightStyle.Trim.None, + ), + ) +} diff --git a/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml b/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml index 284327145e2..d373a1bdf61 100644 --- a/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml +++ b/feature/onboarding/migration/thunderbird/src/main/res/values/strings.xml @@ -1,7 +1,10 @@ Already using Thunderbird on desktop? - You can easily import your account settings.\n\nIn your Thunderbird desktop client, go to the top menu bar, click on ‘Settings’, and select ‘Export for Mobile’.\n\nA new tab with QR codes will appear. Use your Android device to scan the codes. + Easily import your account settings by scanning a QR code. + In Thunderbird desktop, go to: + ‘Settings’ in the Spaces Toolbar (bottom left) + Select ‘Export to Mobile’ and follow the instructions Import settings New to Thunderbird? Add an email account now From 6f7759a9114dacf55334bd0c183044ff5aac3d1b Mon Sep 17 00:00:00 2001 From: cketti Date: Fri, 18 Oct 2024 13:12:17 +0200 Subject: [PATCH 3/3] Switch `CardFilled` to be not clickable --- .../k9mail/core/ui/compose/designsystem/atom/card/CardFilled.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/card/CardFilled.kt b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/card/CardFilled.kt index 27bc159878b..70802a44547 100644 --- a/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/card/CardFilled.kt +++ b/core/ui/compose/designsystem/src/main/kotlin/app/k9mail/core/ui/compose/designsystem/atom/card/CardFilled.kt @@ -8,11 +8,9 @@ import androidx.compose.material3.Card as Material3Card @Composable fun CardFilled( modifier: Modifier = Modifier, - onClick: () -> Unit = {}, content: @Composable ColumnScope.() -> Unit, ) { Material3Card( - onClick = onClick, modifier = modifier, content = content, )