Merge pull request #3649 from element-hq/feature/bma/cryptoCopyAdjustment
Crypto copy adjustment
This commit is contained in:
commit
19f0be51fe
21 changed files with 127 additions and 61 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
package io.element.android.appconfig
|
package io.element.android.appconfig
|
||||||
|
|
||||||
object LearnMoreConfig {
|
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 SECURE_BACKUP_URL: String = "https://element.io/help#encryption5"
|
||||||
const val IDENTITY_CHANGE_URL: String = "https://element.io/help#encryption18"
|
const val IDENTITY_CHANGE_URL: String = "https://element.io/help#encryption18"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ 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
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -50,7 +49,7 @@ fun ResetIdentityRootView(
|
||||||
buttons = {
|
buttons = {
|
||||||
Button(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(id = CommonStrings.action_continue),
|
text = stringResource(id = R.string.screen_encryption_reset_action_continue_reset),
|
||||||
onClick = { state.eventSink(ResetIdentityRootEvent.Continue) },
|
onClick = { state.eventSink(ResetIdentityRootEvent.Continue) },
|
||||||
destructive = true,
|
destructive = true,
|
||||||
)
|
)
|
||||||
|
|
@ -98,9 +97,9 @@ private fun Content() {
|
||||||
iconComposable = {
|
iconComposable = {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(20.dp),
|
modifier = Modifier.size(20.dp),
|
||||||
imageVector = CompoundIcons.Close(),
|
imageVector = CompoundIcons.Info(),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = ElementTheme.colors.iconCriticalPrimary,
|
tint = ElementTheme.colors.iconSecondary,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
@ -109,9 +108,9 @@ private fun Content() {
|
||||||
iconComposable = {
|
iconComposable = {
|
||||||
Icon(
|
Icon(
|
||||||
modifier = Modifier.size(20.dp),
|
modifier = Modifier.size(20.dp),
|
||||||
imageVector = CompoundIcons.Close(),
|
imageVector = CompoundIcons.Info(),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = ElementTheme.colors.iconCriticalPrimary,
|
tint = ElementTheme.colors.iconSecondary,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<string name="screen_create_new_recovery_key_title">"Reset the encryption for your account using another device"</string>
|
<string name="screen_create_new_recovery_key_title">"Reset the encryption for your account using another device"</string>
|
||||||
<string name="screen_encryption_reset_action_continue_reset">"Continue reset"</string>
|
<string name="screen_encryption_reset_action_continue_reset">"Continue reset"</string>
|
||||||
<string name="screen_encryption_reset_bullet_1">"Your account details, contacts, preferences, and chat list will be kept"</string>
|
<string name="screen_encryption_reset_bullet_1">"Your account details, contacts, preferences, and chat list will be kept"</string>
|
||||||
<string name="screen_encryption_reset_bullet_2">"You will lose your existing message history unless it is stored on another device"</string>
|
<string name="screen_encryption_reset_bullet_2">"You will lose any message history that’s stored only on the server"</string>
|
||||||
<string name="screen_encryption_reset_bullet_3">"You will need to verify all your existing devices and contacts again"</string>
|
<string name="screen_encryption_reset_bullet_3">"You will need to verify all your existing devices and contacts again"</string>
|
||||||
<string name="screen_encryption_reset_footer">"Only reset your identity if you don’t have access to another signed-in device and you’ve lost your recovery key."</string>
|
<string name="screen_encryption_reset_footer">"Only reset your identity if you don’t have access to another signed-in device and you’ve lost your recovery key."</string>
|
||||||
<string name="screen_encryption_reset_title">"Can\'t confirm? You’ll need to reset your identity."</string>
|
<string name="screen_encryption_reset_title">"Can\'t confirm? You’ll need to reset your identity."</string>
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class ResetIdentityRootViewTest {
|
||||||
ResetIdentityRootState(displayConfirmationDialog = false, eventSink = eventsRecorder),
|
ResetIdentityRootState(displayConfirmationDialog = false, eventSink = eventsRecorder),
|
||||||
)
|
)
|
||||||
|
|
||||||
rule.clickOn(CommonStrings.action_continue)
|
rule.clickOn(R.string.screen_encryption_reset_action_continue_reset)
|
||||||
|
|
||||||
eventsRecorder.assertSingle(ResetIdentityRootEvent.Continue)
|
eventsRecorder.assertSingle(ResetIdentityRootEvent.Continue)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ android {
|
||||||
setupAnvil()
|
setupAnvil()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(projects.appconfig)
|
||||||
|
implementation(projects.libraries.androidutils)
|
||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
implementation(projects.libraries.architecture)
|
implementation(projects.libraries.architecture)
|
||||||
implementation(projects.libraries.matrix.api)
|
implementation(projects.libraries.matrix.api)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@ import com.bumble.appyx.core.plugin.plugins
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.appconfig.LearnMoreConfig
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.features.logout.api.util.onSuccessLogout
|
import io.element.android.features.logout.api.util.onSuccessLogout
|
||||||
import io.element.android.features.verifysession.api.VerifySessionEntryPoint
|
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.architecture.inputs
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
|
||||||
|
|
@ -36,6 +38,10 @@ class VerifySelfSessionNode @AssistedInject constructor(
|
||||||
showDeviceVerifiedScreen = inputs<VerifySessionEntryPoint.Params>().showDeviceVerifiedScreen,
|
showDeviceVerifiedScreen = inputs<VerifySessionEntryPoint.Params>().showDeviceVerifiedScreen,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun onLearnMoreClick(activity: Activity, dark: Boolean) {
|
||||||
|
activity.openUrlInChromeCustomTab(null, dark, LearnMoreConfig.ENCRYPTION_URL)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
val state = presenter.present()
|
val state = presenter.present()
|
||||||
|
|
@ -44,6 +50,9 @@ class VerifySelfSessionNode @AssistedInject constructor(
|
||||||
VerifySelfSessionView(
|
VerifySelfSessionView(
|
||||||
state = state,
|
state = state,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
onLearnMoreClick = {
|
||||||
|
onLearnMoreClick(activity, isDark)
|
||||||
|
},
|
||||||
onEnterRecoveryKey = callback::onEnterRecoveryKey,
|
onEnterRecoveryKey = callback::onEnterRecoveryKey,
|
||||||
onResetKey = callback::onResetKey,
|
onResetKey = callback::onResetKey,
|
||||||
onFinish = callback::onDone,
|
onFinish = callback::onDone,
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ data class VerifySelfSessionState(
|
||||||
@Stable
|
@Stable
|
||||||
sealed interface VerificationStep {
|
sealed interface VerificationStep {
|
||||||
data object Loading : VerificationStep
|
data object Loading : VerificationStep
|
||||||
|
|
||||||
|
// FIXME canEnterRecoveryKey value is never read.
|
||||||
data class Initial(val canEnterRecoveryKey: Boolean, val isLastDevice: Boolean = false) : VerificationStep
|
data class Initial(val canEnterRecoveryKey: Boolean, val isLastDevice: Boolean = false) : VerificationStep
|
||||||
data object Canceled : VerificationStep
|
data object Canceled : VerificationStep
|
||||||
data object AwaitingOtherDeviceResponse : VerificationStep
|
data object AwaitingOtherDeviceResponse : VerificationStep
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@ package io.element.android.features.verifysession.impl
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
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.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
|
@ -64,6 +64,7 @@ import io.element.android.features.verifysession.impl.VerifySelfSessionState.Ver
|
||||||
@Composable
|
@Composable
|
||||||
fun VerifySelfSessionView(
|
fun VerifySelfSessionView(
|
||||||
state: VerifySelfSessionState,
|
state: VerifySelfSessionState,
|
||||||
|
onLearnMoreClick: () -> Unit,
|
||||||
onEnterRecoveryKey: () -> Unit,
|
onEnterRecoveryKey: () -> Unit,
|
||||||
onResetKey: () -> Unit,
|
onResetKey: () -> Unit,
|
||||||
onFinish: () -> 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
|
@Composable
|
||||||
private fun Content(flowState: FlowStep) {
|
private fun Content(
|
||||||
Column(Modifier.fillMaxHeight(), verticalArrangement = Arrangement.Center) {
|
flowState: FlowStep,
|
||||||
if (flowState is FlowStep.Verifying) {
|
onLearnMoreClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
when (flowState) {
|
||||||
|
is VerifySelfSessionState.VerificationStep.Initial -> {
|
||||||
|
ContentInitial(onLearnMoreClick)
|
||||||
|
}
|
||||||
|
is FlowStep.Verifying -> {
|
||||||
ContentVerifying(flowState)
|
ContentVerifying(flowState)
|
||||||
}
|
}
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private 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
|
@Composable
|
||||||
private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying) {
|
private fun ContentVerifying(verificationFlowStep: FlowStep.Verifying) {
|
||||||
when (verificationFlowStep.data) {
|
Box(
|
||||||
is SessionVerificationData.Decimals -> {
|
modifier = Modifier.fillMaxSize(),
|
||||||
val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() }
|
contentAlignment = Alignment.Center
|
||||||
Text(
|
) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
when (verificationFlowStep.data) {
|
||||||
text = text,
|
is SessionVerificationData.Decimals -> {
|
||||||
style = ElementTheme.typography.fontHeadingLgBold,
|
val text = verificationFlowStep.data.decimals.joinToString(separator = " - ") { it.toString() }
|
||||||
color = MaterialTheme.colorScheme.primary,
|
Text(
|
||||||
textAlign = TextAlign.Center,
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
text = text,
|
||||||
}
|
style = ElementTheme.typography.fontHeadingLgBold,
|
||||||
is SessionVerificationData.Emojis -> {
|
color = MaterialTheme.colorScheme.primary,
|
||||||
// We want each row to have up to 4 emojis
|
textAlign = TextAlign.Center,
|
||||||
val rows = verificationFlowStep.data.emojis.chunked(4)
|
)
|
||||||
Column(
|
}
|
||||||
modifier = Modifier.fillMaxWidth(),
|
is SessionVerificationData.Emojis -> {
|
||||||
verticalArrangement = Arrangement.spacedBy(40.dp),
|
// We want each row to have up to 4 emojis
|
||||||
) {
|
val rows = verificationFlowStep.data.emojis.chunked(4)
|
||||||
rows.forEach { emojis ->
|
Column(
|
||||||
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
|
modifier = Modifier.fillMaxWidth(),
|
||||||
for (emoji in emojis) {
|
verticalArrangement = Arrangement.spacedBy(40.dp),
|
||||||
EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp))
|
) {
|
||||||
|
rows.forEach { emojis ->
|
||||||
|
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) {
|
||||||
|
for (emoji in emojis) {
|
||||||
|
EmojiItemView(emoji = emoji, modifier = Modifier.widthIn(max = 60.dp))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -292,14 +326,14 @@ private fun BottomMenu(
|
||||||
text = stringResource(R.string.screen_identity_use_another_device),
|
text = stringResource(R.string.screen_identity_use_another_device),
|
||||||
onClick = { eventSink(VerifySelfSessionViewEvents.RequestVerification) },
|
onClick = { eventSink(VerifySelfSessionViewEvents.RequestVerification) },
|
||||||
)
|
)
|
||||||
OutlinedButton(
|
Button(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.screen_session_verification_enter_recovery_key),
|
text = stringResource(R.string.screen_session_verification_enter_recovery_key),
|
||||||
onClick = onEnterRecoveryKey,
|
onClick = onEnterRecoveryKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// This option should always be displayed
|
// This option should always be displayed
|
||||||
TextButton(
|
OutlinedButton(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
text = stringResource(R.string.screen_identity_confirmation_cannot_confirm),
|
text = stringResource(R.string.screen_identity_confirmation_cannot_confirm),
|
||||||
onClick = onResetKey,
|
onClick = onResetKey,
|
||||||
|
|
@ -402,6 +436,7 @@ private fun BottomMenu(
|
||||||
internal fun VerifySelfSessionViewPreview(@PreviewParameter(VerifySelfSessionStateProvider::class) state: VerifySelfSessionState) = ElementPreview {
|
internal fun VerifySelfSessionViewPreview(@PreviewParameter(VerifySelfSessionStateProvider::class) state: VerifySelfSessionState) = ElementPreview {
|
||||||
VerifySelfSessionView(
|
VerifySelfSessionView(
|
||||||
state = state,
|
state = state,
|
||||||
|
onLearnMoreClick = {},
|
||||||
onEnterRecoveryKey = {},
|
onEnterRecoveryKey = {},
|
||||||
onResetKey = {},
|
onResetKey = {},
|
||||||
onFinish = {},
|
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
|
@Test
|
||||||
fun `clicking on they match emits the expected event`() {
|
fun `clicking on they match emits the expected event`() {
|
||||||
val eventsRecorder = EventsRecorder<VerifySelfSessionViewEvents>()
|
val eventsRecorder = EventsRecorder<VerifySelfSessionViewEvents>()
|
||||||
|
|
@ -222,6 +238,7 @@ class VerifySelfSessionViewTest {
|
||||||
|
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setVerifySelfSessionView(
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setVerifySelfSessionView(
|
||||||
state: VerifySelfSessionState,
|
state: VerifySelfSessionState,
|
||||||
|
onLearnMoreClick: () -> Unit = EnsureNeverCalled(),
|
||||||
onEnterRecoveryKey: () -> Unit = EnsureNeverCalled(),
|
onEnterRecoveryKey: () -> Unit = EnsureNeverCalled(),
|
||||||
onFinished: () -> Unit = EnsureNeverCalled(),
|
onFinished: () -> Unit = EnsureNeverCalled(),
|
||||||
onResetKey: () -> Unit = EnsureNeverCalled(),
|
onResetKey: () -> Unit = EnsureNeverCalled(),
|
||||||
|
|
@ -230,6 +247,7 @@ class VerifySelfSessionViewTest {
|
||||||
setContent {
|
setContent {
|
||||||
VerifySelfSessionView(
|
VerifySelfSessionView(
|
||||||
state = state,
|
state = state,
|
||||||
|
onLearnMoreClick = onLearnMoreClick,
|
||||||
onEnterRecoveryKey = onEnterRecoveryKey,
|
onEnterRecoveryKey = onEnterRecoveryKey,
|
||||||
onFinish = onFinished,
|
onFinish = onFinished,
|
||||||
onResetKey = onResetKey,
|
onResetKey = onResetKey,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ad503075a2ff0e5fcd544c66a1a1b186abc2d05126facc397e0d812cd2206fc5
|
oid sha256:4a3d734e3d2a572344ab26b042cf249afc56c7eff2d1454565ddc75e54faaced
|
||||||
size 71628
|
size 69147
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:669a2f51c4276c4582e624dda9779d008a01452f0f2a1331f9fbb2b7bbbb38de
|
oid sha256:0a41f758a358792131a03f7015710fe28c9e8fecb49cafa72fe4b0a0a21bbf9d
|
||||||
size 58159
|
size 58206
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9a8c8d8ed03e7f85a0954bd06ac70336994dfaaec318c1d7f2c386f062e6c1e9
|
oid sha256:676c85998a4b76894de1cbf470e18876abc791cc56a8322db9e1d24e32adfd56
|
||||||
size 70136
|
size 67963
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d2ffe911b13cbedf16829ed0b449f291d291f64d87917b827836a97204fe8c65
|
oid sha256:a3f8388e77e222255f9bcd04c81094a88d57176f588feb476146035f56c0054c
|
||||||
size 56167
|
size 56116
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e9513b48683bec56a8892bcc4f953117547bc570acd20dda760fb60904532449
|
oid sha256:ea4aeceb9e0d72642c9be0d8dd1abc7a3b82bd05ce05a07aa95bec4e0b2a9df0
|
||||||
size 31501
|
size 34612
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4e5ecf84200d3c3f1e213552568bb8c1893975403363bfe9856414208ff7d84b
|
oid sha256:4a6896e2fc99b34d37dbc7494c21990d31aa6fb99500d61764b7d04afcffca74
|
||||||
size 32678
|
size 33690
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e9513b48683bec56a8892bcc4f953117547bc570acd20dda760fb60904532449
|
oid sha256:ea4aeceb9e0d72642c9be0d8dd1abc7a3b82bd05ce05a07aa95bec4e0b2a9df0
|
||||||
size 31501
|
size 34612
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:05f503995e71fd66a03efc1b675eacf3bf4f90d1b07e73e171ebb78014862ed6
|
oid sha256:84627a80338301f58e1fc877a587ff602c86dff848684d9ba56a49dde4bf2d9d
|
||||||
size 26020
|
size 29801
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8ed7b8e3bdda766f21419bec8f60497b3e4d18f54ec41a65160be363e165073b
|
oid sha256:70adb44af338740cbc2f2297ca172d35563133d163bcfafbfe09295a4aa644c8
|
||||||
size 30567
|
size 33568
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f633d654de29a28d32308039e9b78b72da948de605fcecf4b61ba3aab6068866
|
oid sha256:2cb5f4af03cdab9e432b790c8f5346358659d7338f1aecc6449f816b765d3b36
|
||||||
size 31180
|
size 32191
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8ed7b8e3bdda766f21419bec8f60497b3e4d18f54ec41a65160be363e165073b
|
oid sha256:70adb44af338740cbc2f2297ca172d35563133d163bcfafbfe09295a4aa644c8
|
||||||
size 30567
|
size 33568
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:72d7a54da8502a7e70d0e6b1bcf8c6e2e0d2e78d328f73b7edacec58a2bf99b2
|
oid sha256:65709ff3ec7a5a495370dfc58cdec1898d07e0f6eea8b41caa1ae40579fce817
|
||||||
size 25377
|
size 28896
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue