Nam integration into the app and some small releated fixes.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2025-01-17 10:48:34 +01:00
parent d5736c99ee
commit 5fdf262bde
13 changed files with 19 additions and 146 deletions

View file

@ -10,7 +10,6 @@ import com.pixelized.rplexicon.data.repository.character.ActionRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.data.repository.character.EquipmentRepository
import com.pixelized.rplexicon.data.repository.character.ItemsRepository import com.pixelized.rplexicon.data.repository.character.ItemsRepository
import com.pixelized.rplexicon.data.repository.character.SkillRepository import com.pixelized.rplexicon.data.repository.character.SkillRepository
import com.pixelized.rplexicon.data.repository.character.SpellRepository import com.pixelized.rplexicon.data.repository.character.SpellRepository
@ -44,7 +43,6 @@ class LauncherViewModel @Inject constructor(
skillRepository: SkillRepository, skillRepository: SkillRepository,
descriptionRepository: DescriptionRepository, descriptionRepository: DescriptionRepository,
itemsRepository: ItemsRepository, itemsRepository: ItemsRepository,
equipmentRepository: EquipmentRepository,
removeConRepository: RemoteConfigRepository // Unused but injected to initialize it. removeConRepository: RemoteConfigRepository // Unused but injected to initialize it.
) : ViewModel() { ) : ViewModel() {
@ -112,14 +110,6 @@ class LauncherViewModel @Inject constructor(
_error.emit(FetchErrorUio.Structure(type = Type.INVENTORY)) _error.emit(FetchErrorUio.Structure(type = Type.INVENTORY))
} }
} }
val equipment = async {
try {
equipmentRepository.fetchEquipment()
} catch (exception: Exception) {
Log.e(TAG, exception.message, exception)
_error.emit(FetchErrorUio.Structure(type = Type.EQUIPMENT))
}
}
awaitAll(characterSheet) awaitAll(characterSheet)
val alteration = async { val alteration = async {
@ -156,7 +146,7 @@ class LauncherViewModel @Inject constructor(
} }
awaitAll(order, lexicon, location, quest) awaitAll(order, lexicon, location, quest)
awaitAll(description, inventory, equipment, alteration, action, spell, skill) awaitAll(description, inventory, alteration, action, spell, skill)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
isLoading = false isLoading = false

View file

@ -5,6 +5,7 @@ import androidx.annotation.StringRes
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
data class CharacterSheet( data class CharacterSheet(
val active: Boolean,
val name: String, val name: String,
val race: String?, val race: String?,
val proficiency: Int, // Bonus de maîtrise val proficiency: Int, // Bonus de maîtrise
@ -22,7 +23,7 @@ data class CharacterSheet(
val spell9: Int?, // level 9 spell slot val spell9: Int?, // level 9 spell slot
val dC: Int?, // offensive saving throw. val dC: Int?, // offensive saving throw.
val armorClass: Int, // Classe d'armure val armorClass: Int, // Classe d'armure
val speed: Int, // Vitesse val speed: Float, // Vitesse
val strength: Int, // Force val strength: Int, // Force
val dexterity: Int, // Dextérité val dexterity: Int, // Dextérité
val constitution: Int, // Constitution val constitution: Int, // Constitution

View file

@ -33,6 +33,7 @@ class CharacterSheetParser @Inject constructor(
val name = item.parse(column = NAME) val name = item.parse(column = NAME)
if (name != null) { if (name != null) {
CharacterSheet( CharacterSheet(
active = item.parseBool(column = ACTIVE) ?: false,
name = name, name = name,
race = item.parse(column = RACE), race = item.parse(column = RACE),
proficiency = item.parseInt(column = MASTERY) ?: 2, proficiency = item.parseInt(column = MASTERY) ?: 2,
@ -50,7 +51,7 @@ class CharacterSheetParser @Inject constructor(
spell9 = item.parseInt(column = SPELL_LEVEL_9), spell9 = item.parseInt(column = SPELL_LEVEL_9),
dC = item.parseInt(column = DD_SAVE_THROW), dC = item.parseInt(column = DD_SAVE_THROW),
armorClass = item.parseInt(column = ARMOR_CLASS) ?: 10, armorClass = item.parseInt(column = ARMOR_CLASS) ?: 10,
speed = item.parseInt(column = SPEED) ?: 10, speed = item.parseFloat(column = SPEED) ?: 10f,
strength = item.parseInt(column = STRENGTH) ?: 10, strength = item.parseInt(column = STRENGTH) ?: 10,
dexterity = item.parseInt(column = DEXTERITY) ?: 10, dexterity = item.parseInt(column = DEXTERITY) ?: 10,
constitution = item.parseInt(column = CONSTITUTION) ?: 10, constitution = item.parseInt(column = CONSTITUTION) ?: 10,
@ -103,6 +104,7 @@ class CharacterSheetParser @Inject constructor(
} }
companion object { companion object {
private val ACTIVE = column("Actif")
private val NAME = column("Nom") private val NAME = column("Nom")
private val RACE = column("Race") private val RACE = column("Race")
private val LEVEL = column("Niveau") private val LEVEL = column("Niveau")
@ -157,6 +159,7 @@ class CharacterSheetParser @Inject constructor(
private val ROWS private val ROWS
get() = listOf( get() = listOf(
ACTIVE,
NAME, NAME,
RACE, RACE,
LEVEL, LEVEL,

View file

@ -1,71 +0,0 @@
package com.pixelized.rplexicon.data.parser.inventory
import com.google.api.services.sheets.v4.model.ValueRange
import com.pixelized.rplexicon.data.model.Equipment
import com.pixelized.rplexicon.data.parser.parserScope
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
import javax.inject.Inject
class EquipmentParser @Inject constructor() {
@Throws(IncompatibleSheetStructure::class)
fun parse(data: ValueRange): Map<String, Equipment> = parserScope {
lateinit var characters: List<String>
val equipments = hashMapOf<String, Equipment.Builder>()
data.forEachRowIndexed { index, row ->
when (index) {
// ignore the first column
0 -> characters = row.drop(1).map { it.toString() }
else -> row.drop(1).forEachIndexed { column, item ->
val character = characters[column]
equipments.getEquipment(name = character).let {
when (row[0]) {
BACKGROUND -> it.background = item.toItem()
HEAD -> it.head = item.toItem()
FACE -> it.face = item.toItem()
NECK -> it.neck = item.toItem()
SHOULDER -> it.shoulder = item.toItem()
BODY -> it.body = item.toItem()
CHEST -> it.chest = item.toItem()
ARM -> it.arm = item.toItem()
HAND -> it.hand = item.toItem()
RING_1 -> it.ring1 = item.toItem()
RING_2 -> it.ring2 = item.toItem()
WAIST -> it.waist = item.toItem()
FOOT -> it.foot = item.toItem()
MAIN_HAND -> it.mainHand = item.toItem()
OFF_HAND -> it.offHand = item.toItem()
}
}
}
}
}
return@parserScope characters.associateWith {
equipments.getEquipment(name = it).build()
}
}
private fun HashMap<String, Equipment.Builder>.getEquipment(name: String) =
this.getOrPut(name) { Equipment.Builder() }
companion object {
private const val BACKGROUND = "Silhouette"
private const val HEAD = "Tête"
private const val FACE = "Visage"
private const val NECK = "Gorge"
private const val SHOULDER = "Épaules"
private const val BODY = "Corp"
private const val CHEST = "Torse"
private const val ARM = "Bras"
private const val HAND = "Mains"
private const val RING_1 = "Anneau 1"
private const val RING_2 = "Anneau 2"
private const val WAIST = "Taille"
private const val FOOT = "Pieds"
private const val MAIN_HAND = "Main droite"
private const val OFF_HAND = "Main gauche"
}
}

View file

@ -1,36 +0,0 @@
package com.pixelized.rplexicon.data.repository.character
import com.pixelized.rplexicon.data.model.Equipment
import com.pixelized.rplexicon.data.parser.inventory.EquipmentParser
import com.pixelized.rplexicon.data.repository.CharacterBinder
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
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 EquipmentRepository @Inject constructor(
private val googleRepository: GoogleSheetServiceRepository,
private val equipmentParser: EquipmentParser,
) {
private val _data = MutableStateFlow<Map<String, Equipment>>(emptyMap())
val data: StateFlow<Map<String, Equipment>> get() = _data
var lastSuccessFullUpdate: Update = Update.INITIAL
private set
fun find(name: String?): Equipment? = _data.value[name]
@Throws(IncompatibleSheetStructure::class, Exception::class)
suspend fun fetchEquipment() {
googleRepository.fetch { sheet ->
val request = sheet.get(CharacterBinder.ID, CharacterBinder.EQUIPMENT)
val data = equipmentParser.parse(data = request.execute())
_data.tryEmit(data)
lastSuccessFullUpdate = Update.currentTime()
}
}
}

View file

@ -320,7 +320,10 @@ private fun rememberPortrait(): List<Int> = rememberSaveable {
listOf( listOf(
R.drawable.im_brulkhai, R.drawable.im_brulkhai,
R.drawable.im_leandre, R.drawable.im_leandre,
R.drawable.im_nelia, // listOf(
// R.drawable.im_nelia,
R.drawable.im_nam,
// ).shuffled().first(),
R.drawable.im_tigrane, R.drawable.im_tigrane,
R.drawable.im_unathana, R.drawable.im_unathana,
).shuffled() ).shuffled()

View file

@ -105,10 +105,7 @@ enum class CharacterTabUio(@StringRes val label: Int) {
Proficiency(R.string.character_sheet_tab_proficiency), Proficiency(R.string.character_sheet_tab_proficiency),
} }
@OptIn( @OptIn(ExperimentalMaterialApi::class)
ExperimentalMaterialApi::class,
ExperimentalFoundationApi::class,
)
@Composable @Composable
fun CharacterSheetScreen( fun CharacterSheetScreen(
viewModel: CharacterSheetViewModel = hiltViewModel(), viewModel: CharacterSheetViewModel = hiltViewModel(),
@ -490,7 +487,6 @@ private fun CharacterScreenPreview(
} }
} }
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterialApi::class)
@Composable @Composable
private fun BackHandler( private fun BackHandler(
sheetState: ModalBottomSheetState, sheetState: ModalBottomSheetState,

View file

@ -10,7 +10,6 @@ import com.pixelized.rplexicon.data.repository.character.ActionRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
import com.pixelized.rplexicon.data.repository.character.EquipmentRepository
import com.pixelized.rplexicon.data.repository.character.ItemsRepository import com.pixelized.rplexicon.data.repository.character.ItemsRepository
import com.pixelized.rplexicon.data.repository.character.SkillRepository import com.pixelized.rplexicon.data.repository.character.SkillRepository
import com.pixelized.rplexicon.data.repository.character.SpellRepository import com.pixelized.rplexicon.data.repository.character.SpellRepository
@ -33,7 +32,6 @@ class CharacterSheetViewModel @Inject constructor(
private val descriptionRepository: DescriptionRepository, private val descriptionRepository: DescriptionRepository,
private val alterationRepository: AlterationRepository, private val alterationRepository: AlterationRepository,
private val itemsRepository: ItemsRepository, private val itemsRepository: ItemsRepository,
private val equipmentRepository: EquipmentRepository,
private val actionRepository: ActionRepository, private val actionRepository: ActionRepository,
private val spellRepository: SpellRepository, private val spellRepository: SpellRepository,
private val skillRepository: SkillRepository, private val skillRepository: SkillRepository,
@ -93,16 +91,6 @@ class CharacterSheetViewModel @Inject constructor(
} }
} }
} }
val equipment = async {
if (force || equipmentRepository.lastSuccessFullUpdate.shouldUpdate()) {
try {
equipmentRepository.fetchEquipment()
} catch (exception: Exception) {
Log.e(TAG, exception.message, exception)
_error.emit(FetchErrorUio.Structure(type = Type.EQUIPMENT))
}
}
}
awaitAll(characters) awaitAll(characters)
val alterations = async { val alterations = async {
if (force || alterationRepository.lastSuccessFullUpdate.shouldUpdate()) { if (force || alterationRepository.lastSuccessFullUpdate.shouldUpdate()) {
@ -144,7 +132,7 @@ class CharacterSheetViewModel @Inject constructor(
} }
} }
} }
awaitAll(description, alterations, inventory, equipment, actions, spells, skills) awaitAll(description, alterations, inventory, actions, spells, skills)
_isLoading.value = false _isLoading.value = false
} }

View file

@ -281,7 +281,7 @@ class CharacterSheetUioFactory @Inject constructor() {
), ),
speed = LabelPointUio( speed = LabelPointUio(
label = R.string.character_sheet_title_speed, label = R.string.character_sheet_title_speed,
value = "${max(sheet.speed + status[Property.SPEED].sum, 0)}m", value = "${max(sheet.speed + status[Property.SPEED].sum.toFloat(), 0f)}m",
), ),
masteries = MasteriesUio( masteries = MasteriesUio(
martial = sheet.martial, martial = sheet.martial,

View file

@ -25,6 +25,9 @@ class SpellUioFactory @Inject constructor(
val modifier = diceThrow.modifier.sumOf { val modifier = diceThrow.modifier.sumOf {
when (it) { when (it) {
Property.PROFICIENCY -> characterSheet.proficiency Property.PROFICIENCY -> characterSheet.proficiency
Property.STRENGTH -> characterSheet.strength.modifier
Property.DEXTERITY -> characterSheet.dexterity.modifier
Property.CONSTITUTION -> characterSheet.constitution.modifier
Property.INTELLIGENCE -> characterSheet.intelligence.modifier Property.INTELLIGENCE -> characterSheet.intelligence.modifier
Property.WISDOM -> characterSheet.wisdom.modifier Property.WISDOM -> characterSheet.wisdom.modifier
Property.CHARISMA -> characterSheet.charisma.modifier Property.CHARISMA -> characterSheet.charisma.modifier

View file

@ -146,7 +146,7 @@ class SummaryFactory @Inject constructor(
val data = DataStruct() val data = DataStruct()
characterSheetRepository.data characterSheetRepository.data
.combine(activeAlterationRepository.getActiveAlterations()) { sheets, alterations -> .combine(activeAlterationRepository.getActiveAlterations()) { sheets, alterations ->
data.sheets = sheets data.sheets = sheets.filter { entry -> entry.value.active }
data.alterations = alterations data.alterations = alterations
} }
.combine(firebaseRepository.getCharacters()) { _, fire -> .combine(firebaseRepository.getCharacters()) { _, fire ->
@ -216,7 +216,7 @@ class SummaryFactory @Inject constructor(
label = (dexterity.modifier + status[Property.INITIATIVE].sum).toLabel() label = (dexterity.modifier + status[Property.INITIATIVE].sum).toLabel()
) )
val speed = label( val speed = label(
label = "${max(sheet.speed + status[Property.SPEED].sum, 0)}m", label = "${max(sheet.speed + status[Property.SPEED].sum.toFloat(), 0f)}m",
) )
val inspiration = proficiency( val inspiration = proficiency(
label = null, label = null,

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -6,10 +6,6 @@ pluginManagement {
} }
} }
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.6.0"
}
dependencyResolutionManagement { dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories { repositories {