Add action to the character sheet detail panel.
This commit is contained in:
parent
b6d02c21be
commit
1fe75062b7
14 changed files with 469 additions and 56 deletions
|
|
@ -8,7 +8,6 @@ import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
class RollHistoryRepository(
|
class RollHistoryRepository(
|
||||||
private val network: NetworkRepository,
|
private val network: NetworkRepository,
|
||||||
|
|
@ -21,23 +20,4 @@ class RollHistoryRepository(
|
||||||
scope = scope,
|
scope = scope,
|
||||||
started = SharingStarted.Eagerly,
|
started = SharingStarted.Eagerly,
|
||||||
)
|
)
|
||||||
|
|
||||||
suspend fun share(
|
|
||||||
characterId: String,
|
|
||||||
skillLabel: String,
|
|
||||||
rollDifficulty: String?,
|
|
||||||
rollValue: Int,
|
|
||||||
resultLabel: String?,
|
|
||||||
rollSuccessLimit: Int?,
|
|
||||||
) {
|
|
||||||
val content = RollMessage(
|
|
||||||
characterId = characterId,
|
|
||||||
skillLabel = skillLabel,
|
|
||||||
rollDifficulty = rollDifficulty,
|
|
||||||
rollValue = rollValue,
|
|
||||||
resultLabel = resultLabel,
|
|
||||||
rollSuccessLimit = rollSuccessLimit,
|
|
||||||
)
|
|
||||||
network.share(payload = content)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.circle
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.border
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
|
import com.pixelized.desktop.lwa.utils.extention.dashedBorder
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MasteryShape(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
shape: Shape = CircleShape,
|
||||||
|
color: Color = MaterialTheme.lwa.colorScheme.base.onSurface,
|
||||||
|
borderWidth: Dp = 1.dp,
|
||||||
|
size: Dp = 12.dp,
|
||||||
|
multiplier: Int,
|
||||||
|
) {
|
||||||
|
when (multiplier) {
|
||||||
|
0 -> Box(
|
||||||
|
modifier = modifier
|
||||||
|
.size(size = size)
|
||||||
|
.dashedBorder(
|
||||||
|
width = borderWidth,
|
||||||
|
color = color,
|
||||||
|
shape = shape,
|
||||||
|
on = 3.dp,
|
||||||
|
off = 2.dp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
1 -> Box(
|
||||||
|
modifier = modifier
|
||||||
|
.size(size = size)
|
||||||
|
.background(
|
||||||
|
color = color,
|
||||||
|
shape = shape,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> Box(
|
||||||
|
modifier = modifier
|
||||||
|
.size(size = size)
|
||||||
|
.border(
|
||||||
|
width = borderWidth,
|
||||||
|
color = color,
|
||||||
|
shape = shape
|
||||||
|
)
|
||||||
|
.padding(all = 2.dp)
|
||||||
|
) {
|
||||||
|
MasteryShape(
|
||||||
|
shape = shape,
|
||||||
|
color = color,
|
||||||
|
borderWidth = borderWidth,
|
||||||
|
size = size - borderWidth * 2,
|
||||||
|
multiplier = multiplier - 1,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ import com.pixelized.desktop.lwa.ui.composable.character.characteristic.Characte
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeader
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeader
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheet
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheet
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetActionUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetSkillUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetSkillUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
|
||||||
|
|
@ -108,6 +109,11 @@ fun CharacterDetailPanel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onAction = {
|
||||||
|
rollViewModel.prepareRoll(roll = it.roll)
|
||||||
|
rollViewModel.showOverlay()
|
||||||
|
blurController.show()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -122,6 +128,7 @@ fun CharacterDetailAnimatedPanel(
|
||||||
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
||||||
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
|
onAction: (CharacterDetailSheetActionUio) -> Unit,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
@ -159,6 +166,7 @@ fun CharacterDetailAnimatedPanel(
|
||||||
onCharacteristic = onCharacteristic,
|
onCharacteristic = onCharacteristic,
|
||||||
onSkill = onSkill,
|
onSkill = onSkill,
|
||||||
onUseSkill = onUseSkill,
|
onUseSkill = onUseSkill,
|
||||||
|
onAction = onAction,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -179,6 +187,7 @@ fun CharacterDetailContent(
|
||||||
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
||||||
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
|
onAction: (CharacterDetailSheetActionUio) -> Unit,
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
|
|
@ -206,6 +215,7 @@ fun CharacterDetailContent(
|
||||||
onCharacteristic = onCharacteristic,
|
onCharacteristic = onCharacteristic,
|
||||||
onSkill = onSkill,
|
onSkill = onSkill,
|
||||||
onUseSkill = onUseSkill,
|
onUseSkill = onUseSkill,
|
||||||
|
onAction = onAction,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail
|
||||||
|
|
||||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetActionUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetSkillUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetSkillUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
|
||||||
|
|
@ -192,6 +193,7 @@ class CharacterDetailFactory(
|
||||||
label = skill.label,
|
label = skill.label,
|
||||||
value = "$value",
|
value = "$value",
|
||||||
used = skill.used,
|
used = skill.used,
|
||||||
|
occupation = skill.occupation,
|
||||||
tooltips = skill.description?.let {
|
tooltips = skill.description?.let {
|
||||||
TooltipUio(
|
TooltipUio(
|
||||||
title = skill.label,
|
title = skill.label,
|
||||||
|
|
@ -217,6 +219,7 @@ class CharacterDetailFactory(
|
||||||
label = skill.label,
|
label = skill.label,
|
||||||
value = "$value",
|
value = "$value",
|
||||||
used = skill.used,
|
used = skill.used,
|
||||||
|
occupation = skill.occupation,
|
||||||
tooltips = skill.description?.let {
|
tooltips = skill.description?.let {
|
||||||
TooltipUio(
|
TooltipUio(
|
||||||
title = skill.label,
|
title = skill.label,
|
||||||
|
|
@ -231,7 +234,7 @@ class CharacterDetailFactory(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}.sortedWith(compareBy(Collator.getInstance()) { it.label }),
|
}.sortedWith(compareBy(Collator.getInstance()) { it.label }),
|
||||||
magicSkill = characterSheet.magicSkills.map { skill ->
|
magicSkills = characterSheet.magicSkills.map { skill ->
|
||||||
val value = expressionUseCase.computeSkillValue(
|
val value = expressionUseCase.computeSkillValue(
|
||||||
sheet = characterSheet,
|
sheet = characterSheet,
|
||||||
skill = skill,
|
skill = skill,
|
||||||
|
|
@ -242,6 +245,7 @@ class CharacterDetailFactory(
|
||||||
label = skill.label,
|
label = skill.label,
|
||||||
value = "$value",
|
value = "$value",
|
||||||
used = skill.used,
|
used = skill.used,
|
||||||
|
occupation = skill.occupation,
|
||||||
tooltips = skill.description?.let {
|
tooltips = skill.description?.let {
|
||||||
TooltipUio(
|
TooltipUio(
|
||||||
title = skill.label,
|
title = skill.label,
|
||||||
|
|
@ -256,6 +260,24 @@ class CharacterDetailFactory(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}.sortedWith(compareBy(Collator.getInstance()) { it.label }),
|
}.sortedWith(compareBy(Collator.getInstance()) { it.label }),
|
||||||
|
actions = characterSheet.actions.map { action ->
|
||||||
|
CharacterDetailSheetActionUio(
|
||||||
|
actionId = action.id,
|
||||||
|
label = action.label,
|
||||||
|
tooltips = action.description?.let {
|
||||||
|
TooltipUio(
|
||||||
|
title = action.label,
|
||||||
|
description = it,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
roll = RollActionUio(
|
||||||
|
characterSheetId = characterInstanceId.characterSheetId,
|
||||||
|
label = action.label,
|
||||||
|
rollAction = action.roll,
|
||||||
|
rollSuccessValue = null,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,25 +1,36 @@
|
||||||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet
|
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Stable
|
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.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__common_title
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__magic_title
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__special_title
|
||||||
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacterDetailSheetUio(
|
data class CharacterDetailSheetUio(
|
||||||
val characterInstanceId: Campaign.CharacterInstance.Id,
|
val characterInstanceId: Campaign.CharacterInstance.Id,
|
||||||
val characteristics: List<CharacterDetailSheetCharacteristicUio>,
|
val characteristics: List<CharacterDetailSheetCharacteristicUio>,
|
||||||
val commonSkills: List<CharacterDetailSheetSkillUio>,
|
val commonSkills: List<CharacterDetailSheetSkillUio>,
|
||||||
val specialSkill: List<CharacterDetailSheetSkillUio>,
|
val specialSkills: List<CharacterDetailSheetSkillUio>,
|
||||||
val magicSkill: List<CharacterDetailSheetSkillUio>,
|
val magicSkills: List<CharacterDetailSheetSkillUio>,
|
||||||
|
val actions: List<CharacterDetailSheetActionUio>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -29,6 +40,7 @@ fun CharacterDetailSheet(
|
||||||
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
||||||
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onUseSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
|
onAction: (CharacterDetailSheetActionUio) -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
@ -39,7 +51,7 @@ fun CharacterDetailSheet(
|
||||||
) {
|
) {
|
||||||
sheet.value?.characteristics?.forEach {
|
sheet.value?.characteristics?.forEach {
|
||||||
CharacterDetailSheetCharacteristic(
|
CharacterDetailSheetCharacteristic(
|
||||||
modifier = Modifier.size(width = 80.dp, height = 120.dp),
|
modifier = Modifier.size(width = 76.dp, height = 110.dp),
|
||||||
characteristic = it,
|
characteristic = it,
|
||||||
onClick = { onCharacteristic(it) },
|
onClick = { onCharacteristic(it) },
|
||||||
)
|
)
|
||||||
|
|
@ -47,12 +59,20 @@ fun CharacterDetailSheet(
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
verticalArrangement = Arrangement.spacedBy(space = 16.dp)
|
||||||
) {
|
) {
|
||||||
DecoratedBox(
|
DecoratedBox(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 8.dp, top = 4.dp),
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = stringResource(Res.string.character_sheet__skills__common_title),
|
||||||
|
)
|
||||||
sheet.value?.commonSkills?.forEach { skill ->
|
sheet.value?.commonSkills?.forEach { skill ->
|
||||||
CharacterDetailSheetSkill(
|
CharacterDetailSheetSkill(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
@ -63,30 +83,67 @@ fun CharacterDetailSheet(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DecoratedBox(
|
AnimatedVisibility(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
visible = sheet.value?.specialSkills?.isNotEmpty() ?: false,
|
||||||
) {
|
) {
|
||||||
Column {
|
DecoratedBox(
|
||||||
sheet.value?.specialSkill?.forEach { skill ->
|
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
|
||||||
CharacterDetailSheetSkill(
|
) {
|
||||||
modifier = Modifier.fillMaxWidth(),
|
Column {
|
||||||
skill = skill,
|
Text(
|
||||||
onSkill = onSkill,
|
modifier = Modifier
|
||||||
onUse = onUseSkill,
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 8.dp, top = 4.dp),
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = stringResource(Res.string.character_sheet__skills__special_title),
|
||||||
)
|
)
|
||||||
|
sheet.value?.specialSkills?.forEach { skill ->
|
||||||
|
CharacterDetailSheetSkill(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
skill = skill,
|
||||||
|
onSkill = onSkill,
|
||||||
|
onUse = onUseSkill,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DecoratedBox(
|
AnimatedVisibility(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
visible = sheet.value?.magicSkills?.isNotEmpty() ?: false,
|
||||||
|
) {
|
||||||
|
DecoratedBox(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp),
|
||||||
|
) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(bottom = 8.dp, top = 4.dp),
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
text = stringResource(Res.string.character_sheet__skills__magic_title),
|
||||||
|
)
|
||||||
|
sheet.value?.magicSkills?.forEach { skill ->
|
||||||
|
CharacterDetailSheetSkill(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
skill = skill,
|
||||||
|
onSkill = onSkill,
|
||||||
|
onUse = onUseSkill,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = sheet.value?.actions?.isNotEmpty() ?: false,
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
sheet.value?.magicSkill?.forEach { skill ->
|
sheet.value?.actions?.forEach { action ->
|
||||||
CharacterDetailSheetSkill(
|
CharacterDetailSheetAction(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
skill = skill,
|
action = action,
|
||||||
onSkill = onSkill,
|
onClick = onAction,
|
||||||
onUse = onUseSkill,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
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.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.roll.RollActionUio
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
|
||||||
|
import org.jetbrains.compose.resources.painterResource
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
data class CharacterDetailSheetActionUio(
|
||||||
|
val actionId: String,
|
||||||
|
val label: String,
|
||||||
|
val tooltips: TooltipUio?,
|
||||||
|
val roll: RollActionUio,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CharacterDetailSheetAction(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
paddingValues: PaddingValues = PaddingValues(start = 28.dp, end = 9.dp, top = 6.dp, bottom = 6.dp),
|
||||||
|
action: CharacterDetailSheetActionUio,
|
||||||
|
onClick: (CharacterDetailSheetActionUio) -> Unit,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(onClick = { onClick(action) })
|
||||||
|
.padding(paddingValues = paddingValues)
|
||||||
|
.then(other = modifier),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
style = MaterialTheme.typography.body1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = action.label,
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(size = 24.dp),
|
||||||
|
painter = painterResource(Res.drawable.ic_d20_24dp),
|
||||||
|
tint = MaterialTheme.colors.primary,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,8 +5,11 @@ import androidx.compose.foundation.clickable
|
||||||
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.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.offset
|
||||||
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.material.Checkbox
|
import androidx.compose.material.Checkbox
|
||||||
import androidx.compose.material.CheckboxDefaults
|
import androidx.compose.material.CheckboxDefaults
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
|
|
@ -18,6 +21,7 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
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 com.pixelized.desktop.lwa.ui.composable.circle.MasteryShape
|
||||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
||||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.roll.RollActionUio
|
import com.pixelized.desktop.lwa.ui.screen.roll.RollActionUio
|
||||||
|
|
@ -28,6 +32,7 @@ data class CharacterDetailSheetSkillUio(
|
||||||
val label: String,
|
val label: String,
|
||||||
val value: String,
|
val value: String,
|
||||||
val used: Boolean,
|
val used: Boolean,
|
||||||
|
val occupation: Boolean,
|
||||||
val tooltips: TooltipUio?,
|
val tooltips: TooltipUio?,
|
||||||
val roll: RollActionUio,
|
val roll: RollActionUio,
|
||||||
)
|
)
|
||||||
|
|
@ -36,7 +41,12 @@ data class CharacterDetailSheetSkillUio(
|
||||||
@Composable
|
@Composable
|
||||||
fun CharacterDetailSheetSkill(
|
fun CharacterDetailSheetSkill(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
paddingValues: PaddingValues = PaddingValues(start = 8.dp),
|
paddingValues: PaddingValues = PaddingValues(
|
||||||
|
start = 8.dp,
|
||||||
|
end = 4.dp,
|
||||||
|
top = 1.dp,
|
||||||
|
bottom = 1.dp
|
||||||
|
),
|
||||||
skill: CharacterDetailSheetSkillUio,
|
skill: CharacterDetailSheetSkillUio,
|
||||||
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
onSkill: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
onUse: (CharacterDetailSheetSkillUio) -> Unit,
|
onUse: (CharacterDetailSheetSkillUio) -> Unit,
|
||||||
|
|
@ -52,6 +62,10 @@ fun CharacterDetailSheetSkill(
|
||||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
|
MasteryShape(
|
||||||
|
modifier = Modifier.padding(top = 4.dp, end = 2.dp),
|
||||||
|
multiplier = if (skill.occupation) 1 else 0,
|
||||||
|
)
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
style = MaterialTheme.typography.body1,
|
style = MaterialTheme.typography.body1,
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,11 @@ import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
|
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio
|
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.roll.DifficultyUio.Difficulty
|
import com.pixelized.desktop.lwa.ui.screen.roll.DifficultyUio.Difficulty
|
||||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||||
|
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
|
||||||
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
||||||
import com.pixelized.shared.lwa.usecase.SkillStepUseCase
|
import com.pixelized.shared.lwa.usecase.SkillStepUseCase
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
@ -32,9 +33,9 @@ import org.jetbrains.compose.resources.getString
|
||||||
|
|
||||||
class RollViewModel(
|
class RollViewModel(
|
||||||
private val characterSheetRepository: CharacterSheetRepository,
|
private val characterSheetRepository: CharacterSheetRepository,
|
||||||
private val rollHistoryRepository: RollHistoryRepository,
|
|
||||||
private val skillComputation: ExpressionUseCase,
|
private val skillComputation: ExpressionUseCase,
|
||||||
private val skillStepUseCase: SkillStepUseCase,
|
private val skillStepUseCase: SkillStepUseCase,
|
||||||
|
private val networkRepository: NetworkRepository,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private lateinit var sheet: CharacterSheet
|
private lateinit var sheet: CharacterSheet
|
||||||
|
|
@ -205,7 +206,7 @@ class RollViewModel(
|
||||||
value = roll,
|
value = roll,
|
||||||
)
|
)
|
||||||
launch {
|
launch {
|
||||||
rollHistoryRepository.share(
|
val payload = RollMessage(
|
||||||
characterId = sheet.id,
|
characterId = sheet.id,
|
||||||
skillLabel = _rollTitle.value.label,
|
skillLabel = _rollTitle.value.label,
|
||||||
rollDifficulty = when (_rollDifficulty.value?.difficulty) {
|
rollDifficulty = when (_rollDifficulty.value?.difficulty) {
|
||||||
|
|
@ -219,6 +220,9 @@ class RollViewModel(
|
||||||
rollSuccessLimit = rollStep?.success?.last,
|
rollSuccessLimit = rollStep?.success?.last,
|
||||||
resultLabel = success,
|
resultLabel = success,
|
||||||
)
|
)
|
||||||
|
networkRepository.share(
|
||||||
|
payload = payload,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import io.ktor.websocket.readText
|
import io.ktor.websocket.readText
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.encodeToJsonElement
|
|
||||||
|
|
||||||
fun Json.decodeFromFrame(frame: Frame.Text): Message {
|
fun Json.decodeFromFrame(frame: Frame.Text): Message {
|
||||||
val json = frame.readText()
|
val json = frame.readText()
|
||||||
|
|
@ -12,6 +11,6 @@ fun Json.decodeFromFrame(frame: Frame.Text): Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Json.encodeToFrame(message: Message): Frame {
|
fun Json.encodeToFrame(message: Message): Frame {
|
||||||
val json = encodeToJsonElement(message)
|
val json = encodeToString(message)
|
||||||
return Frame.Text(text = json.toString())
|
return Frame.Text(text = json)
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.pixelized.desktop.lwa.utils.extention
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithCache
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Size
|
||||||
|
import androidx.compose.ui.geometry.isSimple
|
||||||
|
import androidx.compose.ui.graphics.*
|
||||||
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
|
import androidx.compose.ui.graphics.drawscope.withTransform
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modify element to add border with appearance specified with a [border] and a [shape], pad the
|
||||||
|
* content by the [BorderStroke.width] and clip it.
|
||||||
|
*
|
||||||
|
* @sample androidx.compose.foundation.samples.BorderSample()
|
||||||
|
*
|
||||||
|
* @param border [BorderStroke] class that specifies border appearance, such as size and color
|
||||||
|
* @param shape shape of the border
|
||||||
|
*/
|
||||||
|
fun Modifier.dashedBorder(border: BorderStroke, shape: Shape = RectangleShape, on: Dp, off: Dp) =
|
||||||
|
dashedBorder(width = border.width, brush = border.brush, shape = shape, on, off)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a [Modifier] that adds border with appearance specified with [width], [color] and a
|
||||||
|
* [shape], pads the content by the [width] and clips it.
|
||||||
|
*
|
||||||
|
* @sample androidx.compose.foundation.samples.BorderSampleWithDataClass()
|
||||||
|
*
|
||||||
|
* @param width width of the border. Use [Dp.Hairline] for a hairline border.
|
||||||
|
* @param color color to paint the border with
|
||||||
|
* @param shape shape of the border
|
||||||
|
* @param on the size of the solid part of the dashes
|
||||||
|
* @param off the size of the space between dashes
|
||||||
|
*/
|
||||||
|
fun Modifier.dashedBorder(width: Dp, color: Color, shape: Shape = RectangleShape, on: Dp, off: Dp) =
|
||||||
|
dashedBorder(width, SolidColor(color), shape, on, off)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a [Modifier] that adds border with appearance specified with [width], [brush] and a
|
||||||
|
* [shape], pads the content by the [width] and clips it.
|
||||||
|
*
|
||||||
|
* @sample androidx.compose.foundation.samples.BorderSampleWithBrush()
|
||||||
|
*
|
||||||
|
* @param width width of the border. Use [Dp.Hairline] for a hairline border.
|
||||||
|
* @param brush brush to paint the border with
|
||||||
|
* @param shape shape of the border
|
||||||
|
*/
|
||||||
|
fun Modifier.dashedBorder(width: Dp, brush: Brush, shape: Shape, on: Dp, off: Dp): Modifier =
|
||||||
|
this.then(
|
||||||
|
Modifier.drawWithCache {
|
||||||
|
val outline: Outline = shape.createOutline(size, layoutDirection, this)
|
||||||
|
val borderSize = if (width == Dp.Hairline) 1f else width.toPx()
|
||||||
|
|
||||||
|
var insetOutline: Outline? = null // outline used for roundrect/generic shapes
|
||||||
|
var stroke: Stroke? = null // stroke to draw border for all outline types
|
||||||
|
var pathClip: Path? = null // path to clip roundrect/generic shapes
|
||||||
|
var inset = 0f // inset to translate before drawing the inset outline
|
||||||
|
// path to draw generic shapes or roundrects with different corner radii
|
||||||
|
var insetPath: Path? = null
|
||||||
|
if (borderSize > 0 && size.minDimension > 0f) {
|
||||||
|
if (outline is Outline.Rectangle) {
|
||||||
|
stroke = Stroke(
|
||||||
|
borderSize, pathEffect = PathEffect.dashPathEffect(
|
||||||
|
floatArrayOf(on.toPx(), off.toPx())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
// Multiplier to apply to the border size to get a stroke width that is
|
||||||
|
// large enough to cover the corners while not being too large to overly
|
||||||
|
// square off the internal shape. The resultant shape will be
|
||||||
|
// clipped to the desired shape. Any value lower will show artifacts in
|
||||||
|
// the corners of shapes. A value too large will always square off
|
||||||
|
// the internal shape corners. For example, for a rounded rect border
|
||||||
|
// a large multiplier will always have squared off edges within the
|
||||||
|
// inner section of the stroke, however, having a smaller multiplier
|
||||||
|
// will still keep the rounded effect for the inner section of the
|
||||||
|
// border
|
||||||
|
val strokeWidth = 1.2f * borderSize
|
||||||
|
inset = borderSize - strokeWidth / 2
|
||||||
|
val insetSize = Size(
|
||||||
|
size.width - inset * 2,
|
||||||
|
size.height - inset * 2
|
||||||
|
)
|
||||||
|
insetOutline = shape.createOutline(insetSize, layoutDirection, this)
|
||||||
|
stroke = Stroke(
|
||||||
|
strokeWidth, pathEffect = PathEffect.dashPathEffect(
|
||||||
|
floatArrayOf(on.toPx(), off.toPx())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
pathClip = when (outline) {
|
||||||
|
is Outline.Rounded -> {
|
||||||
|
Path().apply { addRoundRect(outline.roundRect) }
|
||||||
|
}
|
||||||
|
|
||||||
|
is Outline.Generic -> {
|
||||||
|
outline.path
|
||||||
|
}
|
||||||
|
// should not get here because we check for Outline.Rectangle above
|
||||||
|
else -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insetPath = when {
|
||||||
|
// Rounded rect with non equal corner radii needs a path to be pre-translated
|
||||||
|
insetOutline is Outline.Rounded && !insetOutline.roundRect.isSimple -> {
|
||||||
|
Path().apply {
|
||||||
|
addRoundRect(insetOutline.roundRect)
|
||||||
|
translate(Offset(inset, inset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generic paths must be created and pre-translated
|
||||||
|
insetOutline is Outline.Generic -> {
|
||||||
|
|
||||||
|
Path().apply {
|
||||||
|
addPath(insetOutline.path, Offset(inset, inset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Drawing a round rect with equal corner radii without usage of a path
|
||||||
|
else -> {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDrawWithContent {
|
||||||
|
drawContent()
|
||||||
|
// Only draw the border if a have a valid stroke parameter. If we have
|
||||||
|
// an invalid border size we will just draw the content
|
||||||
|
if (stroke != null) {
|
||||||
|
if (insetOutline != null && pathClip != null) {
|
||||||
|
val isSimpleRoundRect =
|
||||||
|
insetOutline is Outline.Rounded && insetOutline.roundRect.isSimple
|
||||||
|
withTransform({
|
||||||
|
clipPath(pathClip)
|
||||||
|
// we are drawing the round rect not as a path so we must
|
||||||
|
// translate ourselves othe
|
||||||
|
if (isSimpleRoundRect) {
|
||||||
|
translate(inset, inset)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
if (isSimpleRoundRect) {
|
||||||
|
// If we don't have an insetPath then we are drawing
|
||||||
|
// a simple round rect with the corner radii all identical
|
||||||
|
val rrect = (insetOutline as Outline.Rounded).roundRect
|
||||||
|
drawRoundRect(
|
||||||
|
brush = brush,
|
||||||
|
topLeft = Offset(rrect.left, rrect.top),
|
||||||
|
size = Size(rrect.width, rrect.height),
|
||||||
|
cornerRadius = rrect.topLeftCornerRadius,
|
||||||
|
style = stroke
|
||||||
|
)
|
||||||
|
} else if (insetPath != null) {
|
||||||
|
drawPath(insetPath, brush, style = stroke)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Rectangular border fast path
|
||||||
|
val strokeWidth = stroke.width
|
||||||
|
val halfStrokeWidth = strokeWidth / 2
|
||||||
|
drawRect(
|
||||||
|
brush = brush,
|
||||||
|
topLeft = Offset(halfStrokeWidth, halfStrokeWidth),
|
||||||
|
size = Size(
|
||||||
|
size.width - strokeWidth,
|
||||||
|
size.height - strokeWidth
|
||||||
|
),
|
||||||
|
style = stroke
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
@ -17,6 +17,7 @@ dependencies {
|
||||||
implementation(projects.shared)
|
implementation(projects.shared)
|
||||||
implementation(libs.logback)
|
implementation(libs.logback)
|
||||||
implementation(libs.koin.ktor)
|
implementation(libs.koin.ktor)
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
implementation(libs.ktor.server.core)
|
implementation(libs.ktor.server.core)
|
||||||
implementation(libs.ktor.server.netty)
|
implementation(libs.ktor.server.netty)
|
||||||
implementation(libs.ktor.server.websockets)
|
implementation(libs.ktor.server.websockets)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import com.pixelized.shared.lwa.protocol.websocket.Message
|
||||||
import io.ktor.websocket.Frame
|
import io.ktor.websocket.Frame
|
||||||
import io.ktor.websocket.readText
|
import io.ktor.websocket.readText
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.encodeToJsonElement
|
|
||||||
|
|
||||||
fun Json.decodeFromFrame(frame: Frame.Text): Message {
|
fun Json.decodeFromFrame(frame: Frame.Text): Message {
|
||||||
val json = frame.readText()
|
val json = frame.readText()
|
||||||
|
|
@ -12,6 +12,6 @@ fun Json.decodeFromFrame(frame: Frame.Text): Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Json.encodeToFrame(message: Message): Frame {
|
fun Json.encodeToFrame(message: Message): Frame {
|
||||||
val json = encodeToJsonElement(message)
|
val json = encodeToString(message)
|
||||||
return Frame.Text(text = json.toString())
|
return Frame.Text(text = json)
|
||||||
}
|
}
|
||||||
|
|
@ -81,7 +81,8 @@ class LocalServer {
|
||||||
val job = launch {
|
val job = launch {
|
||||||
// send local message to the clients
|
// send local message to the clients
|
||||||
engine.webSocket.collect { message ->
|
engine.webSocket.collect { message ->
|
||||||
send(json.encodeToFrame(message))
|
val frame = json.encodeToFrame(message)
|
||||||
|
send(frame)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runCatching {
|
runCatching {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import kotlinx.serialization.Serializable
|
||||||
data class RollMessage(
|
data class RollMessage(
|
||||||
val characterId: String,
|
val characterId: String,
|
||||||
val skillLabel: String,
|
val skillLabel: String,
|
||||||
val resultLabel: String?,
|
val resultLabel: String? = null,
|
||||||
val rollDifficulty: String?,
|
val rollDifficulty: String? = null,
|
||||||
val rollValue: Int,
|
val rollValue: Int,
|
||||||
val rollSuccessLimit: Int?,
|
val rollSuccessLimit: Int? = null,
|
||||||
) : MessagePayload
|
) : MessagePayload
|
||||||
Loading…
Add table
Add a link
Reference in a new issue