Merge pull request #4140 from element-hq/feature/fga/compound_design_announcement

change(design) : New component Announcement
This commit is contained in:
ganfra 2025-01-15 11:38:43 +01:00 committed by GitHub
commit 46119aefa2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 339 additions and 180 deletions

View file

@ -7,6 +7,7 @@
package io.element.android.features.preferences.impl.notifications
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics
import androidx.compose.runtime.Composable
@ -20,7 +21,8 @@ import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.preferences.impl.R
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
import io.element.android.libraries.designsystem.components.Announcement
import io.element.android.libraries.designsystem.components.AnnouncementType
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.components.dialogs.ListOption
@ -132,7 +134,7 @@ private fun NotificationSettingsContentView(
PreferenceText(
icon = CompoundIcons.VoiceCall(),
title = stringResource(id = R.string.full_screen_intent_banner_title),
subtitle = stringResource(R.string.full_screen_intent_banner_message,),
subtitle = stringResource(R.string.full_screen_intent_banner_message),
onClick = {
state.fullScreenIntentPermissionsState.openFullScreenIntentSettings()
}
@ -247,12 +249,17 @@ private fun InvalidNotificationSettingsView(
showError: Boolean,
onContinueClick: () -> Unit,
onDismissError: () -> Unit,
modifier: Modifier = Modifier,
) {
DialogLikeBannerMolecule(
Announcement(
title = stringResource(R.string.screen_notification_settings_configuration_mismatch),
content = stringResource(R.string.screen_notification_settings_configuration_mismatch_description),
onSubmitClick = onContinueClick,
onDismissClick = null,
description = stringResource(R.string.screen_notification_settings_configuration_mismatch_description),
type = AnnouncementType.Actionable(
onActionClick = onContinueClick,
actionText = stringResource(CommonStrings.action_continue),
onDismissClick = null,
),
modifier = modifier.padding(horizontal = 16.dp, vertical = 8.dp),
)
if (showError) {

View file

@ -0,0 +1,17 @@
/*
* Copyright 2025 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.features.roomlist.impl.components
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
/**
* Common padding for RoomList banners.
*/
internal fun Modifier.roomListBannerPadding() = padding(horizontal = 16.dp, vertical = 8.dp)

View file

@ -11,9 +11,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
import io.element.android.libraries.designsystem.components.Announcement
import io.element.android.libraries.designsystem.components.AnnouncementType
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
internal fun ConfirmRecoveryKeyBanner(
@ -21,12 +23,15 @@ internal fun ConfirmRecoveryKeyBanner(
onDismissClick: () -> Unit,
modifier: Modifier = Modifier,
) {
DialogLikeBannerMolecule(
modifier = modifier,
Announcement(
modifier = modifier.roomListBannerPadding(),
title = stringResource(R.string.confirm_recovery_key_banner_title),
content = stringResource(R.string.confirm_recovery_key_banner_message),
onSubmitClick = onContinueClick,
onDismissClick = onDismissClick,
description = stringResource(R.string.confirm_recovery_key_banner_message),
type = AnnouncementType.Actionable(
actionText = stringResource(CommonStrings.action_continue),
onActionClick = onContinueClick,
onDismissClick = onDismissClick,
),
)
}

View file

@ -8,21 +8,31 @@
package io.element.android.features.roomlist.impl.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
import io.element.android.libraries.designsystem.components.Announcement
import io.element.android.libraries.designsystem.components.AnnouncementType
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun FullScreenIntentPermissionBanner(state: FullScreenIntentPermissionsState) {
DialogLikeBannerMolecule(
fun FullScreenIntentPermissionBanner(
state: FullScreenIntentPermissionsState,
modifier: Modifier = Modifier
) {
Announcement(
title = stringResource(R.string.full_screen_intent_banner_title),
content = stringResource(R.string.full_screen_intent_banner_message),
onDismissClick = state.dismissFullScreenIntentBanner,
onSubmitClick = state.openFullScreenIntentSettings,
description = stringResource(R.string.full_screen_intent_banner_message),
type = AnnouncementType.Actionable(
actionText = stringResource(CommonStrings.action_continue),
onDismissClick = state.dismissFullScreenIntentBanner,
onActionClick = state.openFullScreenIntentSettings,
),
modifier = modifier.roomListBannerPadding(),
)
}

View file

@ -11,7 +11,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
import io.element.android.libraries.designsystem.components.Announcement
import io.element.android.libraries.designsystem.components.AnnouncementType
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -21,13 +22,15 @@ internal fun NativeSlidingSyncMigrationBanner(
onDismissClick: () -> Unit,
modifier: Modifier = Modifier,
) {
DialogLikeBannerMolecule(
modifier = modifier,
Announcement(
modifier = modifier.roomListBannerPadding(),
title = stringResource(R.string.banner_migrate_to_native_sliding_sync_title),
content = stringResource(R.string.banner_migrate_to_native_sliding_sync_description),
actionText = stringResource(R.string.banner_migrate_to_native_sliding_sync_action),
onSubmitClick = onContinueClick,
onDismissClick = onDismissClick,
description = stringResource(R.string.banner_migrate_to_native_sliding_sync_description),
type = AnnouncementType.Actionable(
actionText = stringResource(R.string.banner_migrate_to_native_sliding_sync_action),
onActionClick = onContinueClick,
onDismissClick = onDismissClick,
)
)
}

View file

@ -139,13 +139,13 @@ private fun EmptyView(
SecurityBannerState.SetUpRecovery -> {
SetUpRecoveryKeyBanner(
onContinueClick = onSetUpRecoveryClick,
onDismissClick = { eventSink(RoomListEvents.DismissBanner) }
onDismissClick = { eventSink(RoomListEvents.DismissBanner) },
)
}
SecurityBannerState.RecoveryKeyConfirmation -> {
ConfirmRecoveryKeyBanner(
onContinueClick = onConfirmRecoveryKeyClick,
onDismissClick = { eventSink(RoomListEvents.DismissBanner) }
onDismissClick = { eventSink(RoomListEvents.DismissBanner) },
)
}
else -> Unit
@ -217,7 +217,7 @@ private fun RoomsViewList(
item {
SetUpRecoveryKeyBanner(
onContinueClick = onSetUpRecoveryClick,
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) }
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) },
)
}
}
@ -225,7 +225,7 @@ private fun RoomsViewList(
item {
ConfirmRecoveryKeyBanner(
onContinueClick = onConfirmRecoveryKeyClick,
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) }
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) },
)
}
}
@ -233,7 +233,7 @@ private fun RoomsViewList(
item {
NativeSlidingSyncMigrationBanner(
onContinueClick = onMigrateToNativeSlidingSyncClick,
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) }
onDismissClick = { updatedEventSink(RoomListEvents.DismissBanner) },
)
}
}

View file

@ -11,7 +11,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import io.element.android.features.roomlist.impl.R
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
import io.element.android.libraries.designsystem.components.Announcement
import io.element.android.libraries.designsystem.components.AnnouncementType
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -21,13 +22,15 @@ internal fun SetUpRecoveryKeyBanner(
onDismissClick: () -> Unit,
modifier: Modifier = Modifier,
) {
DialogLikeBannerMolecule(
modifier = modifier,
Announcement(
modifier = modifier.roomListBannerPadding(),
title = stringResource(R.string.banner_set_up_recovery_title),
content = stringResource(R.string.banner_set_up_recovery_content),
actionText = stringResource(R.string.banner_set_up_recovery_submit),
onSubmitClick = onContinueClick,
onDismissClick = onDismissClick,
description = stringResource(R.string.banner_set_up_recovery_content),
type = AnnouncementType.Actionable(
actionText = stringResource(R.string.banner_set_up_recovery_submit),
onActionClick = onContinueClick,
onDismissClick = onDismissClick,
),
)
}

View file

@ -1,97 +0,0 @@
/*
* Copyright 2023, 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.atomic.molecules
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
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.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun DialogLikeBannerMolecule(
title: String,
content: String,
onSubmitClick: () -> Unit,
onDismissClick: (() -> Unit)?,
modifier: Modifier = Modifier,
actionText: String = stringResource(CommonStrings.action_continue),
) {
Box(modifier = modifier.padding(horizontal = 16.dp, vertical = 8.dp)) {
Surface(
Modifier.fillMaxWidth(),
shape = MaterialTheme.shapes.small,
color = MaterialTheme.colorScheme.surfaceVariant
) {
Column(
Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 12.dp)
) {
Row {
Text(
text = title,
modifier = Modifier.weight(1f),
style = ElementTheme.typography.fontBodyLgMedium,
color = MaterialTheme.colorScheme.primary,
textAlign = TextAlign.Start,
)
if (onDismissClick != null) {
Icon(
modifier = Modifier.clickable(onClick = onDismissClick),
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(CommonStrings.action_close)
)
}
}
Spacer(modifier = Modifier.height(4.dp))
Text(
text = content,
style = ElementTheme.typography.fontBodyMdRegular,
)
Spacer(modifier = Modifier.height(12.dp))
Button(
text = actionText,
size = ButtonSize.Medium,
modifier = Modifier.fillMaxWidth(),
onClick = onSubmitClick,
)
}
}
}
}
@PreviewsDayNight
@Composable
internal fun DialogLikeBannerMoleculePreview() = ElementPreview {
DialogLikeBannerMolecule(
title = "Title",
content = "Content",
onSubmitClick = {},
onDismissClick = {}
)
}

View file

@ -0,0 +1,211 @@
/*
* Copyright 2025 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.clickable
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
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.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.CommonStrings
/**
* Announcement component following design system https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2002-2154.
*/
@Composable
fun Announcement(
title: String,
description: String?,
type: AnnouncementType,
modifier: Modifier = Modifier,
) {
when (type) {
is AnnouncementType.Informative -> InformativeAnnouncement(
title = title,
description = description,
isError = type.isCritical,
modifier = modifier,
)
is AnnouncementType.Actionable -> ActionableAnnouncement(
title = title,
description = description,
actionText = type.actionText,
onActionClick = type.onActionClick,
onDismissClick = type.onDismissClick,
modifier = modifier,
)
}
}
@Immutable
sealed interface AnnouncementType {
data class Informative(val isCritical: Boolean = false) : AnnouncementType
data class Actionable(
val actionText: String,
val onActionClick: () -> Unit,
val onDismissClick: (() -> Unit)?,
) : AnnouncementType
}
@Composable
private fun ActionableAnnouncement(
title: String,
description: String?,
actionText: String,
onActionClick: () -> Unit,
onDismissClick: (() -> Unit)?,
modifier: Modifier = Modifier,
) {
AnnouncementSurface(modifier) {
Column {
TitleAndDescription(
title = title,
description = description,
trailingContent = onDismissClick?.let {
{
Icon(
modifier = Modifier.clickable(onClick = onDismissClick),
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(CommonStrings.action_close)
)
}
}
)
Spacer(Modifier.height(16.dp))
Button(
text = actionText,
size = ButtonSize.Medium,
onClick = onActionClick,
modifier = Modifier.fillMaxWidth(),
)
}
}
}
@Composable
private fun InformativeAnnouncement(
title: String,
description: String?,
isError: Boolean,
modifier: Modifier = Modifier,
) {
AnnouncementSurface(modifier = modifier) {
Row {
Icon(
imageVector = if (isError) CompoundIcons.Error() else CompoundIcons.Info(),
tint = if (isError) ElementTheme.colors.iconCriticalPrimary else ElementTheme.colors.iconPrimary,
contentDescription = null,
)
Spacer(Modifier.width(12.dp))
TitleAndDescription(
title = title,
description = description,
titleColor = if (isError) ElementTheme.colors.textCriticalPrimary else ElementTheme.colors.textPrimary,
)
}
}
}
@Composable
private fun TitleAndDescription(
title: String,
description: String?,
modifier: Modifier = Modifier,
titleColor: Color = ElementTheme.colors.textPrimary,
descriptionColor: Color = ElementTheme.colors.textSecondary,
trailingContent: (@Composable () -> Unit)? = null,
) {
Column(modifier = modifier) {
Row {
Text(
text = title,
style = ElementTheme.typography.fontBodyLgMedium,
color = titleColor,
modifier = Modifier.weight(1f),
)
if (trailingContent != null) {
Spacer(Modifier.width(12.dp))
trailingContent()
}
}
if (description != null) {
Spacer(Modifier.height(4.dp))
Text(
text = description,
style = ElementTheme.typography.fontBodyMdRegular,
color = descriptionColor,
)
}
}
}
@Composable
private fun AnnouncementSurface(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Surface(
modifier = modifier.fillMaxWidth(),
shape = RoundedCornerShape(size = 12.dp),
color = ElementTheme.colors.bgSubtleSecondary
) {
Box(modifier = Modifier.padding(16.dp)) {
content()
}
}
}
@PreviewsDayNight
@Composable
internal fun AnnouncementPreview() = ElementPreview {
Column(
verticalArrangement = spacedBy(16.dp),
modifier = Modifier.padding(16.dp)
) {
Announcement(
title = "Headline",
description = "Text description goes here.",
type = AnnouncementType.Informative(isCritical = false),
)
Announcement(
title = "Headline",
description = "Text description goes here.",
type = AnnouncementType.Informative(isCritical = true),
)
Announcement(
title = "Headline",
description = "Text description goes here.",
type = AnnouncementType.Actionable(
actionText = "Label",
onActionClick = {},
onDismissClick = {},
),
)
}
}

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:65ad692c5886f2b6b7ff4a092f76f78aa1e2399a20bc868338f16e909d005e48
size 43300
oid sha256:16d1a40f1236f2b0070c05851cfb5f1e73e420361d62aafb8ac5776e20b94db4
size 42127

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a73919f6f52477978e6344b25bc5a53a76c1301847dc6feae60412991c4fb017
size 44694
oid sha256:f96978e1ea1f0ccf62d977e5d41e7036523304b6b42b27b82281756fb5546b39
size 45057

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e63be8118802e41f0ab0c292da98bd9b9c58454a67b45f0e61ab5493ff81e138
size 41085
oid sha256:8dd44e2127936e2e01d99933a2f18e50ca760f614f6a3e1c3162e3387d4931ee
size 39759

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:55a69297fbe88c14e96a0c1c1f283fbd51b8ac8f172e844ea6965e2ce5dda5d4
size 42314
oid sha256:4f22b7825bfa438f55514a3d09696de34450c16f9d4481c4892be9c8dcb45191
size 42486

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d7a0cd7a14b159d7833d5bb6e24941a19b8b4cfcf3f644f0427815ae0b5c2ac7
size 25903
oid sha256:608bc04aa68ecc8842ad896b6aae593b7c0d0c8874b6a7ba41c51655ee1420dc
size 26143

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b6d6997626425814ca7bd8a222db596598b37850eaa5f5dd410ea0acc294d66f
size 24896
oid sha256:75056895683a4ac0c72a1a7b02715b613cbbc6cb8f2af6ef8aff0892d9fbc0fc
size 25034

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2725f52055cb30320d4233630ae4d5f6eeafd1849e6d05c7c82f70c2917e0fe2
size 29619
oid sha256:8c54f8490dde1d413eb8fd0dd0f15c059fe78b7a88826bce3be3e6d32890f210
size 29784

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:04f6f95aed2ea83db78068c321b82a84e9c12b2b1f343461d53551cc752ddc2f
size 28969
oid sha256:a56dc221bfdd24f17d7a1ef5ebbf6c0702f446c2959ac813cec7f5dc1aaea2d5
size 29138

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:89827f64e3999f5310926ba3846d76c7f67ac463696bf45d801705dcd1565683
size 36576
oid sha256:bd29991ad9e550e5f1e997bffd89bd26d68a97a11213819e6f646c594deb0a32
size 37054

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e94f093da8e30f0aa7110c09d0cee380882b0df22ab38f3b89f0cfe220452b81
size 35461
oid sha256:d0abbd15a76d2b3b6a4d66e2ed7df83f1cff94ca03c38b7b2e4ca1e4075229ce
size 35731

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d124a4ee6f34031b0d122330c6c84b467be4a3ff363fa01c36e07db092dac1c4
size 46785
oid sha256:9b00197e010e15b647faba1d6db9cf7e8a1bf7177814e25b07d7207554810107
size 47084

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5574716fab5b8e24fb9d4289f1ca259718bd45a93130588c0f08687e7cf73267
size 73041
oid sha256:e1f630cfee64876a7143dff8720de4166248607d2c1247c857ed35290d08ab07
size 73216

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4d810f71b03757c41a70a8a06ab2b60755b4fc42a00f81f4e6a99d6a63d6bf13
size 45276
oid sha256:c20373e670c4066fef2ca3980ef3d4080a34992a8735bef9a3a87ea095309852
size 45540

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:84b3f2c25e6a8956e305d279f6a77cd7d8aa1b35715f2c2e975d772e0dc56682
size 71833
oid sha256:a8dfdf6bf277bee38b0e63dc4da4c28c7cff394419486681c4ddf8cff20bfb34
size 71739

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:70d5cdbd0b5944106aef135ee7865838f06faee1fbfe3c94d46c8c048dcdbc58
size 32440
oid sha256:17923c7b4c89f8c349710517e96764802ed73f8faba219a87b158812c5dc3c82
size 32754

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:75c42e75b758b877cf6d2d805976a1ccbd902399e77de6539e4e4e57db532409
size 31319
oid sha256:7b1e2c1996dc3b1bb7b7583f62c386baa10f177d8863ed36635ac8214b721324
size 31589

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e7359635c38513c10f53126ac545fd08ccfba47c5221f4daf0bb8b74286260e0
size 107309
oid sha256:edb52d5fc252ee719f6aec12faf98b8976eb9a61992dba510c06386999975ed2
size 105988

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:008877f559e22bf08b70f0b3c5dc0d65ccbcb0cd0a75b61620f65ae076fbc6a3
size 101728
oid sha256:85925c39a59d3ceca4da5234084a3218a33670a9e3fbd3121ef601e06fb93297
size 100367

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c6f8312ca8182e8d5b106cb7e9023a9a577571054770bd02b7d2f08896127a08
size 113159
oid sha256:1ee1b7d094db4cd00af34d1ef79c6e71ed61cec585612c538a0bc870c64b9966
size 111814

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9c2963502d9de945d1555d29dfe4229303043c9271de080242fa8d6b1efa4bcc
size 107186
oid sha256:49097acd61396b5190aa1820c61d826b04738dd56acb4cdfb5df5b04c486e961
size 106227

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:35ff9d95c3d01ca74f2792ae4b116946537467be54fa40cea473ef089048a571
size 10043

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6e8855bd1114f0aab03cfea1f495493e43e3680f954209944c1e6718160bdfac
size 9598

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:297a71fec7335294de0cdd9100e64454102711ff76e1df7a5f1e32e719310ad4
size 27062

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1c986e1494b1c09606b12cf68270c54bda48034caea60dd911cac6cd976f4dc5
size 26082