Add detail on shared throws

This commit is contained in:
Thomas Andres Gomez 2023-12-23 17:24:46 +01:00
parent 980a7e7929
commit ff88c99342
10 changed files with 275 additions and 138 deletions

View file

@ -11,7 +11,6 @@ import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.Skill
import com.pixelized.rplexicon.data.model.Throw
import com.pixelized.rplexicon.data.network.NetworkThrow
import com.pixelized.rplexicon.data.network.NetworkThrow.Bonus
import com.pixelized.rplexicon.data.repository.character.ActionRepository
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
@ -19,7 +18,6 @@ import com.pixelized.rplexicon.data.repository.character.ObjectActionRepository
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.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.utilitary.extentions.icon
import com.pixelized.rplexicon.utilitary.extentions.local.advantage
import com.pixelized.rplexicon.utilitary.extentions.local.critical
@ -39,8 +37,7 @@ import kotlin.math.min
data class DiceThrowResult(
val dice: RollDiceUio,
val card: ThrowsCardUio,
val network: NetworkThrow,
val throws: NetworkThrow,
)
@Suppress("KotlinConstantConditions")
@ -579,7 +576,7 @@ class DiceThrowUseCase @Inject constructor(
if (relatedTitleString != null) {
allValue.add(value)
listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = relatedTitleString,
result = "$value",
)
@ -621,7 +618,7 @@ class DiceThrowUseCase @Inject constructor(
val mastery = character.proficiency * multiplier
allValue.add(mastery)
listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = application.getString(
when (multiplier) {
2 -> R.string.dice_roll_expertise_bonus
@ -646,18 +643,19 @@ class DiceThrowUseCase @Inject constructor(
isCriticalFailure = result.value == 1,
result = rollResult,
),
card = ThrowsCardUio(
throws = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = abilityTitleString.uppercase(),
highlight = abilityLabelString.uppercase(),
dice = R.drawable.ic_d20_24,
face = 20,
roll = allValue.toLabel(),
result = rollResult,
isCriticalSuccess = result.value == 20,
isCriticalFailure = result.value == 1,
details = listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = abilityTitleString,
throws = ThrowsCardUio.Throw(
throws = NetworkThrow.Throw(
dice = R.drawable.ic_d20_24,
advantage = advantage,
disadvantage = disadvantage,
@ -668,18 +666,6 @@ class DiceThrowUseCase @Inject constructor(
),
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + mastery,
),
network = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = abilityTitleString.uppercase(),
result = rollResult,
isCriticalSuccess = if (result.value == 20) true else null,
isCriticalFailure = if (result.value == 1) true else null,
details = bonus(abilityTitleString, "1d20", result.label) +
diceAlterationBonus.detail() +
flatAlterationBonus.detail() +
relatedStatBonus.detail() +
mastery.detail()
),
)
}
}
@ -743,7 +729,7 @@ class DiceThrowUseCase @Inject constructor(
val flatBonus = diceThrow?.flat?.takeIf { it > 0 }?.let {
allValue.add(it)
listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = application.getString(R.string.dice_roll_bonus_detail, action),
result = "$it",
)
@ -765,18 +751,19 @@ class DiceThrowUseCase @Inject constructor(
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
result = rollResult,
),
card = ThrowsCardUio(
throws = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
highlight = action,
dice = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
highlight = action.uppercase(),
face = diceThrow?.faces ?: 20,
isCriticalSuccess = canMakeCriticalRoll && result.value == 20,
isCriticalFailure = canMakeCriticalRoll && result.value == 1,
roll = allValue.toLabel(),
result = rollResult,
details = listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = action,
throws = ThrowsCardUio.Throw(
throws = NetworkThrow.Throw(
dice = diceThrow?.faces?.icon ?: R.drawable.ic_d20_24,
advantage = advantage,
disadvantage = disadvantage,
@ -787,18 +774,6 @@ class DiceThrowUseCase @Inject constructor(
),
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus + flatBonus,
),
network = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
result = rollResult,
isCriticalSuccess = if (canMakeCriticalRoll && result.value == 20) true else null,
isCriticalFailure = if (canMakeCriticalRoll && result.value == 1) true else null,
details = bonus(
title = titleString,
dice = "${diceThrow?.amount}d${diceThrow?.faces}",
result = result.label
) + diceAlterationBonus.detail() + flatAlterationBonus.detail() + relatedStatBonus.detail() + flatBonus.detail()
),
)
}
}
@ -837,9 +812,9 @@ class DiceThrowUseCase @Inject constructor(
fail = status[Property.SPELL_EFFECT].fail,
critical = status[Property.SPELL_EFFECT].critical,
)
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = application.getString(R.string.spell_level_chooser_label, "$it"),
throws = ThrowsCardUio.Throw(
throws = NetworkThrow.Throw(
dice = spell.level.faces.icon,
roll = "${spell.level.amount}d${spell.level.faces}",
advantage = advantage,
@ -865,16 +840,17 @@ class DiceThrowUseCase @Inject constructor(
icon = (spell?.effect?.faces ?: 4).icon,
result = rollResult,
),
card = ThrowsCardUio(
throws = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
highlight = spellName,
dice = (spell?.effect?.faces ?: 4).icon,
highlight = spellName.uppercase(),
face = spell?.effect?.faces ?: 4,
roll = allValue.toLabel(),
result = rollResult,
details = listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = spellName,
throws = ThrowsCardUio.Throw(
throws = NetworkThrow.Throw(
dice = (spell?.effect?.faces ?: 4).icon,
roll = "${spell?.effect?.amount ?: 1}d${spell?.effect?.faces ?: 4}",
advantage = advantage,
@ -885,16 +861,6 @@ class DiceThrowUseCase @Inject constructor(
),
) + levelBonus + relatedStatBonus,
),
network = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
result = rollResult,
details = bonus(
title = titleString,
dice = "${spell?.effect?.amount}d${spell?.effect?.faces}",
result = result.label
) + levelBonus.detail() + relatedStatBonus.detail()
),
)
}
}
@ -939,16 +905,17 @@ class DiceThrowUseCase @Inject constructor(
icon = (skill?.effect?.faces ?: 4).icon,
result = rollResult,
),
card = ThrowsCardUio(
throws = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
highlight = spellName ?: "",
dice = (skill?.effect?.faces ?: 4).icon,
highlight = spellName?.uppercase() ?: "",
face = skill?.effect?.faces ?: 4,
roll = allValue.toLabel(),
result = rollResult,
details = listOf(
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = spellName ?: "",
throws = ThrowsCardUio.Throw(
throws = NetworkThrow.Throw(
dice = (skill?.effect?.faces ?: 4).icon,
roll = "${skill?.effect?.amount ?: 1}d${skill?.effect?.faces ?: 4}",
advantage = advantage,
@ -959,26 +926,10 @@ class DiceThrowUseCase @Inject constructor(
),
) + diceAlterationBonus + flatAlterationBonus + relatedStatBonus,
),
network = NetworkThrow(
timestamp = System.currentTimeMillis(),
title = titleString.uppercase(),
result = rollResult,
details = bonus(
title = titleString,
dice = "${skill?.effect?.amount}d${skill?.effect?.faces}",
result = result.label
) + diceAlterationBonus.detail() + flatAlterationBonus.detail() + relatedStatBonus.detail()
),
)
}
}
private fun bonus(title: String, dice: String, result: String): List<Bonus> =
listOf(Bonus(title, dice, result))
private fun List<ThrowsCardUio.Detail>.detail(): List<Bonus> =
map { Bonus(it.title, it.throws?.roll, it.result) }
/**
* Helper class to track rolls and declare helper method.
*/
@ -993,11 +944,11 @@ class DiceThrowUseCase @Inject constructor(
/**
* Fetch any stats / proficiency / level related bonus and build a ThrowsCardUio.Detail for each.
*/
fun Throw?.statBonus(name: String?): List<ThrowsCardUio.Detail> {
fun Throw?.statBonus(name: String?): List<NetworkThrow.Detail> {
return this?.modifier?.mapNotNull { it.statBonus(name = name) } ?: emptyList()
}
fun Property.statBonus(name: String?): ThrowsCardUio.Detail? {
fun Property.statBonus(name: String?): NetworkThrow.Detail? {
return when (this) {
Property.STRENGTH -> (character.strength + this@ThrowScope.status[this].sum).modifier
Property.DEXTERITY -> (character.dexterity + this@ThrowScope.status[this].sum).modifier
@ -1025,7 +976,7 @@ class DiceThrowUseCase @Inject constructor(
context.getString(R.string.dice_roll_bonus_detail, label)
}
allValue.add(value)
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = titleLabel,
result = "$value",
)
@ -1035,7 +986,7 @@ class DiceThrowUseCase @Inject constructor(
/**
* Fetch any alteration related bonus and build a ThrowsCardUio.Detail for each.
*/
fun List<Alteration.Status>?.alterationsBonus(): List<ThrowsCardUio.Detail> {
fun List<Alteration.Status>?.alterationsBonus(): List<NetworkThrow.Detail> {
return this?.flatMap { status ->
status.dices.map { dice ->
val localRoll = roll(
@ -1046,9 +997,9 @@ class DiceThrowUseCase @Inject constructor(
fail = status.fail,
critical = status.critical,
)
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = dice.title ?: "",
throws = ThrowsCardUio.Throw(
throws = NetworkThrow.Throw(
dice = dice.faces.icon,
advantage = dice.advantage,
disadvantage = dice.disadvantage,
@ -1064,11 +1015,11 @@ class DiceThrowUseCase @Inject constructor(
/**
* Fetch any flat number related bonus and build a ThrowsCardUio.Detail for each.
*/
fun List<Alteration.Status>?.flatAlterationBonus(): List<ThrowsCardUio.Detail> {
fun List<Alteration.Status>?.flatAlterationBonus(): List<NetworkThrow.Detail> {
return this?.flatMap { status ->
status.bonus.map { bonus ->
allValue.add(bonus.value)
ThrowsCardUio.Detail(
NetworkThrow.Detail(
title = bonus.title,
result = "${bonus.value}",
)

View file

@ -15,6 +15,18 @@ data class NetworkThrow(
@set:PropertyName(TITLE)
var title: String = "",
@get:PropertyName(HIGHLIGHT)
@set:PropertyName(HIGHLIGHT)
var highlight: String = "",
@get:PropertyName(FACE)
@set:PropertyName(FACE)
var face: Int = 20,
@get:PropertyName(ROLL)
@set:PropertyName(ROLL)
var roll: String = "",
@get:PropertyName(RESULT)
@set:PropertyName(RESULT)
var result: String = "",
@ -29,26 +41,58 @@ data class NetworkThrow(
@get:PropertyName(DETAILS)
@set:PropertyName(DETAILS)
var details: List<Bonus> = emptyList(),
var details: List<Detail> = emptyList(),
) {
@Keep
@IgnoreExtraProperties
data class Bonus(
@get:PropertyName(LABEL)
@set:PropertyName(LABEL)
var label: String = "",
data class Detail(
@get:PropertyName(TITLE)
@set:PropertyName(TITLE)
var title: String = "",
@get:PropertyName(RESULT)
@set:PropertyName(RESULT)
var result: String = "",
@get:PropertyName(THROW)
@set:PropertyName(THROW)
var throws: Throw? = null,
) {
companion object {
const val TITLE = "title"
const val RESULT = "result"
const val THROW = "throw"
}
}
@Keep
@IgnoreExtraProperties
data class Throw(
@get:PropertyName(DICE)
@set:PropertyName(DICE)
var dice: String? = null,
var dice: Int = 20,
@get:PropertyName(ADVANTAGE)
@set:PropertyName(ADVANTAGE)
var advantage: Boolean? = null,
@get:PropertyName(DISADVANTAGE)
@set:PropertyName(DISADVANTAGE)
var disadvantage: Boolean? = null,
@get:PropertyName(ROLL)
@set:PropertyName(ROLL)
var roll: String = "",
@get:PropertyName(RESULT)
@set:PropertyName(RESULT)
var result: String = "",
) {
companion object {
const val LABEL = "label"
const val DICE = "dice"
const val ADVANTAGE = "adv"
const val DISADVANTAGE = "dis"
const val ROLL = "roll"
const val RESULT = "result"
}
}
@ -56,6 +100,9 @@ data class NetworkThrow(
companion object {
const val TIMESTAMP = "timestamp"
const val TITLE = "title"
const val HIGHLIGHT = "highlight"
const val FACE = "face"
const val ROLL = "roll"
const val RESULT = "result"
const val CRITICAL = "crit"
const val FAIL = "fail"

View file

@ -170,13 +170,6 @@ class FirebaseRepository @Inject constructor(
reference.setValue(value)
}
fun sendThrow(character: String?, throws: NetworkThrow) {
character?.let {
val reference = database.getReference("$PATH_THROWS/")
reference.updateChildren(mapOf(it to throws))
}
}
fun getThrows(): Flow<NetworkThrowMap> {
return callbackFlow {
// reference to the node
@ -207,6 +200,13 @@ class FirebaseRepository @Inject constructor(
}
}
fun sendThrow(character: String?, throws: NetworkThrow) {
character?.let {
val reference = database.getReference("$PATH_THROWS/")
reference.updateChildren(mapOf(it to throws))
}
}
companion object {
private const val TAG = "FirebaseRepository"
private const val PATH_CHARACTERS = "Characters"

View file

@ -18,6 +18,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.actions.Alteratio
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetailUio
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationGroupUio
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowCardFactory
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory
@ -38,6 +39,7 @@ class RollOverlayViewModel @Inject constructor(
private val diceFactory: DiceFactory,
private val alterationFactory: AlterationFactory,
private val firebaseRepository: FirebaseRepository,
private val throwCardFactory: ThrowCardFactory,
application: Application,
) : AndroidViewModel(application) {
private var sheet: CharacterSheet? = null
@ -63,7 +65,7 @@ class RollOverlayViewModel @Inject constructor(
private val _card = mutableStateOf<ThrowsCardUio?>(null)
val card: State<ThrowsCardUio?> get() = _card
private val _showDetail = mutableStateOf(false)
private val _showDetail = mutableStateOf(true)
val showDetail: State<Boolean> get() = _showDetail
private val _alterationDetail = mutableStateOf<AlterationDetailUio?>(null)
@ -96,7 +98,7 @@ class RollOverlayViewModel @Inject constructor(
alterationId = _alterations.value.mapNotNull { if (it.checked) it.label else null },
)
// share the result
result?.network?.let {
result?.throws?.let {
firebaseRepository.sendThrow(sheet?.name, it)
}
// Start the roll animation.
@ -112,7 +114,7 @@ class RollOverlayViewModel @Inject constructor(
result?.dice?.let { _dice.value = it }
delay(250)
// Display the roll card.
result?.card?.let { _card.value = it }
result?.throws?.let { _card.value = throwCardFactory.convert(it) }
}
}
}

View file

@ -0,0 +1,36 @@
package com.pixelized.rplexicon.ui.screens.rolls.composable
import com.pixelized.rplexicon.data.network.NetworkThrow
import com.pixelized.rplexicon.utilitary.extentions.icon
import javax.inject.Inject
class ThrowCardFactory @Inject constructor() {
fun convert(throws: NetworkThrow): ThrowsCardUio {
return ThrowsCardUio(
id = "${throws.timestamp}",
title = throws.title,
highlight = throws.highlight,
dice = throws.face.icon,
roll = throws.roll,
result = throws.result,
isCriticalSuccess = throws.isCriticalSuccess == true,
isCriticalFailure = throws.isCriticalFailure == true,
details = throws.details.map { detail ->
ThrowsCardUio.Detail(
title = detail.title,
result = detail.result,
throws = detail.throws?.let { dice ->
ThrowsCardUio.Throw(
dice = dice.dice.icon,
advantage = dice.advantage == true,
disadvantage = dice.disadvantage == true,
roll = dice.roll,
result = dice.result,
)
},
)
},
)
}
}

View file

@ -55,7 +55,7 @@ import java.util.UUID
@Stable
data class ThrowsCardUio(
val id: String = UUID.randomUUID().toString(),
val title: String, // the roll title
val title: String, // the roll title
val highlight: String?, // the highlighted part of the title
@DrawableRes val dice: Int?, // the dice icon
val roll: String, // the roll + bonus string.
@ -66,7 +66,7 @@ data class ThrowsCardUio(
) {
@Stable
data class Detail(
val title: String = "", // the detail title
val title: String = "", // the detail title
val throws: Throw? = null, // the detail of the roll if any
val result: String, // the result
)
@ -114,8 +114,10 @@ fun ThrowsCard(
.padding(all = 16.dp)
.animateContentSize(),
) {
throws.title?.let {
val highlightRegex = remember(it) { highlightRegex(term = it) }
throws.title.let {
val highlightRegex = remember(throws.highlight) {
highlightRegex(term = throws.highlight ?: it)
}
Text(
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.65f),
style = MaterialTheme.typography.bodyLarge,
@ -202,7 +204,7 @@ private fun ThrowsRollDetail(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
) {
detail.title?.let {
detail.title.let {
Text(
modifier = Modifier.alignByBaseline(),
color = MaterialTheme.colorScheme.onSurface,
@ -312,8 +314,8 @@ private class RollToastPreviewProvider : PreviewParameterProvider<ThrowsCardUio>
),
),
ThrowsCardUio(
title = "ATTACK HIT",
highlight = "HIT",
title = "JET D'ATTAQUE : \"HACHE DE GUERRE\"",
highlight = "Hache de guerre",
dice = R.drawable.ic_d20_24,
roll = "20 + 2 + 3 + 2",
result = "20",

View file

@ -1,12 +1,17 @@
package com.pixelized.rplexicon.ui.screens.summary
import android.content.res.Configuration
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
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.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.ExperimentalMaterialApi
@ -20,6 +25,9 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@ -27,17 +35,21 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.hilt.navigation.compose.hiltViewModel
import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.ui.composable.KeepOnScreen
import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost
import com.pixelized.rplexicon.ui.navigation.screens.navigateToCharacterSheet
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCard
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticSummary
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
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun SummaryScreen(
statisticsViewModel: StatisticViewModel = hiltViewModel()
@ -51,29 +63,75 @@ fun SummaryScreen(
Surface(
modifier = Modifier.fillMaxSize(),
) {
SummaryContent(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding(),
refreshState = refresh,
onBack = {
screen.popBackStack()
},
statistics = {
StatisticSummary(
summary = statisticsViewModel.summary,
onClass = {
screen.navigateToCharacterSheet(name = it.label)
},
onDice = { },
)
},
)
Box {
SummaryContent(
modifier = Modifier
.fillMaxSize()
.statusBarsPadding(),
refreshState = refresh,
onBack = {
screen.popBackStack()
},
statistics = {
StatisticSummary(
summary = statisticsViewModel.summary,
onClass = {
screen.navigateToCharacterSheet(name = it.label)
},
onDice = {
statisticsViewModel.showDetail(dice = it)
},
)
},
)
HandleThrowDetailCard(
modifier = Modifier
.align(Alignment.BottomCenter)
.fillMaxWidth()
.navigationBarsPadding(),
detail = statisticsViewModel.detail,
onDetail = { statisticsViewModel.hideDetail() },
)
}
KeepOnScreen()
}
}
@Composable
private fun HandleThrowDetailCard(
modifier: Modifier = Modifier,
detail: State<ThrowsCardUio?>,
onDetail: () -> Unit,
) {
detail.value?.let {
Dialog(
properties = remember {
DialogProperties(
decorFitsSystemWindows = false,
usePlatformDefaultWidth = false,
)
},
onDismissRequest = onDetail,
) {
AnimatedContent(
modifier = modifier,
targetState = it,
label = "ThrowCardDetailAnimation",
transitionSpec = { fadeIn() togetherWith fadeOut() }
) {
ThrowsCard(
modifier = Modifier.padding(all = 16.dp),
throws = it,
showDetail = remember { mutableStateOf(true) },
onClick = onDetail,
)
}
}
}
}
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun SummaryContent(

View file

@ -71,6 +71,7 @@ data class ClassHeaderSummaryUio(
@Stable
data class Dice(
val characterName: String = "",
val timestamp: Long = 0L,
@DrawableRes val icon: Int = R.drawable.ic_d20_24,
val isCriticalSuccess: Boolean = false,

View file

@ -1,14 +1,52 @@
package com.pixelized.rplexicon.ui.screens.summary.pages.statistic
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.ui.screens.summary.SummaryFactory
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowCardFactory
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryUio
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import javax.inject.Inject
@HiltViewModel
class StatisticViewModel @Inject constructor(
factory: SummaryFactory,
private val firebaseRepository: FirebaseRepository,
private val throwCardFactory: ThrowCardFactory,
summaryFactory: SummaryFactory,
) : ViewModel() {
val summary = factory.fetchSummary(viewModelScope)
val summary = summaryFactory.fetchSummary(viewModelScope)
private var detailJob: Job? = null
private val _detail = mutableStateOf<ThrowsCardUio?>(null)
val detail: State<ThrowsCardUio?> get() = _detail
fun showDetail(dice: ClassHeaderSummaryUio.Dice) {
detailJob?.cancel()
detailJob = viewModelScope.launch(Dispatchers.IO) {
firebaseRepository.getThrows().collect {
val card = it.details[dice.characterName]?.let { throws ->
throwCardFactory.convert(throws = throws)
}
withContext(Dispatchers.Main) {
_detail.value = card
}
}
withContext(Dispatchers.Main) {
_detail.value = null
}
}
}
fun hideDetail() {
detailJob?.cancel()
detailJob = null
_detail.value = null
}
}

View file

@ -1,4 +1,4 @@
package com.pixelized.rplexicon.ui.screens.summary
package com.pixelized.rplexicon.ui.screens.summary.pages.statistic
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
@ -22,7 +22,6 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.label
import com.pixelized.rplexicon.ui.screens.summary.composable.common.maxLabel
import com.pixelized.rplexicon.ui.screens.summary.composable.common.none
import com.pixelized.rplexicon.ui.screens.summary.composable.common.proficiency
import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticSummaryUio
import com.pixelized.rplexicon.utilitary.extentions.local.highestSpellLevel
import com.pixelized.rplexicon.utilitary.extentions.local.mastery
import com.pixelized.rplexicon.utilitary.extentions.local.passivesBonus
@ -39,9 +38,6 @@ import kotlinx.coroutines.withContext
import javax.inject.Inject
import kotlin.math.max
private const val ENTER_ANIMATION_INITIAL_DELAY = 250L
private const val ENTER_ANIMATION_DELAY = 100L
class SummaryFactory @Inject constructor(
private val characterSheetRepository: CharacterSheetRepository,
private val alterationRepository: AlterationRepository,
@ -620,6 +616,7 @@ class SummaryFactory @Inject constructor(
throws.forEach { entry ->
header.getDice(name = entry.key)?.value = ClassHeaderSummaryUio.Dice(
characterName = entry.key,
timestamp = entry.value.timestamp,
result = entry.value.result,
isCriticalSuccess = entry.value.isCriticalSuccess ?: false,
@ -662,4 +659,9 @@ class SummaryFactory @Inject constructor(
operator fun component1() = sheets
operator fun component2() = fires
}
companion object {
private const val ENTER_ANIMATION_INITIAL_DELAY = 250L
private const val ENTER_ANIMATION_DELAY = 100L
}
}