Add alteration page in the character sheet screen.
This commit is contained in:
parent
be602d5325
commit
e2209bf005
19 changed files with 398 additions and 69 deletions
|
|
@ -2,7 +2,8 @@ package com.pixelized.rplexicon.model
|
|||
|
||||
data class Alteration(
|
||||
val name: String,
|
||||
val target: String?,
|
||||
val source: String,
|
||||
val target: String,
|
||||
val active: Boolean = false,
|
||||
val description: String,
|
||||
val status: Map<Property, Status>,
|
||||
|
|
|
|||
|
|
@ -7,8 +7,9 @@ import com.pixelized.rplexicon.repository.GoogleSheetServiceRepository
|
|||
import com.pixelized.rplexicon.repository.parser.alteration.AlterationParser
|
||||
import com.pixelized.rplexicon.utilitary.Update
|
||||
import com.pixelized.rplexicon.utilitary.exceptions.IncompatibleSheetStructure
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -17,13 +18,15 @@ class AlterationRepository @Inject constructor(
|
|||
private val googleRepository: GoogleSheetServiceRepository,
|
||||
private val alterationParser: AlterationParser,
|
||||
) {
|
||||
private val _status = MutableStateFlow<Map<String, Boolean>>(emptyMap())
|
||||
private val _assignedAlterations = MutableStateFlow<Map<String, List<Alteration>>>(emptyMap())
|
||||
val assignedAlterations: StateFlow<Map<String, List<Alteration>>> get() = _assignedAlterations
|
||||
val assignedAlterations: Flow<Map<String, List<Alteration>>> =
|
||||
combine(_assignedAlterations, _status) { alt, _ -> alt }
|
||||
|
||||
var lastSuccessFullUpdate: Update = Update.INITIAL
|
||||
private set
|
||||
|
||||
fun getAlterations(character: String) : List<Alteration> {
|
||||
fun getAlterations(character: String): List<Alteration> {
|
||||
return _assignedAlterations.value[character] ?: emptyList()
|
||||
}
|
||||
|
||||
|
|
@ -33,6 +36,20 @@ class AlterationRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun getStatus(character: String, alteration: String): Boolean {
|
||||
return _status.value[character + alteration]
|
||||
?: _assignedAlterations.value[character]?.firstOrNull { it.name == alteration }?.active
|
||||
?: false
|
||||
}
|
||||
|
||||
suspend fun setStatus(character: String, alteration: String, value: Boolean?) {
|
||||
_status.emit(if (value != null) {
|
||||
_status.value.toMutableMap().also { it[character + alteration] = value }
|
||||
} else {
|
||||
_status.value.toMutableMap().also { it.remove(character + alteration) }
|
||||
})
|
||||
}
|
||||
|
||||
@Throws(IncompatibleSheetStructure::class, Exception::class)
|
||||
suspend fun fetchAlterationSheet(sheets: List<CharacterSheet>) {
|
||||
googleRepository.fetch { sheet ->
|
||||
|
|
|
|||
|
|
@ -37,14 +37,16 @@ class AlterationParser @Inject constructor(
|
|||
|
||||
row is List<*> -> {
|
||||
// Assume that the name is the first column.
|
||||
val alteration = (row.getOrNull(0) as? String)?.let { name ->
|
||||
val target = row.parseString(TARGET)
|
||||
val description = row.parseString(DESCRIPTION)
|
||||
val name = row.getOrNull(0) as? String
|
||||
val source = row.parseString(SOURCE)
|
||||
val target = row.parseString(TARGET)
|
||||
val alteration = if (name != null && source != null && target != null) {
|
||||
Alteration(
|
||||
name = name,
|
||||
source = source,
|
||||
target = target,
|
||||
active = false,
|
||||
description = description ?: "",
|
||||
description = row.parseString(DESCRIPTION) ?: "",
|
||||
status = properties
|
||||
.mapNotNull { property ->
|
||||
val column = alterationStructure.getValue(property.key)
|
||||
|
|
@ -57,14 +59,15 @@ class AlterationParser @Inject constructor(
|
|||
}
|
||||
.toMap(),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (alteration != null) {
|
||||
sheets
|
||||
.filter { // check if the alteration is applicable to the character
|
||||
alteration.target?.let { target ->
|
||||
alteration.target.let { target ->
|
||||
target == ALL || target == it.characterClass || target == it.race || target == it.name
|
||||
} ?: false
|
||||
}
|
||||
}
|
||||
.forEach { // check the default alteration state for that character
|
||||
val column = charactersStructure.getValue(it.name)
|
||||
|
|
@ -124,8 +127,9 @@ class AlterationParser @Inject constructor(
|
|||
private const val FAIL = "fail"
|
||||
|
||||
private const val TARGET = "Cible"
|
||||
private const val SOURCE = "Source"
|
||||
private const val DESCRIPTION = "Description"
|
||||
private val COLUMNS
|
||||
get() = listOf(TARGET, DESCRIPTION) + Property.values().map { it.key }
|
||||
get() = listOf(SOURCE, TARGET, DESCRIPTION) + Property.values().map { it.key }
|
||||
}
|
||||
}
|
||||
|
|
@ -59,6 +59,9 @@ import com.pixelized.rplexicon.ui.screens.character.pages.actions.ActionPage
|
|||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.ActionPagePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.AttackActionViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SpellsActionViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationPage
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationPagePreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.chooser.SpellLevelChooser
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.chooser.SpellLevelChooserPreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.ProficiencyPage
|
||||
|
|
@ -77,6 +80,7 @@ fun CharacterSheetScreen(
|
|||
proficiencyViewModel: ProficiencyViewModel = hiltViewModel(),
|
||||
attackViewModel: AttackActionViewModel = hiltViewModel(),
|
||||
spellsViewModel: SpellsActionViewModel = hiltViewModel(),
|
||||
alterationsViewModel: AlterationViewModel = hiltViewModel(),
|
||||
) {
|
||||
val screen = LocalScreenNavHost.current
|
||||
val overlay = LocalRollOverlay.current
|
||||
|
|
@ -93,7 +97,8 @@ fun CharacterSheetScreen(
|
|||
val haveSheet = proficiencyViewModel.sheet.value != null
|
||||
val haveAction = attackViewModel.attacks.value.isNotEmpty()
|
||||
val haveSpell = spellsViewModel.spells.value.isNotEmpty()
|
||||
(if (haveSheet) 1 else 0) + (if (haveAction || haveSpell) 1 else 0)
|
||||
val haveAlteration = alterationsViewModel.alterations.value.isNotEmpty()
|
||||
haveSheet.toInt() + (haveAction || haveSpell).toInt() + haveAlteration.toInt()
|
||||
}
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
@ -136,6 +141,11 @@ fun CharacterSheetScreen(
|
|||
spellsViewModel = spellsViewModel,
|
||||
)
|
||||
},
|
||||
alterations = {
|
||||
AlterationPage(
|
||||
viewModel = alterationsViewModel,
|
||||
)
|
||||
},
|
||||
sheet = {
|
||||
SpellLevelChooser(
|
||||
modifier = Modifier.navigationBarsPadding(),
|
||||
|
|
@ -176,6 +186,7 @@ private fun CharacterSheetContent(
|
|||
loader: @Composable BoxScope.() -> Unit,
|
||||
proficiencies: @Composable PagerScope.() -> Unit,
|
||||
actions: @Composable PagerScope.() -> Unit,
|
||||
alterations: @Composable PagerScope.() -> Unit,
|
||||
sheet: @Composable () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
|
|
@ -234,12 +245,13 @@ private fun CharacterSheetContent(
|
|||
.fillMaxWidth()
|
||||
.pullRefresh(refreshState),
|
||||
state = pagerState,
|
||||
beyondBoundsPageCount = 1,
|
||||
beyondBoundsPageCount = 2,
|
||||
verticalAlignment = Alignment.Top,
|
||||
pageContent = { page ->
|
||||
when (page) {
|
||||
0 -> proficiencies()
|
||||
1 -> actions()
|
||||
2 -> alterations()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
@ -264,7 +276,7 @@ private fun CharacterScreenPreview(
|
|||
LexiconTheme {
|
||||
Surface {
|
||||
val sheetState = rememberModalBottomSheetState(
|
||||
initialValue = when (preview == 2) {
|
||||
initialValue = when (preview == 3) {
|
||||
true -> ModalBottomSheetValue.Expanded
|
||||
else -> ModalBottomSheetValue.Hidden
|
||||
},
|
||||
|
|
@ -280,12 +292,15 @@ private fun CharacterScreenPreview(
|
|||
loader = { },
|
||||
proficiencies = { ProficiencyPreview() },
|
||||
actions = { ActionPagePreview() },
|
||||
alterations = { AlterationPagePreview() },
|
||||
sheet = { SpellLevelChooserPreview() },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Boolean.toInt(): Int = if (this) 1 else 0
|
||||
|
||||
private class CharacterScreenPreviewProvider : PreviewParameterProvider<Int> {
|
||||
override val values: Sequence<Int> = sequenceOf(0, 1, 2)
|
||||
override val values: Sequence<Int> = sequenceOf(0, 1, 2, 3)
|
||||
}
|
||||
|
|
@ -4,13 +4,11 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
|||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
||||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.Indication
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
|
@ -9,14 +10,18 @@ import androidx.compose.foundation.layout.sizeIn
|
|||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
|
||||
@Composable
|
||||
fun DiceButton(
|
||||
|
|
@ -46,4 +51,19 @@ fun DiceButton(
|
|||
text = text,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun DiceButtonPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
DiceButton(
|
||||
icon = R.drawable.ic_d20_24,
|
||||
text = "1d20",
|
||||
onClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
|
|
@ -93,11 +94,13 @@ fun SpellHeader(
|
|||
count.max?.let { max ->
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Light,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
text = "/",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Light,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
text = "$max",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.FlowRow
|
|||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
|
|
@ -95,6 +94,7 @@ fun Spell(
|
|||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontWeight = FontWeight.Light,
|
||||
fontStyle = FontStyle.Italic,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
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.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
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.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetail
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetailUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlteration
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
@Composable
|
||||
fun AlterationPage(
|
||||
viewModel: AlterationViewModel = hiltViewModel(),
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
AlterationPageContent(
|
||||
alterations = viewModel.alterations,
|
||||
onInfo = {
|
||||
viewModel.showAlterationDetail(id = it)
|
||||
},
|
||||
onClick = {
|
||||
scope.launch {
|
||||
viewModel.toggle(alteration = it)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
AlterationDetailHandler(
|
||||
detail = viewModel.alterationDetail,
|
||||
onDismissRequest = { viewModel.hideAlterationDetail() },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AlterationPageContent(
|
||||
modifier: Modifier = Modifier,
|
||||
alterations: State<List<RollAlterationUio>>,
|
||||
onInfo: (String) -> Unit,
|
||||
onClick: (String) -> Unit,
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = PaddingValues(vertical = 8.dp),
|
||||
) {
|
||||
items(items = alterations.value) {
|
||||
RollAlteration(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
alteration = it,
|
||||
onInfo = onInfo,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AlterationDetailHandler(
|
||||
detail: State<AlterationDetailUio?>,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
detail.value?.let {
|
||||
Dialog(
|
||||
properties = remember { DialogProperties(usePlatformDefaultWidth = false) },
|
||||
onDismissRequest = onDismissRequest,
|
||||
) {
|
||||
AlterationDetail(
|
||||
detail = it,
|
||||
onClose = onDismissRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
fun AlterationPagePreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
AlterationPageContent(
|
||||
alterations = rememberRollAlterations(),
|
||||
onInfo = { },
|
||||
onClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.pages.alteration
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.rplexicon.repository.data.AlterationRepository
|
||||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.AlterationDetailUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class AlterationViewModel @Inject constructor(
|
||||
private val repository: AlterationRepository,
|
||||
private val factory: AlterationFactory,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
private val character = savedStateHandle.characterSheetArgument.name
|
||||
|
||||
private val _alterations = mutableStateOf<List<RollAlterationUio>>(emptyList())
|
||||
val alterations: State<List<RollAlterationUio>> get() = _alterations
|
||||
|
||||
private val _alterationDetail = mutableStateOf<AlterationDetailUio?>(null)
|
||||
val alterationDetail: State<AlterationDetailUio?> get() = _alterationDetail
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
repository.assignedAlterations.collect {
|
||||
_alterations.value = withContext(Dispatchers.IO) {
|
||||
val alterations = it[character] ?: emptyList()
|
||||
factory.convert(character = character, alterations = alterations)
|
||||
.sortedBy { it.label }
|
||||
.sortedBy { it.subLabel }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun toggle(alteration: String) {
|
||||
val value = repository.getStatus(character = character, alteration = alteration)
|
||||
repository.setStatus(character = character, alteration = alteration, value.not())
|
||||
}
|
||||
|
||||
fun showAlterationDetail(id: String) {
|
||||
val alteration = repository.getAlterations(character = character).firstOrNull { it.name == id }
|
||||
if (alteration != null) {
|
||||
_alterationDetail.value = AlterationDetailUio(
|
||||
name = id,
|
||||
source = alteration.source,
|
||||
target = alteration.target,
|
||||
description = alteration.description
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun hideAlterationDetail() {
|
||||
_alterationDetail.value = null
|
||||
}
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ 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
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio
|
||||
import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -315,20 +316,8 @@ private fun RollOverlayPreview(
|
|||
drawer = rememberDrawerState(initialValue = preview.drawer),
|
||||
dice = preview.dice,
|
||||
card = preview.card,
|
||||
alterations = remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
RollAlterationUio(
|
||||
label = "Critique",
|
||||
haveDescription = true,
|
||||
checked = true
|
||||
),
|
||||
)
|
||||
)
|
||||
},
|
||||
showDetail = remember {
|
||||
mutableStateOf(true)
|
||||
},
|
||||
alterations = rememberRollAlterations(),
|
||||
showDetail = remember { mutableStateOf(true) },
|
||||
onMenu = { },
|
||||
onMenuClose = { },
|
||||
onClose = { },
|
||||
|
|
|
|||
|
|
@ -52,6 +52,8 @@ 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) {
|
||||
|
|
@ -99,6 +101,8 @@ class RollOverlayViewModel @Inject constructor(
|
|||
if (alteration != null) {
|
||||
_alterationDetail.value = AlterationDetailUio(
|
||||
name = id,
|
||||
source = alteration.source,
|
||||
target = alteration.target,
|
||||
description = alteration.description
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,16 +22,21 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexicon
|
||||
|
||||
@Stable
|
||||
data class AlterationDetailUio(
|
||||
val name: String,
|
||||
val source: String,
|
||||
val target: String,
|
||||
val description: String,
|
||||
)
|
||||
|
||||
|
|
@ -49,7 +54,9 @@ fun AlterationDetail(
|
|||
) {
|
||||
Column {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(start = 24.dp),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 24.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.Top,
|
||||
) {
|
||||
|
|
@ -76,15 +83,29 @@ fun AlterationDetail(
|
|||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(top = 8.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(top = 8.dp, bottom = 24.dp),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = detail.description,
|
||||
)
|
||||
.padding(horizontal = 24.dp),
|
||||
) {
|
||||
Text(
|
||||
fontWeight = FontWeight.Light,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
text = stringResource(id = R.string.alteration_source, detail.source),
|
||||
)
|
||||
Text(
|
||||
fontWeight = FontWeight.Light,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
text = stringResource(id = R.string.alteration_target, detail.target),
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 8.dp, bottom = 24.dp),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = detail.description,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,6 +118,8 @@ private fun AlterationDetailPreview() {
|
|||
AlterationDetail(
|
||||
detail = AlterationDetailUio(
|
||||
name = "Rage",
|
||||
source = "Barbare",
|
||||
target = "Barbare",
|
||||
description = "\"En combat, vous vous battez avec une férocité bestiale. Durant votre tour, vous pouvez entrer en rage en utilisant une action bonus. En rage, vous gagnez les bénéfices suivants si vous ne portez pas d'armure lourde :\n" +
|
||||
"\n" +
|
||||
"Vous avez un avantage aux jets de Force et aux jets de sauvegarde de Force.\n" +
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
|||
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.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
|
|
@ -19,6 +21,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
|
|
@ -28,8 +31,8 @@ import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
|||
@Stable
|
||||
data class RollAlterationUio(
|
||||
val label: String,
|
||||
val subLabel: String?,
|
||||
val checked: Boolean,
|
||||
val haveDescription: Boolean,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
@ -40,25 +43,37 @@ fun RollAlteration(
|
|||
onClick: (id: String) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.clickable { onClick(alteration.label) }
|
||||
.padding(horizontal = 16.dp),
|
||||
.heightIn(min = 52.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
.then(other = modifier),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = alteration.label,
|
||||
)
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 2.dp),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = alteration.label,
|
||||
)
|
||||
alteration.subLabel?.let {
|
||||
Text(
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
fontWeight = FontWeight.Light,
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
if (alteration.haveDescription) {
|
||||
IconButton(onClick = { onInfo(alteration.label) }) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Info,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(onClick = { onInfo(alteration.label) }) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Info,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
enabled = true,
|
||||
|
|
@ -89,8 +104,20 @@ private fun RollAlterationPreview(
|
|||
|
||||
private class RollAlterationPreviewProvider : PreviewParameterProvider<RollAlterationUio> {
|
||||
override val values: Sequence<RollAlterationUio> = sequenceOf(
|
||||
RollAlterationUio(label = "Critique", checked = false, haveDescription = false),
|
||||
RollAlterationUio(label = "Rage", checked = true, haveDescription = true),
|
||||
RollAlterationUio(label = "Bénédiction", checked = false, haveDescription = false),
|
||||
RollAlterationUio(
|
||||
label = "Critique",
|
||||
checked = false,
|
||||
subLabel = null,
|
||||
),
|
||||
RollAlterationUio(
|
||||
label = "Rage",
|
||||
checked = true,
|
||||
subLabel = "Barbare",
|
||||
),
|
||||
RollAlterationUio(
|
||||
label = "Bénédiction",
|
||||
checked = false,
|
||||
subLabel = "Clerc",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.pixelized.rplexicon.ui.screens.rolls.factory
|
||||
|
||||
import android.app.Application
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.model.Alteration
|
||||
import com.pixelized.rplexicon.model.DiceThrow
|
||||
import com.pixelized.rplexicon.model.Property
|
||||
import com.pixelized.rplexicon.repository.data.ActionRepository
|
||||
|
|
@ -11,11 +10,20 @@ import com.pixelized.rplexicon.ui.screens.rolls.composable.RollAlterationUio
|
|||
import javax.inject.Inject
|
||||
|
||||
class AlterationFactory @Inject constructor(
|
||||
private val application: Application,
|
||||
private val actionRepository: ActionRepository,
|
||||
private val spellRepository: SpellRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
) {
|
||||
fun convert(character: String, alterations: List<Alteration>): List<RollAlterationUio> {
|
||||
return alterations.map {
|
||||
RollAlterationUio(
|
||||
label = it.name,
|
||||
checked = alterationRepository.getStatus(character, it.name),
|
||||
subLabel = it.source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun convertDiceThrow(diceThrow: DiceThrow): List<RollAlterationUio> {
|
||||
val properties = when (diceThrow) {
|
||||
is DiceThrow.Initiative -> listOf(Property.INITIATIVE, Property.DEXTERITY)
|
||||
|
|
@ -90,8 +98,8 @@ class AlterationFactory @Inject constructor(
|
|||
.map {
|
||||
RollAlterationUio(
|
||||
label = it.name,
|
||||
checked = it.active,
|
||||
haveDescription = true,
|
||||
checked = alterationRepository.getStatus(diceThrow.character, it.name),
|
||||
subLabel = it.source,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package com.pixelized.rplexicon.ui.screens.rolls.preview
|
||||
|
||||
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.rolls.composable.RollAlterationUio
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberRollAlterations() = remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
RollAlterationUio(
|
||||
label = "Rage",
|
||||
subLabel = "Barbare",
|
||||
checked = false,
|
||||
),
|
||||
RollAlterationUio(
|
||||
label = "Inspiration bardique",
|
||||
subLabel = "Barde",
|
||||
checked = false
|
||||
),
|
||||
RollAlterationUio(
|
||||
label = "Bénédiction",
|
||||
subLabel = "Clerc",
|
||||
checked = false,
|
||||
),
|
||||
RollAlterationUio(
|
||||
label = "Cape de protection",
|
||||
subLabel = "Équipement",
|
||||
checked = true
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -152,17 +152,23 @@ private fun SpellDetailContent(
|
|||
fontWeight = FontWeight.Bold,
|
||||
text = stringResource(id = R.string.spell_detail_school),
|
||||
)
|
||||
if (detail.ritual) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = stringResource(id = R.string.spell_detail_ritual),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = stringResource(id = detail.school),
|
||||
)
|
||||
if (detail.ritual) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = "-",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = stringResource(id = R.string.spell_detail_ritual),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
FlowRow(
|
||||
|
|
|
|||
|
|
@ -151,4 +151,7 @@
|
|||
<string name="spell_detail_description">Description</string>
|
||||
<string name="spell_level_chooser_label">Sort de niveau %1$s</string>
|
||||
<string name="spell_level_chooser_available">Disponible : </string>
|
||||
|
||||
<string name="alteration_source">Source : %1$s</string>
|
||||
<string name="alteration_target">Cible : %1$s</string>
|
||||
</resources>
|
||||
|
|
@ -151,4 +151,7 @@
|
|||
<string name="spell_detail_description">Description</string>
|
||||
<string name="spell_level_chooser_label">Spell level %1$s</string>
|
||||
<string name="spell_level_chooser_available">Available: </string>
|
||||
|
||||
<string name="alteration_source">Source: %1$s</string>
|
||||
<string name="alteration_target">Target: %1$s</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue