Add Critical damage support.

This commit is contained in:
Thomas Andres Gomez 2023-09-23 10:30:56 +02:00
parent 880d19eb20
commit b6c7009697
13 changed files with 341 additions and 113 deletions

View file

@ -17,6 +17,7 @@ data class CharacterSheet(
val spell7: Counter?,
val spell8: Counter?,
val spell9: Counter?,
val criticalModifier: Int, // Critical Dice Multiplier
val armorClass: String, // Classe d'armure
val speed: Int, // Vitesse
val strength: Int, // Force

View file

@ -1,6 +1,8 @@
package com.pixelized.rplexicon.model
data class Roll(
val character: String,
val canUseCriticalDice: Boolean,
val title: String,
val highlight: String? = null,
val dices: List<Dice>,

View file

@ -1,8 +1,8 @@
package com.pixelized.rplexicon.repository.parser
import com.google.api.services.sheets.v4.model.ValueRange
import com.pixelized.rplexicon.repository.parser.alteration.CounterParser
import com.pixelized.rplexicon.model.CharacterSheet
import com.pixelized.rplexicon.repository.parser.alteration.CounterParser
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
import com.pixelized.rplexicon.utilitary.extentions.local.checkSheetStructure
import com.pixelized.rplexicon.utilitary.extentions.sheet
@ -54,50 +54,33 @@ class CharacterSheetParser @Inject constructor(
maxHitPoint = item.parseString(MAX_HIT_POINT) ?: "1",
lifeDice = item.parseInt(LIFE_DICE) ?: 0,
spell1 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_1
)
value = item.parseString(SPELL_LEVEL_1)
),
spell2 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_2
)
value = item.parseString(SPELL_LEVEL_2)
),
spell3 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_3
)
value = item.parseString(SPELL_LEVEL_3)
),
spell4 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_4
)
value = item.parseString(SPELL_LEVEL_4)
),
spell5 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_5
)
value = item.parseString(SPELL_LEVEL_5)
),
spell6 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_6
)
value = item.parseString(SPELL_LEVEL_6)
),
spell7 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_7
)
value = item.parseString(SPELL_LEVEL_7)
),
spell8 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_8
)
value = item.parseString(SPELL_LEVEL_8)
),
spell9 = counterParser.parseCounter(
value = item.parseString(
SPELL_LEVEL_9
)
value = item.parseString(SPELL_LEVEL_9)
),
criticalModifier = item.parseInt(CRITICAL_MODIFIER) ?: 2,
armorClass = item.parseString(ARMOR_CLASS) ?: "10",
speed = item.parseInt(SPEED) ?: 10,
strength = item.parseInt(STRENGTH) ?: 10,
@ -157,6 +140,7 @@ class CharacterSheetParser @Inject constructor(
private const val SPELL_LEVEL_7 = "Sort de niveau 7"
private const val SPELL_LEVEL_8 = "Sort de niveau 8"
private const val SPELL_LEVEL_9 = "Sort de niveau 9"
private const val CRITICAL_MODIFIER = "Dé de critique"
private const val ARMOR_CLASS = "Classe d'armure"
private const val SPEED = "Vitesse"
private const val MASTERY = "Bonus de maîtrise"
@ -208,6 +192,7 @@ class CharacterSheetParser @Inject constructor(
SPELL_LEVEL_7,
SPELL_LEVEL_8,
SPELL_LEVEL_9,
CRITICAL_MODIFIER,
ARMOR_CLASS,
SPEED,
MASTERY,

View file

@ -212,7 +212,6 @@ private fun CharacterSheetContent(
Surface(
modifier = Modifier.padding(paddingValues = paddingValues),
) {
ModalBottomSheetLayout(
sheetState = sheetState,
sheetContent = {

View file

@ -66,6 +66,7 @@ class AttackActionViewModel @Inject constructor(
return actionRoll(
attack = action,
throws = action?.hit,
canUseCriticalDice = false,
)
}
@ -74,12 +75,14 @@ class AttackActionViewModel @Inject constructor(
return actionRoll(
attack = action,
throws = action?.damage,
canUseCriticalDice = true,
)
}
private fun actionRoll(
attack: Attack?,
throws: Throw?,
canUseCriticalDice: Boolean,
): Roll {
// build the title
val title = context.getString(
@ -123,6 +126,8 @@ class AttackActionViewModel @Inject constructor(
val fail = alterations.any { it.fail }
// build the roll
return Roll(
character = character,
canUseCriticalDice = canUseCriticalDice,
title = title,
highlight = attack?.title,
dices = listOf(

View file

@ -209,6 +209,7 @@ class SpellsActionViewModel @Inject constructor(
spell = spell?.spell,
titleRes = R.string.dice_roll_attack_damage_title,
throws = spell?.effect,
canUseCriticalDice = true,
)
}
@ -221,11 +222,14 @@ class SpellsActionViewModel @Inject constructor(
throws: Throw?,
level: Int = 0,
levelThrow: Throw? = null,
canUseCriticalDice: Boolean = false,
): Roll {
// build the title
val title = context.getString(titleRes, spell?.name)
// build the roll
return Roll(
character = character,
canUseCriticalDice = canUseCriticalDice,
title = title,
highlight = spell?.name,
dices = listOf(

View file

@ -298,6 +298,8 @@ class ProficiencyViewModel @Inject constructor(
val fail = alterations.any { it.fail }
return Roll(
character = character,
canUseCriticalDice = false,
title = context.getString(R.string.dice_roll_check_title, ability.uppercase()),
highlight = ability,
dices = listOf(
@ -337,6 +339,8 @@ class ProficiencyViewModel @Inject constructor(
val fail = alterations.any { it.fail }
return Roll(
character = character,
canUseCriticalDice = false,
title = context.getString(
R.string.dice_roll_saving_throw_title,
ability.uppercase()
@ -388,6 +392,8 @@ class ProficiencyViewModel @Inject constructor(
val fail = alterations.any { it.fail }
return Roll(
character = character,
canUseCriticalDice = false,
title = context.getString(R.string.dice_roll_check_title, ability.uppercase()),
highlight = ability,
dices = listOf(

View file

@ -9,16 +9,23 @@ import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
data class RollResult(
val dice: RollDiceUio?,
val card: ThrowsCardUio?,
)
class ConvertRollIntoDisplayableFactory @Inject constructor() {
fun roll(roll: Roll): Pair<RollDiceUio?, ThrowsCardUio?> {
fun roll(
roll: Roll,
diceMultiplier: Int = 1,
): RollResult {
val mainDices = roll.dices.firstOrNull()
val bonusDicesList = roll.dices.subList(fromIndex = 1, toIndex = roll.dices.size)
val allRolledValues = mutableListOf<Int>()
val (rollDice, rollDetail) = mainDices?.let { dice ->
val (label, sum) = dice.roll()
val (label, sum) = dice.roll(multiplier = diceMultiplier)
allRolledValues.add(sum)
val diceIcon = dice.toRollCardUio(result = sum)
@ -31,7 +38,7 @@ class ConvertRollIntoDisplayableFactory @Inject constructor() {
val isCriticalFailure = rollDice?.isCriticalFailure ?: false
val diceBonus = bonusDicesList.map { dice ->
val (label, sum) = dice.roll()
val (label, sum) = dice.roll(multiplier = diceMultiplier)
allRolledValues.add(sum)
dice.toThrowsCardUio(
@ -49,23 +56,25 @@ class ConvertRollIntoDisplayableFactory @Inject constructor() {
)
}
return rollDice to ThrowsCardUio(
title = roll.title,
highlight = roll.highlight,
dice = mainDices?.faces?.icon,
roll = allRolledValues.toLabel(),
result = when {
isCriticalSuccess -> (mainDices?.faces ?: 20).toString()
isCriticalFailure -> "1"
else -> "${allRolledValues.sum()}"
},
isCriticalSuccess = isCriticalSuccess,
isCriticalFailure = isCriticalFailure,
details = rollDetail + diceBonus + flatBonus,
return RollResult(
dice = rollDice,
card = ThrowsCardUio(
title = roll.title,
highlight = roll.highlight,
dice = mainDices?.faces?.icon,
roll = allRolledValues.toLabel(),
result = when {
isCriticalSuccess -> (mainDices?.faces ?: 20).toString()
isCriticalFailure -> "1"
else -> "${allRolledValues.sum()}"
},
isCriticalSuccess = isCriticalSuccess,
isCriticalFailure = isCriticalFailure,
details = rollDetail + diceBonus + flatBonus,
),
)
}
private fun Roll.Dice.toRollCardUio(result: Int) = RollDiceUio(
icon = faces.icon,
isCriticalSuccess = count == 1 && faces == 20 && result == faces,
@ -85,33 +94,33 @@ class ConvertRollIntoDisplayableFactory @Inject constructor() {
result = "$result",
)
private data class RollResult(
private data class DiceRollResult(
val label: String,
val sum: Int,
)
private fun Roll.Dice.roll(): RollResult {
private fun Roll.Dice.roll(multiplier: Int): DiceRollResult {
return when {
advantage && !disadvantage -> {
val roll = List(count) { random() to random() }
RollResult(
val roll = List(count * multiplier) { random() to random() }
DiceRollResult(
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
sum = roll.sumOf { max(it.first, it.second) },
)
}
disadvantage && !advantage -> {
val roll = List(count) { random() to random() }
RollResult(
val roll = List(count * multiplier) { random() to random() }
DiceRollResult(
label = roll.joinToString(" + ") { "${it.first}~${it.second}" },
sum = roll.sumOf { min(it.first, it.second) },
)
}
else -> {
val roll = List(count) { random() }
RollResult(
val roll = List(count * multiplier) { random() }
DiceRollResult(
label = roll.toLabel(),
sum = roll.sum(),
)

View file

@ -2,6 +2,7 @@ package com.pixelized.rplexicon.ui.screens.rolls
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
@ -11,14 +12,26 @@ import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.Menu
import androidx.compose.material3.DrawerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.Stable
@ -26,124 +39,194 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.rplexicon.LocalRollOverlay
import com.pixelized.rplexicon.NO_WINDOW_INSETS
import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.model.Roll
import com.pixelized.rplexicon.ui.composable.BlurredOverlayHostState
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlteration
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDice
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCard
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.ui.theme.LexiconTheme
import kotlinx.coroutines.launch
@Composable
fun RollOverlay(
viewModel: RollOverlayViewModel = hiltViewModel(),
) {
val overlay = LocalRollOverlay.current
val scope = rememberCoroutineScope()
val drawer = rememberDrawerState(initialValue = DrawerValue.Closed)
RollOverlayContent(
modifier = Modifier.fillMaxSize(),
drawer = drawer,
dice = viewModel.dice,
card = viewModel.card,
alterations = viewModel.alterations,
showDetail = viewModel.showDetail,
onMenu = {
scope.launch { drawer.open() }
},
onClose = {
overlay.hideOverlay()
},
onDice = {
viewModel.roll()
},
onCard = {
viewModel.toggleDetail()
},
onClose = {
overlay.hideOverlay()
}
onAlteration = {
viewModel.onAlteration(it)
},
)
BackHandler(enabled = drawer.isOpen) {
scope.launch { drawer.close() }
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun RollOverlayContent(
modifier: Modifier = Modifier,
drawer: DrawerState,
dice: State<RollDiceUio>,
card: State<ThrowsCardUio?>,
alterations: State<List<RollAlterationUio>>,
showDetail: State<Boolean>,
onMenu: () -> Unit,
onClose: () -> Unit,
onDice: () -> Unit,
onCard: () -> Unit,
onClose: () -> Unit,
onAlteration: (id: String) -> Unit,
) {
val density = LocalDensity.current
Box(
ModalNavigationDrawer(
modifier = modifier,
) {
RollDice(
modifier = Modifier
.align(alignment = Alignment.Center)
.padding(horizontal = 16.dp),
dice = dice,
onDice = onDice,
)
AnimatedContent(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(all = 16.dp),
targetState = card.value,
transitionSpec = {
val enter = fadeIn() + slideInVertically { with(density) { 64.dp.roundToPx() } }
val exit = fadeOut() + slideOutVertically { with(density) { -64.dp.roundToPx() } }
val transform = SizeTransform(clip = false)
enter togetherWith exit using transform
},
label = "RollOverlayDisplay",
) {
when (it) {
null -> Box(
modifier = Modifier.fillMaxWidth(),
)
else -> ThrowsCard(
drawerState = drawer,
drawerContent = {
Surface {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onCard),
throws = it,
showDetail = showDetail,
)
.fillMaxHeight()
.fillMaxWidth(4f / 5f),
) {
items(items = alterations.value) {
RollAlteration(
modifier = Modifier.fillMaxWidth(),
alteration = it,
onClick = onAlteration,
)
}
}
}
}
},
content = {
Scaffold(
containerColor = Color.Transparent,
contentWindowInsets = NO_WINDOW_INSETS,
topBar = {
TopAppBar(
colors = TopAppBarDefaults.topAppBarColors(containerColor = Color.Transparent),
title = { },
navigationIcon = {
IconButton(onClick = onMenu) {
Icon(
imageVector = Icons.Outlined.Menu,
contentDescription = null,
)
}
},
actions = {
IconButton(onClick = onClose) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = null,
)
}
},
)
},
content = { paddingValues ->
Box(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues),
) {
RollDice(
modifier = Modifier
.align(alignment = Alignment.Center)
.padding(horizontal = 16.dp),
dice = dice,
onDice = onDice,
)
IconButton(
modifier = Modifier
.align(alignment = Alignment.TopEnd)
.padding(
top = 6.dp,
end = 4.dp
),
onClick = onClose
) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = null,
AnimatedContent(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter)
.padding(all = 16.dp),
targetState = card.value,
transitionSpec = {
val enter =
fadeIn() + slideInVertically { with(density) { 64.dp.roundToPx() } }
val exit =
fadeOut() + slideOutVertically { with(density) { -64.dp.roundToPx() } }
val transform = SizeTransform(clip = false)
enter togetherWith exit using transform
},
label = "RollOverlayDisplay",
) {
when (it) {
null -> Box(
modifier = Modifier.fillMaxWidth(),
)
else -> ThrowsCard(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onCard),
throws = it,
showDetail = showDetail,
)
}
}
}
}
)
}
}
},
)
}
@Composable
@Preview(uiMode = UI_MODE_NIGHT_NO)
@Preview(uiMode = UI_MODE_NIGHT_YES)
private fun RollOverlayPreview() {
private fun RollOverlayPreview(
@PreviewParameter(RollOverlayPreviewProvider::class) preview: DrawerValue
) {
LexiconTheme {
Surface {
RollOverlayContent(
modifier = Modifier.fillMaxSize(),
drawer = rememberDrawerState(initialValue = preview),
dice = remember {
mutableStateOf(
RollDiceUio(
@ -183,17 +266,30 @@ private fun RollOverlayPreview() {
)
)
},
alterations = remember {
mutableStateOf(
listOf(
RollAlterationUio(label = "Critique", checked = false),
)
)
},
showDetail = remember {
mutableStateOf(true)
},
onMenu = { },
onClose = { },
onDice = { },
onCard = { },
onClose = { },
onAlteration = { },
)
}
}
}
private class RollOverlayPreviewProvider : PreviewParameterProvider<DrawerValue> {
override val values: Sequence<DrawerValue> = sequenceOf(DrawerValue.Closed, DrawerValue.Open)
}
@Stable
interface BlurredRollOverlayHostState : BlurredOverlayHostState {
fun prepareRoll(roll: Roll)

View file

@ -1,12 +1,21 @@
package com.pixelized.rplexicon.ui.screens.rolls
import android.app.Application
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.model.Alteration
import com.pixelized.rplexicon.model.CharacterSheet
import com.pixelized.rplexicon.model.Roll
import com.pixelized.rplexicon.repository.data.AlterationRepository
import com.pixelized.rplexicon.repository.data.CharacterSheetRepository
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.utilitary.extentions.context
import com.pixelized.rplexicon.utilitary.extentions.icon
import com.pixelized.rplexicon.utilitary.extentions.switch
import dagger.hilt.android.lifecycle.HiltViewModel
@ -17,11 +26,18 @@ import javax.inject.Inject
@HiltViewModel
class RollOverlayViewModel @Inject constructor(
application: Application,
private val characterSheetRepository: CharacterSheetRepository,
private val factory: ConvertRollIntoDisplayableFactory,
) : ViewModel() {
) : AndroidViewModel(application) {
private val criticalLabel = context.getString(R.string.dice_roll_critical_label)
private var rollJob: Job? = null
private lateinit var roll: Roll
private var character: CharacterSheet? = null
private val _alterations = mutableStateOf<List<RollAlterationUio>>(emptyList())
val alterations: State<List<RollAlterationUio>> get() = _alterations
private val _dice = mutableStateOf(RollDiceUio())
val dice: State<RollDiceUio> get() = _dice
@ -34,14 +50,38 @@ class RollOverlayViewModel @Inject constructor(
fun prepareRoll(roll: Roll) {
this.roll = roll
this.character = characterSheetRepository.find(name = roll.character)
_dice.value = RollDiceUio(icon = roll.dices.maxOf { it.faces }.icon)
_card.value = null
_alterations.value = if (roll.canUseCriticalDice) {
listOf(RollAlterationUio(label = criticalLabel, checked = false))
} else {
emptyList()
}
}
fun onAlteration(id: String) {
_alterations.value = _alterations.value.toMutableList().also { alterations ->
val index = alterations.indexOfFirst { it.label == id }
val alteration = alterations[index].let { it.copy(checked = it.checked.not()) }
alterations.removeAt(index)
alterations.add(index, alteration)
}
}
fun roll() {
rollJob?.cancel()
rollJob = viewModelScope.launch {
val (dice, card) = factory.roll(roll = roll)
val isCritical = _alterations.value.firstOrNull { it.label == criticalLabel }?.checked ?: false
val (dice, card) = factory.roll(
roll = roll,
diceMultiplier = when {
isCritical -> character?.criticalModifier ?: 2
else -> 1
},
)
// Start the roll animation.
_dice.value = _dice.value.copy(
animationSpec = RollDiceUio.TWEEN,

View file

@ -0,0 +1,79 @@
package com.pixelized.rplexicon.ui.screens.rolls.composable
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp
import com.pixelized.rplexicon.ui.theme.LexiconTheme
@Stable
data class RollAlterationUio(
val label: String,
val checked: Boolean
)
@Composable
fun RollAlteration(
modifier: Modifier = Modifier,
alteration: RollAlterationUio,
onClick: (id: String) -> Unit,
) {
Row(
modifier = modifier
.clickable { onClick(alteration.label) }
.padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
style = MaterialTheme.typography.bodyMedium,
text = alteration.label,
)
Switch(
enabled = true,
checked = alteration.checked,
onCheckedChange = { onClick(alteration.label) },
)
}
}
@Composable
@Preview(uiMode = UI_MODE_NIGHT_NO)
@Preview(uiMode = UI_MODE_NIGHT_YES)
private fun RollAlterationPreview(
@PreviewParameter(RollAlterationPreviewProvider::class) preview: RollAlterationUio,
) {
LexiconTheme {
Surface {
RollAlteration(
modifier = Modifier.fillMaxWidth(),
alteration = preview,
onClick = { },
)
}
}
}
private class RollAlterationPreviewProvider : PreviewParameterProvider<RollAlterationUio> {
override val values: Sequence<RollAlterationUio> = sequenceOf(
RollAlterationUio(label = "Critique", checked = false),
RollAlterationUio(label = "Rage", checked = true),
RollAlterationUio(label = "Bénédiction", checked = false),
)
}

View file

@ -127,6 +127,7 @@
<string name="dice_roll_attack_damage_title">Jet de dommage : \"%1$s\"</string>
<string name="dice_roll_spell_hit_title">Jet de sort : \"%1$s"</string>
<string name="dice_roll_spell_damage_title">Jet de dommage : \"%1$s\"</string>
<string name="dice_roll_critical_label">Critique</string>
<string name="dice_roll_saving_throw_title">JET DE SAUVEGARDE : %1$s</string>
<string name="dice_roll_saving_throw_detail">Sauvegarde de \"%1$s\"</string>

View file

@ -127,6 +127,7 @@
<string name="dice_roll_attack_damage_title">%1$s DAMAGE</string>
<string name="dice_roll_spell_hit_title">%1$s HIT</string>
<string name="dice_roll_spell_damage_title">%1$s DAMAGE</string>
<string name="dice_roll_critical_label">Critical</string>
<string name="dice_roll_saving_throw_title">%1$s SAVING THROW</string>
<string name="dice_roll_saving_throw_detail">%1$s save</string>