Add quality of life (icons, formula instead of plain Ints)

This commit is contained in:
Thomas Andres Gomez 2024-11-29 15:12:42 +01:00
parent 8884d047a6
commit f99a938e64
16 changed files with 235 additions and 145 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp" android:width="24dp"
android:height="32dp" android:height="24dp"
android:viewportWidth="1024" android:viewportWidth="1024"
android:viewportHeight="1024"> android:viewportHeight="1024">

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="#000000"
android:pathData="M14 2H6c-1.1 0-1.99 0.9 -1.99 2L4 20c0 1.1 0.89 2 1.99 2H18c1.1 0 2-0.9 2-2V8l-6-6zm2 16H8v-2h8v2zm0-4H8v-2h8v2zm-3-5V3.5L18.5 9H13z" />
</vector>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M0 0h24v24H0z" />
<path
android:fillColor="#000000"
android:pathData="M20 6h-8l-2-2H4c-1.1 0-1.99 0.9 -1.99 2L2 18c0 1.1 0.9 2 2 2h16c1.1 0 2-0.9 2-2V8c0-1.1-0.9-2-2-2zm0 12H4V8h16v10z" />
</vector>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp" android:width="24dp"
android:height="32dp" android:height="24dp"
android:viewportWidth="512" android:viewportWidth="512"
android:viewportHeight="512"> android:viewportHeight="512">

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
<path
android:fillColor="#000000"
android:pathData="M21.96,9.73l-1.43-5C20.41,4.3,20.02,4,19.57,4H4.43C3.98,4,3.59,4.3,3.47,4.73l-1.43,5C1.86,10.36,2.34,11,3,11h2.2L4,20 h2l0.67-5h10.67L18,20h2l-1.2-9H21C21.66,11,22.14,10.36,21.96,9.73z M6.93,13l0.27-2h9.6l0.27,2H6.93z" />
</vector>

View file

@ -14,45 +14,31 @@ class SkillValueComputationUseCase(
skill: CharacterSheet.Skill, skill: CharacterSheet.Skill,
diminished: Int, diminished: Int,
): Int { ): Int {
val baseSum = arithmeticParser.parse(skill.base).sumOf { instruction -> val base: Int = arithmeticParser.parse(skill.base).compute(sheet = sheet).let {
when (instruction) { when (skill.occupation) {
is Instruction.Dice -> 0 true -> max(MIN_OCCUPATION_VALUE, it)
else -> it
is Instruction.Flat -> { }
instruction.value
}
is Instruction.Word -> {
when (instruction.type) {
Instruction.Word.Type.BDC -> 0
Instruction.Word.Type.BDD -> 0
Instruction.Word.Type.STR -> sheet.strength
Instruction.Word.Type.DEX -> sheet.dexterity
Instruction.Word.Type.CON -> sheet.constitution
Instruction.Word.Type.HEI -> sheet.height
Instruction.Word.Type.INT -> sheet.intelligence
Instruction.Word.Type.POW -> sheet.power
Instruction.Word.Type.CHA -> sheet.charisma
}
}
} * instruction.sign
} }
val bonus = skill.bonus?.let(arithmeticParser::parse)?.compute(sheet = sheet) ?: 0
val level = skill.level?.let(arithmeticParser::parse)?.compute(sheet = sheet) ?: 0
val base = if (skill.occupation) { return max(base + bonus + level - diminished, 0)
max(MIN_OCCUPATION_VALUE, baseSum)
} else {
baseSum
}
return max(base + (skill.bonus ?: 0) + (skill.level ?: 0) - diminished, 0)
} }
fun computeRoll( fun computeRoll(
sheet: CharacterSheet, sheet: CharacterSheet,
roll: String, roll: String,
): Int { // TODO Roll detail instead of an simple Int. ): Int {
return arithmeticParser.parse(value = roll).compute(sheet = sheet)
}
// TODO return RollDetail instance instead of an simple Int.
private fun List<Instruction>.compute(
sheet: CharacterSheet,
): Int {
print("Roll ->") print("Roll ->")
return arithmeticParser.parse(roll).sumOf { instruction -> return sumOf { instruction ->
print(" ($instruction):") print(" ($instruction):")
val value = when (instruction) { val value = when (instruction) {
is Instruction.Dice -> rollUseCase.roll(dice = instruction) is Instruction.Dice -> rollUseCase.roll(dice = instruction)
@ -99,7 +85,9 @@ class SkillValueComputationUseCase(
} }
(value * instruction.sign).also { print("$it") } (value * instruction.sign).also { print("$it") }
}.also { println() } }.also {
println()
}
} }
companion object { companion object {

View file

@ -36,8 +36,8 @@ data class CharacterSheet(
val label: String, val label: String,
val description: String?, val description: String?,
val base: String, val base: String,
val bonus: Int?, val bonus: String?,
val level: Int?, val level: String?,
val occupation: Boolean, val occupation: Boolean,
val used: Boolean, val used: Boolean,
) )
@ -66,4 +66,19 @@ data class CharacterSheet(
const val SLEIGHT_OF_HAND_ID = "SLEIGHT_OF_HAND" const val SLEIGHT_OF_HAND_ID = "SLEIGHT_OF_HAND"
const val AID_ID = "AID" const val AID_ID = "AID"
} }
object CharacteristicId {
const val STR = "STR"
const val DEX = "DEX"
const val CON = "CON"
const val HEI = "HEI"
const val INT = "INT"
const val POW = "POW"
const val CHA = "CHA"
const val MOV = "MOV"
const val HP = "HP"
const val PP = "PP"
const val DMG = "DMG"
const val ARMOR = "ARMOR"
}
} }

View file

@ -38,8 +38,8 @@ data class CharacterSheetJsonV1(
val label: String, val label: String,
val description: String?, val description: String?,
val base: String, val base: String,
val bonus: Int?, val bonus: String?,
val level: Int?, val level: String?,
val occupation: Boolean, val occupation: Boolean,
val used: Boolean, val used: Boolean,
) )

View file

@ -4,6 +4,7 @@ import com.pixelized.desktop.lwa.business.SkillValueComputationUseCase
import com.pixelized.desktop.lwa.composable.tooltip.TooltipUio import com.pixelized.desktop.lwa.composable.tooltip.TooltipUio
import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Node import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Node
import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.Res
@ -37,21 +38,19 @@ class CharacterSheetFactory(
private val skillUseCase: SkillValueComputationUseCase, private val skillUseCase: SkillValueComputationUseCase,
private val skillDescriptionFactory: SkillDescriptionFactory, private val skillDescriptionFactory: SkillDescriptionFactory,
) { ) {
companion object {
const val HP = "HP"
const val PP = "PP"
}
suspend fun convertToUio( suspend fun convertToUio(
sheet: CharacterSheet, sheet: CharacterSheet?,
diminished: Int, diminished: Int,
): CharacterSheetPageUio { ): CharacterSheetPageUio? {
if (sheet == null) return null
return CharacterSheetPageUio( return CharacterSheetPageUio(
id = sheet.id, id = sheet.id,
name = sheet.name, name = sheet.name,
characteristics = listOf( characteristics = listOf(
Characteristic( Characteristic(
id = "STR", id = CharacteristicId.STR,
label = getString(Res.string.character_sheet__characteristics__str), label = getString(Res.string.character_sheet__characteristics__str),
value = "${sheet.strength}", value = "${sheet.strength}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -61,7 +60,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "DEX", id = CharacteristicId.DEX,
label = getString(Res.string.character_sheet__characteristics__dex), label = getString(Res.string.character_sheet__characteristics__dex),
value = "${sheet.dexterity}", value = "${sheet.dexterity}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -71,7 +70,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "CON", id = CharacteristicId.CON,
label = getString(Res.string.character_sheet__characteristics__con), label = getString(Res.string.character_sheet__characteristics__con),
value = "${sheet.constitution}", value = "${sheet.constitution}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -81,7 +80,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "HEI", id = CharacteristicId.HEI,
label = getString(Res.string.character_sheet__characteristics__hei), label = getString(Res.string.character_sheet__characteristics__hei),
value = "${sheet.height}", value = "${sheet.height}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -91,7 +90,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "INT", id = CharacteristicId.INT,
label = getString(Res.string.character_sheet__characteristics__int), label = getString(Res.string.character_sheet__characteristics__int),
value = "${sheet.intelligence}", value = "${sheet.intelligence}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -101,7 +100,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "POW", id = CharacteristicId.POW,
label = getString(Res.string.character_sheet__characteristics__pow), label = getString(Res.string.character_sheet__characteristics__pow),
value = "${sheet.power}", value = "${sheet.power}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -111,7 +110,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "CHA", id = CharacteristicId.CHA,
label = getString(Res.string.character_sheet__characteristics__cha), label = getString(Res.string.character_sheet__characteristics__cha),
value = "${sheet.charisma}", value = "${sheet.charisma}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -123,7 +122,7 @@ class CharacterSheetFactory(
), ),
subCharacteristics = listOf( subCharacteristics = listOf(
Characteristic( Characteristic(
id = "MOV", id = CharacteristicId.MOV,
label = getString(Res.string.character_sheet__sub_characteristics__movement), label = getString(Res.string.character_sheet__sub_characteristics__movement),
value = "${sheet.movement}", value = "${sheet.movement}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -133,7 +132,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = HP, id = CharacteristicId.HP,
label = getString(Res.string.character_sheet__sub_characteristics__hit_point), label = getString(Res.string.character_sheet__sub_characteristics__hit_point),
value = "${sheet.currentHp}/${sheet.maxHp}", value = "${sheet.currentHp}/${sheet.maxHp}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -143,7 +142,7 @@ class CharacterSheetFactory(
editable = true, editable = true,
), ),
Characteristic( Characteristic(
id = PP, id = CharacteristicId.PP,
label = getString(Res.string.character_sheet__sub_characteristics__power_point), label = getString(Res.string.character_sheet__sub_characteristics__power_point),
value = "${sheet.currentPp}/${sheet.maxPp}", value = "${sheet.currentPp}/${sheet.maxPp}",
tooltips = TooltipUio( tooltips = TooltipUio(
@ -153,7 +152,7 @@ class CharacterSheetFactory(
editable = true, editable = true,
), ),
Characteristic( Characteristic(
id = "DMG", id = CharacteristicId.DMG,
label = getString(Res.string.character_sheet__sub_characteristics__damage_bonus), label = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
value = sheet.damageBonus, value = sheet.damageBonus,
tooltips = TooltipUio( tooltips = TooltipUio(
@ -163,7 +162,7 @@ class CharacterSheetFactory(
editable = false, editable = false,
), ),
Characteristic( Characteristic(
id = "ARMOR", id = CharacteristicId.ARMOR,
label = getString(Res.string.character_sheet__sub_characteristics__armor), label = getString(Res.string.character_sheet__sub_characteristics__armor),
value = "${sheet.armor}", value = "${sheet.armor}",
tooltips = TooltipUio( tooltips = TooltipUio(

View file

@ -77,8 +77,8 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet__skills_
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__special_title import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__special_title
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__title import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__title
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__edit__title import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__edit__title
import lwacharactersheet.composeapp.generated.resources.ic_d20_32dp import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
import lwacharactersheet.composeapp.generated.resources.ic_skull_32dp import lwacharactersheet.composeapp.generated.resources.ic_skull_24dp
import org.jetbrains.compose.resources.getString import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
@ -295,7 +295,7 @@ fun CharacterSheetPageContent(
) { ) {
Icon( Icon(
modifier = Modifier.size(size = 24.dp), modifier = Modifier.size(size = 24.dp),
painter = painterResource(Res.drawable.ic_skull_32dp), painter = painterResource(Res.drawable.ic_skull_24dp),
tint = MaterialTheme.colors.primary, tint = MaterialTheme.colors.primary,
contentDescription = null, contentDescription = null,
) )
@ -657,7 +657,7 @@ private fun Roll(
) )
Icon( Icon(
modifier = Modifier.size(size = 24.dp), modifier = Modifier.size(size = 24.dp),
painter = painterResource(Res.drawable.ic_d20_32dp), painter = painterResource(Res.drawable.ic_d20_24dp),
tint = MaterialTheme.colors.primary, tint = MaterialTheme.colors.primary,
contentDescription = null, contentDescription = null,
) )

View file

@ -1,8 +1,8 @@
package com.pixelized.desktop.lwa.screen.characterSheet.detail package com.pixelized.desktop.lwa.screen.characterSheet.detail
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
@ -11,14 +11,12 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetDestination import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.DiminishedStatDialogUio import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.StatChangeDialogUio import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.StatChangeDialogUio
import com.pixelized.desktop.lwa.utils.extention.collectAsState import com.pixelized.desktop.lwa.utils.extention.collectAsState
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet__diminished__label import lwacharactersheet.composeapp.generated.resources.character_sheet__diminished__label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__hit_point import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__hit_point
@ -49,33 +47,26 @@ class CharacterSheetViewModel(
private val _diminishedDialog = mutableStateOf<DiminishedStatDialogUio?>(null) private val _diminishedDialog = mutableStateOf<DiminishedStatDialogUio?>(null)
val diminishedDialog: State<DiminishedStatDialogUio?> get() = _diminishedDialog val diminishedDialog: State<DiminishedStatDialogUio?> get() = _diminishedDialog
private val diminishedValueFlow = repository.characterDiminishedFlow(id = argument.id)
val diminishedValue: State<Int?> val diminishedValue: State<Int?>
@Composable @Composable
@Stable get() = diminishedValueFlow.collectAsState { it ->
get() = repository it.takeIf { it > 0 }
.characterDiminishedFlow(id = argument.id) }
.collectAsState { it -> it.takeIf { it > 0 } }
private val sheetFlow = combine(
repository.characterSheetFlow(id = argument.id),
repository.characterDiminishedFlow(id = argument.id),
transform = { sheet, diminished ->
factory.convertToUio(sheet = sheet, diminished = diminished)
},
)
val sheet: State<CharacterSheetPageUio?> val sheet: State<CharacterSheetPageUio?>
@Composable @Composable
@Stable get() = sheetFlow.collectAsState(
get() = combine( initial = null,
repository.characterSheetFlow(id = argument.id), context = viewModelScope.coroutineContext,
repository.characterDiminishedFlow(id = argument.id), )
transform = { sheet, diminished -> sheet to diminished },
).stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = run {
val sheet = repository.characterSheetFlow(id = argument.id).value
val diminished = repository.characterDiminishedFlow(id = argument.id).value
sheet to diminished
}
).collectAsState { (sheet, diminished) ->
sheet?.let { model ->
runBlocking { factory.convertToUio(sheet = model, diminished = diminished) }
}
}
fun deleteCharacter(id: String) { fun deleteCharacter(id: String) {
repository.delete(id = id) repository.delete(id = id)
@ -120,14 +111,14 @@ class CharacterSheetViewModel(
suspend fun showSubCharacteristicDialog(id: String) { suspend fun showSubCharacteristicDialog(id: String) {
repository.characterSheetFlow(id = argument.id).value?.let { sheet -> repository.characterSheetFlow(id = argument.id).value?.let { sheet ->
_statChangeDialog.value = when (id) { _statChangeDialog.value = when (id) {
CharacterSheetFactory.HP -> { CharacterSheet.CharacteristicId.HP -> {
val value = mutableStateOf( val value = mutableStateOf(
"${sheet.currentHp}".let { "${sheet.currentHp}".let {
TextFieldValue(text = it, selection = TextRange(it.length)) TextFieldValue(text = it, selection = TextRange(it.length))
} }
) )
StatChangeDialogUio( StatChangeDialogUio(
id = CharacterSheetFactory.HP, id = CharacterSheet.CharacteristicId.HP,
label = getString(resource = Res.string.character_sheet_edit__sub_characteristics__hit_point), label = getString(resource = Res.string.character_sheet_edit__sub_characteristics__hit_point),
value = { value.value }, value = { value.value },
onValueChange = { value.value = it }, onValueChange = { value.value = it },
@ -135,14 +126,14 @@ class CharacterSheetViewModel(
) )
} }
CharacterSheetFactory.PP -> { CharacterSheet.CharacteristicId.PP -> {
val value = mutableStateOf( val value = mutableStateOf(
"${sheet.currentPp}".let { "${sheet.currentPp}".let {
TextFieldValue(text = it, selection = TextRange(it.length)) TextFieldValue(text = it, selection = TextRange(it.length))
} }
) )
StatChangeDialogUio( StatChangeDialogUio(
id = CharacterSheetFactory.PP, id = CharacterSheet.CharacteristicId.PP,
label = getString(resource = Res.string.character_sheet_edit__sub_characteristics__power_point), label = getString(resource = Res.string.character_sheet_edit__sub_characteristics__power_point),
value = { value.value }, value = { value.value },
onValueChange = { value.value = it }, onValueChange = { value.value = it },
@ -165,8 +156,20 @@ class CharacterSheetViewModel(
) { ) {
val sheet = repository.characterSheetFlow(id = argument.id).value val sheet = repository.characterSheetFlow(id = argument.id).value
val updated = when (characteristicId) { val updated = when (characteristicId) {
CharacterSheetFactory.HP -> sheet?.copy(currentHp = max(0, min(sheet.maxHp, value))) CharacterSheet.CharacteristicId.HP -> sheet?.copy(
CharacterSheetFactory.PP -> sheet?.copy(currentPp = max(0, min(sheet.maxPp, value))) currentHp = max(
0,
min(sheet.maxHp, value)
)
)
CharacterSheet.CharacteristicId.PP -> sheet?.copy(
currentPp = max(
0,
min(sheet.maxPp, value)
)
)
else -> null else -> null
} }
updated?.let { updated?.let {

View file

@ -125,8 +125,8 @@ class CharacterSheetEditFactory(
label = editedSkill.label, label = editedSkill.label,
description = skillDescriptionFactory.baseSkillDescription(editedSkill.id), description = skillDescriptionFactory.baseSkillDescription(editedSkill.id),
base = "${editedSkill.base.value}", base = "${editedSkill.base.value}",
bonus = editedSkill.bonus.value.value.toIntOrNull(), bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
level = editedSkill.level.value.value.toIntOrNull(), level = editedSkill.level.value.value.takeIf { it.isNotBlank() },
occupation = editedSkill.option.checked.value, occupation = editedSkill.option.checked.value,
used = currentSkill?.used ?: false, used = currentSkill?.used ?: false,
) )
@ -140,8 +140,8 @@ class CharacterSheetEditFactory(
label = editedSkill.label.value.value, label = editedSkill.label.value.value,
description = editedSkill.description.value.value, description = editedSkill.description.value.value,
base = editedSkill.base.value.value, base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull(), bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
level = editedSkill.level.value.value.toIntOrNull(), level = editedSkill.level.value.value.takeIf { it.isNotBlank() },
occupation = editedSkill.options.occupation, occupation = editedSkill.options.occupation,
used = currentSkill?.used ?: false, used = currentSkill?.used ?: false,
) )
@ -155,8 +155,8 @@ class CharacterSheetEditFactory(
label = editedSkill.label.value.value, label = editedSkill.label.value.value,
description = editedSkill.description.value.value, description = editedSkill.description.value.value,
base = editedSkill.base.value.value, base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull(), bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
level = editedSkill.level.value.value.toIntOrNull(), level = editedSkill.level.value.value.takeIf { it.isNotBlank() },
occupation = editedSkill.options.occupation, occupation = editedSkill.options.occupation,
used = currentSkill?.used ?: false, used = currentSkill?.used ?: false,
) )
@ -423,8 +423,8 @@ class CharacterSheetEditFactory(
descriptionValue = skill.description ?: "", descriptionValue = skill.description ?: "",
labelValue = skill.label, labelValue = skill.label,
baseValue = skill.base, baseValue = skill.base,
bonusValue = skill.bonus?.toString() ?: "", bonusValue = skill.bonus ?: "",
levelValue = skill.level?.toString() ?: "", levelValue = skill.level ?: "",
options = run { options = run {
val current = sheet.specialSkills.firstOrNull { it.id == skill.id } val current = sheet.specialSkills.firstOrNull { it.id == skill.id }
listOf( listOf(
@ -441,12 +441,14 @@ class CharacterSheetEditFactory(
descriptionValue = skill.description ?: "", descriptionValue = skill.description ?: "",
labelValue = skill.label, labelValue = skill.label,
baseValue = skill.base, baseValue = skill.base,
bonusValue = skill.bonus?.toString() ?: "", bonusValue = skill.bonus ?: "",
levelValue = skill.level?.toString() ?: "", levelValue = skill.level ?: "",
options = run { options = run {
val current = sheet.magicSkills.firstOrNull { it.id == skill.id } val current = sheet.magicSkills.firstOrNull { it.id == skill.id }
listOf( listOf(
skillFieldFactory.occupationOption(checked = current?.occupation ?: false), skillFieldFactory.occupationOption(
checked = current?.occupation ?: false
),
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) }, skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
) )
}, },
@ -483,11 +485,11 @@ class CharacterSheetEditFactory(
base = base, base = base,
bonus = skillFieldFactory.createWrapper( bonus = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__bonus_label)), label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__bonus_label)),
value = skill?.bonus?.toString() ?: "", value = skill?.bonus ?: "",
), ),
level = skillFieldFactory.createWrapper( level = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__level_label)), label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__level_label)),
value = skill?.level?.toString() ?: "", value = skill?.level ?: "",
), ),
option = skillFieldFactory.occupationOption(skill?.occupation ?: false), option = skillFieldFactory.occupationOption(skill?.occupation ?: false),
) )

View file

@ -3,11 +3,15 @@ package com.pixelized.desktop.lwa.screen.main
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Icon
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.TextButton import androidx.compose.material.TextButton
@ -28,11 +32,16 @@ import com.pixelized.desktop.lwa.navigation.window.destination.CharacterSheetWin
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__create__title import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__create__title
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
import lwacharactersheet.composeapp.generated.resources.ic_file_24dp
import lwacharactersheet.composeapp.generated.resources.ic_folder_24dp
import lwacharactersheet.composeapp.generated.resources.ic_table_24dp
import lwacharactersheet.composeapp.generated.resources.main_page__create_action import lwacharactersheet.composeapp.generated.resources.main_page__create_action
import lwacharactersheet.composeapp.generated.resources.main_page__network_action import lwacharactersheet.composeapp.generated.resources.main_page__network_action
import lwacharactersheet.composeapp.generated.resources.main_page__open_save_directory import lwacharactersheet.composeapp.generated.resources.main_page__open_save_directory
import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
import org.jetbrains.compose.resources.getString import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel import org.koin.compose.viewmodel.koinViewModel
@ -103,65 +112,100 @@ fun MainPageContent(
) { ) {
Column( Column(
modifier = modifier, modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(4.dp),
) { ) {
Column { characters.value.forEach { sheet ->
characters.value.forEach { sheet -> TextButton(
TextButton( onClick = { onCharacter(sheet) },
onClick = { onCharacter(sheet) }, ) {
) { Text(
Text( modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth(), overflow = TextOverflow.Ellipsis,
overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Start,
textAlign = TextAlign.Start, maxLines = 1,
maxLines = 1, text = sheet.name,
text = sheet.name, )
)
}
} }
} }
Spacer(modifier = Modifier.height(height = 24.dp))
TextButton( TextButton(
onClick = onCreateCharacter, onClick = onCreateCharacter,
) { ) {
Text( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
maxLines = 1, horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
overflow = TextOverflow.Ellipsis, verticalAlignment = Alignment.CenterVertically,
textAlign = TextAlign.Start, ) {
text = stringResource(Res.string.main_page__create_action), Icon(
) painter = painterResource(Res.drawable.ic_file_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__create_action),
)
}
} }
TextButton( TextButton(
onClick = onOpenSaveDirectory, onClick = onOpenSaveDirectory,
) { ) {
Text( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
maxLines = 1, horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
overflow = TextOverflow.Ellipsis, verticalAlignment = Alignment.CenterVertically,
textAlign = TextAlign.Start, ) {
text = stringResource(Res.string.main_page__open_save_directory), Icon(
) painter = painterResource(Res.drawable.ic_folder_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__open_save_directory),
)
}
} }
Column { TextButton(
TextButton( onClick = onRollHistory,
onClick = onRollHistory, ) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) { ) {
Icon(
painter = painterResource(Res.drawable.ic_d20_24dp),
contentDescription = null,
)
Text( Text(
modifier = Modifier.fillMaxWidth(),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start, textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__roll_history_action), text = stringResource(Res.string.main_page__roll_history_action),
) )
} }
TextButton( }
onClick = onNetwork,
TextButton(
onClick = onNetwork,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) { ) {
Icon(
painter = painterResource(Res.drawable.ic_table_24dp),
contentDescription = null,
)
Text( Text(
modifier = Modifier.fillMaxWidth(),
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start, textAlign = TextAlign.Start,
maxLines = 1, maxLines = 1,

View file

@ -48,7 +48,7 @@ import com.pixelized.desktop.lwa.screen.roll.DifficultyUio.Difficulty
import com.pixelized.desktop.lwa.utils.DisableInteractionSource import com.pixelized.desktop.lwa.utils.DisableInteractionSource
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.ic_d20_32dp import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
import lwacharactersheet.composeapp.generated.resources.roll_page__dc__label import lwacharactersheet.composeapp.generated.resources.roll_page__dc__label
import lwacharactersheet.composeapp.generated.resources.roll_page__dc_easy__label import lwacharactersheet.composeapp.generated.resources.roll_page__dc_easy__label
import lwacharactersheet.composeapp.generated.resources.roll_page__dc_hard__label import lwacharactersheet.composeapp.generated.resources.roll_page__dc_hard__label
@ -145,7 +145,7 @@ fun RollPage(
this.rotationZ = viewModel.rollRotation.value this.rotationZ = viewModel.rollRotation.value
}, },
tint = MaterialTheme.colors.primary, tint = MaterialTheme.colors.primary,
painter = painterResource(Res.drawable.ic_d20_32dp), painter = painterResource(Res.drawable.ic_d20_24dp),
contentDescription = null, contentDescription = null,
) )
AnimatedContent( AnimatedContent(

View file

@ -34,9 +34,10 @@ class RollUseCaseTest {
} }
private fun build1D100ResultSet(count: Int = ROLL_COUNT): List<Int> { private fun build1D100ResultSet(count: Int = ROLL_COUNT): List<Int> {
val useCase = RollUseCase()
val result = MutableList(100) { 0 } val result = MutableList(100) { 0 }
repeat(count) { repeat(count) {
val roll = RollUseCase.rollD100() val roll = useCase.rollD100()
result[roll - 1] += 1 result[roll - 1] += 1
} }
return result return result

View file

@ -1,12 +1,12 @@
package com.pixelized.desktop.lwa.business package com.pixelized.desktop.lwa.business
import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase.normalize
import org.junit.Test import org.junit.Test
class SkillNormalizerUseCaseText { class SkillNormalizerUseCaseText {
@Test @Test
fun testNormalization() { fun testNormalization() {
val useCase = SkillNormalizerUseCase()
val samples = listOf( val samples = listOf(
0 to 0, 0 to 0,
1 to 0, 1 to 0,
@ -21,7 +21,7 @@ class SkillNormalizerUseCaseText {
10 to 10, 10 to 10,
) )
samples.forEach { (value, expected) -> samples.forEach { (value, expected) ->
assert(normalize(value) == expected) { assert(useCase.normalize(value) == expected) {
"$value should be normalized to $expected" "$value should be normalized to $expected"
} }
} }