Add purse update chatlog message
This commit is contained in:
parent
06c5802d7a
commit
5b633de981
16 changed files with 327 additions and 16 deletions
|
|
@ -256,6 +256,8 @@
|
|||
<string name="chat__characteristic_change__hp_up">%1$s récupère %2$d point(s) de vie</string>
|
||||
<string name="chat__characteristic_change__pp_down">%1$s utilise %2$d point(s) de pouvoir</string>
|
||||
<string name="chat__characteristic_change__pp_up">%1$s récupère %2$d point(s) de pouvoir</string>
|
||||
<string name="chat__purse_change__spend">dépense</string>
|
||||
<string name="chat__purse_change__earn">empoche</string>
|
||||
|
||||
<string name="settings__title">Paramètres de l'application</string>
|
||||
<string name="settings__reset_action">Paramètres par défault</string>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.pixelized.shared.lwa.model.inventory.InventoryJson
|
|||
import com.pixelized.shared.lwa.model.item.ItemJson
|
||||
import com.pixelized.shared.lwa.model.tag.TagJson
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.rest.ApiPurseJson
|
||||
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
|
||||
|
||||
interface LwaClient {
|
||||
|
|
@ -116,6 +117,10 @@ interface LwaClient {
|
|||
create: Boolean,
|
||||
): APIResponse<Unit>
|
||||
|
||||
suspend fun putInventoryPurse(
|
||||
purse: ApiPurseJson,
|
||||
): APIResponse<Unit>
|
||||
|
||||
suspend fun deleteInventory(
|
||||
characterSheetId: String,
|
||||
): APIResponse<Unit>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.pixelized.shared.lwa.model.inventory.InventoryJson
|
|||
import com.pixelized.shared.lwa.model.item.ItemJson
|
||||
import com.pixelized.shared.lwa.model.tag.TagJson
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.rest.ApiPurseJson
|
||||
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
|
|
@ -199,6 +200,16 @@ class LwaClientImpl(
|
|||
}
|
||||
.body<APIResponse<Unit>>()
|
||||
|
||||
@Throws
|
||||
override suspend fun putInventoryPurse(
|
||||
purse: ApiPurseJson,
|
||||
): APIResponse<Unit> = client
|
||||
.put("$root/inventory/update/purse") {
|
||||
contentType(ContentType.Application.Json)
|
||||
setBody(purse)
|
||||
}
|
||||
.body<APIResponse<Unit>>()
|
||||
|
||||
@Throws
|
||||
override suspend fun deleteInventory(characterSheetId: String): APIResponse<Unit> = client
|
||||
.delete("$root/inventory/delete?characterSheetId=$characterSheetId")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ package com.pixelized.desktop.lwa.repository.inventory
|
|||
import com.pixelized.shared.lwa.model.inventory.Inventory
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class InventoryRepository(
|
||||
|
|
@ -50,6 +49,17 @@ class InventoryRepository(
|
|||
)
|
||||
}
|
||||
|
||||
@Throws
|
||||
suspend fun updateInventoryPurse(
|
||||
characterSheetId: String,
|
||||
purse: Inventory.Purse,
|
||||
) {
|
||||
inventoryStore.putInventoryPurse(
|
||||
characterSheetId = characterSheetId,
|
||||
purse = purse,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws
|
||||
suspend fun createInventoryItem(
|
||||
characterSheetId: String,
|
||||
|
|
|
|||
|
|
@ -73,6 +73,22 @@ class InventoryStore(
|
|||
}
|
||||
}
|
||||
|
||||
@Throws
|
||||
suspend fun putInventoryPurse(
|
||||
characterSheetId: String,
|
||||
purse: Inventory.Purse,
|
||||
) {
|
||||
val request = client.putInventoryPurse(
|
||||
purse = factory.convertToApiPurse(
|
||||
characterSheetId = characterSheetId,
|
||||
purse = purse,
|
||||
),
|
||||
)
|
||||
if (request.success.not()) {
|
||||
LwaClient.error(error = request)
|
||||
}
|
||||
}
|
||||
|
||||
@Throws
|
||||
suspend fun deleteInventory(
|
||||
characterSheetId: String,
|
||||
|
|
@ -163,6 +179,20 @@ class InventoryStore(
|
|||
private suspend fun handleMessage(message: SocketMessage) {
|
||||
when (message) {
|
||||
is ApiSynchronisation.InventoryApiSynchronisation -> when (message) {
|
||||
is ApiSynchronisation.PurseUpdate -> _inventories.update {
|
||||
it.toMutableMap().also { inventories ->
|
||||
inventories[message.characterSheetId]?.let { inventory ->
|
||||
inventories[message.characterSheetId] = inventory.copy(
|
||||
purse = Inventory.Purse(
|
||||
gold = inventory.purse.gold + message.gold,
|
||||
silver = inventory.purse.silver + message.silver,
|
||||
copper = inventory.purse.copper + message.copper,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is ApiSynchronisation.InventoryUpdate -> updateInventoryFlow(
|
||||
characterSheetId = message.characterSheetId,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -55,29 +55,26 @@ class PurseDialogViewModel(
|
|||
if (dialog.enableConfirm.value.not()) {
|
||||
return false
|
||||
}
|
||||
// Get the player inventory
|
||||
val inventory = inventoryRepository.inventory(characterSheetId = dialog.characterSheetId)
|
||||
// compute the new purse
|
||||
val sign = if (dialog.add.value) 1 else -1
|
||||
val goldValue = dialog.gold.valueFlow.value.toIntOrNull() ?: 0
|
||||
val silverValue = dialog.silver.valueFlow.value.toIntOrNull() ?: 0
|
||||
val copperValue = dialog.copper.valueFlow.value.toIntOrNull() ?: 0
|
||||
val purse = Inventory.Purse(
|
||||
gold = inventory.purse.gold + goldValue * sign,
|
||||
silver = inventory.purse.silver + silverValue * sign,
|
||||
copper = inventory.purse.copper + copperValue * sign,
|
||||
)
|
||||
// guard case: check if the purse change, not an error case, but avoid useless API call.
|
||||
if (inventory.purse == purse) {
|
||||
if (goldValue == 0 && silverValue == 0 && copperValue == 0) {
|
||||
return true
|
||||
}
|
||||
// build a purse delta
|
||||
val purse = Inventory.Purse(
|
||||
gold = goldValue * sign,
|
||||
silver = silverValue * sign,
|
||||
copper = copperValue * sign,
|
||||
)
|
||||
// API call.
|
||||
return try {
|
||||
inventoryRepository.updateInventory(
|
||||
inventory = inventory.copy(
|
||||
purse = purse
|
||||
),
|
||||
create = false,
|
||||
inventoryRepository.updateInventoryPurse(
|
||||
characterSheetId = dialog.characterSheetId,
|
||||
purse = purse,
|
||||
)
|
||||
true
|
||||
} catch (exception: Exception) {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.Characteristic
|
|||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.CharacteristicTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.DiminishedTextMessage
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.DiminishedTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.PurseTextMessage
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.PurseTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessage
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.TextMessage
|
||||
|
|
@ -123,6 +125,7 @@ fun CampaignChat(
|
|||
) {
|
||||
when (it) {
|
||||
is RollTextMessageUio -> RollTextMessage(message = it)
|
||||
is PurseTextMessageUio -> PurseTextMessage(message = it)
|
||||
is DiminishedTextMessageUio -> DiminishedTextMessage(message = it)
|
||||
is CharacteristicTextMessageUio -> CharacteristicTextMessage(message = it)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetReposit
|
|||
import com.pixelized.desktop.lwa.repository.settings.model.Settings
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.CharacteristicTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.DiminishedTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.PurseTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.TextMessage
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
|
|
@ -19,6 +20,8 @@ import lwacharactersheet.composeapp.generated.resources.chat__characteristic_cha
|
|||
import lwacharactersheet.composeapp.generated.resources.chat__characteristic_change__hp_up
|
||||
import lwacharactersheet.composeapp.generated.resources.chat__characteristic_change__pp_down
|
||||
import lwacharactersheet.composeapp.generated.resources.chat__characteristic_change__pp_up
|
||||
import lwacharactersheet.composeapp.generated.resources.chat__purse_change__earn
|
||||
import lwacharactersheet.composeapp.generated.resources.chat__purse_change__spend
|
||||
import java.text.SimpleDateFormat
|
||||
import kotlin.math.abs
|
||||
|
||||
|
|
@ -143,7 +146,33 @@ class TextMessageFactory(
|
|||
|
||||
is GameAdminEvent -> null
|
||||
|
||||
is ApiSynchronisation -> null
|
||||
is ApiSynchronisation -> when (message) {
|
||||
|
||||
is ApiSynchronisation.PurseUpdate -> {
|
||||
// only display the message if the character is in the party.
|
||||
val isInParty = campaign.characters.contains(message.characterSheetId)
|
||||
if (isInParty.not()) return null
|
||||
// get the character sheet
|
||||
val sheet = characterSheetRepository
|
||||
.characterDetail(characterSheetId = message.characterSheetId)
|
||||
?: return null
|
||||
|
||||
PurseTextMessageUio(
|
||||
id = "${message.timestamp}-${message.characterSheetId}-Purse",
|
||||
timestamp = formatTime.format(message.timestamp),
|
||||
character = sheet.name,
|
||||
action = when (message.add) {
|
||||
true -> Res.string.chat__purse_change__earn
|
||||
else -> Res.string.chat__purse_change__spend
|
||||
},
|
||||
gold = message.gold.takeIf { it != 0 }?.let { abs(it) },
|
||||
silver = message.silver.takeIf { it != 0 }?.let { abs(it) },
|
||||
copper = message.copper.takeIf { it != 0 }?.let { abs(it) },
|
||||
)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.text.messages
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_copper_32px
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_gold_32px
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_silver_32px
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
@Stable
|
||||
data class PurseTextMessageUio(
|
||||
override val id: String,
|
||||
override val timestamp: String,
|
||||
val character: String,
|
||||
val action: StringResource,
|
||||
val gold: Int?,
|
||||
val silver: Int?,
|
||||
val copper: Int?,
|
||||
) : TextMessage
|
||||
|
||||
@Composable
|
||||
fun PurseTextMessage(
|
||||
modifier: Modifier = Modifier,
|
||||
message: PurseTextMessageUio,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 3.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.timestamp,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = message.timestamp,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.timestamp,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = ">",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.text,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = message.character,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.text,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(message.action),
|
||||
)
|
||||
message.gold?.let {
|
||||
Row {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.text,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = "$it",
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(Res.drawable.ic_gold_32px),
|
||||
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
message.silver?.let {
|
||||
Row {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.text,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = "$it",
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(Res.drawable.ic_silver_32px),
|
||||
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
message.copper?.let {
|
||||
Row {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.chat.text,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = "$it",
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(Res.drawable.ic_copper_32px),
|
||||
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ fun GMActionContent(
|
|||
GMAction(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
icon = Res.drawable.ic_sync_24dp,
|
||||
label = "Syncrhonization du serveur",
|
||||
label = "Synchronization du serveur",
|
||||
onAction = onServerSync,
|
||||
)
|
||||
GMAction(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import com.pixelized.server.lwa.server.exception.BusinessException
|
|||
import com.pixelized.shared.lwa.model.inventory.Inventory
|
||||
import com.pixelized.shared.lwa.model.inventory.InventoryJson
|
||||
import com.pixelized.shared.lwa.model.inventory.factory.InventoryJsonFactory
|
||||
import com.pixelized.shared.lwa.protocol.rest.ApiPurseJson
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -38,6 +39,25 @@ class InventoryService(
|
|||
?: factory.convertToJson(Inventory.empty(characterSheetId = characterSheetId))
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun updatePurse(
|
||||
purse: ApiPurseJson,
|
||||
) {
|
||||
val inventory = inventory(
|
||||
characterSheetId = purse.characterSheetId
|
||||
)
|
||||
inventoryStore.save(
|
||||
inventory = inventory.copy(
|
||||
purse = inventory.purse.copy(
|
||||
gold = inventory.purse.gold + purse.gold,
|
||||
silver = inventory.purse.silver + purse.silver,
|
||||
copper = inventory.purse.copper + purse.copper,
|
||||
),
|
||||
),
|
||||
create = false,
|
||||
)
|
||||
}
|
||||
|
||||
@Throws
|
||||
fun save(
|
||||
inventoryJson: InventoryJson,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import com.pixelized.server.lwa.server.rest.inventory.deleteInventory
|
|||
import com.pixelized.server.lwa.server.rest.inventory.deleteInventoryItem
|
||||
import com.pixelized.server.lwa.server.rest.inventory.getInventory
|
||||
import com.pixelized.server.lwa.server.rest.inventory.putInventory
|
||||
import com.pixelized.server.lwa.server.rest.inventory.putPurse
|
||||
import com.pixelized.server.lwa.server.rest.item.deleteItem
|
||||
import com.pixelized.server.lwa.server.rest.item.getItem
|
||||
import com.pixelized.server.lwa.server.rest.item.getItems
|
||||
|
|
@ -272,6 +273,10 @@ class LocalServer {
|
|||
path = "/update",
|
||||
body = engine.putInventory()
|
||||
)
|
||||
put(
|
||||
path = "/update/purse",
|
||||
body = engine.putPurse(),
|
||||
)
|
||||
delete(
|
||||
path = "/delete",
|
||||
body = engine.deleteInventory()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
package com.pixelized.server.lwa.server.rest.inventory
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.rest.ApiPurseJson
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.request.receive
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
||||
fun Engine.putPurse(): suspend RoutingContext.() -> Unit {
|
||||
return {
|
||||
try {
|
||||
// get the query parameter
|
||||
val form = call.receive<ApiPurseJson>()
|
||||
// get the character inventory
|
||||
inventoryService.updatePurse(
|
||||
purse = form,
|
||||
)
|
||||
// send it back to the user.
|
||||
call.respond(
|
||||
message = APIResponse.success()
|
||||
)
|
||||
webSocket.emit(
|
||||
value = ApiSynchronisation.PurseUpdate(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
characterSheetId = form.characterSheetId,
|
||||
add = (form.gold * 10000 + form.silver * 100 + form.copper) >= 0,
|
||||
gold = form.gold,
|
||||
silver = form.silver,
|
||||
copper = form.copper,
|
||||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.shared.lwa.model.inventory.factory
|
|||
import com.pixelized.shared.lwa.model.inventory.Inventory
|
||||
import com.pixelized.shared.lwa.model.inventory.InventoryJson
|
||||
import com.pixelized.shared.lwa.model.inventory.InventoryJsonV1
|
||||
import com.pixelized.shared.lwa.protocol.rest.ApiPurseJson
|
||||
|
||||
class InventoryJsonFactory(
|
||||
private val v1: InventoryJsonFactoryV1,
|
||||
|
|
@ -16,4 +17,16 @@ class InventoryJsonFactory(
|
|||
fun convertToJson(inventory: Inventory): InventoryJson {
|
||||
return v1.convertToJson(inventory = inventory)
|
||||
}
|
||||
|
||||
fun convertToApiPurse(
|
||||
characterSheetId: String,
|
||||
purse: Inventory.Purse,
|
||||
): ApiPurseJson {
|
||||
return ApiPurseJson(
|
||||
characterSheetId = characterSheetId,
|
||||
gold = purse.gold,
|
||||
silver = purse.silver,
|
||||
copper = purse.copper,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.pixelized.shared.lwa.protocol.rest
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ApiPurseJson(
|
||||
val characterSheetId: String,
|
||||
val gold: Int,
|
||||
val silver: Int,
|
||||
val copper: Int,
|
||||
)
|
||||
|
|
@ -53,6 +53,16 @@ sealed interface ApiSynchronisation : SocketMessage {
|
|||
@Serializable
|
||||
sealed interface InventoryApiSynchronisation : ApiSynchronisation, CharacterSheetIdMessage
|
||||
|
||||
@Serializable
|
||||
data class PurseUpdate(
|
||||
override val timestamp: Long,
|
||||
override val characterSheetId: String,
|
||||
val add : Boolean,
|
||||
val gold: Int,
|
||||
val silver: Int,
|
||||
val copper: Int,
|
||||
) : InventoryApiSynchronisation
|
||||
|
||||
@Serializable
|
||||
data class InventoryUpdate(
|
||||
override val timestamp: Long,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue