Add characteristic to the campagin detail panel.
This commit is contained in:
parent
29747dcb5c
commit
b6b135cd40
12 changed files with 690 additions and 331 deletions
|
|
@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.BlurredEdgeTreatment
|
||||
import androidx.compose.ui.draw.blur
|
||||
|
|
@ -36,6 +37,20 @@ class BlurContentController(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberBlurContentController(
|
||||
blurred: Boolean = false,
|
||||
blurredRadius: Dp = 8.dp,
|
||||
scrimColor: Color = LwaColorPalette.DefaultScrimColor,
|
||||
) = remember {
|
||||
BlurContentController(
|
||||
blurred = blurred,
|
||||
blurredRadius = blurredRadius,
|
||||
scrimColor = scrimColor,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun BlurContent(
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
|
|||
|
|
@ -33,9 +33,11 @@ class CharacterDetailCharacteristicDialogViewModel(
|
|||
}
|
||||
|
||||
suspend fun showSubCharacteristicDialog(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characterInstanceId: Campaign.CharacterInstance.Id?,
|
||||
characteristic: Characteristic,
|
||||
) {
|
||||
if (characterInstanceId == null) return
|
||||
|
||||
val sheet: CharacterSheet? = characterSheetRepository.characterDetail(
|
||||
characterSheetId = characterInstanceId.characterSheetId,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
|
|
@ -7,12 +13,14 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.key.Key
|
||||
|
|
@ -25,20 +33,29 @@ 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.ui.composable.blur.BlurContent
|
||||
import com.pixelized.desktop.lwa.ui.composable.blur.rememberBlurContentController
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialog
|
||||
import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetail
|
||||
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
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbon
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialog
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.roll.RollPage
|
||||
import com.pixelized.desktop.lwa.ui.screen.roll.RollViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@Composable
|
||||
fun CampaignScreen(
|
||||
characterDetailViewModel: CharacterDetailViewModel = koinViewModel(),
|
||||
characteristicDialogViewModel: CharacterDetailCharacteristicDialogViewModel = koinViewModel(),
|
||||
dismissedViewModel: CharacterDiminishedViewModel = koinViewModel(),
|
||||
networkViewModel: NetworkViewModel = koinViewModel(),
|
||||
rollViewModel: RollViewModel = koinViewModel(),
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
networkViewModel.connect()
|
||||
|
|
@ -55,48 +72,105 @@ fun CampaignScreen(
|
|||
}
|
||||
}
|
||||
|
||||
Surface {
|
||||
CampaignScreenLayout(
|
||||
val scope = rememberCoroutineScope()
|
||||
val blurController = rememberBlurContentController()
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
BlurContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
top = {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.height(32.dp)
|
||||
.fillMaxWidth(),
|
||||
elevation = 1.dp,
|
||||
) {
|
||||
controller = blurController
|
||||
) {
|
||||
CampaignScreenLayout(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
top = {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.height(32.dp)
|
||||
.fillMaxWidth(),
|
||||
elevation = 1.dp,
|
||||
) {
|
||||
|
||||
}
|
||||
},
|
||||
bottom = {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.height(48.dp)
|
||||
.fillMaxWidth(),
|
||||
elevation = 1.dp,
|
||||
) {
|
||||
}
|
||||
},
|
||||
bottom = {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.height(48.dp)
|
||||
.fillMaxWidth(),
|
||||
elevation = 1.dp,
|
||||
) {
|
||||
|
||||
}
|
||||
},
|
||||
main = {
|
||||
}
|
||||
},
|
||||
main = {
|
||||
|
||||
},
|
||||
leftOverlay = {
|
||||
PlayerRibbon(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
onCharacter = {
|
||||
characterDetailViewModel.showCharacter(id = it)
|
||||
},
|
||||
)
|
||||
},
|
||||
rightOverlay = {
|
||||
CharacterDetailPanel(
|
||||
modifier = Modifier
|
||||
.width(width = 128.dp * 4)
|
||||
.fillMaxHeight()
|
||||
.padding(all = 8.dp),
|
||||
blurController = blurController,
|
||||
detailViewModel = characterDetailViewModel,
|
||||
rollViewModel = rollViewModel,
|
||||
characterDiminishedViewModel = dismissedViewModel,
|
||||
characteristicDialogViewModel = characteristicDialogViewModel,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
targetState = rollViewModel.displayOverlay.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 64 }
|
||||
val exit = fadeOut() + slideOutVertically { 64 }
|
||||
enter togetherWith exit
|
||||
},
|
||||
leftOverlay = {
|
||||
PlayerRibbon(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
onCharacter = {
|
||||
characterDetailViewModel.showCharacter(id = it)
|
||||
) { roll ->
|
||||
when (roll) {
|
||||
true -> RollPage(
|
||||
viewModel = rollViewModel,
|
||||
onDismissRequest = {
|
||||
blurController.hide()
|
||||
rollViewModel.hideOverlay()
|
||||
},
|
||||
)
|
||||
},
|
||||
rightOverlay = {
|
||||
CharacterDetail(
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.fillMaxHeight(),
|
||||
detailViewModel = characterDetailViewModel,
|
||||
dismissedViewModel = dismissedViewModel,
|
||||
|
||||
else -> Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
CharacterSheetCharacteristicDialog(
|
||||
dialog = characteristicDialogViewModel.statChangeDialog,
|
||||
onConfirm = { dialog ->
|
||||
scope.launch {
|
||||
characteristicDialogViewModel.changeSubCharacteristic(
|
||||
characterInstanceId = dialog.characterInstanceId,
|
||||
characteristic = dialog.characteristic,
|
||||
value = dialog.value().text.toIntOrNull() ?: 0,
|
||||
)
|
||||
characteristicDialogViewModel.hideSubCharacteristicDialog()
|
||||
blurController.hide()
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
characteristicDialogViewModel.hideSubCharacteristicDialog()
|
||||
blurController.hide()
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,141 +6,150 @@ import androidx.compose.animation.ExitTransition
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
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
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialog
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogUio
|
||||
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.sheet.CharacterDetailSheet
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.roll.RollViewModel
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_close_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_heart_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_near_me
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_skull_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_water_drop_24dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@Stable
|
||||
data class CharacterDetailHeaderUio(
|
||||
val id: Campaign.CharacterInstance.Id,
|
||||
val portrait: String?,
|
||||
val name: String,
|
||||
val hp: String,
|
||||
val maxHp: String,
|
||||
val pp: String,
|
||||
val maxPp: String,
|
||||
val mov: String,
|
||||
data class CharacterDetailPanelUio(
|
||||
val characterInstanceId: Campaign.CharacterInstance.Id?,
|
||||
val header: StateFlow<CharacterDetailHeaderUio?>,
|
||||
val sheet: StateFlow<CharacterDetailSheetUio?>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterDetail(
|
||||
fun CharacterDetailPanel(
|
||||
modifier: Modifier = Modifier,
|
||||
dismissedViewModel: CharacterDiminishedViewModel,
|
||||
detailViewModel: CharacterDetailViewModel = koinViewModel(),
|
||||
characteristicDialogViewModel: CharacterDetailCharacteristicDialogViewModel = koinViewModel(),
|
||||
blurController: BlurContentController,
|
||||
detailViewModel: CharacterDetailViewModel,
|
||||
characteristicDialogViewModel: CharacterDetailCharacteristicDialogViewModel,
|
||||
characterDiminishedViewModel: CharacterDiminishedViewModel,
|
||||
rollViewModel: RollViewModel,
|
||||
) {
|
||||
val blurController = remember { BlurContentController() }
|
||||
val scope = rememberCoroutineScope()
|
||||
val detail = detailViewModel.detail.collectAsState()
|
||||
val detail: State<CharacterDetailPanelUio> = detailViewModel.detail.collectAsState()
|
||||
|
||||
AnimatedContent(
|
||||
CharacterDetailAnimatedPanel(
|
||||
modifier = modifier,
|
||||
targetState = detail.value,
|
||||
transitionSpec = {
|
||||
if (initialState?.id != targetState?.id) {
|
||||
(fadeIn() + slideInHorizontally { it / 2 }).togetherWith(fadeOut())
|
||||
} else {
|
||||
EnterTransition.None togetherWith ExitTransition.None
|
||||
detail = detail,
|
||||
onDismissRequest = {
|
||||
detailViewModel.hideCharacter()
|
||||
},
|
||||
onDiminished = {
|
||||
scope.launch {
|
||||
characterDiminishedViewModel.showDiminishedDialog(
|
||||
characterInstanceId = it
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
when (it) {
|
||||
null -> Box(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
},
|
||||
onHp = {
|
||||
scope.launch {
|
||||
blurController.show()
|
||||
characteristicDialogViewModel.showSubCharacteristicDialog(
|
||||
characterInstanceId = it,
|
||||
characteristic = Campaign.CharacterInstance.Characteristic.Damage,
|
||||
)
|
||||
}
|
||||
},
|
||||
onPp = {
|
||||
scope.launch {
|
||||
blurController.show()
|
||||
characteristicDialogViewModel.showSubCharacteristicDialog(
|
||||
characterInstanceId = it,
|
||||
characteristic = Campaign.CharacterInstance.Characteristic.Power,
|
||||
)
|
||||
}
|
||||
},
|
||||
onCharacteristic = {
|
||||
rollViewModel.prepareRoll(
|
||||
characterSheetId = detail.value.characterInstanceId?.characterSheetId!!,
|
||||
label = it.label,
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = (it.value.toIntOrNull() ?: 0) * 5,
|
||||
)
|
||||
blurController.show()
|
||||
rollViewModel.showOverlay()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(width = 128.dp * 4),
|
||||
) {
|
||||
CharacterDetailContent(
|
||||
@Composable
|
||||
fun CharacterDetailAnimatedPanel(
|
||||
modifier: Modifier = Modifier,
|
||||
detail: State<CharacterDetailPanelUio>,
|
||||
onDismissRequest: (id: Campaign.CharacterInstance.Id) -> Unit,
|
||||
onDiminished: (id: Campaign.CharacterInstance.Id) -> Unit,
|
||||
onHp: (id: Campaign.CharacterInstance.Id) -> Unit,
|
||||
onPp: (id: Campaign.CharacterInstance.Id) -> Unit,
|
||||
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier,
|
||||
) {
|
||||
AnimatedContent(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
targetState = detail.value,
|
||||
transitionSpec = {
|
||||
if (initialState.characterInstanceId != targetState.characterInstanceId) {
|
||||
val enter = fadeIn() + slideInHorizontally { it / 2 }
|
||||
val exit = fadeOut() + slideOutHorizontally { it / 2 }
|
||||
enter togetherWith exit
|
||||
} else {
|
||||
EnterTransition.None togetherWith ExitTransition.None
|
||||
}
|
||||
}
|
||||
) {
|
||||
when {
|
||||
it.characterInstanceId == null -> Box(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
)
|
||||
|
||||
else -> {
|
||||
Box(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
character = it,
|
||||
onDismissRequest = {
|
||||
detailViewModel.hideCharacter()
|
||||
},
|
||||
onDiminished = {
|
||||
scope.launch {
|
||||
dismissedViewModel.showDiminishedDialog(id = it.id)
|
||||
}
|
||||
},
|
||||
onHp = {
|
||||
scope.launch {
|
||||
characteristicDialogViewModel.showSubCharacteristicDialog(
|
||||
characterInstanceId = it.id,
|
||||
characteristic = Campaign.CharacterInstance.Characteristic.Damage,
|
||||
)
|
||||
}
|
||||
},
|
||||
onPp = {
|
||||
scope.launch {
|
||||
characteristicDialogViewModel.showSubCharacteristicDialog(
|
||||
characterInstanceId = it.id,
|
||||
characteristic = Campaign.CharacterInstance.Characteristic.Power,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
CharacterSheetCharacteristicDialog(
|
||||
dialog = characteristicDialogViewModel.statChangeDialog,
|
||||
onConfirm = { dialog ->
|
||||
scope.launch {
|
||||
characteristicDialogViewModel.changeSubCharacteristic(
|
||||
characterInstanceId = dialog.characterInstanceId,
|
||||
characteristic = dialog.characteristic,
|
||||
value = dialog.value().text.toIntOrNull() ?: 0,
|
||||
)
|
||||
characteristicDialogViewModel.hideSubCharacteristicDialog()
|
||||
blurController.hide()
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
characteristicDialogViewModel.hideSubCharacteristicDialog()
|
||||
blurController.hide()
|
||||
}
|
||||
)
|
||||
) {
|
||||
CharacterDetailContent(
|
||||
modifier = Modifier.matchParentSize(),
|
||||
header = it.header.collectAsState(),
|
||||
sheet = it.sheet.collectAsState(),
|
||||
onDismissRequest = { onDismissRequest(it.characterInstanceId) },
|
||||
onDiminished = { onDiminished(it.characterInstanceId) },
|
||||
onHp = { onHp(it.characterInstanceId) },
|
||||
onPp = { onPp(it.characterInstanceId) },
|
||||
onCharacteristic = onCharacteristic,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,169 +159,35 @@ fun CharacterDetail(
|
|||
@Composable
|
||||
fun CharacterDetailContent(
|
||||
modifier: Modifier = Modifier,
|
||||
character: CharacterDetailHeaderUio,
|
||||
header: State<CharacterDetailHeaderUio?>,
|
||||
sheet: State<CharacterDetailSheetUio?>,
|
||||
onDismissRequest: () -> Unit,
|
||||
onDiminished: () -> Unit,
|
||||
onHp: () -> Unit,
|
||||
onPp: () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier,
|
||||
) {
|
||||
Background(
|
||||
character = character,
|
||||
)
|
||||
Column {
|
||||
CharacterHeader(
|
||||
modifier = Modifier.padding(start = 16.dp).fillMaxWidth(),
|
||||
character = character,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onDiminished = onDiminished,
|
||||
onHp = onHp,
|
||||
onPp = onPp,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Background(
|
||||
modifier: Modifier = Modifier,
|
||||
character: CharacterDetailHeaderUio,
|
||||
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
color = MaterialTheme.lwa.colorScheme.elevatedSurface,
|
||||
) {
|
||||
// Image(
|
||||
// modifier = Modifier.fillMaxSize().drawWithContent {
|
||||
// drawContent()
|
||||
// drawRect(
|
||||
// brush = Brush.verticalGradient(
|
||||
// listOfNotNull(
|
||||
// color?.copy(alpha = 0.7f),
|
||||
// color,
|
||||
// )
|
||||
// )
|
||||
// )
|
||||
// },
|
||||
// painter = rememberAsyncImagePainter(model = character.portrait),
|
||||
// contentDescription = null,
|
||||
// contentScale = ContentScale.Crop,
|
||||
// alignment = Alignment.TopCenter,
|
||||
// )
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CharacterHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
character: CharacterDetailHeaderUio,
|
||||
onDismissRequest: () -> Unit,
|
||||
onDiminished: () -> Unit,
|
||||
onHp: () -> Unit,
|
||||
onPp: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
) {
|
||||
Row {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f)
|
||||
.align(alignment = Alignment.CenterVertically),
|
||||
style = MaterialTheme.typography.h5,
|
||||
text = character.name,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
Column {
|
||||
CharacterDetailHeader(
|
||||
modifier = Modifier.padding(start = 16.dp).fillMaxWidth(),
|
||||
header = header,
|
||||
onDismissRequest = onDismissRequest,
|
||||
onDiminished = onDiminished,
|
||||
onHp = onHp,
|
||||
onPp = onPp,
|
||||
)
|
||||
CharacterDetailSheet(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(all = 16.dp),
|
||||
sheet = sheet,
|
||||
onCharacteristic = onCharacteristic,
|
||||
)
|
||||
IconButton(
|
||||
onClick = onDiminished,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 24.dp),
|
||||
painter = painterResource(Res.drawable.ic_skull_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_close_24dp),
|
||||
tint = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.clip(shape = CircleShape).clickable { onHp() },
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(bottom = 4.dp, end = 2.dp).size(12.dp),
|
||||
painter = painterResource(Res.drawable.ic_heart_24dp),
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = character.hp,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Thin,
|
||||
text = "/${character.maxHp}",
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.clip(shape = CircleShape).clickable { onPp() },
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(bottom = 4.dp, end = 2.dp).size(12.dp),
|
||||
painter = painterResource(Res.drawable.ic_water_drop_24dp),
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = character.pp,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Thin,
|
||||
text = "/${character.maxPp}",
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(bottom = 4.dp, end = 2.dp).size(12.dp),
|
||||
painter = painterResource(Res.drawable.ic_near_me),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
text = character.mov,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = "m",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,35 @@
|
|||
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.screen.campaign.player.detail.header.CharacterDetailHeaderUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetUio
|
||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
|
||||
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.campaign.damage
|
||||
import com.pixelized.shared.lwa.model.campaign.power
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__cha
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__con
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__dex
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__hei
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__int
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__pow
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__str
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__constitution
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__dexterity
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__height
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__intelligence
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__power
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__strength
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class CharacterDetailFactory(
|
||||
private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory,
|
||||
) {
|
||||
|
||||
fun convertToCharacterDetailHeaderUio(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characterSheet: CharacterSheet?,
|
||||
|
|
@ -38,4 +57,80 @@ class CharacterDetailFactory(
|
|||
mov = "${alteredCharacterSheet.movement}"
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun convertToCharacterDetailSheetUio(
|
||||
characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
characterSheet: CharacterSheet?,
|
||||
characterInstance: Campaign.CharacterInstance,
|
||||
alterations: Map<String, List<FieldAlteration>>,
|
||||
): CharacterDetailSheetUio? {
|
||||
if (characterSheet == null) return null
|
||||
|
||||
val alteredCharacterSheet = alteredCharacterSheetFactory.sheet(
|
||||
characterSheet = characterSheet,
|
||||
alterations = alterations,
|
||||
)
|
||||
|
||||
return CharacterDetailSheetUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
characteristics = listOf(
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__str),
|
||||
value = "${alteredCharacterSheet.strength}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__str),
|
||||
description = getString(Res.string.tooltip__characteristics__strength),
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__dex),
|
||||
value = "${alteredCharacterSheet.dexterity}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__dex),
|
||||
description = getString(Res.string.tooltip__characteristics__dexterity),
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__con),
|
||||
value = "${alteredCharacterSheet.constitution}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__con),
|
||||
description = getString(Res.string.tooltip__characteristics__constitution),
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__hei),
|
||||
value = "${alteredCharacterSheet.height}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__hei),
|
||||
description = getString(Res.string.tooltip__characteristics__height),
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__int),
|
||||
value = "${alteredCharacterSheet.intelligence}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__int),
|
||||
description = getString(Res.string.tooltip__characteristics__intelligence),
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__pow),
|
||||
value = "${alteredCharacterSheet.power}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__pow),
|
||||
description = getString(Res.string.tooltip__characteristics__power),
|
||||
),
|
||||
),
|
||||
CharacterDetailSheetCharacteristicUio(
|
||||
label = getString(Res.string.character_sheet__characteristics__cha),
|
||||
value = "${alteredCharacterSheet.charisma}",
|
||||
tooltips = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__cha),
|
||||
description = getString(Res.string.tooltip__characteristics__charisma),
|
||||
),
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,13 +6,11 @@ import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
|||
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
|
||||
class CharacterDetailViewModel(
|
||||
|
|
@ -24,32 +22,50 @@ class CharacterDetailViewModel(
|
|||
|
||||
private val displayedCharacterId = MutableStateFlow<Campaign.CharacterInstance.Id?>(null)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val detail: StateFlow<CharacterDetailHeaderUio?> = displayedCharacterId
|
||||
.flatMapLatest { characterInstanceId ->
|
||||
if (characterInstanceId != null) {
|
||||
campaignRepository
|
||||
.characterInstanceFlow(id = characterInstanceId)
|
||||
.flatMapLatest { characterInstance ->
|
||||
combine(
|
||||
characterSheetRepository.characterDetailFlow(characterId = characterInstanceId.characterSheetId),
|
||||
alterationRepository.alterationsFlow(characterId = characterInstanceId),
|
||||
) { characterSheet, alterations ->
|
||||
characterDetailFactory.convertToCharacterDetailHeaderUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
characterSheet = characterSheet,
|
||||
characterInstance = characterInstance,
|
||||
alterations = alterations,
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
flowOf(null)
|
||||
}
|
||||
}.stateIn(
|
||||
val detail: StateFlow<CharacterDetailPanelUio> = displayedCharacterId
|
||||
.map { characterInstanceId ->
|
||||
if (characterInstanceId == null) return@map empty()
|
||||
|
||||
CharacterDetailPanelUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
header = combine(
|
||||
campaignRepository.characterInstanceFlow(id = characterInstanceId),
|
||||
characterSheetRepository.characterDetailFlow(characterId = characterInstanceId.characterSheetId),
|
||||
alterationRepository.alterationsFlow(characterId = characterInstanceId),
|
||||
) { characterInstance, characterSheet, alterations ->
|
||||
characterDetailFactory.convertToCharacterDetailHeaderUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
characterSheet = characterSheet,
|
||||
characterInstance = characterInstance,
|
||||
alterations = alterations,
|
||||
)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
),
|
||||
sheet = combine(
|
||||
campaignRepository.characterInstanceFlow(id = characterInstanceId),
|
||||
characterSheetRepository.characterDetailFlow(characterId = characterInstanceId.characterSheetId),
|
||||
alterationRepository.alterationsFlow(characterId = characterInstanceId),
|
||||
) { characterInstance, characterSheet, alterations ->
|
||||
characterDetailFactory.convertToCharacterDetailSheetUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
characterSheet = characterSheet,
|
||||
characterInstance = characterInstance,
|
||||
alterations = alterations,
|
||||
)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
),
|
||||
)
|
||||
}
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
initialValue = empty(),
|
||||
)
|
||||
|
||||
fun showCharacter(id: Campaign.CharacterInstance.Id) {
|
||||
|
|
@ -59,4 +75,10 @@ class CharacterDetailViewModel(
|
|||
fun hideCharacter() {
|
||||
displayedCharacterId.value = null
|
||||
}
|
||||
|
||||
private fun empty() = CharacterDetailPanelUio(
|
||||
characterInstanceId = null,
|
||||
header = MutableStateFlow(null),
|
||||
sheet = MutableStateFlow(null),
|
||||
)
|
||||
}
|
||||
|
|
@ -20,14 +20,16 @@ class CharacterDiminishedViewModel(
|
|||
val diminishedDialog: State<DiminishedStatDialogUio?> get() = _diminishedDialog
|
||||
|
||||
suspend fun showDiminishedDialog(
|
||||
id: Campaign.CharacterInstance.Id,
|
||||
characterInstanceId: Campaign.CharacterInstance.Id?,
|
||||
) {
|
||||
if (characterInstanceId == null) return
|
||||
|
||||
val diminished = 0 // TODO repository.characterDiminishedFlow(id = id).value
|
||||
val textFieldValue = mutableStateOf(
|
||||
TextFieldValue("$diminished", selection = TextRange(index = 0))
|
||||
)
|
||||
_diminishedDialog.value = DiminishedStatDialogUio(
|
||||
id = id,
|
||||
id = characterInstanceId,
|
||||
label = getString(resource = Res.string.character_sheet__diminished__label),
|
||||
value = { textFieldValue.value },
|
||||
onValueChange = { value ->
|
||||
|
|
@ -51,6 +53,4 @@ class CharacterDiminishedViewModel(
|
|||
// diminished = value,
|
||||
// )
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_close_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_heart_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_near_me
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_skull_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_water_drop_24dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
@Stable
|
||||
data class CharacterDetailHeaderUio(
|
||||
val id: Campaign.CharacterInstance.Id,
|
||||
val portrait: String?,
|
||||
val name: String,
|
||||
val hp: String,
|
||||
val maxHp: String,
|
||||
val pp: String,
|
||||
val maxPp: String,
|
||||
val mov: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterDetailHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
header: State<CharacterDetailHeaderUio?>,
|
||||
onDismissRequest: () -> Unit,
|
||||
onDiminished: () -> Unit,
|
||||
onHp: () -> Unit,
|
||||
onPp: () -> Unit,
|
||||
) {
|
||||
Column(
|
||||
modifier = modifier,
|
||||
) {
|
||||
Row {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f)
|
||||
.align(alignment = Alignment.CenterVertically),
|
||||
style = MaterialTheme.typography.h5,
|
||||
text = header.value?.name ?: "",
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
IconButton(
|
||||
onClick = onDiminished,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 24.dp),
|
||||
painter = painterResource(Res.drawable.ic_skull_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_close_24dp),
|
||||
tint = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 12.dp),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.clip(shape = CircleShape).clickable { onHp() },
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(bottom = 4.dp, end = 2.dp).size(12.dp),
|
||||
painter = painterResource(Res.drawable.ic_heart_24dp),
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = header.value?.hp ?: "",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Thin,
|
||||
text = "/${header.value?.maxHp ?: ""}",
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.clip(shape = CircleShape).clickable { onPp() },
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(bottom = 4.dp, end = 2.dp).size(12.dp),
|
||||
painter = painterResource(Res.drawable.ic_water_drop_24dp),
|
||||
contentDescription = null
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = header.value?.pp ?: "",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Thin,
|
||||
text = "/${header.value?.maxPp ?: ""}",
|
||||
)
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.padding(bottom = 4.dp, end = 2.dp).size(12.dp),
|
||||
painter = painterResource(Res.drawable.ic_near_me),
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
text = header.value?.mov ?: "",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = "m",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
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.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||
|
||||
@Stable
|
||||
data class CharacterDetailSheetCharacteristicUio(
|
||||
val value: String,
|
||||
val label: String,
|
||||
val tooltips: TooltipUio?,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun CharacterDetailSheetCharacteristic(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(all = 8.dp),
|
||||
characteristic: CharacterDetailSheetCharacteristicUio,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
TooltipLayout(
|
||||
tooltip = characteristic.tooltips,
|
||||
content = {
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.padding(paddingValues = paddingValues)
|
||||
.then(other = modifier),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.align(alignment = Alignment.TopCenter),
|
||||
style = MaterialTheme.typography.caption,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = characteristic.label,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.align(alignment = Alignment.Center),
|
||||
style = MaterialTheme.typography.h3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = characteristic.value
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
|
||||
@Stable
|
||||
data class CharacterDetailSheetUio(
|
||||
val characterInstanceId: Campaign.CharacterInstance.Id,
|
||||
val characteristics: List<CharacterDetailSheetCharacteristicUio>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterDetailSheet(
|
||||
modifier: Modifier = Modifier,
|
||||
sheet: State<CharacterDetailSheetUio?>,
|
||||
onCharacteristic: (CharacterDetailSheetCharacteristicUio) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
||||
) {
|
||||
sheet.value?.characteristics?.forEach {
|
||||
CharacterDetailSheetCharacteristic(
|
||||
modifier = Modifier.size(width = 80.dp, height = 120.dp),
|
||||
characteristic = it,
|
||||
onClick = { onCharacteristic(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
||||
) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -6,13 +6,13 @@ import androidx.compose.animation.core.spring
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
||||
import com.pixelized.shared.lwa.usecase.SkillStepUseCase
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.roll.DifficultyUio.Difficulty
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
||||
import com.pixelized.shared.lwa.usecase.SkillStepUseCase
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
@ -55,13 +55,17 @@ class RollViewModel(
|
|||
private val _rollDifficulty = mutableStateOf<DifficultyUio?>(null)
|
||||
val rollDifficulty: State<DifficultyUio?> get() = _rollDifficulty
|
||||
|
||||
private val _displayOverlay = mutableStateOf(false)
|
||||
val displayOverlay: State<Boolean> get() = _displayOverlay
|
||||
|
||||
fun prepareRoll(
|
||||
sheet: CharacterSheetPageUio,
|
||||
characteristic: CharacterSheetPageUio.Characteristic,
|
||||
) {
|
||||
val diminished = 0 // TODO characterSheetRepository.characterDiminishedFlow(id = sheet.id).value
|
||||
val diminished =
|
||||
0 // TODO characterSheetRepository.characterDiminishedFlow(id = sheet.id).value
|
||||
prepareRoll(
|
||||
sheet = sheet,
|
||||
characterSheetId = sheet.id,
|
||||
label = characteristic.label,
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = (characteristic.value.toIntOrNull() ?: 0) * 5 - diminished,
|
||||
|
|
@ -73,7 +77,7 @@ class RollViewModel(
|
|||
node: CharacterSheetPageUio.Node,
|
||||
) {
|
||||
prepareRoll(
|
||||
sheet = sheet,
|
||||
characterSheetId = sheet.id,
|
||||
label = node.label,
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = node.value,
|
||||
|
|
@ -85,15 +89,15 @@ class RollViewModel(
|
|||
roll: CharacterSheetPageUio.Roll,
|
||||
) {
|
||||
prepareRoll(
|
||||
sheet = sheet,
|
||||
characterSheetId = sheet.id,
|
||||
label = roll.label,
|
||||
rollAction = roll.value,
|
||||
rollSuccessValue = null,
|
||||
)
|
||||
}
|
||||
|
||||
private fun prepareRoll(
|
||||
sheet: CharacterSheetPageUio,
|
||||
fun prepareRoll(
|
||||
characterSheetId: String,
|
||||
label: String,
|
||||
rollAction: String,
|
||||
rollSuccessValue: Int?,
|
||||
|
|
@ -101,7 +105,7 @@ class RollViewModel(
|
|||
this.sheet = runBlocking {
|
||||
rollRotation.snapTo(0f)
|
||||
rollScale.snapTo(1f)
|
||||
characterSheetRepository.characterDetail(characterSheetId = sheet.id)!!
|
||||
characterSheetRepository.characterDetail(characterSheetId = characterSheetId)!!
|
||||
}
|
||||
|
||||
this.rollAction = rollAction
|
||||
|
|
@ -238,4 +242,12 @@ class RollViewModel(
|
|||
value = rollStep?.success?.last
|
||||
)
|
||||
}
|
||||
|
||||
fun showOverlay() {
|
||||
_displayOverlay.value = true
|
||||
}
|
||||
|
||||
fun hideOverlay() {
|
||||
_displayOverlay.value = false
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ class RollUseCase {
|
|||
if (quantity > 1 && left != 1) print(",")
|
||||
}
|
||||
}.also {
|
||||
print("}")
|
||||
println("}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue