Add "Learn more" on identity verification first screen.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
package io.element.android.appconfig
|
||||
|
||||
object LearnMoreConfig {
|
||||
const val ENCRYPTION_URL: String = "https://element.io/help#encryption"
|
||||
const val SECURE_BACKUP_URL: String = "https://element.io/help#encryption5"
|
||||
const val IDENTITY_CHANGE_URL: String = "https://element.io/help#encryption18"
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ android {
|
||||
setupAnvil()
|
||||
|
||||
dependencies {
|
||||
implementation(projects.appconfig)
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
|
||||
@@ -18,9 +18,11 @@ import com.bumble.appyx.core.plugin.plugins
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.appconfig.LearnMoreConfig
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.logout.api.util.onSuccessLogout
|
||||
import io.element.android.features.verifysession.api.VerifySessionEntryPoint
|
||||
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@@ -36,6 +38,10 @@ class VerifySelfSessionNode @AssistedInject constructor(
|
||||
showDeviceVerifiedScreen = inputs<VerifySessionEntryPoint.Params>().showDeviceVerifiedScreen,
|
||||
)
|
||||
|
||||
private fun onLearnMoreClick(activity: Activity, dark: Boolean) {
|
||||
activity.openUrlInChromeCustomTab(null, dark, LearnMoreConfig.ENCRYPTION_URL)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
@@ -44,6 +50,9 @@ class VerifySelfSessionNode @AssistedInject constructor(
|
||||
VerifySelfSessionView(
|
||||
state = state,
|
||||
modifier = modifier,
|
||||
onLearnMoreClick = {
|
||||
onLearnMoreClick(activity, isDark)
|
||||
},
|
||||
onEnterRecoveryKey = callback::onEnterRecoveryKey,
|
||||
onResetKey = callback::onResetKey,
|
||||
onFinish = callback::onDone,
|
||||
|
||||
@@ -23,6 +23,7 @@ data class VerifySelfSessionState(
|
||||
@Stable
|
||||
sealed interface VerificationStep {
|
||||
data object Loading : VerificationStep
|
||||
// FIXME canEnterRecoveryKey value is never read.
|
||||
data class Initial(val canEnterRecoveryKey: Boolean, val isLastDevice: Boolean = false) : VerificationStep
|
||||
data object Canceled : VerificationStep
|
||||
data object AwaitingOtherDeviceResponse : VerificationStep
|
||||
|
||||
@@ -9,13 +9,13 @@ package io.element.android.features.verifysession.impl
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
@@ -64,6 +64,7 @@ import io.element.android.features.verifysession.impl.VerifySelfSessionState.Ver
|
||||
@Composable
|
||||
fun VerifySelfSessionView(
|
||||
state: VerifySelfSessionState,
|
||||
onLearnMoreClick: () -> Unit,
|
||||
onEnterRecoveryKey: () -> Unit,
|
||||
onResetKey: () -> Unit,
|
||||
onFinish: () -> Unit,
|
||||
@@ -140,7 +141,10 @@ fun VerifySelfSessionView(
|
||||
)
|
||||
}
|
||||
) {
|
||||
Content(flowState = verificationFlowStep)
|
||||
Content(
|
||||
flowState = verificationFlowStep,
|
||||
onLearnMoreClick = onLearnMoreClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,38 +207,68 @@ private fun HeaderContent(verificationFlowStep: FlowStep) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Content(flowState: FlowStep) {
|
||||
Column(Modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) {
|
||||
if (flowState is FlowStep.Verifying) {
|
||||
private fun Content(
|
||||
flowState: FlowStep,
|
||||
onLearnMoreClick: () -> Unit,
|
||||
) {
|
||||
when (flowState) {
|
||||
is VerifySelfSessionState.VerificationStep.Initial -> {
|
||||
ContentInitial(onLearnMoreClick)
|
||||
}
|
||||
is FlowStep.Verifying -> {
|
||||
ContentVerifying(flowState)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContentInitial(
|
||||
onLearnMoreClick: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.clickable { onLearnMoreClick() }
|
||||
.padding(vertical = 4.dp, horizontal = 16.dp),
|
||||
text = stringResource(CommonStrings.action_learn_more),
|
||||
style = ElementTheme.typography.fontBodyLgMedium
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying) {
|
||||
when (verificationFlowStep.data) {
|
||||
is SessionVerificationData.Decimals -> {
|
||||
val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() }
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = text,
|
||||
style = ElementTheme.typography.fontHeadingLgBold,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
is SessionVerificationData.Emojis -> {
|
||||
// We want each row to have up to 4 emojis
|
||||
val rows = verificationFlowStep.data.emojis.chunked(4)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(40.dp),
|
||||
) {
|
||||
rows.forEach { emojis ->
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
for (emoji in emojis) {
|
||||
EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp))
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
when (verificationFlowStep.data) {
|
||||
is SessionVerificationData.Decimals -> {
|
||||
val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() }
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = text,
|
||||
style = ElementTheme.typography.fontHeadingLgBold,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
is SessionVerificationData.Emojis -> {
|
||||
// We want each row to have up to 4 emojis
|
||||
val rows = verificationFlowStep.data.emojis.chunked(4)
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(40.dp),
|
||||
) {
|
||||
rows.forEach { emojis ->
|
||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||
for (emoji in emojis) {
|
||||
EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -402,6 +436,7 @@ private fun BottomMenu(
|
||||
internal fun VerifySelfSessionViewPreview(@PreviewParameter(VerifySelfSessionStateProvider::class) state: VerifySelfSessionState) = ElementPreview {
|
||||
VerifySelfSessionView(
|
||||
state = state,
|
||||
onLearnMoreClick = {},
|
||||
onEnterRecoveryKey = {},
|
||||
onResetKey = {},
|
||||
onFinish = {},
|
||||
|
||||
@@ -146,6 +146,22 @@ class VerifySelfSessionViewTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Config(qualifiers = "h1024dp")
|
||||
@Test
|
||||
fun `clicking on learn more invokes the expected callback`() {
|
||||
val eventsRecorder = EventsRecorder<VerifySelfSessionViewEvents>(expectEvents = false)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setVerifySelfSessionView(
|
||||
aVerifySelfSessionState(
|
||||
verificationFlowStep = VerifySelfSessionState.VerificationStep.Initial(true),
|
||||
eventSink = eventsRecorder
|
||||
),
|
||||
onLearnMoreClick = callback,
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_learn_more)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on they match emits the expected event`() {
|
||||
val eventsRecorder = EventsRecorder<VerifySelfSessionViewEvents>()
|
||||
@@ -222,6 +238,7 @@ class VerifySelfSessionViewTest {
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setVerifySelfSessionView(
|
||||
state: VerifySelfSessionState,
|
||||
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
||||
onEnterRecoveryKey: () -> Unit = EnsureNeverCalled(),
|
||||
onFinished: () -> Unit = EnsureNeverCalled(),
|
||||
onResetKey: () -> Unit = EnsureNeverCalled(),
|
||||
@@ -230,6 +247,7 @@ class VerifySelfSessionViewTest {
|
||||
setContent {
|
||||
VerifySelfSessionView(
|
||||
state = state,
|
||||
onLearnMoreClick = onLearnMoreClick,
|
||||
onEnterRecoveryKey = onEnterRecoveryKey,
|
||||
onFinish = onFinished,
|
||||
onResetKey = onResetKey,
|
||||
|
||||
Reference in New Issue
Block a user