Add roll history page
This commit is contained in:
parent
f92922c228
commit
ca456b55d9
20 changed files with 488 additions and 133 deletions
|
|
@ -1,7 +1,9 @@
|
||||||
plugins {
|
plugins {
|
||||||
// this is necessary to avoid the plugins to be loaded multiple times
|
// this is necessary to avoid the plugins to be loaded multiple times
|
||||||
// in each subproject's classloader
|
// 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.composeMultiplatform) apply false
|
||||||
alias(libs.plugins.composeCompiler) apply false
|
alias(libs.plugins.composeCompiler) apply false
|
||||||
alias(libs.plugins.kotlinMultiplatform) apply false
|
|
||||||
}
|
}
|
||||||
|
|
@ -3,10 +3,9 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.kotlinMultiplatform)
|
alias(libs.plugins.kotlinMultiplatform)
|
||||||
alias(libs.plugins.kotlinSerialization)
|
alias(libs.plugins.kotlinSerialization)
|
||||||
|
// alias(libs.plugins.kotlinKtor)
|
||||||
alias(libs.plugins.composeMultiplatform)
|
alias(libs.plugins.composeMultiplatform)
|
||||||
alias(libs.plugins.composeCompiler)
|
alias(libs.plugins.composeCompiler)
|
||||||
// kotlin("jvm") version "1.9.20"
|
|
||||||
// alias(libs.plugins.kotlinKtor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="main_page__create_action">Créer une feuille de personnage</string>
|
<string name="main_page__create_action">Créer une feuille de personnage</string>
|
||||||
<string name="main_page__network_action">Configuration réseau</string>
|
<string name="main_page__network_action">Configuration de la table</string>
|
||||||
<string name="main_page__roll_history_action">Consulter l'historique des lancés</string>
|
<string name="main_page__roll_history_action">Consulter l'historique des lancers</string>
|
||||||
|
|
||||||
|
<string name="roll_page__roll__label">Jet de :</string>
|
||||||
|
<string name="roll_page__roll__success_label">Réussite si lancer inférieur ou égale à : %1$s</string>
|
||||||
<string name="roll_page__critical_success">Réussite critique</string>
|
<string name="roll_page__critical_success">Réussite critique</string>
|
||||||
<string name="roll_page__special_success">Réussite spéciale</string>
|
<string name="roll_page__special_success">Réussite spéciale</string>
|
||||||
<string name="roll_page__success">Réussite</string>
|
<string name="roll_page__success">Réussite</string>
|
||||||
<string name="roll_page__failure">Échec</string>
|
<string name="roll_page__failure">Échec</string>
|
||||||
<string name="roll_page__critical_failure">Échec critique</string>
|
<string name="roll_page__critical_failure">Échec critique</string>
|
||||||
|
<string name="roll_page__dc__label">Dégré de difficulté :</string>
|
||||||
|
<string name="roll_page__dc_easy__label">Facile</string>
|
||||||
|
<string name="roll_page__dc_normal__label">Normal</string>
|
||||||
|
<string name="roll_page__dc_hard__label">Difficile</string>
|
||||||
|
<string name="roll_page__dc_impossible__label">Impossible</string>
|
||||||
|
|
||||||
<string name="character_sheet_edit__title">Création de personnage</string>
|
<string name="character_sheet_edit__title">Création de personnage</string>
|
||||||
<string name="character_sheet_edit__name_placeholder">Nom</string>
|
<string name="character_sheet_edit__name_placeholder">Nom</string>
|
||||||
|
|
@ -68,7 +75,7 @@
|
||||||
<string name="character_sheet__occupations_title">Occupations</string>
|
<string name="character_sheet__occupations_title">Occupations</string>
|
||||||
<string name="character_sheet__magics__title">Compétences magiques</string>
|
<string name="character_sheet__magics__title">Compétences magiques</string>
|
||||||
|
|
||||||
<string name="network__title">Configuration réseau</string>
|
<string name="network__title">Configuration de la table</string>
|
||||||
<string name="network__player_name__label">Nom du joueur</string>
|
<string name="network__player_name__label">Nom du joueur</string>
|
||||||
<string name="network__host__label">host</string>
|
<string name="network__host__label">host</string>
|
||||||
<string name="network__port__label">port</string>
|
<string name="network__port__label">port</string>
|
||||||
|
|
@ -83,5 +90,7 @@
|
||||||
<string name="network__socket__type_client">Client</string>
|
<string name="network__socket__type_client">Client</string>
|
||||||
<string name="network__socket__type_none">Aucun</string>
|
<string name="network__socket__type_none">Aucun</string>
|
||||||
|
|
||||||
<string name="roll_history__title">Historique des lancés</string>
|
<string name="roll_history__title">Historique des lancers</string>
|
||||||
|
<string name="roll_history__item__throw">lance</string>
|
||||||
|
<string name="roll_history__item__difficulty">Difficulté</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -168,7 +168,10 @@ fun HandleCharacterSheetCreation(
|
||||||
title = stringResource(Res.string.character_sheet_edit__title),
|
title = stringResource(Res.string.character_sheet_edit__title),
|
||||||
) {
|
) {
|
||||||
CharacterSheetMainNavHost(
|
CharacterSheetMainNavHost(
|
||||||
startDestination = CharacterSheetEditDestination.navigationRoute(id = null)
|
startDestination = CharacterSheetEditDestination.navigationRoute(
|
||||||
|
id = null,
|
||||||
|
enableBack = false,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.pixelized.desktop.lwa.navigation.destination
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditPage
|
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditPage
|
||||||
|
|
@ -11,22 +12,33 @@ import com.pixelized.desktop.lwa.utils.extention.ARG
|
||||||
object CharacterSheetEditDestination {
|
object CharacterSheetEditDestination {
|
||||||
private const val ROUTE = "character.sheet.edit"
|
private const val ROUTE = "character.sheet.edit"
|
||||||
private const val CHARACTER_ID = "id"
|
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(
|
fun arguments() = listOf(
|
||||||
navArgument(CHARACTER_ID) {
|
navArgument(CHARACTER_ID) {
|
||||||
nullable = true
|
nullable = true
|
||||||
|
type = NavType.StringType
|
||||||
|
},
|
||||||
|
navArgument(ENABLE_BACK) {
|
||||||
|
nullable = false
|
||||||
|
type = NavType.BoolType
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
data class Argument(
|
data class Argument(
|
||||||
val id: String?,
|
val id: String?,
|
||||||
|
val enableBack: Boolean,
|
||||||
) {
|
) {
|
||||||
constructor(savedStateHandle: SavedStateHandle) : this(
|
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||||
id = savedStateHandle.get<String>(CHARACTER_ID)
|
id = savedStateHandle.get<String>(CHARACTER_ID),
|
||||||
|
enableBack = savedStateHandle.get<Boolean>(ENABLE_BACK)
|
||||||
|
?: error("Missing enableBack argument"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -42,7 +54,8 @@ fun NavGraphBuilder.composableCharacterSheetEditPage() {
|
||||||
|
|
||||||
fun NavHostController.navigateToCharacterSheetEdit(
|
fun NavHostController.navigateToCharacterSheetEdit(
|
||||||
id: String? = null,
|
id: String? = null,
|
||||||
|
enableBack: Boolean = true,
|
||||||
) {
|
) {
|
||||||
val route = CharacterSheetEditDestination.navigationRoute(id = id)
|
val route = CharacterSheetEditDestination.navigationRoute(id = id, enableBack = enableBack)
|
||||||
navigate(route = route)
|
navigate(route = route)
|
||||||
}
|
}
|
||||||
|
|
@ -27,6 +27,9 @@ typealias Server = EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine
|
||||||
typealias Client = HttpClient
|
typealias Client = HttpClient
|
||||||
|
|
||||||
object NetworkRepository {
|
object NetworkRepository {
|
||||||
|
const val DEFAULT_PORT = 16030
|
||||||
|
const val DEFAULT_HOST = "pixelized.freeboxos.fr"
|
||||||
|
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
private var networkJob: Job? = null
|
private var networkJob: Job? = null
|
||||||
private var server: Server? = null
|
private var server: Server? = null
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
// https://ktor.io/docs/server-websockets.html#handle-multiple-session
|
// https://ktor.io/docs/server-websockets.html#handle-multiple-session
|
||||||
fun server(
|
fun server(
|
||||||
port: Int = 8080,
|
port: Int,
|
||||||
handler: suspend DefaultWebSocketServerSession.() -> Unit
|
handler: suspend DefaultWebSocketServerSession.() -> Unit
|
||||||
): EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration> {
|
): EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration> {
|
||||||
return embeddedServer(
|
return embeddedServer(
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RollMessage(
|
data class RollMessage(
|
||||||
val label: String,
|
val skillLabel: String,
|
||||||
val roll: Int,
|
val resultLabel: String?,
|
||||||
): MessageContent
|
val rollDifficulty: String?,
|
||||||
|
val rollValue: Int,
|
||||||
|
val rollSuccessLimit: Int?,
|
||||||
|
) : MessageContent
|
||||||
|
|
@ -31,11 +31,20 @@ object RollHistoryRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun share(
|
suspend fun share(
|
||||||
label: String,
|
skillLabel: String,
|
||||||
roll: Int,
|
rollDifficulty: String?,
|
||||||
|
rollValue: Int,
|
||||||
|
resultLabel: String?,
|
||||||
|
rollSuccessLimit: Int?,
|
||||||
) {
|
) {
|
||||||
network.share(
|
network.share(
|
||||||
content = RollMessage(label = label, roll = roll)
|
content = RollMessage(
|
||||||
|
skillLabel = skillLabel,
|
||||||
|
rollDifficulty = rollDifficulty,
|
||||||
|
rollValue = rollValue,
|
||||||
|
resultLabel = resultLabel,
|
||||||
|
rollSuccessLimit = rollSuccessLimit,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,11 +113,11 @@ fun CharacterSheetPage(
|
||||||
CharacterSheetPageContent(
|
CharacterSheetPageContent(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
characterSheet = sheet,
|
characterSheet = sheet,
|
||||||
onBack = {
|
|
||||||
screen.popBackStack()
|
|
||||||
},
|
|
||||||
onEdit = {
|
onEdit = {
|
||||||
screen.navigateToCharacterSheetEdit(id = sheet.id)
|
screen.navigateToCharacterSheetEdit(
|
||||||
|
id = sheet.id,
|
||||||
|
enableBack = true,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onDelete = {
|
onDelete = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|
@ -154,7 +154,6 @@ fun CharacterSheetPageContent(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
scrollState: ScrollState = rememberScrollState(),
|
scrollState: ScrollState = rememberScrollState(),
|
||||||
characterSheet: CharacterSheetPageUio,
|
characterSheet: CharacterSheetPageUio,
|
||||||
onBack: () -> Unit,
|
|
||||||
onEdit: () -> Unit,
|
onEdit: () -> Unit,
|
||||||
onDelete: () -> Unit,
|
onDelete: () -> Unit,
|
||||||
onCharacteristic: (characteristic: CharacterSheetPageUio.Characteristic) -> Unit,
|
onCharacteristic: (characteristic: CharacterSheetPageUio.Characteristic) -> Unit,
|
||||||
|
|
@ -178,6 +177,7 @@ fun CharacterSheetPageContent(
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Edit,
|
imageVector = Icons.Default.Edit,
|
||||||
|
tint = MaterialTheme.colors.primary,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -186,6 +186,7 @@ fun CharacterSheetPageContent(
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
|
tint = MaterialTheme.colors.primary,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -346,9 +347,10 @@ private fun Stat(
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.align(alignment = Alignment.Center),
|
modifier = Modifier.align(alignment = Alignment.Center),
|
||||||
style = MaterialTheme.typography.h4,
|
style = MaterialTheme.typography.h3,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
text = characteristic.value
|
text = characteristic.value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -402,6 +404,7 @@ private fun Roll(
|
||||||
)
|
)
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(Res.drawable.ic_d20_32dp),
|
painter = painterResource(Res.drawable.ic_d20_32dp),
|
||||||
|
tint = MaterialTheme.colors.primary,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -433,6 +436,7 @@ private fun Skill(
|
||||||
Text(
|
Text(
|
||||||
style = MaterialTheme.typography.body1,
|
style = MaterialTheme.typography.body1,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
text = "$value",
|
text = "$value",
|
||||||
)
|
)
|
||||||
Checkbox(modifier = Modifier.size(size = 32.dp), checked = false, onCheckedChange = { })
|
Checkbox(modifier = Modifier.size(size = 32.dp), checked = false, onCheckedChange = { })
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -85,7 +86,13 @@ fun CharacterSheetEditPage(
|
||||||
) {
|
) {
|
||||||
CharacterSheetEdit(
|
CharacterSheetEdit(
|
||||||
form = viewModel.characterSheet.value,
|
form = viewModel.characterSheet.value,
|
||||||
onBack = { screen.popBackStack() },
|
onBack = remember {
|
||||||
|
if (viewModel.enableBack) {
|
||||||
|
{ screen.popBackStack() }
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
},
|
||||||
onNewSkill = viewModel::onSkill,
|
onNewSkill = viewModel::onSkill,
|
||||||
onNewCategory = viewModel::onNewRoll,
|
onNewCategory = viewModel::onNewRoll,
|
||||||
onSave = {
|
onSave = {
|
||||||
|
|
@ -103,7 +110,7 @@ fun CharacterSheetEditPage(
|
||||||
@Composable
|
@Composable
|
||||||
fun CharacterSheetEdit(
|
fun CharacterSheetEdit(
|
||||||
form: CharacterSheetEditPageUio,
|
form: CharacterSheetEditPageUio,
|
||||||
onBack: () -> Unit,
|
onBack: (() -> Unit)?,
|
||||||
onNewSkill: (CharacterSheetEditPageUio.SkillGroup) -> Unit,
|
onNewSkill: (CharacterSheetEditPageUio.SkillGroup) -> Unit,
|
||||||
onNewCategory: () -> Unit,
|
onNewCategory: () -> Unit,
|
||||||
onSave: () -> Unit,
|
onSave: () -> Unit,
|
||||||
|
|
@ -118,14 +125,16 @@ fun CharacterSheetEdit(
|
||||||
text = stringResource(Res.string.character_sheet_edit__title),
|
text = stringResource(Res.string.character_sheet_edit__title),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
navigationIcon = {
|
navigationIcon = onBack?.let { action: () -> Unit ->
|
||||||
IconButton(
|
{
|
||||||
onClick = onBack,
|
IconButton(
|
||||||
) {
|
onClick = action,
|
||||||
Icon(
|
) {
|
||||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
Icon(
|
||||||
contentDescription = null,
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
)
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ class CharacterSheetEditViewModel(
|
||||||
private val repository = CharacterSheetRepository
|
private val repository = CharacterSheetRepository
|
||||||
private val factory = CharacterSheetEditFactory()
|
private val factory = CharacterSheetEditFactory()
|
||||||
|
|
||||||
|
val enableBack = argument.enableBack
|
||||||
|
|
||||||
private val _characterSheet = mutableStateOf(
|
private val _characterSheet = mutableStateOf(
|
||||||
repository.characterSheetFlow(id = argument.id).value.let {
|
repository.characterSheetFlow(id = argument.id).value.let {
|
||||||
runBlocking { factory.convertToUio(it) }
|
runBlocking { factory.convertToUio(it) }
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,9 @@ class NetworkViewModel : ViewModel() {
|
||||||
private val repository = NetworkRepository
|
private val repository = NetworkRepository
|
||||||
private val factory = NetworkFactory()
|
private val factory = NetworkFactory()
|
||||||
|
|
||||||
private val host = mutableStateOf("localhost")
|
private val host = mutableStateOf(NetworkRepository.DEFAULT_HOST)
|
||||||
private val port = mutableStateOf(27030)
|
private val port = mutableStateOf(NetworkRepository.DEFAULT_PORT)
|
||||||
|
|
||||||
val network: State<NetworkPageUio>
|
val network: State<NetworkPageUio>
|
||||||
@Composable
|
@Composable
|
||||||
@Stable
|
@Stable
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.pixelized.desktop.lwa.screen.roll
|
package com.pixelized.desktop.lwa.screen.roll
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.slideInVertically
|
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.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
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.Icon
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
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.Composable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.remember
|
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.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
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 kotlinx.coroutines.launch
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_d20_32dp
|
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.painterResource
|
||||||
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class RollUio(
|
data class RollTitleUio(
|
||||||
val label: String,
|
val label: String,
|
||||||
val value: Int?,
|
val value: Int?,
|
||||||
)
|
)
|
||||||
|
|
@ -51,6 +69,16 @@ data class RollResultUio(
|
||||||
val value: Int,
|
val value: Int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
data class DifficultyUio(
|
||||||
|
val open: Boolean,
|
||||||
|
val difficulty: Difficulty,
|
||||||
|
) {
|
||||||
|
enum class Difficulty {
|
||||||
|
EASY, NORMAL, HARD, IMPOSSIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RollPage(
|
fun RollPage(
|
||||||
viewModel: RollViewModel = viewModel { RollViewModel() },
|
viewModel: RollViewModel = viewModel { RollViewModel() },
|
||||||
|
|
@ -72,24 +100,24 @@ fun RollPage(
|
||||||
style = MaterialTheme.typography.caption,
|
style = MaterialTheme.typography.caption,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
text = "Jet de :",
|
text = stringResource(Res.string.roll_page__roll__label),
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
style = MaterialTheme.typography.h5,
|
style = MaterialTheme.typography.h5,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
text = viewModel.roll.value.label,
|
text = viewModel.rollTitle.value.label,
|
||||||
)
|
)
|
||||||
viewModel.roll.value.value?.let {
|
viewModel.rollTitle.value.value?.let {
|
||||||
Text(
|
Text(
|
||||||
style = MaterialTheme.typography.caption,
|
style = MaterialTheme.typography.caption,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
text = "Réussite en dessous de : ${it}",
|
text = stringResource(Res.string.roll_page__roll__success_label, it),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.weight(weight = 1f),
|
||||||
verticalArrangement = Arrangement.spacedBy(
|
verticalArrangement = Arrangement.spacedBy(
|
||||||
space = 24.dp,
|
space = 24.dp,
|
||||||
alignment = Alignment.CenterVertically,
|
alignment = Alignment.CenterVertically,
|
||||||
|
|
@ -114,7 +142,7 @@ fun RollPage(
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = viewModel.result.value?.value?.toString() ?: "",
|
targetState = viewModel.rollResult.value?.value?.toString() ?: "",
|
||||||
transitionSpec = {
|
transitionSpec = {
|
||||||
val enter = fadeIn() + slideInVertically { 32 }
|
val enter = fadeIn() + slideInVertically { 32 }
|
||||||
val exit = fadeOut() + slideOutVertically { -32 }
|
val exit = fadeOut() + slideOutVertically { -32 }
|
||||||
|
|
@ -137,7 +165,7 @@ fun RollPage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = viewModel.result.value?.label ?: "",
|
targetState = viewModel.rollResult.value?.label ?: "",
|
||||||
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
||||||
) { value ->
|
) { value ->
|
||||||
Text(
|
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,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -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.characterSheet.CharacterSheetRepository
|
||||||
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
|
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
|
||||||
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio
|
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.Job
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
|
@ -20,6 +21,10 @@ import kotlinx.coroutines.runBlocking
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__critical_failure
|
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__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__failure
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__special_success
|
import lwacharactersheet.composeapp.generated.resources.roll_page__special_success
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__success
|
import lwacharactersheet.composeapp.generated.resources.roll_page__success
|
||||||
|
|
@ -28,30 +33,32 @@ import org.jetbrains.compose.resources.getString
|
||||||
class RollViewModel : ViewModel() {
|
class RollViewModel : ViewModel() {
|
||||||
private val repository = RollHistoryRepository
|
private val repository = RollHistoryRepository
|
||||||
|
|
||||||
private val _roll = mutableStateOf(RollUio(label = "", value = 0))
|
private lateinit var sheet: CharacterSheet
|
||||||
val roll: State<RollUio> get() = _roll
|
private lateinit var rollAction: String
|
||||||
|
private var rollSuccessValue: Int? = null
|
||||||
|
|
||||||
private var rollJob: Job? = null
|
private var rollJob: Job? = null
|
||||||
private var rollStep: SkillStepUseCase.SkillStep? = null
|
|
||||||
private lateinit var rollAction: String
|
private val _rollTitle = mutableStateOf(RollTitleUio(label = "", value = 0))
|
||||||
private lateinit var sheet: CharacterSheet
|
val rollTitle: State<RollTitleUio> get() = _rollTitle
|
||||||
|
|
||||||
|
private val _rollResult = mutableStateOf<RollResultUio?>(null)
|
||||||
|
val rollResult: State<RollResultUio?> get() = _rollResult
|
||||||
|
|
||||||
val rollRotation = Animatable(0f)
|
val rollRotation = Animatable(0f)
|
||||||
|
|
||||||
private val _result = mutableStateOf<RollResultUio?>(null)
|
private val _rollDifficulty = mutableStateOf<DifficultyUio?>(null)
|
||||||
val result: State<RollResultUio?> get() = _result
|
val rollDifficulty: State<DifficultyUio?> get() = _rollDifficulty
|
||||||
|
|
||||||
fun prepareRoll(
|
fun prepareRoll(
|
||||||
sheet: CharacterSheetPageUio,
|
sheet: CharacterSheetPageUio,
|
||||||
characteristic: CharacterSheetPageUio.Characteristic,
|
characteristic: CharacterSheetPageUio.Characteristic,
|
||||||
) {
|
) {
|
||||||
val step = SkillStepUseCase.computeSkillStep(
|
|
||||||
skill = (characteristic.value.toIntOrNull() ?: 0) * 5
|
|
||||||
)
|
|
||||||
prepareRoll(
|
prepareRoll(
|
||||||
|
sheet = sheet,
|
||||||
label = characteristic.label,
|
label = characteristic.label,
|
||||||
rollAction = "1d100",
|
rollAction = "1d100",
|
||||||
sheet = sheet,
|
rollSuccessValue = (characteristic.value.toIntOrNull() ?: 0) * 5,
|
||||||
rollStep = step,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,14 +66,11 @@ class RollViewModel : ViewModel() {
|
||||||
sheet: CharacterSheetPageUio,
|
sheet: CharacterSheetPageUio,
|
||||||
node: CharacterSheetPageUio.Node,
|
node: CharacterSheetPageUio.Node,
|
||||||
) {
|
) {
|
||||||
val step = SkillStepUseCase.computeSkillStep(
|
|
||||||
skill = node.value,
|
|
||||||
)
|
|
||||||
prepareRoll(
|
prepareRoll(
|
||||||
|
sheet = sheet,
|
||||||
label = node.label,
|
label = node.label,
|
||||||
rollAction = "1d100",
|
rollAction = "1d100",
|
||||||
sheet = sheet,
|
rollSuccessValue = node.value,
|
||||||
rollStep = step,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,34 +79,45 @@ class RollViewModel : ViewModel() {
|
||||||
roll: CharacterSheetPageUio.Roll,
|
roll: CharacterSheetPageUio.Roll,
|
||||||
) {
|
) {
|
||||||
prepareRoll(
|
prepareRoll(
|
||||||
|
sheet = sheet,
|
||||||
label = roll.label,
|
label = roll.label,
|
||||||
rollAction = roll.value,
|
rollAction = roll.value,
|
||||||
sheet = sheet,
|
rollSuccessValue = null,
|
||||||
rollStep = null,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareRoll(
|
private fun prepareRoll(
|
||||||
|
sheet: CharacterSheetPageUio,
|
||||||
label: String,
|
label: String,
|
||||||
rollAction: String,
|
rollAction: String,
|
||||||
sheet: CharacterSheetPageUio,
|
rollSuccessValue: Int?,
|
||||||
rollStep: SkillStepUseCase.SkillStep?,
|
|
||||||
) {
|
) {
|
||||||
runBlocking { rollRotation.snapTo(0f) }
|
runBlocking { rollRotation.snapTo(0f) }
|
||||||
this.rollStep = rollStep
|
|
||||||
this.rollAction = rollAction
|
|
||||||
this.sheet = CharacterSheetRepository.characterSheetFlow(id = sheet.id).value!!
|
|
||||||
|
|
||||||
_result.value = null
|
this.sheet = CharacterSheetRepository.characterSheetFlow(id = sheet.id).value!!
|
||||||
_roll.value = RollUio(
|
this.rollAction = rollAction
|
||||||
|
this.rollSuccessValue = rollSuccessValue
|
||||||
|
|
||||||
|
val rollStep = rollSuccessValue?.let {
|
||||||
|
SkillStepUseCase.computeSkillStep(skill = it)
|
||||||
|
}
|
||||||
|
|
||||||
|
_rollResult.value = null
|
||||||
|
_rollTitle.value = RollTitleUio(
|
||||||
label = label,
|
label = label,
|
||||||
value = rollStep?.successRange?.last
|
value = rollStep?.successRange?.last
|
||||||
)
|
)
|
||||||
|
_rollDifficulty.value = rollSuccessValue?.let {
|
||||||
|
DifficultyUio(
|
||||||
|
open = false,
|
||||||
|
Difficulty.NORMAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun roll() {
|
suspend fun roll() {
|
||||||
coroutineScope {
|
coroutineScope {
|
||||||
_result.value = null
|
_rollResult.value = null
|
||||||
|
|
||||||
rollJob?.cancel()
|
rollJob?.cancel()
|
||||||
rollJob = launch {
|
rollJob = launch {
|
||||||
|
|
@ -118,31 +133,81 @@ class RollViewModel : ViewModel() {
|
||||||
launch {
|
launch {
|
||||||
delay(500)
|
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") {
|
val roll = if (rollAction == "1d100") {
|
||||||
RollUseCase.rollD100()
|
RollUseCase.rollD100()
|
||||||
} else {
|
} else {
|
||||||
RollUseCase.roll(characterSheet = sheet, roll = rollAction)
|
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(
|
_rollResult.value = RollResultUio(
|
||||||
label = rollStep?.let { rollStep ->
|
label = success ?: "",
|
||||||
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 -> ""
|
|
||||||
}
|
|
||||||
} ?: "",
|
|
||||||
value = roll,
|
value = roll,
|
||||||
)
|
)
|
||||||
|
|
||||||
launch {
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,14 +2,13 @@ package com.pixelized.desktop.lwa.screen.rollhistory
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.IconButton
|
import androidx.compose.material.IconButton
|
||||||
import androidx.compose.material.MaterialTheme
|
|
||||||
import androidx.compose.material.Scaffold
|
import androidx.compose.material.Scaffold
|
||||||
import androidx.compose.material.Surface
|
import androidx.compose.material.Surface
|
||||||
import androidx.compose.material.Text
|
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.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Stable
|
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
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 lwacharactersheet.composeapp.generated.resources.roll_history__title
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
@Stable
|
|
||||||
data class RollItemUio(
|
|
||||||
val from: String,
|
|
||||||
val label: String,
|
|
||||||
val roll: Int,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RollHistoryPage(
|
fun RollHistoryPage(
|
||||||
|
|
@ -58,7 +49,7 @@ fun RollHistoryPage(
|
||||||
@Composable
|
@Composable
|
||||||
private fun RollHistoryContent(
|
private fun RollHistoryContent(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
rolls: State<List<RollItemUio>>,
|
rolls: State<List<RollHistoryItemUio>>,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
@ -92,10 +83,11 @@ private fun RollHistoryContent(
|
||||||
state = state,
|
state = state,
|
||||||
reverseLayout = true,
|
reverseLayout = true,
|
||||||
contentPadding = PaddingValues(all = 24.dp),
|
contentPadding = PaddingValues(all = 24.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
verticalArrangement = Arrangement.spacedBy(space = 16.dp)
|
||||||
) {
|
) {
|
||||||
items(items = rolls.value) {
|
items(items = rolls.value) {
|
||||||
RollItem(
|
RollHistoryItem(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
roll = it
|
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}",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -12,8 +12,8 @@ class RollHistoryViewModel : ViewModel() {
|
||||||
|
|
||||||
private val repository = RollHistoryRepository
|
private val repository = RollHistoryRepository
|
||||||
|
|
||||||
private val _rolls = mutableStateOf((emptyList<RollItemUio>()))
|
private val _rolls = mutableStateOf((emptyList<RollHistoryItemUio>()))
|
||||||
val rolls: State<List<RollItemUio>> get() = _rolls
|
val rolls: State<List<RollHistoryItemUio>> get() = _rolls
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|
@ -22,10 +22,13 @@ class RollHistoryViewModel : ViewModel() {
|
||||||
_rolls.value = _rolls.value.toMutableList().apply {
|
_rolls.value = _rolls.value.toMutableList().apply {
|
||||||
add(
|
add(
|
||||||
index = 0,
|
index = 0,
|
||||||
element = RollItemUio(
|
element = RollHistoryItemUio(
|
||||||
from = it.from,
|
from = it.from,
|
||||||
label = content.label,
|
skillLabel = content.skillLabel,
|
||||||
roll = content.roll
|
rollDifficulty = content.rollDifficulty,
|
||||||
|
resultLabel = content.resultLabel,
|
||||||
|
rollValue = content.rollValue,
|
||||||
|
rollSuccessLimit = content.rollSuccessLimit,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<Interaction> = emptyFlow()
|
||||||
|
|
||||||
|
override suspend fun emit(interaction: Interaction) = Unit
|
||||||
|
|
||||||
|
override fun tryEmit(interaction: Interaction): Boolean = false
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ junit = "4.13.2"
|
||||||
compose-multiplatform = "1.7.0"
|
compose-multiplatform = "1.7.0"
|
||||||
androidx-lifecycle = "2.8.3"
|
androidx-lifecycle = "2.8.3"
|
||||||
androidx-navigation = "2.8.0-alpha10"
|
androidx-navigation = "2.8.0-alpha10"
|
||||||
ktor_version = "3.0.1"
|
ktor_version = "3.0.0"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
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" }
|
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-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" }
|
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-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-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" }
|
ktor-client-websockets = { group = 'io.ktor', name = "ktor-client-websockets", version.ref = "ktor_version" }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue