Add version to the charactersheet savable.

This commit is contained in:
Thomas Andres Gomez 2024-11-17 22:25:48 +01:00
parent c7fe440f8f
commit 52f7f8333b
13 changed files with 211 additions and 134 deletions

View file

@ -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)
}

View file

@ -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 {

View file

@ -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<Dp>,
val background: State<Color>,
)
@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()
)
}
}
}
}

View file

@ -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<Boolean>
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
}
}

View file

@ -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
}
}

View file

@ -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,

View file

@ -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<List<CharacterSheet>> = flow
@Throws(
CharacterSheetStoreException::class,
FileWriteException::class,
@ -19,7 +25,9 @@ class CharacterSheetStore {
)
fun save(sheets: List<CharacterSheet>) {
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<List<CharacterSheet>>(json)
val sheets = Json.decodeFromString<List<CharacterSheetJson>>(json)
sheets.map { factory.convertFromJson(it) }
} catch (exception: Exception) {
throw JsonConversionException(root = exception)
}
}
}
fun loadFlow(): StateFlow<List<CharacterSheet>> = flow
companion object {
private const val NAME = "characters_sheet.json"
}

View file

@ -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<Roll>,
) {
@Serializable
data class Skill(
val label: String,
val value: Int,
val used: Boolean,
)
@Serializable
data class Roll(
val label: String,
val roll: String,

View file

@ -0,0 +1,6 @@
package com.pixelized.desktop.lwa.repository.characterSheet.model
import kotlinx.serialization.Serializable
@Serializable
sealed interface CharacterSheetJson

View file

@ -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<Skill>,
// occupations
val occupations: List<Skill>,
// magic skill
val magics: List<Skill>,
// attack
val rolls: List<Roll>,
) : 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"
}
}

View file

@ -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

View file

@ -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

View file

@ -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