Add Skill passive in the proficiency page
This commit is contained in:
parent
755caf1194
commit
a009e6c831
8 changed files with 265 additions and 85 deletions
|
|
@ -6,4 +6,5 @@ data class Skill(
|
|||
val rest: String?,
|
||||
val cost: String?,
|
||||
val effect: Throw?,
|
||||
val passive: Boolean,
|
||||
)
|
||||
|
|
@ -31,6 +31,7 @@ class SkillParser @Inject constructor(
|
|||
rest = row.parse(column = REST),
|
||||
cost = row.parse(column = COST),
|
||||
effect = throwParser.parse(row.parse(column = EFFECT)),
|
||||
passive = row.parseBool(column = PASSIVE) ?: false
|
||||
)
|
||||
skills.getOrPut(characterSheet.name) { mutableListOf() }.add(skill)
|
||||
}
|
||||
|
|
@ -48,7 +49,8 @@ class SkillParser @Inject constructor(
|
|||
private val REST = column("Récupération")
|
||||
private val COST = column("Coût")
|
||||
private val EFFECT = column("Effect")
|
||||
private val PASSIVE = column("Passif")
|
||||
|
||||
private val COLUMNS get() = listOf(CHARACTER, NAME, AMOUNT, REST, COST, EFFECT)
|
||||
private val COLUMNS get() = listOf(CHARACTER, NAME, AMOUNT, REST, COST, EFFECT, PASSIVE)
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.minimumInteractiveComponentSize
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -64,7 +63,6 @@ fun SkillItem(
|
|||
Box(
|
||||
modifier = Modifier
|
||||
.clickable { onInfo(skill) }
|
||||
.minimumInteractiveComponentSize()
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
contentAlignment = Alignment.Center,
|
||||
|
|
@ -160,7 +158,7 @@ private fun CounterItemPreview(
|
|||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberTokenListStatePreview(): State<List<SkillItemUio>> = remember {
|
||||
fun rememberSkillsListStatePreview(): State<List<SkillItemUio>> = remember {
|
||||
val provider = CounterItemPreviewProvider()
|
||||
mutableStateOf(provider.values.toList())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.factory
|
||||
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.Skill
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import javax.inject.Inject
|
||||
|
||||
class SkillFactoryUioFactory @Inject constructor(
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
) {
|
||||
fun convert(
|
||||
character: CharacterSheet?,
|
||||
fire: CharacterSheetFire?,
|
||||
skills: List<Skill>,
|
||||
): List<SkillItemUio> {
|
||||
// Filter out passive skills, theses are display in the Proficiency Page.
|
||||
return skills.map { skill ->
|
||||
val description = descriptionRepository.find(name = skill.name)
|
||||
val modifier = skill.effect?.modifier?.sumOf {
|
||||
when (it) {
|
||||
Property.LEVEL -> character?.level ?: 0
|
||||
Property.PROFICIENCY -> character?.proficiency ?: 0
|
||||
Property.STRENGTH -> character?.strength?.modifier ?: 0
|
||||
Property.DEXTERITY -> character?.dexterity?.modifier ?: 0
|
||||
Property.CONSTITUTION -> character?.constitution?.modifier ?: 0
|
||||
Property.INTELLIGENCE -> character?.intelligence?.modifier ?: 0
|
||||
Property.WISDOM -> character?.wisdom?.modifier ?: 0
|
||||
Property.CHARISMA -> character?.charisma?.modifier ?: 0
|
||||
else -> 0
|
||||
}
|
||||
} ?: 0
|
||||
SkillItemUio(
|
||||
label = skill.name,
|
||||
translate = description?.original,
|
||||
rest = skill.rest,
|
||||
cost = skill.cost,
|
||||
effect = skill.effect?.let {
|
||||
SkillItemUio.Dice(
|
||||
icon = it.faces.icon,
|
||||
label = "${skill.effect.amount}d${skill.effect.faces}${if (modifier > 0) "+$modifier" else ""}",
|
||||
)
|
||||
},
|
||||
value = fire?.skills?.get(skill.name) ?: 0,
|
||||
max = skill.amount,
|
||||
haveDetail = description?.description != null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import androidx.compose.foundation.lazy.items
|
|||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.ModalBottomSheetState
|
||||
import androidx.compose.material.minimumInteractiveComponentSize
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
|
|
@ -39,7 +40,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.actions.Spell
|
|||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellHeader
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellHeaderUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.rememberTokenListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.rememberSkillsListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberAttackListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberObjectListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberSpellListStatePreview
|
||||
|
|
@ -63,7 +64,7 @@ fun ActionPage(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
attacks = attacksViewModel.attacks,
|
||||
objects = objectsViewModel.objects,
|
||||
tokens = skillViewModel.skills,
|
||||
skills = skillViewModel.skills,
|
||||
spells = spellsViewModel.spells,
|
||||
onAttackHit = { id ->
|
||||
attacksViewModel.onHitRoll(id)?.let {
|
||||
|
|
@ -146,7 +147,7 @@ fun ActionsPageContent(
|
|||
lazyListState: LazyListState = rememberLazyListState(),
|
||||
attacks: State<List<AttackUio>>,
|
||||
objects: State<List<ObjectItemUio>>,
|
||||
tokens: State<List<SkillItemUio>>,
|
||||
skills: State<List<SkillItemUio>>,
|
||||
spells: State<List<Pair<SpellHeaderUio, List<SpellUio>>>>,
|
||||
onAttackHit: (id: String) -> Unit,
|
||||
onAttackDamage: (id: String) -> Unit,
|
||||
|
|
@ -204,14 +205,15 @@ fun ActionsPageContent(
|
|||
}
|
||||
}
|
||||
|
||||
if (tokens.value.isNotEmpty()) {
|
||||
if (skills.value.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
GenericHeader(
|
||||
label = R.string.character_sheet_title_skills,
|
||||
)
|
||||
}
|
||||
items(items = tokens.value) {
|
||||
items(items = skills.value) {
|
||||
SkillItem(
|
||||
modifier = Modifier.minimumInteractiveComponentSize(),
|
||||
skill = it,
|
||||
onInfo = onSkillInfo,
|
||||
onThrow = onSkillThrow,
|
||||
|
|
@ -259,7 +261,7 @@ fun ActionPagePreview() {
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
attacks = rememberAttackListStatePreview(),
|
||||
objects = rememberObjectListStatePreview(),
|
||||
tokens = rememberTokenListStatePreview(),
|
||||
skills = rememberSkillsListStatePreview(),
|
||||
spells = rememberSpellListStatePreview(),
|
||||
onAttackHit = { },
|
||||
onAttackDamage = { },
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.Skill
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
|
|
@ -18,8 +17,7 @@ import com.pixelized.rplexicon.data.repository.character.SkillRepository
|
|||
import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -30,9 +28,10 @@ import javax.inject.Inject
|
|||
@HiltViewModel
|
||||
class SkillsViewModel @Inject constructor(
|
||||
private val sheetRepository: CharacterSheetRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val skillFactory: SkillFactoryUioFactory,
|
||||
application: Application,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : AndroidViewModel(application) {
|
||||
|
|
@ -50,48 +49,23 @@ class SkillsViewModel @Inject constructor(
|
|||
init {
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
val data = SkillStruct()
|
||||
sheetRepository.data
|
||||
.combine(skillRepository.skills) { sheets, skills ->
|
||||
Struct(sheet = sheets[character], skill = skills[character] ?: emptyList())
|
||||
data.sheet = sheets[character]
|
||||
data.skill = skills[character] ?: emptyList()
|
||||
}
|
||||
.combine(firebaseRepository.getCharacter(character = character)) { data, fire ->
|
||||
data.apply { this.fire = fire }
|
||||
.combine(firebaseRepository.getCharacter(character = character)) { _, fire ->
|
||||
data.fire = fire
|
||||
}
|
||||
.collect { data ->
|
||||
val (character, values, fire) = data
|
||||
|
||||
val skills = values.map { skill ->
|
||||
val description = descriptionRepository.find(name = skill.name)
|
||||
val modifier = skill.effect?.modifier?.sumOf {
|
||||
when (it) {
|
||||
Property.LEVEL -> character?.level ?: 0
|
||||
Property.PROFICIENCY -> character?.proficiency ?: 0
|
||||
Property.STRENGTH -> character?.strength?.modifier ?: 0
|
||||
Property.DEXTERITY -> character?.dexterity?.modifier ?: 0
|
||||
Property.CONSTITUTION -> character?.constitution?.modifier ?: 0
|
||||
Property.INTELLIGENCE -> character?.intelligence?.modifier ?: 0
|
||||
Property.WISDOM -> character?.wisdom?.modifier ?: 0
|
||||
Property.CHARISMA -> character?.charisma?.modifier ?: 0
|
||||
else -> 0
|
||||
}
|
||||
} ?: 0
|
||||
SkillItemUio(
|
||||
label = skill.name,
|
||||
translate = description?.original,
|
||||
rest = skill.rest,
|
||||
cost = skill.cost,
|
||||
effect = skill.effect?.let {
|
||||
SkillItemUio.Dice(
|
||||
icon = it.faces.icon,
|
||||
label = "${skill.effect.amount}d${skill.effect.faces}${if (modifier > 0) "+$modifier" else ""}",
|
||||
)
|
||||
},
|
||||
value = fire?.skills?.get(skill.name) ?: 0,
|
||||
max = skill.amount,
|
||||
haveDetail = description?.description != null,
|
||||
)
|
||||
}
|
||||
|
||||
.collect {
|
||||
val (character, fire, values) = data
|
||||
// Filter out passive skills, theses are display in the Proficiency Page.
|
||||
val skills = skillFactory.convert(
|
||||
character = character,
|
||||
fire = fire,
|
||||
skills = values.filter { it.passive.not() }
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_skills.value = skills
|
||||
}
|
||||
|
|
@ -140,9 +114,9 @@ class SkillsViewModel @Inject constructor(
|
|||
hideSkillEditDialog()
|
||||
}
|
||||
|
||||
data class Struct(
|
||||
val sheet: CharacterSheet?,
|
||||
val skill: List<Skill>,
|
||||
var fire: CharacterSheetFire? = null
|
||||
private data class SkillStruct(
|
||||
var sheet: CharacterSheet? = null,
|
||||
var fire: CharacterSheetFire? = null,
|
||||
var skill: List<Skill> = emptyList(),
|
||||
)
|
||||
}
|
||||
|
|
@ -7,8 +7,10 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
|
|
@ -20,6 +22,7 @@ import androidx.compose.material3.Surface
|
|||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -38,6 +41,10 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.LocalRollOverlay
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HandleSkillEditDialog
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.rememberSkillsListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.LabelPointUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.Masteries
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.MasteriesUio
|
||||
|
|
@ -48,6 +55,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.Profici
|
|||
import com.pixelized.rplexicon.ui.screens.character.composable.character.Stat
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberCharacterSheetStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.HandleSkillDetailDialog
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
@ -72,6 +80,7 @@ fun ProficiencyPage(
|
|||
ProficiencyPageContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
sheet = sheet,
|
||||
passives = viewModel.skills,
|
||||
onStats = { stat ->
|
||||
overlay.prepareRoll(diceThrow = viewModel.statRoll(stat.id))
|
||||
overlay.showOverlay()
|
||||
|
|
@ -80,6 +89,27 @@ fun ProficiencyPage(
|
|||
overlay.prepareRoll(diceThrow = viewModel.proficiencyRoll(proficiency.id))
|
||||
overlay.showOverlay()
|
||||
},
|
||||
onSkillCount = {
|
||||
viewModel.showSkillEditDialog(item = it)
|
||||
},
|
||||
onSkillThrow = {
|
||||
overlay.prepareRoll(diceThrow = viewModel.onSkillRoll(it.label))
|
||||
overlay.showOverlay()
|
||||
},
|
||||
onSkillInfo = {
|
||||
viewModel.showSkillDetailDialog(item = it.label)
|
||||
},
|
||||
)
|
||||
|
||||
HandleSkillEditDialog(
|
||||
dialog = viewModel.skillEditDialog,
|
||||
onDismissRequest = viewModel::hideSkillEditDialog,
|
||||
onConfirm = viewModel::applySkillChange
|
||||
)
|
||||
|
||||
HandleSkillDetailDialog(
|
||||
dialog = viewModel.skillDetailDialog,
|
||||
onDismissRequest = viewModel::hideSkillDetailDialog
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -91,13 +121,17 @@ fun ProficiencyPageContent(
|
|||
inner: Shape = remember { RoundedCornerShape(size = 8.dp) },
|
||||
outline: Shape = remember { CutCornerShape(size = 16.dp) },
|
||||
sheet: CharacterSheetUio,
|
||||
passives: State<List<SkillItemUio>>,
|
||||
onStats: (StatUio) -> Unit,
|
||||
onProficiencies: (ProficiencyUio) -> Unit,
|
||||
onSkillThrow: (SkillItemUio) -> Unit,
|
||||
onSkillCount: (SkillItemUio) -> Unit,
|
||||
onSkillInfo: (SkillItemUio) -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.verticalScroll(state = state)
|
||||
.padding(all = 16.dp),
|
||||
.padding(vertical = 16.dp),
|
||||
) {
|
||||
ProficiencyLayout(
|
||||
inner = inner,
|
||||
|
|
@ -181,8 +215,22 @@ fun ProficiencyPageContent(
|
|||
},
|
||||
masteries = {
|
||||
Masteries(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
masteries = sheet.masteries,
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
) {
|
||||
passives.value.forEach {
|
||||
SkillItem(
|
||||
modifier = Modifier.padding(vertical = 4.dp),
|
||||
skill = it,
|
||||
onInfo = onSkillInfo,
|
||||
onThrow = onSkillThrow,
|
||||
onSkill = onSkillCount,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -247,8 +295,9 @@ private fun ProficiencyLayout(
|
|||
measurePolicy = { measurables, constraints ->
|
||||
val spacingPx = with(density) { spacing.toPx().toInt() }
|
||||
val statsWidth = with(density) { 100.dp.toPx().toInt() }
|
||||
val horizontal = with(density) { 16.dp.toPx().toInt() }
|
||||
|
||||
val proficienciesWidth = constraints.maxWidth - statsWidth - spacingPx
|
||||
val proficienciesWidth = constraints.maxWidth - statsWidth - spacingPx - horizontal * 2
|
||||
val passivesMeasure = measurables.passives.measure(
|
||||
constraints = constraints.copy(
|
||||
minWidth = proficienciesWidth,
|
||||
|
|
@ -291,23 +340,23 @@ private fun ProficiencyLayout(
|
|||
height = statsMeasure.height + masteriesMeasure.height + passivesMeasure.height + spacingPx * 2,
|
||||
) {
|
||||
statsMeasure.place(
|
||||
x = 0,
|
||||
x = horizontal,
|
||||
y = 0,
|
||||
)
|
||||
savingThrowsMeasure.place(
|
||||
x = statsWidth + spacingPx,
|
||||
x = horizontal + statsWidth + spacingPx,
|
||||
y = 0,
|
||||
)
|
||||
proficienciesMeasure.place(
|
||||
x = statsWidth + spacingPx,
|
||||
x = horizontal + statsWidth + spacingPx,
|
||||
y = savingThrowsMeasure.height + spacingPx,
|
||||
)
|
||||
speedMeasure.place(
|
||||
x = 0,
|
||||
x = horizontal,
|
||||
y = statsHeight + spacingPx,
|
||||
)
|
||||
passivesMeasure.place(
|
||||
x = statsWidth + spacingPx,
|
||||
x = horizontal + statsWidth + spacingPx,
|
||||
y = savingThrowsMeasure.height + proficienciesMeasure.height + spacingPx * 2,
|
||||
)
|
||||
masteriesMeasure.place(
|
||||
|
|
@ -327,16 +376,20 @@ val List<Measurable>.passives get() = first { it.layoutId == "PassivesId" }
|
|||
val List<Measurable>.masteries get() = first { it.layoutId == "MasteriesId" }
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO, heightDp = 1300)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES, heightDp = 1300)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO, heightDp = 1500)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES, heightDp = 1500)
|
||||
fun ProficiencyPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
val sheet by rememberCharacterSheetStatePreview()
|
||||
ProficiencyPageContent(
|
||||
sheet = sheet,
|
||||
passives = rememberSkillsListStatePreview(),
|
||||
onStats = { },
|
||||
onProficiencies = { },
|
||||
onSkillThrow = { },
|
||||
onSkillCount = { },
|
||||
onSkillInfo = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,23 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Skill
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.SkillRepository
|
||||
import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.ProficiencyUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.CharacterSheetUioFactory
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillDetailUio
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -23,8 +33,12 @@ import javax.inject.Inject
|
|||
@HiltViewModel
|
||||
class ProficiencyViewModel @Inject constructor(
|
||||
private val characterRepository: CharacterSheetRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val characterSheetFactory: CharacterSheetUioFactory,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val skillFactory: SkillFactoryUioFactory,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
application: Application,
|
||||
) : AndroidViewModel(application) {
|
||||
|
|
@ -33,27 +47,63 @@ class ProficiencyViewModel @Inject constructor(
|
|||
private val _sheet = mutableStateOf<CharacterSheetUio?>(null)
|
||||
val sheet: State<CharacterSheetUio?> get() = _sheet
|
||||
|
||||
private val _skillEditDialog = mutableStateOf<SkillEditDialogUio?>(null)
|
||||
val skillEditDialog: State<SkillEditDialogUio?> get() = _skillEditDialog
|
||||
|
||||
private val _skillDetailDialog = mutableStateOf<SkillDetailUio?>(null)
|
||||
val skillDetailDialog: State<SkillDetailUio?> get() = _skillDetailDialog
|
||||
|
||||
private val _skills = mutableStateOf<List<SkillItemUio>>(emptyList())
|
||||
val skills: State<List<SkillItemUio>> get() = _skills
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
characterRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { sheets, _ -> sheets }
|
||||
.collect {
|
||||
val characterSheet = it[character]
|
||||
if (characterSheet != null) {
|
||||
val alterations = alterationRepository.getActiveAlterationsStatus(character)
|
||||
val sheet = characterSheetFactory.convert(
|
||||
sheet = characterSheet,
|
||||
status = alterations,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_sheet.value = sheet
|
||||
}
|
||||
} else {
|
||||
launch {
|
||||
characterRepository.fetchCharacterSheet()
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
characterRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { sheets, _ -> sheets }
|
||||
.collect {
|
||||
val characterSheet = it[character]
|
||||
if (characterSheet != null) {
|
||||
val alterations =
|
||||
alterationRepository.getActiveAlterationsStatus(character)
|
||||
val sheet = characterSheetFactory.convert(
|
||||
sheet = characterSheet,
|
||||
status = alterations,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_sheet.value = sheet
|
||||
}
|
||||
} else {
|
||||
launch {
|
||||
characterRepository.fetchCharacterSheet()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
val data = SkillStruct()
|
||||
characterRepository.data
|
||||
.combine(skillRepository.skills) { sheets, skills ->
|
||||
data.sheet = sheets[character]
|
||||
data.skill = skills[character] ?: emptyList()
|
||||
}
|
||||
.combine(firebaseRepository.getCharacter(character = character)) { _, fire ->
|
||||
data.fire = fire
|
||||
}
|
||||
.collect {
|
||||
val (character, fire, values) = data
|
||||
// Filter out non passive skills.
|
||||
val skills = skillFactory.convert(
|
||||
character = character,
|
||||
fire = fire,
|
||||
skills = values.filter { it.passive }
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_skills.value = skills
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,4 +142,50 @@ class ProficiencyViewModel @Inject constructor(
|
|||
ProficiencyUio.ID.STEALTH -> DiceThrow.Stealth(character)
|
||||
ProficiencyUio.ID.SURVIVAL -> DiceThrow.Survival(character)
|
||||
}
|
||||
|
||||
fun onSkillRoll(name: String): DiceThrow = DiceThrow.Skill(
|
||||
character = character,
|
||||
skill = name,
|
||||
)
|
||||
|
||||
fun showSkillDetailDialog(item: String) {
|
||||
_skillDetailDialog.value = descriptionRepository
|
||||
.find(name = item)
|
||||
?.let { description ->
|
||||
SkillDetailUio(
|
||||
name = item,
|
||||
original = description.original,
|
||||
description = description.description
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideSkillDetailDialog() {
|
||||
_skillDetailDialog.value = null
|
||||
}
|
||||
|
||||
fun showSkillEditDialog(item: SkillItemUio) {
|
||||
if (item.max != null) {
|
||||
_skillEditDialog.value = SkillEditDialogUio(
|
||||
label = item.label,
|
||||
value = item.value ?: 0,
|
||||
max = item.max,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideSkillEditDialog() {
|
||||
_skillEditDialog.value = null
|
||||
}
|
||||
|
||||
fun applySkillChange(id: String, value: Int) {
|
||||
firebaseRepository.setSkill(character = character, name = id, value = value)
|
||||
hideSkillEditDialog()
|
||||
}
|
||||
|
||||
private data class SkillStruct(
|
||||
var sheet: CharacterSheet? = null,
|
||||
var fire: CharacterSheetFire? = null,
|
||||
var skill: List<Skill> = emptyList(),
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue