Add an hidden dice throw feature.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-05-31 12:30:17 +02:00
parent 4b34446697
commit 567b86e724
5 changed files with 110 additions and 13 deletions

View file

@ -56,7 +56,11 @@ class DiceThrowUseCase @Inject constructor(
private val skillRepository: SkillRepository,
private val alterationRepository: AlterationRepository,
) {
fun roll(diceThrow: DiceThrow, alterationId: List<String>): DiceThrowResult? {
fun roll(
diceThrow: DiceThrow,
isThrowHidden: Boolean,
alterationId: List<String>,
): DiceThrowResult? {
val sheet = characterSheetRepository.find(name = diceThrow.character)
val alterations = alterationRepository.getAlterations(character = diceThrow.character)
.filter { alterationId.contains(it.name) }
@ -70,6 +74,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
ability = Property.INITIATIVE,
relatedStat = Property.DEXTERITY,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Strength -> abilityThrow(
@ -79,6 +84,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_strength) },
ability = Property.STRENGTH_THROW,
relatedStat = Property.STRENGTH,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Dexterity -> abilityThrow(
@ -88,6 +94,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
ability = Property.DEXTERITY_THROW,
relatedStat = Property.DEXTERITY,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Constitution -> abilityThrow(
@ -97,6 +104,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_constitution) },
ability = Property.CONSTITUTION_THROW,
relatedStat = Property.CONSTITUTION,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Intelligence -> abilityThrow(
@ -106,6 +114,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.INTELLIGENCE_THROW,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Wisdom -> abilityThrow(
@ -114,7 +123,8 @@ class DiceThrowUseCase @Inject constructor(
abilityLabel = { getString(R.string.character_sheet_stat_wisdom) },
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.WISDOM_THROW,
relatedStat = Property.WISDOM
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Charisma -> abilityThrow(
@ -123,7 +133,8 @@ class DiceThrowUseCase @Inject constructor(
abilityLabel = { getString(R.string.character_sheet_stat_charisma) },
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
ability = Property.CHARISMA_THROW,
relatedStat = Property.CHARISMA
relatedStat = Property.CHARISMA,
isThrowHidden = isThrowHidden,
)
is DiceThrow.StrengthSavingThrow -> savingThrow(
@ -133,6 +144,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_strength) },
ability = Property.STRENGTH_SAVING_THROW,
relatedStat = Property.STRENGTH,
isThrowHidden = isThrowHidden,
)
is DiceThrow.DexteritySavingThrow -> savingThrow(
@ -142,6 +154,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
ability = Property.DEXTERITY_SAVING_THROW,
relatedStat = Property.DEXTERITY,
isThrowHidden = isThrowHidden,
)
is DiceThrow.ConstitutionSavingThrow -> savingThrow(
@ -151,6 +164,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_constitution) },
ability = Property.CONSTITUTION_SAVING_THROW,
relatedStat = Property.CONSTITUTION,
isThrowHidden = isThrowHidden,
)
is DiceThrow.IntelligenceSavingThrow -> savingThrow(
@ -160,6 +174,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.INTELLIGENCE_SAVING_THROW,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.WisdomSavingThrow -> savingThrow(
@ -168,7 +183,8 @@ class DiceThrowUseCase @Inject constructor(
abilityLabel = { getString(R.string.character_sheet_stat_wisdom) },
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.WISDOM_SAVING_THROW,
relatedStat = Property.WISDOM
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.CharismaSavingThrow -> savingThrow(
@ -177,7 +193,8 @@ class DiceThrowUseCase @Inject constructor(
abilityLabel = { getString(R.string.character_sheet_stat_charisma) },
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
ability = Property.CHARISMA_SAVING_THROW,
relatedStat = Property.CHARISMA
relatedStat = Property.CHARISMA,
isThrowHidden = isThrowHidden,
)
is DiceThrow.DeathSavingThrow -> savingThrow(
@ -187,6 +204,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_death) },
ability = Property.DEATH_SAVING_THROW,
relatedStat = null,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Acrobatics -> abilityThrow(
@ -196,6 +214,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
ability = Property.ACROBATICS,
relatedStat = Property.DEXTERITY,
isThrowHidden = isThrowHidden,
)
is DiceThrow.AnimalHandling -> abilityThrow(
@ -205,6 +224,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.ANIMAL_HANDLING,
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Arcana -> abilityThrow(
@ -214,6 +234,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.ARCANA,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Athletics -> abilityThrow(
@ -223,6 +244,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_strength) },
ability = Property.ATHLETICS,
relatedStat = Property.STRENGTH,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Deception -> abilityThrow(
@ -232,6 +254,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
ability = Property.DECEPTION,
relatedStat = Property.CHARISMA,
isThrowHidden = isThrowHidden,
)
is DiceThrow.History -> abilityThrow(
@ -241,6 +264,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.HISTORY,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Insight -> abilityThrow(
@ -250,6 +274,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.INSIGHT,
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Intimidation -> abilityThrow(
@ -259,6 +284,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
ability = Property.INTIMIDATION,
relatedStat = Property.CHARISMA,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Investigation -> abilityThrow(
@ -268,6 +294,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.INVESTIGATION,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Medicine -> abilityThrow(
@ -277,6 +304,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.MEDICINE,
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Nature -> abilityThrow(
@ -286,6 +314,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.NATURE,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Perception -> abilityThrow(
@ -295,6 +324,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.PERCEPTION,
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Performance -> abilityThrow(
@ -304,6 +334,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
ability = Property.PERFORMANCE,
relatedStat = Property.CHARISMA,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Persuasion -> abilityThrow(
@ -313,6 +344,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_charisma) },
ability = Property.PERSUASION,
relatedStat = Property.CHARISMA,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Religion -> abilityThrow(
@ -322,6 +354,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_intelligence) },
ability = Property.RELIGION,
relatedStat = Property.INTELLIGENCE,
isThrowHidden = isThrowHidden,
)
is DiceThrow.SleightOfHand -> abilityThrow(
@ -331,6 +364,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
ability = Property.SLEIGHT_OF_HAND,
relatedStat = Property.DEXTERITY,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Stealth -> abilityThrow(
@ -340,6 +374,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_dexterity) },
ability = Property.STEALTH,
relatedStat = Property.DEXTERITY,
isThrowHidden = isThrowHidden,
)
is DiceThrow.Survival -> abilityThrow(
@ -349,6 +384,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = { getString(R.string.character_sheet_stat_wisdom) },
ability = Property.SURVIVAL,
relatedStat = Property.WISDOM,
isThrowHidden = isThrowHidden,
)
is DiceThrow.PhysicalMeleeAttack -> {
@ -505,6 +541,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel: Context.() -> String?,
ability: Property,
relatedStat: Property,
isThrowHidden: Boolean,
): DiceThrowResult = rollAbility(
character = character,
alterations = alterations,
@ -514,6 +551,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = relatedLabel,
ability = ability,
relatedStat = relatedStat,
isThrowHidden = isThrowHidden,
)
private fun savingThrow(
@ -523,6 +561,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel: Context.() -> String?,
ability: Property,
relatedStat: Property?,
isThrowHidden: Boolean,
): DiceThrowResult = rollAbility(
character = character,
alterations = alterations,
@ -532,6 +571,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel = relatedLabel,
ability = ability,
relatedStat = relatedStat,
isThrowHidden = isThrowHidden,
)
private fun rollAbility(
@ -543,6 +583,7 @@ class DiceThrowUseCase @Inject constructor(
relatedLabel: Context.() -> String?,
ability: Property,
relatedStat: Property?,
isThrowHidden: Boolean,
): DiceThrowResult {
with(ThrowScope(context = application, character = character, alterations = alterations)) {
// retrieve some wording.
@ -655,7 +696,7 @@ class DiceThrowUseCase @Inject constructor(
timestamp = System.currentTimeMillis(),
title = abilityTitleString.uppercase(),
highlight = abilityLabelString.uppercase(),
hidden = ability == Property.DEATH_SAVING_THROW,
hidden = isThrowHidden,
face = 20,
roll = allValue.toLabel(),
result = rollResult,

View file

@ -13,12 +13,16 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
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.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
@ -52,6 +56,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
@ -101,6 +106,7 @@ fun RollOverlay(
card = viewModel.card,
groups = viewModel.alterations,
showDetail = viewModel.showDetail,
isThrowHidden = viewModel.isThrowHidden,
onMenu = {
scope.launch { drawer.open() }
},
@ -122,6 +128,9 @@ fun RollOverlay(
onAlteration = {
viewModel.onAlteration(it)
},
onThrowVisibilityChange = {
viewModel.onThrowVisibilityChange(it)
},
)
BackHandler(
@ -144,6 +153,7 @@ private fun RollOverlayContent(
card: State<ThrowsCardUio?>,
groups: State<List<AlterationGroupUio>>,
showDetail: State<Boolean>,
isThrowHidden: State<Boolean>,
onMenu: () -> Unit,
onMenuClose: () -> Unit,
onClose: () -> Unit,
@ -151,6 +161,7 @@ private fun RollOverlayContent(
onCard: () -> Unit,
onAlterationInfo: (id: String) -> Unit,
onAlteration: (id: String) -> Unit,
onThrowVisibilityChange: (Boolean) -> Unit,
) {
val density = LocalDensity.current
val enableDrawer = remember {
@ -214,14 +225,30 @@ private fun RollOverlayContent(
}
}
TextButton(
modifier = Modifier.align(alignment = Alignment.End),
onClick = onMenuClose,
Row(
modifier = Modifier.fillMaxWidth(4f / 5f),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
modifier = Modifier.padding(horizontal = 8.dp),
text = stringResource(id = R.string.roll_overlay__close_action),
)
IconButton(
onClick = { onThrowVisibilityChange(isThrowHidden.value.not()) },
) {
Icon(
painter = when (isThrowHidden.value) {
true -> painterResource(id = R.drawable.ic_visibility_off_24)
else -> painterResource(id = R.drawable.ic_visibility_24)
},
tint = MaterialTheme.colorScheme.primary,
contentDescription = null,
)
}
TextButton(
onClick = onMenuClose,
) {
Text(
modifier = Modifier.padding(horizontal = 8.dp),
text = stringResource(id = R.string.roll_overlay__close_action),
)
}
}
}
}
@ -352,6 +379,7 @@ private fun RollOverlayPreview(
card = preview.card,
groups = rememberRollAlterations(),
showDetail = remember { mutableStateOf(true) },
isThrowHidden = remember { mutableStateOf(true) },
onMenu = { },
onMenuClose = { },
onClose = { },
@ -359,6 +387,7 @@ private fun RollOverlayPreview(
onCard = { },
onAlterationInfo = { },
onAlteration = { },
onThrowVisibilityChange = { },
)
}
}

View file

@ -68,11 +68,15 @@ class RollOverlayViewModel @Inject constructor(
private val _showDetail = mutableStateOf(true)
val showDetail: State<Boolean> get() = _showDetail
private val _isThrowHidden = mutableStateOf(false)
val isThrowHidden: State<Boolean> get() = _isThrowHidden
private val _alterationDetail = mutableStateOf<AlterationDetailUio?>(null)
val alterationDetail: State<AlterationDetailUio?> get() = _alterationDetail
fun prepareRoll(diceThrow: DiceThrow) {
this.diceThrow = diceThrow
_isThrowHidden.value = diceThrow is DiceThrow.DeathSavingThrow
_card.value = null
sheet = characterSheetRepository.find(name = diceThrow.character)
_dice.value = diceFactory.convertDiceThrow(diceThrow)
@ -95,6 +99,7 @@ class RollOverlayViewModel @Inject constructor(
// roll the dice ;)
val result = rollUseCase.roll(
diceThrow = diceThrow,
isThrowHidden = _isThrowHidden.value,
alterationId = _alterations.value.mapNotNull { if (it.checked) it.label else null },
)
// share the result
@ -123,6 +128,10 @@ class RollOverlayViewModel @Inject constructor(
_showDetail.switch()
}
fun onThrowVisibilityChange(hidden: Boolean) {
_isThrowHidden.value = hidden
}
fun showAlterationDetail(id: String) {
val alteration = diceThrow?.character?.let { character ->
alterationRepository.getAlterations(character = character).firstOrNull { it.name == id }

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M480,640q75,0 127.5,-52.5T660,460q0,-75 -52.5,-127.5T480,280q-75,0 -127.5,52.5T300,460q0,75 52.5,127.5T480,640ZM480,568q-45,0 -76.5,-31.5T372,460q0,-45 31.5,-76.5T480,352q45,0 76.5,31.5T588,460q0,45 -31.5,76.5T480,568ZM480,760q-146,0 -266,-81.5T40,460q54,-137 174,-218.5T480,160q146,0 266,81.5T920,460q-54,137 -174,218.5T480,760ZM480,460ZM480,680q113,0 207.5,-59.5T832,460q-50,-101 -144.5,-160.5T480,240q-113,0 -207.5,59.5T128,460q50,101 144.5,160.5T480,680Z"
android:fillColor="#e8eaed"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="m644,532 l-58,-58q9,-47 -27,-88t-93,-32l-58,-58q17,-8 34.5,-12t37.5,-4q75,0 127.5,52.5T660,460q0,20 -4,37.5T644,532ZM772,658 L714,602q38,-29 67.5,-63.5T832,460q-50,-101 -143.5,-160.5T480,240q-29,0 -57,4t-55,12l-62,-62q41,-17 84,-25.5t90,-8.5q151,0 269,83.5T920,460q-23,59 -60.5,109.5T772,658ZM792,904L624,738q-35,11 -70.5,16.5T480,760q-151,0 -269,-83.5T40,460q21,-53 53,-98.5t73,-81.5L56,168l56,-56 736,736 -56,56ZM222,336q-29,26 -53,57t-41,67q50,101 143.5,160.5T480,680q20,0 39,-2.5t39,-5.5l-36,-38q-11,3 -21,4.5t-21,1.5q-75,0 -127.5,-52.5T300,460q0,-11 1.5,-21t4.5,-21l-84,-82ZM541,429ZM390,504Z"
android:fillColor="#e8eaed"/>
</vector>