Merge pull request #5017 from element-hq/feature/bma/a11y/sessionVerification
[a11y] Improve session verification screens
This commit is contained in:
commit
c40badec65
31 changed files with 123 additions and 209 deletions
|
|
@ -29,13 +29,13 @@ import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
import io.element.android.features.analytics.api.AnalyticsOptInEvents
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
import io.element.android.libraries.designsystem.atomic.organisms.InfoListItem
|
||||||
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrganism
|
||||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
import io.element.android.libraries.designsystem.components.BigIcon
|
||||||
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
import io.element.android.libraries.designsystem.components.ClickableLinkText
|
||||||
import io.element.android.libraries.designsystem.components.PageTitle
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
|
||||||
|
|
@ -89,10 +89,10 @@ private fun AnalyticsOptInHeader(
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
PageTitle(
|
IconTitleSubtitleMolecule(
|
||||||
modifier = Modifier.padding(top = 60.dp, bottom = 12.dp),
|
modifier = Modifier.padding(top = 60.dp, bottom = 28.dp),
|
||||||
title = stringResource(id = R.string.screen_analytics_prompt_title, state.applicationName),
|
title = stringResource(id = R.string.screen_analytics_prompt_title, state.applicationName),
|
||||||
subtitle = stringResource(id = R.string.screen_analytics_prompt_help_us_improve),
|
subTitle = stringResource(id = R.string.screen_analytics_prompt_help_us_improve),
|
||||||
iconStyle = BigIcon.Style.Default(CompoundIcons.Chart())
|
iconStyle = BigIcon.Style.Default(CompoundIcons.Chart())
|
||||||
)
|
)
|
||||||
if (state.hasPolicyLink) {
|
if (state.hasPolicyLink) {
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,10 @@ import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.features.ftue.impl.R
|
import io.element.android.features.ftue.impl.R
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
import io.element.android.libraries.designsystem.components.BigIcon
|
||||||
import io.element.android.libraries.designsystem.components.PageTitle
|
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
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.AvatarData
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
|
|
@ -59,7 +59,7 @@ fun NotificationsOptInView(
|
||||||
.statusBarsPadding()
|
.statusBarsPadding()
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
background = { OnboardingBackground() },
|
background = { OnboardingBackground() },
|
||||||
header = { NotificationsOptInHeader(modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)) },
|
header = { NotificationsOptInHeader(modifier = Modifier.padding(top = 60.dp, bottom = 28.dp)) },
|
||||||
footer = { NotificationsOptInFooter(state) },
|
footer = { NotificationsOptInFooter(state) },
|
||||||
) {
|
) {
|
||||||
NotificationsOptInContent()
|
NotificationsOptInContent()
|
||||||
|
|
@ -70,10 +70,10 @@ fun NotificationsOptInView(
|
||||||
private fun NotificationsOptInHeader(
|
private fun NotificationsOptInHeader(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
PageTitle(
|
IconTitleSubtitleMolecule(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
title = stringResource(R.string.screen_notification_optin_title),
|
title = stringResource(R.string.screen_notification_optin_title),
|
||||||
subtitle = stringResource(R.string.screen_notification_optin_subtitle),
|
subTitle = stringResource(R.string.screen_notification_optin_subtitle),
|
||||||
iconStyle = BigIcon.Style.Default(CompoundIcons.NotificationsSolid()),
|
iconStyle = BigIcon.Style.Default(CompoundIcons.NotificationsSolid()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.features.ftue.impl.R
|
import io.element.android.features.ftue.impl.R
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
import io.element.android.libraries.designsystem.components.BigIcon
|
||||||
import io.element.android.libraries.designsystem.components.PageTitle
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Button
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
|
@ -65,10 +65,11 @@ fun ChooseSelfVerificationModeView(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
header = {
|
header = {
|
||||||
PageTitle(
|
IconTitleSubtitleMolecule(
|
||||||
|
modifier = Modifier.padding(bottom = 16.dp),
|
||||||
iconStyle = BigIcon.Style.Default(CompoundIcons.LockSolid()),
|
iconStyle = BigIcon.Style.Default(CompoundIcons.LockSolid()),
|
||||||
title = stringResource(id = R.string.screen_identity_confirmation_title),
|
title = stringResource(id = R.string.screen_identity_confirmation_title),
|
||||||
subtitle = stringResource(id = R.string.screen_identity_confirmation_subtitle)
|
subTitle = stringResource(id = R.string.screen_identity_confirmation_subtitle)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
footer = {
|
footer = {
|
||||||
|
|
|
||||||
|
|
@ -36,5 +36,9 @@ data class IncomingVerificationState(
|
||||||
data object Canceled : Step
|
data object Canceled : Step
|
||||||
data object Completed : Step
|
data object Completed : Step
|
||||||
data object Failure : Step
|
data object Failure : Step
|
||||||
|
|
||||||
|
val isTimeLimited: Boolean
|
||||||
|
get() = this is Initial ||
|
||||||
|
this is Verifying
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.features.verifysession.impl.incoming
|
package io.element.android.features.verifysession.impl.incoming
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.focusable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
@ -19,6 +20,11 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.ProgressBarRangeInfo
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
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.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -30,9 +36,9 @@ import io.element.android.features.verifysession.impl.incoming.ui.SessionDetails
|
||||||
import io.element.android.features.verifysession.impl.ui.VerificationBottomMenu
|
import io.element.android.features.verifysession.impl.ui.VerificationBottomMenu
|
||||||
import io.element.android.features.verifysession.impl.ui.VerificationContentVerifying
|
import io.element.android.features.verifysession.impl.ui.VerificationContentVerifying
|
||||||
import io.element.android.features.verifysession.impl.ui.VerificationUserProfileContent
|
import io.element.android.features.verifysession.impl.ui.VerificationUserProfileContent
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
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.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
|
@ -140,10 +146,26 @@ private fun IncomingVerificationHeader(step: Step, request: VerificationRequest.
|
||||||
}
|
}
|
||||||
Step.Failure -> R.string.screen_session_verification_request_failure_subtitle
|
Step.Failure -> R.string.screen_session_verification_request_failure_subtitle
|
||||||
}
|
}
|
||||||
PageTitle(
|
val timeLimitMessage = if (step.isTimeLimited) {
|
||||||
|
stringResource(CommonStrings.a11y_time_limited_action_required)
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
IconTitleSubtitleMolecule(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(bottom = 16.dp)
|
||||||
|
.semantics(mergeDescendants = true) {
|
||||||
|
contentDescription = timeLimitMessage
|
||||||
|
focused = true
|
||||||
|
if (iconStyle == BigIcon.Style.Loading) {
|
||||||
|
// Same code than Modifier.progressSemantics()
|
||||||
|
progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focusable(),
|
||||||
iconStyle = iconStyle,
|
iconStyle = iconStyle,
|
||||||
title = stringResource(id = titleTextId),
|
title = stringResource(id = titleTextId),
|
||||||
subtitle = stringResource(id = subtitleTextId)
|
subTitle = stringResource(id = subtitleTextId),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -187,7 +209,9 @@ private fun ContentInitial(
|
||||||
}
|
}
|
||||||
is VerificationRequest.Incoming.User -> {
|
is VerificationRequest.Incoming.User -> {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth().padding(top = 24.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 24.dp),
|
||||||
) {
|
) {
|
||||||
VerificationUserProfileContent(
|
VerificationUserProfileContent(
|
||||||
userId = request.details.senderProfile.userId,
|
userId = request.details.senderProfile.userId,
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.verifysession.impl.R
|
import io.element.android.features.verifysession.impl.R
|
||||||
|
|
@ -46,7 +47,8 @@ fun SessionDetailsView(
|
||||||
color = ElementTheme.colors.borderDisabled,
|
color = ElementTheme.colors.borderDisabled,
|
||||||
shape = RoundedCornerShape(8.dp)
|
shape = RoundedCornerShape(8.dp)
|
||||||
)
|
)
|
||||||
.padding(24.dp),
|
.padding(24.dp)
|
||||||
|
.semantics(mergeDescendants = true) {},
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -76,6 +78,7 @@ fun SessionDetailsView(
|
||||||
label = stringResource(CommonStrings.common_device_id),
|
label = stringResource(CommonStrings.common_device_id),
|
||||||
text = deviceId.value,
|
text = deviceId.value,
|
||||||
modifier = Modifier.weight(5f),
|
modifier = Modifier.weight(5f),
|
||||||
|
spellText = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,5 +29,11 @@ data class OutgoingVerificationState(
|
||||||
data class Verifying(val data: SessionVerificationData, val state: AsyncData<Unit>) : Step
|
data class Verifying(val data: SessionVerificationData, val state: AsyncData<Unit>) : Step
|
||||||
data object Completed : Step
|
data object Completed : Step
|
||||||
data object Exit : Step
|
data object Exit : Step
|
||||||
|
|
||||||
|
val isTimeLimited: Boolean
|
||||||
|
get() = this is Initial ||
|
||||||
|
this is AwaitingOtherDeviceResponse ||
|
||||||
|
this is Ready ||
|
||||||
|
this is Verifying
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ package io.element.android.features.verifysession.impl.outgoing
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.focusable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
|
@ -22,6 +23,11 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.ProgressBarRangeInfo
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
import androidx.compose.ui.semantics.focused
|
||||||
|
import androidx.compose.ui.semantics.progressBarRangeInfo
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
|
|
@ -31,9 +37,9 @@ import io.element.android.features.verifysession.impl.outgoing.OutgoingVerificat
|
||||||
import io.element.android.features.verifysession.impl.ui.VerificationBottomMenu
|
import io.element.android.features.verifysession.impl.ui.VerificationBottomMenu
|
||||||
import io.element.android.features.verifysession.impl.ui.VerificationContentVerifying
|
import io.element.android.features.verifysession.impl.ui.VerificationContentVerifying
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
import io.element.android.libraries.designsystem.atomic.pages.HeaderFooterPage
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
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.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
|
@ -180,11 +186,26 @@ private fun OutgoingVerificationHeader(step: Step, request: VerificationRequest.
|
||||||
}
|
}
|
||||||
is Step.Exit -> return
|
is Step.Exit -> return
|
||||||
}
|
}
|
||||||
|
val timeLimitMessage = if (step.isTimeLimited) {
|
||||||
PageTitle(
|
stringResource(CommonStrings.a11y_time_limited_action_required)
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
IconTitleSubtitleMolecule(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(bottom = 16.dp)
|
||||||
|
.semantics(mergeDescendants = true) {
|
||||||
|
contentDescription = timeLimitMessage
|
||||||
|
focused = true
|
||||||
|
if (iconStyle == BigIcon.Style.Loading) {
|
||||||
|
// Same code than Modifier.progressSemantics()
|
||||||
|
progressBarRangeInfo = ProgressBarRangeInfo.Indeterminate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focusable(),
|
||||||
iconStyle = iconStyle,
|
iconStyle = iconStyle,
|
||||||
title = stringResource(id = titleTextId),
|
title = stringResource(id = titleTextId),
|
||||||
subtitle = stringResource(id = subtitleTextId)
|
subTitle = stringResource(id = subtitleTextId),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
@ -39,14 +41,20 @@ internal fun VerificationContentVerifying(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier.fillMaxSize().padding(bottom = 20.dp),
|
modifier = modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(bottom = 20.dp),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
when (data) {
|
when (data) {
|
||||||
is SessionVerificationData.Decimals -> {
|
is SessionVerificationData.Decimals -> {
|
||||||
val text = data.decimals.joinToString(separator = " - ") { it.toString() }
|
val text = data.decimals.joinToString(separator = " - ")
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.semantics {
|
||||||
|
contentDescription = data.decimals.joinToString()
|
||||||
|
},
|
||||||
text = text,
|
text = text,
|
||||||
style = ElementTheme.typography.fontHeadingLgBold,
|
style = ElementTheme.typography.fontHeadingLgBold,
|
||||||
color = ElementTheme.colors.textPrimary,
|
color = ElementTheme.colors.textPrimary,
|
||||||
|
|
@ -57,7 +65,9 @@ internal fun VerificationContentVerifying(
|
||||||
// We want each row to have up to 4 emojis
|
// We want each row to have up to 4 emojis
|
||||||
val rows = data.emojis.chunked(4)
|
val rows = data.emojis.chunked(4)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.semantics(mergeDescendants = true) {},
|
||||||
verticalArrangement = Arrangement.spacedBy(40.dp),
|
verticalArrangement = Arrangement.spacedBy(40.dp),
|
||||||
) {
|
) {
|
||||||
rows.forEach { emojis ->
|
rows.forEach { emojis ->
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,26 @@ package io.element.android.libraries.designsystem.atomic.molecules
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
|
import androidx.compose.ui.semantics.semantics
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a label and a text in a column.
|
||||||
|
* @param label the label to display
|
||||||
|
* @param text the text to display
|
||||||
|
* @param modifier the modifier to apply to this layout
|
||||||
|
* @param spellText if true, the text will be spelled out in the content description for accessibility.
|
||||||
|
* Useful for deviceId for instance, that the screen reader will read as a list of letters instead of trying to read a
|
||||||
|
* word of random characters.
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun TextWithLabelMolecule(
|
fun TextWithLabelMolecule(
|
||||||
label: String,
|
label: String,
|
||||||
text: String,
|
text: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
spellText: Boolean = false,
|
||||||
) {
|
) {
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -26,6 +38,11 @@ fun TextWithLabelMolecule(
|
||||||
color = ElementTheme.colors.textSecondary,
|
color = ElementTheme.colors.textSecondary,
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
|
modifier = Modifier.semantics {
|
||||||
|
if (spellText) {
|
||||||
|
contentDescription = text.toList().joinToString()
|
||||||
|
}
|
||||||
|
},
|
||||||
text = text,
|
text = text,
|
||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
style = ElementTheme.typography.fontBodyMdRegular,
|
||||||
color = ElementTheme.colors.textPrimary,
|
color = ElementTheme.colors.textPrimary,
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
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.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
|
@ -69,9 +69,10 @@ fun FlowStepPage(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
header = {
|
header = {
|
||||||
PageTitle(
|
IconTitleSubtitleMolecule(
|
||||||
|
modifier = Modifier.padding(bottom = 16.dp),
|
||||||
title = title,
|
title = title,
|
||||||
subtitle = subTitle,
|
subTitle = subTitle,
|
||||||
iconStyle = iconStyle,
|
iconStyle = iconStyle,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,126 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2024 New Vector Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
||||||
* Please see LICENSE files in the repository root for full details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.element.android.libraries.designsystem.components
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
|
||||||
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.libraries.designsystem.preview.ElementPreview
|
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
|
||||||
import io.element.android.libraries.designsystem.theme.components.TextButton
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compound component that displays a big icon, a title, an optional subtitle and an optional call to action component.
|
|
||||||
*
|
|
||||||
* @param title the title to display
|
|
||||||
* @param iconStyle the style of the [BigIcon] to display
|
|
||||||
* @param modifier the modifier to apply to this layout
|
|
||||||
* @param subtitle the optional subtitle to display. It defaults to `null`
|
|
||||||
* @param callToAction the optional call to action component to display. It defaults to `null`
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
fun PageTitle(
|
|
||||||
title: AnnotatedString,
|
|
||||||
iconStyle: BigIcon.Style,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
subtitle: AnnotatedString? = null,
|
|
||||||
callToAction: @Composable (() -> Unit)? = null,
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = modifier.fillMaxWidth(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
) {
|
|
||||||
BigIcon(style = iconStyle)
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.padding(vertical = 16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
text = title,
|
|
||||||
style = ElementTheme.typography.fontHeadingMdBold,
|
|
||||||
color = ElementTheme.colors.textPrimary,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
|
|
||||||
subtitle?.let {
|
|
||||||
Text(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
text = it,
|
|
||||||
style = ElementTheme.typography.fontBodyMdRegular,
|
|
||||||
color = ElementTheme.colors.textSecondary,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callToAction?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compound component that displays a big icon, a title, an optional subtitle and an optional call to action component.
|
|
||||||
*
|
|
||||||
* @param title the title to display
|
|
||||||
* @param iconStyle the style of the [BigIcon] to display
|
|
||||||
* @param modifier the modifier to apply to this layout
|
|
||||||
* @param subtitle the optional subtitle to display. It defaults to `null`
|
|
||||||
* @param callToAction the optional call to action component to display. It defaults to `null`
|
|
||||||
*/
|
|
||||||
@Composable
|
|
||||||
fun PageTitle(
|
|
||||||
title: String,
|
|
||||||
iconStyle: BigIcon.Style,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
subtitle: String? = null,
|
|
||||||
callToAction: @Composable (() -> Unit)? = null,
|
|
||||||
) = PageTitle(
|
|
||||||
title = AnnotatedString(title),
|
|
||||||
iconStyle = iconStyle,
|
|
||||||
modifier = modifier,
|
|
||||||
subtitle = subtitle?.let { AnnotatedString(it) },
|
|
||||||
callToAction = callToAction
|
|
||||||
)
|
|
||||||
|
|
||||||
@PreviewsDayNight
|
|
||||||
@Composable
|
|
||||||
internal fun PageTitleWithIconFullPreview(@PreviewParameter(BigIconStyleProvider::class) style: BigIcon.Style) {
|
|
||||||
ElementPreview {
|
|
||||||
PageTitle(
|
|
||||||
modifier = Modifier.padding(top = 24.dp),
|
|
||||||
title = AnnotatedString("Headline"),
|
|
||||||
subtitle = AnnotatedString("Description goes here"),
|
|
||||||
iconStyle = style,
|
|
||||||
callToAction = {
|
|
||||||
TextButton(text = "Learn more", onClick = {})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PreviewsDayNight
|
|
||||||
@Composable
|
|
||||||
internal fun PageTitleWithIconMinimalPreview() {
|
|
||||||
ElementPreview {
|
|
||||||
PageTitle(
|
|
||||||
modifier = Modifier.padding(top = 24.dp),
|
|
||||||
title = "Headline",
|
|
||||||
iconStyle = BigIcon.Style.Default(CompoundIcons.CheckCircleSolid()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -11,7 +11,9 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
|
@ -28,8 +30,8 @@ import androidx.compose.ui.unit.dp
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
import io.element.android.libraries.designsystem.components.BigIcon
|
||||||
import io.element.android.libraries.designsystem.components.PageTitle
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Button
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
|
@ -57,14 +59,15 @@ fun MediaDeleteConfirmationBottomSheet(
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp),
|
.padding(horizontal = 16.dp),
|
||||||
) {
|
) {
|
||||||
PageTitle(
|
IconTitleSubtitleMolecule(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 16.dp, horizontal = 8.dp),
|
.padding(vertical = 16.dp, horizontal = 8.dp),
|
||||||
title = stringResource(R.string.screen_media_browser_delete_confirmation_title),
|
title = stringResource(R.string.screen_media_browser_delete_confirmation_title),
|
||||||
iconStyle = BigIcon.Style.Default(CompoundIcons.Delete(), useCriticalTint = true),
|
iconStyle = BigIcon.Style.Default(CompoundIcons.Delete(), useCriticalTint = true),
|
||||||
subtitle = stringResource(R.string.screen_media_browser_delete_confirmation_subtitle),
|
subTitle = stringResource(R.string.screen_media_browser_delete_confirmation_subtitle),
|
||||||
)
|
)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
MediaRow(
|
MediaRow(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,9 @@ import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
|
import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubtitleMolecule
|
||||||
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
import io.element.android.libraries.designsystem.background.OnboardingBackground
|
||||||
import io.element.android.libraries.designsystem.components.BigIcon
|
import io.element.android.libraries.designsystem.components.BigIcon
|
||||||
import io.element.android.libraries.designsystem.components.PageTitle
|
|
||||||
import io.element.android.libraries.designsystem.components.async.AsyncFailure
|
import io.element.android.libraries.designsystem.components.async.AsyncFailure
|
||||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
|
@ -472,14 +472,14 @@ private fun EmptyContent(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
OnboardingBackground()
|
OnboardingBackground()
|
||||||
PageTitle(
|
IconTitleSubtitleMolecule(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(top = 44.dp)
|
.padding(top = 44.dp)
|
||||||
.padding(24.dp),
|
.padding(24.dp),
|
||||||
title = stringResource(titleRes),
|
title = stringResource(titleRes),
|
||||||
iconStyle = BigIcon.Style.Default(icon),
|
iconStyle = BigIcon.Style.Default(icon),
|
||||||
subtitle = stringResource(subtitleRes),
|
subTitle = stringResource(subtitleRes),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,6 @@ class KonsistPreviewTest {
|
||||||
"MessagesReactionButtonAddPreview",
|
"MessagesReactionButtonAddPreview",
|
||||||
"MessagesReactionButtonExtraPreview",
|
"MessagesReactionButtonExtraPreview",
|
||||||
"MessagesViewWithIdentityChangePreview",
|
"MessagesViewWithIdentityChangePreview",
|
||||||
"PageTitleWithIconFullPreview",
|
|
||||||
"PageTitleWithIconMinimalPreview",
|
|
||||||
"PendingMemberRowWithLongNamePreview",
|
"PendingMemberRowWithLongNamePreview",
|
||||||
"PinUnlockViewInAppPreview",
|
"PinUnlockViewInAppPreview",
|
||||||
"PollAnswerViewDisclosedNotSelectedPreview",
|
"PollAnswerViewDisclosedNotSelectedPreview",
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:9ea4fd71bc94982578bc061607066dfd3efe55aeccbec69b6826fd345113f95e
|
|
||||||
size 13296
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:56aabf6f359235c77b7bffa3d7e2c4ebf7b2c688eaf9e2d8a67da9a00433ebcb
|
|
||||||
size 12350
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:058f539d2f7652342394adb681084147dcc2d4a1e24f9c8efd47781a0def4c33
|
|
||||||
size 12925
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:315e1d831a1e3082a9d4ea749b76b374b0f8018c6d5c11b1f48ed34db3b3a1c5
|
|
||||||
size 13279
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:eb1c80dfc5926f3aa29ab5118f8c5a6a62ab13a1247e198e32f00509723cd4e3
|
|
||||||
size 12550
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:61c83e013e73d55a6b3504f34dcdb0111744499172839a71c35ada67cece1184
|
|
||||||
size 13162
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:d81aade2945be977896038addacdb9246d17bb1a57fb3bd0d43169e382ce9f03
|
|
||||||
size 13126
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:46639efc4726cfb78ba5955c7c56619ce06342ef222c4c06eb8829c22d90e6f7
|
|
||||||
size 13200
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:316d70aa6507a9b0c5ab9833d750033df44f8197ca3f25d7f6acbfc496b68d59
|
|
||||||
size 12184
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:d07c5029da082dcce7b86a202ea611e089ddb1e379d2511395f75dfabdedd5d3
|
|
||||||
size 13034
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:da1945462f70133c47e33eaaa9dfc3d64033c6a83d4d50b03776adcc7a7f77e0
|
|
||||||
size 13334
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:d4871583b442845d3ae8e3dd98f4099fb7906f2ccccf25b61aad59efb8112c62
|
|
||||||
size 12259
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:0d2d9b68cff6f00bf12eed5df4123af7da908ae3e25e710e5ce305f36b404382
|
|
||||||
size 13101
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:610e68016011b14db56217ebcd27a86ab597c1668a3a90b09c3e39ac308f8764
|
|
||||||
size 13054
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a1638d8805c8029573b8cae9a71c3c2dddf569d5154969f49085def60ec74ec8
|
|
||||||
size 7545
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:19c89df3b96fad54d28fdd608cec70d2d8c71fb20901746abacd9bcc26fd5332
|
|
||||||
size 7579
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue