From 00267623ca32f4935d466b7bc8f89790f0da79c1 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Fri, 15 Dec 2023 10:58:34 +0100 Subject: [PATCH] Update the alteration design. --- .../composable/actions/AlterationItem.kt | 61 ++++++------------- .../pages/alteration/AlterationPage.kt | 41 +++++++++---- .../pages/alteration/AlterationViewModel.kt | 23 ++++--- .../rplexicon/ui/screens/rolls/RollOverlay.kt | 36 +++++++---- .../ui/screens/rolls/RollOverlayViewModel.kt | 16 ++++- .../rolls/factory/AlterationFactory.kt | 46 ++++++++++---- .../rolls/preview/rememberRollAlterations.kt | 58 +++++++++++------- 7 files changed, 171 insertions(+), 110 deletions(-) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationItem.kt index b43dd39..2b117ee 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/AlterationItem.kt @@ -5,8 +5,6 @@ import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -31,12 +29,11 @@ import com.pixelized.rplexicon.ui.theme.LexiconTheme @Stable data class AlterationItemUio( val label: String, - val original: String?, + val source: String, val subLabel: String?, val checked: Boolean, ) -@OptIn(ExperimentalLayoutApi::class) @Composable fun AlterationItem( modifier: Modifier = Modifier, @@ -58,37 +55,23 @@ fun AlterationItem( modifier = Modifier.weight(weight = 1f), verticalArrangement = Arrangement.spacedBy(space = 2.dp), ) { - FlowRow( - horizontalArrangement = Arrangement.spacedBy(space = 4.dp), - ) { - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Bold, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - text = alteration.label, - ) - alteration.original?.let { - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.typography.labelSmall, - fontWeight = FontWeight.Light, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - text = it, - ) - } - } + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + text = alteration.label, + ) alteration.subLabel?.let { Text( style = MaterialTheme.typography.labelSmall, - fontWeight = FontWeight.Normal, + fontWeight = FontWeight.Light, + overflow = TextOverflow.Ellipsis, + maxLines = 1, text = it, ) } } - Switch( enabled = true, checked = alteration.checked, @@ -117,23 +100,17 @@ private fun RollAlterationPreview( private class RollAlterationPreviewProvider : PreviewParameterProvider { override val values: Sequence = sequenceOf( - AlterationItemUio( - label = "Critique", - original = "Critical", - checked = false, - subLabel = null, - ), - AlterationItemUio( - label = "Rage", - original = "Rage", - checked = true, - subLabel = "Barbare", - ), AlterationItemUio( label = "Bénédiction", - original = "Bless", + subLabel = "Bless", + source = "Clerc", checked = false, - subLabel = "Clerc", + ), + AlterationItemUio( + label = "Assistance", + subLabel = "Guidance", + source = "Clerc", + checked = true, ), ) } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt index 687dc1f..9da9667 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationPage.kt @@ -2,14 +2,15 @@ package com.pixelized.rplexicon.ui.screens.character.pages.alteration import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items 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.runtime.rememberCoroutineScope @@ -19,12 +20,18 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.hilt.navigation.compose.hiltViewModel +import com.pixelized.rplexicon.ui.composable.CategoryHeader import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItem import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations import com.pixelized.rplexicon.ui.theme.LexiconTheme import kotlinx.coroutines.launch +@Stable +data class AlterationGroupUio( + val name: String, + val alterations: List, +) @Composable fun AlterationPage( @@ -34,7 +41,7 @@ fun AlterationPage( AlterationPageContent( modifier = Modifier.fillMaxSize(), - alterations = viewModel.alterations, + groups = viewModel.alterations, onAlterationInfo = { viewModel.showAlterationDetail(id = it) }, @@ -51,11 +58,10 @@ fun AlterationPage( ) } -@OptIn(ExperimentalFoundationApi::class) @Composable fun AlterationPageContent( modifier: Modifier = Modifier, - alterations: State>, + groups: State>, onAlterationInfo: (String) -> Unit, onAlterationClick: (String) -> Unit, ) { @@ -63,13 +69,24 @@ fun AlterationPageContent( modifier = modifier, contentPadding = PaddingValues(top = 8.dp, bottom = 16.dp), ) { - items(items = alterations.value) { - AlterationItem( - modifier = Modifier.fillMaxWidth(), - alteration = it, - onInfo = onAlterationInfo, - onClick = onAlterationClick, - ) + groups.value.forEachIndexed { index, group -> + item { + CategoryHeader( + modifier = Modifier + .padding(top = if (index == 0) 0.dp else 16.dp) + .padding(horizontal = 16.dp), + text = group.name, + ) + } + + items(items = group.alterations) { alteration -> + AlterationItem( + modifier = Modifier.fillMaxWidth(), + alteration = alteration, + onInfo = onAlterationInfo, + onClick = onAlterationClick, + ) + } } } } @@ -99,7 +116,7 @@ fun AlterationPagePreview() { LexiconTheme { Surface { AlterationPageContent( - alterations = rememberRollAlterations(), + groups = rememberRollAlterations(), onAlterationInfo = { }, onAlterationClick = { }, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt index 5561dbf..20aaeb8 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationViewModel.kt @@ -10,7 +10,6 @@ import com.pixelized.rplexicon.R import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument -import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory import com.pixelized.rplexicon.utilitary.extentions.context import dagger.hilt.android.lifecycle.HiltViewModel @@ -29,8 +28,8 @@ class AlterationViewModel @Inject constructor( ) : AndroidViewModel(application) { private val character = savedStateHandle.characterSheetArgument.name - private val _alterations = mutableStateOf>(emptyList()) - val alterations: State> get() = _alterations + private val _alterations = mutableStateOf>(emptyList()) + val alterations: State> get() = _alterations private val _alterationDetail = mutableStateOf(null) val alterationDetail: State get() = _alterationDetail @@ -38,11 +37,19 @@ class AlterationViewModel @Inject constructor( init { viewModelScope.launch { launch(Dispatchers.IO) { - alterationRepository.assignedAlterations.collect { - val alterations = it[character] ?: emptyList() - val data = factory.convert(character = character, alterations = alterations) - .sortedBy { alteration -> alteration.label } - .sortedBy { alteration -> alteration.subLabel } + alterationRepository.assignedAlterations.collect { alterationMaps -> + val alterations = alterationMaps[character] ?: emptyList() + val data = alterations + .groupBy { alteration -> alteration.source } + .map { + AlterationGroupUio( + name = it.key, + alterations = factory.convert(character = character, alterations = it.value) + .sortedBy { alteration -> alteration.label } + ) + } + .sortedBy { it.name } + withContext(Dispatchers.Main) { _alterations.value = data } 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 fffafbb..8e3a91c 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 @@ -68,11 +68,12 @@ import com.pixelized.rplexicon.NO_WINDOW_INSETS import com.pixelized.rplexicon.R import com.pixelized.rplexicon.data.model.DiceThrow import com.pixelized.rplexicon.ui.composable.BlurredOverlayHostState +import com.pixelized.rplexicon.ui.composable.CategoryHeader import com.pixelized.rplexicon.ui.composable.ModalNavigationDrawer import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItem -import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetail import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetailUio +import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationGroupUio import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDice import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCard @@ -95,7 +96,7 @@ fun RollOverlay( drawer = drawer, dice = viewModel.dice, card = viewModel.card, - alterations = viewModel.alterations, + groups = viewModel.alterations, showDetail = viewModel.showDetail, onMenu = { scope.launch { drawer.open() } @@ -138,7 +139,7 @@ private fun RollOverlayContent( drawer: DrawerState, dice: State, card: State, - alterations: State>, + groups: State>, showDetail: State, onMenu: () -> Unit, onMenuClose: () -> Unit, @@ -151,7 +152,7 @@ private fun RollOverlayContent( val density = LocalDensity.current val enableDrawer = remember { derivedStateOf { - alterations.value.isNotEmpty() + groups.value.isNotEmpty() } } @@ -189,13 +190,24 @@ private fun RollOverlayContent( .fillMaxWidth(4f / 5f), contentPadding = PaddingValues(vertical = 8.dp), ) { - items(items = alterations.value) { - AlterationItem( - modifier = Modifier.fillMaxWidth(), - alteration = it, - onInfo = onAlterationInfo, - onClick = onAlteration, - ) + groups.value.forEachIndexed { index, group -> + item { + CategoryHeader( + modifier = Modifier + .padding(top = if (index == 0) 0.dp else 16.dp) + .padding(horizontal = 16.dp), + text = group.name, + ) + } + + items(items = group.alterations) { alteration -> + AlterationItem( + modifier = Modifier.fillMaxWidth(), + alteration = alteration, + onInfo = onAlterationInfo, + onClick = onAlteration, + ) + } } } @@ -319,7 +331,7 @@ private fun RollOverlayPreview( drawer = rememberDrawerState(initialValue = preview.drawer), dice = preview.dice, card = preview.card, - alterations = rememberRollAlterations(), + groups = rememberRollAlterations(), showDetail = remember { mutableStateOf(true) }, onMenu = { }, onMenuClose = { }, 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 c30c811..b8b7845 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 @@ -2,6 +2,7 @@ package com.pixelized.rplexicon.ui.screens.rolls import android.app.Application import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope @@ -12,6 +13,7 @@ import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetailUio +import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationGroupUio import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory @@ -37,7 +39,17 @@ class RollOverlayViewModel @Inject constructor( private var rollJob: Job? = null private val _alterations = mutableStateOf>(emptyList()) - val alterations: State> get() = _alterations + val alterations: State> = derivedStateOf { + _alterations.value + .groupBy { it.source } + .map { entry -> + AlterationGroupUio( + name = entry.key, + alterations = entry.value.sortedBy { it.label } + ) + } + .sortedBy { it.name } + } private val _dice = mutableStateOf(null) val dice: State get() = _dice @@ -56,8 +68,6 @@ class RollOverlayViewModel @Inject constructor( _card.value = null _dice.value = diceFactory.convertDiceThrow(diceThrow) _alterations.value = alterationFactory.convertDiceThrow(diceThrow) - .sortedBy { it.label } - .sortedBy { it.subLabel } } fun onAlteration(id: String) { diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/AlterationFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/AlterationFactory.kt index 0e5c1f2..36fee97 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/AlterationFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/factory/AlterationFactory.kt @@ -23,9 +23,9 @@ class AlterationFactory @Inject constructor( val description = descriptionRepository.find(it.name) AlterationItemUio( label = it.name, - original = description?.original, + source = it.source, checked = alterationRepository.getStatus(character, it.name), - subLabel = it.source, + subLabel = description?.original, ) } } @@ -65,44 +65,66 @@ class AlterationFactory @Inject constructor( is DiceThrow.Stealth -> listOf(Property.STEALTH, Property.DEXTERITY) is DiceThrow.Survival -> listOf(Property.SURVIVAL, Property.WISDOM) is DiceThrow.PhysicalMeleeAttack -> { - val action = actionRepository.find(diceThrow.character, action = diceThrow.weapon) + val action = actionRepository.find( + character = diceThrow.character, + action = diceThrow.weapon + ) listOf(Property.PHYSICAL_MELEE_ATTACK) + (action?.hit?.modifier ?: emptyList()) } is DiceThrow.PhysicalMeleeDamage -> { - val action = actionRepository.find(diceThrow.character, action = diceThrow.weapon) + val action = actionRepository.find( + character = diceThrow.character, + action = diceThrow.weapon + ) listOf(Property.PHYSICAL_MELEE_DAMAGE) + (action?.damage?.modifier ?: emptyList()) } is DiceThrow.PhysicalRangeAttack -> { - val action = actionRepository.find(diceThrow.character, action = diceThrow.weapon) + val action = actionRepository.find( + character = diceThrow.character, + action = diceThrow.weapon + ) listOf(Property.PHYSICAL_RANGE_ATTACK) + (action?.hit?.modifier ?: emptyList()) } is DiceThrow.Object -> emptyList() is DiceThrow.PhysicalRangeDamage -> { - val action = actionRepository.find(diceThrow.character, action = diceThrow.weapon) + val action = actionRepository.find( + character = diceThrow.character, + action = diceThrow.weapon + ) listOf(Property.PHYSICAL_RANGE_DAMAGE) + (action?.damage?.modifier ?: emptyList()) } is DiceThrow.SpellAttack -> { - val spell = spellRepository.findAssignedSpell(diceThrow.character, spell = diceThrow.spell) + val spell = spellRepository.findAssignedSpell( + character = diceThrow.character, + spell = diceThrow.spell + ) listOf(Property.SPELL_ATTACK) + (spell?.hit?.modifier ?: emptyList()) } is DiceThrow.SpellDamage -> { - val spell = spellRepository.findAssignedSpell(diceThrow.character, spell = diceThrow.spell) + val spell = spellRepository.findAssignedSpell( + character = diceThrow.character, + spell = diceThrow.spell + ) listOf(Property.SPELL_DAMAGE) + (spell?.effect?.modifier ?: emptyList()) } is DiceThrow.SpellEffect -> { - val spell = spellRepository.findAssignedSpell(diceThrow.character, spell = diceThrow.spell) + val spell = spellRepository.findAssignedSpell( + character = diceThrow.character, + spell = diceThrow.spell + ) spell?.effect?.modifier ?: emptyList() } is DiceThrow.Skill -> { - val skill = skillRepository.find(diceThrow.character, skill = diceThrow.skill) + val skill = + skillRepository.find(character = diceThrow.character, skill = diceThrow.skill) listOf(Property.SKILL) + (skill?.effect?.modifier ?: emptyList()) } } @@ -113,9 +135,9 @@ class AlterationFactory @Inject constructor( val description = descriptionRepository.find(it.name) AlterationItemUio( label = it.name, - original = description?.original, + source = it.source, checked = alterationRepository.getStatus(diceThrow.character, it.name), - subLabel = it.source, + subLabel = description?.original, ) } } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/preview/rememberRollAlterations.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/preview/rememberRollAlterations.kt index 4994a0e..db80bff 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/preview/rememberRollAlterations.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/rolls/preview/rememberRollAlterations.kt @@ -5,35 +5,51 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import com.pixelized.rplexicon.ui.screens.character.composable.actions.AlterationItemUio +import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationGroupUio @Composable @Stable fun rememberRollAlterations() = remember { mutableStateOf( listOf( - AlterationItemUio( - label = "Rage", - original = "Rage", - subLabel = "Barbare", - checked = false, + AlterationGroupUio( + name = "Barbarian", + alterations = listOf( + AlterationItemUio( + label = "Rage", + subLabel = "Rage", + source = "Barbare", + checked = false, + ), + ), ), - AlterationItemUio( - label = "Inspiration bardique", - original = "Bardic inspiration", - subLabel = "Barde", - checked = false + AlterationGroupUio( + name = "Barbarian", + alterations = listOf( + AlterationItemUio( + label = "Inspiration bardique", + subLabel = "Bardic inspiration", + source = "Barde", + checked = false + ), + AlterationItemUio( + label = "Bénédiction", + subLabel = "Bless", + source = "Barde", + checked = false, + ), + ), ), - AlterationItemUio( - label = "Bénédiction", - original = "Bless", - subLabel = "Clerc", - checked = false, - ), - AlterationItemUio( - label = "Cape de protection", - original = "Cape of protection", - subLabel = "Équipement", - checked = true + AlterationGroupUio( + name = "Barbarian", + alterations = listOf( + AlterationItemUio( + label = "Cape de protection", + subLabel = "Cape of protection", + source = "Equipement", + checked = true + ), + ), ), ) )