diff --git a/build.gradle.kts b/build.gradle.kts
index 7d61caf..eb8e169 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,7 +1,9 @@
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
+ alias(libs.plugins.kotlinMultiplatform) apply false
+ alias(libs.plugins.kotlinSerialization) apply false
+ // alias(libs.plugins.kotlinKtor) apply false
alias(libs.plugins.composeMultiplatform) apply false
alias(libs.plugins.composeCompiler) apply false
- alias(libs.plugins.kotlinMultiplatform) apply false
}
\ No newline at end of file
diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
index 359eca4..3f09148 100644
--- a/composeApp/build.gradle.kts
+++ b/composeApp/build.gradle.kts
@@ -3,10 +3,9 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.kotlinSerialization)
+ // alias(libs.plugins.kotlinKtor)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
-// kotlin("jvm") version "1.9.20"
-// alias(libs.plugins.kotlinKtor)
}
kotlin {
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 1407017..99445d2 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -1,14 +1,21 @@
Créer une feuille de personnage
- Configuration réseau
- Consulter l'historique des lancés
+ Configuration de la table
+ Consulter l'historique des lancers
+ Jet de :
+ Réussite si lancer inférieur ou égale à : %1$s
Réussite critique
Réussite spéciale
Réussite
Échec
Échec critique
+ Dégré de difficulté :
+ Facile
+ Normal
+ Difficile
+ Impossible
Création de personnage
Nom
@@ -68,7 +75,7 @@
Occupations
Compétences magiques
- Configuration réseau
+ Configuration de la table
Nom du joueur
host
port
@@ -83,5 +90,7 @@
Client
Aucun
- Historique des lancés
+ Historique des lancers
+ lance
+ Difficulté
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
index 8d33b3c..650c8d0 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
@@ -168,7 +168,10 @@ fun HandleCharacterSheetCreation(
title = stringResource(Res.string.character_sheet_edit__title),
) {
CharacterSheetMainNavHost(
- startDestination = CharacterSheetEditDestination.navigationRoute(id = null)
+ startDestination = CharacterSheetEditDestination.navigationRoute(
+ id = null,
+ enableBack = false,
+ )
)
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/navigation/destination/CharacterSheetEditDestination.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/navigation/destination/CharacterSheetEditDestination.kt
index fe069af..2429a1f 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/navigation/destination/CharacterSheetEditDestination.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/navigation/destination/CharacterSheetEditDestination.kt
@@ -3,6 +3,7 @@ package com.pixelized.desktop.lwa.navigation.destination
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
+import androidx.navigation.NavType
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditPage
@@ -11,22 +12,33 @@ import com.pixelized.desktop.lwa.utils.extention.ARG
object CharacterSheetEditDestination {
private const val ROUTE = "character.sheet.edit"
private const val CHARACTER_ID = "id"
+ private const val ENABLE_BACK = "enable_back"
- fun baseRoute() = "$ROUTE?${CHARACTER_ID.ARG}"
+ fun baseRoute() = "$ROUTE?${CHARACTER_ID.ARG}&${ENABLE_BACK.ARG}"
- fun navigationRoute(id: String?) = "$ROUTE?$CHARACTER_ID=$id"
+ fun navigationRoute(id: String?, enableBack: Boolean) = ROUTE +
+ "?$CHARACTER_ID=$id" +
+ "&$ENABLE_BACK=$enableBack"
fun arguments() = listOf(
navArgument(CHARACTER_ID) {
nullable = true
+ type = NavType.StringType
+ },
+ navArgument(ENABLE_BACK) {
+ nullable = false
+ type = NavType.BoolType
}
)
data class Argument(
val id: String?,
+ val enableBack: Boolean,
) {
constructor(savedStateHandle: SavedStateHandle) : this(
- id = savedStateHandle.get(CHARACTER_ID)
+ id = savedStateHandle.get(CHARACTER_ID),
+ enableBack = savedStateHandle.get(ENABLE_BACK)
+ ?: error("Missing enableBack argument"),
)
}
}
@@ -42,7 +54,8 @@ fun NavGraphBuilder.composableCharacterSheetEditPage() {
fun NavHostController.navigateToCharacterSheetEdit(
id: String? = null,
+ enableBack: Boolean = true,
) {
- val route = CharacterSheetEditDestination.navigationRoute(id = id)
+ val route = CharacterSheetEditDestination.navigationRoute(id = id, enableBack = enableBack)
navigate(route = route)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/NetworkRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/NetworkRepository.kt
index 021d093..011b704 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/NetworkRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/NetworkRepository.kt
@@ -27,6 +27,9 @@ typealias Server = EmbeddedServer Unit
): EmbeddedServer {
return embeddedServer(
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/protocol/RollMessage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/protocol/RollMessage.kt
index 1893b26..fddf0a8 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/protocol/RollMessage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/network/protocol/RollMessage.kt
@@ -4,6 +4,9 @@ import kotlinx.serialization.Serializable
@Serializable
data class RollMessage(
- val label: String,
- val roll: Int,
-): MessageContent
\ No newline at end of file
+ val skillLabel: String,
+ val resultLabel: String?,
+ val rollDifficulty: String?,
+ val rollValue: Int,
+ val rollSuccessLimit: Int?,
+) : MessageContent
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/roll/RollHistoryRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/roll/RollHistoryRepository.kt
index 50557b2..bd7d474 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/roll/RollHistoryRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/roll/RollHistoryRepository.kt
@@ -31,11 +31,20 @@ object RollHistoryRepository {
}
suspend fun share(
- label: String,
- roll: Int,
+ skillLabel: String,
+ rollDifficulty: String?,
+ rollValue: Int,
+ resultLabel: String?,
+ rollSuccessLimit: Int?,
) {
network.share(
- content = RollMessage(label = label, roll = roll)
+ content = RollMessage(
+ skillLabel = skillLabel,
+ rollDifficulty = rollDifficulty,
+ rollValue = rollValue,
+ resultLabel = resultLabel,
+ rollSuccessLimit = rollSuccessLimit,
+ )
)
}
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt
index f371989..5c1acdb 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt
@@ -113,11 +113,11 @@ fun CharacterSheetPage(
CharacterSheetPageContent(
modifier = Modifier.fillMaxSize(),
characterSheet = sheet,
- onBack = {
- screen.popBackStack()
- },
onEdit = {
- screen.navigateToCharacterSheetEdit(id = sheet.id)
+ screen.navigateToCharacterSheetEdit(
+ id = sheet.id,
+ enableBack = true,
+ )
},
onDelete = {
scope.launch {
@@ -154,7 +154,6 @@ fun CharacterSheetPageContent(
modifier: Modifier = Modifier,
scrollState: ScrollState = rememberScrollState(),
characterSheet: CharacterSheetPageUio,
- onBack: () -> Unit,
onEdit: () -> Unit,
onDelete: () -> Unit,
onCharacteristic: (characteristic: CharacterSheetPageUio.Characteristic) -> Unit,
@@ -178,6 +177,7 @@ fun CharacterSheetPageContent(
) {
Icon(
imageVector = Icons.Default.Edit,
+ tint = MaterialTheme.colors.primary,
contentDescription = null,
)
}
@@ -186,6 +186,7 @@ fun CharacterSheetPageContent(
) {
Icon(
imageVector = Icons.Default.Delete,
+ tint = MaterialTheme.colors.primary,
contentDescription = null,
)
}
@@ -346,9 +347,10 @@ private fun Stat(
)
Text(
modifier = Modifier.align(alignment = Alignment.Center),
- style = MaterialTheme.typography.h4,
+ style = MaterialTheme.typography.h3,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
+ color = MaterialTheme.colors.primary,
text = characteristic.value
)
}
@@ -402,6 +404,7 @@ private fun Roll(
)
Icon(
painter = painterResource(Res.drawable.ic_d20_32dp),
+ tint = MaterialTheme.colors.primary,
contentDescription = null,
)
}
@@ -433,6 +436,7 @@ private fun Skill(
Text(
style = MaterialTheme.typography.body1,
fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colors.primary,
text = "$value",
)
Checkbox(modifier = Modifier.size(size = 32.dp), checked = false, onCheckedChange = { })
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt
index 94d0845..2f66917 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt
@@ -22,6 +22,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
+import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -85,7 +86,13 @@ fun CharacterSheetEditPage(
) {
CharacterSheetEdit(
form = viewModel.characterSheet.value,
- onBack = { screen.popBackStack() },
+ onBack = remember {
+ if (viewModel.enableBack) {
+ { screen.popBackStack() }
+ } else {
+ null
+ }
+ },
onNewSkill = viewModel::onSkill,
onNewCategory = viewModel::onNewRoll,
onSave = {
@@ -103,7 +110,7 @@ fun CharacterSheetEditPage(
@Composable
fun CharacterSheetEdit(
form: CharacterSheetEditPageUio,
- onBack: () -> Unit,
+ onBack: (() -> Unit)?,
onNewSkill: (CharacterSheetEditPageUio.SkillGroup) -> Unit,
onNewCategory: () -> Unit,
onSave: () -> Unit,
@@ -118,14 +125,16 @@ fun CharacterSheetEdit(
text = stringResource(Res.string.character_sheet_edit__title),
)
},
- navigationIcon = {
- IconButton(
- onClick = onBack,
- ) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowBack,
- contentDescription = null,
- )
+ navigationIcon = onBack?.let { action: () -> Unit ->
+ {
+ IconButton(
+ onClick = action,
+ ) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = null,
+ )
+ }
}
}
)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditViewModel.kt
index 823f529..ff01c8f 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditViewModel.kt
@@ -18,6 +18,8 @@ class CharacterSheetEditViewModel(
private val repository = CharacterSheetRepository
private val factory = CharacterSheetEditFactory()
+ val enableBack = argument.enableBack
+
private val _characterSheet = mutableStateOf(
repository.characterSheetFlow(id = argument.id).value.let {
runBlocking { factory.convertToUio(it) }
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/network/NetworkViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/network/NetworkViewModel.kt
index 1ce3c31..c1b45d8 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/network/NetworkViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/network/NetworkViewModel.kt
@@ -14,8 +14,9 @@ class NetworkViewModel : ViewModel() {
private val repository = NetworkRepository
private val factory = NetworkFactory()
- private val host = mutableStateOf("localhost")
- private val port = mutableStateOf(27030)
+ private val host = mutableStateOf(NetworkRepository.DEFAULT_HOST)
+ private val port = mutableStateOf(NetworkRepository.DEFAULT_PORT)
+
val network: State
@Composable
@Stable
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollPage.kt
index 189e2de..a9a14d7 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollPage.kt
@@ -1,6 +1,7 @@
package com.pixelized.desktop.lwa.screen.roll
import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
@@ -11,15 +12,22 @@ 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.PaddingValues
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.DropdownMenuItem
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.ExposedDropdownMenuBox
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
@@ -34,13 +42,23 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.pixelized.desktop.lwa.screen.roll.DifficultyUio.Difficulty
+import com.pixelized.desktop.lwa.utils.DisableInteractionSource
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.ic_d20_32dp
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_easy__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_hard__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_impossible__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_normal__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__roll__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__roll__success_label
import org.jetbrains.compose.resources.painterResource
+import org.jetbrains.compose.resources.stringResource
@Stable
-data class RollUio(
+data class RollTitleUio(
val label: String,
val value: Int?,
)
@@ -51,6 +69,16 @@ data class RollResultUio(
val value: Int,
)
+@Stable
+data class DifficultyUio(
+ val open: Boolean,
+ val difficulty: Difficulty,
+) {
+ enum class Difficulty {
+ EASY, NORMAL, HARD, IMPOSSIBLE
+ }
+}
+
@Composable
fun RollPage(
viewModel: RollViewModel = viewModel { RollViewModel() },
@@ -72,24 +100,24 @@ fun RollPage(
style = MaterialTheme.typography.caption,
textAlign = TextAlign.Center,
overflow = TextOverflow.Ellipsis,
- text = "Jet de :",
+ text = stringResource(Res.string.roll_page__roll__label),
)
Text(
style = MaterialTheme.typography.h5,
textAlign = TextAlign.Center,
overflow = TextOverflow.Ellipsis,
- text = viewModel.roll.value.label,
+ text = viewModel.rollTitle.value.label,
)
- viewModel.roll.value.value?.let {
+ viewModel.rollTitle.value.value?.let {
Text(
style = MaterialTheme.typography.caption,
textAlign = TextAlign.Center,
overflow = TextOverflow.Ellipsis,
- text = "Réussite en dessous de : ${it}",
+ text = stringResource(Res.string.roll_page__roll__success_label, it),
)
}
Column(
- modifier = Modifier.fillMaxSize(),
+ modifier = Modifier.weight(weight = 1f),
verticalArrangement = Arrangement.spacedBy(
space = 24.dp,
alignment = Alignment.CenterVertically,
@@ -114,7 +142,7 @@ fun RollPage(
contentDescription = null,
)
AnimatedContent(
- targetState = viewModel.result.value?.value?.toString() ?: "",
+ targetState = viewModel.rollResult.value?.value?.toString() ?: "",
transitionSpec = {
val enter = fadeIn() + slideInVertically { 32 }
val exit = fadeOut() + slideOutVertically { -32 }
@@ -137,7 +165,7 @@ fun RollPage(
}
}
AnimatedContent(
- targetState = viewModel.result.value?.label ?: "",
+ targetState = viewModel.rollResult.value?.label ?: "",
transitionSpec = { fadeIn() togetherWith fadeOut() },
) { value ->
Text(
@@ -148,5 +176,118 @@ fun RollPage(
)
}
}
+ viewModel.rollDifficulty.value?.let {
+ Box(
+ modifier = Modifier.clickable(
+ interactionSource = remember { DisableInteractionSource() },
+ indication = null,
+ onClick = {},
+ )
+ ) {
+ Difficulty(
+ difficulty = it,
+ onToggle = { viewModel.toggleDifficulty() },
+ onDifficulty = { viewModel.onDifficulty(it) }
+ )
+ }
+ }
}
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun Difficulty(
+ modifier: Modifier = Modifier,
+ difficulty: DifficultyUio,
+ onToggle: () -> Unit,
+ onDifficulty: (Difficulty) -> Unit
+) {
+ ExposedDropdownMenuBox(
+ modifier = modifier,
+ expanded = difficulty.open,
+ onExpandedChange = { onToggle() },
+ ) {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Row(
+ modifier = Modifier.padding(
+ horizontal = 16.dp,
+ vertical = 8.dp,
+ ),
+ horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
+ ) {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.body1,
+ text = stringResource(Res.string.roll_page__dc__label)
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.body1,
+ color = MaterialTheme.colors.primary,
+ text = when (difficulty.difficulty) {
+ Difficulty.EASY -> stringResource(Res.string.roll_page__dc_easy__label)
+ Difficulty.NORMAL -> stringResource(Res.string.roll_page__dc_normal__label)
+ Difficulty.HARD -> stringResource(Res.string.roll_page__dc_hard__label)
+ Difficulty.IMPOSSIBLE -> stringResource(Res.string.roll_page__dc_impossible__label)
+ }
+ )
+ }
+ val rotation = animateFloatAsState(
+ targetValue = if (difficulty.open) -180f else 0f,
+ )
+ Icon(
+ modifier = Modifier.graphicsLayer {
+ rotationZ = rotation.value
+ },
+ imageVector = Icons.Default.ArrowDropDown,
+ contentDescription = null
+ )
+ }
+
+ ExposedDropdownMenu(
+ expanded = difficulty.open,
+ onDismissRequest = { onToggle() }
+ ) {
+ DifficultyDropDownItem(
+ label = stringResource(Res.string.roll_page__dc_easy__label),
+ onClick = { onDifficulty(Difficulty.EASY) },
+ )
+ DifficultyDropDownItem(
+ label = stringResource(Res.string.roll_page__dc_normal__label),
+ onClick = { onDifficulty(Difficulty.NORMAL) },
+ )
+ DifficultyDropDownItem(
+ label = stringResource(Res.string.roll_page__dc_hard__label),
+ onClick = { onDifficulty(Difficulty.HARD) },
+ )
+ DifficultyDropDownItem(
+ label = stringResource(Res.string.roll_page__dc_impossible__label),
+ onClick = { onDifficulty(Difficulty.IMPOSSIBLE) },
+ )
+ }
+ }
+}
+
+@Composable
+private fun DifficultyDropDownItem(
+ modifier: Modifier = Modifier,
+ contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp),
+ label: String,
+ onClick: () -> Unit,
+) {
+ DropdownMenuItem(
+ modifier = modifier,
+ onClick = onClick,
+ enabled = true,
+ contentPadding = contentPadding,
+ interactionSource = remember { MutableInteractionSource() },
+ content = {
+ Text(
+ color = MaterialTheme.colors.primary,
+ text = label,
+ )
+ },
+ )
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt
index 20bfb00..843d64a 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/roll/RollViewModel.kt
@@ -12,6 +12,7 @@ import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio
+import com.pixelized.desktop.lwa.screen.roll.DifficultyUio.Difficulty
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
@@ -20,6 +21,10 @@ import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.roll_page__critical_failure
import lwacharactersheet.composeapp.generated.resources.roll_page__critical_success
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_easy__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_hard__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_impossible__label
+import lwacharactersheet.composeapp.generated.resources.roll_page__dc_normal__label
import lwacharactersheet.composeapp.generated.resources.roll_page__failure
import lwacharactersheet.composeapp.generated.resources.roll_page__special_success
import lwacharactersheet.composeapp.generated.resources.roll_page__success
@@ -28,30 +33,32 @@ import org.jetbrains.compose.resources.getString
class RollViewModel : ViewModel() {
private val repository = RollHistoryRepository
- private val _roll = mutableStateOf(RollUio(label = "", value = 0))
- val roll: State get() = _roll
+ private lateinit var sheet: CharacterSheet
+ private lateinit var rollAction: String
+ private var rollSuccessValue: Int? = null
private var rollJob: Job? = null
- private var rollStep: SkillStepUseCase.SkillStep? = null
- private lateinit var rollAction: String
- private lateinit var sheet: CharacterSheet
+
+ private val _rollTitle = mutableStateOf(RollTitleUio(label = "", value = 0))
+ val rollTitle: State get() = _rollTitle
+
+ private val _rollResult = mutableStateOf(null)
+ val rollResult: State get() = _rollResult
+
val rollRotation = Animatable(0f)
- private val _result = mutableStateOf(null)
- val result: State get() = _result
+ private val _rollDifficulty = mutableStateOf(null)
+ val rollDifficulty: State get() = _rollDifficulty
fun prepareRoll(
sheet: CharacterSheetPageUio,
characteristic: CharacterSheetPageUio.Characteristic,
) {
- val step = SkillStepUseCase.computeSkillStep(
- skill = (characteristic.value.toIntOrNull() ?: 0) * 5
- )
prepareRoll(
+ sheet = sheet,
label = characteristic.label,
rollAction = "1d100",
- sheet = sheet,
- rollStep = step,
+ rollSuccessValue = (characteristic.value.toIntOrNull() ?: 0) * 5,
)
}
@@ -59,14 +66,11 @@ class RollViewModel : ViewModel() {
sheet: CharacterSheetPageUio,
node: CharacterSheetPageUio.Node,
) {
- val step = SkillStepUseCase.computeSkillStep(
- skill = node.value,
- )
prepareRoll(
+ sheet = sheet,
label = node.label,
rollAction = "1d100",
- sheet = sheet,
- rollStep = step,
+ rollSuccessValue = node.value,
)
}
@@ -75,34 +79,45 @@ class RollViewModel : ViewModel() {
roll: CharacterSheetPageUio.Roll,
) {
prepareRoll(
+ sheet = sheet,
label = roll.label,
rollAction = roll.value,
- sheet = sheet,
- rollStep = null,
+ rollSuccessValue = null,
)
}
private fun prepareRoll(
+ sheet: CharacterSheetPageUio,
label: String,
rollAction: String,
- sheet: CharacterSheetPageUio,
- rollStep: SkillStepUseCase.SkillStep?,
+ rollSuccessValue: Int?,
) {
runBlocking { rollRotation.snapTo(0f) }
- this.rollStep = rollStep
- this.rollAction = rollAction
- this.sheet = CharacterSheetRepository.characterSheetFlow(id = sheet.id).value!!
- _result.value = null
- _roll.value = RollUio(
+ this.sheet = CharacterSheetRepository.characterSheetFlow(id = sheet.id).value!!
+ this.rollAction = rollAction
+ this.rollSuccessValue = rollSuccessValue
+
+ val rollStep = rollSuccessValue?.let {
+ SkillStepUseCase.computeSkillStep(skill = it)
+ }
+
+ _rollResult.value = null
+ _rollTitle.value = RollTitleUio(
label = label,
value = rollStep?.successRange?.last
)
+ _rollDifficulty.value = rollSuccessValue?.let {
+ DifficultyUio(
+ open = false,
+ Difficulty.NORMAL,
+ )
+ }
}
suspend fun roll() {
coroutineScope {
- _result.value = null
+ _rollResult.value = null
rollJob?.cancel()
rollJob = launch {
@@ -118,31 +133,81 @@ class RollViewModel : ViewModel() {
launch {
delay(500)
+ val rollStep = rollSuccessValue?.let {
+ SkillStepUseCase.computeSkillStep(
+ skill = when (_rollDifficulty.value?.difficulty) {
+ Difficulty.EASY -> it * 2
+ Difficulty.NORMAL -> it
+ Difficulty.HARD -> it / 2
+ Difficulty.IMPOSSIBLE -> it / 4
+ else -> it
+ }
+ )
+ }
val roll = if (rollAction == "1d100") {
RollUseCase.rollD100()
} else {
RollUseCase.roll(characterSheet = sheet, roll = rollAction)
}
+ val success = rollStep?.let {
+ when (roll) {
+ in it.criticalSuccessRange -> getString(resource = Res.string.roll_page__critical_success)
+ in it.specialSuccessRange -> getString(resource = Res.string.roll_page__special_success)
+ in it.successRange -> getString(resource = Res.string.roll_page__success)
+ in it.failureRange -> getString(resource = Res.string.roll_page__failure)
+ in it.criticalFailureRange -> getString(resource = Res.string.roll_page__critical_failure)
+ else -> ""
+ }
+ }
- _result.value = RollResultUio(
- label = rollStep?.let { rollStep ->
- when (roll) {
- in rollStep.criticalSuccessRange -> getString(resource = Res.string.roll_page__critical_success)
- in rollStep.specialSuccessRange -> getString(resource = Res.string.roll_page__special_success)
- in rollStep.successRange -> getString(resource = Res.string.roll_page__success)
- in rollStep.failureRange -> getString(resource = Res.string.roll_page__failure)
- in rollStep.criticalFailureRange -> getString(resource = Res.string.roll_page__critical_failure)
- else -> ""
- }
- } ?: "",
+ _rollResult.value = RollResultUio(
+ label = success ?: "",
value = roll,
)
-
launch {
- repository.share(label = _roll.value.label, roll = roll)
+ repository.share(
+ skillLabel = _rollTitle.value.label,
+ rollDifficulty = when (_rollDifficulty.value?.difficulty) {
+ Difficulty.EASY -> getString(Res.string.roll_page__dc_easy__label)
+ Difficulty.NORMAL -> getString(Res.string.roll_page__dc_normal__label)
+ Difficulty.HARD -> getString(Res.string.roll_page__dc_hard__label)
+ Difficulty.IMPOSSIBLE -> getString(Res.string.roll_page__dc_impossible__label)
+ else -> null
+ },
+ rollValue = roll,
+ rollSuccessLimit = rollStep?.successRange?.last,
+ resultLabel = success,
+ )
}
}
}
}
}
+
+ fun toggleDifficulty() {
+ _rollDifficulty.value = _rollDifficulty.value?.copy(
+ open = _rollDifficulty.value?.open?.not() ?: false
+ )
+ }
+
+ fun onDifficulty(difficulty: Difficulty) {
+ _rollDifficulty.value = DifficultyUio(
+ open = false,
+ difficulty = difficulty,
+ )
+ val rollStep = rollSuccessValue?.let {
+ SkillStepUseCase.computeSkillStep(
+ skill = when (_rollDifficulty.value?.difficulty) {
+ Difficulty.EASY -> it * 2
+ Difficulty.NORMAL -> it
+ Difficulty.HARD -> it / 2
+ Difficulty.IMPOSSIBLE -> it / 4
+ else -> it
+ }
+ )
+ }
+ _rollTitle.value = _rollTitle.value.copy(
+ value = rollStep?.successRange?.last
+ )
+ }
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryItem.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryItem.kt
new file mode 100644
index 0000000..7d0939a
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryItem.kt
@@ -0,0 +1,111 @@
+package com.pixelized.desktop.lwa.screen.rollhistory
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+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.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.roll_history__item__difficulty
+import lwacharactersheet.composeapp.generated.resources.roll_history__item__throw
+import org.jetbrains.compose.resources.stringResource
+
+
+@Stable
+data class RollHistoryItemUio(
+ val from: String,
+ val skillLabel: String,
+ val rollDifficulty: String?,
+ val rollValue: Int,
+ val rollSuccessLimit: Int?,
+ val resultLabel: String?,
+)
+
+@Composable
+fun RollHistoryItem(
+ modifier: Modifier = Modifier,
+ roll: RollHistoryItemUio,
+) {
+ Row(
+ modifier = modifier,
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Column(
+ modifier = Modifier.weight(1f)
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.body1,
+ fontWeight = FontWeight.Bold,
+ text = roll.from,
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.caption,
+ text = stringResource(Res.string.roll_history__item__throw),
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.body1,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = roll.skillLabel,
+ )
+ }
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
+ ) {
+ roll.rollDifficulty?.let {
+ Text(
+ style = MaterialTheme.typography.caption,
+ text = stringResource(Res.string.roll_history__item__difficulty),
+ )
+ Text(
+ style = MaterialTheme.typography.caption,
+ text = it,
+ )
+ Text(
+ style = MaterialTheme.typography.caption,
+ text = "-",
+ )
+ }
+ roll.resultLabel?.let {
+ Text(
+ style = MaterialTheme.typography.caption,
+ fontWeight = FontWeight.Bold,
+ text = it,
+ )
+ }
+ }
+ }
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(2.dp),
+ ) {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.h6,
+ fontWeight = FontWeight.Bold,
+ text = "${roll.rollValue}",
+ )
+ roll.rollSuccessLimit?.let {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.typography.caption,
+ fontWeight = FontWeight.Light,
+ text = "/ $it",
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryPage.kt
index 2023450..e20677f 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryPage.kt
@@ -2,14 +2,13 @@ package com.pixelized.desktop.lwa.screen.rollhistory
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
-import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
@@ -17,10 +16,8 @@ import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
@@ -29,12 +26,6 @@ import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.roll_history__title
import org.jetbrains.compose.resources.stringResource
-@Stable
-data class RollItemUio(
- val from: String,
- val label: String,
- val roll: Int,
-)
@Composable
fun RollHistoryPage(
@@ -58,7 +49,7 @@ fun RollHistoryPage(
@Composable
private fun RollHistoryContent(
modifier: Modifier = Modifier,
- rolls: State>,
+ rolls: State>,
onBack: () -> Unit,
) {
Scaffold(
@@ -92,10 +83,11 @@ private fun RollHistoryContent(
state = state,
reverseLayout = true,
contentPadding = PaddingValues(all = 24.dp),
- verticalArrangement = Arrangement.spacedBy(space = 8.dp)
+ verticalArrangement = Arrangement.spacedBy(space = 16.dp)
) {
items(items = rolls.value) {
- RollItem(
+ RollHistoryItem(
+ modifier = Modifier.fillMaxWidth(),
roll = it
)
}
@@ -104,32 +96,3 @@ private fun RollHistoryContent(
)
}
-@Composable
-private fun RollItem(
- modifier: Modifier = Modifier,
- roll: RollItemUio,
-) {
- Row(
- modifier = modifier,
- horizontalArrangement = Arrangement.spacedBy(4.dp),
- ) {
- Text(
- modifier = Modifier.alignByBaseline(),
- style = MaterialTheme.typography.body1,
- fontWeight = FontWeight.Thin,
- text = roll.from,
- )
- Text(
- modifier = Modifier.alignByBaseline(),
- style = MaterialTheme.typography.body1,
- fontWeight = FontWeight.Light,
- text = roll.label,
- )
- Text(
- modifier = Modifier.alignByBaseline(),
- style = MaterialTheme.typography.body1,
- fontWeight = FontWeight.Bold,
- text = "${roll.roll}",
- )
- }
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryViewModel.kt
index 356fe50..898c81e 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/rollhistory/RollHistoryViewModel.kt
@@ -12,8 +12,8 @@ class RollHistoryViewModel : ViewModel() {
private val repository = RollHistoryRepository
- private val _rolls = mutableStateOf((emptyList()))
- val rolls: State> get() = _rolls
+ private val _rolls = mutableStateOf((emptyList()))
+ val rolls: State> get() = _rolls
init {
viewModelScope.launch {
@@ -22,10 +22,13 @@ class RollHistoryViewModel : ViewModel() {
_rolls.value = _rolls.value.toMutableList().apply {
add(
index = 0,
- element = RollItemUio(
+ element = RollHistoryItemUio(
from = it.from,
- label = content.label,
- roll = content.roll
+ skillLabel = content.skillLabel,
+ rollDifficulty = content.rollDifficulty,
+ resultLabel = content.resultLabel,
+ rollValue = content.rollValue,
+ rollSuccessLimit = content.rollSuccessLimit,
)
)
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/DisableInteractionSource.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/DisableInteractionSource.kt
new file mode 100644
index 0000000..9eddde6
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/DisableInteractionSource.kt
@@ -0,0 +1,14 @@
+package com.pixelized.desktop.lwa.utils
+
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.emptyFlow
+
+class DisableInteractionSource : MutableInteractionSource {
+ override val interactions: Flow = emptyFlow()
+
+ override suspend fun emit(interaction: Interaction) = Unit
+
+ override fun tryEmit(interaction: Interaction): Boolean = false
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index e2f7e34..ac39250 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -6,7 +6,7 @@ junit = "4.13.2"
compose-multiplatform = "1.7.0"
androidx-lifecycle = "2.8.3"
androidx-navigation = "2.8.0-alpha10"
-ktor_version = "3.0.1"
+ktor_version = "3.0.0"
[plugins]
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
@@ -24,6 +24,7 @@ androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle
androidx-navigation-compose = { group = "org.jetbrains.androidx.navigation", name = "navigation-compose", version.ref = "androidx-navigation" }
kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-json" }
+
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor_version" }
ktor-client-cio = { group = 'io.ktor', name = "ktor-client-cio", version.ref = "ktor_version" }
ktor-client-websockets = { group = 'io.ktor', name = "ktor-client-websockets", version.ref = "ktor_version" }