Minor UI adjustment.
This commit is contained in:
parent
ca456b55d9
commit
f6d026d50f
11 changed files with 3907 additions and 329 deletions
|
|
@ -75,6 +75,11 @@
|
|||
<string name="character_sheet__occupations_title">Occupations</string>
|
||||
<string name="character_sheet__magics__title">Compétences magiques</string>
|
||||
|
||||
<string name="character_sheet__delete_dialog__title">Supprimer la feuille de personnage</string>
|
||||
<string name="character_sheet__delete_dialog__description">Êtes-vous sûr de vouloir supprimer "%1$s" ?</string>
|
||||
<string name="character_sheet__delete_dialog__confirm_action">Confirmer</string>
|
||||
<string name="character_sheet__delete_dialog__cancel_action">Annuler</string>
|
||||
|
||||
<string name="network__title">Configuration de la table</string>
|
||||
<string name="network__player_name__label">Nom du joueur</string>
|
||||
<string name="network__host__label">host</string>
|
||||
|
|
|
|||
|
|
@ -1,95 +1,67 @@
|
|||
package com.pixelized.desktop.lwa.business
|
||||
|
||||
import androidx.compose.ui.util.fastRoundToInt
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.round
|
||||
|
||||
object SkillStepUseCase {
|
||||
val NONE: IntRange = -1..-1
|
||||
|
||||
data class SkillStep(
|
||||
val criticalSuccessRange: IntRange,
|
||||
val specialSuccessRange: IntRange,
|
||||
val successRange: IntRange,
|
||||
val failureRange: IntRange,
|
||||
val criticalFailureRange: IntRange,
|
||||
) {
|
||||
constructor(
|
||||
criticalSuccess: Pair<Int, Int>?,
|
||||
specialSuccess: Pair<Int, Int>,
|
||||
success: Pair<Int, Int>,
|
||||
failure: Pair<Int, Int>?,
|
||||
criticalFailure: Pair<Int, Int>,
|
||||
) : this(
|
||||
criticalSuccessRange = criticalSuccess
|
||||
?.let { IntRange(it.first, it.second) }
|
||||
?: IntRange(-1, -1),
|
||||
specialSuccessRange = specialSuccess
|
||||
.let { IntRange(it.first, it.second) },
|
||||
successRange = success
|
||||
.let { IntRange(it.first, it.second) },
|
||||
failureRange = failure
|
||||
?.let { IntRange(it.first, it.second) } ?: IntRange(-1, -1),
|
||||
criticalFailureRange = criticalFailure
|
||||
.let { IntRange(it.first, it.second) },
|
||||
)
|
||||
}
|
||||
val criticalSuccess: IntRange,
|
||||
val specialSuccess: IntRange,
|
||||
val success: IntRange,
|
||||
val failure: IntRange,
|
||||
val criticalFailure: IntRange,
|
||||
)
|
||||
|
||||
/**
|
||||
* Helper method to compute the range in which a roll is a either critical, special, success or failure.
|
||||
* TODO : test.
|
||||
*/
|
||||
fun computeSkillStep(skill: Int): SkillStep {
|
||||
val criticalSuccess: Pair<Int, Int>? = when (skill) {
|
||||
in (0..5) -> null
|
||||
in (10..25) -> 1 to 1
|
||||
in (30..45) -> 1 to 2
|
||||
in (50..65) -> 1 to 3
|
||||
in (70..85) -> 1 to 4
|
||||
in (90..100) -> 1 to 5
|
||||
else -> 1 to skill * 5 / 100
|
||||
}
|
||||
val specialSuccess: Pair<Int, Int> = when (skill) {
|
||||
0, 5 -> 1 to 1
|
||||
10 -> 2 to 2
|
||||
15 -> ((criticalSuccess?.second ?: 0) + 1) to 3
|
||||
20 -> ((criticalSuccess?.second ?: 0) + 1) to 4
|
||||
25 -> ((criticalSuccess?.second ?: 0) + 1) to 5
|
||||
30 -> ((criticalSuccess?.second ?: 0) + 1) to 6
|
||||
35 -> ((criticalSuccess?.second ?: 0) + 1) to 7
|
||||
40 -> ((criticalSuccess?.second ?: 0) + 1) to 8
|
||||
45 -> ((criticalSuccess?.second ?: 0) + 1) to 9
|
||||
50 -> ((criticalSuccess?.second ?: 0) + 1) to 10
|
||||
55 -> ((criticalSuccess?.second ?: 0) + 1) to 11
|
||||
60 -> ((criticalSuccess?.second ?: 0) + 1) to 12
|
||||
65 -> ((criticalSuccess?.second ?: 0) + 1) to 13
|
||||
70 -> ((criticalSuccess?.second ?: 0) + 1) to 14
|
||||
75 -> ((criticalSuccess?.second ?: 0) + 1) to 15
|
||||
80 -> ((criticalSuccess?.second ?: 0) + 1) to 16
|
||||
85 -> ((criticalSuccess?.second ?: 0) + 1) to 17
|
||||
90 -> ((criticalSuccess?.second ?: 0) + 1) to 18
|
||||
95 -> ((criticalSuccess?.second ?: 0) + 1) to 19
|
||||
100 -> ((criticalSuccess?.second ?: 0) + 1) to 20
|
||||
else -> ((criticalSuccess?.second ?: 0) + 1) to skill * 20 / 100
|
||||
}
|
||||
val success: Pair<Int, Int> = (specialSuccess.second + 1) to max(5, min(99, skill))
|
||||
val criticalFailure: Pair<Int, Int> = when (skill) {
|
||||
0, 5, 10 -> 96 to 100
|
||||
15, 20, 25, 30 -> 97 to 100
|
||||
35, 40, 45, 50 -> 98 to 100
|
||||
55, 60, 65, 70 -> 99 to 100
|
||||
else -> 100 to 100
|
||||
}
|
||||
val failure: Pair<Int, Int>? = if (skill >= 100) {
|
||||
null
|
||||
} else {
|
||||
success.second + 1 to criticalFailure.first - 1
|
||||
}
|
||||
val criticalSuccess = 1..min(roundToInt { skill * 0.05f }, 99)
|
||||
val specialSuccess = (roundToInt { skill * 0.05f } + 1)..min(roundToInt { skill * 0.2f }, 99)
|
||||
val success = (roundToInt { skill * 0.2f } + 1)..min(skill, 99)
|
||||
val criticalFailure = 100 - max(4 - criticalSuccess.last, 0)..100
|
||||
val failure = (success.last + 1) until criticalFailure.first
|
||||
|
||||
return SkillStep(
|
||||
criticalSuccess = criticalSuccess,
|
||||
specialSuccess = specialSuccess,
|
||||
success = success,
|
||||
failure = failure,
|
||||
criticalFailure = criticalFailure,
|
||||
criticalSuccess = criticalSuccess.takeIf { it.first <= it.last } ?: NONE,
|
||||
specialSuccess = specialSuccess.takeIf { it.first <= it.last } ?: NONE,
|
||||
success = success.takeIf { it.first <= it.last } ?: NONE,
|
||||
failure = failure.takeIf { it.first <= it.last } ?: NONE,
|
||||
criticalFailure = criticalFailure.takeIf { it.first <= it.last } ?: NONE,
|
||||
)
|
||||
}
|
||||
|
||||
private inline fun roundToInt(block: () -> Float): Int = round(block()).fastRoundToInt()
|
||||
|
||||
fun exportWiki() {
|
||||
fun print(range: IntRange): String = when {
|
||||
range == NONE -> "-"
|
||||
range.first == range.last -> "${range.first}"
|
||||
else -> "${range.first} - ${range.last}"
|
||||
}
|
||||
repeat(100) { skill ->
|
||||
val step = computeSkillStep(skill + 1)
|
||||
println(
|
||||
"|!${skill + 1} " +
|
||||
"|${print(step.criticalSuccess)} " +
|
||||
"|${print(step.specialSuccess)} " +
|
||||
"|${print(step.success)} " +
|
||||
"|${print(step.failure)} " +
|
||||
"|${print(step.criticalFailure)} " +
|
||||
"|"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun exportTest() {
|
||||
println("val expected = hashMapOf(")
|
||||
(1..500).forEach {
|
||||
println(" $it to ${computeSkillStep(it)},")
|
||||
}
|
||||
println(")")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
package com.pixelized.desktop.lwa.screen.characterSheet.detail
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SizeTransform
|
||||
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.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__cancel_action
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__confirm_action
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__title
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
private val DefaultScrimColor = Color.Black.copy(alpha = 0.6f)
|
||||
|
||||
@Stable
|
||||
data class CharacterSheetDeleteConfirmationDialogUio(
|
||||
val id: String,
|
||||
val name: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetDeleteConfirmationDialog(
|
||||
dialog: State<CharacterSheetDeleteConfirmationDialogUio?>,
|
||||
onConfirm: (CharacterSheetDeleteConfirmationDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = dialog.value != null,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(color = DefaultScrimColor),
|
||||
)
|
||||
}
|
||||
AnimatedContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
targetState = dialog.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 32 }
|
||||
val exit = fadeOut() + slideOutVertically { 32 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
when (it) {
|
||||
null -> Box(
|
||||
modifier = Modifier,
|
||||
)
|
||||
|
||||
else -> Dialog(
|
||||
dialog = it,
|
||||
onConfirm = onConfirm,
|
||||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Dialog(
|
||||
dialog: CharacterSheetDeleteConfirmationDialogUio,
|
||||
onConfirm: (CharacterSheetDeleteConfirmationDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = onDismissRequest,
|
||||
)
|
||||
.fillMaxSize()
|
||||
.padding(all = 32.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Surface(
|
||||
shape = remember { RoundedCornerShape(size = 16.dp) },
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 24.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(top = 24.dp),
|
||||
style = MaterialTheme.typography.h6,
|
||||
text = stringResource(Res.string.character_sheet__delete_dialog__title),
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp),
|
||||
style = MaterialTheme.typography.body1,
|
||||
text = stringResource(
|
||||
Res.string.character_sheet__delete_dialog__description,
|
||||
dialog.name
|
||||
),
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 4.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(
|
||||
space = 4.dp,
|
||||
alignment = Alignment.End
|
||||
)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.character_sheet__delete_dialog__cancel_action)
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
onClick = { onConfirm(dialog) },
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.character_sheet__delete_dialog__confirm_action)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -71,6 +71,7 @@ class CharacterSheetFactory {
|
|||
Node(
|
||||
label = it.label,
|
||||
value = it.value,
|
||||
used = it.used,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -81,6 +82,7 @@ class CharacterSheetFactory {
|
|||
Node(
|
||||
label = it.label,
|
||||
value = it.value,
|
||||
used = it.used,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
@ -91,6 +93,7 @@ class CharacterSheetFactory {
|
|||
Node(
|
||||
label = it.label,
|
||||
value = it.value,
|
||||
used = it.used,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.Row
|
|||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
|
|
@ -16,6 +17,7 @@ import androidx.compose.foundation.layout.width
|
|||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.CheckboxDefaults
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
|
|
@ -76,6 +78,7 @@ data class CharacterSheetPageUio(
|
|||
data class Node(
|
||||
val label: String,
|
||||
val value: Int,
|
||||
val used: Boolean,
|
||||
)
|
||||
|
||||
@Stable
|
||||
|
|
@ -120,12 +123,7 @@ fun CharacterSheetPage(
|
|||
)
|
||||
},
|
||||
onDelete = {
|
||||
scope.launch {
|
||||
viewModel.deleteCharacter(id = sheet.id)
|
||||
if (screen.popBackStack().not()) {
|
||||
window.closeWindows()
|
||||
}
|
||||
}
|
||||
viewModel.showConfirmCharacterDeletionDialog()
|
||||
},
|
||||
onCharacteristic = { characteristic ->
|
||||
rollViewModel.prepareRoll(
|
||||
|
|
@ -138,6 +136,7 @@ fun CharacterSheetPage(
|
|||
rollViewModel.prepareRoll(sheet = sheet, node = node)
|
||||
overlayViewModel.show()
|
||||
},
|
||||
onUseSkill = viewModel::onUseSkill,
|
||||
onRoll = { roll ->
|
||||
rollViewModel.prepareRoll(sheet = sheet, roll = roll)
|
||||
overlayViewModel.show()
|
||||
|
|
@ -147,6 +146,21 @@ fun CharacterSheetPage(
|
|||
},
|
||||
)
|
||||
}
|
||||
|
||||
CharacterSheetDeleteConfirmationDialog(
|
||||
dialog = viewModel.displayDeleteConfirmationDialog,
|
||||
onConfirm = {
|
||||
scope.launch {
|
||||
viewModel.deleteCharacter(id = it.id)
|
||||
if (screen.popBackStack().not()) {
|
||||
window.closeWindows()
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
viewModel.hideConfirmCharacterDeletionDialog()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
@ -158,6 +172,7 @@ fun CharacterSheetPageContent(
|
|||
onDelete: () -> Unit,
|
||||
onCharacteristic: (characteristic: CharacterSheetPageUio.Characteristic) -> Unit,
|
||||
onSkill: (skill: CharacterSheetPageUio.Node) -> Unit,
|
||||
onUseSkill: (skill: CharacterSheetPageUio.Node) -> Unit,
|
||||
onRoll: (roll: CharacterSheetPageUio.Roll) -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
|
|
@ -238,7 +253,7 @@ fun CharacterSheetPageContent(
|
|||
)
|
||||
characterSheet.subCharacteristics.forEach {
|
||||
Characteristics(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
modifier = Modifier.cell(),
|
||||
characteristic = it,
|
||||
)
|
||||
}
|
||||
|
|
@ -258,12 +273,12 @@ fun CharacterSheetPageContent(
|
|||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__skills__title),
|
||||
)
|
||||
characterSheet.skills.forEach {
|
||||
characterSheet.skills.forEach { skill ->
|
||||
Skill(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = it.label,
|
||||
value = it.value,
|
||||
onClick = { onSkill(it) },
|
||||
modifier = Modifier.cell(),
|
||||
node = skill,
|
||||
onClick = { onSkill(skill) },
|
||||
onUse = { onUseSkill(skill) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -280,12 +295,12 @@ fun CharacterSheetPageContent(
|
|||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__occupations_title),
|
||||
)
|
||||
characterSheet.occupations.forEach {
|
||||
characterSheet.occupations.forEach { occupation ->
|
||||
Skill(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = it.label,
|
||||
value = it.value,
|
||||
onClick = { onSkill(it) },
|
||||
modifier = Modifier.cell(),
|
||||
node = occupation,
|
||||
onClick = { onSkill(occupation) },
|
||||
onUse = { onUseSkill(occupation) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -302,21 +317,21 @@ fun CharacterSheetPageContent(
|
|||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__magics__title),
|
||||
)
|
||||
characterSheet.magics.forEach {
|
||||
characterSheet.magics.forEach { magic ->
|
||||
Skill(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = it.label,
|
||||
value = it.value,
|
||||
onClick = { onSkill(it) },
|
||||
modifier = Modifier.cell(),
|
||||
node = magic,
|
||||
onClick = { onSkill(magic) },
|
||||
onUse = { onUseSkill(magic) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
characterSheet.rolls.forEach {
|
||||
characterSheet.rolls.forEach { roll ->
|
||||
Roll(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = it.label,
|
||||
onClick = { onRoll(it) },
|
||||
modifier = Modifier.cell(),
|
||||
label = roll.label,
|
||||
onClick = { onRoll(roll) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -381,9 +396,49 @@ private fun Characteristics(
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Roll(
|
||||
private fun Skill(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(horizontal = 8.dp),
|
||||
node: CharacterSheetPageUio.Node,
|
||||
onClick: () -> Unit,
|
||||
onUse: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.padding(paddingValues = paddingValues)
|
||||
.then(other = modifier),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = node.label
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = "${node.value}",
|
||||
)
|
||||
Checkbox(
|
||||
modifier = Modifier.size(size = 32.dp),
|
||||
checked = node.used,
|
||||
colors = CheckboxDefaults.colors(
|
||||
checkedColor = MaterialTheme.colors.primary,
|
||||
),
|
||||
onCheckedChange = { onUse() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Roll(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(start = 10.dp, end = 14.dp),
|
||||
label: String,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
|
|
@ -403,6 +458,7 @@ private fun Roll(
|
|||
text = label
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 24.dp),
|
||||
painter = painterResource(Res.drawable.ic_d20_32dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
|
|
@ -410,35 +466,4 @@ private fun Roll(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Skill(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(horizontal = 8.dp),
|
||||
label: String,
|
||||
value: Any,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.padding(paddingValues = paddingValues)
|
||||
.then(other = modifier),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = label
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = "$value",
|
||||
)
|
||||
Checkbox(modifier = Modifier.size(size = 32.dp), checked = false, onCheckedChange = { })
|
||||
}
|
||||
}
|
||||
private fun Modifier.cell(): Modifier = this.fillMaxWidth().height(height = 32.dp)
|
||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.desktop.lwa.screen.characterSheet.detail
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetDestination
|
||||
|
|
@ -18,6 +19,11 @@ class CharacterSheetViewModel(
|
|||
private val repository = CharacterSheetRepository
|
||||
private val factory = CharacterSheetFactory()
|
||||
|
||||
private val _displayDeleteConfirmationDialog =
|
||||
mutableStateOf<CharacterSheetDeleteConfirmationDialogUio?>(null)
|
||||
val displayDeleteConfirmationDialog: State<CharacterSheetDeleteConfirmationDialogUio?>
|
||||
get() = _displayDeleteConfirmationDialog
|
||||
|
||||
val sheet: State<CharacterSheetPageUio?>
|
||||
@Composable
|
||||
@Stable
|
||||
|
|
@ -32,4 +38,40 @@ class CharacterSheetViewModel(
|
|||
suspend fun deleteCharacter(id: String) {
|
||||
repository.delete(id = id)
|
||||
}
|
||||
|
||||
fun onUseSkill(skill: CharacterSheetPageUio.Node) {
|
||||
repository.characterSheetFlow(id = argument.id).value?.let { sheet ->
|
||||
|
||||
val skills = sheet.skills.map {
|
||||
if (it.label == skill.label) it.copy(used = it.used.not()) else it
|
||||
}
|
||||
val occupations = sheet.occupations.map {
|
||||
if (it.label == skill.label) it.copy(used = it.used.not()) else it
|
||||
}
|
||||
val magics = sheet.magics.map {
|
||||
if (it.label == skill.label) it.copy(used = it.used.not()) else it
|
||||
}
|
||||
|
||||
repository.save(
|
||||
characterSheet = sheet.copy(
|
||||
skills = skills,
|
||||
occupations = occupations,
|
||||
magics = magics,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun showConfirmCharacterDeletionDialog() {
|
||||
repository.characterSheetFlow(id = argument.id).value?.let { sheet ->
|
||||
_displayDeleteConfirmationDialog.value = CharacterSheetDeleteConfirmationDialogUio(
|
||||
id = sheet.id,
|
||||
name = sheet.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideConfirmCharacterDeletionDialog() {
|
||||
_displayDeleteConfirmationDialog.value = null
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.pixelized.desktop.lwa.screen.roll
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
|
|
@ -16,6 +18,7 @@ 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.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
|
|
@ -146,8 +149,8 @@ fun RollPage(
|
|||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 32 }
|
||||
val exit = fadeOut() + slideOutVertically { -32 }
|
||||
enter togetherWith exit
|
||||
}
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
) { label ->
|
||||
Text(
|
||||
modifier = Modifier.width(width = 128.dp),
|
||||
|
|
@ -222,25 +225,34 @@ fun Difficulty(
|
|||
style = MaterialTheme.typography.body1,
|
||||
text = stringResource(Res.string.roll_page__dc__label)
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.body1,
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = when (difficulty.difficulty) {
|
||||
Difficulty.EASY -> stringResource(Res.string.roll_page__dc_easy__label)
|
||||
Difficulty.NORMAL -> stringResource(Res.string.roll_page__dc_normal__label)
|
||||
Difficulty.HARD -> stringResource(Res.string.roll_page__dc_hard__label)
|
||||
Difficulty.IMPOSSIBLE -> stringResource(Res.string.roll_page__dc_impossible__label)
|
||||
}
|
||||
)
|
||||
AnimatedContent(
|
||||
targetState = difficulty.difficulty,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { -16 }
|
||||
val exit = fadeOut() + slideOutVertically { 16 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
) { difficulty ->
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline().animateContentSize(),
|
||||
style = MaterialTheme.typography.body1,
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = when (difficulty) {
|
||||
Difficulty.EASY -> stringResource(Res.string.roll_page__dc_easy__label)
|
||||
Difficulty.NORMAL -> stringResource(Res.string.roll_page__dc_normal__label)
|
||||
Difficulty.HARD -> stringResource(Res.string.roll_page__dc_hard__label)
|
||||
Difficulty.IMPOSSIBLE -> stringResource(Res.string.roll_page__dc_impossible__label)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
val rotation = animateFloatAsState(
|
||||
targetValue = if (difficulty.open) -180f else 0f,
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier.graphicsLayer {
|
||||
rotationZ = rotation.value
|
||||
},
|
||||
modifier = Modifier
|
||||
.offset(x = (-12).dp)
|
||||
.graphicsLayer { rotationZ = rotation.value },
|
||||
imageVector = Icons.Default.ArrowDropDown,
|
||||
contentDescription = null
|
||||
)
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class RollViewModel : ViewModel() {
|
|||
_rollResult.value = null
|
||||
_rollTitle.value = RollTitleUio(
|
||||
label = label,
|
||||
value = rollStep?.successRange?.last
|
||||
value = rollStep?.success?.last
|
||||
)
|
||||
_rollDifficulty.value = rollSuccessValue?.let {
|
||||
DifficultyUio(
|
||||
|
|
@ -151,11 +151,11 @@ class RollViewModel : ViewModel() {
|
|||
}
|
||||
val success = rollStep?.let {
|
||||
when (roll) {
|
||||
in it.criticalSuccessRange -> getString(resource = Res.string.roll_page__critical_success)
|
||||
in it.specialSuccessRange -> getString(resource = Res.string.roll_page__special_success)
|
||||
in it.successRange -> getString(resource = Res.string.roll_page__success)
|
||||
in it.failureRange -> getString(resource = Res.string.roll_page__failure)
|
||||
in it.criticalFailureRange -> getString(resource = Res.string.roll_page__critical_failure)
|
||||
in it.criticalSuccess -> getString(resource = Res.string.roll_page__critical_success)
|
||||
in it.specialSuccess -> getString(resource = Res.string.roll_page__special_success)
|
||||
in it.success -> getString(resource = Res.string.roll_page__success)
|
||||
in it.failure -> getString(resource = Res.string.roll_page__failure)
|
||||
in it.criticalFailure -> getString(resource = Res.string.roll_page__critical_failure)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
|
@ -175,7 +175,7 @@ class RollViewModel : ViewModel() {
|
|||
else -> null
|
||||
},
|
||||
rollValue = roll,
|
||||
rollSuccessLimit = rollStep?.successRange?.last,
|
||||
rollSuccessLimit = rollStep?.success?.last,
|
||||
resultLabel = success,
|
||||
)
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ class RollViewModel : ViewModel() {
|
|||
)
|
||||
}
|
||||
_rollTitle.value = _rollTitle.value.copy(
|
||||
value = rollStep?.successRange?.last
|
||||
value = rollStep?.success?.last
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ fun RollHistoryItem(
|
|||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
style = MaterialTheme.typography.h5,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = "${roll.rollValue}",
|
||||
)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,8 +1,12 @@
|
|||
package com.pixelized.desktop.lwa
|
||||
|
||||
import androidx.compose.ui.window.application
|
||||
import com.pixelized.desktop.lwa.business.SkillStepUseCase
|
||||
|
||||
fun main() {
|
||||
|
||||
SkillStepUseCase.exportTest()
|
||||
|
||||
application {
|
||||
App()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue