From 52f7f8333b60626cc0eafa5ac66abe4165668cbe Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Sun, 17 Nov 2024 22:25:48 +0100 Subject: [PATCH] Add version to the charactersheet savable. --- .../com/pixelized/desktop/lwa/Module.kt | 4 +- .../desktop/lwa/business/RollUseCase.kt | 2 +- .../lwa/composable/overlay/BlurOverlay.kt | 67 ---------- .../overlay/BlurOverlayViewModel.kt | 50 -------- .../CharacterSheetJsonFactory.kt | 118 ++++++++++++++++++ .../CharacterSheetRepository.kt | 3 +- .../characterSheet/CharacterSheetStore.kt | 17 ++- .../{ => model}/CharacterSheet.kt | 7 +- .../model/CharacterSheetJson.kt | 6 + .../model/CharacterSheetJsonV1.kt | 65 ++++++++++ .../detail/CharacterSheetFactory.kt | 2 +- .../edit/CharacterSheetEditFactory.kt | 2 +- .../desktop/lwa/screen/roll/RollViewModel.kt | 2 +- 13 files changed, 211 insertions(+), 134 deletions(-) delete mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlay.kt delete mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlayViewModel.kt create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt rename composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/{ => model}/CharacterSheet.kt (90%) create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJson.kt create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt index 5c6a2af..3425dcc 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt @@ -1,13 +1,14 @@ package com.pixelized.desktop.lwa +import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetJsonFactory import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetStore import com.pixelized.desktop.lwa.repository.network.NetworkRepository import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetFactory import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetViewModel -import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditViewModel import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditFactory +import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditViewModel import com.pixelized.desktop.lwa.screen.main.MainPageViewModel import com.pixelized.desktop.lwa.screen.network.NetworkFactory import com.pixelized.desktop.lwa.screen.network.NetworkViewModel @@ -37,6 +38,7 @@ val factoryDependencies get() = module { factoryOf(::CharacterSheetFactory) factoryOf(::CharacterSheetEditFactory) + factoryOf(::CharacterSheetJsonFactory) factoryOf(::NetworkFactory) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/RollUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/RollUseCase.kt index a6f0739..c5319e0 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/RollUseCase.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/RollUseCase.kt @@ -1,6 +1,6 @@ package com.pixelized.desktop.lwa.business -import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet object RollUseCase { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlay.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlay.kt deleted file mode 100644 index 4a1db1f..0000000 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlay.kt +++ /dev/null @@ -1,67 +0,0 @@ -package com.pixelized.desktop.lwa.composable.overlay - -import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically -import androidx.compose.animation.togetherWith -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.runtime.Composable -import androidx.compose.runtime.Stable -import androidx.compose.runtime.State -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.blur -import androidx.compose.ui.draw.drawWithContent -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.Dp -import androidx.lifecycle.viewmodel.compose.viewModel - -@Stable -data class BlurOverlayTransitionUio( - val blur: State, - val background: State, -) - -@Composable -fun BlurOverlay( - viewModel: BlurOverlayViewModel = viewModel { BlurOverlayViewModel() }, - overlay: @Composable BoxScope.() -> Unit, - content: @Composable BoxScope.() -> Unit, -) { - val transition = viewModel.transition - Box { - Box( - modifier = Modifier - .fillMaxSize() - .blur(radius = transition.blur.value) - .drawWithContent { - drawContent() - drawRect(color = transition.background.value) - }, - content = content, - ) - - AnimatedContent( - targetState = viewModel.overlay.value, - transitionSpec = { - val enter = fadeIn() + slideInVertically { 64 } - val exit = fadeOut() + slideOutVertically { 64 } - enter togetherWith exit - }, - ) { roll -> - when (roll) { - true -> Box( - modifier = Modifier.fillMaxSize(), - content = overlay, - ) - - else -> Box( - modifier = Modifier.fillMaxSize() - ) - } - } - } -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlayViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlayViewModel.kt deleted file mode 100644 index 03ee6c4..0000000 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/composable/overlay/BlurOverlayViewModel.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.pixelized.desktop.lwa.composable.overlay - -import androidx.compose.animation.animateColor -import androidx.compose.animation.core.animateDp -import androidx.compose.animation.core.updateTransition -import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp -import androidx.lifecycle.ViewModel - -class BlurOverlayViewModel : ViewModel() { - private val _overlay = mutableStateOf(false) - val overlay: State - get() = _overlay - - val transition: BlurOverlayTransitionUio - @Composable - get() { - val transition = updateTransition(_overlay.value) - val blur = transition.animateDp { - when (it) { - true -> 8.dp - else -> 0.dp - } - } - val background = transition.animateColor { - when (it) { - true -> Color.Black.copy(alpha = 0.6f) - else -> Color.Black.copy(alpha = 0f) - } - } - return remember { - BlurOverlayTransitionUio( - blur = blur, - background = background, - ) - } - } - - fun show() { - _overlay.value = true - } - - fun hide() { - _overlay.value = false - } -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt new file mode 100644 index 0000000..ffb2468 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt @@ -0,0 +1,118 @@ +package com.pixelized.desktop.lwa.repository.characterSheet + +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJsonV1 + +class CharacterSheetJsonFactory { + + fun convertLastJsonVersion( + sheet: CharacterSheet, + ): CharacterSheetJson { + val json = CharacterSheetJsonV1( + id = sheet.id, + name = sheet.name, + strength = sheet.strength, + dexterity = sheet.dexterity, + constitution = sheet.constitution, + height = sheet.height, + intelligence = sheet.intelligence, + power = sheet.power, + charisma = sheet.charisma, + movement = sheet.movement, + currentHp = sheet.currentHp, + maxHp = sheet.maxHp, + currentPP = sheet.currentPP, + maxPP = sheet.maxPP, + damageBonus = sheet.damageBonus, + armor = sheet.armor, + skills = sheet.skills.map { + CharacterSheetJsonV1.Skill( + label = it.label, + value = it.value, + used = it.used, + ) + }, + occupations = sheet.occupations.map { + CharacterSheetJsonV1.Skill( + label = it.label, + value = it.value, + used = it.used, + ) + }, + magics = sheet.magics.map { + CharacterSheetJsonV1.Skill( + label = it.label, + value = it.value, + used = it.used, + ) + }, + rolls = sheet.rolls.map { + CharacterSheetJsonV1.Roll( + label = it.label, + roll = it.roll, + ) + }, + ) + return json + } + + fun convertFromJson( + json: CharacterSheetJson, + ): CharacterSheet { + return when (json) { + is CharacterSheetJsonV1 -> convertFromV1(json = json) + } + } + + private fun convertFromV1( + json: CharacterSheetJsonV1, + ): CharacterSheet { + val sheet = CharacterSheet( + id = json.id, + name = json.name, + strength = json.strength, + dexterity = json.dexterity, + constitution = json.constitution, + height = json.height, + intelligence = json.intelligence, + power = json.power, + charisma = json.charisma, + movement = json.movement, + currentHp = json.currentHp, + maxHp = json.maxHp, + currentPP = json.currentPP, + maxPP = json.maxPP, + damageBonus = json.damageBonus, + armor = json.armor, + skills = json.skills.map { + CharacterSheet.Skill( + label = it.label, + value = it.value, + used = it.used, + ) + }, + occupations = json.occupations.map { + CharacterSheet.Skill( + label = it.label, + value = it.value, + used = it.used, + ) + }, + magics = json.magics.map { + CharacterSheet.Skill( + label = it.label, + value = it.value, + used = it.used, + ) + }, + rolls = json.rolls.map { + CharacterSheet.Roll( + label = it.label, + roll = it.roll, + ) + }, + ) + return sheet + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt index d405176..69cef43 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt @@ -1,5 +1,6 @@ package com.pixelized.desktop.lwa.repository.characterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -13,7 +14,7 @@ class CharacterSheetRepository( ) { private val scope = CoroutineScope(Dispatchers.IO) - private val sheets = store.loadFlow() + private val sheets = store.characterSheetFlow() .stateIn( scope = scope, started = SharingStarted.Eagerly, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt index a632c3a..df50663 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt @@ -1,5 +1,7 @@ package com.pixelized.desktop.lwa.repository.characterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson import com.pixelized.desktop.lwa.repository.storePath import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -7,11 +9,15 @@ import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import java.io.File -class CharacterSheetStore { +class CharacterSheetStore( + private val factory: CharacterSheetJsonFactory, +) { private val root = File(storePath()).also { it.mkdirs() } private val files = File(root, NAME).also { it.createNewFile() } private val flow = MutableStateFlow(value = load()) + fun characterSheetFlow(): StateFlow> = flow + @Throws( CharacterSheetStoreException::class, FileWriteException::class, @@ -19,7 +25,9 @@ class CharacterSheetStore { ) fun save(sheets: List) { val json = try { - Json.encodeToString(sheets) + sheets + .map(factory::convertLastJsonVersion) + .let(Json::encodeToString) } catch (exception: Exception) { throw JsonConversionException(root = exception) } @@ -49,15 +57,14 @@ class CharacterSheetStore { emptyList() } else { try { - Json.decodeFromString>(json) + val sheets = Json.decodeFromString>(json) + sheets.map { factory.convertFromJson(it) } } catch (exception: Exception) { throw JsonConversionException(root = exception) } } } - fun loadFlow(): StateFlow> = flow - companion object { private const val NAME = "characters_sheet.json" } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheet.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt similarity index 90% rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheet.kt rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt index c310459..34fe597 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheet.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt @@ -1,8 +1,5 @@ -package com.pixelized.desktop.lwa.repository.characterSheet +package com.pixelized.desktop.lwa.repository.characterSheet.model -import kotlinx.serialization.Serializable - -@Serializable data class CharacterSheet( val id: String, val name: String, @@ -31,14 +28,12 @@ data class CharacterSheet( // attack val rolls: List, ) { - @Serializable data class Skill( val label: String, val value: Int, val used: Boolean, ) - @Serializable data class Roll( val label: String, val roll: String, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJson.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJson.kt new file mode 100644 index 0000000..db11792 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJson.kt @@ -0,0 +1,6 @@ +package com.pixelized.desktop.lwa.repository.characterSheet.model + +import kotlinx.serialization.Serializable + +@Serializable +sealed interface CharacterSheetJson \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt new file mode 100644 index 0000000..a342f39 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt @@ -0,0 +1,65 @@ +package com.pixelized.desktop.lwa.repository.characterSheet.model + +import kotlinx.serialization.Serializable + +@Serializable +data class CharacterSheetJsonV1( + val id: String, + val name: String, + // characteristics + val strength: Int, + val dexterity: Int, + val constitution: Int, + val height: Int, + val intelligence: Int, + val power: Int, + val charisma: Int, + // sub characteristics + val movement: Int, + val currentHp: Int, + val maxHp: Int, + val currentPP: Int, + val maxPP: Int, + val damageBonus: String, + val armor: Int, + // skills + val skills: List, + // occupations + val occupations: List, + // magic skill + val magics: List, + // attack + val rolls: List, +) : CharacterSheetJson { + @Serializable + data class Skill( + val label: String, + val value: Int, + val used: Boolean, + ) + + @Serializable + data class Roll( + val label: String, + val roll: String, + ) + + companion object { + const val COMBAT = "Bagarre" + const val DODGE = "Esquive" + const val GRAB = "Saisie" + const val THROW = "Lancer" + const val ATHLETICS = "Athlétisme" + const val ACROBATICS = "Acrobatie" + const val PERCEPTION = "Perception" + const val SEARCH = "Recherche" + const val EMPATHY = "Empathie" + const val PERSUASION = "Persuasion" + const val INTIMIDATION = "Intimidation" + const val SPIEL = "Baratin" + const val BARGAIN = "Marchandage" + const val DISCRETION = "Discrétion" + const val SLEIGHT_OF_HAND = "Escamotage" + const val AID = "Premiers soins" + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt index 1b21f31..1502be5 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt @@ -1,7 +1,7 @@ package com.pixelized.desktop.lwa.screen.characterSheet.detail import com.pixelized.desktop.lwa.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Node import lwacharactersheet.composeapp.generated.resources.Res diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt index 3514e80..3040477 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt @@ -2,7 +2,7 @@ package com.pixelized.desktop.lwa.screen.characterSheet.edit import com.pixelized.desktop.lwa.business.DamageBonusUseCase.bonusDamage import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase.normalize -import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditPageUio.SkillGroup import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio import lwacharactersheet.composeapp.generated.resources.Res diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt index 30b3655..31136a1 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt @@ -8,7 +8,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import com.pixelized.desktop.lwa.business.RollUseCase import com.pixelized.desktop.lwa.business.SkillStepUseCase -import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheet +import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio