Refactor the alteration system to be full flow.
This commit is contained in:
parent
8841529b31
commit
6ea8f90903
41 changed files with 688 additions and 452 deletions
|
|
@ -0,0 +1,25 @@
|
|||
package com.pixelized.rplexicon.business
|
||||
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
|
||||
object AlterationSortUseCase {
|
||||
|
||||
private const val PLAYER = "Joueur"
|
||||
private const val FEAT = "Don"
|
||||
|
||||
fun sort(sheet: CharacterSheet?): Comparator<String> {
|
||||
return compareByDescending<String> {
|
||||
sheet?.name == it
|
||||
}.thenByDescending {
|
||||
PLAYER == it
|
||||
}.thenByDescending {
|
||||
sheet?.characterClass?.any { clazz -> clazz.value == it }
|
||||
}.thenByDescending {
|
||||
sheet?.race == it
|
||||
}.thenByDescending {
|
||||
FEAT == it
|
||||
}.thenBy {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,12 @@ package com.pixelized.rplexicon.business
|
|||
import android.app.Application
|
||||
import android.content.Context
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
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.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.roll.Flat
|
||||
import com.pixelized.rplexicon.data.model.roll.Throw
|
||||
import com.pixelized.rplexicon.data.network.NetworkThrow
|
||||
|
|
@ -20,7 +20,6 @@ import com.pixelized.rplexicon.data.repository.character.SkillRepository
|
|||
import com.pixelized.rplexicon.data.repository.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.advantage
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.base
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.critical
|
||||
|
|
@ -36,6 +35,8 @@ import com.pixelized.rplexicon.utilitary.extentions.local.sum
|
|||
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
|
||||
import com.pixelized.rplexicon.utilitary.extentions.masteryMultiplier
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
|
@ -57,14 +58,15 @@ class DiceThrowUseCase @Inject constructor(
|
|||
private val skillRepository: SkillRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
) {
|
||||
fun roll(
|
||||
suspend 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) }
|
||||
val alterations =
|
||||
alterationRepository.getAssignedAlterations(diceThrow.character).firstOrNull()
|
||||
?.filter { alterationId.contains(it.name) } ?: emptyList()
|
||||
|
||||
return if (sheet != null) {
|
||||
when (diceThrow) {
|
||||
|
|
@ -393,15 +395,12 @@ class DiceThrowUseCase @Inject constructor(
|
|||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
val objectAlterations = alterationRepository.getAlterations(
|
||||
objects = action?.alterations,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.hit,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = alterations + objectAlterations,
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_MELEE_ATTACK,
|
||||
)
|
||||
}
|
||||
|
|
@ -411,15 +410,12 @@ class DiceThrowUseCase @Inject constructor(
|
|||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
val objectAlterations = alterationRepository.getAlterations(
|
||||
objects = action?.alterations,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.damage,
|
||||
title = { getString(R.string.dice_roll_attack_damage_title, it) },
|
||||
alterations = alterations + objectAlterations,
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_MELEE_DAMAGE,
|
||||
)
|
||||
}
|
||||
|
|
@ -429,15 +425,12 @@ class DiceThrowUseCase @Inject constructor(
|
|||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
val objectAlterations = alterationRepository.getAlterations(
|
||||
objects = action?.alterations,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.hit,
|
||||
title = { getString(R.string.dice_roll_attack_hit_title, it) },
|
||||
alterations = alterations + objectAlterations,
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_RANGE_ATTACK,
|
||||
)
|
||||
}
|
||||
|
|
@ -447,15 +440,12 @@ class DiceThrowUseCase @Inject constructor(
|
|||
character = diceThrow.character,
|
||||
action = diceThrow.weapon,
|
||||
)
|
||||
val objectAlterations = alterationRepository.getAlterations(
|
||||
objects = action?.alterations,
|
||||
)
|
||||
actionThrow(
|
||||
character = sheet,
|
||||
action = diceThrow.weapon,
|
||||
diceThrow = action?.damage,
|
||||
title = { getString(R.string.dice_roll_attack_damage_title, it) },
|
||||
alterations = alterations + objectAlterations,
|
||||
alterations = alterations,
|
||||
ability = Property.PHYSICAL_RANGE_DAMAGE,
|
||||
)
|
||||
}
|
||||
|
|
@ -750,11 +740,13 @@ class DiceThrowUseCase @Inject constructor(
|
|||
// compute the amount of main dice to throw.
|
||||
val amount = if (status.isCritical) {
|
||||
diceThrow?.dice?.count?.times(2)?.let {
|
||||
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isSavageAttacks)
|
||||
it.plus(1) else it
|
||||
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isSavageAttacks) it.plus(
|
||||
1
|
||||
) else it
|
||||
}?.let {
|
||||
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isBrutalCritical)
|
||||
it.plus(1) else it
|
||||
if (ability == Property.PHYSICAL_MELEE_DAMAGE && status.isBrutalCritical) it.plus(
|
||||
1
|
||||
) else it
|
||||
}
|
||||
} else {
|
||||
diceThrow?.dice?.count
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ class SearchUseCase @Inject constructor(
|
|||
return spells.filter {
|
||||
criterion.map { criteria ->
|
||||
val schoolName = context.getString(it.school.label)
|
||||
val itemDescription = descriptionRepository.find(name = it.name)
|
||||
val itemDescription = descriptionRepository.getDescription(name = it.name)
|
||||
val name = it.name.contains(criteria, true)
|
||||
val translated = itemDescription?.original?.contains(criteria, true) == true
|
||||
val school = schoolName.contains(criteria, true)
|
||||
|
|
@ -333,7 +333,7 @@ class SearchUseCase @Inject constructor(
|
|||
}.all { it }
|
||||
}.map { item ->
|
||||
val school = context.getString(item.school.label)
|
||||
val itemDescription = descriptionRepository.find(name = item.name)
|
||||
val itemDescription = descriptionRepository.getDescription(name = item.name)
|
||||
|
||||
SearchItemUio.SpellSearchItemUio(
|
||||
id = item.name,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ data class CharacterSheet(
|
|||
val others: List<String>, // others masteries
|
||||
) {
|
||||
val isWarlock: Boolean get() = characterClass.contains(Class.WARLOCK)
|
||||
val resource: String? get() = characterClass.firstNotNullOfOrNull { it.resource }
|
||||
|
||||
enum class Class(
|
||||
val value: String,
|
||||
|
|
@ -82,7 +83,12 @@ data class CharacterSheet(
|
|||
label = R.string.character_sheet_title_conduit,
|
||||
icon = R.drawable.ic_class_cleric_24
|
||||
),
|
||||
DRUID(value = "Druide", icon = R.drawable.ic_class_druid_24),
|
||||
DRUID(
|
||||
value = "Druide",
|
||||
resource = "Forme sauvage",
|
||||
label = R.string.character_sheet_title_wild_shape,
|
||||
icon = R.drawable.ic_class_druid_24,
|
||||
),
|
||||
FIGHTER(value = "Guerrier", icon = R.drawable.ic_class_fighter_24),
|
||||
MONK(value = "Moine", icon = R.drawable.ic_class_monk_24),
|
||||
PALADIN(value = "Paladin", icon = R.drawable.ic_class_paladin_24),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.pixelized.rplexicon.data.model
|
||||
package com.pixelized.rplexicon.data.model.alteration
|
||||
|
||||
import android.net.Uri
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.roll.Dice
|
||||
import com.pixelized.rplexicon.data.model.roll.Flat
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.pixelized.rplexicon.data.model.alteration
|
||||
|
||||
abstract class AlterationStatus {
|
||||
data class Key(
|
||||
val character: String,
|
||||
val alteration: String,
|
||||
)
|
||||
|
||||
data class Value(
|
||||
val value: Boolean,
|
||||
) {
|
||||
fun switch(): Value = Value(value = !value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun entry(character: String, alteration: String, value: Boolean): Pair<Key, Value> =
|
||||
Key(character = character, alteration = alteration) to Value(value = value)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.pixelized.rplexicon.data.parser.alteration
|
||||
|
||||
import com.google.api.services.sheets.v4.model.ValueRange
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.parser.column
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.google.firebase.database.ValueEventListener
|
|||
import com.google.firebase.database.ktx.database
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFireMap
|
||||
import com.pixelized.rplexicon.data.network.NetworkThrow
|
||||
|
|
@ -20,13 +21,13 @@ import kotlinx.coroutines.cancel
|
|||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.callbackFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.flow.mapNotNull
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -34,7 +35,6 @@ import javax.inject.Singleton
|
|||
class FirebaseRepository @Inject constructor(
|
||||
application: Application,
|
||||
) {
|
||||
private val externalScope: CoroutineScope = CoroutineScope(Dispatchers.Default + Job())
|
||||
private val database = Firebase.database(
|
||||
url = application.getString(R.string.firebase_realtime_database),
|
||||
)
|
||||
|
|
@ -42,84 +42,105 @@ class FirebaseRepository @Inject constructor(
|
|||
private val _error = MutableSharedFlow<Exception>()
|
||||
val error: SharedFlow<Exception> get() = _error
|
||||
|
||||
val status: StateFlow<Map<String, Boolean>>
|
||||
private val characterFireSheet: StateFlow<Map<String, CharacterSheetFire>> = callbackFlow {
|
||||
// reference to the node
|
||||
val reference = database.getReference("/")
|
||||
// build a register the callback
|
||||
val listener = reference.addValueEventListener(object : ValueEventListener {
|
||||
override fun onDataChange(dataSnapshot: DataSnapshot) {
|
||||
val value = try {
|
||||
dataSnapshot.getValue(CharacterSheetFireMap::class.java)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to parse value.", exception)
|
||||
_error.tryEmit(exception)
|
||||
null
|
||||
}
|
||||
if (value != null) {
|
||||
trySend(value.characters)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(error: DatabaseError) {
|
||||
Log.e(TAG, "Failed to read value.", error.toException())
|
||||
cancel()
|
||||
}
|
||||
})
|
||||
awaitClose {
|
||||
reference.removeEventListener(listener)
|
||||
}
|
||||
}.stateIn(
|
||||
scope = CoroutineScope(Dispatchers.Default + Job()),
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = emptyMap()
|
||||
)
|
||||
|
||||
private val networkThrows = callbackFlow {
|
||||
// reference to the node
|
||||
val reference = database.getReference("/")
|
||||
// build a register the callback
|
||||
val listener = reference.addValueEventListener(object : ValueEventListener {
|
||||
override fun onDataChange(dataSnapshot: DataSnapshot) {
|
||||
val value = try {
|
||||
dataSnapshot.getValue(NetworkThrowMap::class.java)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to parse value.", exception)
|
||||
_error.tryEmit(exception)
|
||||
null
|
||||
}
|
||||
if (value != null) {
|
||||
trySend(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(error: DatabaseError) {
|
||||
Log.e(TAG, "Failed to read value.", error.toException())
|
||||
cancel()
|
||||
}
|
||||
})
|
||||
awaitClose {
|
||||
reference.removeEventListener(listener)
|
||||
}
|
||||
}.stateIn(
|
||||
scope = CoroutineScope(Dispatchers.Default + Job()),
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = NetworkThrowMap(),
|
||||
)
|
||||
|
||||
private val alterationStatus: StateFlow<Map<AlterationStatus.Key, AlterationStatus.Value>> =
|
||||
characterFireSheet.map { fireSheets: Map<String, CharacterSheetFire> ->
|
||||
fireSheets.flatMap { fireCharacter: Map.Entry<String, CharacterSheetFire> ->
|
||||
fireCharacter.value.alterations.map { alteration ->
|
||||
AlterationStatus.entry(
|
||||
character = fireCharacter.key,
|
||||
alteration = alteration.key,
|
||||
value = alteration.value,
|
||||
)
|
||||
}
|
||||
}.toMap()
|
||||
}.stateIn(
|
||||
scope = CoroutineScope(Dispatchers.Default + Job()),
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = emptyMap()
|
||||
)
|
||||
|
||||
init {
|
||||
Firebase.database.setPersistenceEnabled(true)
|
||||
|
||||
status = MutableStateFlow(emptyMap())
|
||||
externalScope.launch {
|
||||
getCharacter().map {
|
||||
it.characters.flatMap { character ->
|
||||
character.value.alterations.map { alteration ->
|
||||
(character.key + alteration.key) to alteration.value
|
||||
}
|
||||
}.toMap()
|
||||
}.collectLatest {
|
||||
status.value = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCharacter(): Flow<CharacterSheetFireMap> {
|
||||
return callbackFlow {
|
||||
// reference to the node
|
||||
val reference = database.getReference("/")
|
||||
// build a register the callback
|
||||
val listener = reference.addValueEventListener(object : ValueEventListener {
|
||||
override fun onDataChange(dataSnapshot: DataSnapshot) {
|
||||
val value = try {
|
||||
dataSnapshot.getValue(CharacterSheetFireMap::class.java)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to parse value.", exception)
|
||||
_error.tryEmit(exception)
|
||||
null
|
||||
}
|
||||
if (value != null) {
|
||||
trySend(value)
|
||||
}
|
||||
}
|
||||
fun getCharacters(): Flow<Map<String, CharacterSheetFire>> =
|
||||
characterFireSheet
|
||||
|
||||
override fun onCancelled(error: DatabaseError) {
|
||||
Log.e(TAG, "Failed to read value.", error.toException())
|
||||
cancel()
|
||||
}
|
||||
})
|
||||
awaitClose {
|
||||
reference.removeEventListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun getCharacter(character: String): Flow<CharacterSheetFire> =
|
||||
characterFireSheet.mapNotNull { it[character] }
|
||||
|
||||
fun getCharacter(character: String): Flow<CharacterSheetFire> {
|
||||
return callbackFlow {
|
||||
// reference to the node
|
||||
val reference = database.getReference("$PATH_CHARACTERS/$character")
|
||||
// build a register the callback
|
||||
val listener = reference.addValueEventListener(object : ValueEventListener {
|
||||
override fun onDataChange(dataSnapshot: DataSnapshot) {
|
||||
val value = try {
|
||||
dataSnapshot.getValue(CharacterSheetFire::class.java)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to parse value.", exception)
|
||||
_error.tryEmit(exception)
|
||||
null
|
||||
}
|
||||
if (value != null) {
|
||||
trySend(value)
|
||||
}
|
||||
}
|
||||
fun getThrows(): Flow<NetworkThrowMap> =
|
||||
networkThrows
|
||||
|
||||
override fun onCancelled(error: DatabaseError) {
|
||||
Log.e(TAG, "Failed to read value.", error.toException())
|
||||
cancel()
|
||||
}
|
||||
})
|
||||
awaitClose {
|
||||
reference.removeEventListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
fun getAlterationStatus(): Flow<Map<AlterationStatus.Key, AlterationStatus.Value>> =
|
||||
alterationStatus
|
||||
|
||||
fun getAlterationStatusSnapshot(key: AlterationStatus.Key): AlterationStatus.Value =
|
||||
alterationStatus.value[key] ?: AlterationStatus.Value(false)
|
||||
|
||||
fun setCharacterHitPoint(character: String, value: Int, extra: Int) {
|
||||
val reference = database.getReference(
|
||||
|
|
@ -159,45 +180,11 @@ class FirebaseRepository @Inject constructor(
|
|||
reference.setValue(value)
|
||||
}
|
||||
|
||||
fun getStatus(character: String, status: String): Boolean {
|
||||
return this.status.value[character + status] ?: false
|
||||
}
|
||||
|
||||
fun setStatus(character: String, status: String, value: Boolean) {
|
||||
fun setAlterationStatus(key: AlterationStatus.Key, value: AlterationStatus.Value) {
|
||||
val reference = database.getReference(
|
||||
"$PATH_CHARACTERS/$character/${CharacterSheetFire.ALTERATIONS}/$status"
|
||||
"$PATH_CHARACTERS/${key.character}/${CharacterSheetFire.ALTERATIONS}/${key.alteration}"
|
||||
)
|
||||
reference.setValue(value)
|
||||
}
|
||||
|
||||
fun getThrows(): Flow<NetworkThrowMap> {
|
||||
return callbackFlow {
|
||||
// reference to the node
|
||||
val reference = database.getReference("/")
|
||||
// build a register the callback
|
||||
val listener = reference.addValueEventListener(object : ValueEventListener {
|
||||
override fun onDataChange(dataSnapshot: DataSnapshot) {
|
||||
val value = try {
|
||||
dataSnapshot.getValue(NetworkThrowMap::class.java)
|
||||
} catch (exception: Exception) {
|
||||
Log.e(TAG, "Failed to parse value.", exception)
|
||||
_error.tryEmit(exception)
|
||||
null
|
||||
}
|
||||
if (value != null) {
|
||||
trySend(value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(error: DatabaseError) {
|
||||
Log.e(TAG, "Failed to read value.", error.toException())
|
||||
cancel()
|
||||
}
|
||||
})
|
||||
awaitClose {
|
||||
reference.removeEventListener(listener)
|
||||
}
|
||||
}
|
||||
reference.setValue(value.value)
|
||||
}
|
||||
|
||||
fun sendThrow(character: String?, throws: NetworkThrow) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
package com.pixelized.rplexicon.data.repository.character
|
||||
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class ActiveAlterationRepository @Inject constructor(
|
||||
alterationRepository: AlterationRepository,
|
||||
firebaseRepository: FirebaseRepository,
|
||||
) {
|
||||
private val activeAlterations: StateFlow<Map<String, List<Alteration>>> =
|
||||
alterationRepository.getAlterations()
|
||||
.combine(firebaseRepository.getAlterationStatus()) { activeAlterations, status ->
|
||||
activeAlterations.mapValues { entry ->
|
||||
entry.value.filter { alteration ->
|
||||
val key = AlterationStatus.Key(entry.key, alteration.name)
|
||||
status[key] == ACTIVE
|
||||
}
|
||||
}
|
||||
}
|
||||
.stateIn(
|
||||
scope = CoroutineScope(Dispatchers.Default + Job()),
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = emptyMap()
|
||||
)
|
||||
|
||||
/**
|
||||
* Get a list of Active [Alteration] for all characters.
|
||||
* @return a list of alterations.
|
||||
*/
|
||||
fun getActiveAlterations(): Flow<Map<String, List<Alteration>>> =
|
||||
activeAlterations
|
||||
|
||||
/**
|
||||
* Get a list of Active [Alteration] for a character
|
||||
* @return a list of alterations.
|
||||
*/
|
||||
fun getActiveAssignedAlterations(character: String?): Flow<List<Alteration>> =
|
||||
activeAlterations.map { it[character] ?: emptyList() }
|
||||
|
||||
companion object {
|
||||
val ACTIVE = AlterationStatus.Value(value = true)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
package com.pixelized.rplexicon.data.repository.character
|
||||
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.parser.alteration.AlterationParser
|
||||
import com.pixelized.rplexicon.data.repository.CharacterBinder
|
||||
import com.pixelized.rplexicon.data.repository.GoogleSheetServiceRepository
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.flow.map
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -19,11 +19,8 @@ import javax.inject.Singleton
|
|||
class AlterationRepository @Inject constructor(
|
||||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val alterationParser: AlterationParser,
|
||||
private val fireRepository: FirebaseRepository,
|
||||
) {
|
||||
private val _assignedAlterations = MutableStateFlow<Map<String, List<Alteration>>>(emptyMap())
|
||||
val assignedAlterations: Flow<Map<String, List<Alteration>>> =
|
||||
combine(_assignedAlterations, fireRepository.status) { alt, _ -> alt }
|
||||
private val assignedAlterations = MutableStateFlow<Map<String, List<Alteration>>>(emptyMap())
|
||||
|
||||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||
private set
|
||||
|
|
@ -32,18 +29,27 @@ class AlterationRepository @Inject constructor(
|
|||
* get all [Alteration] for a character
|
||||
* @return a list of alterations.
|
||||
*/
|
||||
fun getAlterations(character: String): List<Alteration> {
|
||||
return _assignedAlterations.value[character] ?: emptyList()
|
||||
fun getAlterations(): Flow<Map<String, List<Alteration>>> {
|
||||
return assignedAlterations
|
||||
}
|
||||
|
||||
/**
|
||||
* get all [Alteration] for a list of objects
|
||||
* @returna list of alterations.
|
||||
* get an alteration for a character that have [alteration] as namer.
|
||||
* @return a nullable [Alteration]
|
||||
*/
|
||||
fun getAlterations(objects: List<String>?): List<Alteration> {
|
||||
return objects?.flatMap { objectAlteration ->
|
||||
_assignedAlterations.value[objectAlteration] ?: emptyList()
|
||||
} ?: emptyList()
|
||||
suspend fun getAssignedAlterationSnapshot(character: String?, alteration: String?): Alteration? {
|
||||
return assignedAlterations.firstOrNull()?.get(character)
|
||||
?.firstOrNull { it.name == alteration }
|
||||
}
|
||||
|
||||
/**
|
||||
* get all [Alteration] for a character
|
||||
* @return a list of alterations.
|
||||
*/
|
||||
fun getAssignedAlterations(character: String): Flow<List<Alteration>> {
|
||||
return assignedAlterations.map { alterations ->
|
||||
alterations[character] ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -52,39 +58,15 @@ class AlterationRepository @Inject constructor(
|
|||
* @param properties the property list to filter on.
|
||||
* @return a list of alterations.
|
||||
*/
|
||||
fun getAlterations(character: String, vararg properties: Property): List<Alteration> {
|
||||
return getAlterations(character = character).filter {
|
||||
it.status.keys.any { key -> properties.contains(key) }
|
||||
fun getAssignedAlterations(
|
||||
character: String,
|
||||
vararg properties: Property
|
||||
): Flow<List<Alteration>> {
|
||||
return getAssignedAlterations(character = character).map { alterations ->
|
||||
alterations.filter { it.status.keys.any { key -> properties.contains(key) } }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a list of Active [Alteration] for a character
|
||||
* @return a list of alterations.
|
||||
*/
|
||||
fun getActiveAlterations(character: String): List<Alteration> {
|
||||
return _assignedAlterations.value[character]?.filter { alteration ->
|
||||
fireRepository.status.value[character + alteration.name] == true
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
/**
|
||||
* get a map of [Property] and [Alteration.Status] for a given player if the alteration is active.
|
||||
* @param character the character name
|
||||
* @return a map of [Property] and [Alteration.Status]
|
||||
*/
|
||||
fun getActiveAlterationsStatus(character: String): Map<Property, List<Alteration.Status>> {
|
||||
val status = hashMapOf<Property, MutableList<Alteration.Status>>()
|
||||
_assignedAlterations.value[character]?.forEach { alteration ->
|
||||
if (fireRepository.status.value[character + alteration.name] == true) {
|
||||
alteration.status.forEach {
|
||||
status.getOrPut(it.key) { mutableListOf() }.add(it.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the alteration sheet.
|
||||
*/
|
||||
|
|
@ -93,29 +75,8 @@ class AlterationRepository @Inject constructor(
|
|||
googleRepository.fetch { sheet ->
|
||||
val request = sheet.get(CharacterBinder.ID, CharacterBinder.ALTERATION)
|
||||
val data = alterationParser.parse(sheet = request.execute(), characterSheets = sheets)
|
||||
_assignedAlterations.emit(data)
|
||||
assignedAlterations.tryEmit(data)
|
||||
lastSuccessFullUpdate = Update.currentTime()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun sort(sheet: CharacterSheet?): Comparator<String> {
|
||||
return compareByDescending<String> {
|
||||
sheet?.name == it
|
||||
}.thenByDescending {
|
||||
PLAYER == it
|
||||
}.thenByDescending {
|
||||
sheet?.characterClass?.any { clazz -> clazz.value == it }
|
||||
}.thenByDescending {
|
||||
sheet?.race == it
|
||||
}.thenByDescending {
|
||||
FEAT == it
|
||||
}.thenBy {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
private const val PLAYER = "Joueur"
|
||||
private const val FEAT = "Don"
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,7 @@ class DescriptionRepository @Inject constructor(
|
|||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||
private set
|
||||
|
||||
fun find(name: String?): Description? = _data.value[name]
|
||||
fun getDescription(name: String?): Description? = _data.value[name]
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchDescription() {
|
||||
|
|
|
|||
|
|
@ -151,16 +151,20 @@ fun CharacterSheetScreen(
|
|||
scope.launch { pagerState.animateScrollToPage(it) }
|
||||
},
|
||||
onInitiative = {
|
||||
overlay.prepareRoll(diceThrow = headerViewModel.initiativeRoll())
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = headerViewModel.initiativeRoll())
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onHitPoint = headerViewModel::toggleHitPointDialog,
|
||||
onResource = {
|
||||
headerViewModel.showSkillEditDialog(item = it)
|
||||
},
|
||||
onDeathRoll = {
|
||||
overlay.prepareRoll(diceThrow = headerViewModel.onDeathThrow())
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = headerViewModel.onDeathThrow())
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onDeathSuccess = headerViewModel::onDeathSuccess,
|
||||
onDeathFailure = headerViewModel::onDeathFailure,
|
||||
|
|
@ -203,9 +207,11 @@ fun CharacterSheetScreen(
|
|||
modifier = Modifier.navigationBarsPadding(),
|
||||
spells = spellsViewModel.preparedSpellLevel,
|
||||
onLevel = { spell, level ->
|
||||
scope.launch { sheetState.hide() }
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onCastSpell(spell, level))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
sheetState.hide()
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onCastSpell(spell, level))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,15 +3,24 @@ 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 android.net.Uri
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
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.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Switch
|
||||
|
|
@ -36,6 +45,7 @@ data class AlterationItemUio(
|
|||
val source: String,
|
||||
val subLabel: String?,
|
||||
val checked: Boolean,
|
||||
val override: Boolean,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
@ -46,49 +56,63 @@ fun AlterationItem(
|
|||
onInfo: (id: String) -> Unit,
|
||||
onClick: (id: String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable { onInfo(alteration.label) }
|
||||
.heightIn(min = 52.dp)
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
alteration.icon?.let { uri ->
|
||||
AsyncImage(
|
||||
modifier = Modifier.size(size = 36.dp),
|
||||
model = uri,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 2.dp),
|
||||
Box(modifier = Modifier.height(IntrinsicSize.Min)) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable { onInfo(alteration.label) }
|
||||
.heightIn(min = 52.dp)
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = alteration.label,
|
||||
)
|
||||
alteration.subLabel?.let {
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontWeight = FontWeight.Light,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = it,
|
||||
alteration.icon?.let { uri ->
|
||||
AsyncImage(
|
||||
modifier = Modifier.size(size = 36.dp),
|
||||
model = uri,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 2.dp),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = alteration.label,
|
||||
)
|
||||
alteration.subLabel?.let {
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontWeight = FontWeight.Light,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
Switch(
|
||||
enabled = true,
|
||||
checked = alteration.checked,
|
||||
onCheckedChange = { onClick(alteration.label) },
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = alteration.override,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(width = 2.dp)
|
||||
.background(color = MaterialTheme.colorScheme.primary)
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
enabled = true,
|
||||
checked = alteration.checked,
|
||||
onCheckedChange = { onClick(alteration.label) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +142,7 @@ private class RollAlterationPreviewProvider : PreviewParameterProvider<Alteratio
|
|||
subLabel = "Bless",
|
||||
source = "Clerc",
|
||||
checked = false,
|
||||
override = false,
|
||||
),
|
||||
AlterationItemUio(
|
||||
icon = null,
|
||||
|
|
@ -125,6 +150,7 @@ private class RollAlterationPreviewProvider : PreviewParameterProvider<Alteratio
|
|||
subLabel = "Guidance",
|
||||
source = "Clerc",
|
||||
checked = true,
|
||||
override = true,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.factory
|
||||
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.Attack
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ class CharacterSheetHeaderUioFactory @Inject constructor(
|
|||
sheetHeaderData: HeaderViewModel.SheetHeaderData?,
|
||||
fireHeaderData: HeaderViewModel.FireHeaderData?,
|
||||
): CharacterSheetHeaderUio {
|
||||
val characterClass = sheetHeaderData?.characterClass
|
||||
val classWithResource = sheetHeaderData?.characterClass?.firstOrNull { it.resource != null }
|
||||
val favoriteSkill = skillRepository.find(
|
||||
character = character,
|
||||
skill = sheetHeaderData?.characterClass?.resource
|
||||
skill = classWithResource?.resource
|
||||
)
|
||||
return CharacterSheetHeaderUio(
|
||||
initiative = LabelPointUio(
|
||||
|
|
@ -44,10 +44,10 @@ class CharacterSheetHeaderUioFactory @Inject constructor(
|
|||
value = "$it",
|
||||
)
|
||||
},
|
||||
resource = if (characterClass?.label != null && favoriteSkill?.amount != null) {
|
||||
resource = if (classWithResource?.label != null && favoriteSkill?.amount != null) {
|
||||
ResourcePointUio(
|
||||
id = favoriteSkill.name,
|
||||
label = characterClass.label,
|
||||
label = classWithResource.label,
|
||||
value = fireHeaderData?.resource ?: 0,
|
||||
max = favoriteSkill.amount,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.factory
|
||||
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.character.LabelPointUio
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class SkillFactoryUioFactory @Inject constructor(
|
|||
): 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 description = descriptionRepository.getDescription(name = skill.name)
|
||||
val effectModifier = skill.effect?.modifier?.sumOf {
|
||||
when (it) {
|
||||
Property.LEVEL -> character?.level?.base ?: 0
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ class SpellUioFactory @Inject constructor(
|
|||
icon = assignedSpell.spell.icon,
|
||||
school = assignedSpell.spell.school,
|
||||
name = assignedSpell.spell.name,
|
||||
translated = descriptionRepository.find(name = assignedSpell.spell.name)?.original,
|
||||
translated = descriptionRepository.getDescription(name = assignedSpell.spell.name)?.original,
|
||||
castingTime = assignedSpell.spell.castingTime,
|
||||
range = assignedSpell.spell.range,
|
||||
duration = assignedSpell.spell.duration,
|
||||
|
|
|
|||
|
|
@ -68,14 +68,18 @@ fun ActionPage(
|
|||
spells = spellsViewModel.spells,
|
||||
onAttackHit = { id ->
|
||||
attacksViewModel.onHitRoll(id)?.let {
|
||||
overlay.prepareRoll(diceThrow = it)
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = it)
|
||||
overlay.showOverlay()
|
||||
}
|
||||
}
|
||||
},
|
||||
onAttackDamage = { id ->
|
||||
attacksViewModel.onDamageRoll(id)?.let {
|
||||
overlay.prepareRoll(diceThrow = it)
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = it)
|
||||
overlay.showOverlay()
|
||||
}
|
||||
}
|
||||
},
|
||||
onObject = {
|
||||
|
|
@ -83,16 +87,20 @@ fun ActionPage(
|
|||
},
|
||||
onUseObject = {
|
||||
objectsViewModel.onUse(it.name)?.let { throws ->
|
||||
overlay.prepareRoll(diceThrow = throws)
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = throws)
|
||||
overlay.showOverlay()
|
||||
}
|
||||
}
|
||||
},
|
||||
onSkillCount = {
|
||||
skillViewModel.showSkillEditDialog(item = it)
|
||||
},
|
||||
onSkillThrow = {
|
||||
overlay.prepareRoll(diceThrow = skillViewModel.onSkillRoll(it.label))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = skillViewModel.onSkillRoll(it.label))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onSkillInfo = {
|
||||
skillViewModel.showSkillDetailDialog(item = it.label)
|
||||
|
|
@ -104,20 +112,26 @@ fun ActionPage(
|
|||
screen.navigateToSpellDetail(spell = spell)
|
||||
},
|
||||
onSpellHit = { id ->
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onSpellHitRoll(id))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onSpellHitRoll(id))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onSpellDamage = { id ->
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onSpellDamageRoll(id))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onSpellDamageRoll(id))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onCast = {
|
||||
if (spellsViewModel.shouldDisplaySpellLevelChooser(it)) {
|
||||
spellsViewModel.prepareSpellCast(it)
|
||||
scope.launch { sheetState.show() }
|
||||
} else {
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onCastSpell(it))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = spellsViewModel.onCastSpell(it))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -6,17 +6,18 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.Attack
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.repository.character.ActionRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.AttackUioFactory
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -29,7 +30,7 @@ class AttacksViewModel @Inject constructor(
|
|||
application: Application,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val characterRepository: CharacterSheetRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val activeAlterationRepository: ActiveAlterationRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
attackFactory: AttackUioFactory,
|
||||
) : AndroidViewModel(application) {
|
||||
|
|
@ -39,26 +40,23 @@ class AttacksViewModel @Inject constructor(
|
|||
val attacks: State<List<AttackUio>> get() = _attacks
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
val struct = ActionStruct()
|
||||
characterRepository.data
|
||||
.combine(actionRepository.data) { characters, actions ->
|
||||
ActionData(
|
||||
character = characters[character],
|
||||
actions = actions[character] ?: emptyList()
|
||||
)
|
||||
struct.character = characters[character]
|
||||
struct.actions = actions[character] ?: emptyList()
|
||||
}
|
||||
.combine(alterationRepository.assignedAlterations) { data, _ ->
|
||||
data.also {
|
||||
it.alterations = alterationRepository.getActiveAlterationsStatus(character)
|
||||
}
|
||||
.combine(activeAlterationRepository.getActiveAssignedAlterations(character = character)) { _, alterations ->
|
||||
struct.alterations = alterations.toStatus()
|
||||
}
|
||||
.collect { data ->
|
||||
val characterSheet = data.character
|
||||
if (characterSheet != null) {
|
||||
val attacks = data.actions.map { action ->
|
||||
.collect {
|
||||
val (sheet, actions, alterations) = struct
|
||||
if (sheet != null) {
|
||||
val attacks = actions.map { action ->
|
||||
attackFactory.convert(
|
||||
characterSheet = characterSheet,
|
||||
alterations = data.alterations,
|
||||
characterSheet = sheet,
|
||||
alterations = alterations,
|
||||
attack = action,
|
||||
)
|
||||
}
|
||||
|
|
@ -108,10 +106,14 @@ class AttacksViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private data class ActionData(
|
||||
var character: CharacterSheet?,
|
||||
var actions: List<Attack>,
|
||||
private class ActionStruct(
|
||||
var character: CharacterSheet? = null,
|
||||
) {
|
||||
lateinit var actions: List<Attack>
|
||||
lateinit var alterations: Map<Property, List<Alteration.Status>>
|
||||
|
||||
operator fun component1() = character
|
||||
operator fun component2() = actions
|
||||
operator fun component3() = alterations
|
||||
}
|
||||
}
|
||||
|
|
@ -10,10 +10,12 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.SkillRepository
|
||||
import com.pixelized.rplexicon.ui.composable.edit.HpPointDialogUio
|
||||
import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
|
|
@ -21,6 +23,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.Charact
|
|||
import com.pixelized.rplexicon.ui.screens.character.composable.character.ResourcePointUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.CharacterSheetHeaderUioFactory
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.sum
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -34,15 +37,13 @@ class HeaderViewModel @Inject constructor(
|
|||
private val headerFactory: CharacterSheetHeaderUioFactory,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
characterRepository: CharacterSheetRepository,
|
||||
alterationRepository: AlterationRepository,
|
||||
skillRepository: SkillRepository,
|
||||
activeAlterationRepository: ActiveAlterationRepository,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
val character = savedStateHandle.characterSheetArgument.name
|
||||
|
||||
private val sheetData = mutableStateOf<SheetHeaderData?>(null)
|
||||
private val fireData = mutableStateOf<FireHeaderData?>(null)
|
||||
|
||||
val header: State<CharacterSheetHeaderUio?> = derivedStateOf {
|
||||
headerFactory.convert(
|
||||
character = character,
|
||||
|
|
@ -59,18 +60,19 @@ class HeaderViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch(context = Dispatchers.IO) {
|
||||
launch(context = Dispatchers.Default) {
|
||||
val struct = HeaderStruct()
|
||||
characterRepository.data
|
||||
.combine(skillRepository.skills) { sheets, _ -> sheets[character] }
|
||||
.combine(alterationRepository.assignedAlterations) { sheet, _ -> sheet }
|
||||
.collect { sheet ->
|
||||
.combine(activeAlterationRepository.getActiveAssignedAlterations(character = character)) { sheets, alterations ->
|
||||
struct.sheet = sheets[character]
|
||||
struct.alterationsStatus = alterations.toStatus()
|
||||
}
|
||||
.collect {
|
||||
val (sheet, status) = struct
|
||||
if (sheet != null) {
|
||||
val status = alterationRepository.getActiveAlterationsStatus(
|
||||
character = sheet.name,
|
||||
)
|
||||
val data = SheetHeaderData(
|
||||
hpMax = sheet.hitPoint + status[Property.HIT_POINT].sum,
|
||||
characterClass = sheet.characterClass.firstOrNull(),
|
||||
characterClass = sheet.characterClass,
|
||||
initiative = (sheet.dexterity + status[Property.DEXTERITY].sum).modifier + status[Property.INITIATIVE].sum,
|
||||
ca = sheet.armorClass + status[Property.ARMOR_CLASS].sum,
|
||||
dc = sheet.dC,
|
||||
|
|
@ -83,14 +85,19 @@ class HeaderViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
launch(context = Dispatchers.IO) {
|
||||
|
||||
launch(context = Dispatchers.Default) {
|
||||
val struct = HeaderValueStruct()
|
||||
characterRepository.data
|
||||
.combine(firebaseRepository.getCharacter(character = character)) { sheets, fire -> sheets[character] to fire }
|
||||
.combine(firebaseRepository.getCharacter(character = character)) { sheets, fire ->
|
||||
struct.sheet = sheets[character]
|
||||
struct.fire = fire
|
||||
}
|
||||
.collect {
|
||||
val (sheet, fire) = it
|
||||
val (sheet, fire) = struct
|
||||
val data = FireHeaderData(
|
||||
hp = fire.hitPoint?.value ?: 1,
|
||||
resource = fire.skills[sheet?.characterClass?.firstOrNull()?.resource],
|
||||
resource = fire.skills[sheet?.resource],
|
||||
extra = fire.hitPoint?.additional ?: 0,
|
||||
deathSuccess = fire.death?.success ?: 0,
|
||||
deathFailure = fire.death?.failure ?: 0,
|
||||
|
|
@ -172,10 +179,24 @@ class HeaderViewModel @Inject constructor(
|
|||
|
||||
fun initiativeRoll(): DiceThrow.Initiative = DiceThrow.Initiative(character)
|
||||
|
||||
data class HeaderStruct(
|
||||
var sheet: CharacterSheet? = null,
|
||||
var alterationsStatus: Map<Property, List<Alteration.Status>> = emptyMap(),
|
||||
)
|
||||
|
||||
class HeaderValueStruct(
|
||||
var sheet: CharacterSheet? = null
|
||||
) {
|
||||
lateinit var fire: CharacterSheetFire
|
||||
|
||||
operator fun component1() = sheet
|
||||
operator fun component2() = fire
|
||||
}
|
||||
|
||||
@Stable
|
||||
data class SheetHeaderData(
|
||||
val hpMax: Int,
|
||||
val characterClass: CharacterSheet.Class?,
|
||||
val characterClass: List<CharacterSheet.Class>,
|
||||
val initiative: Int,
|
||||
val ca: Int,
|
||||
val dc: Int?,
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@ class ObjectsViewModel @Inject constructor(
|
|||
val dialog: State<SkillDetailUio?> get() = _dialog
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
objectsRepository.data.collect { objects ->
|
||||
val data = objects[character]?.map {
|
||||
ObjectItemUio(
|
||||
prefix = it.prefix,
|
||||
icon = it.icon,
|
||||
name = it.name,
|
||||
original = descriptionRepository.find(name = it.name)?.original,
|
||||
original = descriptionRepository.getDescription(name = it.name)?.original,
|
||||
effect = it.effect,
|
||||
)
|
||||
} ?: emptyList()
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class SkillsViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.Default) {
|
||||
val data = SkillStruct()
|
||||
sheetRepository.data
|
||||
.combine(skillRepository.skills) { sheets, skills ->
|
||||
|
|
@ -81,7 +81,7 @@ class SkillsViewModel @Inject constructor(
|
|||
|
||||
fun showSkillDetailDialog(item: String) {
|
||||
_skillDetailDialog.value = descriptionRepository
|
||||
.find(name = item)
|
||||
.getDescription(name = item)
|
||||
?.let { description ->
|
||||
SkillDetailUio(
|
||||
name = item,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class SpellsViewModel @Inject constructor(
|
|||
val preparedSpellLevel: State<SpellChooserUio?> get() = _preparedSpellLevel
|
||||
|
||||
init {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
characterRepository.data
|
||||
.combine(spellRepository.spells) { sheets, spells ->
|
||||
character = sheets[characterName]
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ fun AlterationPage(
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
groups = viewModel.alterations,
|
||||
onAlterationInfo = {
|
||||
viewModel.showAlterationDetail(id = it)
|
||||
scope.launch {
|
||||
viewModel.showAlterationDetail(id = it)
|
||||
}
|
||||
},
|
||||
onAlterationClick = {
|
||||
scope.launch {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,13 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.business.AlterationSortUseCase
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Description
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
|
|
@ -25,6 +31,7 @@ import javax.inject.Inject
|
|||
class AlterationViewModel @Inject constructor(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val activeAlterationRepository: ActiveAlterationRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val factory: AlterationFactory,
|
||||
|
|
@ -41,32 +48,38 @@ class AlterationViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.Default) {
|
||||
val data = AlterationStruct()
|
||||
descriptionRepository.data
|
||||
.combine(characterSheetRepository.data) { _, sheet -> sheet }
|
||||
.combine(alterationRepository.assignedAlterations) { sheet, alterations ->
|
||||
sheet[character] to alterations
|
||||
.combine(characterSheetRepository.data) { descriptions, sheet ->
|
||||
data.sheet = sheet[character]
|
||||
data.descriptions = descriptions
|
||||
}
|
||||
.collect { entry ->
|
||||
val (sheet, alterationMaps) = entry
|
||||
val alterations = alterationMaps[character] ?: emptyList()
|
||||
val data = alterations
|
||||
.combine(alterationRepository.getAssignedAlterations(character)) { _, alterations ->
|
||||
data.alterations = alterations
|
||||
}
|
||||
.combine(activeAlterationRepository.getActiveAssignedAlterations(character)) { _, actives ->
|
||||
data.actives = actives.associate { it.name to true }
|
||||
}
|
||||
.collect {
|
||||
val (sheet, descriptions, alterations, actives) = data
|
||||
val uio = alterations
|
||||
.groupBy { alteration -> alteration.source }
|
||||
.toSortedMap(AlterationRepository.sort(sheet = sheet))
|
||||
.toSortedMap(AlterationSortUseCase.sort(sheet = sheet))
|
||||
.map {
|
||||
AlterationGroupUio(
|
||||
name = it.key,
|
||||
alterations = factory.convert(
|
||||
character = character,
|
||||
alterations = it.value
|
||||
alterations = it.value,
|
||||
description = descriptions,
|
||||
actives = actives,
|
||||
).sortedBy { alteration ->
|
||||
alteration.label
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
_alterations.value = data
|
||||
_alterations.value = uio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -74,16 +87,22 @@ class AlterationViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun toggleAlteration(alteration: String) {
|
||||
val status = firebaseRepository.getStatus(character = character, status = alteration)
|
||||
firebaseRepository.setStatus(character = character, status = alteration, status.not())
|
||||
val key = AlterationStatus.Key(character = character, alteration = alteration)
|
||||
firebaseRepository.setAlterationStatus(
|
||||
key = key,
|
||||
value = firebaseRepository.getAlterationStatusSnapshot(key = key).switch(),
|
||||
)
|
||||
}
|
||||
|
||||
fun showAlterationDetail(id: String) {
|
||||
val alteration = alterationRepository.getAlterations(character = character)
|
||||
.firstOrNull { it.name == id }
|
||||
val description = descriptionRepository.find(name = alteration?.name)
|
||||
|
||||
suspend fun showAlterationDetail(id: String) {
|
||||
val alteration = alterationRepository.getAssignedAlterationSnapshot(
|
||||
character = character,
|
||||
alteration = id,
|
||||
)
|
||||
if (alteration != null) {
|
||||
val description = descriptionRepository.getDescription(
|
||||
name = alteration.name,
|
||||
)
|
||||
_alterationDetail.value = AlterationDetailUio(
|
||||
name = id,
|
||||
original = description?.original,
|
||||
|
|
@ -98,4 +117,11 @@ class AlterationViewModel @Inject constructor(
|
|||
fun hideAlterationDetail() {
|
||||
_alterationDetail.value = null
|
||||
}
|
||||
|
||||
private data class AlterationStruct(
|
||||
var sheet: CharacterSheet? = null,
|
||||
var descriptions: Map<String, Description> = emptyMap(),
|
||||
var alterations: List<Alteration> = emptyList(),
|
||||
var actives: Map<String, Boolean> = emptyMap(),
|
||||
)
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ class InventoryViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun showSkillDetailDialog(item: String) {
|
||||
val description = descriptionRepository.find(name = item)
|
||||
val description = descriptionRepository.getDescription(name = item)
|
||||
|
||||
if (description != null) {
|
||||
_dialog.value = SkillDetailUio(
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
|
|
@ -55,6 +56,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberC
|
|||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.HandleSkillDetailDialog
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Stable
|
||||
data class CharacterSheetUio(
|
||||
|
|
@ -71,6 +73,7 @@ data class CharacterSheetUio(
|
|||
fun ProficiencyPage(
|
||||
viewModel: ProficiencyViewModel = hiltViewModel(),
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val overlay = LocalRollOverlay.current
|
||||
|
||||
viewModel.sheet.value?.let { sheet ->
|
||||
|
|
@ -79,19 +82,25 @@ fun ProficiencyPage(
|
|||
sheet = sheet,
|
||||
passives = viewModel.skills,
|
||||
onStats = { stat ->
|
||||
overlay.prepareRoll(diceThrow = viewModel.statRoll(stat.id))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = viewModel.statRoll(stat.id))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onProficiencies = { proficiency ->
|
||||
overlay.prepareRoll(diceThrow = viewModel.proficiencyRoll(proficiency.id))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = viewModel.proficiencyRoll(proficiency.id))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onSkillCount = {
|
||||
viewModel.showSkillEditDialog(item = it)
|
||||
},
|
||||
onSkillThrow = {
|
||||
overlay.prepareRoll(diceThrow = viewModel.onSkillRoll(it.label))
|
||||
overlay.showOverlay()
|
||||
scope.launch {
|
||||
overlay.prepareRoll(diceThrow = viewModel.onSkillRoll(it.label))
|
||||
overlay.showOverlay()
|
||||
}
|
||||
},
|
||||
onSkillInfo = {
|
||||
viewModel.showSkillDetailDialog(item = it.label)
|
||||
|
|
|
|||
|
|
@ -8,10 +8,12 @@ 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.Property
|
||||
import com.pixelized.rplexicon.data.model.Skill
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
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.ActiveAlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.SkillRepository
|
||||
|
|
@ -23,6 +25,7 @@ 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 com.pixelized.rplexicon.utilitary.extentions.local.toStatus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -34,7 +37,7 @@ import javax.inject.Inject
|
|||
class ProficiencyViewModel @Inject constructor(
|
||||
private val characterRepository: CharacterSheetRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val activeAlterationRepository: ActiveAlterationRepository,
|
||||
private val characterSheetFactory: CharacterSheetUioFactory,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
|
|
@ -58,14 +61,16 @@ class ProficiencyViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.Default) {
|
||||
val data = SheetStruct()
|
||||
characterRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { sheets, _ -> sheets }
|
||||
.combine(activeAlterationRepository.getActiveAssignedAlterations(character = character)) { sheets, alterations ->
|
||||
data.sheet = sheets[character]
|
||||
data.alterationStatus = alterations.toStatus()
|
||||
}
|
||||
.collect {
|
||||
val characterSheet = it[character]
|
||||
val (characterSheet, alterations) = data
|
||||
if (characterSheet != null) {
|
||||
val alterations =
|
||||
alterationRepository.getActiveAlterationsStatus(character)
|
||||
val sheet = characterSheetFactory.convert(
|
||||
sheet = characterSheet,
|
||||
status = alterations,
|
||||
|
|
@ -81,7 +86,7 @@ class ProficiencyViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.Default) {
|
||||
val data = SkillStruct()
|
||||
characterRepository.data
|
||||
.combine(skillRepository.skills) { sheets, skills ->
|
||||
|
|
@ -150,7 +155,7 @@ class ProficiencyViewModel @Inject constructor(
|
|||
|
||||
fun showSkillDetailDialog(item: String) {
|
||||
_skillDetailDialog.value = descriptionRepository
|
||||
.find(name = item)
|
||||
.getDescription(name = item)
|
||||
?.let { description ->
|
||||
SkillDetailUio(
|
||||
name = item,
|
||||
|
|
@ -183,6 +188,11 @@ class ProficiencyViewModel @Inject constructor(
|
|||
hideSkillEditDialog()
|
||||
}
|
||||
|
||||
private data class SheetStruct(
|
||||
var sheet: CharacterSheet? = null,
|
||||
var alterationStatus: Map<Property, List<Alteration.Status>> = emptyMap(),
|
||||
)
|
||||
|
||||
private data class SkillStruct(
|
||||
var sheet: CharacterSheet? = null,
|
||||
var fire: CharacterSheetFire? = null,
|
||||
|
|
|
|||
|
|
@ -16,13 +16,11 @@ 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
|
||||
|
|
@ -123,10 +121,10 @@ fun RollOverlay(
|
|||
viewModel.toggleCardDetail()
|
||||
},
|
||||
onAlterationInfo = {
|
||||
viewModel.showAlterationDetail(it)
|
||||
scope.launch { viewModel.showAlterationDetail(it) }
|
||||
},
|
||||
onAlteration = {
|
||||
viewModel.onAlteration(it)
|
||||
scope.launch { viewModel.onAlteration(it) }
|
||||
},
|
||||
onThrowVisibilityChange = {
|
||||
viewModel.onThrowVisibilityChange(it)
|
||||
|
|
@ -472,7 +470,7 @@ private fun animation(density: Density): ContentTransform {
|
|||
|
||||
@Stable
|
||||
interface BlurredRollOverlayHostState : BlurredOverlayHostState {
|
||||
fun prepareRoll(diceThrow: DiceThrow)
|
||||
suspend fun prepareRoll(diceThrow: DiceThrow)
|
||||
}
|
||||
|
||||
@Stable
|
||||
|
|
@ -482,7 +480,7 @@ private class BlurredRollOverlayHostStateImpl(
|
|||
) : BlurredRollOverlayHostState {
|
||||
override var isOverlayVisible by rollOverlayVisibilityState
|
||||
|
||||
override fun prepareRoll(diceThrow: DiceThrow) {
|
||||
override suspend fun prepareRoll(diceThrow: DiceThrow) {
|
||||
viewModel.prepareRoll(diceThrow)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,21 @@
|
|||
package com.pixelized.rplexicon.ui.screens.rolls
|
||||
|
||||
import android.app.Application
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.business.AlterationSortUseCase
|
||||
import com.pixelized.rplexicon.business.DiceThrowUseCase
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Description
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.alteration.AlterationStatus
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
|
|
@ -25,15 +30,21 @@ import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory
|
|||
import com.pixelized.rplexicon.utilitary.extentions.context
|
||||
import com.pixelized.rplexicon.utilitary.extentions.switch
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class RollOverlayViewModel @Inject constructor(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val activeAlterationRepository: ActiveAlterationRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val rollUseCase: DiceThrowUseCase,
|
||||
private val diceFactory: DiceFactory,
|
||||
|
|
@ -43,21 +54,24 @@ class RollOverlayViewModel @Inject constructor(
|
|||
application: Application,
|
||||
) : AndroidViewModel(application) {
|
||||
private var sheet: CharacterSheet? = null
|
||||
private var diceThrow: DiceThrow? = null
|
||||
private var rollJob: Job? = null
|
||||
private var alterationJob: Job? = null
|
||||
private lateinit var diceThrow: DiceThrow
|
||||
|
||||
private val _alterations = mutableStateOf<List<AlterationItemUio>>(emptyList())
|
||||
val alterations: State<List<AlterationGroupUio>> = derivedStateOf {
|
||||
_alterations.value
|
||||
.groupBy { it.source }
|
||||
.toSortedMap(AlterationRepository.sort(sheet = sheet))
|
||||
.map { entry ->
|
||||
AlterationGroupUio(
|
||||
name = entry.key,
|
||||
alterations = entry.value.sortedBy { it.label }
|
||||
)
|
||||
}
|
||||
}
|
||||
private val _alterations = MutableStateFlow<List<AlterationItemUio>>(emptyList())
|
||||
private val _alterationStatusOverride = MutableStateFlow<Map<String, Boolean>>(emptyMap())
|
||||
val alterations: State<List<AlterationGroupUio>>
|
||||
@Composable
|
||||
get() = _alterations.map { data ->
|
||||
data.groupBy { it.source }
|
||||
.toSortedMap(AlterationSortUseCase.sort(sheet = sheet))
|
||||
.map { entry ->
|
||||
AlterationGroupUio(
|
||||
name = entry.key,
|
||||
alterations = entry.value.sortedBy { it.label }
|
||||
)
|
||||
}
|
||||
}.collectAsState(initial = emptyList())
|
||||
|
||||
private val _dice = mutableStateOf<RollDiceUio?>(null)
|
||||
val dice: State<RollDiceUio?> get() = _dice
|
||||
|
|
@ -74,26 +88,61 @@ class RollOverlayViewModel @Inject constructor(
|
|||
private val _alterationDetail = mutableStateOf<AlterationDetailUio?>(null)
|
||||
val alterationDetail: State<AlterationDetailUio?> get() = _alterationDetail
|
||||
|
||||
fun prepareRoll(diceThrow: DiceThrow) {
|
||||
suspend fun prepareRoll(diceThrow: DiceThrow) {
|
||||
this.diceThrow = diceThrow
|
||||
// hide the throw for other player.
|
||||
_isThrowHidden.value = diceThrow is DiceThrow.DeathSavingThrow
|
||||
// hide the detail throw card.
|
||||
_card.value = null
|
||||
sheet = characterSheetRepository.find(name = diceThrow.character)
|
||||
_dice.value = diceFactory.convertDiceThrow(diceThrow)
|
||||
_alterations.value = alterationFactory.convertDiceThrow(diceThrow)
|
||||
}
|
||||
|
||||
fun onAlteration(id: String) {
|
||||
_alterations.value = _alterations.value.toMutableList().also { alterations ->
|
||||
val index = alterations.indexOfFirst { it.label == id }
|
||||
val alteration = alterations[index].let { it.copy(checked = it.checked.not()) }
|
||||
alterations.removeAt(index)
|
||||
alterations.add(index, alteration)
|
||||
// reset the override status
|
||||
_alterationStatusOverride.value = emptyMap()
|
||||
// get the character sheet.
|
||||
sheet = characterSheetRepository.find(
|
||||
name = diceThrow.character,
|
||||
)
|
||||
// build the dice UIO.
|
||||
_dice.value = diceFactory.convertDiceThrow(
|
||||
diceThrow = diceThrow,
|
||||
)
|
||||
// listen to alteration + active to build the list of applicable alteration.
|
||||
alterationJob?.cancel()
|
||||
alterationJob = viewModelScope.launch(Dispatchers.Default) {
|
||||
val character = diceThrow.character
|
||||
val struct = AlterationStruct()
|
||||
descriptionRepository.data
|
||||
.combine(activeAlterationRepository.getActiveAssignedAlterations(character = character)) { descriptions, actives ->
|
||||
struct.descriptions = descriptions
|
||||
struct.actives = actives.associate { it.name to true }
|
||||
}
|
||||
.combine(_alterationStatusOverride) { _, override ->
|
||||
struct.override = override
|
||||
}
|
||||
.collect {
|
||||
val (description, actives, override) = struct
|
||||
val alterations = alterationFactory.convertThrowAlterationItem(
|
||||
diceThrow = diceThrow,
|
||||
description = description,
|
||||
checked = actives,
|
||||
override = override,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
_alterations.value = alterations
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onAlteration(id: String) {
|
||||
val override = _alterationStatusOverride.value.toMutableMap().also {
|
||||
it[id] = it[id]?.not() ?: firebaseRepository.getAlterationStatusSnapshot(
|
||||
key = AlterationStatus.Key(character = diceThrow.character, alteration = id)
|
||||
).value.not()
|
||||
}
|
||||
_alterationStatusOverride.value = override
|
||||
}
|
||||
|
||||
fun roll() {
|
||||
diceThrow?.let { diceThrow ->
|
||||
diceThrow.let { diceThrow ->
|
||||
rollJob?.cancel()
|
||||
rollJob = viewModelScope.launch {
|
||||
// roll the dice ;)
|
||||
|
|
@ -132,12 +181,14 @@ class RollOverlayViewModel @Inject constructor(
|
|||
_isThrowHidden.value = hidden
|
||||
}
|
||||
|
||||
fun showAlterationDetail(id: String) {
|
||||
val alteration = diceThrow?.character?.let { character ->
|
||||
alterationRepository.getAlterations(character = character).firstOrNull { it.name == id }
|
||||
}
|
||||
val description = descriptionRepository.find(name = alteration?.name)
|
||||
|
||||
suspend fun showAlterationDetail(id: String) {
|
||||
val alteration = alterationRepository.getAssignedAlterationSnapshot(
|
||||
character = diceThrow.character,
|
||||
alteration = id,
|
||||
)
|
||||
val description = descriptionRepository.getDescription(
|
||||
name = alteration?.name,
|
||||
)
|
||||
if (alteration != null) {
|
||||
_alterationDetail.value = AlterationDetailUio(
|
||||
name = id,
|
||||
|
|
@ -153,4 +204,10 @@ class RollOverlayViewModel @Inject constructor(
|
|||
fun hideAlterationDetail() {
|
||||
_alterationDetail.value = null
|
||||
}
|
||||
|
||||
private data class AlterationStruct(
|
||||
var descriptions: Map<String, Description> = emptyMap(),
|
||||
var actives: Map<String, Boolean> = emptyMap(),
|
||||
var override: Map<String, Boolean> = emptyMap(),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,43 +1,46 @@
|
|||
package com.pixelized.rplexicon.ui.screens.rolls.factory
|
||||
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.Description
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.repository.character.ActionRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.SkillRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.SpellRepository
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import javax.inject.Inject
|
||||
|
||||
class AlterationFactory @Inject constructor(
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val actionRepository: ActionRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
private val skillRepository: SkillRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
) {
|
||||
fun convert(character: String, alterations: List<Alteration>): List<AlterationItemUio> {
|
||||
fun convert(
|
||||
alterations: List<Alteration>,
|
||||
actives: Map<String, Boolean>,
|
||||
description: Map<String, Description>,
|
||||
): List<AlterationItemUio> {
|
||||
return alterations.map {
|
||||
AlterationItemUio(
|
||||
icon = it.icon,
|
||||
label = it.name,
|
||||
source = it.source,
|
||||
subLabel = descriptionRepository.find(
|
||||
name = it.name,
|
||||
)?.original,
|
||||
checked = firebaseRepository.getStatus(
|
||||
character = character,
|
||||
status = it.name,
|
||||
),
|
||||
subLabel = description[it.name]?.original,
|
||||
checked = actives[it.name] ?: false,
|
||||
override = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun convertDiceThrow(diceThrow: DiceThrow): List<AlterationItemUio> {
|
||||
suspend fun convertThrowAlterationItem(
|
||||
diceThrow: DiceThrow,
|
||||
description: Map<String, Description>,
|
||||
checked: Map<String, Boolean>,
|
||||
override: Map<String, Boolean>,
|
||||
): List<AlterationItemUio> {
|
||||
val properties = when (diceThrow) {
|
||||
is DiceThrow.Initiative -> listOf(Property.INITIATIVE, Property.DEXTERITY)
|
||||
is DiceThrow.Strength -> listOf(Property.STRENGTH, Property.STRENGTH_THROW)
|
||||
|
|
@ -139,20 +142,17 @@ class AlterationFactory @Inject constructor(
|
|||
}
|
||||
|
||||
return alterationRepository
|
||||
.getAlterations(character = diceThrow.character, *properties.toTypedArray())
|
||||
.map {
|
||||
.getAssignedAlterations(character = diceThrow.character, *properties.toTypedArray())
|
||||
.firstOrNull()
|
||||
?.map { alt ->
|
||||
AlterationItemUio(
|
||||
icon = it.icon,
|
||||
label = it.name,
|
||||
source = it.source,
|
||||
checked = firebaseRepository.getStatus(
|
||||
character = diceThrow.character,
|
||||
status = it.name,
|
||||
),
|
||||
subLabel = descriptionRepository.find(
|
||||
name = it.name,
|
||||
)?.original,
|
||||
icon = alt.icon,
|
||||
label = alt.name,
|
||||
subLabel = description[alt.name]?.original,
|
||||
source = alt.source,
|
||||
checked = override[alt.name] ?: checked[alt.name] ?: false,
|
||||
override = override[alt.name]?.let { it != checked[alt.name] } ?: false,
|
||||
)
|
||||
}
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ fun rememberRollAlterations() = remember {
|
|||
subLabel = "Rage",
|
||||
source = "Barbare",
|
||||
checked = false,
|
||||
override = false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -32,7 +33,8 @@ fun rememberRollAlterations() = remember {
|
|||
label = "Inspiration bardique",
|
||||
subLabel = "Bardic inspiration",
|
||||
source = "Barde",
|
||||
checked = false
|
||||
checked = false,
|
||||
override = true,
|
||||
),
|
||||
AlterationItemUio(
|
||||
icon = null,
|
||||
|
|
@ -40,6 +42,7 @@ fun rememberRollAlterations() = remember {
|
|||
subLabel = "Bless",
|
||||
source = "Barde",
|
||||
checked = false,
|
||||
override = true,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
@ -51,7 +54,8 @@ fun rememberRollAlterations() = remember {
|
|||
label = "Cape de protection",
|
||||
subLabel = "Cape of protection",
|
||||
source = "Equipement",
|
||||
checked = true
|
||||
checked = true,
|
||||
override = false,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class SpellDetailViewModel @Inject constructor(
|
|||
|
||||
init {
|
||||
val argument = savedStateHandle.spellDetailArgument
|
||||
val description = descriptionRepository.find(
|
||||
val description = descriptionRepository.getDescription(
|
||||
name = argument.spell,
|
||||
)
|
||||
val spell = spellRepository.findSpell(
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
|
@ -50,6 +51,7 @@ import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticSumma
|
|||
import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticSummaryPreview
|
||||
import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticViewModel
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
|
|
@ -68,6 +70,7 @@ fun SummaryScreen(
|
|||
val extendPassives = rememberSaveable { mutableStateOf(true) }
|
||||
val extendSpells = rememberSaveable { mutableStateOf(true) }
|
||||
val extendStatus = rememberSaveable { mutableStateOf(true) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
@ -101,10 +104,12 @@ fun SummaryScreen(
|
|||
onSpells = { extendSpells.value = it },
|
||||
onStatus = { extendStatus.value = it },
|
||||
onAlteration = {
|
||||
statisticsViewModel.showAlterationDetail(
|
||||
name = it.id,
|
||||
character = it.character,
|
||||
)
|
||||
scope.launch {
|
||||
statisticsViewModel.showAlterationDetail(
|
||||
name = it.id,
|
||||
character = it.character,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import com.pixelized.rplexicon.utilitary.extentions.context
|
|||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
|
@ -62,10 +63,10 @@ class StatisticViewModel @Inject constructor(
|
|||
_detail.value = null
|
||||
}
|
||||
|
||||
fun showAlterationDetail(name: String, character: String,) {
|
||||
val alteration = alterationRepository.getAlterations(character = character)
|
||||
.firstOrNull { it.name == name }
|
||||
val description = descriptionRepository.find(name = alteration?.name)
|
||||
suspend fun showAlterationDetail(name: String, character: String) {
|
||||
val alteration = alterationRepository.getAssignedAlterations(character = character)
|
||||
.firstOrNull()?.firstOrNull { it.name == name }
|
||||
val description = descriptionRepository.getDescription(name = alteration?.name)
|
||||
|
||||
if (alteration != null) {
|
||||
_alterationDetail.value = AlterationDetailUio(
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@ package com.pixelized.rplexicon.ui.screens.summary.pages.statistic
|
|||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.NetworkThrow
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.ActiveAlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.AttributesSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.CharacteristicsSummaryUio
|
||||
|
|
@ -28,6 +28,7 @@ import com.pixelized.rplexicon.utilitary.extentions.local.highestSpellLevel
|
|||
import com.pixelized.rplexicon.utilitary.extentions.local.passivesBonus
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.spell
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.sum
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.toStatus
|
||||
import com.pixelized.rplexicon.utilitary.extentions.masteryMultiplier
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import com.pixelized.rplexicon.utilitary.extentions.toLabel
|
||||
|
|
@ -42,7 +43,7 @@ import kotlin.math.max
|
|||
|
||||
class SummaryFactory @Inject constructor(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val activeAlterationRepository: ActiveAlterationRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
) {
|
||||
fun fetchSummary(scope: CoroutineScope): StatisticSummaryUio {
|
||||
|
|
@ -141,15 +142,19 @@ class SummaryFactory @Inject constructor(
|
|||
scope.launch(Dispatchers.IO) {
|
||||
val data = DataStruct()
|
||||
characterSheetRepository.data
|
||||
.combine(alterationRepository.assignedAlterations) { sheets, _ ->
|
||||
.combine(activeAlterationRepository.getActiveAlterations()) { sheets, alterations ->
|
||||
data.sheets = sheets
|
||||
data.alterations = alterations
|
||||
}
|
||||
.combine(firebaseRepository.getCharacter()) { _, fire ->
|
||||
data.fires = fire.characters
|
||||
.combine(firebaseRepository.getCharacters()) { _, fire ->
|
||||
data.fires = fire
|
||||
}
|
||||
.collect {
|
||||
val (sheets, fires) = data
|
||||
val (sheets, alterations, fires) = data
|
||||
val characters = sheets.keys.sorted()
|
||||
val alterationStatus = sheets.values.associate { sheet ->
|
||||
sheet.name to alterations[sheet.name]?.toStatus()
|
||||
}
|
||||
|
||||
// Update the max spell slot card.
|
||||
val highestSpellSlot = sheets.values.maxOf { it.highestSpellLevel() }
|
||||
|
|
@ -184,7 +189,7 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
// Update the attributes
|
||||
sheets.values.forEach { sheet ->
|
||||
val status = alterationRepository.getActiveAlterationsStatus(sheet.name)
|
||||
val status = alterationStatus[sheet.name] ?: emptyMap()
|
||||
val fire = fires[sheet.name]
|
||||
|
||||
val dexterity = sheet.dexterity + status[Property.DEXTERITY].sum
|
||||
|
|
@ -225,7 +230,7 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
// Update the Characteristics
|
||||
sheets.values.forEach { sheet ->
|
||||
val status = alterationRepository.getActiveAlterationsStatus(sheet.name)
|
||||
val status = alterationStatus[sheet.name] ?: emptyMap()
|
||||
// Update the Characteristics
|
||||
val strengthLabel = label(
|
||||
label = "${sheet.strength + status[Property.STRENGTH].sum}",
|
||||
|
|
@ -261,7 +266,7 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
// Update the SavingThrows
|
||||
sheets.values.forEach { sheet ->
|
||||
val status = alterationRepository.getActiveAlterationsStatus(sheet.name)
|
||||
val status = alterationStatus[sheet.name] ?: emptyMap()
|
||||
|
||||
val proficiency = (sheet.proficiency + status[Property.PROFICIENCY].sum)
|
||||
val strength = sheet.strength + status[Property.STRENGTH].sum
|
||||
|
|
@ -331,7 +336,7 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
// Update proficiencies
|
||||
sheets.values.forEach { sheet ->
|
||||
val status = alterationRepository.getActiveAlterationsStatus(sheet.name)
|
||||
val status = alterationStatus[sheet.name] ?: emptyMap()
|
||||
|
||||
val proficiency = (sheet.proficiency + status[Property.PROFICIENCY].sum)
|
||||
val strength = sheet.strength + status[Property.STRENGTH].sum
|
||||
|
|
@ -494,7 +499,7 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
// Update passives
|
||||
sheets.values.forEach { sheet ->
|
||||
val status = alterationRepository.getActiveAlterationsStatus(sheet.name)
|
||||
val status = alterationStatus[sheet.name] ?: emptyMap()
|
||||
|
||||
val proficiency = (sheet.proficiency + status[Property.PROFICIENCY].sum)
|
||||
val intelligence = sheet.intelligence + status[Property.INTELLIGENCE].sum
|
||||
|
|
@ -614,9 +619,8 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
// Update the Status
|
||||
sheets.values.forEach { sheet ->
|
||||
val status = alterationRepository
|
||||
.getActiveAlterations(character = sheet.name)
|
||||
.filterDndStatus(character = sheet.name)
|
||||
val status = alterations[sheet.name]
|
||||
?.filterDndStatus(character = sheet.name) ?: emptyList()
|
||||
withContext(Dispatchers.Main) {
|
||||
statuses.get(sheet = sheet)?.value = status
|
||||
}
|
||||
|
|
@ -728,10 +732,12 @@ class SummaryFactory @Inject constructor(
|
|||
|
||||
private class DataStruct {
|
||||
lateinit var sheets: Map<String, CharacterSheet>
|
||||
lateinit var alterations: Map<String, List<Alteration>>
|
||||
lateinit var fires: Map<String, CharacterSheetFire>
|
||||
|
||||
operator fun component1() = sheets
|
||||
operator fun component2() = fires
|
||||
operator fun component2() = alterations
|
||||
operator fun component3() = fires
|
||||
}
|
||||
|
||||
private class HeaderStatStruct {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import android.net.Uri
|
|||
import androidx.annotation.DrawableRes
|
||||
import com.pixelized.rplexicon.BuildConfig
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.amateurism
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.mastery
|
||||
import kotlin.math.abs
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.pixelized.rplexicon.utilitary.extentions.local
|
||||
|
||||
import com.pixelized.rplexicon.data.model.Alteration
|
||||
import com.pixelized.rplexicon.data.model.alteration.Alteration
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
|
||||
fun List<Alteration>.toStatus(): Map<Property, List<Alteration.Status>> {
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@
|
|||
<string name="character_sheet_title_rage">Rage</string>
|
||||
<string name="character_sheet_title_inspiration">Inspiration</string>
|
||||
<string name="character_sheet_title_conduit">Conduit Divin</string>
|
||||
<string name="character_sheet_title_wild_shape">Forme sauvage</string>
|
||||
<string name="character_sheet_title_initiative">Initiative</string>
|
||||
<string name="character_sheet_title_proficiency_bonus">Bonus de maîtrise</string>
|
||||
<string name="character_sheet_title_characteristic">Caractéristiques</string>
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@
|
|||
<string name="character_sheet_title_rage">Rage</string>
|
||||
<string name="character_sheet_title_inspiration">Inspiration</string>
|
||||
<string name="character_sheet_title_conduit">Divine conduit</string>
|
||||
<string name="character_sheet_title_wild_shape">Wild shape</string>
|
||||
<string name="character_sheet_title_initiative">Initiative</string>
|
||||
<string name="character_sheet_title_proficiency_bonus">Proficiency bonus</string>
|
||||
<string name="character_sheet_title_saving_throws">Saving Throws</string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue