Merge pull request #5426 from element-hq/feature/bma/incomingVerificationA11y
Improvement and bugfix on incoming verification request screen
This commit is contained in:
commit
43ad8743b8
22 changed files with 101 additions and 77 deletions
|
|
@ -155,7 +155,7 @@ class IncomingVerificationPresenter(
|
|||
StateMachineState.RejectingIncomingVerification,
|
||||
null -> {
|
||||
Step.Initial(
|
||||
deviceDisplayName = sessionVerificationRequestDetails.senderProfile.displayName ?: sessionVerificationRequestDetails.deviceId.value,
|
||||
deviceDisplayName = sessionVerificationRequestDetails.deviceDisplayName,
|
||||
deviceId = sessionVerificationRequestDetails.deviceId,
|
||||
formattedSignInTime = formattedSignInTime,
|
||||
isWaiting = machineState == StateMachineState.AcceptingIncomingVerification ||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ data class IncomingVerificationState(
|
|||
@Stable
|
||||
sealed interface Step {
|
||||
data class Initial(
|
||||
val deviceDisplayName: String,
|
||||
val deviceDisplayName: String?,
|
||||
val deviceId: DeviceId,
|
||||
val formattedSignInTime: String,
|
||||
val isWaiting: Boolean,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import io.element.android.features.verifysession.impl.ui.aEmojisSessionVerificat
|
|||
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||
import io.element.android.libraries.matrix.api.core.FlowId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationRequestDetails
|
||||
import io.element.android.libraries.matrix.api.verification.VerificationRequest
|
||||
|
||||
|
|
@ -55,26 +56,28 @@ internal fun aStepInitial(
|
|||
|
||||
internal fun anIncomingSessionVerificationRequest() = VerificationRequest.Incoming.OtherSession(
|
||||
details = SessionVerificationRequestDetails(
|
||||
senderProfile = SessionVerificationRequestDetails.SenderProfile(
|
||||
senderProfile = MatrixUser(
|
||||
userId = UserId("@alice:example.com"),
|
||||
displayName = "Alice",
|
||||
avatarUrl = null,
|
||||
),
|
||||
flowId = FlowId("1234"),
|
||||
deviceId = DeviceId("ILAKNDNASDLK"),
|
||||
deviceDisplayName = "a device name",
|
||||
firstSeenTimestamp = 0,
|
||||
)
|
||||
)
|
||||
|
||||
internal fun anIncomingUserVerificationRequest() = VerificationRequest.Incoming.User(
|
||||
details = SessionVerificationRequestDetails(
|
||||
senderProfile = SessionVerificationRequestDetails.SenderProfile(
|
||||
senderProfile = MatrixUser(
|
||||
userId = UserId("@alice:example.com"),
|
||||
displayName = "Alice",
|
||||
avatarUrl = null,
|
||||
),
|
||||
flowId = FlowId("1234"),
|
||||
deviceId = DeviceId("ILAKNDNASDLK"),
|
||||
deviceDisplayName = "a device name",
|
||||
firstSeenTimestamp = 0,
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import androidx.compose.ui.semantics.focused
|
|||
import androidx.compose.ui.semantics.progressBarRangeInfo
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
|
@ -214,9 +215,7 @@ private fun ContentInitial(
|
|||
.padding(top = 24.dp),
|
||||
) {
|
||||
VerificationUserProfileContent(
|
||||
userId = request.details.senderProfile.userId,
|
||||
displayName = request.details.senderProfile.displayName,
|
||||
avatarUrl = request.details.senderProfile.avatarUrl,
|
||||
user = request.details.senderProfile,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -292,3 +291,11 @@ internal fun IncomingVerificationViewPreview(@PreviewParameter(IncomingVerificat
|
|||
state = state,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun IncomingVerificationViewA11yPreview() = ElementPreview {
|
||||
IncomingVerificationView(
|
||||
state = anIncomingVerificationState(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
|||
|
||||
@Composable
|
||||
fun SessionDetailsView(
|
||||
deviceName: String,
|
||||
deviceName: String?,
|
||||
deviceId: DeviceId,
|
||||
signInFormattedTimestamp: String,
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -61,7 +61,7 @@ fun SessionDetailsView(
|
|||
resourceId = CompoundDrawables.ic_compound_devices
|
||||
)
|
||||
Text(
|
||||
text = deviceName,
|
||||
text = deviceName ?: deviceId.value,
|
||||
style = ElementTheme.typography.fontBodyMdMedium,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
)
|
||||
|
|
@ -87,9 +87,16 @@ fun SessionDetailsView(
|
|||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun SessionDetailsViewPreview() = ElementPreview {
|
||||
SessionDetailsView(
|
||||
deviceName = "Element X Android",
|
||||
deviceId = DeviceId("ILAKNDNASDLK"),
|
||||
signInFormattedTimestamp = "12:34",
|
||||
)
|
||||
Column {
|
||||
SessionDetailsView(
|
||||
deviceName = "Element X Android",
|
||||
deviceId = DeviceId("ILAKNDNASDLK"),
|
||||
signInFormattedTimestamp = "12:34",
|
||||
)
|
||||
SessionDetailsView(
|
||||
deviceName = null,
|
||||
deviceId = DeviceId("ILAKNDNASDLK"),
|
||||
signInFormattedTimestamp = "12:34",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ 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.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -23,7 +24,6 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarType
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
|
|
@ -31,18 +31,21 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
|
||||
/**
|
||||
* Ref: https://www.figma.com/design/lMrKOhS8BEb75GXVq7FnNI/ER-96--User-Verification-by-Emoji?node-id=116-52049
|
||||
*/
|
||||
@Composable
|
||||
fun VerificationUserProfileContent(
|
||||
userId: UserId,
|
||||
displayName: String?,
|
||||
avatarUrl: String?,
|
||||
user: MatrixUser,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val avatarData = remember(userId, displayName, avatarUrl) {
|
||||
AvatarData(id = userId.value, name = displayName, url = avatarUrl, size = AvatarSize.UserVerification)
|
||||
val avatarData = remember(user) {
|
||||
user.getAvatarData(AvatarSize.UserVerification)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
|
|
@ -55,12 +58,20 @@ fun VerificationUserProfileContent(
|
|||
avatarData = avatarData,
|
||||
avatarType = AvatarType.User,
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(12.dp))
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
|
||||
Text(text = displayName ?: userId.value, style = ElementTheme.typography.fontBodyLgMedium, color = ElementTheme.colors.textPrimary)
|
||||
Text(
|
||||
text = user.getBestName(),
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
color = ElementTheme.colors.textPrimary,
|
||||
)
|
||||
|
||||
if (displayName != null) {
|
||||
Text(text = userId.value, style = ElementTheme.typography.fontBodyMdRegular, color = ElementTheme.colors.textSecondary)
|
||||
if (user.displayName.isNullOrEmpty().not()) {
|
||||
Text(
|
||||
text = user.userId.value,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,8 +83,10 @@ internal fun VerificationUserProfileContentPreview() = ElementPreview(
|
|||
drawableFallbackForImages = CommonDrawables.sample_avatar
|
||||
) {
|
||||
VerificationUserProfileContent(
|
||||
userId = UserId("@alice:example.com"),
|
||||
displayName = "Alice",
|
||||
avatarUrl = "https://example.com/avatar.png",
|
||||
user = MatrixUser(
|
||||
userId = UserId("@alice:example.com"),
|
||||
displayName = "Alice",
|
||||
avatarUrl = "https://example.com/avatar.png",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import io.element.android.features.verifysession.impl.ui.aEmojisSessionVerificat
|
|||
import io.element.android.libraries.dateformatter.api.DateFormatter
|
||||
import io.element.android.libraries.dateformatter.test.FakeDateFormatter
|
||||
import io.element.android.libraries.matrix.api.core.FlowId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationRequestDetails
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
|
||||
|
|
@ -293,13 +294,14 @@ class IncomingVerificationPresenterTest {
|
|||
|
||||
private val anIncomingSessionVerificationRequest = VerificationRequest.Incoming.OtherSession(
|
||||
details = SessionVerificationRequestDetails(
|
||||
senderProfile = SessionVerificationRequestDetails.SenderProfile(
|
||||
senderProfile = MatrixUser(
|
||||
userId = A_USER_ID,
|
||||
displayName = "a device name",
|
||||
displayName = "a user name",
|
||||
avatarUrl = null,
|
||||
),
|
||||
flowId = FlowId("flowId"),
|
||||
deviceId = A_DEVICE_ID,
|
||||
deviceDisplayName = "a device name",
|
||||
firstSeenTimestamp = A_TIMESTAMP,
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,20 +10,14 @@ package io.element.android.libraries.matrix.api.verification
|
|||
import android.os.Parcelable
|
||||
import io.element.android.libraries.matrix.api.core.DeviceId
|
||||
import io.element.android.libraries.matrix.api.core.FlowId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class SessionVerificationRequestDetails(
|
||||
val senderProfile: SenderProfile,
|
||||
val senderProfile: MatrixUser,
|
||||
val flowId: FlowId,
|
||||
val deviceId: DeviceId,
|
||||
val deviceDisplayName: String?,
|
||||
val firstSeenTimestamp: Long,
|
||||
) : Parcelable {
|
||||
@Parcelize
|
||||
data class SenderProfile(
|
||||
val userId: UserId,
|
||||
val displayName: String?,
|
||||
val avatarUrl: String?,
|
||||
) : Parcelable
|
||||
}
|
||||
) : Parcelable
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import io.element.android.libraries.matrix.api.user.MatrixUser
|
|||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.impl.encryption.RustEncryptionService
|
||||
import io.element.android.libraries.matrix.impl.exception.mapClientException
|
||||
import io.element.android.libraries.matrix.impl.mapper.map
|
||||
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
||||
import io.element.android.libraries.matrix.impl.media.RustMediaPreviewService
|
||||
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
||||
|
|
@ -75,7 +76,6 @@ import io.element.android.libraries.matrix.impl.roomlist.roomOrNull
|
|||
import io.element.android.libraries.matrix.impl.spaces.RustSpaceService
|
||||
import io.element.android.libraries.matrix.impl.sync.RustSyncService
|
||||
import io.element.android.libraries.matrix.impl.sync.map
|
||||
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
||||
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
|
||||
import io.element.android.libraries.matrix.impl.util.SessionPathsProvider
|
||||
import io.element.android.libraries.matrix.impl.util.cancelAndDestroy
|
||||
|
|
@ -403,7 +403,7 @@ class RustMatrixClient(
|
|||
|
||||
override suspend fun getProfile(userId: UserId): Result<MatrixUser> = withContext(sessionDispatcher) {
|
||||
runCatchingExceptions {
|
||||
innerClient.getProfile(userId.value).let(UserProfileMapper::map)
|
||||
innerClient.getProfile(userId.value).map()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,17 +5,14 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.usersearch
|
||||
package io.element.android.libraries.matrix.impl.mapper
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import org.matrix.rustcomponents.sdk.UserProfile
|
||||
|
||||
object UserProfileMapper {
|
||||
fun map(userProfile: UserProfile): MatrixUser =
|
||||
MatrixUser(
|
||||
userId = UserId(userProfile.userId),
|
||||
displayName = userProfile.displayName,
|
||||
avatarUrl = userProfile.avatarUrl,
|
||||
)
|
||||
}
|
||||
fun UserProfile.map() = MatrixUser(
|
||||
userId = UserId(userId),
|
||||
displayName = displayName,
|
||||
avatarUrl = avatarUrl,
|
||||
)
|
||||
|
|
@ -8,13 +8,16 @@
|
|||
package io.element.android.libraries.matrix.impl.usersearch
|
||||
|
||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import io.element.android.libraries.matrix.impl.mapper.map
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.matrix.rustcomponents.sdk.SearchUsersResults
|
||||
|
||||
object UserSearchResultMapper {
|
||||
fun map(result: SearchUsersResults): MatrixSearchUserResults {
|
||||
return MatrixSearchUserResults(
|
||||
results = result.results.map(UserProfileMapper::map).toImmutableList(),
|
||||
results = result.results
|
||||
.map { userProfile -> userProfile.map() }
|
||||
.toImmutableList(),
|
||||
limited = result.limited,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,22 +12,17 @@ import io.element.android.libraries.matrix.api.core.FlowId
|
|||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationRequestDetails
|
||||
import io.element.android.libraries.matrix.api.verification.VerificationRequest
|
||||
import io.element.android.libraries.matrix.impl.mapper.map
|
||||
import org.matrix.rustcomponents.sdk.SessionVerificationRequestDetails as RustSessionVerificationRequestDetails
|
||||
import org.matrix.rustcomponents.sdk.UserProfile as RustUserProfile
|
||||
|
||||
fun RustSessionVerificationRequestDetails.map() = SessionVerificationRequestDetails(
|
||||
senderProfile = senderProfile.map(),
|
||||
flowId = FlowId(flowId),
|
||||
deviceId = DeviceId(deviceId),
|
||||
deviceDisplayName = deviceDisplayName,
|
||||
firstSeenTimestamp = firstSeenTimestamp.toLong(),
|
||||
)
|
||||
|
||||
fun RustUserProfile.map() = SessionVerificationRequestDetails.SenderProfile(
|
||||
userId = UserId(userId),
|
||||
displayName = displayName,
|
||||
avatarUrl = avatarUrl,
|
||||
)
|
||||
|
||||
fun RustSessionVerificationRequestDetails.toVerificationRequest(currentUserId: UserId): VerificationRequest.Incoming {
|
||||
val details = map()
|
||||
return if (currentUserId == details.senderProfile.userId) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.matrix.impl.usersearch
|
||||
package io.element.android.libraries.matrix.impl.mapper
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
|
@ -16,7 +16,7 @@ import org.junit.Test
|
|||
class UserProfileMapperTest {
|
||||
@Test
|
||||
fun map() {
|
||||
assertThat(UserProfileMapper.map(aRustUserProfile(A_USER_ID.value, "displayName", "avatarUrl")))
|
||||
assertThat(aRustUserProfile(A_USER_ID.value, "displayName", "avatarUrl").map())
|
||||
.isEqualTo(MatrixUser(A_USER_ID, "displayName", "avatarUrl"))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d345035d1ee105f7fa1702a3f953df99b0bfce2b0cf48cc92e6248d80690e4b5
|
||||
size 14582
|
||||
oid sha256:537781aec261b622c47345b48e8fbfd68e3cf0817bb36bf0e34e83769d6d6d21
|
||||
size 24337
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:15b1f5afddbd729f1ec01326280b11e00f2b7c84e816bd980eac96dc61db92f2
|
||||
size 13970
|
||||
oid sha256:9e5bf90db9ac805e4054c8d9c759181768a61f13bd30092bdf98fe0a962144f8
|
||||
size 23678
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2eecd4b52a31208444d14b5017e42fc31df0391bb0ead311c01c9359a7e42f03
|
||||
size 74367
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:17d9ed21a98412af097ec5f9a209ecfeb33de2c94a3aec2afc1443469106a4f9
|
||||
size 38451
|
||||
oid sha256:f0d95c8515dfe38a3de02fb68a035e41bedac03abadae44e371a85e6f32c9174
|
||||
size 38460
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:78507911cefb2a6c7ab9b0ddf1a7a55bc4c13adadbd3a60075ca7eb89969a8b7
|
||||
size 32351
|
||||
oid sha256:74ecd0909c13895cd8d2e3827fb05fba98bd61f315735b281fd5502a9ae02bd2
|
||||
size 32354
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:541458c40f7b0e7c1dd18ba9211564fb053c264e965a7aaaede4e39c11a6420c
|
||||
size 37505
|
||||
oid sha256:18e41a828de1e73f0909449c096bc7d9660e5b677075845657267db731b913ab
|
||||
size 37597
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f268e84b9d477429d817fc4b80ff99fbaff45434e236bae0ce05d656b4337675
|
||||
size 31620
|
||||
oid sha256:6242746ae0ba35d6e2e4a9c1d4c2a5e9433015eb7711767342afe4386edecfa1
|
||||
size 31701
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:84870e3b5554f97ff8093286bbf246b74b3bfa787a8318304740f55492809721
|
||||
size 12397
|
||||
oid sha256:43836f421a5f9ab68e4a3f6b3430a6d3daeec9f737bc1b20940a3fc9597057c3
|
||||
size 12451
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:72e7183662d01486545e6702faf22dd867cc47ed72a50b8cd2c24a307cef58c9
|
||||
size 12408
|
||||
oid sha256:053fe3e5699e98280bd40008a26f92a64e34c0f3bda1a52434137745e1ed9cf2
|
||||
size 12360
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue