diff --git a/app/src/main/java/com/pixelized/rplexicon/data/repository/character/SpellRepository.kt b/app/src/main/java/com/pixelized/rplexicon/data/repository/character/SpellRepository.kt index f8451bd..0d2e2ec 100644 --- a/app/src/main/java/com/pixelized/rplexicon/data/repository/character/SpellRepository.kt +++ b/app/src/main/java/com/pixelized/rplexicon/data/repository/character/SpellRepository.kt @@ -32,6 +32,7 @@ class SpellRepository @Inject constructor( ) { private var _spellsBook = MutableStateFlow>(emptyList()) val spellsBook: StateFlow> get() = _spellsBook + private val _spells = MutableStateFlow>>(emptyMap()) val spells: StateFlow>> = combine(_spells, firebaseRepository.getAlterationStatus()) { spells, status -> diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt index e29f8f3..4f82d7b 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/CharacterSheetScreen.kt @@ -82,8 +82,8 @@ import com.pixelized.rplexicon.ui.screens.character.pages.actions.SpellsViewMode 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.composable.chooser.SpellLevelChooser +import com.pixelized.rplexicon.ui.screens.character.composable.chooser.SpellLevelChooserPreview import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryPage import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryPagePreview import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryViewModel diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellLevelItem.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellLevelItem.kt index 9f1657e..6db86b4 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellLevelItem.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/actions/SpellLevelItem.kt @@ -67,7 +67,7 @@ fun SpellLevelItem( text = stringResource(id = R.string.spell_level_chooser_available) ) Text( - modifier = Modifier.alignByBaseline(), + modifier = Modifier.alignByBaseline().padding(start = 4.dp), style = MaterialTheme.typography.bodySmall, fontWeight = FontWeight.Bold, text = "${spell.remaining ?: 0}", diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/alteration/AlterationDetailHandler.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/alteration/AlterationDetailHandler.kt deleted file mode 100644 index f2e9793..0000000 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/alteration/AlterationDetailHandler.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.pixelized.rplexicon.ui.screens.character.composable.alteration - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.State -import androidx.compose.runtime.remember -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetail -import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetailUio - -@Composable -fun AlterationDetailHandler( - detail: State, - onDismissRequest: () -> Unit, -) { - detail.value?.let { - Dialog( - properties = remember { DialogProperties(usePlatformDefaultWidth = false) }, - onDismissRequest = onDismissRequest, - ) { - AlterationDetail( - detail = it, - onClose = onDismissRequest, - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/chooser/SpellLevelChooser.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/chooser/SpellLevelChooser.kt similarity index 95% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/chooser/SpellLevelChooser.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/chooser/SpellLevelChooser.kt index b7cb56f..f8c1de8 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/chooser/SpellLevelChooser.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/chooser/SpellLevelChooser.kt @@ -1,11 +1,10 @@ -package com.pixelized.rplexicon.ui.screens.character.pages.chooser +package com.pixelized.rplexicon.ui.screens.character.composable.chooser import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material3.Divider import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/AlterationDetailDialog.kt similarity index 57% rename from app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt rename to app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/AlterationDetailDialog.kt index e30d9f7..d6c456b 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/alteration/AlterationDetail.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/AlterationDetailDialog.kt @@ -1,44 +1,47 @@ -package com.pixelized.rplexicon.ui.screens.character.pages.alteration +package com.pixelized.rplexicon.ui.screens.character.composable.dialogs import android.content.res.Configuration.UI_MODE_NIGHT_NO import android.content.res.Configuration.UI_MODE_NIGHT_YES -import androidx.compose.foundation.layout.Arrangement +import android.net.Uri +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CutCornerShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close -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.Stable +import androidx.compose.runtime.State 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.font.FontStyle 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 androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties import com.pixelized.rplexicon.R +import com.pixelized.rplexicon.ui.composable.BackgroundImage import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.utilitary.annotateWithDropCap import com.pixelized.rplexicon.utilitary.extentions.lexicon import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder @Stable -data class AlterationDetailUio( +data class AlterationDialogDetailUio( + val icon: Uri?, val name: String, val original: String?, val source: String, @@ -46,71 +49,81 @@ data class AlterationDetailUio( val description: String, ) -@OptIn(ExperimentalLayoutApi::class) @Composable -fun AlterationDetail( +fun AlterationDetailDialog( + paddingValues: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 128.dp), + dialog: State, + onDismissRequest: () -> Unit, +) { + dialog.value?.let { + Dialog( + properties = remember { DialogProperties(usePlatformDefaultWidth = false) }, + onDismissRequest = onDismissRequest, + ) { + Box( + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onDismissRequest, + ) + .padding(paddingValues = paddingValues), + ) { + AlterationDetailDialogContent( + modifier = Modifier + .clickable( + enabled = false, + onClick = { }, + ) + .ddBorder( + inner = remember { RoundedCornerShape(size = 8.dp) }, + outline = remember { CutCornerShape(size = 16.dp) }, + ), + detail = it, + ) + } + } + } +} + +@Composable +private fun AlterationDetailDialogContent( modifier: Modifier = Modifier, - detail: AlterationDetailUio, - onClose: () -> Unit, + scrollState: ScrollState = rememberScrollState(), + paddingValues: PaddingValues = PaddingValues(horizontal = 24.dp, vertical = 16.dp), + detail: AlterationDialogDetailUio, ) { Surface( - modifier = Modifier - .padding(all = 16.dp) - .ddBorder( - inner = remember { RoundedCornerShape(size = 8.dp) }, - outline = remember { CutCornerShape(size = 16.dp) }, - ) - .then(other = modifier), + modifier = modifier, ) { - Column { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Top, - ) { - FlowRow( - modifier = Modifier.padding(top = 16.dp), - horizontalArrangement = Arrangement.spacedBy(4.dp), - ) { - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.Bold, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - text = annotateWithDropCap( - text = detail.name, - style = MaterialTheme.lexicon.typography.dropCap.titleMedium, - ), - ) - detail.original?.let { - Text( - modifier = Modifier.alignByBaseline(), - fontWeight = FontWeight.Light, - fontStyle = FontStyle.Italic, - style = MaterialTheme.typography.labelSmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - text = it, - ) - } - } - IconButton(onClick = onClose) { - Icon( - imageVector = Icons.Default.Close, - contentDescription = null - ) - } + Box { + detail.icon?.let { uri -> + BackgroundImage( + modifier = Modifier + .size(size = 144.dp) + .align(alignment = Alignment.TopEnd), + model = uri, + ) } - Column( modifier = Modifier - .padding(top = 8.dp) - .verticalScroll(rememberScrollState()) - .padding(horizontal = 24.dp), + .verticalScroll(state = scrollState) + .padding(paddingValues = paddingValues), ) { + Text( + style = MaterialTheme.lexicon.typography.base.headlineSmall, + text = annotateWithDropCap( + text = detail.name, + style = MaterialTheme.lexicon.typography.dropCap.headlineSmall, + ), + ) + Text( + modifier = Modifier.offset(y = -(4.dp)), + style = MaterialTheme.typography.bodyMedium, + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Light, + text = detail.original ?: "", + ) Text( fontWeight = FontWeight.Light, style = MaterialTheme.typography.labelSmall, @@ -122,7 +135,7 @@ fun AlterationDetail( text = stringResource(id = R.string.alteration_target, detail.target), ) Text( - modifier = Modifier.padding(top = 8.dp, bottom = 24.dp), + modifier = Modifier.padding(top = 12.dp), style = MaterialTheme.typography.bodyMedium, text = detail.description, ) @@ -136,8 +149,9 @@ fun AlterationDetail( @Preview(uiMode = UI_MODE_NIGHT_YES) private fun AlterationDetailPreview() { LexiconTheme { - AlterationDetail( - detail = AlterationDetailUio( + AlterationDetailDialogContent( + detail = AlterationDialogDetailUio( + icon = null, name = "Rage", original = "Rage", source = "Barbare", @@ -154,7 +168,6 @@ private fun AlterationDetailPreview() { "Condition \"\"Rage inhibée\"\" :\n" + "Votre rage vous demande des efforts de concentration ou se dissipe. Vous devez réussir un jet de sauvegarde de constitution dont la difficulté augmente à chaque tour (DC 6 + 2 par tour) sous peine de voir votre rage cesser. Sous certaines conditions, la difficulté pourra augmenter ou baisser au-delà des valeurs indiquées.\"" ), - onClose = { }, ) } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/SkillDetailDialog.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/SkillDetailDialog.kt new file mode 100644 index 0000000..175a852 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/SkillDetailDialog.kt @@ -0,0 +1,147 @@ +package com.pixelized.rplexicon.ui.screens.character.composable.dialogs + +import android.content.res.Configuration +import android.net.Uri +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CutCornerShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +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.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +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 com.pixelized.rplexicon.ui.composable.BackgroundImage +import com.pixelized.rplexicon.ui.theme.LexiconTheme +import com.pixelized.rplexicon.utilitary.annotateWithDropCap +import com.pixelized.rplexicon.utilitary.extentions.lexicon +import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder +import com.pixelized.rplexicon.utilitary.extentions.string.skillIcon + +@Stable +data class SkillDialogDetailUio( + val icon: Uri?, + val name: String, + val original: String?, + val description: String, +) + +@Composable +fun SkillDetailDialog( + dialog: State, + paddingValues: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 128.dp), + onDismissRequest: () -> Unit, +) { + dialog.value?.let { + Dialog( + properties = remember { DialogProperties(usePlatformDefaultWidth = false) }, + onDismissRequest = onDismissRequest, + ) { + Box( + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onDismissRequest, + ) + .padding(paddingValues = paddingValues), + ) { + SkillDetailDialogContent( + modifier = Modifier + .clickable( + enabled = false, + onClick = { }, + ) + .ddBorder( + inner = remember { RoundedCornerShape(size = 8.dp) }, + outline = remember { CutCornerShape(size = 16.dp) }, + ), + detail = it, + ) + } + } + } +} + +@Composable +fun SkillDetailDialogContent( + modifier: Modifier = Modifier, + scrollState: ScrollState = rememberScrollState(), + paddingValues: PaddingValues = PaddingValues(vertical = 16.dp, horizontal = 24.dp), + detail: SkillDialogDetailUio, +) { + Surface( + modifier = modifier, + ) { + Box { + detail.icon?.let { uri -> + BackgroundImage( + modifier = Modifier + .size(size = 144.dp) + .align(alignment = Alignment.TopEnd), + model = uri, + ) + } + Column( + modifier = Modifier + .verticalScroll(state = scrollState) + .padding(paddingValues = paddingValues), + ) { + Text( + style = MaterialTheme.lexicon.typography.base.headlineSmall, + text = annotateWithDropCap( + text = detail.name, + style = MaterialTheme.lexicon.typography.dropCap.headlineSmall, + ), + ) + Text( + modifier = Modifier.offset(y = -(4.dp)), + style = MaterialTheme.typography.bodyMedium, + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Light, + text = detail.original ?: "", + ) + Text( + modifier = Modifier.padding(top = 12.dp), + style = MaterialTheme.typography.bodyMedium, + text = detail.description, + ) + } + } + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun AlterationDetailPreview() { + LexiconTheme { + SkillDetailDialogContent( + detail = SkillDialogDetailUio( + icon = "Endurance implacable".skillIcon(), + name = "Endurance implacable", + original = "Relentless Endurance", + description = "Lorsque vous tombez à 0 point de vie, mais que vous n'êtes pas tué sur le coup, vous pouvez passer à 1 point de vie à la place. Vous devez terminer un repos long avant de pouvoir utiliser cette capacité de nouveau." + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/SpellDetailDialog.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/SpellDetailDialog.kt new file mode 100644 index 0000000..e5da0f6 --- /dev/null +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/dialogs/SpellDetailDialog.kt @@ -0,0 +1,271 @@ +package com.pixelized.rplexicon.ui.screens.character.composable.dialogs + +import android.content.res.Configuration +import android.net.Uri +import androidx.annotation.StringRes +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +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.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CutCornerShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +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.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +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 com.pixelized.rplexicon.R +import com.pixelized.rplexicon.ui.composable.BackgroundImage +import com.pixelized.rplexicon.ui.theme.LexiconTheme +import com.pixelized.rplexicon.utilitary.annotateWithDropCap +import com.pixelized.rplexicon.utilitary.extentions.lexicon +import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder + +@Stable +data class SpellDialogDetailUio( + val icon: Uri?, + val name: String, + val translated: String, + val level: String, + @StringRes val school: Int, + val castingTime: String, + val range: String, + val requirement: String, + val duration: String, + val description: String, + val ritual: Boolean, +) + +@Composable +fun SpellDetailDialog( + dialog: State, + paddingValues: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 128.dp), + onDismissRequest: () -> Unit, +) { + dialog.value?.let { + Dialog( + properties = remember { DialogProperties(usePlatformDefaultWidth = false) }, + onDismissRequest = onDismissRequest, + ) { + Box( + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = onDismissRequest, + ) + .padding(paddingValues = paddingValues), + ) { + SpellDetailDialogContent( + modifier = Modifier + .clickable( + enabled = false, + onClick = { }, + ) + .ddBorder( + inner = remember { RoundedCornerShape(size = 8.dp) }, + outline = remember { CutCornerShape(size = 16.dp) }, + ), + detail = it, + ) + } + } + } +} + +@OptIn(ExperimentalLayoutApi::class) +@Composable +private fun SpellDetailDialogContent( + modifier: Modifier = Modifier, + scrollState: ScrollState = rememberScrollState(), + paddingValues: PaddingValues = PaddingValues(vertical = 16.dp, horizontal = 24.dp), + detail: SpellDialogDetailUio, +) { + val typography = MaterialTheme.lexicon.typography + + Surface( + modifier = modifier, + ) { + Box { + detail.icon?.let { uri -> + BackgroundImage( + modifier = Modifier + .size(size = 144.dp) + .align(alignment = Alignment.TopEnd), + model = uri, + ) + } + Column( + modifier = Modifier + .verticalScroll(state = scrollState) + .padding(paddingValues = paddingValues), + ) { + Text( + style = typography.base.headlineSmall, + text = annotateWithDropCap( + text = detail.name, + style = typography.dropCap.headlineSmall, + ), + ) + + Text( + modifier = Modifier.offset(y = -(4.dp)), + style = MaterialTheme.typography.bodyMedium, + fontStyle = FontStyle.Italic, + fontWeight = FontWeight.Light, + text = detail.translated, + ) + + FlowRow( + modifier = Modifier.padding(top = 12.dp), + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + modifier = Modifier.alignByBaseline(), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_school), + ) + 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( + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_level), + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = detail.level, + ) + } + + FlowRow( + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_casting_time), + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = detail.castingTime, + ) + } + FlowRow( + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_range), + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = detail.range, + ) + } + FlowRow( + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_components), + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = detail.requirement, + ) + } + FlowRow( + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_duration), + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = detail.duration, + ) + } + Text( + modifier = Modifier.padding(top = 16.dp), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Bold, + text = stringResource(id = R.string.spell_detail_description), + ) + Text( + style = MaterialTheme.typography.bodyMedium, + text = detail.description, + ) + } + } + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun SpellDetailDialogPreview() { + LexiconTheme { + SpellDetailDialogContent( + detail = SpellDialogDetailUio( + icon = null, + name = "Représailles infernales", + translated = "Hellish Rebuke", + level = "1", + school = R.string.spell_school_evocation, + castingTime = "1 réaction, que vous prenez après avoir subi des dégâts par une créature située à 18 mètres maximum de vous et que vous pouvez voir.", + range = "18 mètres", + requirement = "V, S", + duration = "Instantanée", + description = "Vous pointez votre doigt, et la créature qui vous a infligé des dégâts est momentanément entourée de flammes infernales. La créature doit effectuer un jet de sauvegarde de Dextérité, subissant 2d10 dégâts de fue en cas d'échecn ou la moitié de ces dégâts en cas de réussite.\n\nAux niveaux supérieurs. Lorsque vous lancez ce sort en utilisant un emplacement de sort de niveau 2 ou supérieur, les dégâts sont augmentés de 1d10 pour chaque niveau d'emplacement au-dela du niveau 1.", + ritual = false, + ), + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberSpellLevelChooserState.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberSpellLevelChooserState.kt index f7d331f..1639d49 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberSpellLevelChooserState.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/composable/preview/rememberSpellLevelChooserState.kt @@ -6,7 +6,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import com.pixelized.rplexicon.R import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellLevelUio -import com.pixelized.rplexicon.ui.screens.character.pages.chooser.SpellChooserUio +import com.pixelized.rplexicon.ui.screens.character.composable.chooser.SpellChooserUio @Composable @Stable diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/CharacterSheetHeaderUioFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/CharacterSheetHeaderUioFactory.kt index 50b65d5..af8b1cd 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/CharacterSheetHeaderUioFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/factory/CharacterSheetHeaderUioFactory.kt @@ -30,7 +30,7 @@ class CharacterSheetHeaderUioFactory @Inject constructor( ), armorClass = LabelPointUio( label = R.string.character_sheet_title_ca, - value = sheetHeaderData?.ca?.let { "$it" } ?: " ", + value = sheetHeaderData?.ca?.let { "$it" } ?: "?", max = null, ), hitPoint = LabelPointUio( @@ -80,7 +80,7 @@ class CharacterSheetHeaderUioFactory @Inject constructor( } else -> when { - fireHeaderData?.wildShapeHp == null -> sheetHeaderData?.hpMax?.let { "$it" } ?: "?" + fireHeaderData.wildShapeHp == null -> sheetHeaderData?.hpMax?.let { "$it" } ?: "?" fireHeaderData.extraHp == 0 -> "${fireHeaderData.wildShapeHp}" else -> "${fireHeaderData.wildShapeHp}+${fireHeaderData.extraHp}" } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ActionsPage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ActionsPage.kt index 8d17710..68a70d1 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ActionsPage.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ActionsPage.kt @@ -27,8 +27,6 @@ import com.pixelized.rplexicon.LocalRollOverlay import com.pixelized.rplexicon.R import com.pixelized.rplexicon.ui.composable.edit.HandleSkillEditDialog import com.pixelized.rplexicon.ui.composable.edit.HandleSpellEditDialog -import com.pixelized.rplexicon.ui.navigation.LocalScreenNavHost -import com.pixelized.rplexicon.ui.navigation.screens.navigateToSpellDetail import com.pixelized.rplexicon.ui.screens.character.composable.actions.Attack import com.pixelized.rplexicon.ui.screens.character.composable.actions.AttackUio import com.pixelized.rplexicon.ui.screens.character.composable.actions.GenericHeader @@ -44,6 +42,8 @@ import com.pixelized.rplexicon.ui.screens.character.composable.actions.rememberS import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberAttackListStatePreview import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberObjectListStatePreview import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberSpellListStatePreview +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDetailDialog +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SpellDetailDialog import com.pixelized.rplexicon.ui.theme.LexiconTheme import kotlinx.coroutines.launch @@ -56,7 +56,6 @@ fun ActionPage( spellsViewModel: SpellsViewModel = hiltViewModel(), skillViewModel: SkillsViewModel = hiltViewModel(), ) { - val screen = LocalScreenNavHost.current val overlay = LocalRollOverlay.current val scope = rememberCoroutineScope() @@ -83,7 +82,7 @@ fun ActionPage( } }, onObject = { - skillViewModel.showSkillDetailDialog(item = it.name) + objectsViewModel.showObjectDetailDialog(item = it.name) }, onUseObject = { objectsViewModel.onUse(it.name)?.let { throws -> @@ -103,13 +102,17 @@ fun ActionPage( } }, onSkillInfo = { - skillViewModel.showSkillDetailDialog(item = it.label) + if (spellsViewModel.isSpell(name = it.label)) { + spellsViewModel.showSpellDetailDialog(item = it.label) + } else { + skillViewModel.showSkillDetailDialog(item = it.label) + } }, onSpellLevel = { level: Int, value: Int, max: Int -> spellsViewModel.showSpellEditDialog(level = level, value = value, max = max) }, onSpell = { spell -> - screen.navigateToSpellDetail(spell = spell) + spellsViewModel.showSpellDetailDialog(item = spell) }, onSpellHit = { id -> scope.launch { @@ -142,16 +145,26 @@ fun ActionPage( onConfirm = spellsViewModel::applySpellChange ) + SpellDetailDialog( + dialog = spellsViewModel.spellDetailDialog, + onDismissRequest = spellsViewModel::hideSpellDetailDialog + ) + HandleSkillEditDialog( dialog = skillViewModel.skillEditDialog, onDismissRequest = skillViewModel::hideSkillEditDialog, onConfirm = skillViewModel::applySkillChange ) - HandleSkillDetailDialog( + SkillDetailDialog( dialog = skillViewModel.skillDetailDialog, onDismissRequest = skillViewModel::hideSkillDetailDialog ) + + SkillDetailDialog( + dialog = objectsViewModel.objectDetailDialog, + onDismissRequest = objectsViewModel::hideObjectDetailDialog + ) } @OptIn(ExperimentalFoundationApi::class) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ObjectsViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ObjectsViewModel.kt index e5c360e..0c97093 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ObjectsViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/ObjectsViewModel.kt @@ -10,6 +10,7 @@ import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.ObjectActionRepository import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument import com.pixelized.rplexicon.ui.screens.character.composable.actions.ObjectItemUio +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio import com.pixelized.rplexicon.utilitary.extentions.string.objectIcon import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -28,8 +29,8 @@ class ObjectsViewModel @Inject constructor( private val _objects = mutableStateOf>(emptyList()) val objects: State> get() = _objects - private val _dialog = mutableStateOf(null) - val dialog: State get() = _dialog + private val _objectDetailDialog = mutableStateOf(null) + val objectDetailDialog: State get() = _objectDetailDialog init { viewModelScope.launch(Dispatchers.Default) { @@ -60,4 +61,21 @@ class ObjectsViewModel @Inject constructor( ) } } + + fun showObjectDetailDialog(item: String) { + val description = descriptionRepository.getDescription(name = item) + val item = objectsRepository.find(character = character, item = item) + if (item != null && description != null) { + _objectDetailDialog.value = SkillDialogDetailUio( + icon = item.icon ?: item.name.objectIcon(), + name = item.name, + original = description.original, + description = description.description + ) + } + } + + fun hideObjectDetailDialog() { + _objectDetailDialog.value = null + } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt deleted file mode 100644 index aad1805..0000000 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/actions/SkillDetail.kt +++ /dev/null @@ -1,161 +0,0 @@ -package com.pixelized.rplexicon.ui.screens.character.pages.actions - -import android.content.res.Configuration -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.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.CutCornerShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close -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.Stable -import androidx.compose.runtime.State -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.font.FontStyle -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 androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import com.pixelized.rplexicon.ui.theme.LexiconTheme -import com.pixelized.rplexicon.utilitary.extentions.lexicon -import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder - -@Stable -data class SkillDetailUio( - val name: String, - val original: String?, - val description: String, -) - -@OptIn(ExperimentalLayoutApi::class) -@Composable -fun SkillDetail( - modifier: Modifier = Modifier, - detail: SkillDetailUio, - onClose: () -> Unit, -) { - Surface( - modifier = Modifier - .padding(all = 16.dp) - .ddBorder( - inner = remember { RoundedCornerShape(size = 8.dp) }, - outline = remember { CutCornerShape(size = 16.dp) }, - ) - .then(other = modifier), - ) { - Column { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Top, - ) { - FlowRow( - modifier = Modifier - .padding(top = 16.dp) - .weight(weight = 1f), - horizontalArrangement = Arrangement.spacedBy(4.dp), - ) { - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.typography.titleMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - text = AnnotatedString( - text = detail.name, - spanStyles = listOf( - AnnotatedString.Range( - item = MaterialTheme.lexicon.typography.dropCap.titleMedium, - start = 0, - end = Integer.min(1, detail.name.length), - ) - ) - ), - ) - detail.original?.let { - Text( - modifier = Modifier.alignByBaseline(), - fontWeight = FontWeight.Light, - fontStyle = FontStyle.Italic, - style = MaterialTheme.typography.labelSmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - text = it, - ) - } - } - IconButton(onClick = onClose) { - Icon( - imageVector = Icons.Default.Close, - contentDescription = null - ) - } - } - - Column( - modifier = Modifier - .padding(top = 8.dp) - .verticalScroll(rememberScrollState()) - .padding(horizontal = 24.dp), - ) { - Text( - modifier = Modifier.padding(top = 8.dp, bottom = 24.dp), - style = MaterialTheme.typography.bodyMedium, - text = detail.description, - ) - } - } - } -} - -@Composable -fun HandleSkillDetailDialog( - dialog: State, - onDismissRequest: () -> Unit, -) { - dialog.value?.let { - Dialog( - properties = remember { DialogProperties(usePlatformDefaultWidth = false) }, - onDismissRequest = onDismissRequest, - ) { - SkillDetail( - detail = it, - onClose = onDismissRequest, - ) - } - } -} - -@Composable -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) -private fun AlterationDetailPreview() { - LexiconTheme { - SkillDetail( - detail = SkillDetailUio( - name = "Endurance implacable", - original = "Relentless Endurance", - description = "Lorsque vous tombez à 0 point de vie, mais que vous n'êtes pas tué sur le coup, vous pouvez passer à 1 point de vie à la place. Vous devez terminer un repos long avant de pouvoir utiliser cette capacité de nouveau." - ), - onClose = { }, - ) - } -} \ No newline at end of file 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 5d34ec0..9622cca 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 @@ -18,6 +18,8 @@ import com.pixelized.rplexicon.ui.composable.edit.SkillEditDialogUio import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument import com.pixelized.rplexicon.ui.screens.character.composable.actions.SkillItemUio import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio +import com.pixelized.rplexicon.utilitary.extentions.string.skillIcon import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest @@ -41,8 +43,8 @@ class SkillsViewModel @Inject constructor( private val _skillEditDialog = mutableStateOf(null) val skillEditDialog: State get() = _skillEditDialog - private val _skillDetailDialog = mutableStateOf(null) - val skillDetailDialog: State get() = _skillDetailDialog + private val _skillDetailDialog = mutableStateOf(null) + val skillDetailDialog: State get() = _skillDetailDialog private val _skills = mutableStateOf>(emptyList()) val skills: State> get() = _skills @@ -81,15 +83,16 @@ class SkillsViewModel @Inject constructor( ) fun showSkillDetailDialog(item: String) { - _skillDetailDialog.value = descriptionRepository - .getDescription(name = item) - ?.let { description -> - SkillDetailUio( - name = item, - original = description.original, - description = description.description - ) - } + val description = descriptionRepository.getDescription(name = item) + val skill = skillRepository.find(character = character, skill = item) + if (skill != null && description != null) { + _skillDetailDialog.value = SkillDialogDetailUio( + icon = skill.icon ?: skill.name.skillIcon(), + name = skill.name, + original = description.original, + description = description.description + ) + } } fun hideSkillDetailDialog() { 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 c198d17..2bedeb6 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 @@ -16,19 +16,23 @@ import com.pixelized.rplexicon.data.model.roll.Throw import com.pixelized.rplexicon.data.network.CharacterSheetFire import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository +import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.data.repository.character.SpellRepository import com.pixelized.rplexicon.ui.composable.edit.SpellEditDialogUio import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellHeaderUio import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellLevelUio import com.pixelized.rplexicon.ui.screens.character.composable.actions.SpellUio -import com.pixelized.rplexicon.ui.screens.character.pages.chooser.SpellChooserUio +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SpellDialogDetailUio +import com.pixelized.rplexicon.ui.screens.character.composable.chooser.SpellChooserUio import com.pixelized.rplexicon.utilitary.extentions.icon import com.pixelized.rplexicon.utilitary.extentions.local.firstSpellSlot import com.pixelized.rplexicon.utilitary.extentions.local.highestSpellLevel +import com.pixelized.rplexicon.utilitary.extentions.local.label import com.pixelized.rplexicon.utilitary.extentions.local.spell import com.pixelized.rplexicon.utilitary.extentions.modifier import com.pixelized.rplexicon.utilitary.extentions.signLabel +import com.pixelized.rplexicon.utilitary.extentions.string.spellIcon import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest @@ -44,6 +48,7 @@ class SpellsViewModel @Inject constructor( private val characterRepository: CharacterSheetRepository, private val firebaseRepository: FirebaseRepository, private val spellRepository: SpellRepository, + private val descriptionRepository: DescriptionRepository, application: Application, spellBookUseCase: SpellBookUseCase, savedStateHandle: SavedStateHandle, @@ -52,6 +57,9 @@ class SpellsViewModel @Inject constructor( private var characterFire: CharacterSheetFire? = null private val characterName = savedStateHandle.characterSheetArgument.name + private val _spellDetailDialog = mutableStateOf(null) + val spellDetailDialog: State get() = _spellDetailDialog + private val _editDialog = mutableStateOf(null) val spellEditDialog: State get() = _editDialog @@ -171,6 +179,34 @@ class SpellsViewModel @Inject constructor( hideSpellEditDialog() } + fun isSpell(name: String): Boolean { + return spellRepository.findSpell(name = name) != null + } + + fun showSpellDetailDialog(item: String) { + val description = descriptionRepository.getDescription(name = item) + val spell = spellRepository.findSpell(name = item) + if (spell != null && description != null) { + _spellDetailDialog.value = SpellDialogDetailUio( + icon = spell.icon ?: spell.name.spellIcon(), + name = spell.name, + translated = description.original, + level = "${spell.level}", + school = spell.school.label, + castingTime = spell.castingTime, + range = spell.range, + requirement = spell.requirement, + duration = spell.duration, + description = description.description, + ritual = spell.ritual, + ) + } + } + + fun hideSpellDetailDialog() { + _spellDetailDialog.value = null + } + /** * Helper method to build a readable String from a Throw. * Create a string following the format "amount 'd' faces '+' modifiers + amount * level 'd' faces" 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 485da36..e0a0f15 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 @@ -20,7 +20,7 @@ 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.character.composable.alteration.AlterationDetailHandler +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDetailDialog import com.pixelized.rplexicon.ui.screens.rolls.preview.rememberRollAlterations import com.pixelized.rplexicon.ui.theme.LexiconTheme import kotlinx.coroutines.launch @@ -52,9 +52,9 @@ fun AlterationPage( }, ) - AlterationDetailHandler( - detail = viewModel.alterationDetail, - onDismissRequest = { viewModel.hideAlterationDetail() }, + AlterationDetailDialog( + dialog = viewModel.alterationDetailDialog, + onDismissRequest = viewModel::hideAlterationDetail, ) } 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 263964a..5894242 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 @@ -19,8 +19,10 @@ import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDialogDetailUio import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory import com.pixelized.rplexicon.utilitary.extentions.context +import com.pixelized.rplexicon.utilitary.extentions.string.alterationIcon import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.collectLatest @@ -45,8 +47,8 @@ class AlterationViewModel @Inject constructor( private val _alterations = mutableStateOf>(emptyList()) val alterations: State> get() = _alterations - private val _alterationDetail = mutableStateOf(null) - val alterationDetail: State get() = _alterationDetail + private val _alterationDetailDialog = mutableStateOf(null) + val alterationDetailDialog: State get() = _alterationDetailDialog init { viewModelScope.launch { @@ -114,7 +116,8 @@ class AlterationViewModel @Inject constructor( val description = descriptionRepository.getDescription( name = alteration.name, ) - _alterationDetail.value = AlterationDetailUio( + _alterationDetailDialog.value = AlterationDialogDetailUio( + icon = alteration.icon ?: alteration.name.alterationIcon(), name = id, original = description?.original, source = alteration.source, @@ -126,7 +129,7 @@ class AlterationViewModel @Inject constructor( } fun hideAlterationDetail() { - _alterationDetail.value = null + _alterationDetailDialog.value = null } private data class AlterationStruct( diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt index 271e140..715a87d 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt @@ -27,7 +27,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.actions.Inventory import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberEquipmentState import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberInventoryListState -import com.pixelized.rplexicon.ui.screens.character.pages.actions.HandleSkillDetailDialog +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDetailDialog import com.pixelized.rplexicon.ui.theme.LexiconTheme import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -50,7 +50,7 @@ fun InventoryPage( }, ) - HandleSkillDetailDialog( + SkillDetailDialog( dialog = viewModel.dialog, onDismissRequest = viewModel::hideSkillDetailDialog, ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt index 5dc27e2..1c05d4b 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt @@ -14,8 +14,9 @@ import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio import com.pixelized.rplexicon.ui.screens.character.factory.ItemUioFactory -import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillDetailUio +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio import com.pixelized.rplexicon.utilitary.extentions.context +import com.pixelized.rplexicon.utilitary.extentions.string.equipmentsIcon import com.pixelized.rplexicon.utilitary.extentions.uri import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -42,8 +43,8 @@ class InventoryViewModel @Inject constructor( private val _inventory = mutableStateOf>(emptyList()) val inventory: State> get() = _inventory - private val _dialog = mutableStateOf(null) - val dialog: State get() = _dialog + private val _dialog = mutableStateOf(null) + val dialog: State get() = _dialog private val _snack = MutableSharedFlow() val snack: SharedFlow get() = _snack @@ -86,12 +87,12 @@ class InventoryViewModel @Inject constructor( } } } - + fun showSkillDetailDialog(item: String) { val description = descriptionRepository.getDescription(name = item) - if (description != null) { - _dialog.value = SkillDetailUio( + _dialog.value = SkillDialogDetailUio( + icon = item.equipmentsIcon(), name = item, original = description.original, description = description.description diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyPage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyPage.kt index ea0292e..a58aedc 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyPage.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyPage.kt @@ -53,7 +53,7 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.Profici import com.pixelized.rplexicon.ui.screens.character.composable.character.Stat import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberCharacterSheetStatePreview -import com.pixelized.rplexicon.ui.screens.character.pages.actions.HandleSkillDetailDialog +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDetailDialog import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.utilitary.extentions.modifier.ddBorder import kotlinx.coroutines.launch @@ -113,7 +113,7 @@ fun ProficiencyPage( onConfirm = viewModel::applySkillChange ) - HandleSkillDetailDialog( + SkillDetailDialog( dialog = viewModel.skillDetailDialog, onDismissRequest = viewModel::hideSkillDetailDialog ) diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyViewModel.kt index e8f0277..18d2a22 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/proficiency/ProficiencyViewModel.kt @@ -24,8 +24,9 @@ import com.pixelized.rplexicon.ui.screens.character.composable.character.Profici import com.pixelized.rplexicon.ui.screens.character.composable.character.StatUio import com.pixelized.rplexicon.ui.screens.character.factory.CharacterSheetUioFactory import com.pixelized.rplexicon.ui.screens.character.factory.SkillFactoryUioFactory -import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillDetailUio +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.SkillDialogDetailUio import com.pixelized.rplexicon.utilitary.extentions.local.toStatus +import com.pixelized.rplexicon.utilitary.extentions.string.skillIcon import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine @@ -53,8 +54,8 @@ class ProficiencyViewModel @Inject constructor( private val _skillEditDialog = mutableStateOf(null) val skillEditDialog: State get() = _skillEditDialog - private val _skillDetailDialog = mutableStateOf(null) - val skillDetailDialog: State get() = _skillDetailDialog + private val _skillDetailDialog = mutableStateOf(null) + val skillDetailDialog: State get() = _skillDetailDialog private val _skills = mutableStateOf>(emptyList()) val skills: State> get() = _skills @@ -154,15 +155,16 @@ class ProficiencyViewModel @Inject constructor( ) fun showSkillDetailDialog(item: String) { - _skillDetailDialog.value = descriptionRepository - .getDescription(name = item) - ?.let { description -> - SkillDetailUio( - name = item, - original = description.original, - description = description.description - ) - } + val description = descriptionRepository.getDescription(name = item) + val skill = skillRepository.find(character = character, skill = item) + if (skill != null && description != null) { + _skillDetailDialog.value = SkillDialogDetailUio( + icon = skill.icon ?: skill.name.skillIcon(), + name = skill.name, + original = description.original, + description = description.description + ) + } } fun hideSkillDetailDialog() { 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 501e16a..d334a3b 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 @@ -66,8 +66,6 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.LayoutDirection 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.LocalRollOverlay import com.pixelized.rplexicon.NO_WINDOW_INSETS @@ -77,9 +75,8 @@ 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.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.character.composable.dialogs.AlterationDetailDialog 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 @@ -136,9 +133,9 @@ fun RollOverlay( onBack = { scope.launch { drawer.close() } }, ) - AlterationDetailHandler( - detail = viewModel.alterationDetail, - onDismissRequest = { viewModel.hideAlterationDetail() }, + AlterationDetailDialog( + dialog = viewModel.alterationDetailDialog, + onDismissRequest = viewModel::hideAlterationDetail, ) } @@ -344,24 +341,6 @@ private fun Modifier.detailPaddingBottom( this.then(other = Modifier.padding(bottom = padding)) } -@Composable -private fun AlterationDetailHandler( - detail: State, - 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) 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 d4677e6..32551fe 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 @@ -20,14 +20,15 @@ import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.CharacterSheetRepository 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.character.composable.dialogs.AlterationDialogDetailUio import com.pixelized.rplexicon.ui.screens.rolls.composable.RollDiceUio import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowCardFactory import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio import com.pixelized.rplexicon.ui.screens.rolls.factory.AlterationFactory import com.pixelized.rplexicon.ui.screens.rolls.factory.DiceFactory import com.pixelized.rplexicon.utilitary.extentions.context +import com.pixelized.rplexicon.utilitary.extentions.string.alterationIcon import com.pixelized.rplexicon.utilitary.extentions.switch import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers @@ -85,8 +86,8 @@ class RollOverlayViewModel @Inject constructor( private val _isThrowHidden = mutableStateOf(false) val isThrowHidden: State get() = _isThrowHidden - private val _alterationDetail = mutableStateOf(null) - val alterationDetail: State get() = _alterationDetail + private val _alterationDetailDialog = mutableStateOf(null) + val alterationDetailDialog: State get() = _alterationDetailDialog suspend fun prepareRoll(diceThrow: DiceThrow) { this.diceThrow = diceThrow @@ -190,7 +191,8 @@ class RollOverlayViewModel @Inject constructor( name = alteration?.name, ) if (alteration != null) { - _alterationDetail.value = AlterationDetailUio( + _alterationDetailDialog.value = AlterationDialogDetailUio( + icon = alteration.icon ?: alteration.name.alterationIcon(), name = id, original = description?.original, source = alteration.source, @@ -202,7 +204,7 @@ class RollOverlayViewModel @Inject constructor( } fun hideAlterationDetail() { - _alterationDetail.value = null + _alterationDetailDialog.value = null } private data class AlterationStruct( 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 c97fd48..27c9ce2 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 @@ -44,7 +44,7 @@ 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.character.composable.alteration.AlterationDetailHandler +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDetailDialog import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCard import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio import com.pixelized.rplexicon.ui.screens.summary.pages.statistic.StatisticSummary @@ -124,8 +124,8 @@ fun SummaryScreen( onDetail = { statisticsViewModel.hideDetail() }, ) - AlterationDetailHandler( - detail = statisticsViewModel.alterationDetail, + AlterationDetailDialog( + dialog = statisticsViewModel.alterationDetailDialog, onDismissRequest = { statisticsViewModel.hideAlterationDetail() }, ) } diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt index 365fa69..05a26c2 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/summary/pages/statistic/StatisticViewModel.kt @@ -9,11 +9,12 @@ import com.pixelized.rplexicon.R import com.pixelized.rplexicon.data.repository.authentication.FirebaseRepository import com.pixelized.rplexicon.data.repository.character.AlterationRepository import com.pixelized.rplexicon.data.repository.character.DescriptionRepository -import com.pixelized.rplexicon.ui.screens.character.pages.alteration.AlterationDetailUio +import com.pixelized.rplexicon.ui.screens.character.composable.dialogs.AlterationDialogDetailUio import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowCardFactory import com.pixelized.rplexicon.ui.screens.rolls.composable.ThrowsCardUio import com.pixelized.rplexicon.ui.screens.summary.composable.ClassHeaderSummaryUio import com.pixelized.rplexicon.utilitary.extentions.context +import com.pixelized.rplexicon.utilitary.extentions.string.alterationIcon import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -38,8 +39,8 @@ class StatisticViewModel @Inject constructor( private val _detail = mutableStateOf(null) val detail: State get() = _detail - private val _alterationDetail = mutableStateOf(null) - val alterationDetail: State get() = _alterationDetail + private val _alterationDetailDialog = mutableStateOf(null) + val alterationDetailDialog: State get() = _alterationDetailDialog fun showDetail(dice: ClassHeaderSummaryUio.Dice) { detailJob?.cancel() @@ -70,7 +71,8 @@ class StatisticViewModel @Inject constructor( val description = descriptionRepository.getDescription(name = alteration?.name) if (alteration != null) { - _alterationDetail.value = AlterationDetailUio( + _alterationDetailDialog.value = AlterationDialogDetailUio( + icon = alteration.icon ?: alteration.name.alterationIcon(), name = name, original = description?.original, source = alteration.source, @@ -82,6 +84,6 @@ class StatisticViewModel @Inject constructor( } fun hideAlterationDetail() { - _alterationDetail.value = null + _alterationDetailDialog.value = null } } \ No newline at end of file diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/string/StringEx+Icon.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/string/StringEx+Icon.kt index 62b2266..45f7559 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/string/StringEx+Icon.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/extentions/string/StringEx+Icon.kt @@ -12,6 +12,10 @@ fun String.objectIcon(): Uri? { return ResourcesCache.objects[this]?.uri?.toUriOrNull() } +fun String.equipmentsIcon(): Uri? { + return ResourcesCache.equipments[this]?.uri?.toUriOrNull() +} + fun String.alterationIcon(): Uri? { return ResourcesCache.alterations[this]?.uri?.toUriOrNull() } @@ -112,6 +116,15 @@ private object ResourcesCache { "Baies nourricières" to R.drawable.icbg_food_goodberry_unfaded, ) + val equipments = hashMapOf( + "Dague" to R.drawable.icbg_dagger_unfaded, + "Hache de guerre en argent" to R.drawable.icbg_battleaxe_plus_one_unfaded, + "Bouclier" to R.drawable.icbg_studded_shield_unfaded, + "Cape de protection" to R.drawable.icbg_cloak_of_protection_unfaded, + "Armure d'écailles" to R.drawable.icbg_scale_mail_unfaded, + "Armure de cuir" to R.drawable.icbg_leather_armour_rogue_unfaded, + ) + val skills = hashMapOf( "Dé de vie (Barbare)" to R.drawable.icbg_bolstering_magic_boon, "Dé de vie (Guerrier)" to R.drawable.icbg_bolstering_magic_boon,