Fix some stuff on the old UI (diminished & edit?)

This commit is contained in:
Thomas Andres Gomez 2025-02-27 22:42:10 +01:00
parent f51a83cf6e
commit 1bf0cb7c0a
15 changed files with 448 additions and 366 deletions

View file

@ -32,7 +32,7 @@ kotlin {
implementation(libs.koin.compose.viewmodel)
// composable component.
implementation(libs.coil.compose)
implementation(libs.coil.network)
implementation(libs.coil.network.ktor)
// network
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.serialization.json)
@ -77,6 +77,9 @@ compose.desktop {
buildTypes.release.proguard {
obfuscate.set(false) // Obfuscation doesn't work because of netty.
// optimize.set(false)
// isEnabled.set(false)
configurationFiles.from(project.file("compose-desktop.pro"))
}
}

View file

@ -11,6 +11,8 @@
# OkHttp comming from COIL.
-dontwarn okhttp3.internal.platform.**
-keep class coil3.compose.** { *; }
-keep class coil3.network.ktor3.** { *; }
# Serialization
-keep class io.ktor.serialization.kotlinx.json.** { *; }

View file

@ -85,10 +85,10 @@ class CharacterSheetStore(
) {
try {
client.deleteCharacter(id = characterId)
_detailFlow.delete(characterId = characterId)
} catch (exception: Exception) {
}
_detailFlow.delete(characterId = characterId)
}
// endregion

View file

