Basic character sheet edit.
This commit is contained in:
parent
6e4f91e007
commit
d74a5fcd7c
3 changed files with 501 additions and 2 deletions
|
|
@ -1,20 +1,31 @@
|
|||
package com.pixelized.desktop.lwa
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.CharacterSheetUio
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.CharacterSheetViewModel
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEdit
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditUio
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.edit.FieldUio
|
||||
import com.pixelized.desktop.lwa.screen.overlay.BlurOverlay
|
||||
import com.pixelized.desktop.lwa.screen.overlay.BlurOverlayViewModel
|
||||
import com.pixelized.desktop.lwa.screen.roll.RollPage
|
||||
|
|
@ -33,13 +44,34 @@ fun App() {
|
|||
val overlayViewModel = viewModel { BlurOverlayViewModel() }
|
||||
val rollViewModel = viewModel { RollViewModel() }
|
||||
|
||||
val edit = remember { mutableStateOf<CharacterSheetEditUio?>(null) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(all = 16.dp),
|
||||
) {
|
||||
Row {
|
||||
Button(
|
||||
onClick = sheetViewModel::showCharacterSheet,
|
||||
) {
|
||||
Text(text = "Koryas Tissenpa")
|
||||
}
|
||||
IconButton(
|
||||
onClick = {
|
||||
edit.value = CharacterSheetEditUio.create(
|
||||
sheet = CharacterSheetUio.Koryas,
|
||||
)
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Edit,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
Button(
|
||||
onClick = sheetViewModel::showCharacterSheet,
|
||||
onClick = { edit.value = CharacterSheetEditUio.Default },
|
||||
) {
|
||||
Text(text = "Koryas Tissenpa")
|
||||
Text(text = "Créer une feuille de personnage")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,6 +114,46 @@ fun App() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
edit.value?.let { sheet ->
|
||||
Window(
|
||||
onCloseRequest = { edit.value = null },
|
||||
state = rememberWindowState(
|
||||
width = 320.dp + 64.dp,
|
||||
height = 900.dp,
|
||||
),
|
||||
title = "LwaCharacterSheet",
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
CharacterSheetEdit(
|
||||
form = sheet,
|
||||
onSkill = { skill ->
|
||||
edit.value = sheet.copy(
|
||||
groups = sheet.groups.map { group ->
|
||||
if (skill.title == group.title) {
|
||||
group.copy(
|
||||
fields = mutableListOf<FieldUio>().apply {
|
||||
addAll(group.fields)
|
||||
add(
|
||||
FieldUio.create(
|
||||
label = "",
|
||||
valuePlaceHolder = { "40" },
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
group
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
package com.pixelized.desktop.lwa.screen.characterSheet.edit
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.composable.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.screen.characterSheet.CharacterSheetUio
|
||||
import kotlin.math.max
|
||||
import kotlin.math.truncate
|
||||
|
||||
@Stable
|
||||
data class CharacterSheetEditUio(
|
||||
val name: FieldUio,
|
||||
val groups: List<Group>,
|
||||
) {
|
||||
@Stable
|
||||
data class Group(
|
||||
val title: String,
|
||||
val editable: Boolean = false,
|
||||
val fields: List<FieldUio>,
|
||||
)
|
||||
|
||||
companion object {
|
||||
val Default = run {
|
||||
val strField = FieldUio.create(label = "Force", valuePlaceHolder = { "0" })
|
||||
fun str(): Int = strField.value.value.toIntOrNull() ?: 0
|
||||
val dexField = FieldUio.create(label = "Dextérité", valuePlaceHolder = { "0" })
|
||||
fun dex(): Int = dexField.value.value.toIntOrNull() ?: 0
|
||||
val conField = FieldUio.create(label = "Constitution", valuePlaceHolder = { "0" })
|
||||
fun con(): Int = conField.value.value.toIntOrNull() ?: 0
|
||||
val vitField = FieldUio.create(label = "Taille", valuePlaceHolder = { "0" })
|
||||
fun vit(): Int = vitField.value.value.toIntOrNull() ?: 0
|
||||
val intField = FieldUio.create(label = "Intelligence", valuePlaceHolder = { "0" })
|
||||
fun int(): Int = intField.value.value.toIntOrNull() ?: 0
|
||||
val powField = FieldUio.create(label = "Pouvoir", valuePlaceHolder = { "0" })
|
||||
fun pow(): Int = powField.value.value.toIntOrNull() ?: 0
|
||||
val chaField = FieldUio.create(label = "Charisme", valuePlaceHolder = { "0" })
|
||||
fun cha(): Int = chaField.value.value.toIntOrNull() ?: 0
|
||||
|
||||
CharacterSheetEditUio(
|
||||
name = FieldUio.create(
|
||||
useLabelAsPlaceholder = true,
|
||||
label = "Name",
|
||||
),
|
||||
groups = listOf(
|
||||
Group(
|
||||
title = "Charactéristiques",
|
||||
fields = listOf(
|
||||
strField,
|
||||
dexField,
|
||||
conField,
|
||||
vitField,
|
||||
intField,
|
||||
powField,
|
||||
chaField
|
||||
),
|
||||
),
|
||||
Group(
|
||||
title = "Charactéristiques dérivées",
|
||||
fields = listOf(
|
||||
FieldUio.create(
|
||||
label = "Déplacement",
|
||||
valuePlaceHolder = { "10" },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Points de vie",
|
||||
valuePlaceHolder = { "${(con() + vit()) / 2}" },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Points de pouvoir",
|
||||
valuePlaceHolder = { "${pow()}" },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Bonus aux dégats",
|
||||
valuePlaceHolder = {
|
||||
val bonus = str() + vit()
|
||||
when {
|
||||
bonus < 12 -> "-1d6"
|
||||
bonus in 12..17 -> "-1d4"
|
||||
bonus in 18..22 -> "-0"
|
||||
bonus in 23..29 -> "1d4"
|
||||
bonus in 30..39 -> "1d6"
|
||||
else -> "2d6"
|
||||
}
|
||||
},
|
||||
),
|
||||
FieldUio.create(label = "Armure", valuePlaceHolder = { "0" }),
|
||||
),
|
||||
),
|
||||
Group(
|
||||
title = "Compétances",
|
||||
editable = true,
|
||||
fields = listOf(
|
||||
FieldUio.create(
|
||||
label = "Bagarre",
|
||||
valuePlaceHolder = { trunc(dex() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Esquive",
|
||||
valuePlaceHolder = { trunc(dex() * 2) }
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Saisie",
|
||||
valuePlaceHolder = { trunc(str() + vit()) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Lancer",
|
||||
valuePlaceHolder = { trunc(str() + dex()) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Athlétisme",
|
||||
valuePlaceHolder = { trunc(str() + con() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Acrobatie",
|
||||
valuePlaceHolder = { trunc(dex() + con() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Perception",
|
||||
valuePlaceHolder = { trunc(10 + int() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Recherche",
|
||||
valuePlaceHolder = { trunc(10 + int() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Empathie",
|
||||
valuePlaceHolder = { trunc(cha() + int()) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Persuasion",
|
||||
valuePlaceHolder = { trunc(cha() * 3) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Intimidation",
|
||||
valuePlaceHolder = { trunc(cha() + max(pow(), vit()) * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Baratin",
|
||||
valuePlaceHolder = { trunc(cha() * 2 + int()) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Marchandage",
|
||||
valuePlaceHolder = { trunc(cha() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Discrétion",
|
||||
valuePlaceHolder = { trunc(cha() + dex() * 2 - vit()) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Escamotage",
|
||||
valuePlaceHolder = { trunc(dex() * 2) },
|
||||
),
|
||||
FieldUio.create(
|
||||
label = "Premiers soins",
|
||||
valuePlaceHolder = { trunc(int() + dex()) },
|
||||
),
|
||||
),
|
||||
),
|
||||
Group(
|
||||
title = "Occupations",
|
||||
editable = true,
|
||||
fields = emptyList(),
|
||||
),
|
||||
Group(
|
||||
title = "Compétences magiques",
|
||||
editable = true,
|
||||
fields = emptyList(),
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun create(sheet: CharacterSheetUio): CharacterSheetEditUio {
|
||||
return CharacterSheetEditUio(
|
||||
name = FieldUio.create(
|
||||
useLabelAsPlaceholder = true,
|
||||
label = "Name",
|
||||
initialValue = sheet.name,
|
||||
),
|
||||
groups = listOf(
|
||||
Group(
|
||||
title = "Charactéristiques",
|
||||
fields = sheet.characteristics.map {
|
||||
FieldUio.create(
|
||||
label = it.label,
|
||||
initialValue = it.value,
|
||||
)
|
||||
},
|
||||
),
|
||||
Group(
|
||||
title = "Charactéristiques dérivées",
|
||||
fields = sheet.subCharacteristics.map {
|
||||
FieldUio.create(
|
||||
label = it.label,
|
||||
initialValue = it.value,
|
||||
)
|
||||
},
|
||||
),
|
||||
Group(
|
||||
title = "Compétances",
|
||||
fields = sheet.skills.map {
|
||||
FieldUio.create(
|
||||
label = it.label,
|
||||
initialValue = "${it.value}",
|
||||
)
|
||||
},
|
||||
),
|
||||
Group(
|
||||
title = "Occupations",
|
||||
editable = true,
|
||||
fields = sheet.occupations.map {
|
||||
FieldUio.create(
|
||||
label = it.label,
|
||||
initialValue = "${it.value}",
|
||||
)
|
||||
},
|
||||
),
|
||||
Group(
|
||||
title = "Compétences magiques",
|
||||
editable = true,
|
||||
fields = sheet.magics.map {
|
||||
FieldUio.create(
|
||||
label = it.label,
|
||||
initialValue = "${it.value}",
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun trunc(value: Int): String {
|
||||
return "${(truncate(value.toFloat() / 5f) * 5f).toInt()}"
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetEdit(
|
||||
form: CharacterSheetEditUio,
|
||||
onSkill: (CharacterSheetEditUio.Group) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(all = 24.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp)
|
||||
) {
|
||||
Form(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
field = form.name,
|
||||
)
|
||||
|
||||
form.groups.forEach {
|
||||
DecoratedBox(
|
||||
modifier = Modifier.animateContentSize(),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = it.title,
|
||||
)
|
||||
it.fields.forEach {
|
||||
Form(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
field = it,
|
||||
)
|
||||
}
|
||||
if (it.editable) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(
|
||||
space = 8.dp,
|
||||
alignment = Alignment.End
|
||||
)
|
||||
) {
|
||||
Button(
|
||||
colors = ButtonDefaults.textButtonColors(),
|
||||
onClick = { onSkill(it) },
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = "Ajouter une ligne",
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.pixelized.desktop.lwa.screen.characterSheet.edit
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Stable
|
||||
open class FieldUio(
|
||||
val useLabelAsPlaceholder: Boolean,
|
||||
val label: State<String>,
|
||||
val onLabelChange: (String) -> Unit,
|
||||
val valuePlaceHolder: State<String>,
|
||||
val value: State<String>,
|
||||
val onValueChange: (String) -> Unit,
|
||||
) {
|
||||
companion object {
|
||||
@Stable
|
||||
fun create(
|
||||
useLabelAsPlaceholder: Boolean = false,
|
||||
label: String = "",
|
||||
initialValue: String = "",
|
||||
valuePlaceHolder: () -> String = { "" },
|
||||
): FieldUio {
|
||||
val labelState = mutableStateOf(label)
|
||||
val valueState = mutableStateOf(initialValue)
|
||||
return FieldUio(
|
||||
useLabelAsPlaceholder = useLabelAsPlaceholder,
|
||||
label = labelState,
|
||||
onLabelChange = { labelState.value = it },
|
||||
valuePlaceHolder = derivedStateOf(valuePlaceHolder),
|
||||
value = valueState,
|
||||
onValueChange = { valueState.value = it },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Form(
|
||||
modifier: Modifier = Modifier,
|
||||
field: FieldUio,
|
||||
) {
|
||||
val focus = LocalFocusManager.current
|
||||
|
||||
AnimatedContent(
|
||||
targetState = field.useLabelAsPlaceholder,
|
||||
transitionSpec = { fadeIn() togetherWith fadeOut() }
|
||||
) {
|
||||
when (it) {
|
||||
true -> {
|
||||
TextField(
|
||||
modifier = modifier,
|
||||
value = field.value.value,
|
||||
label = { Text(text = field.label.value) },
|
||||
singleLine = true,
|
||||
keyboardActions = KeyboardActions { focus.moveFocus(FocusDirection.Next) },
|
||||
onValueChange = field.onValueChange,
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
TextField(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
value = field.label.value,
|
||||
placeholder = { Text(text = "Nom") },
|
||||
singleLine = true,
|
||||
keyboardActions = KeyboardActions { focus.moveFocus(FocusDirection.Next) },
|
||||
onValueChange = field.onLabelChange,
|
||||
)
|
||||
TextField(
|
||||
modifier = Modifier.width(width = 80.dp),
|
||||
value = field.value.value,
|
||||
placeholder = { Text(text = field.valuePlaceHolder.value) },
|
||||
singleLine = true,
|
||||
keyboardActions = KeyboardActions { focus.moveFocus(FocusDirection.Next) },
|
||||
onValueChange = field.onValueChange,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue