Add dice roll sharing
This commit is contained in:
parent
41a094009d
commit
980a7e7929
37 changed files with 745 additions and 327 deletions
2
app/proguard-rules.pro
vendored
2
app/proguard-rules.pro
vendored
|
|
@ -35,4 +35,4 @@
|
|||
# This rule will properly ProGuard all the model classes in
|
||||
# the package com.yourcompany.models.
|
||||
# Modify this rule to fit the structure of your app.
|
||||
-keepclassmembers class com.pixelized.rplexicon.data.model.CharacterSheetFire.** { *; }
|
||||
-keepclassmembers class com.pixelized.rplexicon.data.network.CharacterSheetFire.** { *; }
|
||||
|
|
@ -10,6 +10,8 @@ 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.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
|
||||
|
|
@ -38,6 +40,7 @@ import kotlin.math.min
|
|||
data class DiceThrowResult(
|
||||
val dice: RollDiceUio,
|
||||
val card: ThrowsCardUio,
|
||||
val network: NetworkThrow,
|
||||
)
|
||||
|
||||
@Suppress("KotlinConstantConditions")
|
||||
|
|
@ -664,7 +667,19 @@ class DiceThrowUseCase @Inject constructor(
|
|||
result = "${result.value}",
|
||||
),
|
||||
) + 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()
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -771,7 +786,19 @@ class DiceThrowUseCase @Inject constructor(
|
|||
result = "${result.value}",
|
||||
),
|
||||
) + 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()
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -857,7 +884,17 @@ class DiceThrowUseCase @Inject constructor(
|
|||
result = "${result.value}",
|
||||
),
|
||||
) + 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()
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -904,13 +941,13 @@ class DiceThrowUseCase @Inject constructor(
|
|||
),
|
||||
card = ThrowsCardUio(
|
||||
title = titleString.uppercase(),
|
||||
highlight = spellName,
|
||||
highlight = spellName ?: "",
|
||||
dice = (skill?.effect?.faces ?: 4).icon,
|
||||
roll = allValue.toLabel(),
|
||||
result = rollResult,
|
||||
details = listOf(
|
||||
ThrowsCardUio.Detail(
|
||||
title = spellName,
|
||||
title = spellName ?: "",
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = (skill?.effect?.faces ?: 4).icon,
|
||||
roll = "${skill?.effect?.amount ?: 1}d${skill?.effect?.faces ?: 4}",
|
||||
|
|
@ -921,11 +958,27 @@ class DiceThrowUseCase @Inject constructor(
|
|||
result = "${result.value}",
|
||||
),
|
||||
) + 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.
|
||||
*/
|
||||
|
|
@ -994,7 +1047,7 @@ class DiceThrowUseCase @Inject constructor(
|
|||
critical = status.critical,
|
||||
)
|
||||
ThrowsCardUio.Detail(
|
||||
title = dice.title,
|
||||
title = dice.title ?: "",
|
||||
throws = ThrowsCardUio.Throw(
|
||||
dice = dice.faces.icon,
|
||||
advantage = dice.advantage,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package com.pixelized.rplexicon.business
|
|||
|
||||
import com.pixelized.rplexicon.data.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellHeaderUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.SpellUioFactory
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.data.model
|
||||
package com.pixelized.rplexicon.data.network
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.firebase.database.IgnoreExtraProperties
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.data.model
|
||||
package com.pixelized.rplexicon.data.network
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.firebase.database.IgnoreExtraProperties
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.pixelized.rplexicon.data.network
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.firebase.database.IgnoreExtraProperties
|
||||
import com.google.firebase.database.PropertyName
|
||||
|
||||
@Keep
|
||||
@IgnoreExtraProperties
|
||||
data class NetworkThrow(
|
||||
@get:PropertyName(TIMESTAMP)
|
||||
@set:PropertyName(TIMESTAMP)
|
||||
var timestamp: Long = 0L,
|
||||
|
||||
@get:PropertyName(TITLE)
|
||||
@set:PropertyName(TITLE)
|
||||
var title: String = "",
|
||||
|
||||
@get:PropertyName(RESULT)
|
||||
@set:PropertyName(RESULT)
|
||||
var result: String = "",
|
||||
|
||||
@get:PropertyName(CRITICAL)
|
||||
@set:PropertyName(CRITICAL)
|
||||
var isCriticalSuccess: Boolean? = null,
|
||||
|
||||
@get:PropertyName(FAIL)
|
||||
@set:PropertyName(FAIL)
|
||||
var isCriticalFailure: Boolean? = null,
|
||||
|
||||
@get:PropertyName(DETAILS)
|
||||
@set:PropertyName(DETAILS)
|
||||
var details: List<Bonus> = emptyList(),
|
||||
) {
|
||||
@Keep
|
||||
@IgnoreExtraProperties
|
||||
data class Bonus(
|
||||
@get:PropertyName(LABEL)
|
||||
@set:PropertyName(LABEL)
|
||||
var label: String = "",
|
||||
|
||||
@get:PropertyName(DICE)
|
||||
@set:PropertyName(DICE)
|
||||
var dice: String? = null,
|
||||
|
||||
@get:PropertyName(RESULT)
|
||||
@set:PropertyName(RESULT)
|
||||
var result: String = "",
|
||||
) {
|
||||
companion object {
|
||||
const val LABEL = "label"
|
||||
const val DICE = "dice"
|
||||
const val RESULT = "result"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TIMESTAMP = "timestamp"
|
||||
const val TITLE = "title"
|
||||
const val RESULT = "result"
|
||||
const val CRITICAL = "crit"
|
||||
const val FAIL = "fail"
|
||||
const val DETAILS = "details"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.pixelized.rplexicon.data.network
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.google.firebase.database.IgnoreExtraProperties
|
||||
import com.google.firebase.database.PropertyName
|
||||
|
||||
@Keep
|
||||
@IgnoreExtraProperties
|
||||
data class NetworkThrowMap(
|
||||
@get:PropertyName(CHARACTERS_THROWS)
|
||||
@set:PropertyName(CHARACTERS_THROWS)
|
||||
var details: Map<String, NetworkThrow> = emptyMap(),
|
||||
) {
|
||||
companion object {
|
||||
const val CHARACTERS_THROWS = "CharactersThrows"
|
||||
}
|
||||
}
|
||||
|
|
@ -8,8 +8,11 @@ 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.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFireMap
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFireMap
|
||||
import com.pixelized.rplexicon.data.network.NetworkThrow
|
||||
import com.pixelized.rplexicon.data.network.NetworkThrowMap
|
||||
import com.pixelized.rplexicon.data.network.NetworkThrowMap.Companion.CHARACTERS_THROWS
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -167,8 +170,46 @@ 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
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "FirebaseRepository"
|
||||
private const val PATH_CHARACTERS = "Characters"
|
||||
private const val PATH_THROWS = CHARACTERS_THROWS
|
||||
}
|
||||
}
|
||||
|
|
@ -2,15 +2,11 @@ package com.pixelized.rplexicon.ui.screens.character.factory
|
|||
|
||||
import com.pixelized.rplexicon.data.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellHeaderUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.firstSpellSlot
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.icon
|
||||
import com.pixelized.rplexicon.utilitary.extentions.local.spell
|
||||
import com.pixelized.rplexicon.utilitary.extentions.modifier
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import androidx.lifecycle.AndroidViewModel
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.Skill
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import com.pixelized.rplexicon.R
|
|||
import com.pixelized.rplexicon.business.SpellBookUseCase
|
||||
import com.pixelized.rplexicon.data.model.AssignedSpell
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
import com.pixelized.rplexicon.data.model.Throw
|
||||
|
|
|
|||
|
|
@ -287,9 +287,9 @@ private fun RollOverlayContent(
|
|||
)
|
||||
|
||||
else -> ThrowsCard(
|
||||
modifier = Modifier.padding(
|
||||
bottom = if (enableDrawer.value) 32.dp else 0.dp
|
||||
),
|
||||
modifier = Modifier
|
||||
.padding(bottom = if (enableDrawer.value) 32.dp else 0.dp)
|
||||
.padding(all = 16.dp),
|
||||
throws = it,
|
||||
showDetail = showDetail,
|
||||
onClick = onCard,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.pixelized.rplexicon.R
|
|||
import com.pixelized.rplexicon.business.DiceThrowUseCase
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.DiceThrow
|
||||
import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.AlterationRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository
|
||||
import com.pixelized.rplexicon.data.repository.character.DescriptionRepository
|
||||
|
|
@ -36,6 +37,7 @@ class RollOverlayViewModel @Inject constructor(
|
|||
private val rollUseCase: DiceThrowUseCase,
|
||||
private val diceFactory: DiceFactory,
|
||||
private val alterationFactory: AlterationFactory,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
application: Application,
|
||||
) : AndroidViewModel(application) {
|
||||
private var sheet: CharacterSheet? = null
|
||||
|
|
@ -88,13 +90,19 @@ class RollOverlayViewModel @Inject constructor(
|
|||
diceThrow?.let { diceThrow ->
|
||||
rollJob?.cancel()
|
||||
rollJob = viewModelScope.launch {
|
||||
// roll the dice ;)
|
||||
val result = rollUseCase.roll(
|
||||
diceThrow = diceThrow,
|
||||
alterationId = _alterations.value.mapNotNull { if (it.checked) it.label else null },
|
||||
)
|
||||
// share the result
|
||||
result?.network?.let {
|
||||
firebaseRepository.sendThrow(sheet?.name, it)
|
||||
}
|
||||
// Start the roll animation.
|
||||
_dice.value = _dice.value?.let {
|
||||
it.copy(
|
||||
result = "",
|
||||
animationSpec = RollDiceUio.TWEEN,
|
||||
rotation = it.rotation + 5f,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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? = null, // 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
|
||||
)
|
||||
|
|
@ -104,7 +104,6 @@ fun ThrowsCard(
|
|||
Surface(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(all = 16.dp)
|
||||
.ddBorder(inner = inner, outline = remember { CutCornerShape(size = 16.dp) })
|
||||
.clip(shape = inner)
|
||||
.clickable(onClick = onClick),
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import androidx.compose.runtime.mutableIntStateOf
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.model.Property
|
||||
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.CharacterSheetRepository
|
||||
|
|
@ -21,6 +22,7 @@ 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
|
||||
|
|
@ -45,7 +47,7 @@ class SummaryFactory @Inject constructor(
|
|||
private val alterationRepository: AlterationRepository,
|
||||
private val firebaseRepository: FirebaseRepository,
|
||||
) {
|
||||
fun fetchSummary(scope: CoroutineScope): SummaryUio {
|
||||
fun fetchSummary(scope: CoroutineScope): StatisticSummaryUio {
|
||||
val headerVisibility = mutableStateOf(false)
|
||||
val statsVisibility = mutableStateOf(false)
|
||||
val characteristicsVisibility = mutableStateOf(false)
|
||||
|
|
@ -55,13 +57,18 @@ class SummaryFactory @Inject constructor(
|
|||
val spellsVisibility = mutableStateOf(false)
|
||||
|
||||
val header = ClassHeaderSummaryUio(
|
||||
c1 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
c2 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
c3 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
c4 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
c5 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
clazz1 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
dice1 = mutableStateOf(ClassHeaderSummaryUio.Dice()),
|
||||
clazz2 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
dice2 = mutableStateOf(ClassHeaderSummaryUio.Dice()),
|
||||
clazz3 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
dice3 = mutableStateOf(ClassHeaderSummaryUio.Dice()),
|
||||
clazz4 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
dice4 = mutableStateOf(ClassHeaderSummaryUio.Dice()),
|
||||
clazz5 = mutableStateOf(ClassHeaderSummaryUio.Header()),
|
||||
dice5 = mutableStateOf(ClassHeaderSummaryUio.Dice()),
|
||||
)
|
||||
val stats = AttributesSummaryUio(
|
||||
val attributes = AttributesSummaryUio(
|
||||
hp = SummaryRowUio(label = R.string.character_sheet_title_hp),
|
||||
ac = SummaryRowUio(label = R.string.character_sheet_title_ca),
|
||||
dc = SummaryRowUio(label = R.string.character_sheet_title_dc),
|
||||
|
|
@ -143,24 +150,12 @@ class SummaryFactory @Inject constructor(
|
|||
maxSpellSlot.intValue = highestSpellSlot
|
||||
}
|
||||
|
||||
// extension function to root a character to a column property.
|
||||
fun ClassHeaderSummaryUio.get(sheet: CharacterSheet?) = when (sheet) {
|
||||
sheets[characters.getOrNull(0)] -> c1
|
||||
sheets[characters.getOrNull(1)] -> c2
|
||||
sheets[characters.getOrNull(2)] -> c3
|
||||
sheets[characters.getOrNull(3)] -> c4
|
||||
sheets[characters.getOrNull(4)] -> c5
|
||||
else -> null
|
||||
}
|
||||
// extension functions to root a character to a column property.
|
||||
fun SummaryRowUio.get(sheet: CharacterSheet?) =
|
||||
get(index = characters.indexOf(sheet?.name))
|
||||
|
||||
fun SummaryRowUio.get(sheet: CharacterSheet?) = when (sheet) {
|
||||
sheets[characters.getOrNull(0)] -> c1
|
||||
sheets[characters.getOrNull(1)] -> c2
|
||||
sheets[characters.getOrNull(2)] -> c3
|
||||
sheets[characters.getOrNull(3)] -> c4
|
||||
sheets[characters.getOrNull(4)] -> c5
|
||||
else -> null
|
||||
}
|
||||
fun ClassHeaderSummaryUio.getClass(sheet: CharacterSheet?) =
|
||||
classes.getOrNull(index = characters.indexOf(sheet?.name))
|
||||
|
||||
// Update the header
|
||||
sheets.values.forEach { sheet ->
|
||||
|
|
@ -169,7 +164,7 @@ class SummaryFactory @Inject constructor(
|
|||
icon = sheet.characterClass.firstOrNull()?.icon ?: R.drawable.ic_d20_24,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
header.get(sheet)?.value = clazz
|
||||
header.getClass(sheet)?.value = clazz
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
@ -206,11 +201,11 @@ class SummaryFactory @Inject constructor(
|
|||
label = "${sheet.speed}m",
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
stats.hp.get(sheet)?.value = hitPoint
|
||||
stats.ac.get(sheet)?.value = armorClass
|
||||
stats.dc.get(sheet)?.value = dC
|
||||
stats.initiative.get(sheet)?.value = initiative
|
||||
stats.speed.get(sheet)?.value = speed
|
||||
attributes.hp.get(sheet)?.value = hitPoint
|
||||
attributes.ac.get(sheet)?.value = armorClass
|
||||
attributes.dc.get(sheet)?.value = dC
|
||||
attributes.initiative.get(sheet)?.value = initiative
|
||||
attributes.speed.get(sheet)?.value = speed
|
||||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
@ -609,11 +604,36 @@ class SummaryFactory @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
return SummaryUio(
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val data = HeaderStatStruct()
|
||||
characterSheetRepository.data
|
||||
.combine(firebaseRepository.getThrows()) { sheets, fire ->
|
||||
data.sheets = sheets
|
||||
data.fires = fire.details
|
||||
}
|
||||
.collect {
|
||||
val (sheets, throws) = data
|
||||
val characters = sheets.keys.sorted()
|
||||
|
||||
fun ClassHeaderSummaryUio.getDice(name: String?) =
|
||||
dices.getOrNull(index = characters.indexOf(name))
|
||||
|
||||
throws.forEach { entry ->
|
||||
header.getDice(name = entry.key)?.value = ClassHeaderSummaryUio.Dice(
|
||||
timestamp = entry.value.timestamp,
|
||||
result = entry.value.result,
|
||||
isCriticalSuccess = entry.value.isCriticalSuccess ?: false,
|
||||
isCriticalFailure = entry.value.isCriticalFailure ?: false,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return StatisticSummaryUio(
|
||||
headerVisibility = headerVisibility,
|
||||
header = header,
|
||||
statsVisibility = statsVisibility,
|
||||
stats = stats,
|
||||
attributes = attributes,
|
||||
characteristicsVisibility = characteristicsVisibility,
|
||||
characteristics = characteristics,
|
||||
savingThrowsVisibility = savingThrowsVisibility,
|
||||
|
|
@ -634,4 +654,12 @@ class SummaryFactory @Inject constructor(
|
|||
operator fun component1() = sheets
|
||||
operator fun component2() = fires
|
||||
}
|
||||
|
||||
private class HeaderStatStruct {
|
||||
lateinit var sheets: Map<String, CharacterSheet>
|
||||
lateinit var fires: Map<String, NetworkThrow>
|
||||
|
||||
operator fun component1() = sheets
|
||||
operator fun component2() = fires
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,18 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
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.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.pullrefresh.PullRefreshState
|
||||
import androidx.compose.material.pullrefresh.pullRefresh
|
||||
import androidx.compose.material.pullrefresh.rememberPullRefreshState
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
|
@ -24,73 +20,33 @@ import androidx.compose.material3.Scaffold
|
|||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
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.summary.composable.AttributesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.AttributesSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.CharacteristicsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.CharacteristicsSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.PassivesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.PassivesSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ProficiencySummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ProficiencySummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SavingThrowsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SavingThrowsSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SpellSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SpellSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberCharacteristicsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberClassHeaderSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberPassivesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberProficienciesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberSavingThrowsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberSpellsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberStatsSummary
|
||||
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
|
||||
|
||||
@Stable
|
||||
data class SummaryUio(
|
||||
val headerVisibility: State<Boolean>,
|
||||
val header: ClassHeaderSummaryUio,
|
||||
val statsVisibility: State<Boolean>,
|
||||
val stats: AttributesSummaryUio,
|
||||
val characteristicsVisibility: State<Boolean>,
|
||||
val characteristics: CharacteristicsSummaryUio,
|
||||
val savingThrowsVisibility: State<Boolean>,
|
||||
val savingThrows: SavingThrowsSummaryUio,
|
||||
val proficienciesVisibility: State<Boolean>,
|
||||
val proficiencies: ProficiencySummaryUio,
|
||||
val passivesVisibility: State<Boolean>,
|
||||
val passives: PassivesSummaryUio,
|
||||
val spellsVisibility: State<Boolean>,
|
||||
val spells: SpellSummaryUio,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class, ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun SummaryScreen(
|
||||
viewModel: SummaryViewModel = hiltViewModel(),
|
||||
statisticsViewModel: StatisticViewModel = hiltViewModel()
|
||||
) {
|
||||
val screen = LocalScreenNavHost.current
|
||||
val refresh = rememberPullRefreshState(
|
||||
refreshing = false,
|
||||
onRefresh = { },
|
||||
)
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
@ -98,27 +54,33 @@ fun SummaryScreen(
|
|||
SummaryContent(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.systemBarsPadding(),
|
||||
summary = viewModel.summary,
|
||||
.statusBarsPadding(),
|
||||
refreshState = refresh,
|
||||
onBack = {
|
||||
screen.popBackStack()
|
||||
},
|
||||
onHeader = {
|
||||
screen.navigateToCharacterSheet(name = it.label)
|
||||
}
|
||||
statistics = {
|
||||
StatisticSummary(
|
||||
summary = statisticsViewModel.summary,
|
||||
onClass = {
|
||||
screen.navigateToCharacterSheet(name = it.label)
|
||||
},
|
||||
onDice = { },
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
KeepOnScreen()
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun SummaryContent(
|
||||
modifier: Modifier = Modifier,
|
||||
scrollState: ScrollState = rememberScrollState(),
|
||||
summary: SummaryUio,
|
||||
refreshState: PullRefreshState,
|
||||
onBack: () -> Unit,
|
||||
onHeader: (ClassHeaderSummaryUio.Header) -> Unit,
|
||||
statistics: @Composable () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
|
|
@ -139,7 +101,7 @@ private fun SummaryContent(
|
|||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(id = R.string.character_sheet_summary_title),
|
||||
text = stringResource(id = R.string.summary_title),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
)
|
||||
}
|
||||
|
|
@ -148,140 +110,26 @@ private fun SummaryContent(
|
|||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state = scrollState)
|
||||
.padding(paddingValues = paddingValues)
|
||||
.padding(horizontal = 16.dp),
|
||||
.fillMaxSize()
|
||||
.pullRefresh(refreshState)
|
||||
.padding(paddingValues = paddingValues),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier
|
||||
.zIndex(zIndex = 1f)
|
||||
.fillMaxWidth()
|
||||
.offset { IntOffset(x = 0, y = scrollState.value) }
|
||||
.background(brush = rememberHeaderBackgroundGradient())
|
||||
.padding(bottom = 16.dp, end = 3.dp),
|
||||
visible = summary.headerVisibility.value,
|
||||
enter = fadeIn(),
|
||||
) {
|
||||
ClassHeaderSummary(
|
||||
header = summary.header,
|
||||
onClick = onHeader,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = summary.statsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
AttributesSummary(
|
||||
attributes = summary.stats,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.characteristicsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
CharacteristicsSummary(
|
||||
characteristics = summary.characteristics,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.savingThrowsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
SavingThrowsSummary(
|
||||
savingThrows = summary.savingThrows,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.proficienciesVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
ProficiencySummary(
|
||||
proficiencies = summary.proficiencies,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.passivesVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
PassivesSummary(
|
||||
passives = summary.passives,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.spellsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
SpellSummary(
|
||||
spells = summary.spells,
|
||||
)
|
||||
}
|
||||
}
|
||||
statistics()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
private fun enterTransition(
|
||||
density: Density = LocalDensity.current,
|
||||
): EnterTransition {
|
||||
return fadeIn() + slideInVertically { with(density) { 24.dp.roundToPx() } }
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberHeaderBackgroundGradient(): Brush {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
return remember {
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
colorScheme.surface.copy(alpha = 1.0f),
|
||||
colorScheme.surface.copy(alpha = 1.0f),
|
||||
colorScheme.surface.copy(alpha = 0.5f),
|
||||
colorScheme.surface.copy(alpha = 0.0f),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, heightDp = 1680)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, heightDp = 1680)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
private fun SummaryPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
val header = rememberClassHeaderSummary()
|
||||
val stats = rememberStatsSummary()
|
||||
val characteristics = rememberCharacteristicsSummary()
|
||||
val savingThrows = rememberSavingThrowsSummary()
|
||||
val proficiencies = rememberProficienciesSummary()
|
||||
val passives = rememberPassivesSummary()
|
||||
val spells = rememberSpellsSummary()
|
||||
|
||||
SummaryContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
summary = remember {
|
||||
SummaryUio(
|
||||
headerVisibility = mutableStateOf(true),
|
||||
header = header,
|
||||
statsVisibility = mutableStateOf(true),
|
||||
stats = stats,
|
||||
characteristicsVisibility = mutableStateOf(true),
|
||||
characteristics = characteristics,
|
||||
savingThrowsVisibility = mutableStateOf(true),
|
||||
savingThrows = savingThrows,
|
||||
proficienciesVisibility = mutableStateOf(true),
|
||||
proficiencies = proficiencies,
|
||||
passivesVisibility = mutableStateOf(true),
|
||||
passives = passives,
|
||||
spellsVisibility = mutableStateOf(true),
|
||||
spells = spells,
|
||||
)
|
||||
},
|
||||
refreshState = rememberPullRefreshState(refreshing = false, onRefresh = { }),
|
||||
onBack = { },
|
||||
onHeader = { },
|
||||
statistics = { StatisticSummaryPreview() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberStatsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberAttributesSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
@ -78,7 +78,7 @@ private fun StatsSummaryPreview() {
|
|||
LexiconTheme {
|
||||
Surface {
|
||||
AttributesSummary(
|
||||
attributes = rememberStatsSummary()
|
||||
attributes = rememberAttributesSummary()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberCharacteristicsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberCharacteristicsSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
|
|||
|
|
@ -2,106 +2,210 @@ package com.pixelized.rplexicon.ui.screens.summary.composable
|
|||
|
||||
import android.content.res.Configuration
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.ContentTransform
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shadow
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberClassHeaderSummary
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberClassHeaderSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
||||
@Stable
|
||||
data class ClassHeaderSummaryUio(
|
||||
val c1: MutableState<Header>,
|
||||
val c2: MutableState<Header>,
|
||||
val c3: MutableState<Header>,
|
||||
val c4: MutableState<Header>,
|
||||
val c5: MutableState<Header>,
|
||||
val clazz1: MutableState<Header>,
|
||||
val dice1: MutableState<Dice>,
|
||||
val clazz2: MutableState<Header>,
|
||||
val dice2: MutableState<Dice>,
|
||||
val clazz3: MutableState<Header>,
|
||||
val dice3: MutableState<Dice>,
|
||||
val clazz4: MutableState<Header>,
|
||||
val dice4: MutableState<Dice>,
|
||||
val clazz5: MutableState<Header>,
|
||||
val dice5: MutableState<Dice>,
|
||||
) {
|
||||
val classes = arrayListOf(clazz1, clazz2, clazz3, clazz4, clazz5)
|
||||
val dices = arrayListOf(dice1, dice2, dice3, dice4, dice5)
|
||||
|
||||
@Stable
|
||||
data class Header(
|
||||
val label: String = "",
|
||||
@DrawableRes val icon: Int = R.drawable.ic_d20_24,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class Dice(
|
||||
val timestamp: Long = 0L,
|
||||
@DrawableRes val icon: Int = R.drawable.ic_d20_24,
|
||||
val isCriticalSuccess: Boolean = false,
|
||||
val isCriticalFailure: Boolean = false,
|
||||
val result: String = "",
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ClassHeaderSummary(
|
||||
modifier: Modifier = Modifier,
|
||||
header: ClassHeaderSummaryUio,
|
||||
onClick: (ClassHeaderSummaryUio.Header) -> Unit
|
||||
onClass: (ClassHeaderSummaryUio.Header) -> Unit,
|
||||
onDice: (ClassHeaderSummaryUio.Dice) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
Column(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 1.dp, alignment = Alignment.End),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalAlignment = Alignment.End,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 1.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
header.classes.forEach {
|
||||
IconButton(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
onClick = { onClass(it.value) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
painter = painterResource(id = it.value.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 1.dp, alignment = Alignment.End),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
header.dices.forEach {
|
||||
ClassHeaderDice(
|
||||
dice = it,
|
||||
onDice = onDice,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ClassHeaderDice(
|
||||
modifier: Modifier = Modifier,
|
||||
dice: State<ClassHeaderSummaryUio.Dice>,
|
||||
onDice: (ClassHeaderSummaryUio.Dice) -> Unit
|
||||
) {
|
||||
val typography = MaterialTheme.typography
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val style = remember {
|
||||
typography.headlineLarge.copy(
|
||||
shadow = Shadow(
|
||||
color = colorScheme.surface,
|
||||
offset = Offset.Zero,
|
||||
blurRadius = 10f,
|
||||
),
|
||||
)
|
||||
}
|
||||
val textColor = animateColorAsState(
|
||||
targetValue = when {
|
||||
dice.value.isCriticalSuccess -> MaterialTheme.colorScheme.primary
|
||||
dice.value.isCriticalFailure -> Color.Red
|
||||
else -> MaterialTheme.colorScheme.onSurface
|
||||
},
|
||||
animationSpec = tween(
|
||||
delayMillis = RollDiceUio.ROLL_DURATION.toInt()
|
||||
),
|
||||
label = "ClassHeaderDiceColorAnimation"
|
||||
)
|
||||
val iconColor = remember {
|
||||
derivedStateOf {
|
||||
textColor.value.copy(alpha = 0.5f)
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
onClick = { onClick(header.c1.value) },
|
||||
onClick = { onDice(dice.value) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
painter = painterResource(id = header.c1.value.icon),
|
||||
modifier = Modifier.size(MaterialTheme.lexicon.dimens.summary.cell),
|
||||
painter = painterResource(id = dice.value.icon),
|
||||
tint = iconColor.value,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
onClick = { onClick(header.c2.value) },
|
||||
AnimatedContent(
|
||||
targetState = dice.value,
|
||||
label = "ClassHeaderDiceValueAnimation",
|
||||
transitionSpec = labelAnimationSpec()
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
painter = painterResource(id = header.c2.value.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
onClick = { onClick(header.c3.value) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
painter = painterResource(id = header.c3.value.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
onClick = { onClick(header.c4.value) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
painter = painterResource(id = header.c4.value.icon),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
onClick = { onClick(header.c5.value) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
painter = painterResource(id = header.c5.value.icon),
|
||||
contentDescription = null,
|
||||
Text(
|
||||
modifier = modifier.width(MaterialTheme.lexicon.dimens.summary.cell.width),
|
||||
style = style,
|
||||
textAlign = TextAlign.Center,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = textColor.value,
|
||||
text = it.result
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
private fun labelAnimationSpec(): AnimatedContentTransitionScope<*>.() -> ContentTransform = {
|
||||
val slideIn = slideInVertically(
|
||||
animationSpec = tween(
|
||||
delayMillis = RollDiceUio.ROLL_DURATION.toInt()
|
||||
)
|
||||
) { it / 2 }
|
||||
val fadeIn = fadeIn(
|
||||
animationSpec = tween(
|
||||
delayMillis = RollDiceUio.ROLL_DURATION.toInt()
|
||||
)
|
||||
)
|
||||
val slideOut = slideOutVertically(
|
||||
animationSpec = tween()
|
||||
) { -it / 2 }
|
||||
val fadeOut = fadeOut(
|
||||
animationSpec = tween()
|
||||
)
|
||||
slideIn + fadeIn togetherWith slideOut + fadeOut using SizeTransform(clip = false)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
|
|
@ -111,7 +215,8 @@ private fun ClassHeaderSummaryPreview() {
|
|||
ClassHeaderSummary(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
header = rememberClassHeaderSummary(),
|
||||
onClick = { }
|
||||
onClass = { },
|
||||
onDice = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberPassivesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberPassivesSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberProficienciesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberProficienciesSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberSavingThrowsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberSavingThrowsSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import androidx.compose.ui.unit.dp
|
|||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRow
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.common.SummaryRowUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.rememberSpellsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberSpellsSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.ddBorder
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,18 @@ data class SummaryRowUio(
|
|||
val c3: MutableState<SummaryCellUio> = mutableStateOf(none()),
|
||||
val c4: MutableState<SummaryCellUio> = mutableStateOf(none()),
|
||||
val c5: MutableState<SummaryCellUio> = mutableStateOf(none()),
|
||||
)
|
||||
) {
|
||||
operator fun get(index: Int): MutableState<SummaryCellUio>? {
|
||||
return when (index) {
|
||||
0 -> c1
|
||||
1 -> c2
|
||||
2 -> c3
|
||||
3 -> c4
|
||||
4 -> c5
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SummaryRow(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -11,7 +11,7 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.common.label
|
|||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberStatsSummary(): AttributesSummaryUio {
|
||||
fun rememberAttributesSummary(): AttributesSummaryUio {
|
||||
return remember {
|
||||
AttributesSummaryUio(
|
||||
hp = SummaryRowUio(
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -12,36 +12,53 @@ import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryU
|
|||
fun rememberClassHeaderSummary(): ClassHeaderSummaryUio {
|
||||
return remember {
|
||||
ClassHeaderSummaryUio(
|
||||
c1 = mutableStateOf(
|
||||
clazz1 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Header(
|
||||
label = "Brulkai",
|
||||
icon = R.drawable.ic_class_barbarian_24,
|
||||
)
|
||||
),
|
||||
c2 = mutableStateOf(
|
||||
dice1 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Dice(
|
||||
result = "20",
|
||||
)
|
||||
),
|
||||
clazz2 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Header(
|
||||
label = "Léandre",
|
||||
icon = R.drawable.ic_class_cleric_24,
|
||||
)
|
||||
),
|
||||
c3 = mutableStateOf(
|
||||
dice2 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Dice()
|
||||
),
|
||||
clazz3 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Header(
|
||||
label = "Nélia",
|
||||
icon = R.drawable.ic_class_ranger_24,
|
||||
)
|
||||
),
|
||||
c4 = mutableStateOf(
|
||||
dice3 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Dice()
|
||||
),
|
||||
clazz4 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Header(
|
||||
label = "Tigrane",
|
||||
icon = R.drawable.ic_class_warlock_24,
|
||||
)
|
||||
),
|
||||
c5 = mutableStateOf(
|
||||
dice4 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Dice()
|
||||
),
|
||||
clazz5 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Header(
|
||||
label = "Unathana",
|
||||
icon = R.drawable.ic_class_bard_24,
|
||||
)
|
||||
),
|
||||
dice5 = mutableStateOf(
|
||||
ClassHeaderSummaryUio.Dice()
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview
|
||||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticSummaryUio
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberStatisticSummary(): StatisticSummaryUio {
|
||||
val header = rememberClassHeaderSummary()
|
||||
val attributes = rememberAttributesSummary()
|
||||
val characteristics = rememberCharacteristicsSummary()
|
||||
val savingThrows = rememberSavingThrowsSummary()
|
||||
val proficiencies = rememberProficienciesSummary()
|
||||
val passives = rememberPassivesSummary()
|
||||
val spells = rememberSpellsSummary()
|
||||
|
||||
return remember {
|
||||
StatisticSummaryUio(
|
||||
headerVisibility = mutableStateOf(true),
|
||||
header = header,
|
||||
statsVisibility = mutableStateOf(true),
|
||||
attributes = attributes,
|
||||
characteristicsVisibility = mutableStateOf(true),
|
||||
characteristics = characteristics,
|
||||
savingThrowsVisibility = mutableStateOf(true),
|
||||
savingThrows = savingThrows,
|
||||
proficienciesVisibility = mutableStateOf(true),
|
||||
proficiencies = proficiencies,
|
||||
passivesVisibility = mutableStateOf(true),
|
||||
passives = passives,
|
||||
spellsVisibility = mutableStateOf(true),
|
||||
spells = spells,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary.pages.statistic
|
||||
|
||||
import android.content.res.Configuration
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.AttributesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.AttributesSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.CharacteristicsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.CharacteristicsSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.PassivesSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.PassivesSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ProficiencySummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.ProficiencySummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SavingThrowsSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SavingThrowsSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SpellSummary
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.SpellSummaryUio
|
||||
import com.pixelized.rplexicon.ui.screens.summary.composable.preview.statistic.rememberStatisticSummary
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Stable
|
||||
data class StatisticSummaryUio(
|
||||
val headerVisibility: State<Boolean>,
|
||||
val header: ClassHeaderSummaryUio,
|
||||
val statsVisibility: State<Boolean>,
|
||||
val attributes: AttributesSummaryUio,
|
||||
val characteristicsVisibility: State<Boolean>,
|
||||
val characteristics: CharacteristicsSummaryUio,
|
||||
val savingThrowsVisibility: State<Boolean>,
|
||||
val savingThrows: SavingThrowsSummaryUio,
|
||||
val proficienciesVisibility: State<Boolean>,
|
||||
val proficiencies: ProficiencySummaryUio,
|
||||
val passivesVisibility: State<Boolean>,
|
||||
val passives: PassivesSummaryUio,
|
||||
val spellsVisibility: State<Boolean>,
|
||||
val spells: SpellSummaryUio,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun StatisticSummary(
|
||||
modifier: Modifier = Modifier,
|
||||
scrollState: ScrollState = rememberScrollState(),
|
||||
summary: StatisticSummaryUio,
|
||||
onClass: (ClassHeaderSummaryUio.Header) -> Unit,
|
||||
onDice: (ClassHeaderSummaryUio.Dice) -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state = scrollState)
|
||||
.padding(horizontal = 16.dp)
|
||||
.then(other = modifier),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier
|
||||
.zIndex(zIndex = 1f)
|
||||
.fillMaxWidth()
|
||||
.offset { IntOffset(x = 0, y = scrollState.value) }
|
||||
.background(brush = rememberHeaderBackgroundGradient())
|
||||
.padding(bottom = 16.dp, end = 3.dp),
|
||||
visible = summary.headerVisibility.value,
|
||||
enter = fadeIn(),
|
||||
) {
|
||||
ClassHeaderSummary(
|
||||
header = summary.header,
|
||||
onClass = onClass,
|
||||
onDice = onDice,
|
||||
)
|
||||
}
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = summary.statsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
AttributesSummary(
|
||||
attributes = summary.attributes,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.characteristicsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
CharacteristicsSummary(
|
||||
characteristics = summary.characteristics,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.savingThrowsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
SavingThrowsSummary(
|
||||
savingThrows = summary.savingThrows,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.proficienciesVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
ProficiencySummary(
|
||||
proficiencies = summary.proficiencies,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.passivesVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
PassivesSummary(
|
||||
passives = summary.passives,
|
||||
)
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = summary.spellsVisibility.value,
|
||||
enter = enterTransition(),
|
||||
) {
|
||||
SpellSummary(
|
||||
spells = summary.spells,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun enterTransition(
|
||||
density: Density = LocalDensity.current,
|
||||
): EnterTransition {
|
||||
return fadeIn() + slideInVertically { with(density) { 24.dp.roundToPx() } }
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun rememberHeaderBackgroundGradient(): Brush {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
return remember {
|
||||
Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
colorScheme.surface.copy(alpha = 1.0f),
|
||||
colorScheme.surface.copy(alpha = 1.0f),
|
||||
colorScheme.surface.copy(alpha = 0.75f),
|
||||
colorScheme.surface.copy(alpha = 0.0f),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, heightDp = 1680)
|
||||
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, heightDp = 1680)
|
||||
fun StatisticSummaryPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
StatisticSummary(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
summary = rememberStatisticSummary(),
|
||||
onClass = { },
|
||||
onDice = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
package com.pixelized.rplexicon.ui.screens.summary
|
||||
package com.pixelized.rplexicon.ui.screens.summary.pages.statistic
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.ui.screens.summary.SummaryFactory
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class SummaryViewModel @Inject constructor(
|
||||
class StatisticViewModel @Inject constructor(
|
||||
factory: SummaryFactory,
|
||||
) : ViewModel() {
|
||||
val summary = factory.fetchSummary(viewModelScope)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.pixelized.rplexicon.utilitary.extentions.local
|
||||
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheet
|
||||
import com.pixelized.rplexicon.data.model.CharacterSheetFire
|
||||
import com.pixelized.rplexicon.data.network.CharacterSheetFire
|
||||
|
||||
fun CharacterSheet.spell(level: Int): Int? = when (level) {
|
||||
1 -> spell1
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@
|
|||
<string name="map_destination">Destinations :</string>
|
||||
<string name="map_illustrations">Illustrations :</string>
|
||||
|
||||
<string name="character_sheet_summary_title">Détails des personnages</string>
|
||||
<string name="character_sheet_refresh_label">Rafraichir</string>
|
||||
<string name="character_sheet_tab_proficiency">Talents</string>
|
||||
<string name="character_sheet_tab_inventory">Inventaire</string>
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@
|
|||
<string name="map_destination">Destinations:</string>
|
||||
<string name="map_illustrations">Illustrations:</string>
|
||||
|
||||
<string name="character_sheet_summary_title">Characters sheets details</string>
|
||||
<string name="character_sheet_refresh_label">Refresh</string>
|
||||
<string name="character_sheet_tab_proficiency">Proficiencies</string>
|
||||
<string name="character_sheet_tab_inventory">Inventory</string>
|
||||
|
|
@ -216,4 +215,9 @@
|
|||
<string name="character_sheet_equipment_main_hand">Main hand</string>
|
||||
<string name="character_sheet_equipment_off_hand">Off hand</string>
|
||||
<string name="character_sheet_equipment_empty_description">This equipment does not have any description</string>
|
||||
|
||||
<string name="summary_title">Game Master</string>
|
||||
<string name="summary_title_tab_statistics">Statistic</string>
|
||||
<string name="summary_title_tab_combats">Combat</string>
|
||||
<string name="summary_title_tab_rolls">Rolls</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue