Sign in with QR code (#2793)

* Add QR code login.
* Add FF to disable it in release mode.
* Force portrait orientation on the login flow.
* Create `NumberedList` UI components.
* Improve camera permission dialog.
* Make nodes in qrcode feature use `QrCodeLoginScope` instead of `AppScope`
* Bump SDK version.
* Fix maestro tests

---------

Co-authored-by: Benoit Marty <benoit@matrix.org>
Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa 2024-05-31 14:38:27 +02:00 committed by GitHub
parent e29f919abc
commit c8bd04ceb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
253 changed files with 4421 additions and 326 deletions

View file

@ -16,35 +16,26 @@
package io.element.android.features.securebackup.impl.createkey
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.securebackup.impl.R
import io.element.android.libraries.designsystem.atomic.organisms.NumberedListOrganism
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.PageTitle
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.modifiers.squareSize
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.designsystem.utils.annotatedTextWithBold
import kotlinx.collections.immutable.toImmutableList
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -74,55 +65,19 @@ fun CreateNewRecoveryKeyView(
@Composable
private fun Content(desktopApplicationName: String) {
Column(modifier = Modifier.padding(horizontal = 16.dp), verticalArrangement = Arrangement.spacedBy(24.dp)) {
Item(index = 1, text = AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_1, desktopApplicationName)))
Item(index = 2, text = AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_2)))
Item(
index = 3,
text = buildAnnotatedString {
val resetAllAction = stringResource(R.string.screen_create_new_recovery_key_list_item_3_reset_all)
val text = stringResource(R.string.screen_create_new_recovery_key_list_item_3, resetAllAction)
append(text)
val start = text.indexOf(resetAllAction)
val end = start + resetAllAction.length
if (start in text.indices && end in text.indices) {
addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
}
}
)
Item(index = 4, text = AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_4)))
Item(index = 5, text = AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_5)))
}
}
@Composable
private fun Item(index: Int, text: AnnotatedString) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
ItemNumber(index = index)
Text(text = text, style = ElementTheme.typography.fontBodyMdRegular, color = ElementTheme.colors.textPrimary)
}
}
@Composable
private fun ItemNumber(
index: Int,
) {
val color = ElementTheme.colors.textPlaceholder
Box(
modifier = Modifier
.border(1.dp, color, CircleShape)
.squareSize()
) {
Text(
modifier = Modifier.padding(1.5.dp),
text = index.toString(),
style = ElementTheme.typography.fontBodySmRegular,
color = color,
textAlign = TextAlign.Center,
val listItems = buildList {
add(AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_1, desktopApplicationName)))
add(AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_2)))
add(
annotatedTextWithBold(
text = stringResource(R.string.screen_create_new_recovery_key_list_item_3),
boldText = stringResource(R.string.screen_create_new_recovery_key_list_item_3_reset_all)
)
)
add(AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_4)))
add(AnnotatedString(stringResource(R.string.screen_create_new_recovery_key_list_item_5)))
}
NumberedListOrganism(modifier = Modifier.padding(horizontal = 16.dp), items = listItems.toImmutableList())
}
@PreviewsDayNight

View file

@ -32,6 +32,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.securebackup.impl.R
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview
@ -52,7 +53,7 @@ fun SecureBackupDisableView(
onBackClick = onBackClick,
title = stringResource(id = R.string.screen_key_backup_disable_title),
subTitle = stringResource(id = R.string.screen_key_backup_disable_description),
iconVector = CompoundIcons.KeyOffSolid(),
iconStyle = BigIcon.Style.Default(CompoundIcons.KeyOffSolid()),
buttons = { Buttons(state = state) },
) {
Content(state = state)

View file

@ -25,6 +25,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.securebackup.impl.R
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -41,7 +42,7 @@ fun SecureBackupEnableView(
modifier = modifier,
onBackClick = onBackClick,
title = stringResource(id = R.string.screen_chat_backup_key_backup_action_enable),
iconVector = CompoundIcons.KeySolid(),
iconStyle = BigIcon.Style.Default(CompoundIcons.KeySolid()),
buttons = { Buttons(state = state) }
)
AsyncActionView(

View file

@ -28,6 +28,7 @@ import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.securebackup.impl.R
import io.element.android.features.securebackup.impl.setup.views.RecoveryKeyView
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -55,7 +56,7 @@ fun SecureBackupEnterRecoveryKeyView(
FlowStepPage(
modifier = modifier,
onBackClick = onBackClick,
iconVector = CompoundIcons.KeySolid(),
iconStyle = BigIcon.Style.Default(CompoundIcons.KeySolid()),
title = stringResource(id = R.string.screen_recovery_key_confirm_title),
subTitle = stringResource(id = R.string.screen_recovery_key_confirm_description),
buttons = { Buttons(state = state, onCreateRecoveryKey = onCreateNewRecoveryKey) }

View file

@ -31,6 +31,7 @@ import io.element.android.features.securebackup.impl.setup.views.RecoveryKeyView
import io.element.android.libraries.androidutils.system.copyToClipboard
import io.element.android.libraries.androidutils.system.startSharePlainTextIntent
import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -51,7 +52,7 @@ fun SecureBackupSetupView(
onBackClick = onBackClick.takeIf { state.canGoBack() },
title = title(state),
subTitle = subtitle(state),
iconVector = CompoundIcons.KeySolid(),
iconStyle = BigIcon.Style.Default(CompoundIcons.KeySolid()),
buttons = { Buttons(state, onFinish = onSuccess) },
) {
Content(state = state)