Merge pull request #1714 from vector-im/feature/fga/unlock_settings_2
Pin unlock : implement design for in-app unlock
This commit is contained in:
commit
46869b8df8
50 changed files with 228 additions and 104 deletions
|
|
@ -94,7 +94,8 @@ class LockScreenFlowNode @AssistedInject constructor(
|
|||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.Unlock -> {
|
||||
createNode<PinUnlockNode>(buildContext)
|
||||
val inputs = PinUnlockNode.Inputs(isInAppUnlock = false)
|
||||
createNode<PinUnlockNode>(buildContext, plugins = listOf(inputs))
|
||||
}
|
||||
NavTarget.Setup -> {
|
||||
createNode<LockScreenSetupFlowNode>(buildContext)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,8 @@ class LockScreenSettingsFlowNode @AssistedInject constructor(
|
|||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.Unlock -> {
|
||||
createNode<PinUnlockNode>(buildContext)
|
||||
val inputs = PinUnlockNode.Inputs(isInAppUnlock = true)
|
||||
createNode<PinUnlockNode>(buildContext, plugins = listOf(inputs))
|
||||
}
|
||||
NavTarget.Setup -> {
|
||||
val callback = object : LockScreenSetupFlowNode.Callback {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypadModel
|
|||
|
||||
sealed interface PinUnlockEvents {
|
||||
data class OnPinKeypadPressed(val pinKeypadModel: PinKeypadModel) : PinUnlockEvents
|
||||
data class OnPinEntryChanged(val entryAsText: String) : PinUnlockEvents
|
||||
data object OnForgetPin : PinUnlockEvents
|
||||
data object ClearSignOutPrompt : PinUnlockEvents
|
||||
data object SignOut : PinUnlockEvents
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import com.bumble.appyx.core.plugin.Plugin
|
|||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
|
|
@ -33,11 +35,18 @@ class PinUnlockNode @AssistedInject constructor(
|
|||
private val presenter: PinUnlockPresenter,
|
||||
) : Node(buildContext, plugins = plugins) {
|
||||
|
||||
data class Inputs(
|
||||
val isInAppUnlock: Boolean
|
||||
) : NodeInputs
|
||||
|
||||
private val inputs: Inputs = inputs()
|
||||
|
||||
@Composable
|
||||
override fun View(modifier: Modifier) {
|
||||
val state = presenter.present()
|
||||
PinUnlockView(
|
||||
state = state,
|
||||
isInAppUnlock = inputs.isInAppUnlock,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,6 +116,9 @@ class PinUnlockPresenter @Inject constructor(
|
|||
PinUnlockEvents.ClearBiometricError -> {
|
||||
biometricUnlockResult = null
|
||||
}
|
||||
is PinUnlockEvents.OnPinEntryChanged -> {
|
||||
pinEntryState.value = pinEntry.process(event.entryAsText)
|
||||
}
|
||||
}
|
||||
}
|
||||
return PinUnlockState(
|
||||
|
|
@ -159,6 +162,16 @@ class PinUnlockPresenter @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun Async<PinEntry>.process(pinEntryAsText: String): Async<PinEntry> {
|
||||
return when (this) {
|
||||
is Async.Success -> {
|
||||
val pinEntry = data.fillWith(pinEntryAsText)
|
||||
Async.Success(pinEntry)
|
||||
}
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.signOut(signOutAction: MutableState<Async<String?>>) = launch {
|
||||
suspend {
|
||||
matrixClient.logout(ignoreSdkError = true)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package io.element.android.features.lockscreen.impl.unlock
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
|
|
@ -29,6 +30,7 @@ import androidx.compose.foundation.layout.fillMaxHeight
|
|||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
|
|
@ -37,8 +39,12 @@ import androidx.compose.material.icons.Icons
|
|||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
|
@ -46,10 +52,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import io.element.android.features.lockscreen.impl.R
|
||||
import io.element.android.features.lockscreen.impl.components.PinEntryTextField
|
||||
import io.element.android.features.lockscreen.impl.pin.model.PinDigit
|
||||
import io.element.android.features.lockscreen.impl.pin.model.PinEntry
|
||||
import io.element.android.features.lockscreen.impl.unlock.keypad.PinKeypad
|
||||
import io.element.android.libraries.architecture.Async
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom
|
||||
import io.element.android.libraries.designsystem.components.ProgressDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||
|
|
@ -66,6 +74,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
|||
@Composable
|
||||
fun PinUnlockView(
|
||||
state: PinUnlockState,
|
||||
isInAppUnlock: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
OnLifecycleEvent { _, event ->
|
||||
|
|
@ -75,56 +84,7 @@ fun PinUnlockView(
|
|||
}
|
||||
}
|
||||
Surface(modifier) {
|
||||
BoxWithConstraints {
|
||||
val commonModifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.padding(all = 20.dp)
|
||||
|
||||
val header = @Composable {
|
||||
PinUnlockHeader(
|
||||
state = state,
|
||||
modifier = Modifier.padding(top = 60.dp, bottom = 12.dp)
|
||||
)
|
||||
}
|
||||
val footer = @Composable {
|
||||
PinUnlockFooter(
|
||||
modifier = Modifier.padding(top = 24.dp),
|
||||
showBiometricUnlock = state.showBiometricUnlock,
|
||||
onUseBiometric = {
|
||||
state.eventSink(PinUnlockEvents.OnUseBiometric)
|
||||
},
|
||||
onForgotPin = {
|
||||
state.eventSink(PinUnlockEvents.OnForgetPin)
|
||||
},
|
||||
)
|
||||
}
|
||||
val content = @Composable { constraints: BoxWithConstraintsScope ->
|
||||
PinKeypad(
|
||||
onClick = {
|
||||
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it))
|
||||
},
|
||||
maxWidth = constraints.maxWidth,
|
||||
maxHeight = constraints.maxHeight,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
)
|
||||
}
|
||||
if (maxHeight < 600.dp) {
|
||||
PinUnlockCompactView(
|
||||
header = header,
|
||||
footer = footer,
|
||||
content = content,
|
||||
modifier = commonModifier,
|
||||
)
|
||||
} else {
|
||||
PinUnlockExpandedView(
|
||||
header = header,
|
||||
footer = footer,
|
||||
content = content,
|
||||
modifier = commonModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
PinUnlockPage(state = state, isInAppUnlock = isInAppUnlock)
|
||||
if (state.showSignOutPrompt) {
|
||||
SignOutPrompt(
|
||||
isCancellable = state.isSignOutPromptCancellable,
|
||||
|
|
@ -144,6 +104,86 @@ fun PinUnlockView(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PinUnlockPage(
|
||||
state: PinUnlockState,
|
||||
isInAppUnlock: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
BoxWithConstraints {
|
||||
val commonModifier = modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding()
|
||||
.imePadding()
|
||||
.padding(all = 20.dp)
|
||||
|
||||
val header = @Composable {
|
||||
PinUnlockHeader(
|
||||
state = state,
|
||||
isInAppUnlock = isInAppUnlock,
|
||||
modifier = Modifier.padding(top = 60.dp)
|
||||
)
|
||||
}
|
||||
val footer = @Composable {
|
||||
PinUnlockFooter(
|
||||
modifier = Modifier.padding(top = 24.dp),
|
||||
showBiometricUnlock = state.showBiometricUnlock,
|
||||
onUseBiometric = {
|
||||
state.eventSink(PinUnlockEvents.OnUseBiometric)
|
||||
},
|
||||
onForgotPin = {
|
||||
state.eventSink(PinUnlockEvents.OnForgetPin)
|
||||
},
|
||||
)
|
||||
}
|
||||
val content = @Composable { constraints: BoxWithConstraintsScope ->
|
||||
if (isInAppUnlock) {
|
||||
val pinEntry = state.pinEntry.dataOrNull()
|
||||
if (pinEntry != null) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
PinEntryTextField(
|
||||
pinEntry = pinEntry,
|
||||
isSecured = true,
|
||||
onValueChange = {
|
||||
state.eventSink(PinUnlockEvents.OnPinEntryChanged(it))
|
||||
},
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
PinKeypad(
|
||||
onClick = {
|
||||
state.eventSink(PinUnlockEvents.OnPinKeypadPressed(it))
|
||||
},
|
||||
maxWidth = constraints.maxWidth,
|
||||
maxHeight = constraints.maxHeight,
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (maxHeight < 600.dp) {
|
||||
PinUnlockCompactView(
|
||||
header = header,
|
||||
footer = footer,
|
||||
content = content,
|
||||
modifier = commonModifier,
|
||||
)
|
||||
} else {
|
||||
PinUnlockExpandedView(
|
||||
header = header,
|
||||
footer = footer,
|
||||
content = content,
|
||||
modifier = commonModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SignOutPrompt(
|
||||
isCancellable: Boolean,
|
||||
|
|
@ -248,16 +288,21 @@ private fun PinDot(
|
|||
@Composable
|
||||
private fun PinUnlockHeader(
|
||||
state: PinUnlockState,
|
||||
isInAppUnlock: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(32.dp),
|
||||
tint = ElementTheme.colors.iconPrimary,
|
||||
imageVector = Icons.Filled.Lock,
|
||||
contentDescription = "",
|
||||
)
|
||||
if (isInAppUnlock) {
|
||||
RoundedIconAtom(imageVector = Icons.Filled.Lock)
|
||||
} else {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(32.dp),
|
||||
tint = ElementTheme.colors.iconPrimary,
|
||||
imageVector = Icons.Filled.Lock,
|
||||
contentDescription = "",
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Text(
|
||||
text = stringResource(id = CommonStrings.common_enter_your_pin),
|
||||
|
|
@ -290,8 +335,8 @@ private fun PinUnlockHeader(
|
|||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = subtitleColor,
|
||||
)
|
||||
Spacer(Modifier.height(24.dp))
|
||||
if (state.pinEntry is Async.Success) {
|
||||
if (!isInAppUnlock && state.pinEntry is Async.Success) {
|
||||
Spacer(Modifier.height(24.dp))
|
||||
PinDotsRow(state.pinEntry.data)
|
||||
}
|
||||
}
|
||||
|
|
@ -314,10 +359,22 @@ private fun PinUnlockFooter(
|
|||
|
||||
@Composable
|
||||
@PreviewsDayNight
|
||||
internal fun PinUnlockViewPreview(@PreviewParameter(PinUnlockStateProvider::class) state: PinUnlockState) {
|
||||
internal fun PinUnlockInAppViewPreview(@PreviewParameter(PinUnlockStateProvider::class) state: PinUnlockState) {
|
||||
ElementPreview {
|
||||
PinUnlockView(
|
||||
state = state,
|
||||
isInAppUnlock = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@PreviewsDayNight
|
||||
internal fun PinUnlockDefaultViewPreview(@PreviewParameter(PinUnlockStateProvider::class) state: PinUnlockState) {
|
||||
ElementPreview {
|
||||
PinUnlockView(
|
||||
state = state,
|
||||
isInAppUnlock = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1ece6fcfbf1c064287f6e0ead16c3abc471ea3f7db1aa4dbb7b8cdd2657e115a
|
||||
size 40369
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8526a23e31e2c87ca2f43b127f00f05067a3525eff3319fe2965530096caab87
|
||||
size 40836
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:88a97cfbbb601a889cc1f2a81ac6fcb9a58288232358968d536f4216ae8882f0
|
||||
size 41692
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c5313634888c4d26b2a6c92485de0b2b4d7a6479ba5a872794c9fa8d8d30639b
|
||||
size 46796
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:82d010d152311c8a19e33fa80ea7d70c061a0ed3bdc654f0cb7276207398d4ae
|
||||
size 37930
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ee09e25c131831cb08ebd85fb2fcbe078f075da74734f34c9811fac6b6e30437
|
||||
size 44372
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:38dfb87d845af20021622440ff3fee5d81f32d1a8a574f4ab9fece71ce36f5ce
|
||||
size 35193
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2d538426d487708ba2139b322b31ff58675279f19c9dec53d636f68b0d5fa6a0
|
||||
size 37231
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9651646be4e8b732d9d8e1395191ac2b3e1ca2dbf7280090741ffcac290402d4
|
||||
size 37679
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:079e0f74c91d988d03af37ff66a94ad85df5e6312d7ebd531fde1cbf1105ec8e
|
||||
size 38219
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:724b77f4eb0e3d721b05eddfc3d9c2e5b585213d1a4e4eca5d598175536abe47
|
||||
size 41018
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6236756ef44cf19160e7977a9390dee51950f5324446355179e16285c5584270
|
||||
size 35185
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bd70746d6c331e0c2004bc756b8ef207f755b357b3a6eff57ad085ff75e08a0f
|
||||
size 38676
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4faa194d51d356d8ad659c225a92b124d9d93f16972acff1aa1b45aabfd101b6
|
||||
size 31475
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b58f216453eb1d131ece67219021f074c1f5b1bc7593b76a2efedfb2c9f09887
|
||||
size 23690
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:65226593d4548b87ded518f143b9a2030908befc5f423846a03e7938fe681390
|
||||
size 23410
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:41e9a94fd494477437bbb625df08870875ef8021f7b02bc6e1953fac0cd3a8d3
|
||||
size 24948
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e9c4bc23a4a15ebc6d434da33381336f01d7c1566fb9ef9dae94bf03138df334
|
||||
size 39615
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e7081eb4ef25d5220e638e83ad4a3aa4248db8ddf22e371cb7698b6ce0fd91f3
|
||||
size 21328
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1f7aa0b84dd7b059443afb2d0f281ab684266883010e9146b557954bf17c7807
|
||||
size 37078
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96299aa2059245aa3dd2c374d122c8cbda50040bf80930e62e74d634407bc913
|
||||
size 26731
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:900a9ce415198cb4736d99f91e1f997021363f45ab5dded5e3870631e91c864f
|
||||
size 22476
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bdb6f9f7e684d0bf2f84670cc7848b038fd6c8f7fde119de53fcc576aa522af5
|
||||
size 22420
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9428610c1ffa0b93e53d1470a06e3cc8f3568a2dd86fd3fa99ef76d935220a5d
|
||||
size 23467
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:05f512aa7541a7b5f92f14c3f9bcc2c8d69141b92fd0be4fcc2ead162ccd7015
|
||||
size 34474
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:02876aee2a4e9574d4503bb2cb71ff25a588e5917356cff3f3d0ac517a16eee3
|
||||
size 20399
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ae7c91ff420b979f5b818e5f750e3c740c9c03a0301660f90bb7471997c88b6b
|
||||
size 32104
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4bca2311722ab2f3603da2cdb6181411c83b929c38b87b63a8923d0e563f915a
|
||||
size 23809
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c94f10441359bdb901ee1f8be9c307312586d6ca54495e88ec231c1e931eb36b
|
||||
size 38994
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:38456a511fbc72e3d544c8f88138be4f24b6adb3a10629989c037141213a9e19
|
||||
size 39441
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:083c3972e5d019ce1d8565a655bd6f6fb6689e17792ddf7ed282d5eee529a7b6
|
||||
size 40292
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bda49a721fbd19b4cbe0f4dc1b4013154a55e17f78e099f411d1caaef82cfa6c
|
||||
size 46711
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1facbdcba634b37a8162876e6af02a3565eaee2ac4afe32816b1f8e9602b2a65
|
||||
size 36565
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b0d360c0697733a9e1067589be5178f631da673743b97daeb50ebdc51fd89502
|
||||
size 44289
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dc653f37c55ce7f9ef001d8f8ab57de23008baae2f644c6db49a7f4bccc831d5
|
||||
size 34938
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ab8c04689414b5183fa6ab5a479063b478b3d02dfb6bf2df72b1b606c77392ad
|
||||
size 36278
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fda961a2240c1458ad561c8f4e7fa265bbe6c70cf9b0fbfcd1ae0879036a3343
|
||||
size 36714
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0cb889338b21dd8e1a913348ff02cd217f48840c4d54b99ed4d89b67dff771bb
|
||||
size 37254
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:836f26b162a031b14151511405ec0b9dd43fe1c37127a5ec05e277ab0e2ab667
|
||||
size 41054
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a4b3e856f102b2d53fd5776204a8576ed515e9e4bfd9899e4138eb1515a11b12
|
||||
size 34241
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2c53928f35405266f99bbc4976f9c12915f47765289481b2cd65086925ea1b50
|
||||
size 38710
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fd06f078cff08947537a58ddc2df9a79f4aa3d55372b6b8eafa962f2266ca02f
|
||||
size 31443
|
||||
Loading…
Add table
Add a link
Reference in a new issue