Add Object action in the character action sheet.
This commit is contained in:
parent
f9b3adfee0
commit
cd921ac16f
21 changed files with 416 additions and 10 deletions
|
|
@ -12,6 +12,7 @@ import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepositor
|
|||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.repository.data.lexicon.LexiconRepository
|
||||
|
|
@ -35,6 +36,7 @@ class LauncherViewModel @Inject constructor(
|
|||
alterationRepository: AlterationRepository,
|
||||
characterSheetRepository: CharacterSheetRepository,
|
||||
actionRepository: ActionRepository,
|
||||
objectActionRepository: ObjectActionRepository,
|
||||
spellRepository: SpellRepository,
|
||||
skillRepository: SkillRepository,
|
||||
descriptionRepository: DescriptionRepository,
|
||||
|
|
@ -124,6 +126,14 @@ class LauncherViewModel @Inject constructor(
|
|||
_error.emit(FetchErrorUio.Structure(type = Type.ACTION))
|
||||
}
|
||||
}
|
||||
val objects = async {
|
||||
try {
|
||||
objectActionRepository.fetchObjectAction()
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
_error.emit(FetchErrorUio.Structure(type = Type.OBJECT))
|
||||
}
|
||||
}
|
||||
val spell = async {
|
||||
try {
|
||||
spellRepository.fetchSpells()
|
||||
|
|
@ -142,7 +152,7 @@ class LauncherViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
awaitAll(lexicon, location, quest)
|
||||
awaitAll(description, inventory, equipment, alteration, action, spell, skill)
|
||||
awaitAll(description, inventory, equipment, alteration, action, objects, spell, skill)
|
||||
|
||||
isLoading = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.pixelized.rplexicon.model.Throw
|
|||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
|
|
@ -42,6 +43,7 @@ class DiceThrowUseCase @Inject constructor(
|
|||
private val application: Application,
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
private val objectRepository: ObjectActionRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
|
|
@ -393,6 +395,21 @@ class DiceThrowUseCase @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
is DiceThrow.Object -> {
|
||||
val action = objectRepository.find(
|
||||
character = diceThrow.character,
|
||||
item = diceThrow.item,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.item,
|
||||
diceThrow = action?.effect,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = emptyMap(),
|
||||
ability = null,
|
||||
)
|
||||
}
|
||||
|
||||
is DiceThrow.SpellAttack -> {
|
||||
val spell = spellRepository.find(
|
||||
character = diceThrow.character,
|
||||
|
|
@ -664,7 +681,7 @@ class DiceThrowUseCase @Inject constructor(
|
|||
diceThrow: Throw?,
|
||||
title: Context.(action: String) -> String,
|
||||
alterations: Map<Property, List<Alteration.Status>>,
|
||||
ability: Property,
|
||||
ability: Property?,
|
||||
): DiceThrowResult {
|
||||
// retrieve some wording.
|
||||
val titleString = title(application, action)
|
||||
|
|
@ -778,6 +795,17 @@ class DiceThrowUseCase @Inject constructor(
|
|||
}
|
||||
} ?: emptyList()
|
||||
|
||||
// check for flat dice bonus (ex: healing potion 2d4 + 2)
|
||||
val flatBonus = diceThrow?.flat?.takeIf { it > 0 }?.let {
|
||||
allValue.add(it)
|
||||
listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = application.getString(R.string.dice_roll_bonus_detail, action),
|
||||
result = "$it",
|
||||
)
|
||||
)
|
||||
}?: emptyList()
|
||||
|
||||
// build the result.
|
||||
return DiceThrowResult(
|
||||
dice = RollDiceUio(
|
||||
|
|
@ -812,7 +840,7 @@ class DiceThrowUseCase @Inject constructor(
|
|||
),
|
||||
result = "${result.value}",
|
||||
),
|
||||
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus,
|
||||
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + flatBonus,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,4 +40,5 @@ sealed class DiceThrow(val character: String) {
|
|||
class SpellDamage(character: String, val spell: String) : DiceThrow(character)
|
||||
class SpellEffect(character: String, val spell: String, val level: Int) : DiceThrow(character)
|
||||
class Skill(character: String, val skill: String) : DiceThrow(character)
|
||||
class Object(character: String, val item: String) : DiceThrow(character)
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.pixelized.rplexicon.model
|
||||
|
||||
data class ObjectAction(
|
||||
val name: String,
|
||||
val effect: Throw?,
|
||||
)
|
||||
|
|
@ -3,5 +3,6 @@ package com.pixelized.rplexicon.model
|
|||
class Throw(
|
||||
val amount: Int,
|
||||
val faces: Int,
|
||||
val flat: Int,
|
||||
val modifier: List<Property>,
|
||||
)
|
||||
|
|
@ -14,6 +14,7 @@ object CharacterBinder {
|
|||
|
||||
const val CHARACTER = "Feuille de personnage"
|
||||
const val ATTACK = "Attaques"
|
||||
const val OBJECT = "Objets"
|
||||
const val MAGIC = "Magies"
|
||||
const val SKILL = "Capacités"
|
||||
const val MAGIC_LEXICON = "Lexique magique"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
package com.pixelized.rplexicon.repository.data.character
|
||||
|
||||
import com.pixelized.rplexicon.model.ObjectAction
|
||||
import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.repository.data.CharacterBinder
|
||||
import com.pixelized.rplexicon.repository.parser.ObjectActionParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ObjectActionRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val parser: ObjectActionParser
|
||||
) {
|
||||
private val _data = MutableStateFlow<Map<String, List<ObjectAction>>>(emptyMap())
|
||||
val data: StateFlow<Map<String, List<ObjectAction>>> get() = _data
|
||||
|
||||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||
private set
|
||||
|
||||
fun find(character: String?): List<ObjectAction> =
|
||||
_data.value[character] ?: emptyList()
|
||||
|
||||
fun find(character: String?, item: String): ObjectAction? =
|
||||
find(character).firstOrNull { it.name == item }
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchObjectAction() {
|
||||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.OBJECT)
|
||||
val data = parser.parse(data = request.execute())
|
||||
_data.tryEmit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.pixelized.rplexicon.repository.parser
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.model.ObjectAction
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import javax.inject.Inject
|
||||
|
||||
class ObjectActionParser @Inject constructor(
|
||||
private val throwParser: ThrowParser,
|
||||
) {
|
||||
@Throws(IncompatibleSheetStructure::class)
|
||||
fun parse(data: ValueRange): Map<String, List<ObjectAction>> = parserScope {
|
||||
val objects = hashMapOf<String, MutableList<ObjectAction>>()
|
||||
|
||||
data.forEachRow { index, row ->
|
||||
when {
|
||||
index == 0 -> updateStructure(row = row, columns = COLUMNS)
|
||||
|
||||
row.isNotEmpty() -> {
|
||||
val character = row[0]?.toItem()
|
||||
val name = row.parse(column = NAME)
|
||||
val effect = throwParser.parse(value = row.parse(column = EFFECT))
|
||||
if (character != null && name != null && effect != null) {
|
||||
objects.getOrPut(character) { mutableListOf() }.add(
|
||||
ObjectAction(
|
||||
name = name,
|
||||
effect = effect,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return@parserScope objects
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val NAME = "Nom"
|
||||
private const val EFFECT = "Effet"
|
||||
private val COLUMNS = listOf(NAME, EFFECT)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
package com.pixelized.rplexicon.repository.parser
|
||||
|
||||
import com.pixelized.rplexicon.repository.parser.roll.DiceParser
|
||||
import com.pixelized.rplexicon.repository.parser.roll.ModifierParser
|
||||
import com.pixelized.rplexicon.model.Throw
|
||||
import com.pixelized.rplexicon.repository.parser.roll.DiceParser
|
||||
import com.pixelized.rplexicon.repository.parser.roll.FlatValueParser
|
||||
import com.pixelized.rplexicon.repository.parser.roll.ModifierParser
|
||||
import javax.inject.Inject
|
||||
|
||||
class ThrowParser @Inject constructor(
|
||||
private val diceParser: DiceParser,
|
||||
private val flatValueParser: FlatValueParser,
|
||||
private val modifierParser: ModifierParser,
|
||||
) {
|
||||
fun parse(value: String?): Throw? {
|
||||
|
|
@ -14,9 +16,11 @@ class ThrowParser @Inject constructor(
|
|||
val dice = diceParser.findAll(value = value).firstOrNull()
|
||||
if (dice != null) {
|
||||
val modifier = modifierParser.findAll(value = value)
|
||||
val flat = flatValueParser.parse(value = value)
|
||||
return Throw(
|
||||
amount = dice.count,
|
||||
faces = dice.faces,
|
||||
flat = flat,
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,12 @@ import javax.inject.Inject
|
|||
class FlatValueParser @Inject constructor() {
|
||||
|
||||
companion object {
|
||||
private val FLAT_REGEX = Regex("(?<!d|\\d)(-?\\d+)(?!d)")
|
||||
private val FLAT_REGEX = Regex("(?<!d)([-+]?\\s?\\d+)(?!d)")
|
||||
}
|
||||
|
||||
fun parse(value: String): Int {
|
||||
return FLAT_REGEX.findAll(value)
|
||||
.sumOf { it.value.replace(" ", "").toIntOrNull() ?: 0 }
|
||||
}
|
||||
|
||||
fun findAll(title: String, value: String): List<Roll.Bonus> {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ sealed class FetchErrorUio {
|
|||
DESCRIPTION,
|
||||
EQUIPMENT,
|
||||
INVENTORY,
|
||||
OBJECT,
|
||||
SKILL,
|
||||
SPELL,
|
||||
LEXICON,
|
||||
|
|
@ -53,6 +54,7 @@ fun HandleFetchError(
|
|||
FetchErrorUio.Structure.Type.DESCRIPTION -> R.string.error_structure_description
|
||||
FetchErrorUio.Structure.Type.EQUIPMENT -> R.string.error_structure_equipment
|
||||
FetchErrorUio.Structure.Type.INVENTORY -> R.string.error_structure_inventory
|
||||
FetchErrorUio.Structure.Type.OBJECT -> R.string.error_structure_objects
|
||||
FetchErrorUio.Structure.Type.SKILL -> R.string.error_structure_skill
|
||||
FetchErrorUio.Structure.Type.SPELL -> R.string.error_structure_spell
|
||||
FetchErrorUio.Structure.Type.LEXICON -> R.string.error_structure_lexicon
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio
|
|||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ActionPage
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ActionPagePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.AttacksViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.HeaderViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ObjectsViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillsViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SpellsViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationPage
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationPagePreview
|
||||
|
|
@ -93,8 +96,11 @@ fun CharacterSheetScreen(
|
|||
viewModel: CharacterSheetViewModel = hiltViewModel(),
|
||||
inventoryViewModel: InventoryViewModel = hiltViewModel(),
|
||||
proficiencyViewModel: ProficiencyViewModel = hiltViewModel(),
|
||||
headerViewModel: HeaderViewModel = hiltViewModel(),
|
||||
attacksViewModel: AttacksViewModel = hiltViewModel(),
|
||||
objectsViewModel: ObjectsViewModel = hiltViewModel(),
|
||||
spellsViewModel: SpellsViewModel = hiltViewModel(),
|
||||
skillViewModel: SkillsViewModel = hiltViewModel(),
|
||||
alterationsViewModel: AlterationViewModel = hiltViewModel(),
|
||||
) {
|
||||
val snack = LocalSnack.current
|
||||
|
|
@ -153,8 +159,11 @@ fun CharacterSheetScreen(
|
|||
actions = {
|
||||
ActionPage(
|
||||
sheetState = sheetState,
|
||||
headerViewModel = headerViewModel,
|
||||
attacksViewModel = attacksViewModel,
|
||||
objectsViewModel = objectsViewModel,
|
||||
spellsViewModel = spellsViewModel,
|
||||
skillViewModel = skillViewModel,
|
||||
)
|
||||
},
|
||||
alterations = {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.pixelized.rplexicon.repository.data.character.CharacterSheetRepositor
|
|||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.EquipmentRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.InventoryRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.composable.error.FetchErrorUio
|
||||
|
|
@ -35,6 +36,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
private val inventoryRepository: InventoryRepository,
|
||||
private val equipmentRepository: EquipmentRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
private val objectRepository: ObjectActionRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
|
|
@ -124,6 +126,16 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
val objects = async {
|
||||
if (force || objectRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||
try {
|
||||
objectRepository.fetchObjectAction()
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, exception.message, exception)
|
||||
_error.emit(FetchErrorUio.Structure(type = Type.OBJECT))
|
||||
}
|
||||
}
|
||||
}
|
||||
val spells = async {
|
||||
if (force || spellRepository.lastSuccessFullUpdate.shouldUpdate()) {
|
||||
try {
|
||||
|
|
@ -144,7 +156,7 @@ class CharacterSheetViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
awaitAll(description, alterations, inventory, equipment, actions, spells, skill)
|
||||
awaitAll(description, alterations, inventory, equipment, actions, objects, spells, skill)
|
||||
_isLoading.value = false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
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.OutlinedButton
|
||||
import androidx.compose.material3.Surface
|
||||
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.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Stable
|
||||
data class ObjectItemUio(
|
||||
val name: String,
|
||||
val original: String?,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
@Composable
|
||||
fun ObjectItem(
|
||||
modifier: Modifier = Modifier,
|
||||
padding: PaddingValues = PaddingValues(top = 4.dp, bottom = 4.dp, start = 16.dp, end = 16.dp),
|
||||
item: ObjectItemUio,
|
||||
onObject: (String) -> Unit,
|
||||
onUse: (String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable { onObject(item.name) }
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(weight = 1f)
|
||||
) {
|
||||
FlowRow(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = item.name,
|
||||
)
|
||||
item.original?.let {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontWeight = FontWeight.Light,
|
||||
fontStyle = FontStyle.Italic,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutlinedButton(
|
||||
border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
onClick = { onUse(item.name) },
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.character_sheet_action_spell_cast),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun ObjectItemPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
ObjectItem(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
item = ObjectItemUio(
|
||||
name = "Potion de guérison",
|
||||
original = "Healing potion",
|
||||
),
|
||||
onObject = { },
|
||||
onUse = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.preview
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberObjectListStatePreview() = remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
ObjectItemUio(
|
||||
name = "Potion de guérison",
|
||||
original = "Healing potion",
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -17,13 +17,10 @@ import androidx.compose.material.ModalBottomSheetState
|
|||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.LocalRollOverlay
|
||||
import com.pixelized.rplexicon.R
|
||||
|
|
@ -35,6 +32,8 @@ import com.pixelized.rplexicon.ui.navigation.screens.navigateToSpellDetail
|
|||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.Attack
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.GenericHeader
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItem
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
|
||||
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.Spell
|
||||
|
|
@ -46,6 +45,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.Charact
|
|||
import com.pixelized.rplexicon.ui.screens.character.composable.character.CharacterSheetHeaderUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberAttackListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberCharacterHeaderStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberObjectListStatePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberSpellListStatePreview
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -56,6 +56,7 @@ fun ActionPage(
|
|||
sheetState: ModalBottomSheetState,
|
||||
headerViewModel: HeaderViewModel = hiltViewModel(),
|
||||
attacksViewModel: AttacksViewModel = hiltViewModel(),
|
||||
objectsViewModel: ObjectsViewModel = hiltViewModel(),
|
||||
spellsViewModel: SpellsViewModel = hiltViewModel(),
|
||||
skillViewModel: SkillsViewModel = hiltViewModel(),
|
||||
) {
|
||||
|
|
@ -67,6 +68,7 @@ fun ActionPage(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
header = headerViewModel.header,
|
||||
attacks = attacksViewModel.attacks,
|
||||
objects = objectsViewModel.objects,
|
||||
tokens = skillViewModel.skills,
|
||||
spells = spellsViewModel.spells,
|
||||
onHitPoint = headerViewModel::toggleHitPointDialog,
|
||||
|
|
@ -82,6 +84,15 @@ fun ActionPage(
|
|||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onObject = {
|
||||
|
||||
},
|
||||
onUseObject = { id ->
|
||||
objectsViewModel.onUse(id)?.let {
|
||||
overlay.prepareRoll(diceThrow = it)
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onSkillCount = {
|
||||
skillViewModel.showSkillEditDialog(item = it)
|
||||
},
|
||||
|
|
@ -151,11 +162,14 @@ fun ActionsPageContent(
|
|||
lazyListState: LazyListState = rememberLazyListState(),
|
||||
header: State<CharacterSheetHeaderUio?>,
|
||||
attacks: State<List<AttackUio>>,
|
||||
objects: State<List<ObjectItemUio>>,
|
||||
tokens: State<List<SkillItemUio>>,
|
||||
spells: State<List<Pair<SpellHeaderUio, List<SpellUio>>>>,
|
||||
onHitPoint: () -> Unit,
|
||||
onAttackHit: (id: String) -> Unit,
|
||||
onAttackDamage: (id: String) -> Unit,
|
||||
onObject: (id: String) -> Unit,
|
||||
onUseObject: (id: String) -> Unit,
|
||||
onSkillThrow: (SkillItemUio) -> Unit,
|
||||
onSkillCount: (SkillItemUio) -> Unit,
|
||||
onSkillInfo: (SkillItemUio) -> Unit,
|
||||
|
|
@ -195,6 +209,24 @@ fun ActionsPageContent(
|
|||
}
|
||||
}
|
||||
|
||||
if (objects.value.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
GenericHeader(
|
||||
label = R.string.character_sheet_title_objects,
|
||||
)
|
||||
}
|
||||
items(items = objects.value) {
|
||||
ObjectItem(
|
||||
item = it,
|
||||
onObject = onObject,
|
||||
onUse = onUseObject,
|
||||
)
|
||||
}
|
||||
items(count = 1) {
|
||||
Spacer(modifier = Modifier.height(height = 16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
if (tokens.value.isNotEmpty()) {
|
||||
stickyHeader {
|
||||
GenericHeader(
|
||||
|
|
@ -248,11 +280,14 @@ fun ActionPagePreview() {
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
header = rememberCharacterHeaderStatePreview(),
|
||||
attacks = rememberAttackListStatePreview(),
|
||||
objects = rememberObjectListStatePreview(),
|
||||
tokens = rememberTokenListStatePreview(),
|
||||
spells = rememberSpellListStatePreview(),
|
||||
onHitPoint = { },
|
||||
onAttackHit = { },
|
||||
onAttackDamage = { },
|
||||
onObject = { },
|
||||
onUseObject = { },
|
||||
onSkillCount = { },
|
||||
onSkillThrow = { },
|
||||
onSkillInfo = { },
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.pages.actions
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.repository.data.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class ObjectsViewModel @Inject constructor(
|
||||
private val objectsRepository: ObjectActionRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
val character = savedStateHandle.characterSheetArgument.name
|
||||
|
||||
private val _objects = mutableStateOf<List<ObjectItemUio>>(emptyList())
|
||||
val objects: State<List<ObjectItemUio>> get() = _objects
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
objectsRepository.data.collect { objects ->
|
||||
val data = objects[character]?.map {
|
||||
ObjectItemUio(
|
||||
name = it.name,
|
||||
original = descriptionRepository.find(name = it.name)?.original
|
||||
)
|
||||
} ?: emptyList()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
_objects.value = data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onObject(name: String) {
|
||||
|
||||
}
|
||||
|
||||
fun onUse(name: String): DiceThrow? {
|
||||
val item = objectsRepository.find(character = character, item = name)
|
||||
return item?.let {
|
||||
DiceThrow.Object(
|
||||
character = character,
|
||||
item = it.name,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,6 +78,8 @@ class AlterationFactory @Inject constructor(
|
|||
listOf(Property.PHYSICAL_RANGE_ATTACK) + (action?.hit?.modifier ?: emptyList())
|
||||
}
|
||||
|
||||
is DiceThrow.Object -> emptyList()
|
||||
|
||||
is DiceThrow.PhysicalRangeDamage -> {
|
||||
val action = actionRepository.find(diceThrow.character, action = diceThrow.weapon)
|
||||
listOf(Property.PHYSICAL_RANGE_DAMAGE) + (action?.damage?.modifier ?: emptyList())
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.pixelized.rplexicon.ui.screens.rolls.factory
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.repository.data.character.ActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.ObjectActionRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SkillRepository
|
||||
import com.pixelized.rplexicon.repository.data.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
|
|
@ -11,6 +12,7 @@ import javax.inject.Inject
|
|||
|
||||
class DiceFactory @Inject constructor(
|
||||
private val actionRepository: ActionRepository,
|
||||
private val objectActionRepository: ObjectActionRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
) {
|
||||
|
|
@ -50,6 +52,13 @@ class DiceFactory @Inject constructor(
|
|||
RollDiceUio(icon = it)
|
||||
}
|
||||
|
||||
is DiceThrow.Object -> objectActionRepository.find(
|
||||
character = diceThrow.character,
|
||||
item = diceThrow.item,
|
||||
)?.effect?.faces?.icon?.let {
|
||||
RollDiceUio(icon = it)
|
||||
}
|
||||
|
||||
else -> RollDiceUio(icon = R.drawable.ic_d20_24)
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
<string name="error_structure_description">La structure de la feuille de description semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
<string name="error_structure_equipment">La structure de la feuille d\'équipement semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
<string name="error_structure_inventory">La structure de la feuille d\'inventaire semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
<string name="error_structure_objects">La structure de la feuille d\'actions (object) semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
<string name="error_structure_skill">La structure de la feuille des talents semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
<string name="error_structure_spell">La structure de la feuille des sorts semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
<string name="error_structure_lexicon">La structure du lexique semble avoir changé et n\'est plus compatible avec cette application.</string>
|
||||
|
|
@ -99,6 +100,7 @@
|
|||
<string name="character_sheet_title_proficiencies">Maîtrises</string>
|
||||
<string name="character_sheet_title_skills">Capacités</string>
|
||||
<string name="character_sheet_title_attacks">Attaques</string>
|
||||
<string name="character_sheet_title_objects">Objets</string>
|
||||
<string name="character_sheet_title_inventory">Inventaire</string>
|
||||
<string name="character_sheet_title_equipment">Equipement</string>
|
||||
<string name="character_sheet_stat_strength">Force</string>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<string name="error_structure_description">The description sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
<string name="error_structure_equipment">The equipment sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
<string name="error_structure_inventory">The inventory sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
<string name="error_structure_objects">The objects sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
<string name="error_structure_skill">The skill sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
<string name="error_structure_spell">The spell sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
<string name="error_structure_lexicon">The lexicon sheet structure appears to have changed and is no longer compatible with this application</string>
|
||||
|
|
@ -98,6 +99,7 @@
|
|||
<string name="character_sheet_title_saving_throws">Saving Throws</string>
|
||||
<string name="character_sheet_title_proficiencies">Proficiencies</string>
|
||||
<string name="character_sheet_title_attacks">Attacks</string>
|
||||
<string name="character_sheet_title_objects">Objects</string>
|
||||
<string name="character_sheet_title_skills">Skills</string>
|
||||
<string name="character_sheet_title_inventory">Inventory</string>
|
||||
<string name="character_sheet_title_equipment">Equipment</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue