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:
parent
e29f919abc
commit
c8bd04ceb1
253 changed files with 4421 additions and 326 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue