Compare commits
3 commits
c4db7b2a72
...
24fe030663
| Author | SHA1 | Date | |
|---|---|---|---|
| 24fe030663 | |||
| c5f4a3e46e | |||
| 171651c5e8 |
22 changed files with 358 additions and 69 deletions
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="#5f6368"
|
||||||
|
android:pathData="M160,560L160,480L440,480L440,560L160,560ZM160,400L160,320L600,320L600,400L160,400ZM160,240L160,160L600,160L600,240L160,240ZM520,800L520,677L741,457Q750,448 761,444Q772,440 783,440Q795,440 806,444.5Q817,449 826,458L863,495Q871,504 875.5,515Q880,526 880,537Q880,548 876,559.5Q872,571 863,580L643,800L520,800ZM820,537L820,537L783,500L783,500L820,537ZM580,740L618,740L739,618L721,599L702,581L580,702L580,740ZM721,599L702,581L702,581L739,618L739,618L721,599Z" />
|
||||||
|
</vector>
|
||||||
|
|
@ -325,6 +325,7 @@
|
||||||
<string name="game_master__character_edit__title">Édition de personnage</string>
|
<string name="game_master__character_edit__title">Édition de personnage</string>
|
||||||
<string name="game_master__actions__on_server_sync__title">Synchronisation du serveur</string>
|
<string name="game_master__actions__on_server_sync__title">Synchronisation du serveur</string>
|
||||||
<string name="game_master__actions__on_server_sync__description">Demander au serveur d'invalider son cache</string>
|
<string name="game_master__actions__on_server_sync__description">Demander au serveur d'invalider son cache</string>
|
||||||
|
<string name="game_master__actions__campaign_scene__title">Titre de la scène</string>
|
||||||
<string name="game_master__actions__party_heal__title">Soigner les personnages joueurs</string>
|
<string name="game_master__actions__party_heal__title">Soigner les personnages joueurs</string>
|
||||||
<string name="game_master__actions__party_heal__description">Cette action réinitialisera les points de vie, de pouvoir et d'état diminué de chaque personnage joueur présent dans le groupe.</string>
|
<string name="game_master__actions__party_heal__description">Cette action réinitialisera les points de vie, de pouvoir et d'état diminué de chaque personnage joueur présent dans le groupe.</string>
|
||||||
<string name="game_master__actions__hide_player__title">Cacher le groupe de personnages joueur</string>
|
<string name="game_master__actions__hide_player__title">Cacher le groupe de personnages joueur</string>
|
||||||
|
|
|
||||||
|
|
@ -31,21 +31,22 @@ import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogFa
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogViewModel
|
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogFactory
|
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogFactory
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
|
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.image.ImagerModelConverter
|
||||||
import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlayViewModel
|
import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlayViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
|
import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.network.NetworkFactory
|
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.network.NetworkViewModel
|
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.CharacterRibbonFactory
|
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetFactory
|
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailPanelViewModel
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailPanelViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderFactory
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderFactory
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.CharacterDetailInventoryFactory
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.CharacterDetailInventoryFactory
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetFactory
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.CharacterRibbonFactory
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.NpcRibbonViewModel
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.NpcRibbonViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbonViewModel
|
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbonViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.CampaignChatViewModel
|
import com.pixelized.desktop.lwa.ui.screen.campaign.text.CampaignChatViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.TextMessageFactory
|
import com.pixelized.desktop.lwa.ui.screen.campaign.text.TextMessageFactory
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.CampaignToolbarViewModel
|
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.CampaignToolbarViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.links.ResourcesViewModel
|
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.links.ResourcesViewModel
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.network.NetworkFactory
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.network.NetworkViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionUseCase
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionUseCase
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionViewModel
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionViewModel
|
||||||
|
|
@ -112,6 +113,7 @@ val toolsDependencies
|
||||||
single {
|
single {
|
||||||
PathProvider(appName = "LwaClient")
|
PathProvider(appName = "LwaClient")
|
||||||
}
|
}
|
||||||
|
singleOf(::ImagerModelConverter)
|
||||||
}
|
}
|
||||||
|
|
||||||
val storeDependencies
|
val storeDependencies
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ interface LwaClient {
|
||||||
|
|
||||||
suspend fun getCampaign(): APIResponse<CampaignJson>
|
suspend fun getCampaign(): APIResponse<CampaignJson>
|
||||||
|
|
||||||
|
suspend fun putCampaignScene(
|
||||||
|
scene: CampaignJson.SceneJson,
|
||||||
|
): APIResponse<Unit>
|
||||||
|
|
||||||
suspend fun putCampaignCharacter(
|
suspend fun putCampaignCharacter(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
): APIResponse<Unit>
|
): APIResponse<Unit>
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,16 @@ class LwaClientImpl(
|
||||||
.get("$root/campaign")
|
.get("$root/campaign")
|
||||||
.body()
|
.body()
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
override suspend fun putCampaignScene(
|
||||||
|
scene: CampaignJson.SceneJson,
|
||||||
|
): APIResponse<Unit> = client
|
||||||
|
.put("$root/campaign/scene") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(scene)
|
||||||
|
}
|
||||||
|
.body<APIResponse<Unit>>()
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
override suspend fun putCampaignCharacter(
|
override suspend fun putCampaignCharacter(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,12 @@ class CampaignRepository(
|
||||||
store.updateCampaignFlow()
|
store.updateCampaignFlow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun updateSceneTitle(
|
||||||
|
title: String,
|
||||||
|
) {
|
||||||
|
store.changeSceneTitle(title = title)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
suspend fun addCharacter(
|
suspend fun addCharacter(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,17 @@ class CampaignStore(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws
|
||||||
|
suspend fun changeSceneTitle(
|
||||||
|
title: String,
|
||||||
|
) {
|
||||||
|
val scene = factory.createScene(title = title)
|
||||||
|
val request = client.putCampaignScene(scene = scene)
|
||||||
|
if (request.success.not()) {
|
||||||
|
LwaClient.error(error = request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Throws
|
@Throws
|
||||||
suspend fun addCharacter(
|
suspend fun addCharacter(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,10 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
import androidx.compose.ui.graphics.DefaultAlpha
|
import androidx.compose.ui.graphics.DefaultAlpha
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import coil3.compose.AsyncImage
|
|
||||||
import coil3.compose.AsyncImagePainter.Companion.DefaultTransform
|
import coil3.compose.AsyncImagePainter.Companion.DefaultTransform
|
||||||
import coil3.compose.AsyncImagePainter.State
|
import coil3.compose.AsyncImagePainter.State
|
||||||
import com.pixelized.desktop.lwa.utils.rememberBackgroundGradient
|
import com.pixelized.desktop.lwa.utils.rememberBackgroundGradient
|
||||||
|
|
@ -32,8 +30,10 @@ fun DesaturatedAsyncImage(
|
||||||
filterQuality: FilterQuality = FilterQuality.Low,
|
filterQuality: FilterQuality = FilterQuality.Low,
|
||||||
clipToBounds: Boolean = true,
|
clipToBounds: Boolean = true,
|
||||||
) {
|
) {
|
||||||
Box(modifier = modifier) {
|
Box(
|
||||||
AsyncImage(
|
modifier = modifier,
|
||||||
|
) {
|
||||||
|
LwaAsyncImage(
|
||||||
model = model,
|
model = model,
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = Modifier.matchParentSize(),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.image
|
||||||
|
|
||||||
|
class ImagerModelConverter {
|
||||||
|
|
||||||
|
val googleDriveUrlRegex = Regex("""drive\.google\.com/file/d/([^/]*)""")
|
||||||
|
val workingGoogleDriveUri = "https://drive.google.com/uc?export=view&id="
|
||||||
|
|
||||||
|
fun convert(
|
||||||
|
model: Any?,
|
||||||
|
): Any? {
|
||||||
|
return when (model) {
|
||||||
|
is String -> googleDriveUrlRegex.find(model)?.let {
|
||||||
|
val id = it.groupValues.getOrNull(1)
|
||||||
|
"$workingGoogleDriveUri$id"
|
||||||
|
} ?: model
|
||||||
|
else -> model
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.image
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.DefaultAlpha
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import coil3.compose.AsyncImage
|
||||||
|
import coil3.compose.AsyncImagePainter.Companion.DefaultTransform
|
||||||
|
import coil3.compose.AsyncImagePainter.State
|
||||||
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LwaAsyncImage(
|
||||||
|
model: Any?,
|
||||||
|
modelConverter: ImagerModelConverter? = koinInject<ImagerModelConverter?>(),
|
||||||
|
contentDescription: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
transform: (State) -> State = DefaultTransform,
|
||||||
|
onState: ((State) -> Unit)? = null,
|
||||||
|
alignment: Alignment = Alignment.Center,
|
||||||
|
contentScale: ContentScale = ContentScale.Fit,
|
||||||
|
alpha: Float = DefaultAlpha,
|
||||||
|
colorFilter: ColorFilter? = null,
|
||||||
|
filterQuality: FilterQuality = FilterQuality.Low,
|
||||||
|
clipToBounds: Boolean = true,
|
||||||
|
) {
|
||||||
|
AsyncImage(
|
||||||
|
modifier = modifier,
|
||||||
|
model = remember(modelConverter, model) { modelConverter?.convert(model) ?: model },
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
transform = transform,
|
||||||
|
onState = onState,
|
||||||
|
alignment = alignment,
|
||||||
|
contentScale = contentScale,
|
||||||
|
alpha = alpha,
|
||||||
|
colorFilter = colorFilter,
|
||||||
|
filterQuality = filterQuality,
|
||||||
|
clipToBounds = clipToBounds,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.image.LwaAsyncImage
|
||||||
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
|
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
|
||||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -97,7 +98,7 @@ private fun PortraitContent(
|
||||||
else -> Box(
|
else -> Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
AsyncImage(
|
LwaAsyncImage(
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = Modifier.matchParentSize(),
|
||||||
model = it,
|
model = it,
|
||||||
filterQuality = FilterQuality.High,
|
filterQuality = FilterQuality.High,
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
|
|
@ -360,14 +361,24 @@ private fun CampaignLayout(
|
||||||
) {
|
) {
|
||||||
leftPanel()
|
leftPanel()
|
||||||
}
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.weight(weight = 1f, fill = true),
|
||||||
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(alignment = Alignment.Bottom)
|
.fillMaxWidth()
|
||||||
.weight(weight = 1f, fill = true)
|
.weight(weight = 1f, fill = true),
|
||||||
|
) {
|
||||||
|
overlay()
|
||||||
|
}
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.onSizeChanged { chatOverlayState.value = it.toDp(density) },
|
.onSizeChanged { chatOverlayState.value = it.toDp(density) },
|
||||||
) {
|
) {
|
||||||
chat()
|
chat()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(width = MaterialTheme.lwa.dimen.layout.panelWidth)
|
.width(width = MaterialTheme.lwa.dimen.layout.panelWidth)
|
||||||
|
|
@ -377,13 +388,6 @@ private fun CampaignLayout(
|
||||||
rightPanel()
|
rightPanel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.align(alignment = Alignment.Center)
|
|
||||||
.fillMaxSize(),
|
|
||||||
) {
|
|
||||||
overlay()
|
|
||||||
}
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(alignment = Alignment.CenterStart)
|
.align(alignment = Alignment.CenterStart)
|
||||||
|
|
|
||||||
|
|
@ -44,10 +44,10 @@ import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil3.PlatformContext
|
import coil3.PlatformContext
|
||||||
import coil3.compose.AsyncImage
|
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||||
import com.pixelized.desktop.lwa.ui.composable.image.DesaturatedAsyncImage
|
import com.pixelized.desktop.lwa.ui.composable.image.DesaturatedAsyncImage
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.image.LwaAsyncImage
|
||||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
||||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
import com.pixelized.desktop.lwa.utils.extention.calculatePaddings
|
import com.pixelized.desktop.lwa.utils.extention.calculatePaddings
|
||||||
|
|
@ -194,7 +194,8 @@ fun InventoryItem(
|
||||||
shape = CircleShape,
|
shape = CircleShape,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
AsyncImage(
|
|
||||||
|
LwaAsyncImage(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(size = icon)
|
.size(size = icon)
|
||||||
.aspectRatio(ratio = 1f, matchHeightConstraintsFirst = true),
|
.aspectRatio(ratio = 1f, matchHeightConstraintsFirst = true),
|
||||||
|
|
|
||||||
|
|
@ -21,19 +21,18 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.DpSize
|
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil3.PlatformContext
|
import coil3.PlatformContext
|
||||||
import coil3.compose.AsyncImage
|
|
||||||
import coil3.request.ImageRequest
|
import coil3.request.ImageRequest
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.image.LwaAsyncImage
|
||||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipLayout
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipLayout
|
||||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
|
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
|
||||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
|
import com.pixelized.desktop.lwa.utils.extention.invert
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacterRibbonAlterationUio(
|
data class CharacterRibbonAlterationUio(
|
||||||
|
|
||||||
val icon: String,
|
val icon: String,
|
||||||
val tooltips: BasicTooltipUio?,
|
val tooltips: BasicTooltipUio?,
|
||||||
)
|
)
|
||||||
|
|
@ -63,14 +62,10 @@ fun CharacterRibbonAlteration(
|
||||||
delayMillis = 0,
|
delayMillis = 0,
|
||||||
tooltip = it.tooltips,
|
tooltip = it.tooltips,
|
||||||
tooltipPlacement = remember(direction) {
|
tooltipPlacement = remember(direction) {
|
||||||
TooltipPlacement.ComponentRect(
|
TooltipPlacement.CursorPoint(
|
||||||
anchor = when (direction) {
|
alignment = when (direction.invert) {
|
||||||
LayoutDirection.Ltr -> Alignment.CenterEnd
|
LayoutDirection.Ltr -> Alignment.CenterStart
|
||||||
LayoutDirection.Rtl -> Alignment.CenterStart
|
LayoutDirection.Rtl -> Alignment.CenterEnd
|
||||||
},
|
|
||||||
alignment = when (direction) {
|
|
||||||
LayoutDirection.Ltr -> Alignment.CenterEnd
|
|
||||||
LayoutDirection.Rtl -> Alignment.CenterStart
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -79,7 +74,7 @@ fun CharacterRibbonAlteration(
|
||||||
targetState = it.icon,
|
targetState = it.icon,
|
||||||
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
||||||
) { icon ->
|
) { icon ->
|
||||||
AsyncImage(
|
LwaAsyncImage(
|
||||||
modifier = Modifier.size(24.dp),
|
modifier = Modifier.size(24.dp),
|
||||||
model = ImageRequest.Builder(context = PlatformContext.INSTANCE)
|
model = ImageRequest.Builder(context = PlatformContext.INSTANCE)
|
||||||
.data(data = icon)
|
.data(data = icon)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.PointerMatcher
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
|
@ -18,7 +17,6 @@ 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.foundation.layout.width
|
||||||
import androidx.compose.foundation.onClick
|
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.IconButton
|
import androidx.compose.material.IconButton
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
|
|
@ -30,12 +28,11 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.drawWithContent
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.input.pointer.PointerButton
|
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import coil3.compose.AsyncImage
|
import com.pixelized.desktop.lwa.ui.composable.image.LwaAsyncImage
|
||||||
import com.pixelized.desktop.lwa.ui.composable.shapes.ArrowShape
|
import com.pixelized.desktop.lwa.ui.composable.shapes.ArrowShape
|
||||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
|
@ -80,7 +77,7 @@ fun CharacterRibbonPortrait(
|
||||||
targetState = character.portrait,
|
targetState = character.portrait,
|
||||||
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
||||||
) { portrait ->
|
) { portrait ->
|
||||||
AsyncImage(
|
LwaAsyncImage(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
model = portrait,
|
model = portrait,
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
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
|
||||||
|
|
@ -15,11 +16,13 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
|
|
||||||
import com.pixelized.desktop.lwa.ui.composable.confirmation.ConfirmationDialog
|
import com.pixelized.desktop.lwa.ui.composable.confirmation.ConfirmationDialog
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
|
||||||
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_camping_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_camping_24dp
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.ic_edit_note_24dp
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_sync_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_sync_24dp
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_visibility_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_visibility_24dp
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_visibility_off_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_visibility_off_24dp
|
||||||
|
|
@ -38,6 +41,7 @@ fun GMActionPage(
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val scroll = rememberScrollState()
|
val scroll = rememberScrollState()
|
||||||
val actions = viewModel.actions.collectAsStateWithLifecycle()
|
val actions = viewModel.actions.collectAsStateWithLifecycle()
|
||||||
|
val editDialog = viewModel.editDialog.collectAsStateWithLifecycle()
|
||||||
val validationDialog = viewModel.validationDialog.collectAsStateWithLifecycle()
|
val validationDialog = viewModel.validationDialog.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
GMActionContent(
|
GMActionContent(
|
||||||
|
|
@ -48,6 +52,11 @@ fun GMActionPage(
|
||||||
viewModel.onServerSync()
|
viewModel.onServerSync()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onEditSession = {
|
||||||
|
scope.launch {
|
||||||
|
viewModel.onEditSession()
|
||||||
|
}
|
||||||
|
},
|
||||||
onPartyHeal = {
|
onPartyHeal = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
viewModel.onPartyHeal()
|
viewModel.onPartyHeal()
|
||||||
|
|
@ -72,15 +81,20 @@ fun GMActionPage(
|
||||||
ConfirmationDialog(
|
ConfirmationDialog(
|
||||||
dialog = validationDialog,
|
dialog = validationDialog,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
GMEditDialog(
|
||||||
|
dialog = editDialog
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun GMActionContent(
|
fun GMActionContent(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
scroll: ScrollState,
|
scroll: ScrollState,
|
||||||
spacing: Dp = 8.dp,
|
spacing: Dp = MaterialTheme.lwa.dimen.paddingValue,
|
||||||
actions: State<ActionPageUio?>,
|
actions: State<ActionPageUio?>,
|
||||||
onServerSync: () -> Unit,
|
onServerSync: () -> Unit,
|
||||||
|
onEditSession: () -> Unit,
|
||||||
onPartyHeal: () -> Unit,
|
onPartyHeal: () -> Unit,
|
||||||
onPartyVisibility: () -> Unit,
|
onPartyVisibility: () -> Unit,
|
||||||
onNpcVisibility: () -> Unit,
|
onNpcVisibility: () -> Unit,
|
||||||
|
|
@ -97,6 +111,12 @@ fun GMActionContent(
|
||||||
label = "Synchronization du serveur",
|
label = "Synchronization du serveur",
|
||||||
onAction = onServerSync,
|
onAction = onServerSync,
|
||||||
)
|
)
|
||||||
|
GMAction(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
icon = Res.drawable.ic_edit_note_24dp,
|
||||||
|
label = "Edition du titre de session",
|
||||||
|
onAction = onEditSession,
|
||||||
|
)
|
||||||
GMAction(
|
GMAction(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
icon = Res.drawable.ic_camping_24dp,
|
icon = Res.drawable.ic_camping_24dp,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,16 @@ class GMActionUseCase(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun currentSceneTitle(): String = campaignRepository.campaignFlow().value.scene.name
|
||||||
|
|
||||||
|
suspend fun updateSceneTitle(
|
||||||
|
title: String,
|
||||||
|
) {
|
||||||
|
campaignRepository.updateSceneTitle(
|
||||||
|
title = title,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun healPlayerParty() {
|
suspend fun healPlayerParty() {
|
||||||
campaignRepository.campaignFlow().value.characters.forEach { characterSheetId ->
|
campaignRepository.campaignFlow().value.characters.forEach { characterSheetId ->
|
||||||
val sheet = characterRepository.characterDetail(
|
val sheet = characterRepository.characterDetail(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||||
import com.pixelized.desktop.lwa.ui.composable.confirmation.ConfirmationDialogUio
|
import com.pixelized.desktop.lwa.ui.composable.confirmation.ConfirmationDialogUio
|
||||||
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
|
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
|
|
@ -15,6 +17,7 @@ import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__campaign_scene__title
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__description
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__description
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__title
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__title
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_player__description
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_player__description
|
||||||
|
|
@ -27,7 +30,6 @@ import lwacharactersheet.composeapp.generated.resources.game_master__actions__sh
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_npc__title
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_npc__title
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__description
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__description
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__title
|
import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__title
|
||||||
import org.jetbrains.compose.resources.StringResource
|
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
|
|
||||||
class GMActionViewModel(
|
class GMActionViewModel(
|
||||||
|
|
@ -55,11 +57,14 @@ class GMActionViewModel(
|
||||||
private val _validationDialog = MutableStateFlow<ConfirmationDialogUio?>(null)
|
private val _validationDialog = MutableStateFlow<ConfirmationDialogUio?>(null)
|
||||||
val validationDialog: StateFlow<ConfirmationDialogUio?> = _validationDialog
|
val validationDialog: StateFlow<ConfirmationDialogUio?> = _validationDialog
|
||||||
|
|
||||||
|
private val _editDialog = MutableStateFlow<GMEditDialogUio?>(null)
|
||||||
|
val editDialog: StateFlow<GMEditDialogUio?> = _editDialog
|
||||||
|
|
||||||
suspend fun onServerSync() {
|
suspend fun onServerSync() {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
title = Res.string.game_master__actions__on_server_sync__title,
|
title = getString(Res.string.game_master__actions__on_server_sync__title),
|
||||||
description = Res.string.game_master__actions__on_server_sync__description,
|
description = getString(Res.string.game_master__actions__on_server_sync__description),
|
||||||
onConfirmationRequest = {
|
onConfirmRequest = {
|
||||||
try {
|
try {
|
||||||
actionUseCase.invalidateServerCache()
|
actionUseCase.invalidateServerCache()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
@ -73,11 +78,29 @@ class GMActionViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun onEditSession() {
|
||||||
|
showEditDialog(
|
||||||
|
title = getString(Res.string.game_master__actions__campaign_scene__title),
|
||||||
|
value = actionUseCase.currentSceneTitle(),
|
||||||
|
onConfirmRequest = {
|
||||||
|
try {
|
||||||
|
actionUseCase.updateSceneTitle(title = it)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
val message = ErrorSnackUio.from(exception = exception)
|
||||||
|
_error.emit(message)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDismissRequest = {
|
||||||
|
_editDialog.value = null
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun onPartyHeal() {
|
suspend fun onPartyHeal() {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
title = Res.string.game_master__actions__party_heal__title,
|
title = getString(Res.string.game_master__actions__party_heal__title),
|
||||||
description = Res.string.game_master__actions__party_heal__description,
|
description = getString(Res.string.game_master__actions__party_heal__description),
|
||||||
onConfirmationRequest = {
|
onConfirmRequest = {
|
||||||
try {
|
try {
|
||||||
actionUseCase.healPlayerParty()
|
actionUseCase.healPlayerParty()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
@ -91,14 +114,14 @@ class GMActionViewModel(
|
||||||
suspend fun onPlayerVisibility() {
|
suspend fun onPlayerVisibility() {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
title = when (actions.value?.party) {
|
title = when (actions.value?.party) {
|
||||||
true -> Res.string.game_master__actions__hide_player__title
|
true -> getString(Res.string.game_master__actions__hide_player__title)
|
||||||
else -> Res.string.game_master__actions__show_player__title
|
else -> getString(Res.string.game_master__actions__show_player__title)
|
||||||
},
|
},
|
||||||
description = when (actions.value?.party) {
|
description = when (actions.value?.party) {
|
||||||
true -> Res.string.game_master__actions__hide_player__description
|
true -> getString(Res.string.game_master__actions__hide_player__description)
|
||||||
else -> Res.string.game_master__actions__show_player__description
|
else -> getString(Res.string.game_master__actions__show_player__description)
|
||||||
},
|
},
|
||||||
onConfirmationRequest = {
|
onConfirmRequest = {
|
||||||
try {
|
try {
|
||||||
actionUseCase.togglePlayerVisibility()
|
actionUseCase.togglePlayerVisibility()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
@ -112,14 +135,14 @@ class GMActionViewModel(
|
||||||
suspend fun onNpcVisibility() {
|
suspend fun onNpcVisibility() {
|
||||||
showConfirmationDialog(
|
showConfirmationDialog(
|
||||||
title = when (actions.value?.npc) {
|
title = when (actions.value?.npc) {
|
||||||
true -> Res.string.game_master__actions__hide_npc__title
|
true -> getString(Res.string.game_master__actions__hide_npc__title)
|
||||||
else -> Res.string.game_master__actions__show_npc__title
|
else -> getString(Res.string.game_master__actions__show_npc__title)
|
||||||
},
|
},
|
||||||
description = when (actions.value?.npc) {
|
description = when (actions.value?.npc) {
|
||||||
true -> Res.string.game_master__actions__hide_npc__description
|
true -> getString(Res.string.game_master__actions__hide_npc__description)
|
||||||
else -> Res.string.game_master__actions__show_npc__description
|
else -> getString(Res.string.game_master__actions__show_npc__description)
|
||||||
},
|
},
|
||||||
onConfirmationRequest = {
|
onConfirmRequest = {
|
||||||
try {
|
try {
|
||||||
actionUseCase.toggleNpcVisibility()
|
actionUseCase.toggleNpcVisibility()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
|
|
@ -130,18 +153,42 @@ class GMActionViewModel(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend inline fun showConfirmationDialog(
|
private inline fun showConfirmationDialog(
|
||||||
title: StringResource,
|
title: String,
|
||||||
description: StringResource,
|
description: String,
|
||||||
crossinline onConfirmationRequest: suspend () -> Unit,
|
crossinline onConfirmRequest: suspend () -> Unit,
|
||||||
crossinline onDismissRequest: () -> Unit = { _validationDialog.value = null },
|
crossinline onDismissRequest: () -> Unit = { _validationDialog.value = null },
|
||||||
) {
|
) {
|
||||||
_validationDialog.value = ConfirmationDialogUio(
|
_validationDialog.value = ConfirmationDialogUio(
|
||||||
title = getString(title),
|
title = title,
|
||||||
description = getString(description),
|
description = description,
|
||||||
onConfirmRequest = {
|
onConfirmRequest = {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
onConfirmationRequest()
|
onConfirmRequest()
|
||||||
|
onDismissRequest()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDismissRequest = {
|
||||||
|
onDismissRequest()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun showEditDialog(
|
||||||
|
title: String,
|
||||||
|
value: String,
|
||||||
|
crossinline onConfirmRequest: suspend (String) -> Unit,
|
||||||
|
crossinline onDismissRequest: () -> Unit = { _editDialog.value = null },
|
||||||
|
) {
|
||||||
|
val edit = createLwaTextFieldFlow(
|
||||||
|
label = value,
|
||||||
|
)
|
||||||
|
_editDialog.value = GMEditDialogUio(
|
||||||
|
title = title,
|
||||||
|
edit = edit.createLwaTextField(),
|
||||||
|
onConfirmRequest = {
|
||||||
|
viewModelScope.launch {
|
||||||
|
onConfirmRequest(edit.valueFlow.value)
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.screen.gamemaster.action
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.material.TextButton
|
||||||
|
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.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pixelized.desktop.lwa.LocalBlurController
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.LwaDialog
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.dialog__cancel_action
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.dialog__confirm_action
|
||||||
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
data class GMEditDialogUio(
|
||||||
|
val title: String,
|
||||||
|
val edit: LwaTextFieldUio,
|
||||||
|
val onConfirmRequest: () -> Unit,
|
||||||
|
val onDismissRequest: () -> Unit,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
object GMEditDialogDefault {
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
val paddings = PaddingValues(start = 16.dp, top = 16.dp, end = 16.dp)
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
val spacings: Dp = 8.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GMEditDialog(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
paddingValues: PaddingValues = GMEditDialogDefault.paddings,
|
||||||
|
spacing: Dp = GMEditDialogDefault.spacings,
|
||||||
|
dialog: State<GMEditDialogUio?>,
|
||||||
|
) {
|
||||||
|
LwaDialog(
|
||||||
|
modifier = modifier,
|
||||||
|
blur = LocalBlurController.current,
|
||||||
|
state = dialog,
|
||||||
|
onDismissRequest = { dialog.value?.onDismissRequest?.invoke() },
|
||||||
|
onConfirm = { dialog.value?.onConfirmRequest?.invoke() },
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(paddingValues = paddingValues),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(space = spacing),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
style = MaterialTheme.typography.caption,
|
||||||
|
text = it.title,
|
||||||
|
)
|
||||||
|
LwaTextField(
|
||||||
|
field = it.edit,
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.align(alignment = Alignment.End),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(
|
||||||
|
space = spacing / 2,
|
||||||
|
alignment = Alignment.End,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
TextButton(
|
||||||
|
onClick = it.onDismissRequest,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
color = MaterialTheme.colors.primaryVariant,
|
||||||
|
text = stringResource(Res.string.dialog__cancel_action)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
TextButton(
|
||||||
|
onClick = it.onConfirmRequest,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
color = MaterialTheme.colors.primary,
|
||||||
|
text = stringResource(Res.string.dialog__confirm_action)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -60,9 +60,9 @@ import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import coil3.compose.AsyncImage
|
|
||||||
import com.pixelized.desktop.lwa.LocalRollHostState
|
import com.pixelized.desktop.lwa.LocalRollHostState
|
||||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.image.LwaAsyncImage
|
||||||
import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler
|
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.LocalScreenController
|
||||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.LevelUpDestination
|
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.LevelUpDestination
|
||||||
|
|
@ -204,7 +204,7 @@ private fun LevelUpContent(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
background = {
|
background = {
|
||||||
AsyncImage(
|
LwaAsyncImage(
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = Modifier.matchParentSize(),
|
||||||
model = header.value?.portrait,
|
model = header.value?.portrait,
|
||||||
contentScale = ContentScale.FillHeight,
|
contentScale = ContentScale.FillHeight,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package com.pixelized.desktop.lwa.utils.extention
|
package com.pixelized.desktop.lwa.utils.extention
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
|
||||||
val LayoutDirection.invert: LayoutDirection
|
val LayoutDirection.invert: LayoutDirection
|
||||||
|
@Stable
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
LayoutDirection.Ltr -> LayoutDirection.Rtl
|
LayoutDirection.Ltr -> LayoutDirection.Rtl
|
||||||
LayoutDirection.Rtl -> LayoutDirection.Ltr
|
LayoutDirection.Rtl -> LayoutDirection.Ltr
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,14 @@ class CampaignJsonFactory(
|
||||||
|
|
||||||
// Json conversion.
|
// Json conversion.
|
||||||
|
|
||||||
|
fun createScene(
|
||||||
|
title: String,
|
||||||
|
): CampaignJsonV2.SceneJsonV2 {
|
||||||
|
return CampaignJsonV2.SceneJsonV2(
|
||||||
|
name = title,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun convertToJson(
|
fun convertToJson(
|
||||||
campaign: Campaign,
|
campaign: Campaign,
|
||||||
): CampaignJson {
|
): CampaignJson {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue