Update the alteration design.

This commit is contained in:
Thomas Andres Gomez 2023-12-15 10:58:34 +01:00
parent 9cbd33fd2e
commit 00267623ca
7 changed files with 171 additions and 110 deletions

View file

@ -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<AlterationItemUio> {
override val values: Sequence<AlterationItemUio> = 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,
),
)
}

View file

@ -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<AlterationItemUio>,
)
@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<List<AlterationItemUio>>,
groups: State<List<AlterationGroupUio>>,
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 = { },
)

View file

@ -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<List<AlterationItemUio>>(emptyList())
val alterations: State<List<AlterationItemUio>> get() = _alterations
private val _alterations = mutableStateOf<List<AlterationGroupUio>>(emptyList())
val alterations: State<List<AlterationGroupUio>> get() = _alterations
private val _alterationDetail = mutableStateOf<AlterationDetailUio?>(null)
val alterationDetail: State<AlterationDetailUio?> 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
}

View file

@ -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<RollDiceUio?>,
card: State<ThrowsCardUio?>,
alterations: State<List<AlterationItemUio>>,
groups: State<List<AlterationGroupUio>>,
showDetail: State<Boolean>,
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 = { },

View file

@ -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<List<AlterationItemUio>>(emptyList())
val alterations: State<List<AlterationItemUio>> get() = _alterations
val alterations: State<List<AlterationGroupUio>> = 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<RollDiceUio?>(null)
val dice: State<RollDiceUio?> 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) {

View file

@ -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,
)
}
}

View file

@ -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
),
),
),
)
)