diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 3501227..0df87e7 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -242,6 +242,7 @@
Ajouter aux Npcs
Retirer des Npcs
Créer un personnage
+ Édition d'Altération
Filtrer par nom :
Créer une altération
Supprimer l'altération
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaNetworkException.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaNetworkException.kt
index 3f048e8..753751a 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaNetworkException.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaNetworkException.kt
@@ -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"
)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/error/ErrorSnackUio.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/error/ErrorSnackUio.kt
index 3b39cda..d3f60bf 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/error/ErrorSnackUio.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/error/ErrorSnackUio.kt
@@ -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,
) {
LaunchedEffect(Unit) {
- error.collect {
+ error.collectLatest {
snack.showSnackbar(
message = it.message,
actionLabel = it.action,
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt
index ada79c6..22fdf75 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt
@@ -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,
- val labelFlow: StateFlow?,
- val valueFlow: StateFlow,
- val placeHolderFlow: StateFlow?,
+ val isError: MutableStateFlow,
+ val labelFlow: MutableStateFlow?,
+ val valueFlow: MutableStateFlow,
+ val placeHolderFlow: MutableStateFlow?,
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)
},
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/gamemaster/GMAlterationEditDestination.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/gamemaster/GMAlterationEditDestination.kt
index 8bdd8f9..b24461a 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/gamemaster/GMAlterationEditDestination.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/gamemaster/GMAlterationEditDestination.kt
@@ -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()
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditFactory.kt
index 14e5d51..c06cae7 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditFactory.kt
@@ -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,
): 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(
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditPage.kt
index 8d6c051..e07e731 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditPage.kt
@@ -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,
val fields: MutableStateFlow>,
) {
@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,
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
@@ -283,4 +373,9 @@ private fun AlterationEditKeyHandler(
else -> false
}
}
-}
\ No newline at end of file
+}
+
+private fun NavHostController.navigateBack() = popBackStack(
+ route = GMAlterationEditDestination.baseRoute(),
+ inclusive = true,
+)
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditViewModel.kt
index c3a1d1f..aa27701 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/alteration/edit/GMAlterationEditViewModel.kt
@@ -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())
+ }
+ )
+ }
+ }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTag.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTag.kt
index 1437e22..f1d7b05 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTag.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTag.kt
@@ -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
@@ -61,4 +63,36 @@ fun GMTag(
text = tag.label,
)
}
+}
+
+
+@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,
+ )
+ }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTagFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTagFactory.kt
index 10f59cd..76e7d4c 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTagFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/common/tag/GMTagFactory.kt
@@ -5,6 +5,23 @@ import java.text.Collator
class GMTagFactory {
+ fun convertToGMTagItemUio(
+ tags: Collection,
+ selectedTagIds: List,
+ ): List {
+ 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,
selectedTagId: String?,
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt
index 9438901..3e06b69 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt
@@ -56,7 +56,7 @@ fun LwaTheme(
MaterialTheme(
colors = lwaColors.base,
typography = MaterialTheme.typography,
- shapes = MaterialTheme.shapes,
+ shapes = lwaShapes.base,
content = content,
)
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/component/LwaButtonColors.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/component/LwaButtonColors.kt
index 8a8b2b6..de546e3 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/component/LwaButtonColors.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/component/LwaButtonColors.kt
@@ -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),
-)
-
+)
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt
index 17dfada..97b11a7 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt
@@ -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,
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/alteration/AlterationStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/alteration/AlterationStore.kt
index 0a155cd..ce74f7e 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/model/alteration/AlterationStore.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/alteration/AlterationStore.kt
@@ -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)
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt
index 105df98..e71b8fa 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt
@@ -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 {
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt
index 1baa868..5a499b4 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignStore.kt
@@ -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)
}
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/character/CharacterSheetStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/character/CharacterSheetStore.kt
index d804870..06ff442 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/model/character/CharacterSheetStore.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/character/CharacterSheetStore.kt
@@ -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)
}
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/tag/TagStore.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/tag/TagStore.kt
index 5bbff0b..1538552 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/model/tag/TagStore.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/tag/TagStore.kt
@@ -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)
}
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/BusinessException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/BusinessException.kt
new file mode 100644
index 0000000..54d0a7b
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/BusinessException.kt
@@ -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)
+)
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/FileReadException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/FileReadException.kt
new file mode 100644
index 0000000..f3fe591
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/FileReadException.kt
@@ -0,0 +1,3 @@
+package com.pixelized.server.lwa.server.exception
+
+class FileReadException(root: Exception) : ServerException(root)
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/FileWriteException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/FileWriteException.kt
new file mode 100644
index 0000000..5b66d40
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/FileWriteException.kt
@@ -0,0 +1,3 @@
+package com.pixelized.server.lwa.server.exception
+
+class FileWriteException(root: Exception) : ServerException(root)
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/JsonCodingException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/JsonCodingException.kt
new file mode 100644
index 0000000..35f271e
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/JsonCodingException.kt
@@ -0,0 +1,3 @@
+package com.pixelized.server.lwa.server.exception
+
+class JsonCodingException(root: Exception) : ServerException(root)
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/JsonConversionException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/JsonConversionException.kt
new file mode 100644
index 0000000..0c98955
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/JsonConversionException.kt
@@ -0,0 +1,3 @@
+package com.pixelized.server.lwa.server.exception
+
+class JsonConversionException(root: Exception) : ServerException(root)
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/MissingParameterException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/MissingParameterException.kt
new file mode 100644
index 0000000..9ae5498
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/MissingParameterException.kt
@@ -0,0 +1,4 @@
+package com.pixelized.server.lwa.server.exception
+
+class MissingParameterException(name: String) :
+ ServerException(root = Exception("Missing '$name' parameter."))
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/ServerException.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/ServerException.kt
new file mode 100644
index 0000000..4b3fc3a
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/exception/ServerException.kt
@@ -0,0 +1,3 @@
+package com.pixelized.server.lwa.server.exception
+
+sealed class ServerException(root: Exception) : Exception(root)
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt
index 557ce43..837240e 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/DELETE_Alteration.kt
@@ -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,
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alteration.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alteration.kt
index 6a70c41..30f89cd 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alteration.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alteration.kt
@@ -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,
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_AlterationTags.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_AlterationTags.kt
index 07edd33..fe86478 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_AlterationTags.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_AlterationTags.kt
@@ -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,
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alterations.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alterations.kt
index 6022814..728f750 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alterations.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/GET_Alterations.kt
@@ -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,
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alteration.kt
similarity index 68%
rename from server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt
rename to server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alteration.kt
index da2e233..ee1a824 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alateration.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/alteration/PUT_Alteration.kt
@@ -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,
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt
index a2e1a2d..fdec0e7 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Character.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt
index 336e562..7d4f911 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/DELETE_Campaign_Npc.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt
index f345e13..72a4ad7 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt
index 80f012a..a301e2a 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Character.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt
index 07dfd5d..c0dbcad 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Npc.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt
index e2e37bb..2da6626 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_Scene_Name.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt
index 42629b4..89dc7c7 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/DELETE_Character.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Character.kt
index 200bba4..2e70f75 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Character.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Character.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_CharacterTags.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_CharacterTags.kt
index 52b5c3f..8f1b876 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_CharacterTags.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_CharacterTags.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Characters.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Characters.kt
index 354b4ee..4f62a70 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Characters.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/GET_Characters.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character.kt
index dbc0f21..58225a3 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Alteration.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Alteration.kt
index a6fd05b..bb77670 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Alteration.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Alteration.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Damage.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Damage.kt
index 427c4be..3687b79 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Damage.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Damage.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Diminished.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Diminished.kt
index b695e26..666eb99 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Diminished.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Diminished.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Fatigue.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Fatigue.kt
index 6f565cc..1709485 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Fatigue.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/character/PUT_Character_Fatigue.kt
@@ -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
)
}
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt b/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt
index b719213..1559b91 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/ParametersExt.kt
@@ -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.")
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/RoutingCallExt+exception.kt b/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/RoutingCallExt+exception.kt
new file mode 100644
index 0000000..45688b6
--- /dev/null
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/utils/extentions/RoutingCallExt+exception.kt
@@ -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 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 ?: "?",
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt
index f5893b4..a6d2d9e 100644
--- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt
+++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/APIResponse.kt
@@ -7,46 +7,52 @@ data class APIResponse(
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 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
}
}
\ No newline at end of file