Merge pull request #1955 from vector-im/feature/bma/notificationForInvites
Add setting to disable notification for invites
This commit is contained in:
commit
8f5fed48ab
19 changed files with 100 additions and 38 deletions
1
changelog.d/1944.misc
Normal file
1
changelog.d/1944.misc
Normal file
|
|
@ -0,0 +1 @@
|
|||
Add toggle in the notification settings to disable notifications for room invites.
|
||||
|
|
@ -117,7 +117,7 @@ You can also have access to the aars through the [release](https://github.com/ma
|
|||
|
||||
#### Build the SDK locally
|
||||
|
||||
Easiest way: run the script [./tools/sdk/build_rust_sdk.sh](./tools/sdk/build_rust_sdk.sh) and just answer the questions.
|
||||
Easiest way: run the script [../tools/sdk/build_rust_sdk.sh](../tools/sdk/build_rust_sdk.sh) and just answer the questions.
|
||||
|
||||
Legacy way:
|
||||
|
||||
|
|
|
|||
|
|
@ -17,11 +17,11 @@
|
|||
package io.element.android.features.preferences.impl.notifications
|
||||
|
||||
sealed interface NotificationSettingsEvents {
|
||||
|
||||
data object RefreshSystemNotificationsEnabled : NotificationSettingsEvents
|
||||
data class SetNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data class SetAtRoomNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data class SetCallNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data class SetInviteForMeNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
|
||||
data object FixConfigurationMismatch : NotificationSettingsEvents
|
||||
data object ClearConfigurationMismatchError : NotificationSettingsEvents
|
||||
data object ClearNotificationChangeError : NotificationSettingsEvents
|
||||
|
|
|
|||
|
|
@ -76,6 +76,9 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
is NotificationSettingsEvents.SetCallNotificationsEnabled -> {
|
||||
localCoroutineScope.setCallNotificationsEnabled(event.enabled, changeNotificationSettingAction)
|
||||
}
|
||||
is NotificationSettingsEvents.SetInviteForMeNotificationsEnabled -> {
|
||||
localCoroutineScope.setInviteForMeNotificationsEnabled(event.enabled, changeNotificationSettingAction)
|
||||
}
|
||||
is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled)
|
||||
NotificationSettingsEvents.ClearConfigurationMismatchError -> {
|
||||
matrixSettings.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false)
|
||||
|
|
@ -123,10 +126,12 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
|
||||
val callNotificationsEnabled = notificationSettingsService.isCallEnabled().getOrThrow()
|
||||
val atRoomNotificationsEnabled = notificationSettingsService.isRoomMentionEnabled().getOrThrow()
|
||||
val inviteForMeNotificationsEnabled = notificationSettingsService.isInviteForMeEnabled().getOrThrow()
|
||||
|
||||
target.value = NotificationSettingsState.MatrixSettings.Valid(
|
||||
atRoomNotificationsEnabled = atRoomNotificationsEnabled,
|
||||
callNotificationsEnabled = callNotificationsEnabled,
|
||||
inviteForMeNotificationsEnabled = inviteForMeNotificationsEnabled,
|
||||
defaultGroupNotificationMode = encryptedGroupDefaultMode,
|
||||
defaultOneToOneNotificationMode = encryptedOneToOneDefaultMode,
|
||||
)
|
||||
|
|
@ -175,6 +180,12 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
}.runCatchingUpdatingState(action)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setInviteForMeNotificationsEnabled(enabled: Boolean, action: MutableState<Async<Unit>>) = launch {
|
||||
suspend {
|
||||
notificationSettingsService.setInviteForMeEnabled(enabled).getOrThrow()
|
||||
}.runCatchingUpdatingState(action)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch {
|
||||
userPushStore.setNotificationEnabledForDevice(enabled)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ data class NotificationSettingsState(
|
|||
data class Valid(
|
||||
val atRoomNotificationsEnabled: Boolean,
|
||||
val callNotificationsEnabled: Boolean,
|
||||
val inviteForMeNotificationsEnabled: Boolean,
|
||||
val defaultGroupNotificationMode: RoomNotificationMode?,
|
||||
val defaultOneToOneNotificationMode: RoomNotificationMode?,
|
||||
) : MatrixSettings
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ fun aNotificationSettingsState(
|
|||
matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
|
||||
atRoomNotificationsEnabled = true,
|
||||
callNotificationsEnabled = true,
|
||||
inviteForMeNotificationsEnabled = true,
|
||||
defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
||||
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ fun NotificationSettingsView(
|
|||
onMentionNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(it)) },
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) },
|
||||
onInviteForMeNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(it)) },
|
||||
)
|
||||
}
|
||||
AsyncView(
|
||||
|
|
@ -98,6 +99,7 @@ private fun NotificationSettingsContentView(
|
|||
onMentionNotificationsChanged: (Boolean) -> Unit,
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// onCallsNotificationsChanged: (Boolean) -> Unit,
|
||||
onInviteForMeNotificationsChanged: (Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
|
@ -147,8 +149,8 @@ private fun NotificationSettingsContentView(
|
|||
onCheckedChange = onMentionNotificationsChanged
|
||||
)
|
||||
}
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// PreferenceCategory(title = stringResource(id = CommonStrings.screen_notification_settings_additional_settings_section_title)) {
|
||||
PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_additional_settings_section_title)) {
|
||||
// TODO We are removing the call notification toggle until support for call notifications has been added
|
||||
// PreferenceSwitch(
|
||||
// modifier = Modifier,
|
||||
// title = stringResource(id = CommonStrings.screen_notification_settings_calls_label),
|
||||
|
|
@ -156,7 +158,14 @@ private fun NotificationSettingsContentView(
|
|||
// switchAlignment = Alignment.Top,
|
||||
// onCheckedChange = onCallsNotificationsChanged
|
||||
// )
|
||||
// }
|
||||
PreferenceSwitch(
|
||||
modifier = Modifier,
|
||||
title = stringResource(id = R.string.screen_notification_settings_invite_for_me_label),
|
||||
isChecked = matrixSettings.inviteForMeNotificationsEnabled,
|
||||
switchAlignment = Alignment.Top,
|
||||
onCheckedChange = onInviteForMeNotificationsChanged
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ class NotificationSettingsPresenterTests {
|
|||
assertThat(initialState.appSettings.appNotificationsEnabled).isFalse()
|
||||
assertThat(initialState.appSettings.systemNotificationsEnabled).isTrue()
|
||||
assertThat(initialState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Uninitialized)
|
||||
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
|
|
@ -50,6 +49,7 @@ class NotificationSettingsPresenterTests {
|
|||
val valid = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(valid?.atRoomNotificationsEnabled).isFalse()
|
||||
assertThat(valid?.callNotificationsEnabled).isFalse()
|
||||
assertThat(valid?.inviteForMeNotificationsEnabled).isFalse()
|
||||
assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
|
||||
assertThat(valid?.defaultOneToOneNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
|
|
@ -63,7 +63,6 @@ class NotificationSettingsPresenterTests {
|
|||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
|
|
@ -82,7 +81,6 @@ class NotificationSettingsPresenterTests {
|
|||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
|
||||
notificationSettingsService.setDefaultRoomNotificationMode(
|
||||
isEncrypted = true,
|
||||
isOneToOne = false,
|
||||
|
|
@ -118,7 +116,6 @@ class NotificationSettingsPresenterTests {
|
|||
val fixedState = consumeItemsUntilPredicate(timeout = 2000.milliseconds) {
|
||||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
|
||||
val fixedMatrixState = fixedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(fixedMatrixState?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
|
||||
}
|
||||
|
|
@ -134,7 +131,6 @@ class NotificationSettingsPresenterTests {
|
|||
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
|
||||
}.last()
|
||||
assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
|
||||
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(false))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
!it.appSettings.appNotificationsEnabled
|
||||
|
|
@ -155,7 +151,6 @@ class NotificationSettingsPresenterTests {
|
|||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(validMatrixState?.callNotificationsEnabled).isFalse()
|
||||
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(true))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.callNotificationsEnabled == true
|
||||
|
|
@ -166,6 +161,27 @@ class NotificationSettingsPresenterTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - set invite for me notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val loadedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == false
|
||||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(validMatrixState?.inviteForMeNotificationsEnabled).isFalse()
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(true))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == true
|
||||
}.last()
|
||||
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(updatedMatrixState?.inviteForMeNotificationsEnabled).isTrue()
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - set atRoom notifications enabled`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter()
|
||||
|
|
@ -177,7 +193,6 @@ class NotificationSettingsPresenterTests {
|
|||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
|
||||
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(true))
|
||||
val updatedState = consumeItemsUntilPredicate {
|
||||
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == true
|
||||
|
|
@ -201,14 +216,12 @@ class NotificationSettingsPresenterTests {
|
|||
}.last()
|
||||
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
|
||||
assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
|
||||
|
||||
loadedState.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(true))
|
||||
val errorState = consumeItemsUntilPredicate {
|
||||
it.changeNotificationSettingAction.isFailure()
|
||||
}.last()
|
||||
assertThat(errorState.changeNotificationSettingAction.isFailure()).isTrue()
|
||||
errorState.eventSink(NotificationSettingsEvents.ClearNotificationChangeError)
|
||||
|
||||
val clearErrorState = consumeItemsUntilPredicate {
|
||||
it.changeNotificationSettingAction.isUninitialized()
|
||||
}.last()
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ jsoup = "org.jsoup:jsoup:1.17.1"
|
|||
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
|
||||
molecule-runtime = "app.cash.molecule:molecule-runtime:1.3.1"
|
||||
timber = "com.jakewharton.timber:timber:5.0.1"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.73"
|
||||
matrix_sdk = "org.matrix.rustcomponents:sdk-android:0.1.74"
|
||||
matrix_richtexteditor = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
|
||||
matrix_richtexteditor_compose = { module = "io.element.android:wysiwyg-compose", version.ref = "wysiwyg" }
|
||||
sqldelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
|
||||
|
|
|
|||
|
|
@ -38,5 +38,7 @@ interface NotificationSettingsService {
|
|||
suspend fun setRoomMentionEnabled(enabled: Boolean): Result<Unit>
|
||||
suspend fun isCallEnabled(): Result<Boolean>
|
||||
suspend fun setCallEnabled(enabled: Boolean): Result<Unit>
|
||||
suspend fun isInviteForMeEnabled(): Result<Boolean>
|
||||
suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit>
|
||||
suspend fun getRoomsWithUserDefinedRules(): Result<List<String>>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,10 +119,9 @@ class RustMatrixClient constructor(
|
|||
.filterByPushRules()
|
||||
.finish()
|
||||
}
|
||||
private val notificationSettings = client.getNotificationSettings()
|
||||
|
||||
private val notificationService = RustNotificationService(sessionId, notificationClient, dispatchers, clock)
|
||||
private val notificationSettingsService = RustNotificationSettingsService(notificationSettings, dispatchers)
|
||||
private val notificationSettingsService = RustNotificationSettingsService(client, dispatchers)
|
||||
.apply { start() }
|
||||
private val roomSyncSubscriber = RoomSyncSubscriber(innerRoomListService, dispatchers)
|
||||
private val encryptionService = RustEncryptionService(
|
||||
client = client,
|
||||
|
|
@ -346,8 +345,7 @@ class RustMatrixClient constructor(
|
|||
override fun close() {
|
||||
sessionCoroutineScope.cancel()
|
||||
clientDelegateTaskHandle?.cancelAndDestroy()
|
||||
notificationSettings.setDelegate(null)
|
||||
notificationSettings.destroy()
|
||||
notificationSettingsService.destroy()
|
||||
verificationService.destroy()
|
||||
syncService.destroy()
|
||||
innerRoomListService.destroy()
|
||||
|
|
|
|||
|
|
@ -26,16 +26,16 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.matrix.rustcomponents.sdk.NotificationSettings
|
||||
import org.matrix.rustcomponents.sdk.Client
|
||||
import org.matrix.rustcomponents.sdk.NotificationSettingsDelegate
|
||||
import org.matrix.rustcomponents.sdk.NotificationSettingsException
|
||||
import timber.log.Timber
|
||||
|
||||
class RustNotificationSettingsService(
|
||||
private val notificationSettings: NotificationSettings,
|
||||
client: Client,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
) : NotificationSettingsService {
|
||||
|
||||
private val notificationSettings = client.getNotificationSettings()
|
||||
private val _notificationSettingsChangeFlow = MutableSharedFlow<Unit>(extraBufferCapacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
override val notificationSettingsChangeFlow: SharedFlow<Unit> = _notificationSettingsChangeFlow.asSharedFlow()
|
||||
|
||||
|
|
@ -45,10 +45,15 @@ class RustNotificationSettingsService(
|
|||
}
|
||||
}
|
||||
|
||||
init {
|
||||
fun start() {
|
||||
notificationSettings.setDelegate(notificationSettingsDelegate)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
notificationSettings.setDelegate(null)
|
||||
notificationSettings.destroy()
|
||||
}
|
||||
|
||||
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> =
|
||||
runCatching {
|
||||
notificationSettings.getRoomNotificationSettings(roomId.value, isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::map)
|
||||
|
|
@ -119,6 +124,18 @@ class RustNotificationSettingsService(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun isInviteForMeEnabled(): Result<Boolean> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
notificationSettings.isInviteForMeEnabled()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit> = withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
notificationSettings.setInviteForMeEnabled(enabled)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoomsWithUserDefinedRules(): Result<List<String>> =
|
||||
runCatching {
|
||||
notificationSettings.getRoomsWithUserDefinedRules(enabled = true)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class FakeNotificationSettingsService(
|
|||
private var roomNotificationMode: RoomNotificationMode = initialRoomMode
|
||||
private var roomNotificationModeIsDefault: Boolean = initialRoomModeIsDefault
|
||||
private var callNotificationsEnabled = false
|
||||
private var inviteNotificationsEnabled = false
|
||||
private var atRoomNotificationsEnabled = false
|
||||
private var setNotificationModeError: Throwable? = null
|
||||
private var restoreDefaultNotificationModeError: Throwable? = null
|
||||
|
|
@ -52,7 +53,7 @@ class FakeNotificationSettingsService(
|
|||
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> {
|
||||
return Result.success(
|
||||
RoomNotificationSettings(
|
||||
mode = if(roomNotificationModeIsDefault) defaultEncryptedGroupRoomNotificationMode else roomNotificationMode,
|
||||
mode = if (roomNotificationModeIsDefault) defaultEncryptedGroupRoomNotificationMode else roomNotificationMode,
|
||||
isDefault = roomNotificationModeIsDefault
|
||||
)
|
||||
)
|
||||
|
|
@ -149,6 +150,15 @@ class FakeNotificationSettingsService(
|
|||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun isInviteForMeEnabled(): Result<Boolean> {
|
||||
return Result.success(inviteNotificationsEnabled)
|
||||
}
|
||||
|
||||
override suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit> {
|
||||
inviteNotificationsEnabled = enabled
|
||||
return Result.success(Unit)
|
||||
}
|
||||
|
||||
override suspend fun getRoomsWithUserDefinedRules(): Result<List<String>> {
|
||||
return Result.success(if (roomNotificationModeIsDefault) listOf() else listOf(A_ROOM_ID.value))
|
||||
}
|
||||
|
|
@ -168,5 +178,4 @@ class FakeNotificationSettingsService(
|
|||
fun givenSetDefaultNotificationModeError(throwable: Throwable?) {
|
||||
setDefaultNotificationModeError = throwable
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2f9516130ee975b723283523d1d62eaa116ae075be3ce62477aaf0429eeff13c
|
||||
size 52832
|
||||
oid sha256:a4b146a10957549dd4410bff3ce4793d25c31910607eec43db44b7be019af068
|
||||
size 60521
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3ae4c265af9ff1c5ffeff7f4aa6adfb5e0091ae9fd6360f46ee8261cf4ca213d
|
||||
size 48895
|
||||
oid sha256:340808b11e072679e7b90c939bcb5367a723b9881f084dccc0b594de5f12d543
|
||||
size 54830
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e5b745897ee2bfb084a80ebbc585577532261d5a8d71926ad42c02008be46003
|
||||
size 48810
|
||||
oid sha256:ff00bafd64a4827472d757e6519955550327bb9dca97ea8a7163da4ce278f445
|
||||
size 54777
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3a68d87c82275e80a6774712ea0ab85b04cece2c2d2dc8c19133e6878d71a1b4
|
||||
size 49178
|
||||
oid sha256:d0b8f14d6bcd6309cf8a961104738c529164621a2de4c642ce7944a48217d609
|
||||
size 55838
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8ecc7a31d53543fae8950e2773da0aea2ebdb6c9b557254e0062ce000dcd79b3
|
||||
size 45061
|
||||
oid sha256:964fc455b25f442bfc89e917148c15f7f9301d9b6db5c94f2075d994b74a6eef
|
||||
size 50975
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8bb56b559b52efdd9f6ac41e0ae674054b6f511292b2cf88208bbf32afb765a9
|
||||
size 44414
|
||||
oid sha256:fccd2b3e6fff431b0b650cccef21c0b8129c838dfc3b1b0bc6ee83321dcfe698
|
||||
size 50386
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue