From 980a7e792999a6c268bcff23830f68fa70016dbe Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Fri, 22 Dec 2023 16:08:16 +0100 Subject: [PATCH] Add dice roll sharing --- app/proguard-rules.pro | 2 +- .../rplexicon/business/DiceThrowUseCase.kt | 67 ++++- .../rplexicon/business/SpellBookUseCase.kt | 2 +- .../{model => network}/CharacterSheetFire.kt | 2 +- .../CharacterSheetFireMap.kt | 2 +- .../rplexicon/data/network/NetworkThrow.kt | 64 +++++ .../rplexicon/data/network/NetworkThrowMap.kt | 17 ++ .../authentication/FirebaseRepository.kt | 45 +++- .../character/factory/SpellUioFactory.kt | 4 - .../pages/actions/SkillsViewModel.kt | 2 +- .../pages/actions/SpellsViewModel.kt | 2 +- .../rplexicon/ui/screens/rolls/RollOverlay.kt | 6 +- .../ui/screens/rolls/RollOverlayViewModel.kt | 8 + .../ui/screens/rolls/composable/ThrowsCard.kt | 5 +- .../ui/screens/summary/SummaryFactory.kt | 94 ++++--- .../ui/screens/summary/SummaryScreen.kt | 230 +++--------------- .../summary/composable/AttributesSummary.kt | 4 +- .../composable/CharacteristicsSummary.kt | 2 +- .../summary/composable/ClassHeaderSummary.kt | 209 ++++++++++++---- .../summary/composable/PassivesSummary.kt | 2 +- .../summary/composable/ProficiencySummary.kt | 2 +- .../summary/composable/SavingThrowsSummary.kt | 2 +- .../summary/composable/SpellSummary.kt | 2 +- .../summary/composable/common/SummaryRow.kt | 13 +- .../rememberAttributesSummary.kt} | 4 +- .../rememberCharacteristicsSummary.kt | 2 +- .../rememberClassHeaderSummary.kt | 29 ++- .../rememberPassivesSummary.kt | 2 +- .../rememberProficienciesSummary.kt | 2 +- .../rememberSavingThrowsSummary.kt | 2 +- .../{ => statistic}/rememberSpellsSummary.kt | 2 +- .../statistic/rememberStatisticSummary.kt | 38 +++ .../pages/statistic/StatisticSummary.kt | 189 ++++++++++++++ .../statistic/StatisticViewModel.kt} | 5 +- .../extentions/local/CharacterSheetEx.kt | 2 +- app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values/strings.xml | 6 +- 37 files changed, 745 insertions(+), 327 deletions(-) rename app/src/main/java/com/pixelized/rplexicon/data/{model => network}/CharacterSheetFire.kt (97%) rename app/src/main/java/com/pixelized/rplexicon/data/{model => network}/CharacterSheetFireMap.kt (90%) create mode 100644 app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrow.kt create mode 100644 app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrowMap.kt rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{rememberStatsSummary.kt => statistic/rememberAttributesSummary.kt} (96%) rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{ => statistic}/rememberCharacteristicsSummary.kt (99%) rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{ => statistic}/rememberClassHeaderSummary.kt (65%) rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{ => statistic}/rememberPassivesSummary.kt (99%) rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{ => statistic}/rememberProficienciesSummary.kt (99%) rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{ => statistic}/rememberSavingThrowsSummary.kt (99%) rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/{ => statistic}/rememberSpellsSummary.kt (99%) create mode 100644 app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberStatisticSummary.kt create mode 100644 app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticSummary.kt rename app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/{SummaryViewModel.kt => pages/statistic/StatisticViewModel.kt} (60%) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 5dc9e9a..f2db787 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -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.** { *; } \ No newline at end of file +-keepclassmembers class com.pixelized.rplexicon.data.network.CharacterSheetFire.** { *; } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt b/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt index 946f3e3..033a7dd 100644 --- a/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt +++ b/app/src/main/java/com/pixelized/rplexicon/business/DiceThrowUseCase.kt @@ -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 = + listOf(Bonus(title, dice, result)) + + private fun List.detail(): List = + 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, diff --git a/app/src/main/java/com/pixelized/rplexicon/business/SpellBookUseCase.kt b/app/src/main/java/com/pixelized/rplexicon/business/SpellBookUseCase.kt index d9b38f2..1d287e9 100644 --- a/app/src/main/java/com/pixelized/rplexicon/business/SpellBookUseCase.kt +++ b/app/src/main/java/com/pixelized/rplexicon/business/SpellBookUseCase.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/CharacterSheetFire.kt b/app/src/main/java/com/pixelized/rplexicon/data/network/CharacterSheetFire.kt similarity index 97% rename from app/src/main/java/com/pixelized/rplexicon/data/model/CharacterSheetFire.kt rename to app/src/main/java/com/pixelized/rplexicon/data/network/CharacterSheetFire.kt index 3b17d36..b6ba088 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/CharacterSheetFire.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/network/CharacterSheetFire.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/data/model/CharacterSheetFireMap.kt b/app/src/main/java/com/pixelized/rplexicon/data/network/CharacterSheetFireMap.kt similarity index 90% rename from app/src/main/java/com/pixelized/rplexicon/data/model/CharacterSheetFireMap.kt rename to app/src/main/java/com/pixelized/rplexicon/data/network/CharacterSheetFireMap.kt index aa0e911..f743591 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/model/CharacterSheetFireMap.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/network/CharacterSheetFireMap.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrow.kt b/app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrow.kt new file mode 100644 index 0000000..7823982 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrow.kt @@ -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 = 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" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrowMap.kt b/app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrowMap.kt new file mode 100644 index 0000000..55d5632 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/data/network/NetworkThrowMap.kt @@ -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 = emptyMap(), +) { + companion object { + const val CHARACTERS_THROWS = "CharactersThrows" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/data/repository/authentication/FirebaseRepository.kt b/app/src/main/java/com/pixelized/rplexicon/data/repository/authentication/FirebaseRepository.kt index ba6b4bb..4dc3f4e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/repository/authentication/FirebaseRepository.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/repository/authentication/FirebaseRepository.kt @@ -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 { + 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 } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt index ae4133a..e0ac7f7 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/SpellUioFactory.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt index 568f380..1f1ae08 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillsViewModel.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt index 4418840..07fc4bc 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SpellsViewModel.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt index 2b8ca36..e06f966 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlay.kt @@ -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, diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt index 244a6b9..9594bb7 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/RollOverlayViewModel.kt @@ -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, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/ThrowsCard.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/ThrowsCard.kt index 7038549..7e4e871 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/ThrowsCard.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/composable/ThrowsCard.kt @@ -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), diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryFactory.kt index f6dc356..69228c5 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryFactory.kt @@ -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 + lateinit var fires: Map + + operator fun component1() = sheets + operator fun component2() = fires + } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt index bc67eb1..269fe75 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryScreen.kt @@ -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, - val header: ClassHeaderSummaryUio, - val statsVisibility: State, - val stats: AttributesSummaryUio, - val characteristicsVisibility: State, - val characteristics: CharacteristicsSummaryUio, - val savingThrowsVisibility: State, - val savingThrows: SavingThrowsSummaryUio, - val proficienciesVisibility: State, - val proficiencies: ProficiencySummaryUio, - val passivesVisibility: State, - val passives: PassivesSummaryUio, - val spellsVisibility: State, - 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() }, ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/AttributesSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/AttributesSummary.kt index 7ee491e..eff2803 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/AttributesSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/AttributesSummary.kt @@ -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() ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/CharacteristicsSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/CharacteristicsSummary.kt index 61c2068..d109cc6 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/CharacteristicsSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/CharacteristicsSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ClassHeaderSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ClassHeaderSummary.kt index cf3a59e..1abef16 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ClassHeaderSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ClassHeaderSummary.kt @@ -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
, - val c2: MutableState
, - val c3: MutableState
, - val c4: MutableState
, - val c5: MutableState
, + val clazz1: MutableState
, + val dice1: MutableState, + val clazz2: MutableState
, + val dice2: MutableState, + val clazz3: MutableState
, + val dice3: MutableState, + val clazz4: MutableState
, + val dice4: MutableState, + val clazz5: MutableState
, + val dice5: MutableState, ) { + 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, + 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 = { }, ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/PassivesSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/PassivesSummary.kt index c92afc7..5be7744 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/PassivesSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/PassivesSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ProficiencySummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ProficiencySummary.kt index a065cd3..3f3cb22 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ProficiencySummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/ProficiencySummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SavingThrowsSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SavingThrowsSummary.kt index 3b38538..3f3edda 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SavingThrowsSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SavingThrowsSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SpellSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SpellSummary.kt index e4bd03e..f800e7f 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SpellSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/SpellSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/common/SummaryRow.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/common/SummaryRow.kt index 337fcbd..f9cf715 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/common/SummaryRow.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/common/SummaryRow.kt @@ -35,7 +35,18 @@ data class SummaryRowUio( val c3: MutableState = mutableStateOf(none()), val c4: MutableState = mutableStateOf(none()), val c5: MutableState = mutableStateOf(none()), -) +) { + operator fun get(index: Int): MutableState? { + return when (index) { + 0 -> c1 + 1 -> c2 + 2 -> c3 + 3 -> c4 + 4 -> c5 + else -> null + } + } +} @Composable fun SummaryRow( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberStatsSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberAttributesSummary.kt similarity index 96% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberStatsSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberAttributesSummary.kt index fa7b78b..dfab513 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberStatsSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberAttributesSummary.kt @@ -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( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberCharacteristicsSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberCharacteristicsSummary.kt similarity index 99% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberCharacteristicsSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberCharacteristicsSummary.kt index 74e3319..4c03865 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberCharacteristicsSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberCharacteristicsSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberClassHeaderSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberClassHeaderSummary.kt similarity index 65% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberClassHeaderSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberClassHeaderSummary.kt index 26df5b7..8cc9f17 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberClassHeaderSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberClassHeaderSummary.kt @@ -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() + ), ) } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberPassivesSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberPassivesSummary.kt similarity index 99% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberPassivesSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberPassivesSummary.kt index 0740314..2bfa26e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberPassivesSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberPassivesSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberProficienciesSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberProficienciesSummary.kt similarity index 99% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberProficienciesSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberProficienciesSummary.kt index 2abd604..1ccb8d3 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberProficienciesSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberProficienciesSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberSavingThrowsSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberSavingThrowsSummary.kt similarity index 99% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberSavingThrowsSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberSavingThrowsSummary.kt index 118fb92..b2a6e9a 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberSavingThrowsSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberSavingThrowsSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberSpellsSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberSpellsSummary.kt similarity index 99% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberSpellsSummary.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberSpellsSummary.kt index e532309..d7cb14e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/rememberSpellsSummary.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberSpellsSummary.kt @@ -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 diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberStatisticSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberStatisticSummary.kt new file mode 100644 index 0000000..5e040a5 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/composable/preview/statistic/rememberStatisticSummary.kt @@ -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, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticSummary.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticSummary.kt new file mode 100644 index 0000000..3903a6c --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticSummary.kt @@ -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, + val header: ClassHeaderSummaryUio, + val statsVisibility: State, + val attributes: AttributesSummaryUio, + val characteristicsVisibility: State, + val characteristics: CharacteristicsSummaryUio, + val savingThrowsVisibility: State, + val savingThrows: SavingThrowsSummaryUio, + val proficienciesVisibility: State, + val proficiencies: ProficiencySummaryUio, + val passivesVisibility: State, + val passives: PassivesSummaryUio, + val spellsVisibility: State, + 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 = { }, + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt similarity index 60% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryViewModel.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt index 375b1b1..8341a5a 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/SummaryViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt @@ -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) diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/CharacterSheetEx.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/CharacterSheetEx.kt index 65d0340..ce9050b 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/CharacterSheetEx.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/local/CharacterSheetEx.kt @@ -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 diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d262ed7..bfe361b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -86,7 +86,6 @@ Destinations : Illustrations : - Détails des personnages Rafraichir Talents Inventaire diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6bb8b5e..b23756d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -86,7 +86,6 @@ Destinations: Illustrations: - Characters sheets details Refresh Proficiencies Inventory @@ -216,4 +215,9 @@ Main hand Off hand This equipment does not have any description + + Game Master + Statistic + Combat + Rolls \ No newline at end of file