Merge pull request #4103 from element-hq/feature/bma/fixDmAvatarRtl
Fix dm avatar rtl
This commit is contained in:
commit
1272ee43d6
26 changed files with 245 additions and 49 deletions
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.knockrequests.impl.banner
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.BlendMode
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.CompositingStrategy
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.designsystem.text.toPx
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a row of avatars (they must all have the same size), from start to end.
|
||||||
|
* @param avatarDataList the avatars to render. Note: they will all be rendered, the caller may
|
||||||
|
* want to limit the list size
|
||||||
|
* @param modifier Jetpack Compose modifier
|
||||||
|
* @param overlapRatio the overlap ration. When 0f, avatars will render without overlap, when 1f
|
||||||
|
* only the first avatar will be visible
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun AvatarRow(
|
||||||
|
avatarDataList: ImmutableList<AvatarData>,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
overlapRatio: Float = 0.5f,
|
||||||
|
) {
|
||||||
|
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
|
||||||
|
Box(
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
|
val lastItemIndex = avatarDataList.size - 1
|
||||||
|
val avatarSize = avatarDataList.firstOrNull()?.size?.dp ?: return
|
||||||
|
val avatarSizePx = avatarSize.toPx()
|
||||||
|
avatarDataList
|
||||||
|
.reversed()
|
||||||
|
.forEachIndexed { index, avatarData ->
|
||||||
|
Avatar(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = avatarSize * (1 - overlapRatio) * (lastItemIndex - index))
|
||||||
|
.graphicsLayer {
|
||||||
|
compositingStrategy = CompositingStrategy.Offscreen
|
||||||
|
}
|
||||||
|
.drawWithContent {
|
||||||
|
// Draw content and clear the pixels for the avatar on the left (right in RTL).
|
||||||
|
drawContent()
|
||||||
|
val xOffset = if (isRtl) {
|
||||||
|
size.width - avatarSizePx * (overlapRatio - 0.5f)
|
||||||
|
} else {
|
||||||
|
0f + avatarSizePx * (overlapRatio - 0.5f)
|
||||||
|
}
|
||||||
|
if (index < lastItemIndex) {
|
||||||
|
drawCircle(
|
||||||
|
color = Color.Black,
|
||||||
|
center = Offset(
|
||||||
|
x = xOffset,
|
||||||
|
y = size.height / 2,
|
||||||
|
),
|
||||||
|
radius = avatarSizePx / 2,
|
||||||
|
blendMode = BlendMode.Clear,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.size(size = avatarSize)
|
||||||
|
// Keep internal padding, it has the advantage to not reduce the size of the Avatar image,
|
||||||
|
// which is already small in our use case.
|
||||||
|
.padding(2.dp),
|
||||||
|
avatarData = avatarData,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@PreviewsDayNight
|
||||||
|
internal fun AvatarRowPreview(@PreviewParameter(OverlapRatioProvider::class) overlapRatio: Float) {
|
||||||
|
ElementPreview {
|
||||||
|
ContentToPreview(overlapRatio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@PreviewsDayNight
|
||||||
|
internal fun AvatarRowRtlPreview(@PreviewParameter(OverlapRatioProvider::class) overlapRatio: Float) {
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalLayoutDirection provides LayoutDirection.Rtl,
|
||||||
|
) {
|
||||||
|
ElementPreview {
|
||||||
|
ContentToPreview(overlapRatio)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ContentToPreview(overlapRatio: Float) {
|
||||||
|
AvatarRow(
|
||||||
|
avatarDataList = listOf("A", "B", "C").map {
|
||||||
|
AvatarData(
|
||||||
|
id = it,
|
||||||
|
name = it,
|
||||||
|
size = AvatarSize.RoomListItem,
|
||||||
|
)
|
||||||
|
}.toImmutableList(),
|
||||||
|
overlapRatio = overlapRatio,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -19,19 +19,12 @@ 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.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.drawWithContent
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.BlendMode
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.CompositingStrategy
|
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
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
|
||||||
|
|
@ -56,6 +49,7 @@ import io.element.android.libraries.designsystem.theme.components.Surface
|
||||||
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 io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
private const val MAX_AVATAR_COUNT = 3
|
private const val MAX_AVATAR_COUNT = 3
|
||||||
|
|
||||||
|
|
@ -120,9 +114,9 @@ private fun KnockRequestsBannerContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier
|
modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(all = 16.dp)
|
.padding(all = 16.dp)
|
||||||
) {
|
) {
|
||||||
Row {
|
Row {
|
||||||
KnockRequestAvatarView(
|
KnockRequestAvatarView(
|
||||||
|
|
@ -212,44 +206,16 @@ private fun KnockRequestAvatarListView(
|
||||||
knockRequests: ImmutableList<KnockRequestPresentable>,
|
knockRequests: ImmutableList<KnockRequestPresentable>,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val avatarSize = AvatarSize.KnockRequestBanner.dp
|
val avatars = knockRequests
|
||||||
Box(
|
.take(MAX_AVATAR_COUNT)
|
||||||
|
.map { knockRequest ->
|
||||||
|
knockRequest.getAvatarData(AvatarSize.KnockRequestBanner)
|
||||||
|
}
|
||||||
|
.toImmutableList()
|
||||||
|
AvatarRow(
|
||||||
|
avatarDataList = avatars,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
)
|
||||||
knockRequests
|
|
||||||
.take(MAX_AVATAR_COUNT)
|
|
||||||
.reversed()
|
|
||||||
.let { smallReversedList ->
|
|
||||||
val lastItemIndex = smallReversedList.size - 1
|
|
||||||
smallReversedList.forEachIndexed { index, knockRequest ->
|
|
||||||
Avatar(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = avatarSize / 2 * (lastItemIndex - index))
|
|
||||||
.graphicsLayer {
|
|
||||||
compositingStrategy = CompositingStrategy.Offscreen
|
|
||||||
}
|
|
||||||
.drawWithContent {
|
|
||||||
// Draw content and clear the pixels for the avatar on the left.
|
|
||||||
drawContent()
|
|
||||||
if (index < lastItemIndex) {
|
|
||||||
drawCircle(
|
|
||||||
color = Color.Black,
|
|
||||||
center = Offset(
|
|
||||||
x = 0f,
|
|
||||||
y = size.height / 2,
|
|
||||||
),
|
|
||||||
radius = avatarSize.toPx() / 2,
|
|
||||||
blendMode = BlendMode.Clear,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.size(size = avatarSize)
|
|
||||||
.padding(2.dp),
|
|
||||||
avatarData = knockRequest.getAvatarData(AvatarSize.KnockRequestBanner),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 New Vector Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
* Please see LICENSE in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.knockrequests.impl.banner
|
||||||
|
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
|
|
||||||
|
class OverlapRatioProvider : PreviewParameterProvider<Float> {
|
||||||
|
override val values: Sequence<Float> = sequenceOf(
|
||||||
|
0f,
|
||||||
|
0.25f,
|
||||||
|
0.5f,
|
||||||
|
0.75f,
|
||||||
|
1f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
|
@ -21,7 +22,9 @@ import androidx.compose.ui.graphics.BlendMode
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.CompositingStrategy
|
import androidx.compose.ui.graphics.CompositingStrategy
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
import io.element.android.libraries.designsystem.text.toPx
|
import io.element.android.libraries.designsystem.text.toPx
|
||||||
|
|
@ -45,10 +48,11 @@ fun DmAvatars(
|
||||||
val boxSize = userAvatarData.size.dp * SIZE_RATIO
|
val boxSize = userAvatarData.size.dp * SIZE_RATIO
|
||||||
val boxSizePx = boxSize.toPx()
|
val boxSizePx = boxSize.toPx()
|
||||||
val otherAvatarRadius = otherUserAvatarData.size.dp.toPx() / 2
|
val otherAvatarRadius = otherUserAvatarData.size.dp.toPx() / 2
|
||||||
|
val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier.size(boxSize),
|
modifier = modifier.size(boxSize),
|
||||||
) {
|
) {
|
||||||
// Draw user avatar and cut top right corner
|
// Draw user avatar and cut top end corner
|
||||||
Avatar(
|
Avatar(
|
||||||
avatarData = userAvatarData,
|
avatarData = userAvatarData,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -58,10 +62,15 @@ fun DmAvatars(
|
||||||
}
|
}
|
||||||
.drawWithContent {
|
.drawWithContent {
|
||||||
drawContent()
|
drawContent()
|
||||||
|
val xOffset = if (isRtl) {
|
||||||
|
size.width - boxSizePx + otherAvatarRadius
|
||||||
|
} else {
|
||||||
|
boxSizePx - otherAvatarRadius
|
||||||
|
}
|
||||||
drawCircle(
|
drawCircle(
|
||||||
color = Color.Black,
|
color = Color.Black,
|
||||||
center = Offset(
|
center = Offset(
|
||||||
x = boxSizePx - otherAvatarRadius,
|
x = xOffset,
|
||||||
y = size.height - (boxSizePx - otherAvatarRadius),
|
y = size.height - (boxSizePx - otherAvatarRadius),
|
||||||
),
|
),
|
||||||
radius = otherAvatarRadius / 0.9f,
|
radius = otherAvatarRadius / 0.9f,
|
||||||
|
|
@ -106,3 +115,13 @@ internal fun DmAvatarsPreview() = ElementThemedPreview {
|
||||||
openOtherAvatarPreview = {},
|
openOtherAvatarPreview = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview(group = PreviewGroup.Avatars)
|
||||||
|
@Composable
|
||||||
|
internal fun DmAvatarsRtlPreview() {
|
||||||
|
CompositionLocalProvider(
|
||||||
|
LocalLayoutDirection provides LayoutDirection.Rtl,
|
||||||
|
) {
|
||||||
|
DmAvatarsPreview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ class KonsistClassNameTest {
|
||||||
.withAllParentsOf(PreviewParameterProvider::class)
|
.withAllParentsOf(PreviewParameterProvider::class)
|
||||||
.withoutName(
|
.withoutName(
|
||||||
"AspectRatioProvider",
|
"AspectRatioProvider",
|
||||||
|
"OverlapRatioProvider",
|
||||||
)
|
)
|
||||||
.also {
|
.also {
|
||||||
// Check that classes are actually found
|
// Check that classes are actually found
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:d318e0e4fa1bd8a123057dca6efc9c92c5dc96614dad3514813559274288e115
|
||||||
|
size 8520
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b0bee0c2e2c712621bbc92c430807c758429ef1179394b107c393f9236295bbb
|
||||||
|
size 8447
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:4a92d34b2ac73b7d3341f39f46bbf0a4dcf9862e9cccdfc0111b64c562930f03
|
||||||
|
size 7720
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:79a021e58c28d0e0cbb50f99304dae5c8c2ec95ca99a02d7876a167adc911e7f
|
||||||
|
size 6948
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ea4febe911c963e720535c576a65842d2616ffb61103153a8a8738886c26eca7
|
||||||
|
size 5251
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:33ad034f7be86da7a2399d11c0991b5d6997ddaffa9f26b20a456f1b22666b70
|
||||||
|
size 8825
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:5784d917b0176cfa6b584804b28d8592ed97fe6e1f60a805619cce3170acb802
|
||||||
|
size 8722
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:06a0cef40417aa586e85b5896e763279e2c3df6121ffd65b9b85129e2a5ea4f4
|
||||||
|
size 8023
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ac5300b143c12ebf39fb6b0074677b5f16760217cca3823229304838e322e424
|
||||||
|
size 7375
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:690a1313ac8dd2cb84d7d560a16bdcd3eb0b65ad16d502da37efccecc4198b27
|
||||||
|
size 5467
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:836e6d27c46a85d5a8d6fd8b612ba4b2d79c2ffddd5660c00bf0a4302871734c
|
||||||
|
size 8503
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c2606e39c21d12059e70c1bf95a80828c415ad1dc5fe27d2533dad58cec6e948
|
||||||
|
size 8445
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:fe8810842b717b145cfd850221a0b24608b7693d60735c15d2a2ea349449f781
|
||||||
|
size 8015
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:dff87afdeca9e6de4a5053947270d93a61a23faf4a605e52b6b01e814b5d5e3e
|
||||||
|
size 6927
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:ea4febe911c963e720535c576a65842d2616ffb61103153a8a8738886c26eca7
|
||||||
|
size 5251
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:4cfea11d355bbe92346b49438ef59e4f7fe694039cdec8fdfc6ca097edbcdcea
|
||||||
|
size 8837
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:d4de82de886361037273b9a06fd29bff1b24a20a329d8590d97d03515ca21b43
|
||||||
|
size 8733
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cecf626b261bfbe72dfd9692a467d7205ee773db2afcb7adeabecfd9e390daf0
|
||||||
|
size 8331
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:6e05d4bb9772b9535617ae9da1f461ed399fc9665dc2adf55a9d647ff640319b
|
||||||
|
size 7331
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:690a1313ac8dd2cb84d7d560a16bdcd3eb0b65ad16d502da37efccecc4198b27
|
||||||
|
size 5467
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b0007ee6df39ec6b8f180cab21a99f97adef39deb1055ba8d179e5fee5ca1203
|
||||||
|
size 13856
|
||||||
Loading…
Add table
Add a link
Reference in a new issue