Client : Error management

This commit is contained in:
Thomas Andres Gomez 2025-04-01 16:01:43 +02:00
parent d806048510
commit 1ebb7c1400
48 changed files with 630 additions and 473 deletions

View file

@ -1,5 +1,8 @@
package com.pixelized.desktop.lwa package com.pixelized.desktop.lwa
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.ButtonDefaults import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
@ -10,11 +13,13 @@ import androidx.compose.material.SnackbarDefaults
import androidx.compose.material.SnackbarDuration import androidx.compose.material.SnackbarDuration
import androidx.compose.material.SnackbarHost import androidx.compose.material.SnackbarHost
import androidx.compose.material.SnackbarHostState import androidx.compose.material.SnackbarHostState
import androidx.compose.material.Surface
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.TextButton import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
@ -146,7 +151,7 @@ private fun MainWindowScreen(
} }
LwaScaffold( LwaScaffold(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize()
) { ) {
MainNavHost() MainNavHost()

View file

@ -6,6 +6,7 @@ import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.network.NetworkRepository import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
import com.pixelized.desktop.lwa.repository.tag.TagRepository
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
@ -19,6 +20,7 @@ class DataSyncViewModel(
private val characterRepository: CharacterSheetRepository, private val characterRepository: CharacterSheetRepository,
private val alterationRepository: AlterationRepository, private val alterationRepository: AlterationRepository,
private val campaignRepository: CampaignRepository, private val campaignRepository: CampaignRepository,
private val tagRepository: TagRepository,
private val settingsRepository: SettingsRepository, private val settingsRepository: SettingsRepository,
private val networkRepository: NetworkRepository, private val networkRepository: NetworkRepository,
) : ViewModel() { ) : ViewModel() {
@ -40,10 +42,10 @@ class DataSyncViewModel(
networkRepository.status networkRepository.status
.filter { status -> status == NetworkRepository.Status.CONNECTED } .filter { status -> status == NetworkRepository.Status.CONNECTED }
.onEach { .onEach {
tagRepository.updateAlterationTags()
alterationRepository.updateAlterations() alterationRepository.updateAlterations()
alterationRepository.updateTags() tagRepository.updateCharacterTags()
characterRepository.updateCharacterPreviews() characterRepository.updateCharacterPreviews()
characterRepository.updateTags()
campaignRepository.updateCampaign() campaignRepository.updateCampaign()
} }
.launchIn(this) .launchIn(this)
@ -54,9 +56,8 @@ class DataSyncViewModel(
.distinctUntilChanged() .distinctUntilChanged()
.onEach { instances -> .onEach { instances ->
instances.forEach { characterSheetId -> instances.forEach { characterSheetId ->
characterRepository.characterDetail( characterRepository.updateCharacterSheet(
characterSheetId = characterSheetId, characterSheetId = characterSheetId,
forceUpdate = true,
) )
} }
} }

View file

@ -13,6 +13,8 @@ import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
import com.pixelized.desktop.lwa.repository.settings.SettingsFactory import com.pixelized.desktop.lwa.repository.settings.SettingsFactory
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
import com.pixelized.desktop.lwa.repository.settings.SettingsStore import com.pixelized.desktop.lwa.repository.settings.SettingsStore
import com.pixelized.desktop.lwa.repository.tag.TagRepository
import com.pixelized.desktop.lwa.repository.tag.TagStore
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogFactory import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogFactory
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogFactory import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogFactory
@ -37,9 +39,9 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillField
import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel
import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionViewModel import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionViewModel
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditFactory
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditViewModel
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.list.GMAlterationFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.list.GMAlterationFactory
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.list.GMAlterationViewModel import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.list.GMAlterationViewModel
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditViewModel
import com.pixelized.desktop.lwa.ui.screen.gamemaster.character.list.GMCharacterFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.character.list.GMCharacterFactory
import com.pixelized.desktop.lwa.ui.screen.gamemaster.character.list.GMCharacterViewModel import com.pixelized.desktop.lwa.ui.screen.gamemaster.character.list.GMCharacterViewModel
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory
@ -100,6 +102,7 @@ val storeDependencies
singleOf(::SettingsStore) singleOf(::SettingsStore)
singleOf(::AlterationStore) singleOf(::AlterationStore)
singleOf(::CampaignStore) singleOf(::CampaignStore)
singleOf(::TagStore)
} }
val repositoryDependencies val repositoryDependencies
@ -110,6 +113,7 @@ val repositoryDependencies
singleOf(::SettingsRepository) singleOf(::SettingsRepository)
singleOf(::AlterationRepository) singleOf(::AlterationRepository)
singleOf(::CampaignRepository) singleOf(::CampaignRepository)
singleOf(::TagRepository)
} }
val factoryDependencies val factoryDependencies

View file

@ -5,83 +5,89 @@ import com.pixelized.shared.lwa.model.campaign.CampaignJson
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.model.tag.TagJson import com.pixelized.shared.lwa.model.tag.TagJson
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
import com.pixelized.shared.lwa.protocol.rest.APIResponse
interface LwaClient { interface LwaClient {
// Alteration // Alteration
suspend fun alterations(): List<AlterationJson> suspend fun getAlterations(): APIResponse<List<AlterationJson>>
suspend fun alterations( suspend fun getAlteration(
alterationId: String, alterationId: String,
): AlterationJson? ): APIResponse<AlterationJson?>
suspend fun updateAlteration( suspend fun putAlteration(
alterationJson: AlterationJson alterationJson: AlterationJson,
) create: Boolean,
): APIResponse<Unit>
suspend fun deleteAlteration( suspend fun deleteAlteration(
alterationId: String, alterationId: String,
) ): APIResponse<Unit>
suspend fun alterationTags(): List<TagJson> suspend fun getAlterationTags(): APIResponse<List<TagJson>>
// Campaign // Campaign
suspend fun campaign(): CampaignJson suspend fun getCampaign(): APIResponse<CampaignJson>
suspend fun campaignAddCharacter( suspend fun putCampaignCharacter(
characterSheetId: String, characterSheetId: String,
) ): APIResponse<Unit>
suspend fun campaignRemoveCharacter( suspend fun removeCampaignCharacter(
characterSheetId: String, characterSheetId: String,
) ): APIResponse<Unit>
suspend fun campaignAddNpc( suspend fun putCampaignNpc(
characterSheetId: String, characterSheetId: String,
) ): APIResponse<Unit>
suspend fun campaignRemoveNpc( suspend fun removeCampaignNpc(
characterSheetId: String, characterSheetId: String,
) ): APIResponse<Unit>
// Character // Character
suspend fun characters(): List<CharacterPreviewJson> suspend fun getCharacters(): APIResponse<List<CharacterPreviewJson>>
suspend fun characterTags(): List<TagJson> suspend fun getCharacterTags(): APIResponse<List<TagJson>>
suspend fun character( suspend fun getCharacter(
characterSheetId: String, characterSheetId: String,
): CharacterSheetJson ): APIResponse<CharacterSheetJson>
suspend fun updateCharacter( suspend fun putCharacter(
sheet: CharacterSheetJson, sheet: CharacterSheetJson,
) ): APIResponse<Unit>
suspend fun updateCharacterDamage( suspend fun putCharacterDamage(
characterSheetId: String, characterSheetId: String,
damage: Int, damage: Int,
) ): APIResponse<Unit>
suspend fun updateCharacterFatigue( suspend fun putCharacterFatigue(
characterSheetId: String, characterSheetId: String,
fatigue: Int, fatigue: Int,
) ): APIResponse<Unit>
suspend fun updateCharacterDiminished( suspend fun putCharacterDiminished(
characterSheetId: String, characterSheetId: String,
diminished: Int, diminished: Int,
) ): APIResponse<Unit>
suspend fun updateCharacterAlteration( suspend fun putCharacterAlteration(
characterSheetId: String, characterSheetId: String,
alterationId: Int, alterationId: Int,
active: Boolean, active: Boolean,
) ): APIResponse<Unit>
suspend fun deleteCharacterSheet( suspend fun deleteCharacterSheet(
characterSheetId: String, characterSheetId: String,
) ): APIResponse<Unit>
companion object {
fun error(error: APIResponse<*>): Nothing = throw LwaNetworkException(error)
}
} }

View file

@ -5,6 +5,7 @@ import com.pixelized.shared.lwa.model.alteration.AlterationJson
import com.pixelized.shared.lwa.model.campaign.CampaignJson import com.pixelized.shared.lwa.model.campaign.CampaignJson
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.model.tag.TagJson import com.pixelized.shared.lwa.model.tag.TagJson
import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson import com.pixelized.shared.lwa.protocol.rest.CharacterPreviewJson
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.call.body import io.ktor.client.call.body
@ -21,114 +22,134 @@ class LwaClientImpl(
) : LwaClient { ) : LwaClient {
private val root = setting.settings().network.root private val root = setting.settings().network.root
override suspend fun alterations(): List<AlterationJson> = client @Throws
override suspend fun getAlterations(): APIResponse<List<AlterationJson>> = client
.get("$root/alteration/all") .get("$root/alteration/all")
.body() .body()
override suspend fun alterations( @Throws
override suspend fun getAlteration(
alterationId: String, alterationId: String,
): AlterationJson? = client ): APIResponse<AlterationJson?> = client
.get("$root/alteration/detail?alterationId=$alterationId") .get("$root/alteration/detail?alterationId=$alterationId")
.body() .body()
override suspend fun updateAlteration( @Throws
alterationJson: AlterationJson override suspend fun putAlteration(
alterationJson: AlterationJson,
create: Boolean,
) = client ) = client
.put("$root/alteration/update") { .put("$root/alteration/update?create=$create") {
contentType(ContentType.Application.Json) contentType(ContentType.Application.Json)
setBody(alterationJson) setBody(alterationJson)
} }
.body<Unit>() .body<APIResponse<Unit>>()
@Throws
override suspend fun deleteAlteration(alterationId: String) = client override suspend fun deleteAlteration(alterationId: String) = client
.delete("$root/alteration/delete?alterationId=$alterationId") .delete("$root/alteration/delete?alterationId=$alterationId")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun alterationTags(): List<TagJson> = client @Throws
override suspend fun getAlterationTags(): APIResponse<List<TagJson>> = client
.get("$root/alteration/tags") .get("$root/alteration/tags")
.body() .body()
override suspend fun campaign(): CampaignJson = client @Throws
override suspend fun getCampaign(): APIResponse<CampaignJson> = client
.get("$root/campaign") .get("$root/campaign")
.body() .body()
override suspend fun campaignAddCharacter( @Throws
override suspend fun putCampaignCharacter(
characterSheetId: String, characterSheetId: String,
) = client ) = client
.put("$root/campaign/character/add?characterSheetId=$characterSheetId") .put("$root/campaign/character/add?characterSheetId=$characterSheetId")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun campaignRemoveCharacter( @Throws
override suspend fun removeCampaignCharacter(
characterSheetId: String, characterSheetId: String,
) = client ) = client
.delete("$root/campaign/character/delete?characterSheetId=$characterSheetId") .delete("$root/campaign/character/delete?characterSheetId=$characterSheetId")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun campaignAddNpc( @Throws
override suspend fun putCampaignNpc(
characterSheetId: String, characterSheetId: String,
) = client ) = client
.put("$root/campaign/npc/add?characterSheetId=$characterSheetId") .put("$root/campaign/npc/add?characterSheetId=$characterSheetId")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun campaignRemoveNpc( @Throws
override suspend fun removeCampaignNpc(
characterSheetId: String, characterSheetId: String,
) = client ) = client
.delete("$root/campaign/npc/delete?characterSheetId=$characterSheetId") .delete("$root/campaign/npc/delete?characterSheetId=$characterSheetId")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun characters(): List<CharacterPreviewJson> = client @Throws
override suspend fun getCharacters(): APIResponse<List<CharacterPreviewJson>> = client
.get("$root/character/all") .get("$root/character/all")
.body() .body()
override suspend fun characterTags(): List<TagJson> = client @Throws
override suspend fun getCharacterTags(): APIResponse<List<TagJson>> = client
.get("$root/character/tags") .get("$root/character/tags")
.body() .body()
override suspend fun character( @Throws
override suspend fun getCharacter(
characterSheetId: String, characterSheetId: String,
): CharacterSheetJson = client ): APIResponse<CharacterSheetJson> = client
.get("$root/character/detail?characterSheetId=$characterSheetId") .get("$root/character/detail?characterSheetId=$characterSheetId")
.body() .body()
override suspend fun updateCharacter( @Throws
override suspend fun putCharacter(
sheet: CharacterSheetJson, sheet: CharacterSheetJson,
) = client ) = client
.put("$root/character/update/sheet") { .put("$root/character/update/sheet") {
contentType(ContentType.Application.Json) contentType(ContentType.Application.Json)
setBody(sheet) setBody(sheet)
} }
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun updateCharacterDamage( @Throws
override suspend fun putCharacterDamage(
characterSheetId: String, characterSheetId: String,
damage: Int, damage: Int,
) = client ) = client
.put("$root/character/update/damage?characterSheetId=$characterSheetId&damage=$damage") .put("$root/character/update/damage?characterSheetId=$characterSheetId&damage=$damage")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun updateCharacterFatigue( @Throws
override suspend fun putCharacterFatigue(
characterSheetId: String, characterSheetId: String,
fatigue: Int, fatigue: Int,
) = client ) = client
.put("$root/character/update/fatigue?characterSheetId=$characterSheetId&fatigue=$fatigue") .put("$root/character/update/fatigue?characterSheetId=$characterSheetId&fatigue=$fatigue")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun updateCharacterDiminished( @Throws
override suspend fun putCharacterDiminished(
characterSheetId: String, characterSheetId: String,
diminished: Int, diminished: Int,
) = client ) = client
.put("$root/character/update/diminished?characterSheetId=$characterSheetId&diminished=$diminished") .put("$root/character/update/diminished?characterSheetId=$characterSheetId&diminished=$diminished")
.body<Unit>() .body<APIResponse<Unit>>()
override suspend fun updateCharacterAlteration( @Throws
override suspend fun putCharacterAlteration(
characterSheetId: String, characterSheetId: String,
alterationId: Int, alterationId: Int,
active: Boolean, active: Boolean,
) = client ) = client
.put("$root/character/update/alteration?characterSheetId=$characterSheetId&alterationId=$alterationId&active=$active") .put("$root/character/update/alteration?characterSheetId=$characterSheetId&alterationId=$alterationId&active=$active")
.body<Unit>() .body<APIResponse<Unit>>()
@Throws
override suspend fun deleteCharacterSheet(characterSheetId: String) = client override suspend fun deleteCharacterSheet(characterSheetId: String) = client
.delete("$root/character/delete?characterSheetId=$characterSheetId") .delete("$root/character/delete?characterSheetId=$characterSheetId")
.body<Unit>() .body<APIResponse<Unit>>()
} }

View file

@ -0,0 +1,13 @@
package com.pixelized.desktop.lwa.network
import com.pixelized.shared.lwa.protocol.rest.APIResponse
class LwaNetworkException(
val status: Int,
message: String,
) : Exception(message) {
constructor(error: APIResponse<*>) : this(
status = error.status,
message = error.message ?: "An unknown error occurred"
)
}

View file

@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.stateIn
class AlterationRepository( class AlterationRepository(
private val alterationStore: AlterationStore, private val alterationStore: AlterationStore,
campaignRepository: CampaignRepository, campaignRepository: CampaignRepository,
characterRepository: CharacterSheetRepository, characterRepository: CharacterSheetRepository,
) { ) {
@ -26,8 +27,6 @@ class AlterationRepository(
val alterationFlow get() = alterationStore.alterationsFlow val alterationFlow get() = alterationStore.alterationsFlow
val tagsFlow get() = alterationStore.tagsFlow
/** /**
* This flow transform the campaign instance (player + npc) into a * This flow transform the campaign instance (player + npc) into a
* Map<CharacterSheetId, List<AlterationId>>. * Map<CharacterSheetId, List<AlterationId>>.
@ -66,11 +65,7 @@ class AlterationRepository(
) )
suspend fun updateAlterations() { suspend fun updateAlterations() {
alterationStore.updateAlterations() alterationStore.updateAlterationsFlow()
}
suspend fun updateTags() {
alterationStore.updateTags()
} }
fun alteration( fun alteration(
@ -91,10 +86,15 @@ class AlterationRepository(
return activeAlterationMapFlow.map { it[characterSheetId] ?: emptyMap() } return activeAlterationMapFlow.map { it[characterSheetId] ?: emptyMap() }
} }
@Throws
suspend fun updateAlteration( suspend fun updateAlteration(
alteration: Alteration alteration: Alteration,
create: Boolean,
) { ) {
alterationStore.putAlteration(alteration) alterationStore.putAlteration(
alteration = alteration,
create = create,
)
} }
suspend fun deleteAlteration( suspend fun deleteAlteration(

View file

@ -4,8 +4,6 @@ import com.pixelized.desktop.lwa.network.LwaClient
import com.pixelized.desktop.lwa.repository.network.NetworkRepository import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.shared.lwa.model.alteration.Alteration import com.pixelized.shared.lwa.model.alteration.Alteration
import com.pixelized.shared.lwa.model.alteration.AlterationJsonFactory import com.pixelized.shared.lwa.model.alteration.AlterationJsonFactory
import com.pixelized.shared.lwa.model.tag.Tag
import com.pixelized.shared.lwa.model.tag.TagJsonFactory
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -18,22 +16,14 @@ import kotlinx.coroutines.launch
class AlterationStore( class AlterationStore(
private val networkRepository: NetworkRepository, private val networkRepository: NetworkRepository,
private val alterationFactory: AlterationJsonFactory, private val factory: AlterationJsonFactory,
private val tagFactory: TagJsonFactory,
private val client: LwaClient, private val client: LwaClient,
) { ) {
private val _alterationsFlow = MutableStateFlow<Map<String, Alteration>>(emptyMap()) private val _alterationsFlow = MutableStateFlow<Map<String, Alteration>>(emptyMap())
val alterationsFlow: StateFlow<Map<String, Alteration>> = _alterationsFlow val alterationsFlow: StateFlow<Map<String, Alteration>> = _alterationsFlow
private val _tagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
val tagsFlow: StateFlow<Map<String, Tag>> = _tagsFlow
init { init {
val scope = CoroutineScope(Dispatchers.IO + Job()) val scope = CoroutineScope(Dispatchers.IO + Job())
scope.launch {
updateAlterations()
updateTags()
}
// data update through WebSocket. // data update through WebSocket.
scope.launch { scope.launch {
networkRepository.data.collect(::handleMessage) networkRepository.data.collect(::handleMessage)
@ -44,19 +34,11 @@ class AlterationStore(
return alterationsFlow.value.values return alterationsFlow.value.values
} }
fun tags(): Collection<Tag> {
return tagsFlow.value.values
}
fun alteration(alterationId: String): Alteration? { fun alteration(alterationId: String): Alteration? {
return alterationsFlow.value[alterationId] return alterationsFlow.value[alterationId]
} }
fun tag(tagId: String): Tag? { suspend fun updateAlterationsFlow() {
return tagsFlow.value[tagId]
}
suspend fun updateAlterations() {
_alterationsFlow.value = try { _alterationsFlow.value = try {
getAlteration() getAlteration()
} catch (exception: Exception) { } catch (exception: Exception) {
@ -65,7 +47,7 @@ class AlterationStore(
} }
} }
suspend fun updateAlteration( private suspend fun updateAlterationFlow(
alterationId: String, alterationId: String,
) { ) {
val alteration = try { val alteration = try {
@ -74,9 +56,9 @@ class AlterationStore(
println(exception.message) // TODO proper exception handling println(exception.message) // TODO proper exception handling
null null
} }
// guard case if getAlteration failed
if (alteration == null) return if (alteration == null) return
// update the flow with the alteration.
_alterationsFlow.update { alterations -> _alterationsFlow.update { alterations ->
alterations.toMutableMap().also { alterations.toMutableMap().also {
it[alterationId] = alteration it[alterationId] = alteration
@ -84,60 +66,59 @@ class AlterationStore(
} }
} }
suspend fun updateTags() {
_tagsFlow.value = try {
getAlterationTag()
} catch (exception: Exception) {
println(exception.message) // TODO proper exception handling
emptyMap()
}
}
@Throws @Throws
private suspend fun getAlteration(): Map<String, Alteration> { private suspend fun getAlteration(): Map<String, Alteration> {
val request = client.alterations() val request = client.getAlterations()
val data = request.map { alterationFactory.convertFromJson(json = it) } return when (request.success) {
return data.associateBy { it.id } true -> request.data
?.map { factory.convertFromJson(json = it) }
?.associateBy { it.id }
?: emptyMap()
else -> LwaClient.error(error = request)
}
} }
@Throws @Throws
private suspend fun getAlteration( private suspend fun getAlteration(
alterationId: String, alterationId: String,
): Alteration? { ): Alteration? {
val request = client.alterations(alterationId = alterationId) val request = client.getAlteration(alterationId = alterationId)
return request?.let { alterationFactory.convertFromJson(json = it) } return when (request.success) {
} true -> request.data?.let { factory.convertFromJson(json = it) }
else -> LwaClient.error(error = request)
@Throws }
private suspend fun getAlterationTag(): Map<String, Tag> {
val request = client.alterationTags()
val data = request.map { tagFactory.convertFromJson(json = it) }
return data.associateBy { it.id }
} }
@Throws @Throws
suspend fun putAlteration( suspend fun putAlteration(
alteration: Alteration, alteration: Alteration,
create: Boolean,
) { ) {
client.updateAlteration( val request = client.putAlteration(
alterationJson = alterationFactory.convertToJson(data = alteration) alterationJson = factory.convertToJson(data = alteration),
create = create,
) )
if (request.success.not()) {
LwaClient.error(error = request)
}
} }
@Throws @Throws
suspend fun deleteAlteration( suspend fun deleteAlteration(
alterationId: String alterationId: String,
) { ) {
client.deleteAlteration( val request = client.deleteAlteration(alterationId = alterationId)
alterationId = alterationId if (request.success.not()) {
) LwaClient.error(error = request)
}
} }
// region: WebSocket & data update. // region: WebSocket & data update.
private suspend fun handleMessage(message: SocketMessage) { private suspend fun handleMessage(message: SocketMessage) {
when (message) { when (message) {
is ApiSynchronisation.AlterationUpdate -> updateAlteration( is ApiSynchronisation.AlterationUpdate -> updateAlterationFlow(
alterationId = message.alterationId, alterationId = message.alterationId,
) )

View file

@ -3,33 +3,45 @@ package com.pixelized.desktop.lwa.repository.campaign
class CampaignRepository( class CampaignRepository(
private val store: CampaignStore, private val store: CampaignStore,
) { ) {
val campaignFlow get() = store.campaignFlow val campaignFlow = store.campaignFlow()
suspend fun updateCampaign() { suspend fun updateCampaign() {
store.campaign(update = true) store.updateCampaignFlow()
} }
@Throws
suspend fun addCharacter( suspend fun addCharacter(
characterSheetId: String, characterSheetId: String,
) = store.addCharacter( ) {
characterSheetId = characterSheetId, store.addCharacter(
) characterSheetId = characterSheetId,
)
}
@Throws
suspend fun removeCharacter( suspend fun removeCharacter(
characterSheetId: String, characterSheetId: String,
) = store.removeCharacter( ) {
characterSheetId = characterSheetId, store.removeCharacter(
) characterSheetId = characterSheetId,
)
}
@Throws
suspend fun addNpc( suspend fun addNpc(
characterSheetId: String, characterSheetId: String,
) = store.addNpc( ) {
characterSheetId = characterSheetId, store.addNpc(
) characterSheetId = characterSheetId,
)
}
@Throws
suspend fun removeNpc( suspend fun removeNpc(
characterSheetId: String, characterSheetId: String,
) = store.removeNpc( ) {
characterSheetId = characterSheetId, store.removeNpc(
) characterSheetId = characterSheetId,
)
}
} }

View file

@ -19,81 +19,76 @@ class CampaignStore(
private val client: LwaClient, private val client: LwaClient,
private val network: NetworkRepository, private val network: NetworkRepository,
private val factory: CampaignJsonFactory, private val factory: CampaignJsonFactory,
) {
) { private val campaignFlow = MutableStateFlow(value = Campaign.empty())
private val _campaignFlow = MutableStateFlow(value = Campaign.empty())
val campaignFlow: StateFlow<Campaign> get() = _campaignFlow
init { init {
val scope = CoroutineScope(Dispatchers.IO + Job()) val scope = CoroutineScope(Dispatchers.IO + Job())
scope.launch {
campaign(update = true)
}
scope.launch { scope.launch {
network.data.collect(::handleMessage) network.data.collect(::handleMessage)
} }
} }
suspend fun campaign(update: Boolean): Campaign { fun campaignFlow(): StateFlow<Campaign> = campaignFlow
val campaign = _campaignFlow.value
if (update || campaign == Campaign.empty()) { suspend fun updateCampaignFlow() {
val data = try { campaignFlow.value = try {
val request = client.campaign() getCampaign()
factory.convertFromJson(json = request) } catch (exception: Exception) {
} catch (exception: Exception) { println(exception.message) // TODO proper exception handling
println(exception) // TODO proper exception handling Campaign.empty()
Campaign.empty()
}
return _campaignFlow.update(data)
} }
return campaign
} }
@Throws
suspend fun addCharacter( suspend fun addCharacter(
characterSheetId: String, characterSheetId: String,
) { ) {
try { val request = client.putCampaignCharacter(characterSheetId = characterSheetId)
client.campaignAddCharacter( if (request.success.not()) {
characterSheetId = characterSheetId LwaClient.error(error = request)
)
} catch (exception: Exception) {
println(exception) // TODO proper exception handling
} }
} }
@Throws
suspend fun removeCharacter( suspend fun removeCharacter(
characterSheetId: String, characterSheetId: String,
) { ) {
try { val request = client.removeCampaignCharacter(characterSheetId = characterSheetId)
client.campaignRemoveCharacter( if (request.success.not()) {
characterSheetId = characterSheetId, LwaClient.error(error = request)
)
} catch (exception: Exception) {
println(exception) // TODO proper exception handling
} }
} }
@Throws
suspend fun addNpc( suspend fun addNpc(
characterSheetId: String, characterSheetId: String,
) { ) {
try { val request = client.putCampaignNpc(characterSheetId = characterSheetId)
client.campaignAddNpc( if (request.success.not()) {
characterSheetId = characterSheetId LwaClient.error(error = request)
)
} catch (exception: Exception) {
println(exception) // TODO proper exception handling
} }
} }
@Throws
suspend fun removeNpc( suspend fun removeNpc(
characterSheetId: String, characterSheetId: String,
) { ) {
try { val request = client.removeCampaignNpc(characterSheetId = characterSheetId)
client.campaignRemoveNpc( if (request.success.not()) {
characterSheetId = characterSheetId, LwaClient.error(error = request)
) }
} catch (exception: Exception) { }
println(exception) // TODO proper exception handling
@Throws
private suspend fun getCampaign(): Campaign {
val request = client.getCampaign()
return when (request.success) {
true -> request.data
?.let { factory.convertFromJson(json = it) }
?: Campaign.empty()
else -> LwaClient.error(error = request)
} }
} }
@ -103,7 +98,7 @@ class CampaignStore(
when (message) { when (message) {
is CampaignEvent -> { is CampaignEvent -> {
when (message) { when (message) {
is CampaignEvent.CharacterAdded -> _campaignFlow.update { campaign -> is CampaignEvent.CharacterAdded -> campaignFlow.update { campaign ->
campaign.copy( campaign.copy(
characters = campaign.characters.toMutableSet().also { characters = campaign.characters.toMutableSet().also {
it.add(message.characterSheetId) it.add(message.characterSheetId)
@ -111,7 +106,7 @@ class CampaignStore(
) )
} }
is CampaignEvent.CharacterRemoved -> _campaignFlow.update { campaign -> is CampaignEvent.CharacterRemoved -> campaignFlow.update { campaign ->
campaign.copy( campaign.copy(
characters = campaign.characters.toMutableSet().also { characters = campaign.characters.toMutableSet().also {
it.remove(message.characterSheetId) it.remove(message.characterSheetId)
@ -119,7 +114,7 @@ class CampaignStore(
) )
} }
is CampaignEvent.NpcAdded -> _campaignFlow.update { campaign -> is CampaignEvent.NpcAdded -> campaignFlow.update { campaign ->
campaign.copy( campaign.copy(
npcs = campaign.npcs.toMutableSet().also { npcs = campaign.npcs.toMutableSet().also {
it.add(message.characterSheetId) it.add(message.characterSheetId)
@ -127,7 +122,7 @@ class CampaignStore(
) )
} }
is CampaignEvent.NpcRemoved -> _campaignFlow.update { campaign -> is CampaignEvent.NpcRemoved -> campaignFlow.update { campaign ->
campaign.copy( campaign.copy(
npcs = campaign.npcs.toMutableSet().also { npcs = campaign.npcs.toMutableSet().also {
it.remove(message.characterSheetId) it.remove(message.characterSheetId)
@ -135,7 +130,7 @@ class CampaignStore(
) )
} }
is CampaignEvent.UpdateScene -> _campaignFlow.update { campaign -> is CampaignEvent.UpdateScene -> campaignFlow.update { campaign ->
campaign.copy( campaign.copy(
scene = Campaign.Scene(name = message.name) scene = Campaign.Scene(name = message.name)
) )
@ -145,17 +140,17 @@ class CampaignStore(
is GameMasterEvent -> when (message) { is GameMasterEvent -> when (message) {
is GameMasterEvent.ToggleNpc -> { is GameMasterEvent.ToggleNpc -> {
_campaignFlow.value = _campaignFlow.value.copy( campaignFlow.value = campaignFlow.value.copy(
options = _campaignFlow.value.options.copy( options = campaignFlow.value.options.copy(
showNpcs = _campaignFlow.value.options.showNpcs.not() showNpcs = campaignFlow.value.options.showNpcs.not()
) )
) )
} }
is GameMasterEvent.TogglePlayer -> { is GameMasterEvent.TogglePlayer -> {
_campaignFlow.value = _campaignFlow.value.copy( campaignFlow.value = campaignFlow.value.copy(
options = _campaignFlow.value.options.copy( options = campaignFlow.value.options.copy(
showParty = _campaignFlow.value.options.showParty.not() showParty = campaignFlow.value.options.showParty.not()
) )
) )
} }
@ -168,9 +163,4 @@ class CampaignStore(
} }
// endregion // endregion
private fun MutableStateFlow<Campaign>.update(campaign: Campaign): Campaign {
value = campaign
return campaign
}
} }

View file

@ -18,46 +18,27 @@ class CharacterSheetRepository(
val characterSheetPreviewFlow get() = store.previewFlow val characterSheetPreviewFlow get() = store.previewFlow
val characterDetailFlow get() = store.detailFlow
val tagsFlow get() = store.tagsFlow
suspend fun updateCharacterPreviews() { suspend fun updateCharacterPreviews() {
store.updateCharactersPreview() store.updateCharactersPreviewFlow()
} }
suspend fun updateTags() { suspend fun updateCharacterSheet(characterSheetId: String) {
store.updateTags() store.updateCharacterSheetDetailFlow(characterSheetId = characterSheetId)
} }
fun characterPreview(characterId: String?): CharacterSheetPreview? { fun characterPreview(characterId: String?): CharacterSheetPreview? {
return characterSheetPreviewFlow.value.firstOrNull { it.characterSheetId == characterId } return characterSheetPreviewFlow.value.firstOrNull { it.characterSheetId == characterId }
} }
suspend fun characterDetail( fun characterDetail(
characterSheetId: String?, characterSheetId: String?,
forceUpdate: Boolean = false,
): CharacterSheet? { ): CharacterSheet? {
return try { return store.detailFlow.value[characterSheetId]
characterSheetId?.let {
store.getCharacterSheet(
characterSheetId = it,
forceUpdate = forceUpdate
)
}
} catch (exception: Exception) {
null
}
} }
fun characterDetailFlow( fun characterDetailFlow(
characterSheetId: String?, characterSheetId: String?,
): StateFlow<CharacterSheet?> { ): StateFlow<CharacterSheet?> {
val initial = store.detailFlow.value[characterSheetId]
if (initial == null) {
scope.launch { characterDetail(characterSheetId = characterSheetId) }
}
return store.detailFlow return store.detailFlow
.map { sheets -> .map { sheets ->
sheets[characterSheetId] sheets[characterSheetId]
@ -65,16 +46,18 @@ class CharacterSheetRepository(
.stateIn( .stateIn(
scope = scope, scope = scope,
started = SharingStarted.Eagerly, started = SharingStarted.Eagerly,
initialValue = initial, initialValue = store.detailFlow.value[characterSheetId],
) )
} }
@Throws
suspend fun updateCharacter( suspend fun updateCharacter(
sheet: CharacterSheet, sheet: CharacterSheet,
) { ) {
store.updateCharacterSheet(sheet = sheet) store.updateCharacterSheet(sheet = sheet)
} }
@Throws
suspend fun deleteCharacter( suspend fun deleteCharacter(
characterSheetId: String, characterSheetId: String,
) { ) {

View file

@ -6,12 +6,9 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview
import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory
import com.pixelized.shared.lwa.model.tag.Tag
import com.pixelized.shared.lwa.model.tag.TagJsonFactory
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@ -25,7 +22,6 @@ class CharacterSheetStore(
private val client: LwaClient, private val client: LwaClient,
private val network: NetworkRepository, private val network: NetworkRepository,
private val factory: CharacterSheetJsonFactory, private val factory: CharacterSheetJsonFactory,
private val tagFactory: TagJsonFactory,
) { ) {
private val _previewFlow = MutableStateFlow<List<CharacterSheetPreview>>(value = emptyList()) private val _previewFlow = MutableStateFlow<List<CharacterSheetPreview>>(value = emptyList())
val previewFlow: StateFlow<List<CharacterSheetPreview>> get() = _previewFlow val previewFlow: StateFlow<List<CharacterSheetPreview>> get() = _previewFlow
@ -33,16 +29,8 @@ class CharacterSheetStore(
private val _detailFlow = MutableStateFlow<Map<String, CharacterSheet>>(value = emptyMap()) private val _detailFlow = MutableStateFlow<Map<String, CharacterSheet>>(value = emptyMap())
val detailFlow: StateFlow<Map<String, CharacterSheet>> get() = _detailFlow val detailFlow: StateFlow<Map<String, CharacterSheet>> get() = _detailFlow
private val _tagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
val tagsFlow: StateFlow<Map<String, Tag>> = _tagsFlow
init { init {
val scope = CoroutineScope(Dispatchers.IO + Job()) val scope = CoroutineScope(Dispatchers.IO + Job())
// initial data loading.
scope.launch {
updateCharactersPreview()
updateTags()
}
// data update through WebSocket. // data update through WebSocket.
scope.launch { scope.launch {
network.data.collect(::handleMessage) network.data.collect(::handleMessage)
@ -51,71 +39,75 @@ class CharacterSheetStore(
// region Rest // region Rest
suspend fun updateCharactersPreview(): List<CharacterSheetPreview> { suspend fun updateCharactersPreviewFlow() {
val request = try { _previewFlow.value = try {
client.characters() getCharacters()
} catch (exception: Exception) { } catch (exception: Exception) {
println(exception) // TODO proper exception handling println(exception.message) // TODO proper exception handling
emptyList() emptyList()
} }
val characters = request.map {
factory.convertFromJson(it)
}
return _previewFlow.update(characters)
} }
suspend fun updateTags(): Map<String, Tag> { suspend fun updateCharacterSheetDetailFlow(
val request = try {
client.characterTags()
} catch (exception: Exception) {
println(exception) // TODO proper exception handling
emptyList()
}
val tags = request.map {
tagFactory.convertFromJson(json = it)
}.associateBy { it.id }
_tagsFlow.value = tags
return tags
}
suspend fun getCharacterSheet(
characterSheetId: String, characterSheetId: String,
forceUpdate: Boolean = false, ) {
): CharacterSheet? { val characterSheet = try {
val character = _detailFlow.value[characterSheetId] getCharacterSheet(characterSheetId = characterSheetId)
if (forceUpdate || character == null) { } catch (exception: Exception) {
try { println(exception.message) // TODO proper exception handling
val request = client.character(characterSheetId = characterSheetId) null
val data = factory.convertFromJson(json = request) }
return _detailFlow.update(data) if (characterSheet == null) return
} catch (exception: Exception) { _detailFlow.update { data ->
println(exception) // TODO proper exception handling data.toMutableMap().also {
return null it[characterSheetId] = characterSheet
} }
} }
return character
} }
@Throws
suspend fun getCharacters(): List<CharacterSheetPreview> {
val request = client.getCharacters()
return when (request.success) {
true -> request.data
?.map { factory.convertFromJson(it) }
?: emptyList()
else -> LwaClient.error(error = request)
}
}
@Throws
suspend fun getCharacterSheet(
characterSheetId: String,
): CharacterSheet {
val request = client.getCharacter(characterSheetId = characterSheetId)
return when (request.success) {
true -> request.data!!.let { factory.convertFromJson(json = it) }
else -> LwaClient.error(error = request)
}
}
// TODO check crash
@Throws
suspend fun updateCharacterSheet( suspend fun updateCharacterSheet(
sheet: CharacterSheet, sheet: CharacterSheet,
) { ) {
val json = factory.convertToJson(sheet = sheet) val json = factory.convertToJson(sheet = sheet)
try { val request = client.putCharacter(sheet = json)
client.updateCharacter(sheet = json) if (request.success) {
} catch (exception: Exception) { LwaClient.error(error = request)
println(exception) // TODO
} }
_detailFlow.update(sheet = sheet)
} }
// TODO check crash
@Throws
suspend fun deleteCharacterSheet( suspend fun deleteCharacterSheet(
characterSheetId: String, characterSheetId: String,
) { ) {
try { val request = client.deleteCharacterSheet(characterSheetId = characterSheetId)
client.deleteCharacterSheet(characterSheetId = characterSheetId) if (request.success) {
} catch (exception: Exception) { LwaClient.error(error = request)
println(exception) // TODO
} }
} }
@ -124,32 +116,35 @@ class CharacterSheetStore(
private suspend fun handleMessage(message: SocketMessage) { private suspend fun handleMessage(message: SocketMessage) {
when (message) { when (message) {
is ApiSynchronisation -> when (message) { is ApiSynchronisation -> try {
is ApiSynchronisation.CharacterSheetUpdate -> { when (message) {
getCharacterSheet( is ApiSynchronisation.CharacterSheetUpdate -> {
characterSheetId = message.characterSheetId, _detailFlow.update(
forceUpdate = true, sheet = getCharacterSheet(characterSheetId = message.characterSheetId)
) )
if (_previewFlow.value.firstOrNull { it.characterSheetId == message.characterSheetId } == null) { if (_previewFlow.value.firstOrNull { it.characterSheetId == message.characterSheetId } == null) {
updateCharactersPreview() _previewFlow.value = getCharacters()
}
}
is ApiSynchronisation.CharacterSheetDelete -> {
_previewFlow.update { previews ->
previews.toMutableList().also { sheet ->
sheet.removeIf {
it.characterSheetId == message.characterSheetId
}
} }
} }
_detailFlow.update { sheets ->
sheets.toMutableMap().also { it.remove(message.characterSheetId) }
}
}
is ApiSynchronisation.AlterationUpdate -> Unit is ApiSynchronisation.CharacterSheetDelete -> {
is ApiSynchronisation.AlterationDelete -> Unit _previewFlow.update { previews ->
previews.toMutableList().also { sheet ->
sheet.removeIf {
it.characterSheetId == message.characterSheetId
}
}
}
_detailFlow.update { sheets ->
sheets.toMutableMap().also { it.remove(message.characterSheetId) }
}
}
is ApiSynchronisation.AlterationUpdate -> Unit
is ApiSynchronisation.AlterationDelete -> Unit
}
} catch (exception: Exception) {
println(exception.message) // TODO proper exception handling
} }
is CharacterSheetEvent -> when (message) { is CharacterSheetEvent -> when (message) {
@ -190,7 +185,7 @@ class CharacterSheetStore(
skillId: String, skillId: String,
used: Boolean, used: Boolean,
) { ) {
val sheet = getCharacterSheet(characterSheetId = characterSheetId) ?: return val sheet = getCharacterSheet(characterSheetId = characterSheetId)
val character = sheet.copy( val character = sheet.copy(
commonSkills = sheet.commonSkills.map { skill -> commonSkills = sheet.commonSkills.map { skill ->
skill.takeIf { skill.id == skillId }?.copy(used = used) ?: skill skill.takeIf { skill.id == skillId }?.copy(used = used) ?: skill
@ -211,7 +206,7 @@ class CharacterSheetStore(
active: Boolean, active: Boolean,
) { ) {
if (alterationStore.alteration(alterationId = alterationId) == null) return if (alterationStore.alteration(alterationId = alterationId) == null) return
val sheet = getCharacterSheet(characterSheetId = characterSheetId) ?: return val sheet = getCharacterSheet(characterSheetId = characterSheetId)
val containAlteration = sheet.alterations.contains(alterationId) val containAlteration = sheet.alterations.contains(alterationId)
@ -233,7 +228,7 @@ class CharacterSheetStore(
characterSheetId: String, characterSheetId: String,
damage: Int, damage: Int,
) { ) {
val sheet = getCharacterSheet(characterSheetId = characterSheetId) ?: return val sheet = getCharacterSheet(characterSheetId = characterSheetId)
_detailFlow.update(sheet.copy(damage = damage)) _detailFlow.update(sheet.copy(damage = damage))
} }
@ -241,7 +236,7 @@ class CharacterSheetStore(
characterSheetId: String, characterSheetId: String,
diminished: Int, diminished: Int,
) { ) {
val sheet = getCharacterSheet(characterSheetId = characterSheetId) ?: return val sheet = getCharacterSheet(characterSheetId = characterSheetId)
_detailFlow.update(sheet.copy(diminished = diminished)) _detailFlow.update(sheet.copy(diminished = diminished))
} }
@ -249,18 +244,12 @@ class CharacterSheetStore(
characterSheetId: String, characterSheetId: String,
fatigue: Int, fatigue: Int,
) { ) {
val sheet = getCharacterSheet(characterSheetId = characterSheetId) ?: return val sheet = getCharacterSheet(characterSheetId = characterSheetId)
_detailFlow.update(sheet.copy(fatigue = fatigue)) _detailFlow.update(sheet.copy(fatigue = fatigue))
} }
// endregion // endregion
private fun MutableStateFlow<List<CharacterSheetPreview>>.update(
previews: List<CharacterSheetPreview>,
): List<CharacterSheetPreview> {
value = previews
return previews
}
private fun MutableStateFlow<Map<String, CharacterSheet>>.update( private fun MutableStateFlow<Map<String, CharacterSheet>>.update(
sheet: CharacterSheet, sheet: CharacterSheet,

View file

@ -0,0 +1,16 @@
package com.pixelized.desktop.lwa.repository.tag
import com.pixelized.shared.lwa.model.tag.Tag
import kotlinx.coroutines.flow.StateFlow
class TagRepository(
private val store: TagStore,
) {
suspend fun updateCharacterTags() = store.updateCharacterTagsFlow()
suspend fun updateAlterationTags() = store.updateAlterationTagsFlow()
fun charactersTagFlow(): StateFlow<Map<String, Tag>> = store.charactersTagFlow()
fun alterationsTagFlow(): StateFlow<Map<String, Tag>> = store.alterationsTagFlow()
}

View file

@ -0,0 +1,79 @@
package com.pixelized.desktop.lwa.repository.tag
import com.pixelized.desktop.lwa.network.LwaClient
import com.pixelized.shared.lwa.model.tag.Tag
import com.pixelized.shared.lwa.model.tag.TagJsonFactory
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
class TagStore(
private val factory: TagJsonFactory,
private val client: LwaClient,
) {
private val characterTagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
private val alterationTagsFlow = MutableStateFlow<Map<String, Tag>>(emptyMap())
fun charactersTagFlow(): StateFlow<Map<String, Tag>> = characterTagsFlow
fun characters(): Collection<Tag> {
return characterTagsFlow.value.values
}
fun character(tagId: String): Tag? {
return characterTagsFlow.value[tagId]
}
fun alterationsTagFlow(): StateFlow<Map<String, Tag>> = alterationTagsFlow
fun alterations(): Collection<Tag> {
return alterationTagsFlow.value.values
}
fun alteration(tagId: String): Tag? {
return alterationTagsFlow.value[tagId]
}
suspend fun updateCharacterTagsFlow() {
characterTagsFlow.value = try {
getCharacterTag()
} catch (exception: Exception) {
println(exception.message) // TODO proper exception handling
emptyMap()
}
}
suspend fun updateAlterationTagsFlow() {
alterationTagsFlow.value = try {
getAlterationTag()
} catch (exception: Exception) {
println(exception.message) // TODO proper exception handling
emptyMap()
}
}
@Throws
private suspend fun getCharacterTag(): Map<String, Tag> {
val request = client.getCharacterTags()
return when (request.success) {
true -> request.data
?.map { factory.convertFromJson(json = it) }
?.associateBy { it.id }
?: emptyMap()
else -> LwaClient.error(error = request)
}
}
@Throws
private suspend fun getAlterationTag(): Map<String, Tag> {
val request = client.getAlterationTags()
return when (request.success) {
true -> request.data
?.map { factory.convertFromJson(json = it) }
?.associateBy { it.id }
?: emptyMap()
else -> LwaClient.error(error = request)
}
}
}

View file

@ -24,7 +24,7 @@ class ErrorSnackUio(
} }
@Composable @Composable
fun ErrorSnack( fun ErrorSnackHandler(
snack: SnackbarHostState = LocalErrorSnackHost.current, snack: SnackbarHostState = LocalErrorSnackHost.current,
error: SharedFlow<ErrorSnackUio>, error: SharedFlow<ErrorSnackUio>,
) { ) {

View file

@ -43,7 +43,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.LocalSnackHost import com.pixelized.desktop.lwa.LocalSnackHost
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnack import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.ui.theme.lwa
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.Res
@ -148,7 +148,7 @@ fun NetworkDialog(
} }
} }
ErrorSnack( ErrorSnackHandler(
error = viewModel.networkError, error = viewModel.networkError,
) )
} }

View file

@ -35,6 +35,7 @@ import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.type import androidx.compose.ui.input.key.type
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
@ -109,6 +110,10 @@ fun GMAlterationEditPage(
} }
} }
ErrorSnackHandler(
error = viewModel.error,
)
AlterationEditKeyHandler( AlterationEditKeyHandler(
onDismissRequest = { onDismissRequest = {
screen.popBackStack() screen.popBackStack()

View file

@ -4,8 +4,11 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.GMAlterationEditDestination import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.GMAlterationEditDestination
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -20,6 +23,9 @@ class GMAlterationEditViewModel(
private val _form = MutableStateFlow<GMAlterationEditPageUio?>(null) private val _form = MutableStateFlow<GMAlterationEditPageUio?>(null)
val form: StateFlow<GMAlterationEditPageUio?> get() = _form val form: StateFlow<GMAlterationEditPageUio?> get() = _form
private val _error = MutableSharedFlow<ErrorSnackUio>()
val error: SharedFlow<ErrorSnackUio> get() = _error
init { init {
viewModelScope.launch { viewModelScope.launch {
_form.value = factory.createForm( _form.value = factory.createForm(
@ -30,14 +36,22 @@ class GMAlterationEditViewModel(
suspend fun save() { suspend fun save() {
val edited = factory.createAlteration(form = form.value) val edited = factory.createAlteration(form = form.value)
val actual = alterationRepository.alterationFlow.value[edited?.id] val actual = alterationRepository.alterationFlow.value[edited?.id]
// TODO if argument.id == null et actual?.id != null on créer et on écrase existant !!! if (edited == null) return
if (edited != null) try {
if (argument.id == null && actual?.id != null) {
alterationRepository.updateAlteration(edited) error("Id already taken by an another alteration")
}
alterationRepository.updateAlteration(
alteration = edited,
create = argument.id == null,
)
} catch (exception: Exception) {
val message = ErrorSnackUio.from(exception = exception)
_error.emit(message)
}
} }
suspend fun addField() { suspend fun addField() {

View file

@ -3,6 +3,7 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.list
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
import com.pixelized.desktop.lwa.repository.tag.TagRepository
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagUio import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagUio
@ -22,6 +23,7 @@ import org.jetbrains.compose.resources.getString
class GMAlterationViewModel( class GMAlterationViewModel(
private val alterationRepository: AlterationRepository, private val alterationRepository: AlterationRepository,
alterationFactory: GMAlterationFactory, alterationFactory: GMAlterationFactory,
tagRepository: TagRepository,
tagFactory: GMTagFactory, tagFactory: GMTagFactory,
) : ViewModel() { ) : ViewModel() {
@ -38,7 +40,7 @@ class GMAlterationViewModel(
) )
val tags: StateFlow<List<GMTagUio>> = combine( val tags: StateFlow<List<GMTagUio>> = combine(
alterationRepository.tagsFlow, tagRepository.alterationsTagFlow(),
selectedTagId, selectedTagId,
) { tags, selectedTagId -> ) { tags, selectedTagId ->
tagFactory.convertToGMTagItemUio( tagFactory.convertToGMTagItemUio(
@ -53,7 +55,7 @@ class GMAlterationViewModel(
val alterations: StateFlow<List<GMAlterationUio>> = combine( val alterations: StateFlow<List<GMAlterationUio>> = combine(
alterationRepository.alterationFlow, alterationRepository.alterationFlow,
alterationRepository.tagsFlow, tagRepository.alterationsTagFlow(),
filter.valueFlow.map { it.unAccent() }, filter.valueFlow.map { it.unAccent() },
selectedTagId, selectedTagId,
) { alterations, tags, unAccentFilter, selectedTagId -> ) { alterations, tags, unAccentFilter, selectedTagId ->

View file

@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.network.NetworkRepository import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.tag.TagRepository
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
import com.pixelized.desktop.lwa.ui.screen.gamemaster.character.list.GMCharacterItemUio.Action import com.pixelized.desktop.lwa.ui.screen.gamemaster.character.list.GMCharacterItemUio.Action
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory
@ -27,6 +28,7 @@ class GMCharacterViewModel(
private val networkRepository: NetworkRepository, private val networkRepository: NetworkRepository,
private val campaignRepository: CampaignRepository, private val campaignRepository: CampaignRepository,
characterSheetRepository: CharacterSheetRepository, characterSheetRepository: CharacterSheetRepository,
tagRepository: TagRepository,
private val factory: GMCharacterFactory, private val factory: GMCharacterFactory,
private val tagFactory: GMTagFactory, private val tagFactory: GMTagFactory,
) : ViewModel() { ) : ViewModel() {
@ -44,7 +46,7 @@ class GMCharacterViewModel(
) )
val tags = combine( val tags = combine(
characterSheetRepository.tagsFlow, tagRepository.charactersTagFlow(),
selectedTagId, selectedTagId,
) { tags, selectedTagId -> ) { tags, selectedTagId ->
tagFactory.convertToGMTagItemUio( tagFactory.convertToGMTagItemUio(

View file

@ -39,7 +39,7 @@ class AlterationStore(
alterationFlow.value = try { alterationFlow.value = try {
load() load()
} catch (exception: Exception) { } catch (exception: Exception) {
println(exception) // TODO proper exception handling println(exception.message) // TODO proper exception handling
emptyList() emptyList()
} }
} }

View file

@ -38,7 +38,7 @@ class CampaignStore(
campaignFlow.value = try { campaignFlow.value = try {
load() load()
} catch (exception: Exception) { } catch (exception: Exception) {
println(exception) // TODO proper exception handling println(exception.message) // TODO proper exception handling
Campaign.empty() Campaign.empty()
} }
} }

View file

@ -38,7 +38,7 @@ class CharacterSheetStore(
characterSheetsFlow.value = try { characterSheetsFlow.value = try {
load() load()
} catch (exception: Exception) { } catch (exception: Exception) {
println(exception) // TODO proper exception handling println(exception.message) // TODO proper exception handling
emptyList() emptyList()
} }
} }

View file

@ -49,7 +49,7 @@ class TagStore(
flow.value = try { flow.value = try {
file.readTags().associateBy { it.id } file.readTags().associateBy { it.id }
} catch (exception: Exception) { } catch (exception: Exception) {
println(exception) // TODO proper exception handling println(exception.message) // TODO proper exception handling
emptyMap() emptyMap()
} }
} }

View file

@ -24,7 +24,7 @@ class Engine(
try { try {
unSafeHandle(message) unSafeHandle(message)
} catch (exception: Exception) { } catch (exception: Exception) {
println(exception) // TODO proper exception handling println(exception.message) // TODO proper exception handling
} }
} }

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.alteration
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.alterationId import com.pixelized.server.lwa.utils.extentions.alterationId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -19,7 +19,7 @@ fun Engine.deleteAlteration(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = ApiSynchronisation.AlterationDelete( value = ApiSynchronisation.AlterationDelete(
@ -29,15 +29,15 @@ fun Engine.deleteAlteration(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -2,7 +2,7 @@ package com.pixelized.server.lwa.server.rest.alteration
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.alterationId import com.pixelized.server.lwa.utils.extentions.alterationId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -17,12 +17,14 @@ fun Engine.getAlteration(): suspend RoutingContext.() -> Unit {
?: error("Alteration with id:$alterationId not found.") ?: error("Alteration with id:$alterationId not found.")
// send it back to the user. // send it back to the user.
call.respond( call.respond(
message = alteration, message = APIResponse.success(
data = alteration
)
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -1,7 +1,7 @@
package com.pixelized.server.lwa.server.rest.alteration package com.pixelized.server.lwa.server.rest.alteration
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -9,12 +9,14 @@ fun Engine.getAlterationTags(): suspend RoutingContext.() -> Unit {
return { return {
try { try {
call.respond( call.respond(
message = alterationService.tags(), message = APIResponse.success(
data = alterationService.tags(),
),
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -1,7 +1,7 @@
package com.pixelized.server.lwa.server.rest.alteration package com.pixelized.server.lwa.server.rest.alteration
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -9,12 +9,14 @@ fun Engine.getAlterations(): suspend RoutingContext.() -> Unit {
return { return {
try { try {
call.respond( call.respond(
message = alterationService.alterations(), message = APIResponse.success(
data = alterationService.alterations(),
)
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -4,7 +4,7 @@ import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.create import com.pixelized.server.lwa.utils.extentions.create
import com.pixelized.shared.lwa.model.alteration.AlterationJson import com.pixelized.shared.lwa.model.alteration.AlterationJson
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import io.ktor.server.request.receive import io.ktor.server.request.receive
import io.ktor.server.response.respond import io.ktor.server.response.respond
@ -21,7 +21,7 @@ fun Engine.putAlteration(): suspend RoutingContext.() -> Unit {
create = create, create = create,
) )
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = ApiSynchronisation.AlterationUpdate( value = ApiSynchronisation.AlterationUpdate(
@ -31,15 +31,15 @@ fun Engine.putAlteration(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -19,7 +19,7 @@ fun Engine.removeCampaignCharacter(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses // API & WebSocket responses
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = CampaignEvent.CharacterRemoved( value = CampaignEvent.CharacterRemoved(
@ -29,15 +29,15 @@ fun Engine.removeCampaignCharacter(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -19,7 +19,7 @@ fun Engine.removeCampaignNpc(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses // API & WebSocket responses
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = CampaignEvent.NpcRemoved( value = CampaignEvent.NpcRemoved(
@ -29,15 +29,15 @@ fun Engine.removeCampaignNpc(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -1,7 +1,7 @@
package com.pixelized.server.lwa.server.rest.campaign package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -9,12 +9,14 @@ fun Engine.getCampaign(): suspend RoutingContext.() -> Unit {
return { return {
try { try {
call.respond( call.respond(
message = campaignService.campaignJson(), message = APIResponse.success(
data = campaignService.campaignJson(),
),
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -19,7 +19,7 @@ fun Engine.putCampaignCharacter(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = CampaignEvent.CharacterAdded( value = CampaignEvent.CharacterAdded(
@ -29,15 +29,15 @@ fun Engine.putCampaignCharacter(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -19,7 +19,7 @@ fun Engine.putCampaignNpc(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = CampaignEvent.NpcAdded( value = CampaignEvent.NpcAdded(
@ -29,15 +29,15 @@ fun Engine.putCampaignNpc(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.campaign
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV2 import com.pixelized.shared.lwa.model.campaign.CampaignJsonV2
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import io.ktor.server.request.receive import io.ktor.server.request.receive
import io.ktor.server.response.respond import io.ktor.server.response.respond
@ -17,10 +17,12 @@ fun Engine.putCampaignScene(): suspend RoutingContext.() -> Unit {
// convert the scene into the a usable data model. // convert the scene into the a usable data model.
val scene = campaignJsonFactory.convertFromJson(json = form) val scene = campaignJsonFactory.convertFromJson(json = form)
// update the campaign. // update the campaign.
campaignService.setScene(scene = scene) campaignService.setScene(
scene = scene,
)
// API & WebSocket responses // API & WebSocket responses
call.respond( call.respond(
message = ResultJson.Success(), message = APIResponse.success(),
) )
webSocket.emit( webSocket.emit(
value = CampaignEvent.UpdateScene( value = CampaignEvent.UpdateScene(
@ -30,15 +32,15 @@ fun Engine.putCampaignScene(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -19,7 +19,7 @@ fun Engine.deleteCharacter(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success() message = APIResponse.success()
) )
webSocket.emit( webSocket.emit(
value = ApiSynchronisation.CharacterSheetDelete( value = ApiSynchronisation.CharacterSheetDelete(
@ -29,15 +29,15 @@ fun Engine.deleteCharacter(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -18,19 +18,21 @@ fun Engine.getCharacter(): suspend RoutingContext.() -> Unit {
?: error("CharacterSheet with id:$characterSheetId not found.") ?: error("CharacterSheet with id:$characterSheetId not found.")
// send it back to the user. // send it back to the user.
call.respond( call.respond(
message = characterSheet, message = APIResponse.success(
data = characterSheet,
),
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -1,7 +1,7 @@
package com.pixelized.server.lwa.server.rest.character package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -9,12 +9,14 @@ fun Engine.getCharacterTags(): suspend RoutingContext.() -> Unit {
return { return {
try { try {
call.respond( call.respond(
message = characterService.tags(), message = APIResponse.success(
data = characterService.tags(),
),
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -1,7 +1,7 @@
package com.pixelized.server.lwa.server.rest.character package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -9,12 +9,14 @@ fun Engine.getCharacters(): suspend RoutingContext.() -> Unit {
return { return {
try { try {
call.respond( call.respond(
message = characterService.charactersJson(), message = APIResponse.success(
data = characterService.charactersJson(),
),
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -4,7 +4,7 @@ import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.create import com.pixelized.server.lwa.utils.extentions.create
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import io.ktor.server.request.receive import io.ktor.server.request.receive
import io.ktor.server.response.respond import io.ktor.server.response.respond
@ -20,7 +20,7 @@ fun Engine.putCharacter(): suspend RoutingContext.() -> Unit {
create = create, create = create,
) )
call.respond( call.respond(
message = ResultJson.Success() message = APIResponse.success()
) )
webSocket.emit( webSocket.emit(
value = ApiSynchronisation.CharacterSheetUpdate( value = ApiSynchronisation.CharacterSheetUpdate(
@ -30,15 +30,15 @@ fun Engine.putCharacter(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -5,7 +5,7 @@ import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.active import com.pixelized.server.lwa.utils.extentions.active
import com.pixelized.server.lwa.utils.extentions.alterationId import com.pixelized.server.lwa.utils.extentions.alterationId
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -25,7 +25,7 @@ fun Engine.putCharacterAlteration(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success() message = APIResponse.success()
) )
webSocket.emit( webSocket.emit(
value = CharacterSheetEvent.UpdateAlteration( value = CharacterSheetEvent.UpdateAlteration(
@ -37,15 +37,15 @@ fun Engine.putCharacterAlteration(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -16,7 +16,7 @@ fun Engine.putCharacterDamage(): suspend RoutingContext.() -> Unit {
val damage = call.queryParameters["damage"]?.toIntOrNull() val damage = call.queryParameters["damage"]?.toIntOrNull()
?: throw MissingParameterException( ?: throw MissingParameterException(
name = "damage", name = "damage",
errorCode = ResultJson.Error.MISSING_DAMAGE errorCode = APIResponse.MISSING_DAMAGE
) )
// fetch the character sheet // fetch the character sheet
val characterSheet = characterService.character(characterSheetId) val characterSheet = characterService.character(characterSheetId)
@ -28,7 +28,7 @@ fun Engine.putCharacterDamage(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success() message = APIResponse.success()
) )
webSocket.emit( webSocket.emit(
value = CharacterSheetEvent.UpdateDamage( value = CharacterSheetEvent.UpdateDamage(
@ -40,15 +40,15 @@ fun Engine.putCharacterDamage(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -16,7 +16,7 @@ fun Engine.putCharacterDiminished(): suspend RoutingContext.() -> Unit {
val diminished = call.queryParameters["diminished"]?.toIntOrNull() val diminished = call.queryParameters["diminished"]?.toIntOrNull()
?: throw MissingParameterException( ?: throw MissingParameterException(
name = "diminished", name = "diminished",
errorCode = ResultJson.Error.MISSING_DIMINISHED errorCode = APIResponse.MISSING_DIMINISHED
) )
// Update the character damage // Update the character damage
characterService.updateDiminished( characterService.updateDiminished(
@ -25,7 +25,7 @@ fun Engine.putCharacterDiminished(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success() message = APIResponse.success()
) )
webSocket.emit( webSocket.emit(
value = CharacterSheetEvent.UpdateDiminished( value = CharacterSheetEvent.UpdateDiminished(
@ -36,15 +36,15 @@ fun Engine.putCharacterDiminished(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -3,7 +3,7 @@ package com.pixelized.server.lwa.server.rest.character
import com.pixelized.server.lwa.server.Engine import com.pixelized.server.lwa.server.Engine
import com.pixelized.server.lwa.utils.extentions.MissingParameterException import com.pixelized.server.lwa.utils.extentions.MissingParameterException
import com.pixelized.server.lwa.utils.extentions.characterSheetId import com.pixelized.server.lwa.utils.extentions.characterSheetId
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
import io.ktor.server.response.respond import io.ktor.server.response.respond
import io.ktor.server.routing.RoutingContext import io.ktor.server.routing.RoutingContext
@ -16,7 +16,7 @@ fun Engine.putCharacterFatigue(): suspend RoutingContext.() -> Unit {
val fatigue = call.queryParameters["fatigue"]?.toIntOrNull() val fatigue = call.queryParameters["fatigue"]?.toIntOrNull()
?: throw MissingParameterException( ?: throw MissingParameterException(
name = "fatigue", name = "fatigue",
errorCode = ResultJson.Error.MISSING_FATIGUE errorCode = APIResponse.MISSING_FATIGUE
) )
// fetch the character sheet // fetch the character sheet
val characterSheet = characterService.character(characterSheetId) val characterSheet = characterService.character(characterSheetId)
@ -28,7 +28,7 @@ fun Engine.putCharacterFatigue(): suspend RoutingContext.() -> Unit {
) )
// API & WebSocket responses. // API & WebSocket responses.
call.respond( call.respond(
message = ResultJson.Success() message = APIResponse.success()
) )
webSocket.emit( webSocket.emit(
value = CharacterSheetEvent.UpdateFatigue( value = CharacterSheetEvent.UpdateFatigue(
@ -40,15 +40,15 @@ fun Engine.putCharacterFatigue(): suspend RoutingContext.() -> Unit {
) )
} catch (exception: MissingParameterException) { } catch (exception: MissingParameterException) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = exception.errorCode, status = exception.errorCode,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )
} catch (exception: Exception) { } catch (exception: Exception) {
call.respond( call.respond(
message = ResultJson.Error( message = APIResponse.error(
status = ResultJson.Error.GENERIC, status = APIResponse.GENERIC,
message = exception.message ?: "?", message = exception.message ?: "?",
) )
) )

View file

@ -1,13 +1,13 @@
package com.pixelized.server.lwa.utils.extentions package com.pixelized.server.lwa.utils.extentions
import com.pixelized.shared.lwa.protocol.rest.ResultJson import com.pixelized.shared.lwa.protocol.rest.APIResponse
import io.ktor.http.Parameters import io.ktor.http.Parameters
val Parameters.characterSheetId val Parameters.characterSheetId
get() = "characterSheetId".let { param -> get() = "characterSheetId".let { param ->
this[param] ?: throw MissingParameterException( this[param] ?: throw MissingParameterException(
name = param, name = param,
errorCode = ResultJson.Error.MISSING_CHARACTER_SHEET_ID, errorCode = APIResponse.MISSING_CHARACTER_SHEET_ID,
) )
} }
@ -15,7 +15,7 @@ val Parameters.alterationId
get() = "alterationId".let { param -> get() = "alterationId".let { param ->
this[param] ?: throw MissingParameterException( this[param] ?: throw MissingParameterException(
name = param, name = param,
errorCode = ResultJson.Error.MISSING_ALTERATION_ID, errorCode = APIResponse.MISSING_ALTERATION_ID,
) )
} }
@ -23,7 +23,7 @@ val Parameters.create
get() = "create".let { param -> get() = "create".let { param ->
this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException( this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException(
name = param, name = param,
errorCode = ResultJson.Error.MISSING_CREATE errorCode = APIResponse.MISSING_CREATE
) )
} }
@ -31,7 +31,7 @@ val Parameters.active
get() = "active".let { param -> get() = "active".let { param ->
this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException( this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException(
name = param, name = param,
errorCode = ResultJson.Error.MISSING_ACTIVE errorCode = APIResponse.MISSING_ACTIVE
) )
} }

View file

@ -0,0 +1,52 @@
package com.pixelized.shared.lwa.protocol.rest
import kotlinx.serialization.Serializable
@Serializable
data class APIResponse<T>(
val success: Boolean,
val status: Int,
val message: String?,
val data: T?,
) {
companion object {
const val SUCCESS = 100
const val GENERIC = 600
const val MISSING_PARAMETER = 700
const val MISSING_CHARACTER_SHEET_ID = MISSING_PARAMETER + 1
const val MISSING_ALTERATION_ID = MISSING_PARAMETER + 2
const val MISSING_CREATE = MISSING_PARAMETER + 3
const val MISSING_ACTIVE = MISSING_PARAMETER + 4
const val MISSING_DAMAGE = MISSING_PARAMETER + 5
const val MISSING_FATIGUE = MISSING_PARAMETER + 6
const val MISSING_DIMINISHED = MISSING_PARAMETER + 7
fun error(
status: Int,
message: String?,
) = APIResponse(
success = false,
status = status,
message = message,
data = null,
)
fun success() = APIResponse(
success = true,
status = SUCCESS,
message = null,
data = null,
)
inline fun <reified T> success(
data: T? = null,
) = APIResponse(
success = true,
status = SUCCESS,
message = null,
data = data,
)
}
}

View file

@ -1,34 +0,0 @@
package com.pixelized.shared.lwa.protocol.rest
import kotlinx.serialization.Serializable
@Serializable
sealed interface ResultJson {
val success: Boolean
@Serializable
data class Error(
override val success: Boolean = false,
val status: Int,
val message: String,
) : ResultJson {
companion object {
const val GENERIC = 600
const val MISSING_PARAMETER = 700
const val MISSING_CHARACTER_SHEET_ID = MISSING_PARAMETER + 1
const val MISSING_ALTERATION_ID = MISSING_PARAMETER + 2
const val MISSING_CREATE = MISSING_PARAMETER + 3
const val MISSING_ACTIVE = MISSING_PARAMETER + 4
const val MISSING_DAMAGE = MISSING_PARAMETER + 5
const val MISSING_FATIGUE = MISSING_PARAMETER + 6
const val MISSING_DIMINISHED = MISSING_PARAMETER + 7
}
}
@Serializable
data class Success(
override val success: Boolean = true,
val status: Int = 100,
) : ResultJson
}