@ -34,6 +34,7 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent
import com.pixelized.desktop.lwa.ui.composable.blur.rememberBlurContentController
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
@ -41,6 +42,7 @@ import com.pixelized.desktop.lwa.ui.composable.character.characteristic.Characte
import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToOldMainPage
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToRollHistory
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailPanel
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDiminishedViewModel
@ -51,6 +53,7 @@ import com.pixelized.desktop.lwa.ui.screen.roll.RollPage
import com.pixelized.desktop.lwa.ui.screen.roll.RollViewModel
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
import lwacharactersheet.composeapp.generated.resources.ic_table_24dp
import org.jetbrains.compose.resources.painterResource
import org.koin.compose.viewmodel.koinViewModel
@ -74,6 +77,7 @@ fun MainPage(
}
}
val windows = LocalWindowController.current
val screen = LocalScreenController.current
val scope = rememberCoroutineScope()
val blurController = rememberBlurContentController()
@ -91,6 +95,16 @@ fun MainPage(
Toolbar(
title = campaignViewModel.title.collectAsState(initial = "").value,
actions = {
IconButton(
onClick = {
windows.navigateToRollHistory()
},
) {
Icon(
painter = painterResource(Res.drawable.ic_d20_24dp),
contentDescription = null,
)
}
IconButton(
onClick = {
screen.navigateToOldMainPage()

View file

@ -1,8 +1,10 @@
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetSkillUio
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Node
import com.pixelized.desktop.lwa.ui.screen.roll.RollActionUio
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.campaign.Campaign
@ -70,71 +72,113 @@ class CharacterSheetFactory(
id = CharacteristicId.STR,
label = getString(Res.string.character_sheet__characteristics__str),
value = "${alteredSheet.strength}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__str),
description = getString(Res.string.tooltip__characteristics__strength),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__str),
rollAction = "1d100",
rollSuccessValue = alteredSheet.strength * 5 - instance.diminished,
),
),
Characteristic(
id = CharacteristicId.DEX,
label = getString(Res.string.character_sheet__characteristics__dex),
value = "${alteredSheet.dexterity}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__dex),
description = getString(Res.string.tooltip__characteristics__dexterity),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__dex),
rollAction = "1d100",
rollSuccessValue = alteredSheet.dexterity * 5 - instance.diminished,
),
),
Characteristic(
id = CharacteristicId.CON,
label = getString(Res.string.character_sheet__characteristics__con),
value = "${alteredSheet.constitution}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__con),
description = getString(Res.string.tooltip__characteristics__constitution),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__con),
rollAction = "1d100",
rollSuccessValue = alteredSheet.constitution * 5 - instance.diminished,
),
),
Characteristic(
id = CharacteristicId.HEI,
label = getString(Res.string.character_sheet__characteristics__hei),
value = "${alteredSheet.height}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__hei),
description = getString(Res.string.tooltip__characteristics__height),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__hei),
rollAction = "1d100",
rollSuccessValue = alteredSheet.height * 5 - instance.diminished,
),
),
Characteristic(
id = CharacteristicId.INT,
label = getString(Res.string.character_sheet__characteristics__int),
value = "${alteredSheet.intelligence}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__int),
description = getString(Res.string.tooltip__characteristics__intelligence),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__int),
rollAction = "1d100",
rollSuccessValue = alteredSheet.intelligence * 5 - instance.diminished,
),
),
Characteristic(
id = CharacteristicId.POW,
label = getString(Res.string.character_sheet__characteristics__pow),
value = "${alteredSheet.power}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__pow),
description = getString(Res.string.tooltip__characteristics__power),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__pow),
rollAction = "1d100",
rollSuccessValue = alteredSheet.power * 5 - instance.diminished,
),
),
Characteristic(
id = CharacteristicId.CHA,
label = getString(Res.string.character_sheet__characteristics__cha),
value = "${alteredSheet.charisma}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__characteristics__cha),
description = getString(Res.string.tooltip__characteristics__charisma),
),
editable = false,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = getString(Res.string.character_sheet__characteristics__cha),
rollAction = "1d100",
rollSuccessValue = alteredSheet.charisma * 5 - instance.diminished,
),
),
),
subCharacteristics = listOf(
@ -142,139 +186,170 @@ class CharacterSheetFactory(
id = CharacteristicId.MOV,
label = getString(Res.string.character_sheet__sub_characteristics__movement),
value = "${alteredSheet.movement}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__movement),
description = getString(Res.string.tooltip__sub_characteristics__movement),
),
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.HP,
label = getString(Res.string.character_sheet__sub_characteristics__hit_point),
value = alteredSheet.maxHp.let { maxHp -> "${maxHp - instance.damage}/${maxHp}" },
editable = true,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__hit_point),
description = getString(Res.string.tooltip__sub_characteristics__hit_point),
),
editable = true,
roll = null,
),
Characteristic(
id = CharacteristicId.PP,
label = getString(Res.string.character_sheet__sub_characteristics__power_point),
value = alteredSheet.maxPp.let { maxPp -> "${maxPp - instance.power}/${maxPp}" },
editable = true,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__power_point),
description = getString(Res.string.tooltip__sub_characteristics__power_point),
),
editable = true,
roll = null,
),
Characteristic(
id = CharacteristicId.DMG,
label = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
value = alteredSheet.damageBonus,
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
description = getString(Res.string.tooltip__sub_characteristics__bonus_damage),
),
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.ARMOR,
label = getString(Res.string.character_sheet__sub_characteristics__armor),
value = "${alteredSheet.armor}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__armor),
description = getString(Res.string.tooltip__sub_characteristics__armor),
),
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.LB,
label = getString(Res.string.character_sheet__sub_characteristics__learning),
value = "${alteredSheet.learning}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__learning),
description = getString(Res.string.tooltip__sub_characteristics__learning),
),
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.GHP,
label = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
value = "${alteredSheet.hpGrow}",
editable = false,
tooltips = TooltipUio(
title = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
description = getString(Res.string.tooltip__sub_characteristics__hp_grow),
),
editable = false,
roll = null,
),
),
commonSkills = characterSheet.commonSkills.map { skill ->
val value = skillUseCase.computeSkillValue(
sheet = characterSheet,
skill = skill,
diminished = instance.diminished,
alterations = alterations,
)
Node(
id = skill.id,
label = skill.label,
value = skillUseCase.computeSkillValue(
sheet = characterSheet,
skill = skill,
diminished = instance.diminished,
alterations = alterations,
),
value = value,
used = skill.used,
tooltips = skill.description?.let {
TooltipUio(
title = skill.label,
description = it,
)
},
used = skill.used,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = skill.label,
rollAction = "1d100",
rollSuccessValue = value,
),
)
},
specialSKills = characterSheet.specialSkills.map { skill ->
val value = skillUseCase.computeSkillValue(
sheet = characterSheet,
skill = skill,
diminished = instance.diminished,
alterations = alterations,
)
Node(
id = skill.id,
label = skill.label,
tooltips = skill.description?.takeIf { it.isNotBlank() }?.let { description ->
value = value,
used = skill.used,
tooltips = skill.description?.let {
TooltipUio(
title = skill.label,
description = description,
description = it,
)
},
value = skillUseCase.computeSkillValue(
sheet = characterSheet,
skill = skill,
diminished = instance.diminished,
alterations = alterations,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = skill.label,
rollAction = "1d100",
rollSuccessValue = value,
),
used = skill.used,
)
},
magicsSkills = characterSheet.magicSkills.map { skill ->
val value = skillUseCase.computeSkillValue(
sheet = characterSheet,
skill = skill,
diminished = instance.diminished,
alterations = alterations,
)
Node(
id = skill.id,
label = skill.label,
tooltips = skill.description?.takeIf { it.isNotBlank() }?.let { description ->
value = value,
used = skill.used,
tooltips = skill.description?.let {
TooltipUio(
title = skill.label,
description = description,
description = it,
)
},
value = skillUseCase.computeSkillValue(
sheet = characterSheet,
skill = skill,
diminished = instance.diminished,
alterations = alterations,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = skill.label,
rollAction = "1d100",
rollSuccessValue = value,
),
used = skill.used,
)
},
actions = characterSheet.actions.mapNotNull {
if (it.roll.isNotEmpty()) {
CharacterSheetPageUio.Roll(
if (it.roll.isEmpty()) return@mapNotNull null
CharacterSheetPageUio.Roll(
label = it.label,
value = it.roll,
roll = RollActionUio(
characterSheetId = alteredSheet.id,
label = it.label,
value = it.roll,
rollAction = it.roll,
rollSuccessValue = null,
)
} else {
null
}
)
}
)
}

View file

@ -45,6 +45,7 @@ import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@ -67,6 +68,7 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetP
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialog
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialog
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.preview.rememberCharacterSheetPreview
import com.pixelized.desktop.lwa.ui.screen.roll.RollActionUio
import com.pixelized.desktop.lwa.ui.screen.roll.RollPage
import com.pixelized.desktop.lwa.ui.screen.roll.RollViewModel
import com.pixelized.desktop.lwa.utils.preview.ContentPreview
@ -105,6 +107,7 @@ data class CharacterSheetPageUio(
val value: String,
val editable: Boolean,
val tooltips: TooltipUio?,
val roll: RollActionUio?,
)
@Stable
@ -112,14 +115,16 @@ data class CharacterSheetPageUio(
val id: String,
val label: String,
val value: Int,
val tooltips: TooltipUio? = null,
val used: Boolean,
val tooltips: TooltipUio? = null,
val roll: RollActionUio,
)
@Stable
data class Roll(
val label: String,
val value: String,
val roll: RollActionUio?,
)
}
@ -133,6 +138,7 @@ fun CharacterSheetPage(
val window = LocalWindow.current
val scope = rememberCoroutineScope()
val blurController = remember { BlurContentController() }
val sheet = viewModel.sheetFlow.collectAsState()
Surface(
modifier = Modifier.fillMaxSize(),
@ -140,11 +146,11 @@ fun CharacterSheetPage(
BlurContent(
controller = blurController,
content = {
viewModel.sheet.value?.let { sheet ->
sheet.value?.let { sheet ->
CharacterSheetPageContent(
modifier = Modifier.fillMaxSize(),
characterSheet = sheet,
diminishedValue = viewModel.diminishedValue,
diminishedValue = viewModel.diminishedValueFlow.collectAsState(),
onDiminished = {
blurController.show()
scope.launch {
@ -162,11 +168,9 @@ fun CharacterSheetPage(
viewModel.showConfirmCharacterDeletionDialog()
},
onCharacteristic = { characteristic ->
if (characteristic.roll == null) return@CharacterSheetPageContent
rollViewModel.prepareRoll(characteristic.roll)
blurController.show()
rollViewModel.prepareRoll(
sheet = sheet,
characteristic = characteristic
)
viewModel.showRollOverlay()
},
onSubCharacteristic = {
@ -177,7 +181,7 @@ fun CharacterSheetPage(
},
onSkill = { node ->
blurController.show()
rollViewModel.prepareRoll(sheet = sheet, node = node)
rollViewModel.prepareRoll(node.roll)
viewModel.showRollOverlay()
},
onUseSkill = viewModel::onUseSkill,
@ -233,11 +237,11 @@ fun CharacterSheetPage(
DiminishedStatDialog(
dialog = viewModel.diminishedDialog,
onConfirm = {
viewModel.changeDiminished(
dialog = it
)
viewModel.hideDiminishedDialog()
blurController.hide()
scope.launch {
viewModel.changeDiminished(dialog = it)
viewModel.hideDiminishedDialog()
blurController.hide()
}
},
onDismissRequest = {
viewModel.hideDiminishedDialog()

View file

@ -1,10 +1,9 @@
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@ -15,13 +14,18 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet__diminished__label
import javax.swing.UIManager.getString
private typealias CSDCDialogUio = CharacterSheetDeleteConfirmationDialogUio
@ -46,16 +50,12 @@ class CharacterSheetViewModel(
private val _diminishedDialog = mutableStateOf<DiminishedStatDialogUio?>(null)
val diminishedDialog: State<DiminishedStatDialogUio?> get() = _diminishedDialog
// TODO
// private val diminishedValueFlow = characterRepository.characterDiminishedFlow(id = argument.id)
val diminishedValue: State<Int?>
@Composable
// get() = diminishedValueFlow.collectAsState { it ->
// it.takeIf { it > 0 }
// }
get() = remember { mutableStateOf(null) }
val diminishedValueFlow: StateFlow<Int?> = campaignRepository
.characterInstanceFlow(id = argument.characterInstanceId)
.map { instance -> instance.diminished.takeIf { it > 0 } }
.stateIn(scope = viewModelScope, SharingStarted.Lazily, null)
private val sheetFlow = combine(
val sheetFlow = combine(
characterRepository.characterDetailFlow(characterId = argument.characterInstanceId.characterSheetId),
campaignRepository.campaignFlow,
alteration.alterationsFlow(characterId = argument.characterInstanceId),
@ -72,9 +72,6 @@ class CharacterSheetViewModel(
started = SharingStarted.Eagerly,
initialValue = null,
)
val sheet: State<CharacterSheetPageUio?>
@Composable
get() = sheetFlow.collectAsState()
suspend fun deleteCharacter(id: String) {
characterRepository.deleteCharacter(characterId = id)
@ -93,14 +90,13 @@ class CharacterSheetViewModel(
}
fun showConfirmCharacterDeletionDialog() {
characterRepository.characterPreview(
val preview = characterRepository.characterPreview(
characterId = argument.characterInstanceId.characterSheetId
)?.let { preview ->
_displayDeleteConfirmationDialog.value = CharacterSheetDeleteConfirmationDialogUio(
id = preview.id,
name = preview.name,
)
}
) ?: return
_displayDeleteConfirmationDialog.value = CharacterSheetDeleteConfirmationDialogUio(
id = preview.id,
name = preview.name,
)
}
fun hideConfirmCharacterDeletionDialog() {
@ -115,32 +111,43 @@ class CharacterSheetViewModel(
_displayRollOverlay.value = false
}
suspend fun showDiminishedDialog() {
// val diminished = characterRepository.characterDiminishedFlow(id = argument.id).value
// val textFieldValue =
// mutableStateOf(TextFieldValue("$diminished", selection = TextRange(index = 0)))
// _diminishedDialog.value = DiminishedStatDialogUio(
// id = argument.id,
// label = getString(resource = Res.string.character_sheet__diminished__label),
// value = { textFieldValue.value },
// onValueChange = { value ->
// textFieldValue.value = when (value.text.toIntOrNull()?.takeIf { it >= 0 }) {
// null -> TextFieldValue("0", selection = TextRange(index = 0))
// else -> value
// }
// },
// )
fun showDiminishedDialog() {
val diminished = campaignRepository
.characterInstance(characterInstanceId = argument.characterInstanceId)
.diminished
val textFieldValue = mutableStateOf(
TextFieldValue(
text = "$diminished",
selection = TextRange(index = 0),
)
)
_diminishedDialog.value = DiminishedStatDialogUio(
characterInstanceId = argument.characterInstanceId,
label = getString(Res.string.character_sheet__diminished__label),
value = { textFieldValue.value },
onValueChange = { value ->
textFieldValue.value = when (value.text.toIntOrNull()?.takeIf { it >= 0 }) {
null -> TextFieldValue("0", selection = TextRange(index = 0))
else -> value
}
},
)
}
fun hideDiminishedDialog() {
_diminishedDialog.value = null
}
fun changeDiminished(dialog: DiminishedStatDialogUio) {
// val value = dialog.value().text.toIntOrNull() ?: 0
// characterRepository.setDiminishedForCharacter(
// id = dialog.id,
// diminished = value,
// )
suspend fun changeDiminished(dialog: DiminishedStatDialogUio) {
val diminished = dialog.value().text.toIntOrNull() ?: 0
network.share(
payload = CampaignMessage.UpdateDiminished(
characterSheetId = dialog.characterInstanceId.characterSheetId,
instanceId = dialog.characterInstanceId.instanceId,
diminished = diminished,
)
)
}
}

View file

@ -22,6 +22,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.DEX,
@ -29,6 +30,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.CON,
@ -36,6 +38,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.HEI,
@ -43,6 +46,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.INT,
@ -50,6 +54,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.POW,
@ -57,6 +62,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.CHA,
@ -64,6 +70,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
),
subCharacteristics = listOf(
@ -73,6 +80,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "10",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.HP,
@ -80,6 +88,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "20/20",
tooltips = null,
editable = true,
roll = null,
),
Characteristic(
id = CharacteristicId.PP,
@ -87,6 +96,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "15/15",
tooltips = null,
editable = true,
roll = null,
),
Characteristic(
id = CharacteristicId.DMG,
@ -94,6 +104,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "1d4",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.ARMOR,
@ -101,6 +112,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "0",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.LB,
@ -108,6 +120,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "0",
tooltips = null,
editable = false,
roll = null,
),
Characteristic(
id = CharacteristicId.GHP,
@ -115,6 +128,7 @@ fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
value = "5",
tooltips = null,
editable = false,
roll = null,
),
),
commonSkills = emptyList(),

View file

@ -1,5 +1,6 @@
package com.pixelized.desktop.lwa.ui.screen.main
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -31,9 +32,11 @@ import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToNetw
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheet
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheetEdit
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToRollHistory
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.Toolbar
import com.pixelized.shared.lwa.model.campaign.Campaign
import kotlinx.coroutines.runBlocking
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.app_name
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__create__title
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
import lwacharactersheet.composeapp.generated.resources.ic_file_24dp
@ -63,53 +66,47 @@ fun OldMainPage(
val screen = LocalScreenController.current
val characters = viewModel.characters.collectAsState()
val npcs = viewModel.npcs.collectAsState()
val enableRollHistory = viewModel.enableRollHistoryFlow.collectAsState()
Surface(
modifier = Modifier.fillMaxSize(),
) {
Box(
modifier = Modifier
.verticalScroll(state = rememberScrollState())
.fillMaxSize()
.padding(horizontal = 16.dp),
contentAlignment = Alignment.Center,
) {
MainPageContent(
characters = characters,
npcs = npcs,
enableRollHistory = viewModel.enableRollHistory,
onCharacter = {
window.navigateToCharacterSheet(
characterId = it.id,
title = it.name,
)
},
onCreateCharacter = {
window.navigateToCharacterSheetEdit(
characterId = null,
title = runBlocking { getString(Res.string.character_sheet_edit__create__title) },
)
},
onRollHistory = {
window.navigateToRollHistory()
},
onOpenSaveDirectory = {
viewModel.openSaveDirectory()
},
onNetwork = {
screen.navigateToNetwork()
},
onMainPage = {
screen.navigateToMainPage()
}
)
}
MainPageContent(
characters = characters,
npcs = npcs,
enableRollHistory = enableRollHistory,
onCharacter = {
window.navigateToCharacterSheet(
characterId = it.id,
title = it.name,
)
},
onCreateCharacter = {
window.navigateToCharacterSheetEdit(
characterId = null,
title = runBlocking { getString(Res.string.character_sheet_edit__create__title) },
)
},
onRollHistory = {
window.navigateToRollHistory()
},
onOpenSaveDirectory = {
viewModel.openSaveDirectory()
},
onNetwork = {
screen.navigateToNetwork()
},
onMainPage = {
screen.navigateToMainPage()
}
)
}
}
@Composable
fun MainPageContent(
modifier: Modifier = Modifier,
scrollState: ScrollState = rememberScrollState(),
characters: State<List<CharacterUio>>,
npcs: State<List<CharacterUio>>,
enableRollHistory: State<Boolean>,
@ -123,150 +120,164 @@ fun MainPageContent(
Column(
modifier = modifier,
) {
if (characters.value.isNotEmpty()) {
Column {
characters.value.forEach { sheet ->
TextButton(
onClick = { onCharacter(sheet) },
Toolbar(
title = runBlocking { getString(Res.string.app_name) },
actions = {
TextButton(
onClick = onMainPage,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_swords_24dp),
contentDescription = null,
)
Text(
modifier = Modifier.fillMaxWidth(),
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = sheet.name,
text = "Nouvelle interface utilisateur",
)
}
}
}
}
if (characters.value.isNotEmpty() && npcs.value.isNotEmpty()) {
Spacer(modifier = Modifier.height(height = 24.dp))
}
if (npcs.value.isNotEmpty()) {
)
Box(
modifier = Modifier
.verticalScroll(state = scrollState)
.fillMaxSize()
.padding(horizontal = 16.dp),
contentAlignment = Alignment.Center,
) {
Column {
npcs.value.forEach { sheet ->
TextButton(
onClick = { onCharacter(sheet) },
if (characters.value.isNotEmpty()) {
Column {
characters.value.forEach { sheet ->
TextButton(
onClick = { onCharacter(sheet) },
) {
Text(
modifier = Modifier.fillMaxWidth(),
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = sheet.name,
)
}
}
}
}
if (characters.value.isNotEmpty() && npcs.value.isNotEmpty()) {
Spacer(modifier = Modifier.height(height = 24.dp))
}
if (npcs.value.isNotEmpty()) {
Column {
npcs.value.forEach { sheet ->
TextButton(
onClick = { onCharacter(sheet) },
) {
Text(
modifier = Modifier.fillMaxWidth(),
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = sheet.name,
)
}
}
}
}
Spacer(modifier = Modifier.height(height = 24.dp))
TextButton(
onClick = onCreateCharacter,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_file_24dp),
contentDescription = null,
)
Text(
modifier = Modifier.fillMaxWidth(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = sheet.name,
text = stringResource(Res.string.main_page__create_action),
)
}
}
}
}
Spacer(modifier = Modifier.height(height = 24.dp))
TextButton(
onClick = onOpenSaveDirectory,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_folder_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__open_save_directory),
)
}
}
TextButton(
onClick = onCreateCharacter,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_file_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__create_action),
)
}
}
TextButton(
enabled = enableRollHistory.value,
onClick = onRollHistory,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_d20_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__roll_history_action),
)
}
}
TextButton(
onClick = onOpenSaveDirectory,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_folder_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__open_save_directory),
)
}
}
TextButton(
enabled = enableRollHistory.value,
onClick = onRollHistory,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_d20_24dp),
contentDescription = null,
)
Text(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
text = stringResource(Res.string.main_page__roll_history_action),
)
}
}
TextButton(
onClick = onNetwork,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_table_24dp),
contentDescription = null,
)
Text(
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = stringResource(Res.string.main_page__network_action),
)
}
}
TextButton(
onClick = onMainPage,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_swords_24dp),
contentDescription = null,
)
Text(
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = "Nouvelle interface utilisateur",
)
TextButton(
onClick = onNetwork,
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
painter = painterResource(Res.drawable.ic_table_24dp),
contentDescription = null,
)
Text(
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Start,
maxLines = 1,
text = stringResource(Res.string.main_page__network_action),
)
}
}
}
}
}

View file

@ -1,14 +1,11 @@
package com.pixelized.desktop.lwa.ui.screen.main
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lordcodes.turtle.shellRun
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.utils.extention.collectAsState
import com.pixelized.shared.lwa.OperatingSystem
import com.pixelized.shared.lwa.storePath
import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -78,10 +75,13 @@ class MainPageViewModel(
initialValue = emptyList(),
)
private val networkStatus = networkRepository.status
val enableRollHistory: State<Boolean>
@Composable
get() = networkStatus.collectAsState { it == NetworkRepository.Status.CONNECTED }
val enableRollHistoryFlow = networkRepository.status
.map { it == NetworkRepository.Status.CONNECTED }
.stateIn(
scope = viewModelScope,
started = SharingStarted.Lazily,
initialValue = false,
)
fun openSaveDirectory(
os: OperatingSystem = OperatingSystem.current,

View file

@ -34,6 +34,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
@ -60,7 +61,25 @@ data class NetworkPageUio(
val enableFields: Boolean,
val enableActions: Boolean,
val enableCancel: Boolean,
)
) {
companion object {
fun empty(
player: String = "",
host: String = "",
port: String = "",
enableFields: Boolean = false,
enableActions: Boolean = false,
enableCancel: Boolean = false,
) = NetworkPageUio(
player = player,
host = host,
port = port,
enableFields = enableFields,
enableActions = enableActions,
enableCancel = enableCancel,
)
}
}
@Composable
fun NetworkPage(
@ -82,7 +101,7 @@ fun NetworkPage(
) {
NetworkContent(
modifier = Modifier.fillMaxSize(),
player = viewModel.network,
player = viewModel.network.collectAsState(),
onBack = { screen.popBackStack() },
onPlayerChange = viewModel::onPlayerNameChange,
onHostChange = viewModel::onHostChange,

View file

@ -1,21 +1,19 @@
package com.pixelized.desktop.lwa.ui.screen.network
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.desktop.lwa.utils.extention.collectAsState
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class NetworkViewModel(
@ -38,23 +36,21 @@ class NetworkViewModel(
val controller: BlurContentController = BlurContentController()
val network: State<NetworkPageUio>
@Composable
@Stable
get() {
val player = settingsRepository.settingsFlow().collectAsState { it.playerName }
val status = networkRepository.status.collectAsState()
return remember {
derivedStateOf {
factory.convertToUio(
player = player.value,
status = status.value,
host = host.value,
port = port.value,
)
}
}
}
val network: StateFlow<NetworkPageUio> = combine(
settingsRepository.settingsFlow(),
networkRepository.status,
) { settings, status ->
factory.convertToUio(
player = settings.playerName,
status = status,
host = host.value,
port = port.value,
)
}.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = NetworkPageUio.empty()
)
fun onPlayerNameChange(player: String) {
settingsRepository.update(

View file

@ -59,35 +59,6 @@ class RollViewModel(
private val _displayOverlay = mutableStateOf(false)
val displayOverlay: State<Boolean> get() = _displayOverlay
@Deprecated(message = "@See prepareRoll(RollActionUio)")
fun prepareRoll(
sheet: CharacterSheetPageUio,
characteristic: CharacterSheetPageUio.Characteristic,
) {
// TODO characterSheetRepository.characterDiminishedFlow(id = sheet.id).value
val diminished = 0
prepareRoll(
characterSheetId = sheet.id,
label = characteristic.label,
rollAction = "1d100",
rollSuccessValue = (characteristic.value.toIntOrNull() ?: 0) * 5 - diminished,
)
}
@Deprecated(message = "@See prepareRoll(RollActionUio)")
fun prepareRoll(
sheet: CharacterSheetPageUio,
node: CharacterSheetPageUio.Node,
) {
prepareRoll(
characterSheetId = sheet.id,
label = node.label,
rollAction = "1d100",
rollSuccessValue = node.value,
)
}
@Deprecated(message = "@See prepareRoll(RollActionUio)")
fun prepareRoll(
sheet: CharacterSheetPageUio,

View file

@ -1,34 +0,0 @@
package com.pixelized.desktop.lwa.utils.extention
import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.withContext
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
@Suppress("StateFlowValueCalledInComposition")
@Composable
fun <T, R> StateFlow<T>.collectAsState(
context: CoroutineContext = EmptyCoroutineContext,
convert: (T) -> R,
): State<R> = collectAsState(
initial = value,
context = context,
convert = convert,
)
@Composable
fun <T, R> Flow<T>.collectAsState(
initial: T,
context: CoroutineContext = EmptyCoroutineContext,
convert: (T) -> R,
): State<R> = produceState(convert(initial), this, context) {
if (context == EmptyCoroutineContext) {
collect { value = convert(it) }
} else withContext(context) {
collect { value = convert(it) }
}
}