diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt index 7d87359..6f4909f 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt @@ -9,6 +9,7 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch class CharacterSheetRepository( private val store: CharacterSheetStore, @@ -47,6 +48,11 @@ class CharacterSheetRepository( characterSheetId: String?, ): StateFlow { val initial = store.detailFlow.value[characterSheetId] + + if (initial == null) { + scope.launch { characterDetail(characterSheetId = characterSheetId) } + } + return store.detailFlow .map { sheets -> sheets[characterSheetId] diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/characteristic/CharacterSheetCharacteristicDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/characteristic/CharacterSheetCharacteristicDialog.kt index 2d0753c..601d46a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/characteristic/CharacterSheetCharacteristicDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/characteristic/CharacterSheetCharacteristicDialog.kt @@ -1,12 +1,5 @@ package com.pixelized.desktop.lwa.ui.composable.character.characteristic -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 @@ -38,6 +31,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign 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 @@ -67,35 +61,22 @@ fun CharacterSheetCharacteristicDialog( onConfirm: (CharacterSheetCharacteristicDialogUio) -> 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.value?.let { + Dialog( + onDismissRequest = onDismissRequest, + content = { + CharacterSheetCharacteristicContent( dialog = it, onConfirm = onConfirm, onDismissRequest = onDismissRequest, ) } - } + ) } } @Composable -private fun Dialog( +private fun CharacterSheetCharacteristicContent( dialog: CharacterSheetCharacteristicDialogUio, onConfirm: (CharacterSheetCharacteristicDialogUio) -> Unit, onDismissRequest: () -> Unit, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt index db8625b..39b1837 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt @@ -21,7 +21,7 @@ fun WindowController.navigateToGameMasterWindow( window = GameMasterWindow( title = title, size = DpSize( - width = 124.dp * 4 + 64.dp, + width = 124.dp * 4 + 108.dp, height = maxWindowHeight - 32.dp, ) ) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt index 1f3b32a..db132db 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt @@ -16,7 +16,6 @@ import kotlinx.coroutines.flow.stateIn class CharacterDetailViewModel( private val characterSheetRepository: CharacterSheetRepository, - private val campaignRepository: CampaignRepository, private val alterationRepository: AlterationRepository, private val characterDetailFactory: CharacterDetailFactory, private val network: NetworkRepository, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/copy/CharacterSheetCopyDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/copy/CharacterSheetCopyDialog.kt index dd70ca2..d5c5b01 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/copy/CharacterSheetCopyDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/copy/CharacterSheetCopyDialog.kt @@ -31,9 +31,6 @@ 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.input.key.Key -import androidx.compose.ui.input.key.key -import androidx.compose.ui.input.key.onPreviewKeyEvent import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField @@ -51,7 +48,7 @@ import org.jetbrains.compose.resources.stringResource data class CharacterSheetCopyDialogUio( val label: String, val value: LwaTextFieldUio, - val validate: () -> Boolean + val validate: () -> Boolean, ) @Composable @@ -165,7 +162,11 @@ private fun Dialog( ) } TextButton( - onClick = { if(dialog.validate()) {onConfirm(dialog)} }, + onClick = { + if (dialog.validate()) { + onConfirm(dialog) + } + }, ) { Text( text = stringResource(Res.string.dialog__confirm_action) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/CharacterSheetDeleteConfirmationDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/CharacterSheetDeleteConfirmationDialog.kt index 502c6b9..73138d5 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/CharacterSheetDeleteConfirmationDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/CharacterSheetDeleteConfirmationDialog.kt @@ -1,12 +1,5 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog -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 @@ -26,14 +19,11 @@ import androidx.compose.runtime.State import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.input.key.Key -import androidx.compose.ui.input.key.key -import androidx.compose.ui.input.key.onPreviewKeyEvent 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 @@ -52,35 +42,22 @@ fun CharacterSheetDeleteConfirmationDialog( onConfirm: (CharacterSheetDeleteConfirmationDialogUio) -> 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.value?.let { + Dialog( + onDismissRequest = onDismissRequest, + content = { + CharacterSheetDeleteConfirmationContent( dialog = it, onConfirm = onConfirm, onDismissRequest = onDismissRequest, ) } - } + ) } } @Composable -private fun Dialog( +private fun CharacterSheetDeleteConfirmationContent( dialog: CharacterSheetDeleteConfirmationDialogUio, onConfirm: (CharacterSheetDeleteConfirmationDialogUio) -> Unit, onDismissRequest: () -> Unit, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/DiminishedStatDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/DiminishedStatDialog.kt index 3174b2d..7c8ed01 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/DiminishedStatDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/dialog/DiminishedStatDialog.kt @@ -1,12 +1,5 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog -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 @@ -38,9 +31,9 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign 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 com.pixelized.shared.lwa.model.campaign.Campaign import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.dialog__cancel_action import lwacharactersheet.composeapp.generated.resources.dialog__confirm_action @@ -60,35 +53,22 @@ fun DiminishedStatDialog( onConfirm: (CharacterSheetDiminishedStatDialogUio) -> 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.value?.let { + Dialog( + onDismissRequest = onDismissRequest, + content = { + DiminishedDialogContent( dialog = it, onConfirm = onConfirm, onDismissRequest = onDismissRequest, ) } - } + ) } } @Composable -private fun Dialog( +private fun DiminishedDialogContent( dialog: CharacterSheetDiminishedStatDialogUio, onConfirm: (CharacterSheetDiminishedStatDialogUio) -> Unit, onDismissRequest: () -> Unit, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt index cba245f..2e78df7 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt @@ -2,6 +2,7 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxHeight @@ -19,14 +20,24 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.type import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.rememberNavController +import com.pixelized.desktop.lwa.LocalBlurController +import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel +import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedViewModel +import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.GMActionDestination import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.composableGameMasterActionPage @@ -37,6 +48,9 @@ import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.nav import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.navigateToGameMasterAlterationPage import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.navigateToGameMasterCharacterPage import com.pixelized.desktop.lwa.ui.navigation.screen.destination.gamemaster.navigateToGameMasterObjectPage +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailPanel +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.rememberTransitionAnimation import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTab import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTabUio import com.pixelized.desktop.lwa.ui.theme.color.component.LwaSwitchColors @@ -47,34 +61,36 @@ import lwacharactersheet.composeapp.generated.resources.game_master__title import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel - @Composable fun GameMasterScreen( - viewModel: GameMasterViewModel = koinViewModel(), + gameMasterViewModel: GameMasterViewModel = koinViewModel(), + ) { val screen = rememberNavController() - val gameMaster = viewModel.isGameMaster.collectAsState() + val gameMaster = gameMasterViewModel.isGameMaster.collectAsState() - Surface( - modifier = Modifier.fillMaxSize() + CompositionLocalProvider( + LocalScreenController provides screen, ) { - CompositionLocalProvider( - LocalScreenController provides screen, + Surface( + modifier = Modifier.fillMaxSize() ) { - GameMasterContent( - modifier = Modifier.fillMaxSize(), - controller = screen, - gameMaster = gameMaster, - onGameMaster = viewModel::onGameMaster, - onTab = { - when (it) { - GMTabUio.Actions -> screen.navigateToGameMasterActionPage() - GMTabUio.Characters -> screen.navigateToGameMasterCharacterPage() - GMTabUio.Alterations -> screen.navigateToGameMasterAlterationPage() - GMTabUio.Objects -> screen.navigateToGameMasterObjectPage() - } - }, - ) + Box { + GameMasterContent( + modifier = Modifier.fillMaxSize(), + controller = screen, + gameMaster = gameMaster, + onGameMaster = gameMasterViewModel::onGameMaster, + onTab = { + when (it) { + GMTabUio.Actions -> screen.navigateToGameMasterActionPage() + GMTabUio.Characters -> screen.navigateToGameMasterCharacterPage() + GMTabUio.Alterations -> screen.navigateToGameMasterAlterationPage() + GMTabUio.Objects -> screen.navigateToGameMasterObjectPage() + } + }, + ) + } } } } @@ -121,44 +137,46 @@ private fun GameMasterContent( ) }, content = { paddingValues -> - Row( + Box( modifier = Modifier .fillMaxSize() .padding(paddingValues), ) { - Surface( - elevation = 1.dp, - ) { - Column( - modifier = Modifier - .fillMaxHeight() - .width(width = 64.dp) - .padding(vertical = 8.dp), - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(space = 8.dp), + Row { + Surface( + elevation = 1.dp, ) { - GMTabUio.entries.forEach { - GMTab( - tab = it, - onClick = { onTab(it) }, - ) + Column( + modifier = Modifier + .fillMaxHeight() + .width(width = 64.dp) + .padding(vertical = 8.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(space = 8.dp), + ) { + GMTabUio.entries.forEach { + GMTab( + tab = it, + onClick = { onTab(it) }, + ) + } } } - } - Surface( - modifier = Modifier - .fillMaxHeight() - .weight(weight = 1f), - ) { - NavHost( - modifier = Modifier.fillMaxSize(), - navController = controller, - startDestination = GMActionDestination.navigationRoute(), + Surface( + modifier = Modifier + .fillMaxHeight() + .weight(weight = 1f), ) { - composableGameMasterActionPage() - composableGameMasterCharacterPage() - composableGameMasterAlterationPage() - composableGameMasterObjectPage() + NavHost( + modifier = Modifier.fillMaxSize(), + navController = controller, + startDestination = GMActionDestination.navigationRoute(), + ) { + composableGameMasterActionPage() + composableGameMasterCharacterPage() + composableGameMasterAlterationPage() + composableGameMasterObjectPage() + } } } } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/GMCharacterPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/GMCharacterPage.kt index 9329f74..bd0428c 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/GMCharacterPage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/GMCharacterPage.kt @@ -5,8 +5,10 @@ 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.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape @@ -23,17 +25,30 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.type import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.LocalBlurController import com.pixelized.desktop.lwa.LocalWindowController +import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel +import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialog +import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedViewModel +import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheetEdit +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailPanel +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.rememberTransitionAnimation +import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialog import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacter import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterItemUio import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMFilterHeader import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagItemUio import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors -import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__create__title @@ -46,35 +61,99 @@ import org.koin.compose.viewmodel.koinViewModel @Composable fun GMCharacterPage( viewModel: GMCharacterViewModel = koinViewModel(), + characterDetailViewModel: CharacterDetailViewModel = koinViewModel(), + characteristicDialogViewModel: CharacterDetailCharacteristicDialogViewModel = koinViewModel(), + dismissedViewModel: CharacterSheetDiminishedViewModel = koinViewModel(), ) { val windows = LocalWindowController.current + val blurController = LocalBlurController.current val scope = rememberCoroutineScope() val characters = viewModel.characters.collectAsState() val tags = viewModel.tags.collectAsState() - GMCharacterContent( - filter = viewModel.filter, - tags = tags, - characters = characters, - onTag = viewModel::onTag, - onCharacterAction = viewModel::onCharacterAction, - onCharacterSheetEdit = { characterSheetId -> - scope.launch { - windows.navigateToCharacterSheetEdit( - characterId = characterSheetId, - title = getString(Res.string.character_sheet_edit__edit__title), - ) - } - }, - onCharacterSheetCreate = { - scope.launch { - windows.navigateToCharacterSheetEdit( - characterId = null, - title = getString(Res.string.character_sheet_edit__create__title), - ) - } - }, + Box { + GMCharacterContent( + filter = viewModel.filter, + tags = tags, + characters = characters, + onTag = viewModel::onTag, + onCharacterAction = viewModel::onCharacterAction, + onCharacterSheetDetail = { characterSheetId -> + characterDetailViewModel.showCharacter(characterSheetId = characterSheetId) + }, + onCharacterSheetEdit = { characterSheetId -> + scope.launch { + windows.navigateToCharacterSheetEdit( + characterId = characterSheetId, + title = getString(Res.string.character_sheet_edit__edit__title), + ) + } + }, + onCharacterSheetCreate = { + scope.launch { + windows.navigateToCharacterSheetEdit( + characterId = null, + title = getString(Res.string.character_sheet_edit__create__title), + ) + } + }, + ) + + CharacterDetailPanel( + modifier = Modifier + .align(alignment = Alignment.TopEnd) + .padding(all = 8.dp) + .width(width = 128.dp * 4) + .fillMaxHeight(), + transitionSpec = rememberTransitionAnimation(direction = LayoutDirection.Rtl), + blurController = blurController, + detailViewModel = characterDetailViewModel, + characterDiminishedViewModel = dismissedViewModel, + characteristicDialogViewModel = characteristicDialogViewModel, + ) + + CharacterSheetCharacteristicDialog( + dialog = characteristicDialogViewModel.statChangeDialog, + onConfirm = { dialog -> + scope.launch { + characteristicDialogViewModel.changeSubCharacteristic( + characterSheetId = dialog.characterSheetId, + characteristic = dialog.characteristic, + value = dialog.value().text.toIntOrNull() ?: 0, + ) + characteristicDialogViewModel.hideSubCharacteristicDialog() + blurController.hide() + } + }, + onDismissRequest = { + characteristicDialogViewModel.hideSubCharacteristicDialog() + blurController.hide() + }, + ) + + DiminishedStatDialog( + dialog = dismissedViewModel.diminishedDialog, + onConfirm = { diminished -> + scope.launch { + dismissedViewModel.changeDiminished( + dialog = diminished + ) + blurController.hide() + dismissedViewModel.hideDiminishedDialog() + } + }, + onDismissRequest = { + blurController.hide() + dismissedViewModel.hideDiminishedDialog() + }, + ) + } + + GameMasterCharacterKeyHandler( + onDismissRequest = { + characterDetailViewModel.hideCharacter() + } ) } @@ -88,6 +167,7 @@ fun GMCharacterContent( characters: State>, onTag: (GMTagItemUio.TagId) -> Unit, onCharacterAction: (String, GMCharacterItemUio.Action) -> Unit, + onCharacterSheetDetail: (String) -> Unit, onCharacterSheetEdit: (String) -> Unit, onCharacterSheetCreate: () -> Unit, ) { @@ -129,7 +209,10 @@ fun GMCharacterContent( .fillMaxWidth() .animateItem(), character = character, - onEdit = { + onClick = { + onCharacterSheetDetail(character.characterSheetId) + }, + onSecondary = { onCharacterSheetEdit(character.characterSheetId) }, onAction = { action -> @@ -162,4 +245,20 @@ fun GMCharacterContent( } } } +} + +@Composable +private fun GameMasterCharacterKeyHandler( + onDismissRequest: () -> Unit, +) { + KeyHandler { + when { + it.type == KeyEventType.KeyUp && it.key == Key.Escape -> { + onDismissRequest() + true + } + + else -> false + } + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt index 7f1afc6..b657b16 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt @@ -1,5 +1,7 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster.items +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.PointerMatcher import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -8,7 +10,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.onClick import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Icon @@ -24,8 +26,8 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.input.pointer.PointerButton import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterItemUio.Action import com.pixelized.desktop.lwa.ui.theme.lwa @@ -42,6 +44,7 @@ import lwacharactersheet.composeapp.generated.resources.ic_group_24dp import lwacharactersheet.composeapp.generated.resources.ic_group_off_24dp import lwacharactersheet.composeapp.generated.resources.ic_imagesmode_24dp import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -56,30 +59,36 @@ data class GMCharacterItemUio( @Stable sealed class Action( val icon: DrawableResource, + val label: StringResource, ) { @Stable data object DisplayPortrait : Action( icon = Res.drawable.ic_imagesmode_24dp, + label = Res.string.game_master__character_action__display_portrait, ) @Stable data object AddToGroup : Action( icon = Res.drawable.ic_group_24dp, + label = Res.string.game_master__character_action__add_to_group, ) @Stable data object RemoveFromGroup : Action( icon = Res.drawable.ic_group_off_24dp, + label = Res.string.game_master__character_action__remove_from_group, ) @Stable data object AddToNpc : Action( icon = Res.drawable.ic_face_24dp, + label = Res.string.game_master__character_action__add_to_npc, ) @Stable data object RemoveFromNpc : Action( icon = Res.drawable.ic_face_retouching_off_24dp, + label = Res.string.game_master__character_action__remove_from_npc, ) } } @@ -88,12 +97,14 @@ object GMCharacterPreviewDefault { val padding = PaddingValues(horizontal = 16.dp) } +@OptIn(ExperimentalFoundationApi::class) @Composable fun GMCharacter( modifier: Modifier = Modifier, padding: PaddingValues = GMCharacterPreviewDefault.padding, character: GMCharacterItemUio, - onEdit: () -> Unit, + onClick: () -> Unit, + onSecondary: () -> Unit, onAction: (Action) -> Unit, onTag: (GMTagItemUio.TagId) -> Unit, ) { @@ -103,7 +114,11 @@ fun GMCharacter( Box( modifier = Modifier .clip(shape = MaterialTheme.lwa.shapes.gameMaster) - .clickable(onClick = onEdit) + .onClick( + matcher = PointerMatcher.mouse(PointerButton.Secondary), + onClick = onSecondary, + ) + .clickable(onClick = onClick) .background(color = MaterialTheme.lwa.colorScheme.elevated.base1dp) .then(other = modifier), ) { @@ -167,58 +182,37 @@ private fun OverflowActionMenu( tint = MaterialTheme.colors.primary, contentDescription = null, ) - } - DropdownMenu( - offset = remember { DpOffset(x = -(48.dp + 8.dp), y = -(48.dp)) }, - expanded = overflowMenu.value, - onDismissRequest = { - overflowMenu.value = false - }, - content = { - character.actions.forEach { action -> - DropdownMenuItem( - onClick = { - overflowMenu.value = false - onAction(action) - }, - ) { - Row( - horizontalArrangement = Arrangement.spacedBy(space = 8.dp), - verticalAlignment = Alignment.CenterVertically, + DropdownMenu( + expanded = overflowMenu.value, + onDismissRequest = { + overflowMenu.value = false + }, + content = { + character.actions.forEach { action -> + DropdownMenuItem( + onClick = { + overflowMenu.value = false + onAction(action) + }, ) { - Icon( - painter = painterResource(action.icon), - tint = MaterialTheme.lwa.colorScheme.base.primary, - contentDescription = null, - ) - Text( - style = MaterialTheme.lwa.typography.base.body1, - color = MaterialTheme.lwa.colorScheme.base.primary, - text = when (action) { - Action.DisplayPortrait -> stringResource( - Res.string.game_master__character_action__display_portrait, - ) - - Action.AddToGroup -> stringResource( - Res.string.game_master__character_action__add_to_group, - ) - - Action.AddToNpc -> stringResource( - Res.string.game_master__character_action__add_to_npc, - ) - - Action.RemoveFromGroup -> stringResource( - Res.string.game_master__character_action__remove_from_group, - ) - - Action.RemoveFromNpc -> stringResource( - Res.string.game_master__character_action__remove_from_npc, - ) - } - ) + Row( + horizontalArrangement = Arrangement.spacedBy(space = 8.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(action.icon), + tint = MaterialTheme.lwa.colorScheme.base.primary, + contentDescription = null, + ) + Text( + style = MaterialTheme.lwa.typography.base.body1, + color = MaterialTheme.lwa.colorScheme.base.primary, + text = stringResource(action.label), + ) + } } } - } - }, - ) + }, + ) + } } \ No newline at end of file