Merge pull request #4312 from element-hq/feature/bma/fixMultipleNtfy
Fix issues due to multiple ntfy applications with the same name.
This commit is contained in:
commit
1bbcedfa38
19 changed files with 121 additions and 60 deletions
|
|
@ -83,19 +83,19 @@ class NotificationSettingsPresenter @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// List of Distributor names
|
// List of Distributors
|
||||||
val distributorNames = remember {
|
val availableDistributors = remember {
|
||||||
distributors.map { it.second.name }.toImmutableList()
|
distributors.map { it.second }.toImmutableList()
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentDistributorName by remember { mutableStateOf<AsyncData<String>>(AsyncData.Uninitialized) }
|
var currentDistributor by remember { mutableStateOf<AsyncData<Distributor>>(AsyncData.Uninitialized) }
|
||||||
var refreshPushProvider by remember { mutableIntStateOf(0) }
|
var refreshPushProvider by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
LaunchedEffect(refreshPushProvider) {
|
LaunchedEffect(refreshPushProvider) {
|
||||||
val p = pushService.getCurrentPushProvider()
|
val p = pushService.getCurrentPushProvider()
|
||||||
val name = p?.getCurrentDistributor(matrixClient.sessionId)?.name
|
val distributor = p?.getCurrentDistributor(matrixClient.sessionId)
|
||||||
currentDistributorName = if (name != null) {
|
currentDistributor = if (distributor != null) {
|
||||||
AsyncData.Success(name)
|
AsyncData.Success(distributor)
|
||||||
} else {
|
} else {
|
||||||
AsyncData.Failure(Exception("Failed to get current push provider"))
|
AsyncData.Failure(Exception("Failed to get current push provider"))
|
||||||
}
|
}
|
||||||
|
|
@ -108,24 +108,23 @@ class NotificationSettingsPresenter @Inject constructor(
|
||||||
) = launch {
|
) = launch {
|
||||||
showChangePushProviderDialog = false
|
showChangePushProviderDialog = false
|
||||||
data ?: return@launch
|
data ?: return@launch
|
||||||
// No op if the value is the same.
|
val (pushProvider, distributor) = data
|
||||||
if (data.second.name == currentDistributorName.dataOrNull()) return@launch
|
// No op if the distributor is the same.
|
||||||
currentDistributorName = AsyncData.Loading(currentDistributorName.dataOrNull())
|
if (distributor == currentDistributor.dataOrNull()) return@launch
|
||||||
data.let { (pushProvider, distributor) ->
|
currentDistributor = AsyncData.Loading(currentDistributor.dataOrNull())
|
||||||
pushService.registerWith(
|
pushService.registerWith(
|
||||||
matrixClient = matrixClient,
|
matrixClient = matrixClient,
|
||||||
pushProvider = pushProvider,
|
pushProvider = pushProvider,
|
||||||
distributor = distributor
|
distributor = distributor
|
||||||
|
)
|
||||||
|
.fold(
|
||||||
|
{
|
||||||
|
refreshPushProvider++
|
||||||
|
},
|
||||||
|
{
|
||||||
|
currentDistributor = AsyncData.Failure(it)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
.fold(
|
|
||||||
{
|
|
||||||
refreshPushProvider++
|
|
||||||
},
|
|
||||||
{
|
|
||||||
currentDistributorName = AsyncData.Failure(it)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun handleEvents(event: NotificationSettingsEvents) {
|
fun handleEvents(event: NotificationSettingsEvents) {
|
||||||
|
|
@ -162,8 +161,8 @@ class NotificationSettingsPresenter @Inject constructor(
|
||||||
appNotificationsEnabled = appNotificationsEnabled.value
|
appNotificationsEnabled = appNotificationsEnabled.value
|
||||||
),
|
),
|
||||||
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
||||||
currentPushDistributor = currentDistributorName,
|
currentPushDistributor = currentDistributor,
|
||||||
availablePushDistributors = distributorNames,
|
availablePushDistributors = availableDistributors,
|
||||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||||
fullScreenIntentPermissionsState = key(refreshFullScreenIntentSettings) { fullScreenIntentPermissionsPresenter.present() },
|
fullScreenIntentPermissionsState = key(refreshFullScreenIntentSettings) { fullScreenIntentPermissionsPresenter.present() },
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import io.element.android.libraries.architecture.AsyncAction
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
|
import io.element.android.libraries.pushproviders.api.Distributor
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
|
|
@ -19,8 +20,8 @@ data class NotificationSettingsState(
|
||||||
val matrixSettings: MatrixSettings,
|
val matrixSettings: MatrixSettings,
|
||||||
val appSettings: AppSettings,
|
val appSettings: AppSettings,
|
||||||
val changeNotificationSettingAction: AsyncAction<Unit>,
|
val changeNotificationSettingAction: AsyncAction<Unit>,
|
||||||
val currentPushDistributor: AsyncData<String>,
|
val currentPushDistributor: AsyncData<Distributor>,
|
||||||
val availablePushDistributors: ImmutableList<String>,
|
val availablePushDistributors: ImmutableList<Distributor>,
|
||||||
val showChangePushProviderDialog: Boolean,
|
val showChangePushProviderDialog: Boolean,
|
||||||
val fullScreenIntentPermissionsState: FullScreenIntentPermissionsState,
|
val fullScreenIntentPermissionsState: FullScreenIntentPermissionsState,
|
||||||
val eventSink: (NotificationSettingsEvents) -> Unit,
|
val eventSink: (NotificationSettingsEvents) -> Unit,
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
import io.element.android.libraries.fullscreenintent.api.FullScreenIntentPermissionsState
|
||||||
import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState
|
import io.element.android.libraries.fullscreenintent.api.aFullScreenIntentPermissionsState
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
|
import io.element.android.libraries.pushproviders.api.Distributor
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
|
|
@ -24,11 +25,19 @@ open class NotificationSettingsStateProvider : PreviewParameterProvider<Notifica
|
||||||
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading),
|
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading),
|
||||||
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))),
|
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))),
|
||||||
aValidNotificationSettingsState(
|
aValidNotificationSettingsState(
|
||||||
availablePushDistributors = listOf("Firebase"),
|
availablePushDistributors = listOf(aDistributor("Firebase")),
|
||||||
changeNotificationSettingAction = AsyncAction.Failure(Throwable("error")),
|
changeNotificationSettingAction = AsyncAction.Failure(Throwable("error")),
|
||||||
),
|
),
|
||||||
aValidNotificationSettingsState(availablePushDistributors = listOf("Firebase")),
|
aValidNotificationSettingsState(availablePushDistributors = listOf(aDistributor("Firebase"))),
|
||||||
aValidNotificationSettingsState(showChangePushProviderDialog = true),
|
aValidNotificationSettingsState(showChangePushProviderDialog = true),
|
||||||
|
aValidNotificationSettingsState(
|
||||||
|
availablePushDistributors = listOf(
|
||||||
|
aDistributor("Firebase"),
|
||||||
|
aDistributor("ntfy", "app.id1"),
|
||||||
|
aDistributor("ntfy", "app.id2"),
|
||||||
|
),
|
||||||
|
showChangePushProviderDialog = true,
|
||||||
|
),
|
||||||
aValidNotificationSettingsState(currentPushDistributor = AsyncData.Loading()),
|
aValidNotificationSettingsState(currentPushDistributor = AsyncData.Loading()),
|
||||||
aValidNotificationSettingsState(currentPushDistributor = AsyncData.Failure(Exception("Failed to change distributor"))),
|
aValidNotificationSettingsState(currentPushDistributor = AsyncData.Failure(Exception("Failed to change distributor"))),
|
||||||
aInvalidNotificationSettingsState(),
|
aInvalidNotificationSettingsState(),
|
||||||
|
|
@ -45,8 +54,11 @@ fun aValidNotificationSettingsState(
|
||||||
inviteForMeNotificationsEnabled: Boolean = true,
|
inviteForMeNotificationsEnabled: Boolean = true,
|
||||||
systemNotificationsEnabled: Boolean = true,
|
systemNotificationsEnabled: Boolean = true,
|
||||||
appNotificationEnabled: Boolean = true,
|
appNotificationEnabled: Boolean = true,
|
||||||
currentPushDistributor: AsyncData<String> = AsyncData.Success("Firebase"),
|
currentPushDistributor: AsyncData<Distributor> = AsyncData.Success(aDistributor("Firebase")),
|
||||||
availablePushDistributors: List<String> = listOf("Firebase", "ntfy"),
|
availablePushDistributors: List<Distributor> = listOf(
|
||||||
|
aDistributor("Firebase"),
|
||||||
|
aDistributor("ntfy"),
|
||||||
|
),
|
||||||
showChangePushProviderDialog: Boolean = false,
|
showChangePushProviderDialog: Boolean = false,
|
||||||
fullScreenIntentPermissionsState: FullScreenIntentPermissionsState = aFullScreenIntentPermissionsState(),
|
fullScreenIntentPermissionsState: FullScreenIntentPermissionsState = aFullScreenIntentPermissionsState(),
|
||||||
eventSink: (NotificationSettingsEvents) -> Unit = {},
|
eventSink: (NotificationSettingsEvents) -> Unit = {},
|
||||||
|
|
@ -88,3 +100,11 @@ fun aInvalidNotificationSettingsState(
|
||||||
fullScreenIntentPermissionsState = aFullScreenIntentPermissionsState(),
|
fullScreenIntentPermissionsState = aFullScreenIntentPermissionsState(),
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun aDistributor(
|
||||||
|
name: String = "Name",
|
||||||
|
value: String = "$name Value",
|
||||||
|
) = Distributor(
|
||||||
|
value = value,
|
||||||
|
name = name,
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ private fun NotificationSettingsContentView(
|
||||||
stringResource(id = CommonStrings.common_error)
|
stringResource(id = CommonStrings.common_error)
|
||||||
)
|
)
|
||||||
is AsyncData.Success -> ListItemContent.Text(
|
is AsyncData.Success -> ListItemContent.Text(
|
||||||
state.currentPushDistributor.dataOrNull() ?: ""
|
state.currentPushDistributor.dataOrNull()?.name ?: ""
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
@ -219,8 +219,14 @@ private fun NotificationSettingsContentView(
|
||||||
if (state.showChangePushProviderDialog) {
|
if (state.showChangePushProviderDialog) {
|
||||||
SingleSelectionDialog(
|
SingleSelectionDialog(
|
||||||
title = stringResource(id = R.string.screen_advanced_settings_choose_distributor_dialog_title_android),
|
title = stringResource(id = R.string.screen_advanced_settings_choose_distributor_dialog_title_android),
|
||||||
options = state.availablePushDistributors.map {
|
options = state.availablePushDistributors.map { distributor ->
|
||||||
ListOption(title = it)
|
// If there are several distributors with the same name, use the full name
|
||||||
|
val title = if (state.availablePushDistributors.count { it.name == distributor.name } > 1) {
|
||||||
|
distributor.fullName
|
||||||
|
} else {
|
||||||
|
distributor.name
|
||||||
|
}
|
||||||
|
ListOption(title = title)
|
||||||
}.toImmutableList(),
|
}.toImmutableList(),
|
||||||
initialSelection = state.availablePushDistributors.indexOf(state.currentPushDistributor.dataOrNull()),
|
initialSelection = state.availablePushDistributors.indexOf(state.currentPushDistributor.dataOrNull()),
|
||||||
onSelectOption = { index ->
|
onSelectOption = { index ->
|
||||||
|
|
|
||||||
|
|
@ -240,8 +240,11 @@ class NotificationSettingsPresenterTest {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
val initialState = awaitLastSequentialItem()
|
val initialState = awaitLastSequentialItem()
|
||||||
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncData.Success("aDistributorName0"))
|
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncData.Success(Distributor(value = "aDistributorValue0", name = "aDistributorName0")))
|
||||||
assertThat(initialState.availablePushDistributors).containsExactly("aDistributorName0", "aDistributorName1")
|
assertThat(initialState.availablePushDistributors).containsExactly(
|
||||||
|
Distributor(value = "aDistributorValue0", name = "aDistributorName0"),
|
||||||
|
Distributor(value = "aDistributorValue1", name = "aDistributorName1"),
|
||||||
|
)
|
||||||
initialState.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
initialState.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
||||||
val withDialog = awaitItem()
|
val withDialog = awaitItem()
|
||||||
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
||||||
|
|
@ -257,11 +260,35 @@ class NotificationSettingsPresenterTest {
|
||||||
assertThat(withNewProvider.currentPushDistributor).isInstanceOf(AsyncData.Loading::class.java)
|
assertThat(withNewProvider.currentPushDistributor).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
skipItems(1)
|
skipItems(1)
|
||||||
val lastItem = awaitItem()
|
val lastItem = awaitItem()
|
||||||
assertThat(lastItem.currentPushDistributor).isEqualTo(AsyncData.Success("aDistributorName1"))
|
assertThat(lastItem.currentPushDistributor).isEqualTo(AsyncData.Success(Distributor(value = "aDistributorValue1", name = "aDistributorName1")))
|
||||||
cancelAndIgnoreRemainingEvents()
|
cancelAndIgnoreRemainingEvents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - change push provider to the same value is no op`() = runTest {
|
||||||
|
val presenter = createNotificationSettingsPresenter(
|
||||||
|
pushService = createFakePushService(),
|
||||||
|
)
|
||||||
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitLastSequentialItem()
|
||||||
|
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncData.Success(Distributor(value = "aDistributorValue0", name = "aDistributorName0")))
|
||||||
|
assertThat(initialState.availablePushDistributors).containsExactly(
|
||||||
|
Distributor(value = "aDistributorValue0", name = "aDistributorName0"),
|
||||||
|
Distributor(value = "aDistributorValue1", name = "aDistributorName1"),
|
||||||
|
)
|
||||||
|
initialState.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
||||||
|
assertThat(awaitItem().showChangePushProviderDialog).isTrue()
|
||||||
|
// Choose the same value (index 0)
|
||||||
|
initialState.eventSink(NotificationSettingsEvents.SetPushProvider(0))
|
||||||
|
val withNewProvider = awaitItem()
|
||||||
|
assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
|
||||||
|
expectNoEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - RefreshSystemNotificationsEnabled also refreshes fullScreenIntentState`() = runTest {
|
fun `present - RefreshSystemNotificationsEnabled also refreshes fullScreenIntentState`() = runTest {
|
||||||
var lambdaResult = aFullScreenIntentPermissionsState(permissionGranted = false)
|
var lambdaResult = aFullScreenIntentPermissionsState(permissionGranted = false)
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ class NotificationSettingsViewTest {
|
||||||
state = aValidNotificationSettingsState(
|
state = aValidNotificationSettingsState(
|
||||||
eventSink = eventsRecorder,
|
eventSink = eventsRecorder,
|
||||||
showChangePushProviderDialog = true,
|
showChangePushProviderDialog = true,
|
||||||
availablePushDistributors = listOf("P1", "P2")
|
availablePushDistributors = listOf(aDistributor("P1"), aDistributor("P2"))
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
rule.onNodeWithText("P2").performClick()
|
rule.onNodeWithText("P2").performClick()
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,6 @@ package io.element.android.libraries.pushproviders.api
|
||||||
data class Distributor(
|
data class Distributor(
|
||||||
val value: String,
|
val value: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
) {
|
||||||
|
val fullName = "$name ($value)"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:16d1a40f1236f2b0070c05851cfb5f1e73e420361d62aafb8ac5776e20b94db4
|
oid sha256:f96978e1ea1f0ccf62d977e5d41e7036523304b6b42b27b82281756fb5546b39
|
||||||
size 42127
|
size 45057
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:a56d884dacc6f73de25255dc4c0960e15968a6b9b89cfab858571d5f6c5a16e6
|
oid sha256:16d1a40f1236f2b0070c05851cfb5f1e73e420361d62aafb8ac5776e20b94db4
|
||||||
size 59133
|
size 42127
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c7317fdf96ff21fe516286aca2720c89390eab57c15336a4fa82afd5473d29ec
|
oid sha256:a56d884dacc6f73de25255dc4c0960e15968a6b9b89cfab858571d5f6c5a16e6
|
||||||
size 15296
|
size 59133
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c7317fdf96ff21fe516286aca2720c89390eab57c15336a4fa82afd5473d29ec
|
||||||
|
size 15296
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:afafd3155ea2199c3e0d566797337a1bb5c88ffdf8beac3274d91829ef91d44d
|
oid sha256:796869e88b376df6e40b6ee51d471cbb9ba19f308a5353a818eb182b6d7fbe47
|
||||||
size 43807
|
size 44214
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f96978e1ea1f0ccf62d977e5d41e7036523304b6b42b27b82281756fb5546b39
|
oid sha256:afafd3155ea2199c3e0d566797337a1bb5c88ffdf8beac3274d91829ef91d44d
|
||||||
size 45057
|
size 43807
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8dd44e2127936e2e01d99933a2f18e50ca760f614f6a3e1c3162e3387d4931ee
|
oid sha256:4f22b7825bfa438f55514a3d09696de34450c16f9d4481c4892be9c8dcb45191
|
||||||
size 39759
|
size 42486
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:399efdebf67b1c042dc105d6538ea4fb622314c883fd6d3899eebcedd3ff357e
|
oid sha256:8dd44e2127936e2e01d99933a2f18e50ca760f614f6a3e1c3162e3387d4931ee
|
||||||
size 57540
|
size 39759
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0c484008012b2d569c6d313823b4ea8c96521fb6a172d37ee1db11f6794dce62
|
oid sha256:399efdebf67b1c042dc105d6538ea4fb622314c883fd6d3899eebcedd3ff357e
|
||||||
size 14806
|
size 57540
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:0c484008012b2d569c6d313823b4ea8c96521fb6a172d37ee1db11f6794dce62
|
||||||
|
size 14806
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8ddfa90c2eaf6b493ebc9c2c5164888716918c7b453c49d7653a0cd4dd69af81
|
oid sha256:bc77d365ea38cd50d5fac90efb15a610b52a069cbb799b8bf0d9924ea650ab79
|
||||||
size 42092
|
size 41408
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4f22b7825bfa438f55514a3d09696de34450c16f9d4481c4892be9c8dcb45191
|
oid sha256:8ddfa90c2eaf6b493ebc9c2c5164888716918c7b453c49d7653a0cd4dd69af81
|
||||||
size 42486
|
size 42092
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue