Iterate on QrCode login error buttons (#6101)
* Iterate on login error: add a cancel button that fully close the flow. tom * Fix compilation warning: `Name contains character(s) that can cause problems on Windows: "` * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
commit
f4a9900a0d
41 changed files with 181 additions and 89 deletions
|
|
@ -193,7 +193,8 @@ class LinkNewDeviceFlowNode(
|
|||
is ErrorType.Unknown -> ErrorScreenType.UnknownError
|
||||
is ErrorType.UnsupportedProtocol -> ErrorScreenType.UnknownError
|
||||
}
|
||||
// It is OK to push on backstack, since when user leaves the error screen, a new root will be set
|
||||
// It is OK to push on backstack, since when user leaves the error screen, a new root will be set,
|
||||
// or the whole flow will be popped.
|
||||
backstack.push(NavTarget.Error(error))
|
||||
}
|
||||
|
||||
|
|
@ -263,6 +264,12 @@ class LinkNewDeviceFlowNode(
|
|||
linkNewDesktopHandler.reset()
|
||||
backstack.newRoot(NavTarget.Root)
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
linkNewMobileHandler.reset()
|
||||
linkNewDesktopHandler.reset()
|
||||
callback.onDone()
|
||||
}
|
||||
}
|
||||
createNode<ErrorNode>(buildContext, listOf(callback, navTarget.errorScreenType))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class ErrorNode(
|
|||
) : Node(buildContext = buildContext, plugins = plugins) {
|
||||
interface Callback : Plugin {
|
||||
fun onRetry()
|
||||
fun onCancel()
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
|
|
@ -38,6 +39,7 @@ class ErrorNode(
|
|||
modifier = modifier,
|
||||
errorScreenType = errorScreenType,
|
||||
onRetry = callback::onRetry,
|
||||
onCancel = callback::onCancel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
|||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -41,17 +42,23 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
fun ErrorView(
|
||||
errorScreenType: ErrorScreenType,
|
||||
onRetry: () -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val appName = LocalBuildMeta.current.applicationName
|
||||
BackHandler(onBack = onRetry)
|
||||
BackHandler(onBack = onCancel)
|
||||
FlowStepPage(
|
||||
modifier = modifier,
|
||||
iconStyle = BigIcon.Style.AlertSolid,
|
||||
title = titleText(errorScreenType, appName),
|
||||
subTitle = subtitleText(errorScreenType, appName),
|
||||
content = { Content(errorScreenType) },
|
||||
buttons = { Buttons(onRetry) },
|
||||
buttons = {
|
||||
Buttons(
|
||||
onRetry = onRetry,
|
||||
onCancel = onCancel,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +125,19 @@ private fun Content(errorScreenType: ErrorScreenType) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Buttons(onRetry: () -> Unit) {
|
||||
private fun Buttons(
|
||||
onRetry: () -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(CommonStrings.action_start_over),
|
||||
onClick = onRetry
|
||||
text = stringResource(CommonStrings.action_try_again),
|
||||
onClick = onRetry,
|
||||
)
|
||||
OutlinedButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(CommonStrings.action_cancel),
|
||||
onClick = onCancel,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -133,6 +148,7 @@ internal fun ErrorViewPreview(@PreviewParameter(ErrorScreenTypeProvider::class)
|
|||
ErrorView(
|
||||
errorScreenType = errorScreenType,
|
||||
onRetry = {},
|
||||
onCancel = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
|||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.ensureCalledOnce
|
||||
import io.element.android.tests.testutils.pressBackKey
|
||||
|
|
@ -26,33 +27,45 @@ class ErrorViewTest {
|
|||
val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `on back pressed - calls the onRetry callback`() {
|
||||
fun `on back pressed - calls the onCancel callback`() {
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setErrorView(
|
||||
onRetry = callback
|
||||
onCancel = callback,
|
||||
)
|
||||
rule.pressBackKey()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on start over button clicked - calls the expected callback`() {
|
||||
fun `on try again button clicked - calls the expected callback`() {
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setErrorView(
|
||||
onRetry = callback
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_start_over)
|
||||
rule.clickOn(CommonStrings.action_try_again)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on cancel button clicked - calls the expected callback`() {
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setErrorView(
|
||||
onCancel = callback
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setErrorView(
|
||||
onRetry: () -> Unit,
|
||||
onRetry: () -> Unit = EnsureNeverCalled(),
|
||||
onCancel: () -> Unit = EnsureNeverCalled(),
|
||||
errorScreenType: ErrorScreenType = ErrorScreenType.UnknownError,
|
||||
) {
|
||||
setContent {
|
||||
ErrorView(
|
||||
errorScreenType = errorScreenType,
|
||||
onRetry = onRetry,
|
||||
onCancel = onCancel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import com.bumble.appyx.core.modality.BuildContext
|
|||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.pop
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import com.bumble.appyx.navmodel.backstack.operation.singleTop
|
||||
import dev.zacsweers.metro.AppScope
|
||||
|
|
@ -196,7 +197,12 @@ class LoginFlowNode(
|
|||
createNode<ChooseAccountProviderNode>(buildContext, listOf(callback))
|
||||
}
|
||||
NavTarget.QrCode -> {
|
||||
createNode<QrCodeLoginFlowNode>(buildContext)
|
||||
val callback = object : QrCodeLoginFlowNode.Callback {
|
||||
override fun navigateBack() {
|
||||
backstack.pop()
|
||||
}
|
||||
}
|
||||
createNode<QrCodeLoginFlowNode>(buildContext, listOf(callback))
|
||||
}
|
||||
is NavTarget.ConfirmAccountProvider -> {
|
||||
val inputs = ConfirmAccountProviderNode.Inputs(
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import io.element.android.libraries.architecture.BackstackView
|
|||
import io.element.android.libraries.architecture.BaseFlowNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.architecture.callback
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.core.coroutine.CoroutineDispatchers
|
||||
import io.element.android.libraries.di.DependencyInjectionGraphOwner
|
||||
|
|
@ -64,6 +65,12 @@ class QrCodeLoginFlowNode(
|
|||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
), DependencyInjectionGraphOwner {
|
||||
interface Callback : Plugin {
|
||||
fun navigateBack()
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
|
||||
private var authenticationJob: Job? = null
|
||||
|
||||
override val graph = qrCodeLoginGraphFactory.create()
|
||||
|
|
@ -85,7 +92,6 @@ class QrCodeLoginFlowNode(
|
|||
|
||||
override fun onBuilt() {
|
||||
super.onBuilt()
|
||||
|
||||
observeLoginStep()
|
||||
}
|
||||
|
||||
|
|
@ -178,7 +184,13 @@ class QrCodeLoginFlowNode(
|
|||
}
|
||||
is NavTarget.Error -> {
|
||||
val callback = object : QrCodeErrorNode.Callback {
|
||||
override fun onRetry() = reset()
|
||||
override fun onRetry() {
|
||||
reset()
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
callback.navigateBack()
|
||||
}
|
||||
}
|
||||
createNode<QrCodeErrorNode>(buildContext, plugins = listOf(navTarget.errorType, callback))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ class QrCodeErrorNode(
|
|||
) : Node(buildContext = buildContext, plugins = plugins) {
|
||||
interface Callback : Plugin {
|
||||
fun onRetry()
|
||||
fun onCancel()
|
||||
}
|
||||
|
||||
private val callback: Callback = callback()
|
||||
|
|
@ -43,6 +44,7 @@ class QrCodeErrorNode(
|
|||
errorScreenType = qrCodeErrorScreenType,
|
||||
appName = buildMeta.productionApplicationName,
|
||||
onRetry = callback::onRetry,
|
||||
onCancel = callback::onCancel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import io.element.android.libraries.designsystem.components.BigIcon
|
|||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
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.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
|
@ -44,16 +45,22 @@ fun QrCodeErrorView(
|
|||
errorScreenType: QrCodeErrorScreenType,
|
||||
appName: String,
|
||||
onRetry: () -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BackHandler(onBack = onRetry)
|
||||
BackHandler(onBack = onCancel)
|
||||
FlowStepPage(
|
||||
modifier = modifier,
|
||||
iconStyle = BigIcon.Style.AlertSolid,
|
||||
title = titleText(errorScreenType, appName),
|
||||
subTitle = subtitleText(errorScreenType, appName),
|
||||
content = { Content(errorScreenType) },
|
||||
buttons = { Buttons(onRetry) },
|
||||
buttons = {
|
||||
Buttons(
|
||||
onRetry = onRetry,
|
||||
onCancel = onCancel,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +125,19 @@ private fun Content(errorScreenType: QrCodeErrorScreenType) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Buttons(onRetry: () -> Unit) {
|
||||
private fun Buttons(
|
||||
onRetry: () -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
) {
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(R.string.screen_qr_code_login_start_over_button),
|
||||
onClick = onRetry
|
||||
text = stringResource(CommonStrings.action_try_again),
|
||||
onClick = onRetry,
|
||||
)
|
||||
OutlinedButton(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = stringResource(CommonStrings.action_cancel),
|
||||
onClick = onCancel,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -133,7 +148,8 @@ internal fun QrCodeErrorViewPreview(@PreviewParameter(QrCodeErrorScreenTypeProvi
|
|||
QrCodeErrorView(
|
||||
errorScreenType = errorScreenType,
|
||||
appName = "Element X",
|
||||
onRetry = {}
|
||||
onRetry = {},
|
||||
onCancel = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.auth.qrlogin.QrLoginException
|
|||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
||||
import io.element.android.libraries.matrix.test.auth.FakeMatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.test.auth.qrlogin.FakeMatrixQrCodeLoginData
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
|
|
@ -183,7 +184,11 @@ class QrCodeLoginFlowNodeTest {
|
|||
)
|
||||
return QrCodeLoginFlowNode(
|
||||
buildContext = buildContext,
|
||||
plugins = emptyList(),
|
||||
plugins = listOf(
|
||||
object : QrCodeLoginFlowNode.Callback {
|
||||
override fun navigateBack() = lambdaError()
|
||||
}
|
||||
),
|
||||
qrCodeLoginGraphFactory = FakeQrCodeLoginGraph.Builder(qrCodeLoginManager),
|
||||
coroutineDispatchers = coroutineDispatchers,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,8 +12,9 @@ import androidx.activity.ComponentActivity
|
|||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.features.login.impl.R
|
||||
import io.element.android.features.login.impl.qrcode.QrCodeErrorScreenType
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.ensureCalledOnce
|
||||
import io.element.android.tests.testutils.pressBackKey
|
||||
|
|
@ -28,10 +29,10 @@ class QrCodeErrorViewTest {
|
|||
val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `on back pressed - calls the onRetry callback`() {
|
||||
fun `on back pressed - calls the onCancel callback`() {
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setQrCodeErrorView(
|
||||
onRetry = callback
|
||||
onCancel = callback,
|
||||
)
|
||||
rule.pressBackKey()
|
||||
}
|
||||
|
|
@ -41,14 +42,25 @@ class QrCodeErrorViewTest {
|
|||
fun `on try again button clicked - calls the expected callback`() {
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setQrCodeErrorView(
|
||||
onRetry = callback
|
||||
onRetry = callback,
|
||||
)
|
||||
rule.clickOn(R.string.screen_qr_code_login_start_over_button)
|
||||
rule.clickOn(CommonStrings.action_try_again)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on cancel button clicked - calls the expected callback`() {
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setQrCodeErrorView(
|
||||
onCancel = callback,
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_cancel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setQrCodeErrorView(
|
||||
onRetry: () -> Unit,
|
||||
onRetry: () -> Unit = EnsureNeverCalled(),
|
||||
onCancel: () -> Unit = EnsureNeverCalled(),
|
||||
errorScreenType: QrCodeErrorScreenType = QrCodeErrorScreenType.UnknownError,
|
||||
appName: String = "Element X",
|
||||
) {
|
||||
|
|
@ -56,7 +68,8 @@ class QrCodeErrorViewTest {
|
|||
QrCodeErrorView(
|
||||
errorScreenType = errorScreenType,
|
||||
appName = appName,
|
||||
onRetry = onRetry
|
||||
onRetry = onRetry,
|
||||
onCancel = onCancel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1217,7 +1217,7 @@ class MessagesPresenterTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `present - shows a "history" icon if the room is encrypted and history is shared`() = runTest {
|
||||
fun `present - shows a history icon if the room is encrypted and history is shared`() = runTest {
|
||||
val presenter = createMessagesPresenter(
|
||||
joinedRoom = FakeJoinedRoom(
|
||||
baseRoom = FakeBaseRoom(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:24fd98aa0c43fdf26b67ec4dffc72d7f2d48f5d19f0a68a79c2c2c53e6c5fd12
|
||||
size 20769
|
||||
oid sha256:892d117c62e7d92f85e8b548fe6da6d89a710dbbfb873595cc258c77ea915636
|
||||
size 24075
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:58ddf6004bf14c10a0b65f271f6e95641891777e28ab12967e234363a10c33a5
|
||||
size 18411
|
||||
oid sha256:1fd2e78820084f25ba79b541e1aa881040808e205673854fa85fdfc683a427cb
|
||||
size 21755
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c7f5c9646571391933edc18c8a6b672b5208a6a4636b5bc15f77b8a06c6ec4a6
|
||||
size 21751
|
||||
oid sha256:1992fe80581dd92f8f55712deaa8f8da0a56660e7e7a652929640659af803dd5
|
||||
size 25009
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:157115c94aff169efbcb87343c4167334d074a4eb78ff4ddb075fa0cfff2c400
|
||||
size 33058
|
||||
oid sha256:cc516ea5fb1ea076f4ce9138a658bce06932aedeeb2a3e86151309832832bc75
|
||||
size 36342
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7077c7ed0c0656c538887db2e08e7c288e522261c160a13753e1573ed18606ca
|
||||
size 32697
|
||||
oid sha256:4e728f9a8fd89b690072999f096bee4756c2cb4a28f674e58594c132b8b2954a
|
||||
size 35986
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6e0ae0d30fde1317c5b8f20569597cc6039eac3e8f70c80c075ef4259e3e74c4
|
||||
size 67039
|
||||
oid sha256:f3c6ff6af93ffef30d140a9cbbd74fa170803accb0f0e92bbe5e4b530f9d8f3a
|
||||
size 63968
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9077a09b21bbdc7e2a22cf4fca9a6533ec11b1b6e898aa71d2b5393ef01f426c
|
||||
size 21058
|
||||
oid sha256:f4148a71f1851d1a00a568ac86a2c956cc918a402720e7cbbfe26256ef263dd7
|
||||
size 24355
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:330d0d44bb7638a4668fa33974e3b2cd31b3ce285776c993cced2b928b01bbb0
|
||||
size 20909
|
||||
oid sha256:5340ee86d402adbc1425754468788f95168acd1479d93d20fc9fb034776dab8b
|
||||
size 24223
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fe2527eae9bc919a3994cd59e8f6d0c181aa3ab9209b1c34b2bf6e63c7a434af
|
||||
size 20505
|
||||
oid sha256:ece98582d91c12f103df65543eb153101790b902356cb31fd37603dbc5fe8dc6
|
||||
size 23560
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d015f4c5905ab38b4bd987aaf4bf0ac8f55795700de8ae19b5872d4acd5bfd8c
|
||||
size 18323
|
||||
oid sha256:8f124f04bd6b188b5db42268b1f8e25b81f3edf67bf523a5e1698b72fabbad88
|
||||
size 21350
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:443ca45f4951fc0ef2d390cca6bb2c5717c0160a9df04fd3fe5bb7ede82a1f91
|
||||
size 21530
|
||||
oid sha256:4c69e8dcf511b456e7e28fd6ca25033fa1cc2f635f07f047ffc77d233b815fe7
|
||||
size 24520
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f72a52b922d9a4b058cc5bf1475711b0d1adb6e4ebb1b3e75278a4b9117a9869
|
||||
size 32359
|
||||
oid sha256:7fbc93e4ab01881ad5bd1fc8b4aa5a21a0662270dab1318551bfecc6e5659f56
|
||||
size 35352
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3430a0cdbd3eb28989a5f9fb397fc082b012ea2a3c284787d27da24870ecd12c
|
||||
size 32244
|
||||
oid sha256:39139613d9259e9e83b2610c1e484fe86b7a8fcd1e5d7f6bd04c8e57c571375b
|
||||
size 35247
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a90a5fb148455d4e4d9c4d8332222927d6cf3c606e27c695e4c44af13cedad9a
|
||||
size 65592
|
||||
oid sha256:3334e027c4256d1e7c935d1431d48f7139f03b0b2e4ca3dbb919fe7a280398fb
|
||||
size 62484
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f6481d57a4d3331e812b310a4a90963e30255ef894a9644df66de73eccccea7d
|
||||
size 20735
|
||||
oid sha256:f14dfadde7fc4ab18f0dc27cccae9dfe301f44e3ce0e5ca142f90abeabf5c4b1
|
||||
size 23783
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:516a6c8873c80c96febb9edf8956bccb00b849301df4682b969d3979158316a0
|
||||
size 20632
|
||||
oid sha256:a25d836da9f3a772d6343ff64687f270277f3b180d13596386d63b784eb5a523
|
||||
size 23661
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:24fd98aa0c43fdf26b67ec4dffc72d7f2d48f5d19f0a68a79c2c2c53e6c5fd12
|
||||
size 20769
|
||||
oid sha256:892d117c62e7d92f85e8b548fe6da6d89a710dbbfb873595cc258c77ea915636
|
||||
size 24075
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:58ddf6004bf14c10a0b65f271f6e95641891777e28ab12967e234363a10c33a5
|
||||
size 18411
|
||||
oid sha256:1fd2e78820084f25ba79b541e1aa881040808e205673854fa85fdfc683a427cb
|
||||
size 21755
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c7f5c9646571391933edc18c8a6b672b5208a6a4636b5bc15f77b8a06c6ec4a6
|
||||
size 21751
|
||||
oid sha256:1992fe80581dd92f8f55712deaa8f8da0a56660e7e7a652929640659af803dd5
|
||||
size 25009
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8f32bf15145564a938bacc40ae61e8f7d02d74e7a76452d62e56c88b5c193931
|
||||
size 33053
|
||||
oid sha256:c74e7f3a7a8cc96ece8e093fbed82c74dfd64e42ca32d4e2f9498d0f982d2325
|
||||
size 36336
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6e0ae0d30fde1317c5b8f20569597cc6039eac3e8f70c80c075ef4259e3e74c4
|
||||
size 67039
|
||||
oid sha256:f3c6ff6af93ffef30d140a9cbbd74fa170803accb0f0e92bbe5e4b530f9d8f3a
|
||||
size 63968
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:55c8f3cde0d4f5466e24a6636ee04c4baccb7e10edd4ba24e034ac16f74af1d4
|
||||
size 21150
|
||||
oid sha256:f6443db959c3c6fc569335568a6d8098880655c0397ca52c811850b066c05caa
|
||||
size 24474
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:330d0d44bb7638a4668fa33974e3b2cd31b3ce285776c993cced2b928b01bbb0
|
||||
size 20909
|
||||
oid sha256:5340ee86d402adbc1425754468788f95168acd1479d93d20fc9fb034776dab8b
|
||||
size 24223
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fe2527eae9bc919a3994cd59e8f6d0c181aa3ab9209b1c34b2bf6e63c7a434af
|
||||
size 20505
|
||||
oid sha256:ece98582d91c12f103df65543eb153101790b902356cb31fd37603dbc5fe8dc6
|
||||
size 23560
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d015f4c5905ab38b4bd987aaf4bf0ac8f55795700de8ae19b5872d4acd5bfd8c
|
||||
size 18323
|
||||
oid sha256:8f124f04bd6b188b5db42268b1f8e25b81f3edf67bf523a5e1698b72fabbad88
|
||||
size 21350
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:443ca45f4951fc0ef2d390cca6bb2c5717c0160a9df04fd3fe5bb7ede82a1f91
|
||||
size 21530
|
||||
oid sha256:4c69e8dcf511b456e7e28fd6ca25033fa1cc2f635f07f047ffc77d233b815fe7
|
||||
size 24520
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:76f4bf4c4d8783e9f79d2cd174484433dce3d4ac67eb3b60a178dfafc3df780f
|
||||
size 32416
|
||||
oid sha256:176a60dfdacd866f7689d0e16de93991cd9adb5720b5d8ca5915aca44ce95823
|
||||
size 35409
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a90a5fb148455d4e4d9c4d8332222927d6cf3c606e27c695e4c44af13cedad9a
|
||||
size 65592
|
||||
oid sha256:3334e027c4256d1e7c935d1431d48f7139f03b0b2e4ca3dbb919fe7a280398fb
|
||||
size 62484
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3d2efd7eeeb3ef4dd0746f854028dd012705e4565510596fbc25c86b27e41903
|
||||
size 20955
|
||||
oid sha256:d3bdc3e6cf80a38d93c9f3d567bfef8218adba66aad54499e329244efdc4d60d
|
||||
size 23961
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:516a6c8873c80c96febb9edf8956bccb00b849301df4682b969d3979158316a0
|
||||
size 20632
|
||||
oid sha256:a25d836da9f3a772d6343ff64687f270277f3b180d13596386d63b784eb5a523
|
||||
size 23661
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue