Refactor: clean unused legacy character sheet stuff.
This commit is contained in:
parent
09ed7d2d90
commit
763f575be4
28 changed files with 0 additions and 4051 deletions
|
|
@ -35,17 +35,12 @@ import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
|
|||
import com.pixelized.desktop.lwa.ui.composable.key.KeyEventHandler
|
||||
import com.pixelized.desktop.lwa.ui.composable.key.LocalKeyEventHandlers
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.MainNavHost
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetDestination
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetEditDestination
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindowState
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.WindowController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.WindowsNavHost
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.CharacterSheetEditWindow
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.CharacterSheetWindow
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.GameMasterWindow
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.rememberMaxWindowHeight
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollHostState
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.CharacterSheetMainNavHost
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterNavHost
|
||||
import com.pixelized.desktop.lwa.ui.theme.LwaTheme
|
||||
import com.pixelized.desktop.lwa.utils.InstallCoil
|
||||
|
|
@ -162,18 +157,6 @@ private fun WindowsHandler(
|
|||
controller = windowController,
|
||||
content = { window ->
|
||||
when (window) {
|
||||
is CharacterSheetWindow -> CharacterSheetMainNavHost(
|
||||
startDestination = CharacterSheetDestination.navigationRoute(
|
||||
characterSheetId = window.characterSheetId,
|
||||
),
|
||||
)
|
||||
|
||||
is CharacterSheetEditWindow -> CharacterSheetMainNavHost(
|
||||
startDestination = CharacterSheetEditDestination.navigationRoute(
|
||||
characterSheetId = window.characterSheetId,
|
||||
),
|
||||
)
|
||||
|
||||
is GameMasterWindow -> LwaScaffold {
|
||||
GameMasterNavHost()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,11 +46,6 @@ 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.toolbar.CampaignToolbarViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.links.ResourcesViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEditFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEditViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditFactory
|
||||
|
|
@ -144,10 +139,7 @@ val repositoryDependencies
|
|||
|
||||
val factoryDependencies
|
||||
get() = module {
|
||||
factoryOf(::CharacterSheetFactory)
|
||||
factoryOf(::CharacterSheetEditFactory)
|
||||
factoryOf(::NetworkFactory)
|
||||
factoryOf(::SkillFieldFactory)
|
||||
factoryOf(::SettingsFactory)
|
||||
factoryOf(::CampaignJsonFactory)
|
||||
factoryOf(::CharacterRibbonFactory)
|
||||
|
|
@ -177,8 +169,6 @@ val viewModelDependencies
|
|||
viewModelOf(::DataSyncViewModel)
|
||||
viewModelOf(::CampaignToolbarViewModel)
|
||||
viewModelOf(::ResourcesViewModel)
|
||||
viewModelOf(::CharacterSheetViewModel)
|
||||
viewModelOf(::CharacterSheetEditViewModel)
|
||||
viewModelOf(::RollViewModel)
|
||||
viewModelOf(::NetworkViewModel)
|
||||
viewModelOf(::PlayerRibbonViewModel)
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.navigation.screen.destination
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPage
|
||||
import com.pixelized.desktop.lwa.utils.extention.ARG
|
||||
|
||||
object CharacterSheetDestination {
|
||||
private const val ROUTE = "characterSheet"
|
||||
private const val CHARACTER_SHEET_ID = "characterSheetId"
|
||||
|
||||
fun baseRoute() = "$ROUTE?${CHARACTER_SHEET_ID.ARG}"
|
||||
|
||||
fun navigationRoute(characterSheetId: String) = "$ROUTE?$CHARACTER_SHEET_ID=${characterSheetId}"
|
||||
|
||||
fun arguments() = listOf(
|
||||
navArgument(CHARACTER_SHEET_ID) {
|
||||
nullable = false
|
||||
type = NavType.StringType
|
||||
},
|
||||
)
|
||||
|
||||
data class Argument(
|
||||
val characterSheetId: String,
|
||||
) {
|
||||
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||
characterSheetId = savedStateHandle
|
||||
.get<String>(CHARACTER_SHEET_ID)
|
||||
?: error("missing characterSheetId parameter"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun NavGraphBuilder.composableCharacterSheetPage() {
|
||||
composable(
|
||||
route = CharacterSheetDestination.baseRoute(),
|
||||
arguments = CharacterSheetDestination.arguments(),
|
||||
) {
|
||||
CharacterSheetPage()
|
||||
}
|
||||
}
|
||||
|
||||
fun NavHostController.navigateToCharacterSheet(
|
||||
characterSheetId: String,
|
||||
) {
|
||||
val route = CharacterSheetDestination.navigationRoute(characterSheetId = characterSheetId)
|
||||
navigate(route = route)
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.navigation.screen.destination
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.NavType
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.navArgument
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEditPage
|
||||
import com.pixelized.desktop.lwa.utils.extention.ARG
|
||||
|
||||
object CharacterSheetEditDestination {
|
||||
private const val ROUTE = "character.sheet.edit"
|
||||
private const val CHARACTER_ID = "id"
|
||||
|
||||
fun baseRoute() = "$ROUTE?${CHARACTER_ID.ARG}"
|
||||
|
||||
fun navigationRoute(characterSheetId: String?) = "$ROUTE?$CHARACTER_ID=$characterSheetId"
|
||||
|
||||
fun arguments() = listOf(
|
||||
navArgument(CHARACTER_ID) {
|
||||
nullable = true
|
||||
type = NavType.StringType
|
||||
},
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class Argument(
|
||||
val id: String?,
|
||||
) {
|
||||
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||
id = savedStateHandle.get<String>(CHARACTER_ID),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun NavGraphBuilder.composableCharacterSheetEditPage() {
|
||||
composable(
|
||||
route = CharacterSheetEditDestination.baseRoute(),
|
||||
arguments = CharacterSheetEditDestination.arguments(),
|
||||
) {
|
||||
CharacterSheetEditPage()
|
||||
}
|
||||
}
|
||||
|
||||
fun NavHostController.navigateToCharacterSheetEdit(
|
||||
id: String? = null,
|
||||
) {
|
||||
val route = CharacterSheetEditDestination.navigationRoute(characterSheetId = id)
|
||||
navigate(route = route)
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.navigation.window.destination
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.WindowController
|
||||
|
||||
@Stable
|
||||
class CharacterSheetEditWindow(
|
||||
val characterSheetId: String?,
|
||||
title: String,
|
||||
size: DpSize,
|
||||
) : Window(
|
||||
title = title,
|
||||
size = size,
|
||||
)
|
||||
|
||||
fun WindowController.navigateToCharacterSheetEdit(
|
||||
characterId: String?,
|
||||
title: String = "",
|
||||
) {
|
||||
showWindow(
|
||||
window = CharacterSheetEditWindow(
|
||||
characterSheetId = characterId,
|
||||
title = title,
|
||||
size = DpSize(
|
||||
width = 600.dp,
|
||||
height = maxWindowHeight - 32.dp,
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.navigation.window.destination
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.WindowController
|
||||
|
||||
@Stable
|
||||
class CharacterSheetWindow(
|
||||
val characterSheetId: String,
|
||||
title: String,
|
||||
size: DpSize,
|
||||
) : Window(
|
||||
title = title,
|
||||
size = size,
|
||||
)
|
||||
|
||||
fun WindowController.navigateToCharacterSheet(
|
||||
characterSheetId: String,
|
||||
title: String = "Feuille de personnage",
|
||||
) {
|
||||
showWindow(
|
||||
window = CharacterSheetWindow(
|
||||
characterSheetId = characterSheetId,
|
||||
title = title,
|
||||
size = DpSize(
|
||||
width = 400.dp + 64.dp,
|
||||
height = maxWindowHeight - 32.dp,
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -6,8 +6,6 @@ import androidx.navigation.NavHostController
|
|||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.navigateToGameMasterCharacterEditPage
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.WindowController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheetEdit
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult.BoundedRollResult.Difficulty
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult.BoundedRollResult.Result
|
||||
|
|
@ -23,9 +21,6 @@ import kotlinx.coroutines.flow.SharingStarted
|
|||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__edit__title
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class CharacterDetailPanelViewModel(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableCharacterSheetEditPage
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableCharacterSheetPage
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetMainNavHost(
|
||||
controller: NavHostController = rememberNavController(),
|
||||
startDestination: String,
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
LocalScreenController provides controller,
|
||||
) {
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
NavHost(
|
||||
navController = controller,
|
||||
startDestination = startDestination,
|
||||
) {
|
||||
composableCharacterSheetPage()
|
||||
composableCharacterSheetEditPage()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.copy
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SizeTransform
|
||||
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.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import com.pixelized.desktop.lwa.utils.extention.onPreviewEscape
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__copy__error
|
||||
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 CharacterSheetCopyDialogUio(
|
||||
val label: String,
|
||||
val value: LwaTextFieldUio,
|
||||
val validate: () -> Boolean,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetCopyDialog(
|
||||
dialog: State<CharacterSheetCopyDialogUio?>,
|
||||
onConfirm: (CharacterSheetCopyDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
AnimatedContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
targetState = dialog.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 32 }
|
||||
val exit = fadeOut() + slideOutVertically { 32 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
when (it) {
|
||||
null -> Box(
|
||||
modifier = Modifier,
|
||||
)
|
||||
|
||||
else -> {
|
||||
val focusRequester = remember {
|
||||
FocusRequester()
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
Dialog(
|
||||
dialog = it,
|
||||
focusRequester = focusRequester,
|
||||
onConfirm = onConfirm,
|
||||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Dialog(
|
||||
dialog: CharacterSheetCopyDialogUio,
|
||||
focusRequester: FocusRequester = remember { FocusRequester() },
|
||||
onConfirm: (CharacterSheetCopyDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = onDismissRequest,
|
||||
)
|
||||
.onPreviewEscape(
|
||||
escape = onDismissRequest,
|
||||
enter = { onConfirm(dialog) },
|
||||
)
|
||||
.fillMaxSize()
|
||||
.padding(all = 32.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
DecoratedBox {
|
||||
Surface {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(top = 16.dp, start = 24.dp, end = 24.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = dialog.label,
|
||||
)
|
||||
|
||||
LwaTextField(
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester = focusRequester)
|
||||
.width(512.dp),
|
||||
field = dialog.value,
|
||||
)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = dialog.value.errorFlow.collectAsState().value,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.lwa.typography.system.caption,
|
||||
color = MaterialTheme.lwa.colorScheme.base.error,
|
||||
text = stringResource(Res.string.character_sheet_edit__copy__error)
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 4.dp)
|
||||
.padding(horizontal = 16.dp)
|
||||
.align(alignment = Alignment.End),
|
||||
horizontalArrangement = Arrangement.spacedBy(
|
||||
space = 4.dp,
|
||||
alignment = Alignment.End
|
||||
)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
Text(
|
||||
color = MaterialTheme.colors.primary.copy(alpha = .7f),
|
||||
text = stringResource(Res.string.dialog__cancel_action)
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (dialog.validate()) {
|
||||
onConfirm(dialog)
|
||||
}
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.dialog__confirm_action)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.delete
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.SizeTransform
|
||||
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.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
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.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.utils.extention.onPreviewEscape
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__title
|
||||
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 CharacterSheetDeleteDialogUio(
|
||||
val characterSheetId: String,
|
||||
val name: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetDeleteDialog(
|
||||
dialog: State<CharacterSheetDeleteDialogUio?>,
|
||||
onConfirm: (CharacterSheetDeleteDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
AnimatedContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
targetState = dialog.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 32 }
|
||||
val exit = fadeOut() + slideOutVertically { 32 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
when (it) {
|
||||
null -> Box(
|
||||
modifier = Modifier,
|
||||
)
|
||||
|
||||
else -> {
|
||||
Dialog(
|
||||
dialog = it,
|
||||
onConfirm = onConfirm,
|
||||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Dialog(
|
||||
dialog: CharacterSheetDeleteDialogUio,
|
||||
onConfirm: (CharacterSheetDeleteDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = onDismissRequest,
|
||||
)
|
||||
.onPreviewEscape(
|
||||
escape = onDismissRequest,
|
||||
enter = { onConfirm(dialog) },
|
||||
)
|
||||
.fillMaxSize()
|
||||
.padding(all = 32.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
DecoratedBox {
|
||||
Surface {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 24.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(top = 24.dp),
|
||||
style = MaterialTheme.typography.h6,
|
||||
text = stringResource(Res.string.character_sheet__delete_dialog__title),
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp),
|
||||
style = MaterialTheme.typography.body1,
|
||||
text = stringResource(
|
||||
Res.string.character_sheet__delete_dialog__description,
|
||||
dialog.name
|
||||
),
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 4.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(
|
||||
space = 4.dp,
|
||||
alignment = Alignment.End
|
||||
)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.dialog__cancel_action)
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
onClick = { onConfirm(dialog) },
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.dialog__confirm_action)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,352 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail
|
||||
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Node
|
||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
|
||||
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
||||
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.character_sheet__sub_characteristics__armor
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__damage_bonus
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hit_point
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hp_grow
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__learning
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__movement
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__power_point
|
||||
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 lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__armor
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__bonus_damage
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hit_point
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hp_grow
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__learning
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__movement
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__power_point
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class CharacterSheetFactory(
|
||||
private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory,
|
||||
private val skillUseCase: ExpressionUseCase,
|
||||
) {
|
||||
suspend fun convertToUio(
|
||||
characterSheetId: String,
|
||||
characterSheet: CharacterSheet?,
|
||||
alterations: Map<String, List<FieldAlteration>>,
|
||||
): CharacterSheetPageUio? {
|
||||
if (characterSheet == null) return null
|
||||
|
||||
val alteredCharacterSheet = alteredCharacterSheetFactory.sheet(
|
||||
characterSheet = characterSheet,
|
||||
alterations = alterations,
|
||||
)
|
||||
|
||||
return CharacterSheetPageUio(
|
||||
id = alteredCharacterSheet.id,
|
||||
name = alteredCharacterSheet.name,
|
||||
diminished = alteredCharacterSheet.diminished,
|
||||
characteristics = listOf(
|
||||
Characteristic(
|
||||
id = CharacteristicId.STR,
|
||||
label = getString(Res.string.character_sheet__characteristics__str),
|
||||
value = "${alteredCharacterSheet.strength}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__str),
|
||||
description = getString(Res.string.tooltip__characteristics__strength),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__str),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.strength * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.DEX,
|
||||
label = getString(Res.string.character_sheet__characteristics__dex),
|
||||
value = "${alteredCharacterSheet.dexterity}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__dex),
|
||||
description = getString(Res.string.tooltip__characteristics__dexterity),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__dex),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.dexterity * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.CON,
|
||||
label = getString(Res.string.character_sheet__characteristics__con),
|
||||
value = "${alteredCharacterSheet.constitution}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__con),
|
||||
description = getString(Res.string.tooltip__characteristics__constitution),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__con),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.constitution * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.HEI,
|
||||
label = getString(Res.string.character_sheet__characteristics__hei),
|
||||
value = "${alteredCharacterSheet.height}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__hei),
|
||||
description = getString(Res.string.tooltip__characteristics__height),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__hei),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.height * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.INT,
|
||||
label = getString(Res.string.character_sheet__characteristics__int),
|
||||
value = "${alteredCharacterSheet.intelligence}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__int),
|
||||
description = getString(Res.string.tooltip__characteristics__intelligence),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__int),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.intelligence * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.POW,
|
||||
label = getString(Res.string.character_sheet__characteristics__pow),
|
||||
value = "${alteredCharacterSheet.power}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__pow),
|
||||
description = getString(Res.string.tooltip__characteristics__power),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__pow),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.power * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.CHA,
|
||||
label = getString(Res.string.character_sheet__characteristics__cha),
|
||||
value = "${alteredCharacterSheet.charisma}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__characteristics__cha),
|
||||
description = getString(Res.string.tooltip__characteristics__charisma),
|
||||
),
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = getString(Res.string.character_sheet__characteristics__cha),
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = alteredCharacterSheet.charisma * 5 - alteredCharacterSheet.diminished,
|
||||
),
|
||||
),
|
||||
),
|
||||
subCharacteristics = listOf(
|
||||
Characteristic(
|
||||
id = CharacteristicId.MOV,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__movement),
|
||||
value = "${alteredCharacterSheet.movement}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__movement),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__movement),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.HP,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__hit_point),
|
||||
value = alteredCharacterSheet.maxHp.let { maxHp -> "${maxHp - alteredCharacterSheet.damage}/${maxHp}" },
|
||||
editable = true,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__hit_point),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__hit_point),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.PP,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__power_point),
|
||||
value = alteredCharacterSheet.maxPp.let { maxPp -> "${maxPp - alteredCharacterSheet.power}/${maxPp}" },
|
||||
editable = true,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__power_point),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__power_point),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.DMG,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
|
||||
value = alteredCharacterSheet.damageBonus,
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__bonus_damage),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.ARMOR,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__armor),
|
||||
value = "${alteredCharacterSheet.armor}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__armor),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__armor),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.LB,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__learning),
|
||||
value = "${alteredCharacterSheet.learning}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__learning),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__learning),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.GHP,
|
||||
label = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
|
||||
value = "${alteredCharacterSheet.hpGrow}",
|
||||
editable = false,
|
||||
tooltips = BasicTooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__hp_grow),
|
||||
),
|
||||
roll = null,
|
||||
),
|
||||
),
|
||||
commonSkills = characterSheet.commonSkills.map { skill ->
|
||||
val value = skillUseCase.computeSkillValue(
|
||||
sheet = alteredCharacterSheet,
|
||||
skill = skill,
|
||||
diminished = alteredCharacterSheet.diminished,
|
||||
alterations = alterations,
|
||||
)
|
||||
Node(
|
||||
id = skill.id,
|
||||
label = skill.label,
|
||||
value = value,
|
||||
used = skill.used,
|
||||
tooltips = skill.description?.let {
|
||||
BasicTooltipUio(
|
||||
title = skill.label,
|
||||
description = it,
|
||||
)
|
||||
},
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = skill.label,
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = value,
|
||||
),
|
||||
)
|
||||
},
|
||||
specialSKills = characterSheet.specialSkills.map { skill ->
|
||||
val value = skillUseCase.computeSkillValue(
|
||||
sheet = alteredCharacterSheet,
|
||||
skill = skill,
|
||||
diminished = alteredCharacterSheet.diminished,
|
||||
alterations = alterations,
|
||||
)
|
||||
Node(
|
||||
id = skill.id,
|
||||
label = skill.label,
|
||||
value = value,
|
||||
used = skill.used,
|
||||
tooltips = skill.description?.let {
|
||||
BasicTooltipUio(
|
||||
title = skill.label,
|
||||
description = it,
|
||||
)
|
||||
},
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = skill.label,
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = value,
|
||||
),
|
||||
)
|
||||
},
|
||||
magicsSkills = characterSheet.magicSkills.map { skill ->
|
||||
val value = skillUseCase.computeSkillValue(
|
||||
sheet = alteredCharacterSheet,
|
||||
skill = skill,
|
||||
diminished = alteredCharacterSheet.diminished,
|
||||
alterations = alterations,
|
||||
)
|
||||
Node(
|
||||
id = skill.id,
|
||||
label = skill.label,
|
||||
value = value,
|
||||
used = skill.used,
|
||||
tooltips = skill.description?.let {
|
||||
BasicTooltipUio(
|
||||
title = skill.label,
|
||||
description = it,
|
||||
)
|
||||
},
|
||||
roll = RollAction.Uio.BoundedRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = skill.label,
|
||||
rollAction = "1d100",
|
||||
rollSuccessValue = value,
|
||||
),
|
||||
)
|
||||
},
|
||||
actions = characterSheet.actions.mapNotNull { action ->
|
||||
if (action.default.isEmpty()) return@mapNotNull null
|
||||
|
||||
CharacterSheetPageUio.Roll(
|
||||
label = action.label,
|
||||
value = action.default,
|
||||
roll = RollAction.Uio.BoundlessRollActionUio(
|
||||
characterSheetId = characterSheetId,
|
||||
label = action.label,
|
||||
canBeCritical = action.canBeCritical,
|
||||
rollDefaultAction = action.default,
|
||||
rollSpecialAction = action.special,
|
||||
rollCriticalAction = action.critical,
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,690 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.SizeTransform
|
||||
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.desktop.ui.tooling.preview.Preview
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.ScrollState
|
||||
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.PaddingValues
|
||||
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.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.CheckboxDefaults
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
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.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.LocalWindowController
|
||||
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent
|
||||
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogViewModel
|
||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipLayout
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindow
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheetEdit
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollPage
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialog
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialog
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.preview.rememberCharacterSheetPreview
|
||||
import com.pixelized.desktop.lwa.utils.preview.ContentPreview
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete__label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__edit__label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__common_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__magic_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__special_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__edit__title
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_skull_24dp
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@Stable
|
||||
data class CharacterSheetPageUio(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val diminished: Int,
|
||||
val characteristics: List<Characteristic>,
|
||||
val subCharacteristics: List<Characteristic>,
|
||||
val commonSkills: List<Node>,
|
||||
val specialSKills: List<Node>,
|
||||
val magicsSkills: List<Node>,
|
||||
val actions: List<Roll>,
|
||||
) {
|
||||
@Stable
|
||||
data class Characteristic(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val value: String,
|
||||
val editable: Boolean,
|
||||
val tooltips: BasicTooltipUio?,
|
||||
val roll: RollAction.Uio?,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class Node(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val value: Int,
|
||||
val used: Boolean,
|
||||
val tooltips: BasicTooltipUio? = null,
|
||||
val roll: RollAction.Uio,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class Roll(
|
||||
val label: String,
|
||||
val value: String,
|
||||
val roll: RollAction.Uio,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetPage(
|
||||
viewModel: CharacterSheetViewModel = koinViewModel(),
|
||||
diminishedDialogViewModel: CharacterSheetDiminishedDialogViewModel = koinViewModel(),
|
||||
rollViewModel: RollViewModel = koinViewModel(),
|
||||
) {
|
||||
val windowController = LocalWindowController.current
|
||||
val screen = LocalScreenController.current
|
||||
val window = LocalWindow.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val blurController = remember { BlurContentController() }
|
||||
val sheet = viewModel.sheetFlow.collectAsState()
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
BlurContent(
|
||||
controller = blurController,
|
||||
content = {
|
||||
sheet.value?.let { sheet ->
|
||||
CharacterSheetPageContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
characterSheet = sheet,
|
||||
onDiminished = {
|
||||
blurController.show()
|
||||
scope.launch {
|
||||
diminishedDialogViewModel.showDiminishedDialog(
|
||||
characterSheetId = it
|
||||
)
|
||||
}
|
||||
},
|
||||
onEdit = {
|
||||
windowController.navigateToCharacterSheetEdit(
|
||||
title = runBlocking { getString(Res.string.character_sheet_edit__edit__title) },
|
||||
characterId = sheet.id,
|
||||
)
|
||||
},
|
||||
onDelete = {
|
||||
blurController.show()
|
||||
viewModel.showConfirmCharacterDeletionDialog()
|
||||
},
|
||||
onCharacteristic = { characteristic ->
|
||||
if (characteristic.roll == null) return@CharacterSheetPageContent
|
||||
scope.launch {
|
||||
rollViewModel.prepareRoll(characteristic.roll)
|
||||
blurController.show()
|
||||
viewModel.showRollOverlay()
|
||||
}
|
||||
},
|
||||
onSubCharacteristic = {
|
||||
// blurController.show()
|
||||
// scope.launch {
|
||||
// viewModel.showSubCharacteristicDialog(id = it.id)
|
||||
// }
|
||||
},
|
||||
onSkill = { node ->
|
||||
scope.launch {
|
||||
blurController.show()
|
||||
rollViewModel.prepareRoll(node.roll)
|
||||
viewModel.showRollOverlay()
|
||||
}
|
||||
},
|
||||
onUseSkill = viewModel::onUseSkill,
|
||||
onRoll = { roll ->
|
||||
scope.launch {
|
||||
blurController.show()
|
||||
rollViewModel.prepareRoll(roll.roll)
|
||||
viewModel.showRollOverlay()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
AnimatedContent(
|
||||
targetState = viewModel.displayRollOverlay.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 64 }
|
||||
val exit = fadeOut() + slideOutVertically { 64 }
|
||||
enter togetherWith exit
|
||||
},
|
||||
) { roll ->
|
||||
when (roll) {
|
||||
true -> RollPage(
|
||||
viewModel = rollViewModel,
|
||||
onDismissRequest = {
|
||||
blurController.hide()
|
||||
viewModel.hideRollOverlay()
|
||||
},
|
||||
onRoll = {
|
||||
scope.launch {
|
||||
rollViewModel.roll()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
else -> Box(
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
CharacterSheetDeleteConfirmationDialog(
|
||||
dialog = viewModel.displayDeleteConfirmationDialog,
|
||||
onConfirm = {
|
||||
scope.launch {
|
||||
viewModel.deleteCharacter(id = it.id)
|
||||
if (screen.popBackStack().not()) {
|
||||
windowController.hideWindow(window = window)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
blurController.hide()
|
||||
viewModel.hideConfirmCharacterDeletionDialog()
|
||||
},
|
||||
)
|
||||
|
||||
CharacterSheetDiminishedDialog(
|
||||
dialog = viewModel.diminishedDialog,
|
||||
onConfirm = {
|
||||
scope.launch {
|
||||
diminishedDialogViewModel.changeDiminished(dialog = it)
|
||||
diminishedDialogViewModel.hideDiminishedDialog()
|
||||
blurController.hide()
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
diminishedDialogViewModel.hideDiminishedDialog()
|
||||
blurController.hide()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetPageContent(
|
||||
modifier: Modifier = Modifier,
|
||||
scrollState: ScrollState = rememberScrollState(),
|
||||
characterSheet: CharacterSheetPageUio,
|
||||
onDiminished: (characterSheetId: String) -> Unit,
|
||||
onEdit: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
onCharacteristic: (characteristic: Characteristic) -> Unit,
|
||||
onSubCharacteristic: (characteristic: Characteristic) -> Unit,
|
||||
onSkill: (skill: CharacterSheetPageUio.Node) -> Unit,
|
||||
onUseSkill: (skill: CharacterSheetPageUio.Node) -> Unit,
|
||||
onRoll: (roll: CharacterSheetPageUio.Roll) -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = characterSheet.name,
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { onDiminished(characterSheet.id) },
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 24.dp),
|
||||
painter = painterResource(Res.drawable.ic_skull_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
AnimatedContent(
|
||||
modifier = Modifier.align(alignment = Alignment.BottomCenter),
|
||||
targetState = characterSheet.diminished,
|
||||
transitionSpec = {
|
||||
val sign = if (targetState > initialState) 1 else -1
|
||||
val enter = fadeIn() + slideInVertically { 16 * sign }
|
||||
val exit = fadeOut() + slideOutVertically { -16 * sign }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.caption,
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
text = "${it}",
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(
|
||||
onClick = { showMenu.value = showMenu.value.not() },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showMenu.value,
|
||||
onDismissRequest = { showMenu.value = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
showMenu.value = false
|
||||
onEdit()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Edit,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = stringResource(Res.string.character_sheet__edit__label),
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
showMenu.value = false
|
||||
onDelete()
|
||||
},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Delete,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = stringResource(Res.string.character_sheet__delete__label),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
content = { paddingValues ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state = scrollState)
|
||||
.padding(paddingValues)
|
||||
.padding(all = 16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(100.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
characterSheet.characteristics.forEach {
|
||||
Stat(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = 120.dp),
|
||||
characteristic = it,
|
||||
onClick = { onCharacteristic(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.weight(2f / 3f),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__sub_characteristics__title),
|
||||
)
|
||||
characterSheet.subCharacteristics.forEach {
|
||||
SubCharacteristics(
|
||||
modifier = Modifier.cell(),
|
||||
characteristic = it,
|
||||
onCharacteristic = when {
|
||||
it.editable -> onSubCharacteristic
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 8.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__skills__common_title),
|
||||
)
|
||||
characterSheet.commonSkills.forEach { skill ->
|
||||
Skill(
|
||||
modifier = Modifier.cell(),
|
||||
node = skill,
|
||||
onClick = { onSkill(skill) },
|
||||
onUse = { onUseSkill(skill) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = characterSheet.specialSKills.isNotEmpty()
|
||||
) {
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__skills__special_title),
|
||||
)
|
||||
characterSheet.specialSKills.forEach { occupation ->
|
||||
Skill(
|
||||
modifier = Modifier.cell(),
|
||||
node = occupation,
|
||||
onClick = { onSkill(occupation) },
|
||||
onUse = { onUseSkill(occupation) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(
|
||||
visible = characterSheet.magicsSkills.isNotEmpty()
|
||||
) {
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
textAlign = TextAlign.Center,
|
||||
text = stringResource(Res.string.character_sheet__skills__magic_title),
|
||||
)
|
||||
characterSheet.magicsSkills.forEach { magic ->
|
||||
Skill(
|
||||
modifier = Modifier.cell(),
|
||||
node = magic,
|
||||
onClick = { onSkill(magic) },
|
||||
onUse = { onUseSkill(magic) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
characterSheet.actions.forEach { roll ->
|
||||
Roll(
|
||||
modifier = Modifier.cell(),
|
||||
label = roll.label,
|
||||
onClick = { onRoll(roll) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun Stat(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(all = 8.dp),
|
||||
characteristic: Characteristic,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
BasicTooltipLayout(
|
||||
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
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun SubCharacteristics(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(horizontal = 8.dp),
|
||||
characteristic: Characteristic,
|
||||
onCharacteristic: ((characteristic: Characteristic) -> Unit)?,
|
||||
) {
|
||||
BasicTooltipLayout(
|
||||
tooltip = characteristic.tooltips,
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(enabled = characteristic.editable && onCharacteristic != null) {
|
||||
onCharacteristic?.invoke(characteristic)
|
||||
}
|
||||
.padding(paddingValues = paddingValues).then(other = modifier),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
text = characteristic.label
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = when (characteristic.editable && onCharacteristic != null) {
|
||||
true -> MaterialTheme.colors.primary
|
||||
else -> MaterialTheme.colors.onSurface
|
||||
},
|
||||
text = characteristic.value,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun Skill(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(horizontal = 8.dp),
|
||||
node: CharacterSheetPageUio.Node,
|
||||
onClick: () -> Unit,
|
||||
onUse: () -> Unit,
|
||||
) {
|
||||
BasicTooltipLayout(
|
||||
tooltip = node.tooltips,
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.padding(paddingValues = paddingValues)
|
||||
.then(other = modifier),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = node.label
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colors.primary,
|
||||
text = "${node.value}",
|
||||
)
|
||||
Checkbox(
|
||||
modifier = Modifier.size(size = 32.dp),
|
||||
checked = node.used,
|
||||
colors = CheckboxDefaults.colors(
|
||||
checkedColor = MaterialTheme.colors.primary,
|
||||
),
|
||||
onCheckedChange = { onUse() },
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Roll(
|
||||
modifier: Modifier = Modifier,
|
||||
paddingValues: PaddingValues = PaddingValues(start = 10.dp, end = 14.dp),
|
||||
label: String,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(onClick = onClick)
|
||||
.padding(paddingValues = paddingValues)
|
||||
.then(other = modifier),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = label
|
||||
)
|
||||
Icon(
|
||||
modifier = Modifier.size(size = 24.dp),
|
||||
painter = painterResource(Res.drawable.ic_d20_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Modifier.cell(): Modifier = this.fillMaxWidth().height(height = 32.dp)
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun DecoratedBoxPreview() {
|
||||
ContentPreview {
|
||||
CharacterSheetPageContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
scrollState = rememberScrollState(),
|
||||
characterSheet = rememberCharacterSheetPreview(),
|
||||
onDiminished = { },
|
||||
onEdit = { },
|
||||
onDelete = { },
|
||||
onCharacteristic = { },
|
||||
onSubCharacteristic = { },
|
||||
onSkill = { },
|
||||
onUseSkill = { },
|
||||
onRoll = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetDestination
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogUio
|
||||
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private typealias CSDCDialogUio = CharacterSheetDeleteConfirmationDialogUio
|
||||
|
||||
class CharacterSheetViewModel(
|
||||
private val characterRepository: CharacterSheetRepository,
|
||||
private val networkRepository: NetworkRepository,
|
||||
alteration: AlterationRepository,
|
||||
factory: CharacterSheetFactory,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
|
||||
private val argument = CharacterSheetDestination.Argument(savedStateHandle)
|
||||
|
||||
private val _displayDeleteConfirmationDialog = mutableStateOf<CSDCDialogUio?>(null)
|
||||
val displayDeleteConfirmationDialog: State<CSDCDialogUio?> get() = _displayDeleteConfirmationDialog
|
||||
|
||||
private val _displayRollOverlay = mutableStateOf(false)
|
||||
val displayRollOverlay: State<Boolean> get() = _displayRollOverlay
|
||||
|
||||
private val _diminishedDialog = mutableStateOf<CharacterSheetDiminishedDialogUio?>(null)
|
||||
val diminishedDialog: State<CharacterSheetDiminishedDialogUio?> get() = _diminishedDialog
|
||||
|
||||
val sheetFlow = combine(
|
||||
characterRepository.characterDetailFlow(characterSheetId = argument.characterSheetId),
|
||||
alteration.activeFieldAlterationsFlow(characterSheetId = argument.characterSheetId),
|
||||
transform = { characterSheet, alterations ->
|
||||
factory.convertToUio(
|
||||
characterSheetId = argument.characterSheetId,
|
||||
characterSheet = characterSheet,
|
||||
alterations = alterations,
|
||||
)
|
||||
},
|
||||
).stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
suspend fun deleteCharacter(id: String) {
|
||||
characterRepository.deleteCharacter(characterSheetId = id)
|
||||
}
|
||||
|
||||
fun onUseSkill(skill: CharacterSheetPageUio.Node) {
|
||||
viewModelScope.launch {
|
||||
networkRepository.share(
|
||||
message = CharacterSheetEvent.UpdateSkillUsageEvent(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
characterSheetId = argument.characterSheetId,
|
||||
skillId = skill.id,
|
||||
used = skill.used.not(),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun showConfirmCharacterDeletionDialog() {
|
||||
val preview = characterRepository.characterPreview(
|
||||
characterId = argument.characterSheetId
|
||||
) ?: return
|
||||
_displayDeleteConfirmationDialog.value = CharacterSheetDeleteConfirmationDialogUio(
|
||||
id = preview.characterSheetId,
|
||||
name = preview.name,
|
||||
)
|
||||
}
|
||||
|
||||
fun hideConfirmCharacterDeletionDialog() {
|
||||
_displayDeleteConfirmationDialog.value = null
|
||||
}
|
||||
|
||||
fun showRollOverlay() {
|
||||
_displayRollOverlay.value = true
|
||||
}
|
||||
|
||||
fun hideRollOverlay() {
|
||||
_displayRollOverlay.value = false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
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.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.utils.extention.onPreviewEscape
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete_dialog__title
|
||||
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 CharacterSheetDeleteConfirmationDialogUio(
|
||||
val id: String,
|
||||
val name: String,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetDeleteConfirmationDialog(
|
||||
dialog: State<CharacterSheetDeleteConfirmationDialogUio?>,
|
||||
onConfirm: (CharacterSheetDeleteConfirmationDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
dialog.value?.let {
|
||||
Dialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
content = {
|
||||
CharacterSheetDeleteConfirmationContent(
|
||||
dialog = it,
|
||||
onConfirm = onConfirm,
|
||||
onDismissRequest = onDismissRequest,
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CharacterSheetDeleteConfirmationContent(
|
||||
dialog: CharacterSheetDeleteConfirmationDialogUio,
|
||||
onConfirm: (CharacterSheetDeleteConfirmationDialogUio) -> Unit,
|
||||
onDismissRequest: () -> Unit,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = null,
|
||||
onClick = onDismissRequest,
|
||||
)
|
||||
.onPreviewEscape(
|
||||
escape = onDismissRequest,
|
||||
enter = { onConfirm(dialog) },
|
||||
)
|
||||
.fillMaxSize()
|
||||
.padding(all = 32.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
DecoratedBox {
|
||||
Surface {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(space = 24.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(top = 24.dp),
|
||||
style = MaterialTheme.typography.h6,
|
||||
text = stringResource(Res.string.character_sheet__delete_dialog__title),
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 24.dp),
|
||||
style = MaterialTheme.typography.body1,
|
||||
text = stringResource(
|
||||
Res.string.character_sheet__delete_dialog__description,
|
||||
dialog.name
|
||||
),
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.padding(bottom = 4.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(
|
||||
space = 4.dp,
|
||||
alignment = Alignment.End
|
||||
)
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onDismissRequest,
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.dialog__cancel_action)
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
onClick = { onConfirm(dialog) },
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.dialog__confirm_action)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.preview
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
|
||||
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun rememberCharacterSheetPreview(): CharacterSheetPageUio {
|
||||
return remember {
|
||||
CharacterSheetPageUio(
|
||||
id = "Koryas_Id",
|
||||
name = "Koryas",
|
||||
diminished = 0,
|
||||
characteristics = listOf(
|
||||
Characteristic(
|
||||
id = CharacteristicId.STR,
|
||||
label = "Force",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.DEX,
|
||||
label = "Dexterité",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.CON,
|
||||
label = "Constitution",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.HEI,
|
||||
label = "Taille",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.INT,
|
||||
label = "Intelligence",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.POW,
|
||||
label = "Pouvoir",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.CHA,
|
||||
label = "Charisme",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
),
|
||||
subCharacteristics = listOf(
|
||||
Characteristic(
|
||||
id = CharacteristicId.MOV,
|
||||
label = "Mouvement",
|
||||
value = "10",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.HP,
|
||||
label = "Point de vie",
|
||||
value = "20/20",
|
||||
tooltips = null,
|
||||
editable = true,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.PP,
|
||||
label = "Point de pouvoir",
|
||||
value = "15/15",
|
||||
tooltips = null,
|
||||
editable = true,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.DMG,
|
||||
label = "Domage bonus",
|
||||
value = "1d4",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.ARMOR,
|
||||
label = "Armure",
|
||||
value = "0",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.LB,
|
||||
label = "Apprentissage",
|
||||
value = "0",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
Characteristic(
|
||||
id = CharacteristicId.GHP,
|
||||
label = "Bonus de PV",
|
||||
value = "5",
|
||||
tooltips = null,
|
||||
editable = false,
|
||||
roll = null,
|
||||
),
|
||||
),
|
||||
commonSkills = emptyList(),
|
||||
specialSKills = emptyList(),
|
||||
magicsSkills = emptyList(),
|
||||
actions = emptyList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,623 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.occupation
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.LevelUpWrapperUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
|
||||
import com.pixelized.desktop.lwa.utils.extention.unAccent
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__critical_action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__default_action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__description_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__spacial_action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__cha
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__con
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__dex
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__hei
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__int
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__level
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__portrait
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__pow
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__str
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__thumbnail
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__level_up
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__name_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bonus_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__level_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__special_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_base
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_description
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_label
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import kotlin.math.max
|
||||
|
||||
class CharacterSheetEditFactory(
|
||||
private val skillFieldFactory: SkillFieldFactory,
|
||||
private val characterSheetUseCase: CharacterSheetUseCase,
|
||||
) {
|
||||
suspend fun updateCharacterSheet(
|
||||
currentSheet: CharacterSheet?,
|
||||
editedSheet: CharacterSheetEditPageUio,
|
||||
): CharacterSheet {
|
||||
|
||||
val level = editedSheet.level.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.level
|
||||
?: 1
|
||||
val strength = editedSheet.strength.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.strength
|
||||
?: 0
|
||||
val dexterity = editedSheet.dexterity.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.dexterity
|
||||
?: 0
|
||||
val constitution = editedSheet.constitution.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.constitution
|
||||
?: 0
|
||||
val height = editedSheet.height.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.height
|
||||
?: 0
|
||||
val intelligence = editedSheet.intelligence.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.intelligence
|
||||
?: 0
|
||||
val power = editedSheet.power.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.power
|
||||
?: 0
|
||||
val charisma = editedSheet.charisma.unpack()?.toIntOrNull()
|
||||
?: currentSheet?.charisma
|
||||
?: 0
|
||||
|
||||
return CharacterSheet(
|
||||
id = editedSheet.id.value,
|
||||
name = editedSheet.name.value.value,
|
||||
job = "",
|
||||
portrait = editedSheet.portrait.value.value,
|
||||
thumbnail = editedSheet.thumbnail.value.value,
|
||||
externalLink = "",
|
||||
level = level,
|
||||
shouldLevelUp = editedSheet.levelUp.checked.value,
|
||||
strength = strength,
|
||||
dexterity = dexterity,
|
||||
constitution = constitution,
|
||||
height = height,
|
||||
intelligence = intelligence,
|
||||
power = power,
|
||||
charisma = charisma,
|
||||
damage = currentSheet?.damage ?: 0,
|
||||
fatigue = currentSheet?.fatigue ?: 0,
|
||||
diminished = currentSheet?.diminished ?: 0,
|
||||
alterations = currentSheet?.alterations ?: emptyList(),
|
||||
commonSkills = editedSheet.commonSkills.map { editedSkill ->
|
||||
val currentSkill = currentSheet?.commonSkills?.firstOrNull {
|
||||
it.id == editedSkill.id
|
||||
}
|
||||
CharacterSheet.Skill(
|
||||
id = editedSkill.id,
|
||||
label = editedSkill.label,
|
||||
description = currentSkill?.description
|
||||
?: commonSkillDescription(skillId = editedSkill.id),
|
||||
base = currentSkill?.base
|
||||
?: commonSkillBase(skillId = editedSkill.id),
|
||||
bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
|
||||
level = editedSkill.level.value.value.toIntOrNull() ?: 0,
|
||||
occupation = editedSkill.option.checked.value,
|
||||
used = currentSkill?.used ?: false,
|
||||
)
|
||||
},
|
||||
specialSkills = editedSheet.specialSkills.map { editedSkill ->
|
||||
val currentSkill = currentSheet?.specialSkills?.firstOrNull {
|
||||
it.id == editedSkill.id
|
||||
}
|
||||
CharacterSheet.Skill(
|
||||
id = editedSkill.id,
|
||||
label = editedSkill.label.value.value,
|
||||
description = editedSkill.description.value.value,
|
||||
base = editedSkill.base.value.value,
|
||||
bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
|
||||
level = editedSkill.level.value.value.toIntOrNull() ?: 0,
|
||||
occupation = editedSkill.options.occupation,
|
||||
used = currentSkill?.used ?: false,
|
||||
)
|
||||
},
|
||||
magicSkills = editedSheet.magicSkills.map { editedSkill ->
|
||||
val currentSkill = currentSheet?.magicSkills?.firstOrNull {
|
||||
it.id == editedSkill.id
|
||||
}
|
||||
CharacterSheet.Skill(
|
||||
id = editedSkill.id,
|
||||
label = editedSkill.label.value.value,
|
||||
description = editedSkill.description.value.value,
|
||||
base = editedSkill.base.value.value,
|
||||
bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
|
||||
level = editedSkill.level.value.value.toIntOrNull() ?: 0,
|
||||
occupation = editedSkill.options.occupation,
|
||||
used = currentSkill?.used ?: false,
|
||||
)
|
||||
},
|
||||
actions = editedSheet.actions.map {
|
||||
CharacterSheet.Roll(
|
||||
id = it.id,
|
||||
label = it.label.valueFlow.value,
|
||||
description = it.description.valueFlow.value,
|
||||
canBeCritical = it.canBeCritical.checked.value,
|
||||
default = it.default.valueFlow.value,
|
||||
special = it.special?.valueFlow?.value,
|
||||
critical = it.critical?.valueFlow?.value,
|
||||
)
|
||||
},
|
||||
tags = emptyList(),
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun convertToUio(
|
||||
sheet: CharacterSheet?,
|
||||
onDeleteSkill: (id: String) -> Unit,
|
||||
): CharacterSheetEditPageUio {
|
||||
val str = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__str),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.strength?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10")
|
||||
),
|
||||
)
|
||||
val dex = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__dex),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.dexterity?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10"),
|
||||
),
|
||||
)
|
||||
val con = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__con),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.constitution?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10"),
|
||||
)
|
||||
)
|
||||
val hei = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__hei),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.height?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10"),
|
||||
)
|
||||
)
|
||||
val int = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__int),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.intelligence?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10"),
|
||||
)
|
||||
)
|
||||
val pow = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__pow),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.power?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10"),
|
||||
)
|
||||
)
|
||||
val cha = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__cha),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.charisma?.toString() ?: "",
|
||||
placeholder = mutableStateOf("10"),
|
||||
)
|
||||
)
|
||||
|
||||
fun str(): Int = str.unpack()?.toIntOrNull() ?: 0
|
||||
fun dex(): Int = dex.unpack()?.toIntOrNull() ?: 0
|
||||
fun con(): Int = con.unpack()?.toIntOrNull() ?: 0
|
||||
fun hei(): Int = hei.unpack()?.toIntOrNull() ?: 0
|
||||
fun int(): Int = int.unpack()?.toIntOrNull() ?: 0
|
||||
fun pow(): Int = pow.unpack()?.toIntOrNull() ?: 0
|
||||
fun cha(): Int = cha.unpack()?.toIntOrNull() ?: 0
|
||||
|
||||
val specialSkillsLabel = getString(Res.string.character_sheet_edit__skills__special_title)
|
||||
val magicSkillsLabel = getString(Res.string.character_sheet_edit__skills__magic_title)
|
||||
val portrait = mutableStateOf(sheet?.portrait ?: "")
|
||||
val thumbnail = mutableStateOf(sheet?.thumbnail ?: "")
|
||||
|
||||
return with(characterSheetUseCase) {
|
||||
val name = skillFieldFactory.createWrapper(
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__name_label)),
|
||||
value = sheet?.name ?: ""
|
||||
)
|
||||
CharacterSheetEditPageUio(
|
||||
id = derivedStateOf {
|
||||
sheet?.id ?: name.value.value.unAccent().replace(" ", "_")
|
||||
},
|
||||
levelUp = createLevelUpWrapper(shouldLevelUp = sheet?.shouldLevelUp ?: false),
|
||||
name = name,
|
||||
level = SimpleFieldUio(
|
||||
label = getString(Res.string.character_sheet_edit__characteristics__level),
|
||||
value = skillFieldFactory.createWrapper(
|
||||
value = sheet?.level?.toString() ?: "",
|
||||
placeholder = mutableStateOf("1"),
|
||||
)
|
||||
),
|
||||
portrait = TextFieldWrapperUio(
|
||||
enable = true,
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__characteristics__portrait)),
|
||||
value = portrait,
|
||||
placeholder = mutableStateOf(null),
|
||||
onValueChange = { portrait.value = it },
|
||||
),
|
||||
thumbnail = TextFieldWrapperUio(
|
||||
enable = true,
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__characteristics__thumbnail)),
|
||||
value = thumbnail,
|
||||
placeholder = mutableStateOf(null),
|
||||
onValueChange = { thumbnail.value = it },
|
||||
),
|
||||
strength = str,
|
||||
dexterity = dex,
|
||||
constitution = con,
|
||||
height = hei,
|
||||
intelligence = int,
|
||||
power = pow,
|
||||
charisma = cha,
|
||||
commonSkills = listOf(
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.COMBAT_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__combat_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__combat_description),
|
||||
base = derivedStateOf { normalize(dex() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.DODGE_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__dodge_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__dodge_description),
|
||||
base = derivedStateOf { normalize(dex() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.GRAB_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__grab_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__grab_description),
|
||||
base = derivedStateOf { normalize(str() + hei()) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.THROW_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__throw_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__throw_description),
|
||||
base = derivedStateOf { normalize(str() + dex()) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.ATHLETICS_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__athletics_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__athletics_description),
|
||||
base = derivedStateOf { normalize(str() + con() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.ACROBATICS_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__acrobatics_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__acrobatics_description),
|
||||
base = derivedStateOf { normalize(dex() + con() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.PERCEPTION_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__perception_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__perception_description),
|
||||
base = derivedStateOf { normalize(10 + int() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.SEARCH_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__search_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__search_description),
|
||||
base = derivedStateOf { normalize(10 + int() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.EMPATHY_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__empathy_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__empathy_description),
|
||||
base = derivedStateOf { normalize(cha() + int()) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.PERSUASION_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__persuasion_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__persuasion_description),
|
||||
base = derivedStateOf { normalize(cha() * 3) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.INTIMIDATION_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__intimidation_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__intimidation_description),
|
||||
base = derivedStateOf { normalize(cha() + max(pow(), hei()) * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.SPIEL_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__spiel_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__spiel_description),
|
||||
base = derivedStateOf { normalize(cha() * 2 + int()) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.BARGAIN_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__bargain_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__bargain_description),
|
||||
base = derivedStateOf { normalize(cha() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.DISCRETION_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__discretion_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__discretion_description),
|
||||
base = derivedStateOf { normalize(cha() + dex() * 2 - hei()) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__sleight_of_hand_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__sleight_of_hand_description),
|
||||
base = derivedStateOf { normalize(dex() * 2) },
|
||||
),
|
||||
createBaseSkill(
|
||||
sheet = sheet,
|
||||
id = CharacterSheet.CommonSkillId.AID_ID,
|
||||
label = getString(Res.string.character_sheet_edit__skills__aid_label),
|
||||
description = getString(Res.string.character_sheet_edit__skills__aid_description),
|
||||
base = derivedStateOf { normalize(int() + dex()) },
|
||||
),
|
||||
),
|
||||
specialSkills = sheet?.specialSkills?.map { skill ->
|
||||
skillFieldFactory.createSkill(
|
||||
id = skill.id,
|
||||
label = specialSkillsLabel,
|
||||
descriptionValue = skill.description ?: "",
|
||||
labelValue = skill.label,
|
||||
baseValue = skill.base,
|
||||
bonusValue = skill.bonus ?: "",
|
||||
levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "",
|
||||
options = run {
|
||||
val current = sheet.specialSkills.firstOrNull { it.id == skill.id }
|
||||
listOf(
|
||||
skillFieldFactory.occupationOption(current?.occupation ?: false),
|
||||
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
|
||||
)
|
||||
},
|
||||
)
|
||||
} ?: emptyList(),
|
||||
magicSkills = sheet?.magicSkills?.map { skill ->
|
||||
skillFieldFactory.createSkill(
|
||||
id = skill.id,
|
||||
label = magicSkillsLabel,
|
||||
descriptionValue = skill.description ?: "",
|
||||
labelValue = skill.label,
|
||||
baseValue = skill.base,
|
||||
bonusValue = skill.bonus ?: "",
|
||||
levelValue = skill.level.takeIf { it > 0 }?.toString() ?: "",
|
||||
options = run {
|
||||
val current = sheet.magicSkills.firstOrNull { it.id == skill.id }
|
||||
listOf(
|
||||
skillFieldFactory.occupationOption(
|
||||
checked = current?.occupation ?: false
|
||||
),
|
||||
skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
|
||||
)
|
||||
},
|
||||
)
|
||||
} ?: emptyList(),
|
||||
actions = sheet?.actions?.map { action ->
|
||||
ActionFieldUio(
|
||||
id = action.id,
|
||||
label = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__name_label),
|
||||
value = action.label,
|
||||
).createLwaTextField(),
|
||||
description = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__description_label),
|
||||
value = action.description ?: "",
|
||||
).createLwaTextField(),
|
||||
canBeCritical = createLwaBox(
|
||||
checked = action.canBeCritical,
|
||||
),
|
||||
default = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__default_action_label),
|
||||
value = action.default,
|
||||
).createLwaTextField(),
|
||||
special = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__spacial_action_label),
|
||||
value = action.special ?: "",
|
||||
).createLwaTextField(),
|
||||
critical = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__critical_action_label),
|
||||
value = action.critical ?: "",
|
||||
).createLwaTextField(),
|
||||
option = skillFieldFactory.deleteOption { onDeleteSkill(action.id) },
|
||||
)
|
||||
} ?: emptyList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun createLwaBox(
|
||||
enable: Boolean = true,
|
||||
checked: Boolean,
|
||||
): LwaCheckBoxUio {
|
||||
val checkedFlow = MutableStateFlow(checked)
|
||||
|
||||
return LwaCheckBoxUio(
|
||||
enable = enable,
|
||||
checked = checkedFlow,
|
||||
onCheckedChange = { checkedFlow.value = it },
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun createLevelUpWrapper(
|
||||
shouldLevelUp: Boolean,
|
||||
): LevelUpWrapperUio {
|
||||
val field = mutableStateOf(shouldLevelUp)
|
||||
return LevelUpWrapperUio(
|
||||
label = getString(Res.string.character_sheet_edit__level_up),
|
||||
checked = field,
|
||||
onCheck = { field.value = it },
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun createBaseSkill(
|
||||
sheet: CharacterSheet?,
|
||||
id: String,
|
||||
label: String,
|
||||
description: String,
|
||||
base: State<Int>,
|
||||
): BaseSkillFieldUio {
|
||||
val skill = sheet?.commonSkills?.firstOrNull { it.id == id }
|
||||
|
||||
return BaseSkillFieldUio(
|
||||
id = id,
|
||||
label = label,
|
||||
base = base,
|
||||
bonus = skillFieldFactory.createWrapper(
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__bonus_label)),
|
||||
value = skill?.bonus ?: "",
|
||||
),
|
||||
level = skillFieldFactory.createWrapper(
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__level_label)),
|
||||
value = skill?.level?.takeIf { it > 0 }?.toString() ?: "",
|
||||
),
|
||||
option = skillFieldFactory.occupationOption(skill?.occupation ?: false),
|
||||
tooltip = BasicTooltipUio(
|
||||
title = label,
|
||||
description = description,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun SimpleFieldUio.unpack(): String? {
|
||||
return value.value.value.ifBlank { value.placeholder.value }
|
||||
}
|
||||
|
||||
private suspend fun commonSkillBase(skillId: String): String {
|
||||
return when (skillId) {
|
||||
CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.character_sheet_edit__skills__combat_base)
|
||||
CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.character_sheet_edit__skills__dodge_base)
|
||||
CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.character_sheet_edit__skills__grab_base)
|
||||
CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.character_sheet_edit__skills__throw_base)
|
||||
CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.character_sheet_edit__skills__athletics_base)
|
||||
CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.character_sheet_edit__skills__acrobatics_base)
|
||||
CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.character_sheet_edit__skills__perception_base)
|
||||
CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.character_sheet_edit__skills__search_base)
|
||||
CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.character_sheet_edit__skills__empathy_base)
|
||||
CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.character_sheet_edit__skills__persuasion_base)
|
||||
CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.character_sheet_edit__skills__intimidation_base)
|
||||
CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.character_sheet_edit__skills__spiel_base)
|
||||
CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.character_sheet_edit__skills__bargain_base)
|
||||
CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.character_sheet_edit__skills__discretion_base)
|
||||
CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.character_sheet_edit__skills__sleight_of_hand_base)
|
||||
CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.character_sheet_edit__skills__aid_base)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun commonSkillLabel(skillId: String): String {
|
||||
return when (skillId) {
|
||||
CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.character_sheet_edit__skills__combat_label)
|
||||
CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.character_sheet_edit__skills__dodge_label)
|
||||
CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.character_sheet_edit__skills__grab_label)
|
||||
CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.character_sheet_edit__skills__throw_label)
|
||||
CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.character_sheet_edit__skills__athletics_label)
|
||||
CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.character_sheet_edit__skills__acrobatics_label)
|
||||
CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.character_sheet_edit__skills__perception_label)
|
||||
CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.character_sheet_edit__skills__search_label)
|
||||
CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.character_sheet_edit__skills__empathy_label)
|
||||
CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.character_sheet_edit__skills__persuasion_label)
|
||||
CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.character_sheet_edit__skills__intimidation_label)
|
||||
CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.character_sheet_edit__skills__spiel_label)
|
||||
CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.character_sheet_edit__skills__bargain_label)
|
||||
CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.character_sheet_edit__skills__discretion_label)
|
||||
CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.character_sheet_edit__skills__sleight_of_hand_label)
|
||||
CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.character_sheet_edit__skills__aid_label)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun commonSkillDescription(skillId: String): String {
|
||||
return when (skillId) {
|
||||
CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.character_sheet_edit__skills__combat_description)
|
||||
CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.character_sheet_edit__skills__dodge_description)
|
||||
CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.character_sheet_edit__skills__grab_description)
|
||||
CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.character_sheet_edit__skills__throw_description)
|
||||
CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.character_sheet_edit__skills__athletics_description)
|
||||
CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.character_sheet_edit__skills__acrobatics_description)
|
||||
CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.character_sheet_edit__skills__perception_description)
|
||||
CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.character_sheet_edit__skills__search_description)
|
||||
CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.character_sheet_edit__skills__empathy_description)
|
||||
CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.character_sheet_edit__skills__persuasion_description)
|
||||
CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.character_sheet_edit__skills__intimidation_description)
|
||||
CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.character_sheet_edit__skills__spiel_description)
|
||||
CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.character_sheet_edit__skills__bargain_description)
|
||||
CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.character_sheet_edit__skills__discretion_description)
|
||||
CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.character_sheet_edit__skills__sleight_of_hand_description)
|
||||
CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.character_sheet_edit__skills__aid_description)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,477 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Scaffold
|
||||
import androidx.compose.material.Surface
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.material.TopAppBar
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
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.LocalWindowController
|
||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindow
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.copy.CharacterSheetCopyDialog
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.delete.CharacterSheetDeleteDialog
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionField
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillForm
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.LevelUpField
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.LevelUpWrapperUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleField
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SkillFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SkillForm
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapper
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__common_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__magic_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__special_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__add_roll_action
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__save_action
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_action
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__special_action
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_delete_forever_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_save_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_save_as_24dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@Stable
|
||||
data class CharacterSheetEditPageUio(
|
||||
val id: State<String>,
|
||||
val levelUp: LevelUpWrapperUio,
|
||||
val name: TextFieldWrapperUio,
|
||||
val level: SimpleFieldUio,
|
||||
val portrait: TextFieldWrapperUio,
|
||||
val thumbnail: TextFieldWrapperUio,
|
||||
val strength: SimpleFieldUio,
|
||||
val dexterity: SimpleFieldUio,
|
||||
val constitution: SimpleFieldUio,
|
||||
val height: SimpleFieldUio,
|
||||
val intelligence: SimpleFieldUio,
|
||||
val power: SimpleFieldUio,
|
||||
val charisma: SimpleFieldUio,
|
||||
val commonSkills: List<BaseSkillFieldUio>,
|
||||
val specialSkills: List<SkillFieldUio>,
|
||||
val magicSkills: List<SkillFieldUio>,
|
||||
val actions: List<ActionFieldUio>,
|
||||
) {
|
||||
val characteristics
|
||||
get() = listOf(
|
||||
strength,
|
||||
dexterity,
|
||||
constitution,
|
||||
height,
|
||||
intelligence,
|
||||
power,
|
||||
charisma,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetEditPage(
|
||||
viewModel: CharacterSheetEditViewModel = koinViewModel(),
|
||||
) {
|
||||
val windowController = LocalWindowController.current
|
||||
val window = LocalWindow.current
|
||||
val screen = LocalScreenController.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
CharacterSheetEdit(
|
||||
title = window.title,
|
||||
form = viewModel.characterSheet.value,
|
||||
onNewSpecialSkill = {
|
||||
scope.launch {
|
||||
viewModel.onNewSpecialSkill()
|
||||
}
|
||||
},
|
||||
onNewMagicSkill = {
|
||||
scope.launch {
|
||||
viewModel.onNewMagicSkill()
|
||||
}
|
||||
},
|
||||
onNewAction = {
|
||||
scope.launch {
|
||||
viewModel.onNewAction()
|
||||
}
|
||||
},
|
||||
onDelete = {
|
||||
scope.launch {
|
||||
viewModel.showDeleteCharacterSheetDialog()
|
||||
}
|
||||
},
|
||||
onCopy = {
|
||||
scope.launch {
|
||||
viewModel.showCopyCharacterSheetDialog()
|
||||
}
|
||||
},
|
||||
onSave = {
|
||||
scope.launch {
|
||||
viewModel.save()
|
||||
if (screen.popBackStack().not()) {
|
||||
windowController.hideWindow(window = window)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
CharacterSheetCopyDialog(
|
||||
dialog = viewModel.copyCharacterSheetDialog,
|
||||
onConfirm = { dialog ->
|
||||
scope.launch {
|
||||
val characterSheetId = dialog.value.valueFlow.value
|
||||
viewModel.saveAs(characterSheetId = characterSheetId)
|
||||
if (screen.popBackStack().not()) {
|
||||
windowController.hideWindow(window = window)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
viewModel.hideCopyCharacterSheetDialog()
|
||||
}
|
||||
)
|
||||
|
||||
CharacterSheetDeleteDialog(
|
||||
dialog = viewModel.deleteCharacterSheetDialog,
|
||||
onConfirm = { dialog ->
|
||||
scope.launch {
|
||||
viewModel.delete(characterSheetId = dialog.characterSheetId)
|
||||
if (screen.popBackStack().not()) {
|
||||
windowController.hideWindow(window = window)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismissRequest = {
|
||||
viewModel.hideDeleteCharacterSheetDialog()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CharacterSheetEdit(
|
||||
modifier: Modifier = Modifier,
|
||||
title: String,
|
||||
form: CharacterSheetEditPageUio,
|
||||
onNewSpecialSkill: () -> Unit,
|
||||
onNewMagicSkill: () -> Unit,
|
||||
onNewAction: () -> Unit,
|
||||
onDelete: () -> Unit,
|
||||
onCopy: () -> Unit,
|
||||
onSave: () -> Unit,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = {
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = title,
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
IconButton(
|
||||
onClick = onDelete,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_delete_forever_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
onClick = onCopy,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_save_as_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
IconButton(
|
||||
onClick = onSave,
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_save_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
content = { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.verticalScroll(state = rememberScrollState())
|
||||
.padding(paddingValues = paddingValues)
|
||||
.padding(all = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.lwa.typography.system.caption,
|
||||
text = "id : "
|
||||
)
|
||||
SelectionContainer {
|
||||
Text(
|
||||
style = MaterialTheme.lwa.typography.system.caption,
|
||||
text = form.id.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
wrapper = form.name,
|
||||
)
|
||||
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
wrapper = form.portrait,
|
||||
)
|
||||
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
wrapper = form.thumbnail,
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
LevelUpField(
|
||||
modifier = Modifier.weight(1f).offset(y = 4.dp),
|
||||
field = form.levelUp,
|
||||
)
|
||||
SimpleField(
|
||||
modifier = Modifier.weight(2f),
|
||||
field = form.level,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 16.dp)
|
||||
) {
|
||||
DecoratedBox(
|
||||
modifier = Modifier.weight(weight = 1f),
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = stringResource(Res.string.character_sheet_edit__characteristics__title),
|
||||
)
|
||||
form.characteristics.forEach {
|
||||
SimpleField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
field = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize(),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = stringResource(Res.string.character_sheet__skills__common_title),
|
||||
)
|
||||
form.commonSkills.forEach {
|
||||
BaseSkillForm(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 4.dp),
|
||||
field = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize(),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = stringResource(Res.string.character_sheet__skills__special_title),
|
||||
)
|
||||
form.specialSkills.forEach {
|
||||
SkillForm(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 4.dp),
|
||||
field = it,
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
modifier = Modifier.align(alignment = Alignment.End),
|
||||
onClick = onNewSpecialSkill,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(Res.string.character_sheet_edit__skills__special_action),
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DecoratedBox(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize(),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(vertical = 8.dp),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
style = MaterialTheme.typography.caption,
|
||||
text = stringResource(Res.string.character_sheet__skills__magic_title),
|
||||
)
|
||||
form.magicSkills.forEach {
|
||||
SkillForm(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 4.dp),
|
||||
field = it,
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
modifier = Modifier.align(alignment = Alignment.End),
|
||||
onClick = onNewMagicSkill,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(Res.string.character_sheet_edit__skills__magic_action),
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.animateContentSize(),
|
||||
) {
|
||||
form.actions.forEach {
|
||||
ActionField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 6.dp, bottom = 16.dp),
|
||||
action = it,
|
||||
)
|
||||
}
|
||||
TextButton(
|
||||
modifier = Modifier.align(alignment = Alignment.End),
|
||||
onClick = onNewAction,
|
||||
) {
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(Res.string.character_sheet_edit__add_roll_action)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
) {
|
||||
TextButton(
|
||||
onClick = onSave,
|
||||
) {
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(Res.string.character_sheet_edit__save_action),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit
|
||||
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetEditDestination
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.copy.CharacterSheetCopyDialogUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.delete.CharacterSheetDeleteDialogUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__critical_action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__default_action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__description_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__spacial_action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__copy__label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__copy__title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__special_title
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import java.util.UUID
|
||||
|
||||
class CharacterSheetEditViewModel(
|
||||
private val characterSheetRepository: CharacterSheetRepository,
|
||||
private val sheetFactory: CharacterSheetEditFactory,
|
||||
private val skillFactory: SkillFieldFactory,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
|
||||
private val argument = CharacterSheetEditDestination.Argument(savedStateHandle)
|
||||
|
||||
private val copyDialog = mutableStateOf<CharacterSheetCopyDialogUio?>(null)
|
||||
val copyCharacterSheetDialog: State<CharacterSheetCopyDialogUio?> = copyDialog
|
||||
|
||||
private val deleteDialog = mutableStateOf<CharacterSheetDeleteDialogUio?>(null)
|
||||
val deleteCharacterSheetDialog: State<CharacterSheetDeleteDialogUio?> = deleteDialog
|
||||
|
||||
private val _characterSheet = mutableStateOf(
|
||||
runBlocking {
|
||||
sheetFactory.convertToUio(
|
||||
sheet = characterSheetRepository.characterDetail(characterSheetId = argument.id),
|
||||
onDeleteSkill = ::deleteSkill,
|
||||
)
|
||||
}
|
||||
)
|
||||
val characterSheet: State<CharacterSheetEditPageUio> get() = _characterSheet
|
||||
|
||||
suspend fun showCopyCharacterSheetDialog() {
|
||||
val idFieldFlow = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__copy__label),
|
||||
value = argument.id ?: "",
|
||||
)
|
||||
copyDialog.value = CharacterSheetCopyDialogUio(
|
||||
label = getString(Res.string.character_sheet_edit__copy__title),
|
||||
value = idFieldFlow.createLwaTextField(),
|
||||
validate = {
|
||||
characterSheetRepository.checkCharacterSheetIdValidity(
|
||||
characterSheetId = idFieldFlow.valueFlow.value
|
||||
).also {
|
||||
idFieldFlow.errorFlow.value = it.not()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun hideCopyCharacterSheetDialog() {
|
||||
copyDialog.value = null
|
||||
}
|
||||
|
||||
fun showDeleteCharacterSheetDialog() {
|
||||
deleteDialog.value = CharacterSheetDeleteDialogUio(
|
||||
characterSheetId = argument.id ?: "",
|
||||
name = characterSheet.value.name.value.value,
|
||||
)
|
||||
}
|
||||
|
||||
fun hideDeleteCharacterSheetDialog() {
|
||||
deleteDialog.value = null
|
||||
}
|
||||
|
||||
suspend fun onNewSpecialSkill() {
|
||||
val id = UUID.randomUUID().toString()
|
||||
val skill = skillFactory.createSkill(
|
||||
id = id,
|
||||
label = getString(Res.string.character_sheet_edit__skills__special_title),
|
||||
options = listOf(
|
||||
skillFactory.occupationOption(checked = true),
|
||||
skillFactory.deleteOption { deleteSkill(skillId = id) }
|
||||
),
|
||||
)
|
||||
val skills = _characterSheet.value.specialSkills
|
||||
.toMutableList()
|
||||
.also { it.add(skill) }
|
||||
_characterSheet.value = characterSheet.value.copy(
|
||||
specialSkills = skills,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun onNewMagicSkill() {
|
||||
val id = UUID.randomUUID().toString()
|
||||
val skill = skillFactory.createSkill(
|
||||
id = id,
|
||||
label = getString(Res.string.character_sheet_edit__skills__magic_title),
|
||||
options = listOf(
|
||||
skillFactory.occupationOption(checked = false),
|
||||
skillFactory.deleteOption { deleteSkill(skillId = id) }
|
||||
),
|
||||
)
|
||||
val skills = _characterSheet.value.magicSkills
|
||||
.toMutableList()
|
||||
.also { it.add(skill) }
|
||||
_characterSheet.value = characterSheet.value.copy(
|
||||
magicSkills = skills,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun onNewAction() {
|
||||
val id = UUID.randomUUID().toString()
|
||||
val field = ActionFieldUio(
|
||||
id = id,
|
||||
label = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__name_label),
|
||||
value = "",
|
||||
).createLwaTextField(),
|
||||
description = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__description_label),
|
||||
value = "",
|
||||
).createLwaTextField(),
|
||||
canBeCritical = sheetFactory.createLwaBox(
|
||||
checked = false,
|
||||
),
|
||||
default = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__default_action_label),
|
||||
value = "",
|
||||
).createLwaTextField(),
|
||||
special = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__spacial_action_label),
|
||||
value = "",
|
||||
).createLwaTextField(),
|
||||
critical = createLwaTextFieldFlow(
|
||||
label = getString(Res.string.character_sheet_edit__actions__critical_action_label),
|
||||
value = "",
|
||||
).createLwaTextField(),
|
||||
option = skillFactory.deleteOption { deleteSkill(id) },
|
||||
)
|
||||
val actions = _characterSheet.value.actions.toMutableList().also {
|
||||
it.add(field)
|
||||
}
|
||||
_characterSheet.value = _characterSheet.value.copy(
|
||||
actions = actions,
|
||||
)
|
||||
}
|
||||
|
||||
private fun deleteSkill(skillId: String) {
|
||||
_characterSheet.value = _characterSheet.value.copy(
|
||||
specialSkills = _characterSheet.value.specialSkills.toMutableList().also { skills ->
|
||||
skills.removeIf { it.id == skillId }
|
||||
},
|
||||
magicSkills = _characterSheet.value.magicSkills.toMutableList().also { skills ->
|
||||
skills.removeIf { it.id == skillId }
|
||||
},
|
||||
actions = _characterSheet.value.actions.toMutableList().also { actions ->
|
||||
actions.removeIf { it.id == skillId }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun save() {
|
||||
val updatedSheet = sheetFactory.updateCharacterSheet(
|
||||
currentSheet = characterSheetRepository.characterDetail(characterSheetId = _characterSheet.value.id.value),
|
||||
editedSheet = _characterSheet.value,
|
||||
)
|
||||
characterSheetRepository.updateCharacter(
|
||||
sheet = updatedSheet,
|
||||
create = argument.id == null,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun saveAs(
|
||||
characterSheetId: String,
|
||||
) {
|
||||
val updatedSheet = sheetFactory.updateCharacterSheet(
|
||||
currentSheet = characterSheetRepository.characterDetail(characterSheetId = _characterSheet.value.id.value),
|
||||
editedSheet = _characterSheet.value,
|
||||
)
|
||||
characterSheetRepository.updateCharacter(
|
||||
sheet = updatedSheet.copy(id = characterSheetId),
|
||||
create = true,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun delete(
|
||||
characterSheetId: String,
|
||||
) {
|
||||
characterSheetRepository.deleteCharacter(
|
||||
characterSheetId = characterSheetId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SkillFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.ActionOption
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.CheckedOption
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.OptionUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__delete__label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__occupation__label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__base_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bonus_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__description_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__level_label
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import java.util.UUID
|
||||
|
||||
class SkillFieldFactory {
|
||||
|
||||
suspend fun createSkill(
|
||||
id: String = UUID.randomUUID().toString(),
|
||||
label: String,
|
||||
labelValue: String = "",
|
||||
descriptionValue: String = "",
|
||||
baseValue: String = "",
|
||||
bonusValue: String = "",
|
||||
levelValue: String = "",
|
||||
options: List<OptionUio> = emptyList(),
|
||||
): SkillFieldUio {
|
||||
val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label)
|
||||
return SkillFieldUio(
|
||||
id = id,
|
||||
label = createWrapper(
|
||||
label = mutableStateOf(label),
|
||||
value = labelValue,
|
||||
),
|
||||
description = createWrapper(
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__description_label)),
|
||||
value = descriptionValue,
|
||||
),
|
||||
base = createWrapper(
|
||||
label = derivedStateOf {
|
||||
options
|
||||
.firstOrNull { it is CheckedOption && it.checked.value }
|
||||
?.let { "$baseLabel *" }
|
||||
?: baseLabel
|
||||
},
|
||||
value = baseValue,
|
||||
),
|
||||
bonus = createWrapper(
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__bonus_label)),
|
||||
value = bonusValue,
|
||||
),
|
||||
level = createWrapper(
|
||||
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__level_label)),
|
||||
value = levelValue,
|
||||
),
|
||||
options = options,
|
||||
)
|
||||
}
|
||||
|
||||
fun createWrapper(
|
||||
enable: Boolean = true,
|
||||
label: State<String?> = mutableStateOf(null),
|
||||
placeholder: State<String?> = mutableStateOf(null),
|
||||
value: String = "",
|
||||
): TextFieldWrapperUio {
|
||||
val state = mutableStateOf(value)
|
||||
return TextFieldWrapperUio(
|
||||
enable = enable,
|
||||
label = label,
|
||||
value = state,
|
||||
placeholder = placeholder,
|
||||
onValueChange = { state.value = it },
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun deleteOption(onDelete: () -> Unit) = ActionOption.DeleteOptionUio(
|
||||
icon = Icons.Default.Delete,
|
||||
label = getString(Res.string.character_sheet_edit__delete__label),
|
||||
onOption = onDelete,
|
||||
)
|
||||
|
||||
suspend fun occupationOption(checked: Boolean) = mutableStateOf(checked).let { state ->
|
||||
CheckedOption.OccupationOption(
|
||||
checked = state,
|
||||
label = getString(Res.string.character_sheet_edit__occupation__label),
|
||||
onOption = { state.value = state.value.not() },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val List<OptionUio>.occupation: Boolean
|
||||
get() = this.firstNotNullOfOrNull {
|
||||
if (it is CheckedOption.OccupationOption) it.checked.value else null
|
||||
} ?: false
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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.ui.composable.checkbox.LwaCheckBox
|
||||
import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
|
||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.ActionOption
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.DropDownActionMenuItem
|
||||
|
||||
@Stable
|
||||
data class ActionFieldUio(
|
||||
val id: String,
|
||||
val label: LwaTextFieldUio,
|
||||
val description: LwaTextFieldUio,
|
||||
val canBeCritical: LwaCheckBoxUio,
|
||||
val default: LwaTextFieldUio,
|
||||
val special: LwaTextFieldUio?,
|
||||
val critical: LwaTextFieldUio?,
|
||||
val option: ActionOption.DeleteOptionUio,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun ActionField(
|
||||
modifier: Modifier = Modifier,
|
||||
space: Dp = 4.dp,
|
||||
action: ActionFieldUio,
|
||||
) {
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
val canBeCritical = action.canBeCritical.checked.collectAsState()
|
||||
|
||||
Column(
|
||||
modifier = modifier,
|
||||
verticalArrangement = Arrangement.spacedBy(space = space),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = space),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = action.label,
|
||||
)
|
||||
LwaCheckBox(
|
||||
field = action.canBeCritical,
|
||||
)
|
||||
IconButton(
|
||||
onClick = { showMenu.value = showMenu.value.not() },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = showMenu.value,
|
||||
onDismissRequest = { showMenu.value = false }
|
||||
) {
|
||||
DropDownActionMenuItem(
|
||||
wrapper = action.option,
|
||||
onClick = {
|
||||
showMenu.value = false
|
||||
action.option.onOption()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().animateContentSize(),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = space),
|
||||
) {
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = action.default,
|
||||
)
|
||||
if (canBeCritical.value) {
|
||||
action.special?.let { field ->
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = field,
|
||||
)
|
||||
}
|
||||
action.critical?.let { field ->
|
||||
LwaTextField(
|
||||
modifier = Modifier.weight(1f),
|
||||
field = field,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
LwaTextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
singleLine = false,
|
||||
field = action.description,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
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.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipLayout
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.BasicTooltipUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.CheckedOption
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.DropDownCheckedMenuItem
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapper
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__base_label
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
@Stable
|
||||
class BaseSkillFieldUio(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val base: State<Int>,
|
||||
val bonus: TextFieldWrapperUio,
|
||||
val level: TextFieldWrapperUio,
|
||||
val option: CheckedOption,
|
||||
val tooltip: BasicTooltipUio,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BaseSkillForm(
|
||||
modifier: Modifier = Modifier,
|
||||
field: BaseSkillFieldUio,
|
||||
) {
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
val baseLabel = stringResource(Res.string.character_sheet_edit__skills__base_label)
|
||||
.let { label ->
|
||||
remember {
|
||||
derivedStateOf {
|
||||
when (field.option.checked.value) {
|
||||
true -> "$label *"
|
||||
else -> label
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp, alignment = Alignment.End),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 16.dp, bottom = 12.dp)
|
||||
.align(alignment = Alignment.Bottom),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = field.label,
|
||||
)
|
||||
BasicTooltipLayout(
|
||||
modifier = Modifier
|
||||
.width(width = 96.dp)
|
||||
.padding(start = 16.dp),
|
||||
tooltip = field.tooltip,
|
||||
) {
|
||||
Column {
|
||||
Text(
|
||||
style = MaterialTheme.typography.caption,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium),
|
||||
text = baseLabel.value,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = "+${field.base.value}",
|
||||
)
|
||||
}
|
||||
}
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.width(width = 96.dp),
|
||||
wrapper = field.bonus,
|
||||
)
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.width(width = 96.dp),
|
||||
wrapper = field.level,
|
||||
)
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showMenu.value = showMenu.value.not() },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showMenu.value,
|
||||
onDismissRequest = { showMenu.value = false }
|
||||
) {
|
||||
DropDownCheckedMenuItem(
|
||||
wrapper = field.option,
|
||||
onClick = {
|
||||
showMenu.value = false
|
||||
field.option.onOption()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.material.Checkbox
|
||||
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 com.pixelized.desktop.lwa.ui.theme.color.component.LwaCheckboxColors
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
|
||||
@Stable
|
||||
class LevelUpWrapperUio(
|
||||
val label: String,
|
||||
val checked: State<Boolean>,
|
||||
val onCheck: (Boolean) -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun LevelUpField(
|
||||
modifier: Modifier = Modifier,
|
||||
field: LevelUpWrapperUio,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.body1,
|
||||
text = field.label,
|
||||
)
|
||||
Checkbox(
|
||||
colors = LwaCheckboxColors(),
|
||||
checked = field.checked.value,
|
||||
onCheckedChange = field.onCheck,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
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.screen.characterSheet.edit.composable.textfield.TextFieldWrapper
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
|
||||
|
||||
@Stable
|
||||
class SimpleFieldUio(
|
||||
val label: String,
|
||||
val value: TextFieldWrapperUio,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun SimpleField(
|
||||
modifier: Modifier = Modifier,
|
||||
field: SimpleFieldUio,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp, alignment = Alignment.End),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(start = 16.dp, bottom = 12.dp)
|
||||
.align(alignment = Alignment.Bottom),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = field.label,
|
||||
)
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.width(width = 96.dp),
|
||||
wrapper = field.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,106 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable
|
||||
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.DropdownMenu
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.MoreVert
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.DropDownMenuItemWrapper
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.OptionUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapper
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio
|
||||
|
||||
@Stable
|
||||
class SkillFieldUio(
|
||||
val id: String,
|
||||
val label: TextFieldWrapperUio,
|
||||
val description: TextFieldWrapperUio,
|
||||
val base: TextFieldWrapperUio,
|
||||
val bonus: TextFieldWrapperUio,
|
||||
val level: TextFieldWrapperUio,
|
||||
val options: List<OptionUio>,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun SkillForm(
|
||||
modifier: Modifier = Modifier,
|
||||
field: SkillFieldUio,
|
||||
) {
|
||||
val showMenu = remember { mutableStateOf(false) }
|
||||
|
||||
Row(
|
||||
modifier = modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(1f),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 4.dp)
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.weight(1f),
|
||||
wrapper = field.label,
|
||||
)
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.width(width = 96.dp),
|
||||
wrapper = field.base,
|
||||
)
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.width(width = 96.dp),
|
||||
wrapper = field.bonus,
|
||||
)
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.width(width = 96.dp),
|
||||
wrapper = field.level,
|
||||
)
|
||||
}
|
||||
TextFieldWrapper(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
singleLine = false,
|
||||
wrapper = field.description,
|
||||
)
|
||||
}
|
||||
if (field.options.isNotEmpty()) {
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showMenu.value = showMenu.value.not() },
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.MoreVert,
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showMenu.value,
|
||||
onDismissRequest = { showMenu.value = false }
|
||||
) {
|
||||
field.options.forEach {
|
||||
DropDownMenuItemWrapper(
|
||||
wrapper = it,
|
||||
onClick = {
|
||||
showMenu.value = false
|
||||
it.onOption()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Stable
|
||||
sealed class ActionOption(
|
||||
val icon: ImageVector,
|
||||
val label: String,
|
||||
onOption: () -> Unit,
|
||||
) : OptionUio(onOption = onOption) {
|
||||
class DeleteOptionUio(
|
||||
icon: ImageVector,
|
||||
label: String,
|
||||
onOption: () -> Unit,
|
||||
) : ActionOption(
|
||||
icon = icon,
|
||||
label = label,
|
||||
onOption = onOption,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DropDownActionMenuItem(
|
||||
modifier: Modifier = Modifier,
|
||||
wrapper: ActionOption,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
) {
|
||||
Icon(
|
||||
tint = MaterialTheme.colors.primary,
|
||||
imageVector = wrapper.icon,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
text = wrapper.label,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.Checkbox
|
||||
import androidx.compose.material.CheckboxDefaults
|
||||
import androidx.compose.material.DropdownMenuItem
|
||||
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.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Stable
|
||||
sealed class CheckedOption(
|
||||
val label: String,
|
||||
val checked: State<Boolean>,
|
||||
onOption: () -> Unit,
|
||||
) : OptionUio(onOption = onOption) {
|
||||
class OccupationOption(
|
||||
label: String,
|
||||
checked: State<Boolean>,
|
||||
onOption: () -> Unit,
|
||||
) : CheckedOption(
|
||||
label = label,
|
||||
checked = checked,
|
||||
onOption = onOption,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DropDownCheckedMenuItem(
|
||||
modifier: Modifier = Modifier,
|
||||
wrapper: CheckedOption,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
) {
|
||||
Checkbox(
|
||||
modifier = Modifier.size(size = 24.dp),
|
||||
checked = wrapper.checked.value,
|
||||
colors = CheckboxDefaults.colors(
|
||||
checkedColor = MaterialTheme.colors.primary,
|
||||
),
|
||||
onCheckedChange = null
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 8.dp),
|
||||
text = wrapper.label,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Stable
|
||||
sealed class OptionUio(
|
||||
val onOption: () -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun DropDownMenuItemWrapper(
|
||||
modifier: Modifier = Modifier,
|
||||
wrapper: OptionUio,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
when (wrapper) {
|
||||
is ActionOption -> DropDownActionMenuItem(
|
||||
modifier = modifier,
|
||||
wrapper = wrapper,
|
||||
onClick = onClick,
|
||||
)
|
||||
|
||||
is CheckedOption -> DropDownCheckedMenuItem(
|
||||
modifier = modifier,
|
||||
wrapper = wrapper,
|
||||
onClick = onClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield
|
||||
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextField
|
||||
import androidx.compose.material.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusDirection
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.utils.rememberKeyboardActions
|
||||
import kotlin.math.sin
|
||||
|
||||
@Stable
|
||||
data class TextFieldWrapperUio(
|
||||
val enable: Boolean,
|
||||
val label: State<String?>,
|
||||
val value: State<String>,
|
||||
val placeholder: State<String?>,
|
||||
val onValueChange: (String) -> Unit,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun TextFieldWrapper(
|
||||
modifier: Modifier = Modifier,
|
||||
singleLine: Boolean = true,
|
||||
wrapper: TextFieldWrapperUio,
|
||||
) {
|
||||
val colorScheme = MaterialTheme.colors
|
||||
val focus = LocalFocusManager.current
|
||||
val localModifier = if (singleLine) {
|
||||
Modifier.height(height = 56.dp)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
|
||||
TextField(
|
||||
modifier = localModifier.then(other = modifier),
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
backgroundColor = remember(wrapper.enable) {
|
||||
when (wrapper.enable) {
|
||||
true -> colorScheme.onSurface.copy(alpha = 0.03f)
|
||||
else -> colorScheme.surface
|
||||
}
|
||||
},
|
||||
),
|
||||
keyboardActions = rememberKeyboardActions {
|
||||
focus.moveFocus(FocusDirection.Next)
|
||||
},
|
||||
enabled = wrapper.enable,
|
||||
singleLine = singleLine,
|
||||
placeholder = wrapper.placeholder.value?.let {
|
||||
{
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = it
|
||||
)
|
||||
}
|
||||
},
|
||||
label = wrapper.label.value?.let {
|
||||
{
|
||||
Text(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = it
|
||||
)
|
||||
}
|
||||
},
|
||||
onValueChange = { wrapper.onValueChange(it) },
|
||||
value = wrapper.value.value,
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue