Add specific alteration error management.
This commit is contained in:
parent
6213d5ac15
commit
f94a530621
48 changed files with 606 additions and 511 deletions
|
|
@ -242,6 +242,7 @@
|
|||
<string name="game_master__character_action__add_to_npc">Ajouter aux Npcs</string>
|
||||
<string name="game_master__character_action__remove_from_npc">Retirer des Npcs</string>
|
||||
<string name="game_master__create_character_sheet">Créer un personnage</string>
|
||||
<string name="game_master__alteration__title">Édition d'Altération</string>
|
||||
<string name="game_master__alteration__filter">Filtrer par nom :</string>
|
||||
<string name="game_master__alteration__create">Créer une altération</string>
|
||||
<string name="game_master__alteration__delete">Supprimer l'altération</string>
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@ import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
|||
|
||||
class LwaNetworkException(
|
||||
val status: Int,
|
||||
val code: APIResponse.ErrorCode?,
|
||||
message: String,
|
||||
) : Exception(message) {
|
||||
constructor(error: APIResponse<*>) : this(
|
||||
status = error.status,
|
||||
code = error.code,
|
||||
message = error.message ?: "An unknown error occurred"
|
||||
)
|
||||
}
|
||||
|
|
@ -7,6 +7,10 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.Stable
|
||||
import com.pixelized.desktop.lwa.LocalErrorSnackHost
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.error__default__action
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
@Stable
|
||||
class ErrorSnackUio(
|
||||
|
|
@ -15,10 +19,10 @@ class ErrorSnackUio(
|
|||
val duration: SnackbarDuration,
|
||||
) {
|
||||
companion object {
|
||||
fun from(exception: Exception) = ErrorSnackUio(
|
||||
suspend fun from(exception: Exception) = ErrorSnackUio(
|
||||
message = exception.localizedMessage,
|
||||
action = "Ok",
|
||||
duration = SnackbarDuration.Indefinite
|
||||
action = getString(Res.string.error__default__action),
|
||||
duration = SnackbarDuration.Long,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +33,7 @@ fun ErrorSnackHandler(
|
|||
error: SharedFlow<ErrorSnackUio>,
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
error.collect {
|
||||
error.collectLatest {
|
||||
snack.showSnackbar(
|
||||
message = it.message,
|
||||
actionLabel = it.action,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.desktop.lwa.ui.composable.textfield
|
||||
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldColors
|
||||
|
|
@ -9,20 +10,21 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaTextFieldColors
|
||||
import com.pixelized.desktop.lwa.utils.rememberKeyboardActions
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
@Stable
|
||||
data class LwaTextFieldUio(
|
||||
val enable: Boolean = true,
|
||||
val isError: StateFlow<Boolean>,
|
||||
val labelFlow: StateFlow<String?>?,
|
||||
val valueFlow: StateFlow<String>,
|
||||
val placeHolderFlow: StateFlow<String?>?,
|
||||
val isError: MutableStateFlow<Boolean>,
|
||||
val labelFlow: MutableStateFlow<String?>?,
|
||||
val valueFlow: MutableStateFlow<String>,
|
||||
val placeHolderFlow: MutableStateFlow<String?>?,
|
||||
val onValueChange: (String) -> Unit,
|
||||
)
|
||||
|
||||
|
|
@ -30,6 +32,7 @@ data class LwaTextFieldUio(
|
|||
fun LwaTextField(
|
||||
modifier: Modifier = Modifier,
|
||||
colors: TextFieldColors = LwaTextFieldColors(),
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
leadingIcon: @Composable (() -> Unit)? = null,
|
||||
trailingIcon: @Composable (() -> Unit)? = null,
|
||||
singleLine: Boolean = true,
|
||||
|
|
@ -51,6 +54,7 @@ fun LwaTextField(
|
|||
TextField(
|
||||
modifier = localModifier.then(other = modifier),
|
||||
colors = colors,
|
||||
shape = shape,
|
||||
keyboardActions = rememberKeyboardActions {
|
||||
focus.moveFocus(FocusDirection.Next)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.navigation.NavHostController
|
|||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditPage
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditScreen
|
||||
import com.pixelized.desktop.lwa.utils.extention.ARG
|
||||
|
||||
@Stable
|
||||
|
|
@ -44,7 +44,7 @@ fun NavGraphBuilder.composableGameMasterAlterationEditPage() {
|
|||
route = GMAlterationEditDestination.baseRoute(),
|
||||
arguments = GMAlterationEditDestination.arguments(),
|
||||
) {
|
||||
GMAlterationEditPage()
|
||||
GMAlterationEditScreen()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,34 +1,39 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit
|
||||
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagFactory
|
||||
import com.pixelized.shared.lwa.model.alteration.Alteration
|
||||
import com.pixelized.shared.lwa.model.tag.Tag
|
||||
import com.pixelized.shared.lwa.parser.expression.ExpressionParser
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_description
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_expression
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_id
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_id
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_label
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_description
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_tags
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import java.util.UUID
|
||||
|
||||
class GMAlterationEditFactory(
|
||||
private val expressionParser: ExpressionParser,
|
||||
private val tagFactory: GMTagFactory,
|
||||
) {
|
||||
suspend fun createForm(
|
||||
originId: String?,
|
||||
alteration: Alteration?,
|
||||
tags: Collection<Tag>,
|
||||
): GMAlterationEditPageUio {
|
||||
val id = MutableStateFlow(alteration?.id ?: "")
|
||||
val label = MutableStateFlow(alteration?.metadata?.name ?: "")
|
||||
val description = MutableStateFlow(alteration?.metadata?.description ?: "")
|
||||
val tags = MutableStateFlow(alteration?.tags?.joinToString(", ") { it } ?: "")
|
||||
val fields = MutableStateFlow(alteration?.fields?.map { createField(it) } ?: listOf(createField(null)))
|
||||
val fields = MutableStateFlow(alteration?.fields?.map { createField(it) } ?: listOf(
|
||||
createField(null)
|
||||
))
|
||||
|
||||
return GMAlterationEditPageUio(
|
||||
id = LwaTextFieldUio(
|
||||
enable = true,
|
||||
enable = originId == null,
|
||||
isError = MutableStateFlow(false),
|
||||
labelFlow = MutableStateFlow(getString(Res.string.game_master__alteration__edit_id)),
|
||||
valueFlow = id,
|
||||
|
|
@ -51,13 +56,9 @@ class GMAlterationEditFactory(
|
|||
placeHolderFlow = null,
|
||||
onValueChange = { description.value = it },
|
||||
),
|
||||
tags = LwaTextFieldUio(
|
||||
enable = true,
|
||||
isError = MutableStateFlow(false),
|
||||
labelFlow = MutableStateFlow(getString(Res.string.game_master__alteration__edit_tags)),
|
||||
valueFlow = tags,
|
||||
placeHolderFlow = null,
|
||||
onValueChange = { tags.value = it },
|
||||
tags = tagFactory.convertToGMTagItemUio(
|
||||
tags = tags,
|
||||
selectedTagIds = alteration?.tags ?: emptyList(),
|
||||
),
|
||||
fields = fields,
|
||||
)
|
||||
|
|
@ -101,7 +102,7 @@ class GMAlterationEditFactory(
|
|||
name = form.label.valueFlow.value,
|
||||
description = form.description.valueFlow.value,
|
||||
),
|
||||
tags = form.tags.valueFlow.value.split(","),
|
||||
tags = form.tags.filter { it.highlight }.map { it.id },
|
||||
fields = form.fields.value.mapNotNull { field ->
|
||||
expressionParser.parse(input = field.expression.valueFlow.value)?.let {
|
||||
Alteration.Field(
|
||||
|
|
|
|||
|
|
@ -1,9 +1,16 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.draggable
|
||||
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||
import androidx.compose.foundation.gestures.scrollBy
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
|
@ -11,21 +18,31 @@ import androidx.compose.foundation.layout.PaddingValues
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -34,21 +51,27 @@ import androidx.compose.ui.input.key.Key
|
|||
import androidx.compose.ui.input.key.KeyEventType
|
||||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.navigation.NavHostController
|
||||
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.textfield.LwaTextField
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.LocalGMScreenController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.GMAlterationEditDestination
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagButton
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_add_field
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_cancel
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_save
|
||||
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__title
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_save_24dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
|
@ -59,7 +82,7 @@ data class GMAlterationEditPageUio(
|
|||
val id: LwaTextFieldUio,
|
||||
val label: LwaTextFieldUio,
|
||||
val description: LwaTextFieldUio,
|
||||
val tags: LwaTextFieldUio,
|
||||
val tags: List<GMTagUio>,
|
||||
val fields: MutableStateFlow<List<SkillUio>>,
|
||||
) {
|
||||
@Stable
|
||||
|
|
@ -76,40 +99,37 @@ object GMAlterationEditPageDefault {
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun GMAlterationEditPage(
|
||||
fun GMAlterationEditScreen(
|
||||
viewModel: GMAlterationEditViewModel = koinViewModel(),
|
||||
) {
|
||||
val screen = LocalScreenController.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val form = viewModel.form.collectAsState()
|
||||
|
||||
AnimatedContent(
|
||||
targetState = form.value,
|
||||
transitionSpec = { fadeIn() togetherWith fadeOut() }
|
||||
) {
|
||||
when (it) {
|
||||
null -> Box(modifier = Modifier.fillMaxSize())
|
||||
else -> GMAlterationEditContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
form = it,
|
||||
paddings = GMAlterationEditPageDefault.paddings,
|
||||
addField = {
|
||||
scope.launch {
|
||||
viewModel.addField()
|
||||
}
|
||||
},
|
||||
removeField = viewModel::removeField,
|
||||
onSave = {
|
||||
scope.launch {
|
||||
viewModel.save()
|
||||
}
|
||||
},
|
||||
onCancel = {
|
||||
screen.popBackStack()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
GMAlterationEditContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
form = form,
|
||||
paddings = GMAlterationEditPageDefault.paddings,
|
||||
onBack = {
|
||||
screen.navigateBack()
|
||||
},
|
||||
addField = {
|
||||
scope.launch {
|
||||
viewModel.addField()
|
||||
}
|
||||
},
|
||||
removeField = viewModel::removeField,
|
||||
onSave = {
|
||||
scope.launch {
|
||||
if (viewModel.save()) {
|
||||
screen.navigateBack()
|
||||
}
|
||||
}
|
||||
},
|
||||
onTag = { tag ->
|
||||
viewModel.addTag(tag = tag)
|
||||
},
|
||||
)
|
||||
|
||||
ErrorSnackHandler(
|
||||
error = viewModel.error,
|
||||
|
|
@ -117,7 +137,7 @@ fun GMAlterationEditPage(
|
|||
|
||||
AlterationEditKeyHandler(
|
||||
onDismissRequest = {
|
||||
screen.popBackStack()
|
||||
screen.navigateBack()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -125,148 +145,218 @@ fun GMAlterationEditPage(
|
|||
@Composable
|
||||
private fun GMAlterationEditContent(
|
||||
modifier: Modifier = Modifier,
|
||||
form: GMAlterationEditPageUio,
|
||||
scope: CoroutineScope = rememberCoroutineScope(),
|
||||
tagsState: LazyListState = rememberLazyListState(),
|
||||
form: State<GMAlterationEditPageUio?>,
|
||||
paddings: PaddingValues,
|
||||
onBack: () -> Unit,
|
||||
addField: () -> Unit,
|
||||
removeField: (index: Int) -> Unit,
|
||||
onSave: () -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
onTag: (GMTagUio) -> Unit,
|
||||
) {
|
||||
val fields = form.fields.collectAsState()
|
||||
|
||||
LazyColumn(
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
contentPadding = paddings,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
item(
|
||||
key = "Id",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = form.id,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
item(
|
||||
key = "Name",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = form.label,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
item(
|
||||
key = "Description",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = form.description,
|
||||
singleLine = false,
|
||||
)
|
||||
}
|
||||
item(
|
||||
key = "Tags",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = form.tags,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
itemsIndexed(
|
||||
items = fields.value,
|
||||
key = { _, item -> item.key },
|
||||
) { index, item ->
|
||||
Row(
|
||||
modifier = Modifier.animateItem(),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = item.id,
|
||||
singleLine = true,
|
||||
)
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = item.expression,
|
||||
singleLine = true,
|
||||
)
|
||||
IconButton(
|
||||
onClick = { removeField(index) },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Close,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
text = stringResource(Res.string.game_master__alteration__title),
|
||||
)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = onBack,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Default.ArrowBack,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
TextButton(
|
||||
onClick = onSave,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
text = stringResource(Res.string.game_master__alteration__edit_field_save),
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_save_24dp),
|
||||
tint = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
content = {
|
||||
AnimatedContent(
|
||||
targetState = form.value,
|
||||
transitionSpec = {
|
||||
if (initialState?.id == targetState?.id) {
|
||||
EnterTransition.None togetherWith ExitTransition.None
|
||||
} else {
|
||||
fadeIn() togetherWith fadeOut()
|
||||
}
|
||||
}
|
||||
) {
|
||||
when (it) {
|
||||
null -> Box(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
|
||||
else -> {
|
||||
val fields = it.fields.collectAsState()
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = paddings,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
item(
|
||||
key = "Id",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = it.id,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
item(
|
||||
key = "Name",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = it.label,
|
||||
singleLine = true,
|
||||
)
|
||||
}
|
||||
item(
|
||||
key = "Description",
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
field = it.description,
|
||||
singleLine = false,
|
||||
)
|
||||
}
|
||||
item(
|
||||
key = "Tags",
|
||||
) {
|
||||
LazyRow(
|
||||
modifier = Modifier.draggable(
|
||||
orientation = Orientation.Horizontal,
|
||||
state = rememberDraggableState { delta ->
|
||||
scope.launch {
|
||||
tagsState.scrollBy(-delta)
|
||||
}
|
||||
},
|
||||
),
|
||||
state = tagsState,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
items(
|
||||
items = it.tags,
|
||||
) { tag ->
|
||||
GMTagButton(
|
||||
modifier = Modifier.height(48.dp),
|
||||
tag = tag,
|
||||
onTag = { onTag(tag) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
itemsIndexed(
|
||||
items = fields.value,
|
||||
key = { _, item -> item.key },
|
||||
) { index, item ->
|
||||
Row(
|
||||
modifier = Modifier.animateItem(),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = item.id,
|
||||
singleLine = true,
|
||||
)
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = item.expression,
|
||||
singleLine = true,
|
||||
)
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.size(size = 56.dp)
|
||||
.background(
|
||||
color = MaterialTheme.lwa.colorScheme.elevated.base1dp,
|
||||
shape = MaterialTheme.shapes.small,
|
||||
),
|
||||
onClick = { removeField(index) },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Close,
|
||||
tint = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
item(
|
||||
key = "Actions",
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.End
|
||||
) {
|
||||
Button(
|
||||
colors = LwaButtonColors(),
|
||||
shape = CircleShape,
|
||||
onClick = addField,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = stringResource(Res.string.game_master__alteration__edit_add_field),
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
Button(
|
||||
colors = LwaButtonColors(),
|
||||
shape = CircleShape,
|
||||
onClick = onSave,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = stringResource(Res.string.game_master__alteration__edit_field_save),
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_save_24dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
item(
|
||||
key = "Actions",
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateItem()
|
||||
.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.End
|
||||
) {
|
||||
Button(
|
||||
colors = LwaButtonColors(),
|
||||
shape = CircleShape,
|
||||
onClick = addField,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = stringResource(Res.string.game_master__alteration__edit_add_field),
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
Button(
|
||||
colors = LwaButtonColors(),
|
||||
shape = CircleShape,
|
||||
onClick = onSave,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = stringResource(Res.string.game_master__alteration__edit_field_save),
|
||||
)
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_save_24dp),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
Button(
|
||||
colors = LwaButtonColors(),
|
||||
shape = CircleShape,
|
||||
onClick = onCancel,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
text = stringResource(Res.string.game_master__alteration__edit_field_cancel),
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -284,3 +374,8 @@ private fun AlterationEditKeyHandler(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun NavHostController.navigateBack() = popBackStack(
|
||||
route = GMAlterationEditDestination.baseRoute(),
|
||||
inclusive = true,
|
||||
)
|
||||
|
|
@ -3,9 +3,13 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.desktop.lwa.network.LwaNetworkException
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
||||
import com.pixelized.desktop.lwa.repository.tag.TagRepository
|
||||
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.screen.gamemaster.common.tag.GMTagUio
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse.ErrorCode
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
|
@ -15,6 +19,7 @@ import kotlinx.coroutines.launch
|
|||
|
||||
class GMAlterationEditViewModel(
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val tagRepository: TagRepository,
|
||||
private val factory: GMAlterationEditFactory,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
|
|
@ -29,28 +34,33 @@ class GMAlterationEditViewModel(
|
|||
init {
|
||||
viewModelScope.launch {
|
||||
_form.value = factory.createForm(
|
||||
alteration = alterationRepository.alteration(alterationId = argument.id)
|
||||
originId = argument.id,
|
||||
alteration = alterationRepository.alteration(alterationId = argument.id),
|
||||
tags = tagRepository.alterationsTagFlow().value.values,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun save() {
|
||||
val edited = factory.createAlteration(form = form.value)
|
||||
val actual = alterationRepository.alterationFlow.value[edited?.id]
|
||||
|
||||
if (edited == null) return
|
||||
suspend fun save(): Boolean {
|
||||
val edited = factory.createAlteration(form = form.value) ?: return false
|
||||
|
||||
try {
|
||||
if (argument.id == null && actual?.id != null) {
|
||||
error("Id already taken by an another alteration")
|
||||
}
|
||||
alterationRepository.updateAlteration(
|
||||
alteration = edited,
|
||||
create = argument.id == null,
|
||||
)
|
||||
return true
|
||||
} catch (exception: LwaNetworkException) {
|
||||
_form.value?.id?.isError?.value = exception.code == ErrorCode.AlterationId
|
||||
_form.value?.label?.isError?.value = exception.code == ErrorCode.AlterationName
|
||||
|
||||
val message = ErrorSnackUio.from(exception = exception)
|
||||
_error.emit(message)
|
||||
return false
|
||||
} catch (exception: Exception) {
|
||||
val message = ErrorSnackUio.from(exception = exception)
|
||||
_error.emit(message)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -69,4 +79,16 @@ class GMAlterationEditViewModel(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addTag(tag: GMTagUio) {
|
||||
_form.update {
|
||||
it?.copy(
|
||||
tags = it.tags.toMutableList().also { tags ->
|
||||
val index = tags.indexOf(tag)
|
||||
if (index > -1)
|
||||
tags[index] = tag.copy(highlight = tag.highlight.not())
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.clickable
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
|
|
@ -15,6 +16,7 @@ import androidx.compose.ui.graphics.Shape
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
|
||||
|
||||
|
|
@ -62,3 +64,35 @@ fun GMTag(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun GMTagButton(
|
||||
modifier: Modifier = Modifier,
|
||||
padding: PaddingValues = GmTagDefault.padding,
|
||||
shape: Shape = MaterialTheme.shapes.small,
|
||||
tag: GMTagUio,
|
||||
onTag: (() -> Unit)? = null,
|
||||
) {
|
||||
val animatedColor = animateColorAsState(
|
||||
when (tag.highlight) {
|
||||
true -> MaterialTheme.lwa.colorScheme.base.secondary
|
||||
else -> MaterialTheme.lwa.colorScheme.base.onSurface
|
||||
}
|
||||
)
|
||||
Button(
|
||||
modifier = modifier,
|
||||
colors = LwaButtonColors(contentColor = animatedColor.value),
|
||||
shape = shape,
|
||||
enabled = onTag != null,
|
||||
onClick = { onTag?.invoke() },
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(paddingValues = padding),
|
||||
color = animatedColor.value,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = tag.label,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,23 @@ import java.text.Collator
|
|||
|
||||
class GMTagFactory {
|
||||
|
||||
fun convertToGMTagItemUio(
|
||||
tags: Collection<Tag>,
|
||||
selectedTagIds: List<String>,
|
||||
): List<GMTagUio> {
|
||||
return tags
|
||||
.map { tag ->
|
||||
GMTagUio(
|
||||
id = tag.id,
|
||||
label = tag.label,
|
||||
highlight = selectedTagIds.contains(tag.id),
|
||||
)
|
||||
}
|
||||
.sortedWith(
|
||||
comparator = compareBy(Collator.getInstance()) { it.label }
|
||||
)
|
||||
}
|
||||
|
||||
fun convertToGMTagItemUio(
|
||||
tags: Collection<Tag>,
|
||||
selectedTagId: String?,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ fun LwaTheme(
|
|||
MaterialTheme(
|
||||
colors = lwaColors.base,
|
||||
typography = MaterialTheme.typography,
|
||||
shapes = MaterialTheme.shapes,
|
||||
shapes = lwaShapes.base,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import androidx.compose.material.ContentAlpha
|
|||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun LwaButtonColors(): ButtonColors = ButtonDefaults.buttonColors(
|
||||
fun LwaButtonColors(
|
||||
contentColor: Color = MaterialTheme.colors.primary,
|
||||
): ButtonColors = ButtonDefaults.buttonColors(
|
||||
backgroundColor = MaterialTheme.colors.surface,
|
||||
contentColor = MaterialTheme.colors.primary,
|
||||
contentColor = contentColor,
|
||||
disabledContentColor = MaterialTheme.colors.surface.copy(alpha = ContentAlpha.disabled),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.desktop.lwa.ui.theme.shapes
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Shapes
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -9,6 +10,7 @@ import androidx.compose.ui.unit.dp
|
|||
|
||||
@Stable
|
||||
data class LwaShapes(
|
||||
val base: Shapes,
|
||||
val portrait: Shape,
|
||||
val panel: Shape,
|
||||
val settings: Shape,
|
||||
|
|
@ -18,12 +20,16 @@ data class LwaShapes(
|
|||
@Stable
|
||||
@Composable
|
||||
fun lwaShapes(
|
||||
base: Shapes = Shapes(
|
||||
small = RoundedCornerShape(4.dp),
|
||||
),
|
||||
portrait: Shape = RoundedCornerShape(8.dp),
|
||||
panel: Shape = RoundedCornerShape(8.dp),
|
||||
settings: Shape = RoundedCornerShape(8.dp),
|
||||
gameMaster: Shape = RoundedCornerShape(8.dp),
|
||||
): LwaShapes = remember {
|
||||
LwaShapes(
|
||||
base = base,
|
||||
portrait = portrait,
|
||||
panel = panel,
|
||||
settings = settings,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,14 @@
|
|||
package com.pixelized.server.lwa.model.alteration
|
||||
|
||||
import com.pixelized.server.lwa.server.exception.BusinessException
|
||||
import com.pixelized.server.lwa.server.exception.FileReadException
|
||||
import com.pixelized.server.lwa.server.exception.FileWriteException
|
||||
import com.pixelized.server.lwa.server.exception.JsonCodingException
|
||||
import com.pixelized.server.lwa.server.exception.JsonConversionException
|
||||
import com.pixelized.shared.lwa.model.alteration.Alteration
|
||||
import com.pixelized.shared.lwa.model.alteration.AlterationJson
|
||||
import com.pixelized.shared.lwa.model.alteration.AlterationJsonFactory
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.utils.PathProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -93,8 +99,9 @@ class AlterationStore(
|
|||
val file = alterationFile(id = json.id)
|
||||
// Guard case on update alteration
|
||||
if (create && file.exists()) {
|
||||
val root = Exception("Alteration already exist, creation is impossible.")
|
||||
throw BusinessException(root = root)
|
||||
throw BusinessException(
|
||||
message = "Alteration already exist, creation is impossible.",
|
||||
)
|
||||
}
|
||||
// Transform the json into the model.
|
||||
val alteration = try {
|
||||
|
|
@ -102,6 +109,18 @@ class AlterationStore(
|
|||
} catch (exception: Exception) {
|
||||
throw JsonConversionException(root = exception)
|
||||
}
|
||||
if (alteration.id.isEmpty()) {
|
||||
throw BusinessException(
|
||||
message = "Alteration 'id' is a mandatory field.",
|
||||
code = APIResponse.ErrorCode.AlterationId,
|
||||
)
|
||||
}
|
||||
if (alteration.metadata.name.isEmpty()) {
|
||||
throw BusinessException(
|
||||
message = "Alteration 'name' is a mandatory field.",
|
||||
code = APIResponse.ErrorCode.AlterationName,
|
||||
)
|
||||
}
|
||||
// Encode the json into a string.
|
||||
val data = try {
|
||||
this.json.encodeToString(json)
|
||||
|
|
@ -139,13 +158,15 @@ class AlterationStore(
|
|||
val file = alterationFile(id = id)
|
||||
// Guard case on the file existence.
|
||||
if (file.exists().not()) {
|
||||
val root = Exception("Alteration doesn't not exist, deletion is impossible.")
|
||||
throw BusinessException(root = root)
|
||||
throw BusinessException(
|
||||
message = "Alteration doesn't not exist, deletion is impossible.",
|
||||
)
|
||||
}
|
||||
// Guard case on the file deletion
|
||||
if (file.delete().not()) {
|
||||
val root = Exception("Alteration file have not been deleted for unknown reason.")
|
||||
throw BusinessException(root = root)
|
||||
throw BusinessException(
|
||||
message = "Alteration file have not been deleted for unknown reason.",
|
||||
)
|
||||
}
|
||||
// Update the data model with the deleted alteration.
|
||||
alterationFlow.update { alterations ->
|
||||
|
|
@ -162,11 +183,4 @@ class AlterationStore(
|
|||
private fun alterationFile(id: String): File {
|
||||
return File("${pathProvider.alterationsPath()}${id}.json")
|
||||
}
|
||||
|
||||
sealed class AlterationStoreException(root: Exception) : Exception(root)
|
||||
class JsonConversionException(root: Exception) : AlterationStoreException(root)
|
||||
class JsonCodingException(root: Exception) : AlterationStoreException(root)
|
||||
class BusinessException(root: Exception) : AlterationStoreException(root)
|
||||
class FileWriteException(root: Exception) : AlterationStoreException(root)
|
||||
class FileReadException(root: Exception) : AlterationStoreException(root)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.pixelized.server.lwa.model.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.exception.BusinessException
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJson
|
||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||
|
|
@ -43,8 +44,7 @@ class CampaignService(
|
|||
) {
|
||||
// Check if the character is already in the campaign.
|
||||
if (campaign.instances.contains(characterSheetId)) {
|
||||
val root = Exception("Character with id:$characterSheetId is already in the campaign.")
|
||||
throw CampaignStore.BusinessException(root = root)
|
||||
throw BusinessException(message = "Character with id:$characterSheetId is already in the campaign.")
|
||||
}
|
||||
// Update the corresponding instance
|
||||
val characters = campaign.characters.toMutableSet().also {
|
||||
|
|
@ -62,8 +62,7 @@ class CampaignService(
|
|||
) {
|
||||
// Check if the character is already in the campaign.
|
||||
if (campaign.instances.contains(characterSheetId)) {
|
||||
val root = Exception("Character with id:$characterSheetId is already in the campaign.")
|
||||
throw CampaignStore.BusinessException(root = root)
|
||||
throw BusinessException(message = "Character with id:$characterSheetId is already in the campaign.")
|
||||
}
|
||||
// Update the corresponding instance
|
||||
val characters = campaign.npcs.toMutableSet().also {
|
||||
|
|
@ -81,8 +80,7 @@ class CampaignService(
|
|||
) {
|
||||
// Check if the character is in the campaign.
|
||||
if (campaign.characters.contains(characterSheetId).not()) {
|
||||
val root = Exception("Character with id:$characterSheetId is not in the party.")
|
||||
throw CampaignStore.BusinessException(root = root)
|
||||
throw BusinessException(message = "Character with id:$characterSheetId is not in the party.")
|
||||
}
|
||||
// Update the corresponding instance
|
||||
val characters = campaign.characters.toMutableSet().also {
|
||||
|
|
@ -100,8 +98,7 @@ class CampaignService(
|
|||
) {
|
||||
// Check if the character is in the campaign.
|
||||
if (campaign.npcs.contains(characterSheetId).not()) {
|
||||
val root = Exception("Character with id:$characterSheetId is not in the npcs.")
|
||||
throw CampaignStore.BusinessException(root = root)
|
||||
throw BusinessException(message = "Character with id:$characterSheetId is not in the npcs.")
|
||||
}
|
||||
// Update the corresponding instance
|
||||
val characters = campaign.npcs.toMutableSet().also {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package com.pixelized.server.lwa.model.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.exception.FileReadException
|
||||
import com.pixelized.server.lwa.server.exception.FileWriteException
|
||||
import com.pixelized.server.lwa.server.exception.JsonCodingException
|
||||
import com.pixelized.server.lwa.server.exception.JsonConversionException
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJson
|
||||
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
|
||||
|
|
@ -108,11 +112,4 @@ class CampaignStore(
|
|||
private fun campaignFile(): File {
|
||||
return File("${pathProvider.campaignPath()}campaign.json")
|
||||
}
|
||||
|
||||
sealed class CampaignStoreException(root: Exception) : Exception(root)
|
||||
class JsonConversionException(root: Exception) : CampaignStoreException(root)
|
||||
class JsonCodingException(root: Exception) : CampaignStoreException(root)
|
||||
class BusinessException(root: Exception) : CampaignStoreException(root)
|
||||
class FileWriteException(root: Exception) : CampaignStoreException(root)
|
||||
class FileReadException(root: Exception) : CampaignStoreException(root)
|
||||
}
|
||||
|
|
@ -1,8 +1,14 @@
|
|||
package com.pixelized.server.lwa.model.character
|
||||
|
||||
import com.pixelized.server.lwa.server.exception.BusinessException
|
||||
import com.pixelized.server.lwa.server.exception.FileReadException
|
||||
import com.pixelized.server.lwa.server.exception.FileWriteException
|
||||
import com.pixelized.server.lwa.server.exception.JsonCodingException
|
||||
import com.pixelized.server.lwa.server.exception.JsonConversionException
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
|
||||
import com.pixelized.shared.lwa.model.characterSheet.factory.CharacterSheetJsonFactory
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.utils.PathProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -93,8 +99,7 @@ class CharacterSheetStore(
|
|||
val file = characterSheetFile(id = sheet.id)
|
||||
// Guard case on update alteration
|
||||
if (create && file.exists()) {
|
||||
val root = Exception("Character already exist, creation is impossible.")
|
||||
throw BusinessException(root = root)
|
||||
throw BusinessException(message = "Character already exist, creation is impossible.")
|
||||
}
|
||||
// Transform the json into the model.
|
||||
val json = try {
|
||||
|
|
@ -139,13 +144,16 @@ class CharacterSheetStore(
|
|||
val file = characterSheetFile(id = characterSheetId)
|
||||
// Guard case on the file existence.
|
||||
if (file.exists().not()) {
|
||||
val root = Exception("Character file with id:$characterSheetId doesn't not exist.")
|
||||
throw BusinessException(root = root)
|
||||
throw BusinessException(
|
||||
message = "Character file with id:$characterSheetId doesn't not exist.",
|
||||
code = APIResponse.ErrorCode.CharacterSheetId
|
||||
)
|
||||
}
|
||||
// Guard case on the file deletion
|
||||
if (file.delete().not()) {
|
||||
val root = Exception("Character file have not been deleted for unknown reason.")
|
||||
throw BusinessException(root = root)
|
||||
throw BusinessException(
|
||||
message = "Character file have not been deleted for unknown reason.",
|
||||
)
|
||||
}
|
||||
// Update the data model with the deleted character.
|
||||
characterSheetsFlow.update { characters ->
|
||||
|
|
@ -158,11 +166,4 @@ class CharacterSheetStore(
|
|||
private fun characterSheetFile(id: String): File {
|
||||
return File("${pathProvider.characterStorePath()}${id}.json")
|
||||
}
|
||||
|
||||
sealed class CharacterSheetStoreException(root: Exception) : Exception(root)
|
||||
class JsonConversionException(root: Exception) : CharacterSheetStoreException(root)
|
||||
class JsonCodingException(root: Exception) : CharacterSheetStoreException(root)
|
||||
class BusinessException(root: Exception) : CharacterSheetStoreException(root)
|
||||
class FileWriteException(root: Exception) : CharacterSheetStoreException(root)
|
||||
class FileReadException(root: Exception) : CharacterSheetStoreException(root)
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
package com.pixelized.server.lwa.model.tag
|
||||
|
||||
import com.pixelized.server.lwa.server.exception.FileReadException
|
||||
import com.pixelized.server.lwa.server.exception.FileWriteException
|
||||
import com.pixelized.server.lwa.server.exception.JsonConversionException
|
||||
import com.pixelized.shared.lwa.model.tag.TagJson
|
||||
import com.pixelized.shared.lwa.utils.PathProvider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -100,9 +103,4 @@ class TagStore(
|
|||
private fun characterFile() = File("${pathProvider.tagsPath()}$CHARACTER.json")
|
||||
|
||||
private fun alterationFile() = File("${pathProvider.tagsPath()}$ALTERATION.json")
|
||||
|
||||
sealed class TagStoreException(root: Exception) : Exception(root)
|
||||
class JsonConversionException(root: Exception) : TagStoreException(root)
|
||||
class FileWriteException(root: Exception) : TagStoreException(root)
|
||||
class FileReadException(root: Exception) : TagStoreException(root)
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
|
||||
class BusinessException(
|
||||
message: String,
|
||||
val code: APIResponse.ErrorCode? = null,
|
||||
) : ServerException(
|
||||
root = Exception(message)
|
||||
)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
class FileReadException(root: Exception) : ServerException(root)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
class FileWriteException(root: Exception) : ServerException(root)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
class JsonCodingException(root: Exception) : ServerException(root)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
class JsonConversionException(root: Exception) : ServerException(root)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
class MissingParameterException(name: String) :
|
||||
ServerException(root = Exception("Missing '$name' parameter."))
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
package com.pixelized.server.lwa.server.exception
|
||||
|
||||
sealed class ServerException(root: Exception) : Exception(root)
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.alteration
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.alterationId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -27,19 +27,9 @@ fun Engine.deleteAlteration(): suspend RoutingContext.() -> Unit {
|
|||
alterationId = alterationId,
|
||||
),
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.pixelized.server.lwa.server.rest.alteration
|
|||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.alterationId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -22,11 +23,8 @@ fun Engine.getAlteration(): suspend RoutingContext.() -> Unit {
|
|||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.server.lwa.server.rest.alteration
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -14,11 +15,8 @@ fun Engine.getAlterationTags(): suspend RoutingContext.() -> Unit {
|
|||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.server.lwa.server.rest.alteration
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -14,11 +15,8 @@ fun Engine.getAlterations(): suspend RoutingContext.() -> Unit {
|
|||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.alteration
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.create
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.model.alteration.AlterationJson
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
|
|
@ -29,19 +29,9 @@ fun Engine.putAlteration(): suspend RoutingContext.() -> Unit {
|
|||
alterationId = form.id,
|
||||
),
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -27,19 +27,9 @@ fun Engine.removeCampaignCharacter(): suspend RoutingContext.() -> Unit {
|
|||
characterSheetId = characterSheetId,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -27,19 +27,9 @@ fun Engine.removeCampaignNpc(): suspend RoutingContext.() -> Unit {
|
|||
characterSheetId = characterSheetId,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.server.lwa.server.rest.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -14,11 +15,8 @@ fun Engine.getCampaign(): suspend RoutingContext.() -> Unit {
|
|||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -27,19 +27,9 @@ fun Engine.putCampaignCharacter(): suspend RoutingContext.() -> Unit {
|
|||
characterSheetId = characterSheetId,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -27,19 +27,9 @@ fun Engine.putCampaignNpc(): suspend RoutingContext.() -> Unit {
|
|||
characterSheetId = characterSheetId,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.pixelized.server.lwa.server.rest.campaign
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignJsonV2
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
|
||||
|
|
@ -30,19 +30,9 @@ fun Engine.putCampaignScene(): suspend RoutingContext.() -> Unit {
|
|||
name = scene.name,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -27,19 +27,9 @@ fun Engine.deleteCharacter(): suspend RoutingContext.() -> Unit {
|
|||
characterSheetId = characterSheetId,
|
||||
),
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -22,19 +22,9 @@ fun Engine.getCharacter(): suspend RoutingContext.() -> Unit {
|
|||
data = characterSheet,
|
||||
),
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -14,11 +15,8 @@ fun Engine.getCharacterTags(): suspend RoutingContext.() -> Unit {
|
|||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingContext
|
||||
|
|
@ -14,11 +15,8 @@ fun Engine.getCharacters(): suspend RoutingContext.() -> Unit {
|
|||
),
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.create
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetJson
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
|
||||
|
|
@ -28,19 +28,9 @@ fun Engine.putCharacter(): suspend RoutingContext.() -> Unit {
|
|||
characterSheetId = form.id,
|
||||
),
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.active
|
||||
import com.pixelized.server.lwa.utils.extentions.alterationId
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -35,19 +35,9 @@ fun Engine.putCharacterAlteration(): suspend RoutingContext.() -> Unit {
|
|||
active = active,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.server.exception.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -14,10 +15,7 @@ fun Engine.putCharacterDamage(): suspend RoutingContext.() -> Unit {
|
|||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val damage = call.queryParameters["damage"]?.toIntOrNull()
|
||||
?: throw MissingParameterException(
|
||||
name = "damage",
|
||||
errorCode = APIResponse.MISSING_DAMAGE
|
||||
)
|
||||
?: throw MissingParameterException(name = "damage")
|
||||
// fetch the character sheet
|
||||
val characterSheet = characterService.character(characterSheetId)
|
||||
?: error("CharacterSheet with id:$characterSheetId not found.")
|
||||
|
|
@ -38,19 +36,9 @@ fun Engine.putCharacterDamage(): suspend RoutingContext.() -> Unit {
|
|||
damage = damage,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.server.exception.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -14,10 +15,7 @@ fun Engine.putCharacterDiminished(): suspend RoutingContext.() -> Unit {
|
|||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val diminished = call.queryParameters["diminished"]?.toIntOrNull()
|
||||
?: throw MissingParameterException(
|
||||
name = "diminished",
|
||||
errorCode = APIResponse.MISSING_DIMINISHED
|
||||
)
|
||||
?: throw MissingParameterException(name = "diminished")
|
||||
// Update the character damage
|
||||
characterService.updateDiminished(
|
||||
characterSheetId = characterSheetId,
|
||||
|
|
@ -34,19 +32,9 @@ fun Engine.putCharacterDiminished(): suspend RoutingContext.() -> Unit {
|
|||
diminished = diminished,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.pixelized.server.lwa.server.rest.character
|
||||
|
||||
import com.pixelized.server.lwa.server.Engine
|
||||
import com.pixelized.server.lwa.utils.extentions.MissingParameterException
|
||||
import com.pixelized.server.lwa.server.exception.MissingParameterException
|
||||
import com.pixelized.server.lwa.utils.extentions.characterSheetId
|
||||
import com.pixelized.server.lwa.utils.extentions.exception
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
|
||||
import io.ktor.server.response.respond
|
||||
|
|
@ -14,10 +15,7 @@ fun Engine.putCharacterFatigue(): suspend RoutingContext.() -> Unit {
|
|||
// get the query parameter
|
||||
val characterSheetId = call.queryParameters.characterSheetId
|
||||
val fatigue = call.queryParameters["fatigue"]?.toIntOrNull()
|
||||
?: throw MissingParameterException(
|
||||
name = "fatigue",
|
||||
errorCode = APIResponse.MISSING_FATIGUE
|
||||
)
|
||||
?: throw MissingParameterException(name = "fatigue")
|
||||
// fetch the character sheet
|
||||
val characterSheet = characterService.character(characterSheetId)
|
||||
?: error("CharacterSheet with id:$characterSheetId not found.")
|
||||
|
|
@ -38,19 +36,9 @@ fun Engine.putCharacterFatigue(): suspend RoutingContext.() -> Unit {
|
|||
fatigue = fatigue,
|
||||
)
|
||||
)
|
||||
} catch (exception: MissingParameterException) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = exception.errorCode,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
call.respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.GENERIC,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
call.exception(
|
||||
exception = exception
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,24 @@
|
|||
package com.pixelized.server.lwa.utils.extentions
|
||||
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import com.pixelized.server.lwa.server.exception.MissingParameterException
|
||||
import io.ktor.http.Parameters
|
||||
|
||||
val Parameters.characterSheetId
|
||||
get() = "characterSheetId".let { param ->
|
||||
this[param] ?: throw MissingParameterException(
|
||||
name = param,
|
||||
errorCode = APIResponse.MISSING_CHARACTER_SHEET_ID,
|
||||
)
|
||||
this[param] ?: throw MissingParameterException(name = param)
|
||||
}
|
||||
|
||||
val Parameters.alterationId
|
||||
get() = "alterationId".let { param ->
|
||||
this[param] ?: throw MissingParameterException(
|
||||
name = param,
|
||||
errorCode = APIResponse.MISSING_ALTERATION_ID,
|
||||
)
|
||||
this[param] ?: throw MissingParameterException(name = param)
|
||||
}
|
||||
|
||||
val Parameters.create
|
||||
get() = "create".let { param ->
|
||||
this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException(
|
||||
name = param,
|
||||
errorCode = APIResponse.MISSING_CREATE
|
||||
)
|
||||
this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException(name = param)
|
||||
}
|
||||
|
||||
val Parameters.active
|
||||
get() = "active".let { param ->
|
||||
this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException(
|
||||
name = param,
|
||||
errorCode = APIResponse.MISSING_ACTIVE
|
||||
)
|
||||
this[param]?.toBooleanStrictOrNull() ?: throw MissingParameterException(name = param)
|
||||
}
|
||||
|
||||
class MissingParameterException(
|
||||
name: String,
|
||||
val errorCode: Int,
|
||||
) : Exception("Missing $name parameter.")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package com.pixelized.server.lwa.utils.extentions
|
||||
|
||||
import com.pixelized.server.lwa.server.exception.BusinessException
|
||||
import com.pixelized.server.lwa.server.exception.MissingParameterException
|
||||
import com.pixelized.shared.lwa.protocol.rest.APIResponse
|
||||
import io.ktor.server.response.respond
|
||||
import io.ktor.server.routing.RoutingCall
|
||||
|
||||
|
||||
suspend inline fun <reified T : Exception> RoutingCall.exception(exception: T) {
|
||||
when (exception) {
|
||||
|
||||
is MissingParameterException -> {
|
||||
respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.BAD_REQUEST,
|
||||
message = exception.message ?: "?",
|
||||
code = APIResponse.ErrorCode.AlterationName,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
is BusinessException -> {
|
||||
respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.INTERNAL_ERROR,
|
||||
message = exception.message ?: "?",
|
||||
code = exception.code,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> respond(
|
||||
message = APIResponse.error(
|
||||
status = APIResponse.INTERNAL_ERROR,
|
||||
message = exception.message ?: "?",
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -7,46 +7,52 @@ data class APIResponse<T>(
|
|||
val success: Boolean,
|
||||
val status: Int,
|
||||
val message: String?,
|
||||
val code: ErrorCode?,
|
||||
val data: T?,
|
||||
) {
|
||||
@Serializable
|
||||
enum class ErrorCode {
|
||||
AlterationId,
|
||||
AlterationName,
|
||||
CharacterSheetId,
|
||||
}
|
||||
|
||||
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,
|
||||
code: ErrorCode? = null,
|
||||
message: String?,
|
||||
) = APIResponse(
|
||||
success = false,
|
||||
status = status,
|
||||
code = code,
|
||||
message = message,
|
||||
data = null,
|
||||
)
|
||||
|
||||
fun success() = APIResponse(
|
||||
fun success(
|
||||
status: Int = OK,
|
||||
) = APIResponse(
|
||||
success = true,
|
||||
status = SUCCESS,
|
||||
status = status,
|
||||
code = null,
|
||||
message = null,
|
||||
data = null,
|
||||
)
|
||||
|
||||
inline fun <reified T> success(
|
||||
status: Int = OK,
|
||||
data: T? = null,
|
||||
) = APIResponse(
|
||||
success = true,
|
||||
status = SUCCESS,
|
||||
status = status,
|
||||
code = null,
|
||||
message = null,
|
||||
data = data,
|
||||
)
|
||||
|
||||
const val OK = 200
|
||||
const val BAD_REQUEST = 400
|
||||
const val INTERNAL_ERROR = 500
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue