diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 6361bbf..4251b6a 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -177,6 +177,15 @@
Passage du niveau %1$d ▸ %2$d
niv : %1$d -
-
+ niv: %1$d
+ joueur
+ joueur: %1$d
+ npc
+ npc: %1$d
+ Afficher le portrait
+ Ajouter au groupe
+ Retirer du groupe (id: %1$d)
+ Ajouter aux Npcs
+ Retirer des Npcs (id: %1$d)
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
index f3f7ddc..313d952 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
@@ -47,19 +47,15 @@ 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.NetworkWindows
+import com.pixelized.desktop.lwa.ui.navigation.window.destination.GameMasterWindow
import com.pixelized.desktop.lwa.ui.navigation.window.destination.RollHistoryWindow
import com.pixelized.desktop.lwa.ui.navigation.window.rememberMaxWindowHeight
import com.pixelized.desktop.lwa.ui.overlay.roll.RollHostState
import com.pixelized.desktop.lwa.ui.overlay.roll.RollOverlay
-import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
-import com.pixelized.desktop.lwa.ui.screen.campaign.chat.CampaignChatViewModel
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbon
import com.pixelized.desktop.lwa.ui.screen.characterSheet.CharacterSheetMainNavHost
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkPage
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterScreen
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryPage
-import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryViewModel
import com.pixelized.desktop.lwa.ui.theme.LwaTheme
import com.pixelized.desktop.lwa.utils.InstallCoil
import kotlinx.coroutines.launch
@@ -153,10 +149,6 @@ fun ApplicationScope.LwaApplication() {
@Composable
private fun MainWindowScreen(
dataSyncViewModel: DataSyncViewModel = koinViewModel(),
- networkViewModel: NetworkViewModel = koinViewModel(),
- campaignViewModel: CampaignViewModel = koinViewModel(),
- campaignChatViewModel: CampaignChatViewModel = koinViewModel(),
- rollViewModel: RollHistoryViewModel = koinViewModel(),
) {
LaunchedEffect(Unit) {
dataSyncViewModel.autoConnect()
@@ -221,7 +213,6 @@ private fun MainWindowScreen(
)
WindowsHandler(
windowController = windowController,
- rollViewModel = rollViewModel,
)
}
}
@@ -230,7 +221,6 @@ private fun MainWindowScreen(
@Composable
private fun WindowsHandler(
windowController: WindowController,
- rollViewModel: RollHistoryViewModel = koinViewModel(),
) {
WindowsNavHost(
controller = windowController,
@@ -248,11 +238,9 @@ private fun WindowsHandler(
),
)
- is RollHistoryWindow -> RollHistoryPage(
- viewModel = rollViewModel,
- )
+ is RollHistoryWindow -> RollHistoryPage()
- is NetworkWindows -> NetworkPage()
+ is GameMasterWindow -> GameMasterScreen()
}
}
)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
index 6cd6669..d49e879 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
@@ -16,7 +16,7 @@ import com.pixelized.desktop.lwa.repository.settings.SettingsStore
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogFactory
import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
-import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
+import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.CampaignToolbarViewModel
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.CampaignChatViewModel
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.TextMessageFactory
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailFactory
@@ -31,9 +31,11 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEdi
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
import com.pixelized.desktop.lwa.ui.screen.levelup.LevelUpFactory
import com.pixelized.desktop.lwa.ui.screen.levelup.LevelUpViewModel
-import com.pixelized.desktop.lwa.ui.screen.main.MainPageViewModel
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkFactory
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
+import com.pixelized.desktop.lwa.ui.screen.campaign.network.NetworkFactory
+import com.pixelized.desktop.lwa.ui.screen.campaign.network.NetworkViewModel
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterActionUseCase
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterFactory
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryViewModel
import com.pixelized.desktop.lwa.ui.screen.settings.SettingsViewModel
import com.pixelized.desktop.lwa.usecase.SettingsUseCase
@@ -112,13 +114,13 @@ val factoryDependencies
factoryOf(::CharacterSheetCharacteristicDialogFactory)
factoryOf(::TextMessageFactory)
factoryOf(::LevelUpFactory)
+ factoryOf(::GameMasterFactory)
}
val viewModelDependencies
get() = module {
viewModelOf(::DataSyncViewModel)
- viewModelOf(::CampaignViewModel)
- viewModelOf(::MainPageViewModel)
+ viewModelOf(::CampaignToolbarViewModel)
viewModelOf(::CharacterSheetViewModel)
viewModelOf(::CharacterSheetEditViewModel)
viewModelOf(::RollViewModel)
@@ -131,9 +133,11 @@ val viewModelDependencies
viewModelOf(::CampaignChatViewModel)
viewModelOf(::SettingsViewModel)
viewModelOf(::LevelUpViewModel)
+ viewModelOf(::GameMasterViewModel)
}
val useCaseDependencies
get() = module {
factoryOf(::SettingsUseCase)
+ factoryOf(::GameMasterActionUseCase)
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt
index 1f2ae80..173e37a 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClient.kt
@@ -17,11 +17,11 @@ interface LwaClient {
suspend fun campaign(): CampaignJson
- suspend fun campaignAddCharacter(characterSheetId: String, instanceId: Int)
+ suspend fun campaignAddCharacter(characterSheetId: String)
suspend fun campaignDeleteCharacter(characterSheetId: String, instanceId: Int)
- suspend fun campaignAddNpc(characterSheetId: String, instanceId: Int)
+ suspend fun campaignAddNpc(characterSheetId: String)
suspend fun campaignDeleteNpc(characterSheetId: String, instanceId: Int)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt
index bb0373c..19e2b3c 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt
@@ -45,9 +45,8 @@ class LwaClientImpl(
override suspend fun campaignAddCharacter(
characterSheetId: String,
- instanceId: Int,
) = client
- .put("$root/campaign/character/update?characterSheetId=$characterSheetId&instanceId=$instanceId")
+ .put("$root/campaign/character/update?characterSheetId=$characterSheetId")
.body()
override suspend fun campaignDeleteCharacter(
@@ -59,9 +58,8 @@ class LwaClientImpl(
override suspend fun campaignAddNpc(
characterSheetId: String,
- instanceId: Int,
) = client
- .put("$root/campaign/npc/update?characterSheetId=$characterSheetId&instanceId=$instanceId")
+ .put("$root/campaign/npc/update?characterSheetId=$characterSheetId")
.body()
override suspend fun campaignDeleteNpc(
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt
index c98cc3a..776c1ea 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt
@@ -40,4 +40,32 @@ class CampaignRepository(
): Campaign.CharacterInstance {
return campaignFlow.value.character(characterInstanceId)
}
+
+ suspend fun addCharacter(
+ characterSheetId: String,
+ ) = store.addCharacter(
+ characterSheetId = characterSheetId,
+ )
+
+ suspend fun removeCharacter(
+ characterSheetId: String,
+ instanceId: Int,
+ ) = store.removeCharacter(
+ characterSheetId = characterSheetId,
+ instanceId = instanceId,
+ )
+
+ suspend fun addNpc(
+ characterSheetId: String,
+ ) = store.addNpc(
+ characterSheetId = characterSheetId,
+ )
+
+ suspend fun removeNpc(
+ characterSheetId: String,
+ instanceId: Int,
+ ) = store.removeNpc(
+ characterSheetId = characterSheetId,
+ instanceId = instanceId,
+ )
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt
index 61dddfe..f2558bc 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt
@@ -3,8 +3,8 @@ package com.pixelized.desktop.lwa.repository.campaign
import com.pixelized.desktop.lwa.network.LwaClient
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.shared.lwa.model.campaign.Campaign
-import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
import com.pixelized.shared.lwa.model.campaign.character
+import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
import com.pixelized.shared.lwa.model.campaign.npc
import com.pixelized.shared.lwa.protocol.websocket.Message
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
@@ -47,6 +47,42 @@ class CampaignStore(
return data
}
+ suspend fun addCharacter(
+ characterSheetId: String,
+ ) {
+ client.campaignAddCharacter(
+ characterSheetId = characterSheetId
+ )
+ }
+
+ suspend fun removeCharacter(
+ characterSheetId: String,
+ instanceId: Int,
+ ) {
+ client.campaignDeleteCharacter(
+ characterSheetId = characterSheetId,
+ instanceId = instanceId,
+ )
+ }
+
+ suspend fun addNpc(
+ characterSheetId: String,
+ ) {
+ client.campaignAddNpc(
+ characterSheetId = characterSheetId
+ )
+ }
+
+ suspend fun removeNpc(
+ characterSheetId: String,
+ instanceId: Int,
+ ) {
+ client.campaignDeleteNpc(
+ characterSheetId = characterSheetId,
+ instanceId = instanceId,
+ )
+ }
+
// region : WebSocket message Handling.
private suspend fun handleMessage(message: Message) {
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/model/CharacterSheetPreview.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/model/CharacterSheetPreview.kt
index 7c9f403..f9aea42 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/model/CharacterSheetPreview.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/model/CharacterSheetPreview.kt
@@ -1,7 +1,7 @@
package com.pixelized.desktop.lwa.repository.campaign.model
data class CharacterSheetPreview(
- val id: String,
+ val characterSheetId: String,
val name: String,
val level: Int,
)
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 0cdb070..c08f6bf 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
@@ -19,7 +19,7 @@ class CharacterSheetRepository(
val characterDetailFlow get() = store.detailFlow
fun characterPreview(characterId: String?): CharacterSheetPreview? {
- return characterSheetPreviewFlow.value.firstOrNull { it.id == characterId }
+ return characterSheetPreviewFlow.value.firstOrNull { it.characterSheetId == characterId }
}
suspend fun characterDetail(
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt
index a5eba7d..784ae18 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt
@@ -46,7 +46,7 @@ class CharacterSheetStore(
val request = client.characters()
val data = request.map {
CharacterSheetPreview(
- id = it.id,
+ characterSheetId = it.id,
name = it.name,
level = it.level,
)
@@ -105,7 +105,7 @@ class CharacterSheetStore(
is RestSynchronisation.CharacterDelete -> {
_previewFlow.value = previewFlow.value.toMutableList()
- .also { sheets -> sheets.removeIf { it.id == payload.characterId } }
+ .also { sheets -> sheets.removeIf { it.characterSheetId == payload.characterId } }
_detailFlow.delete(payload.characterId)
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt
index 9c8c92b..6876e36 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt
@@ -21,6 +21,7 @@ class SettingsFactory(
autoHideDelay = settings.autoHideDelay,
autoShowChat = settings.autoShowChat,
autoScrollChat = settings.autoScrollChat,
+ isGM = settings.isGM,
)
}
@@ -45,6 +46,7 @@ class SettingsFactory(
autoHideDelay = json.autoHideDelay ?: default.autoHideDelay,
autoShowChat = json.autoShowChat ?: default.autoShowChat,
autoScrollChat = json.autoScrollChat ?: default.autoScrollChat,
+ isGM = json.isGM ?: default.isGM,
)
}
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt
index 2693887..eebeeb4 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt
@@ -9,6 +9,7 @@ data class Settings(
val autoHideDelay: Int,
val autoShowChat: Boolean,
val autoScrollChat: Boolean,
+ val isGM: Boolean,
) {
val root: String get() = "http://${"${host}:${port}".removePrefix("http://")}"
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt
index b83937e..2c9a7fd 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt
@@ -12,4 +12,5 @@ data class SettingsJsonV1(
val autoHideDelay: Int?,
val autoShowChat: Boolean?,
val autoScrollChat: Boolean?,
+ val isGM: Boolean?,
) : SettingsJson
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt
new file mode 100644
index 0000000..5bf6b5b
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/textfield/LwaTextField.kt
@@ -0,0 +1,88 @@
+package com.pixelized.desktop.lwa.ui.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.collectAsState
+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 kotlinx.coroutines.flow.StateFlow
+
+@Stable
+data class LwaTextFieldUio(
+ val enable: Boolean,
+ val labelFlow: StateFlow,
+ val valueFlow: StateFlow,
+ val placeHolderFlow: StateFlow,
+ val onValueChange: (String) -> Unit,
+)
+
+@Composable
+fun LwaTextField(
+ modifier: Modifier = Modifier,
+ leadingIcon: @Composable (() -> Unit)? = null,
+ trailingIcon: @Composable (() -> Unit)? = null,
+ singleLine: Boolean = true,
+ field: LwaTextFieldUio,
+) {
+ val focus = LocalFocusManager.current
+ val colorScheme = MaterialTheme.colors
+
+ val localModifier = if (singleLine) {
+ Modifier.height(height = 56.dp)
+ } else {
+ Modifier
+ }
+
+ val label = field.labelFlow.collectAsState()
+ val value = field.valueFlow.collectAsState()
+ val placeHolder = field.placeHolderFlow.collectAsState()
+
+ TextField(
+ modifier = localModifier.then(other = modifier),
+ colors = TextFieldDefaults.textFieldColors(
+ backgroundColor = remember(field.enable) {
+ when (field.enable) {
+ true -> colorScheme.onSurface.copy(alpha = 0.03f)
+ else -> colorScheme.surface
+ }
+ },
+ ),
+ keyboardActions = rememberKeyboardActions {
+ focus.moveFocus(FocusDirection.Next)
+ },
+ enabled = field.enable,
+ singleLine = singleLine,
+ placeholder = placeHolder.value?.let {
+ {
+ Text(
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = it
+ )
+ }
+ },
+ label = label.value?.let {
+ {
+ Text(
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = it
+ )
+ }
+ },
+ leadingIcon = leadingIcon,
+ trailingIcon = trailingIcon,
+ onValueChange = { field.onValueChange(it) },
+ value = value.value,
+ )
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/MainNavHost.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/MainNavHost.kt
index 2d326ad..e2937b5 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/MainNavHost.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/MainNavHost.kt
@@ -9,12 +9,7 @@ import androidx.navigation.compose.rememberNavController
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.MainDestination
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableLevelUp
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableMainPage
-import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableNetworkPage
-import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableOldMainPage
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableSettingsPage
-import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
-import com.pixelized.desktop.lwa.ui.screen.campaign.chat.CampaignChatViewModel
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
val LocalScreenController = compositionLocalOf {
error("MainNavHost controller is not yet ready")
@@ -35,9 +30,6 @@ fun MainNavHost(
composableMainPage()
composableSettingsPage()
composableLevelUp()
-
- composableNetworkPage()
- composableOldMainPage()
}
}
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/NetworkDestination.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/NetworkDestination.kt
deleted file mode 100644
index 15b53a3..0000000
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/NetworkDestination.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.pixelized.desktop.lwa.ui.navigation.screen.destination
-
-import androidx.navigation.NavGraphBuilder
-import androidx.navigation.NavHostController
-import androidx.navigation.compose.composable
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkScreen
-
-@Deprecated(message = "Part of the old UI")
-object NetworkDestination {
- private const val ROUTE = "network"
-
- fun baseRoute() = ROUTE
- fun navigationRoute() = ROUTE
-}
-
-@Deprecated(message = "Part of the old UI")
-fun NavGraphBuilder.composableNetworkPage() {
- composable(
- route = NetworkDestination.baseRoute(),
- ) {
- NetworkScreen()
- }
-}
-
-@Deprecated(message = "Part of the old UI")
-fun NavHostController.navigateToNetwork() {
- val route = NetworkDestination.navigationRoute()
- navigate(route = route)
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/OldMainDestination.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/OldMainDestination.kt
deleted file mode 100644
index f572b43..0000000
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/screen/destination/OldMainDestination.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.pixelized.desktop.lwa.ui.navigation.screen.destination
-
-import androidx.navigation.NavGraphBuilder
-import androidx.navigation.NavHostController
-import androidx.navigation.compose.composable
-import com.pixelized.desktop.lwa.ui.screen.main.OldMainPage
-
-@Deprecated(message = "Part of the old UI")
-object OldMainDestination {
- private const val ROUTE = "old_main"
-
- fun baseRoute() = ROUTE
- fun navigationRoute() = ROUTE
-}
-
-@Deprecated(message = "Part of the old UI")
-fun NavGraphBuilder.composableOldMainPage() {
- composable(
- route = OldMainDestination.baseRoute(),
- ) {
- OldMainPage()
- }
-}
-
-@Deprecated(message = "Part of the old UI")
-fun NavHostController.navigateToOldMainPage() {
- val route = OldMainDestination.navigationRoute()
- navigate(route = route)
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/NetworkWindows.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt
similarity index 58%
rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/NetworkWindows.kt
rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt
index d70afd4..d2e158e 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/NetworkWindows.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/GameMasterWindow.kt
@@ -6,7 +6,7 @@ import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.navigation.window.WindowController
@Stable
-class NetworkWindows(
+class GameMasterWindow(
title: String,
size: DpSize,
) : Window(
@@ -14,14 +14,15 @@ class NetworkWindows(
size = size,
)
-fun WindowController.navigateToNetwork(
- title: String = "",
+fun WindowController.navigateToGameMasterWindow(
+ title: String = "Game master",
) {
showWindow(
- window = NetworkWindows(
- title = title, size = DpSize(
- width = 464.dp,
- height = 300.dp,
+ window = GameMasterWindow(
+ title = title,
+ size = DpSize(
+ width = 400.dp + 64.dp,
+ height = maxWindowHeight - 32.dp,
)
)
)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/RollHistoryWindow.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/RollHistoryWindow.kt
index bbd9cc1..712dcde 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/RollHistoryWindow.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/navigation/window/destination/RollHistoryWindow.kt
@@ -19,7 +19,8 @@ fun WindowController.navigateToRollHistory(
) {
showWindow(
window = RollHistoryWindow(
- title = title, size = DpSize(
+ title = title,
+ size = DpSize(
width = 400.dp + 64.dp,
height = maxWindowHeight,
)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt
index bb3bf52..2eff35d 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt
@@ -42,10 +42,8 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDimin
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbon
import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.CampaignToolbar
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialog
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
-import com.pixelized.desktop.lwa.ui.overlay.roll.RollHostState
-import com.pixelized.desktop.lwa.ui.overlay.roll.RollOverlay
-import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
+import com.pixelized.desktop.lwa.ui.screen.campaign.network.NetworkViewModel
+import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.CampaignToolbarViewModel
import kotlinx.coroutines.launch
import org.koin.compose.viewmodel.koinViewModel
@@ -58,7 +56,7 @@ fun CampaignScreen(
characterDetailViewModel: CharacterDetailViewModel = koinViewModel(),
characteristicDialogViewModel: CharacterDetailCharacteristicDialogViewModel = koinViewModel(),
dismissedViewModel: CharacterDiminishedViewModel = koinViewModel(),
- campaignViewModel: CampaignViewModel = koinViewModel(),
+ campaignViewModel: CampaignToolbarViewModel = koinViewModel(),
networkViewModel: NetworkViewModel = koinViewModel(),
campaignChatViewModel: CampaignChatViewModel = koinViewModel(),
) {
@@ -88,8 +86,7 @@ fun CampaignScreen(
modifier = Modifier.fillMaxSize(),
top = {
CampaignToolbar(
- campaignViewModel = campaignViewModel,
- networkViewModel = networkViewModel,
+ viewModel = campaignViewModel,
)
},
bottom = {
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignViewModel.kt
deleted file mode 100644
index de9a871..0000000
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignViewModel.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.pixelized.desktop.lwa.ui.screen.campaign
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
-import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
-import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
-import com.pixelized.desktop.lwa.repository.network.NetworkRepository
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collectLatest
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
-
-class CampaignViewModel(
- private val characterRepository: CharacterSheetRepository,
- private val alterationRepository: AlterationRepository,
- private val campaignRepository: CampaignRepository,
- private val network: NetworkRepository,
-) : ViewModel() {
-
- val title: Flow = campaignRepository.campaignFlow
- .map { it.scene.name }
-
- val networkStatus = network.status
-
- fun init() {
- viewModelScope.launch {
- launch {
- network.status.collect { status ->
- if (status == NetworkRepository.Status.CONNECTED) {
- campaignRepository.update()
- }
- }
- }
- launch {
- combine(
- network.status,
- campaignRepository.campaignFlow,
- ) { status, campaign ->
- status to campaign
- }.collectLatest { (status, campaign) ->
- if (status == NetworkRepository.Status.CONNECTED) {
- campaign.characters.keys.forEach { id ->
- characterRepository.characterDetail(
- characterSheetId = id.characterSheetId,
- forceUpdate = true,
- )
- alterationRepository.updateActiveAlterations(
- characterInstanceId = id,
- )
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkDialog.kt
similarity index 72%
rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkScreen.kt
rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkDialog.kt
index ec766bd..37d295d 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkDialog.kt
@@ -1,4 +1,4 @@
-package com.pixelized.desktop.lwa.ui.screen.network
+package com.pixelized.desktop.lwa.ui.screen.campaign.network
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
@@ -27,15 +27,11 @@ import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Scaffold
import androidx.compose.material.SnackbarDuration
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.TextField
-import androidx.compose.material.TopAppBar
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.Stable
@@ -44,12 +40,10 @@ import androidx.compose.runtime.collectAsState
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.LocalSnackHost
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnack
-import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.ui.theme.lwa
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
@@ -59,7 +53,6 @@ import lwacharactersheet.composeapp.generated.resources.network__player_name__la
import lwacharactersheet.composeapp.generated.resources.network__port__label
import lwacharactersheet.composeapp.generated.resources.network__socket__connect_action
import lwacharactersheet.composeapp.generated.resources.network__socket__disconnect_action
-import lwacharactersheet.composeapp.generated.resources.network__title
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
@@ -100,93 +93,7 @@ data class NetworkPageUio(
}
@Composable
-fun NetworkScreen(
- viewModel: NetworkViewModel = koinViewModel(),
-) {
- val screen = LocalScreenController.current
- val snack = LocalSnackHost.current
- val scope = rememberCoroutineScope()
-
- Surface(
- modifier = Modifier.fillMaxSize(),
- ) {
- Box(
- modifier = Modifier.fillMaxSize(),
- contentAlignment = Alignment.Center,
- ) {
- BlurContent(
- modifier = Modifier.fillMaxSize(),
- controller = viewModel.blurController,
- ) {
- Scaffold(
- modifier = Modifier.fillMaxSize(),
- topBar = {
- TopAppBar(
- title = {
- Text(
- overflow = TextOverflow.Ellipsis,
- maxLines = 1,
- text = stringResource(Res.string.network__title),
- )
- },
- navigationIcon = {
- IconButton(
- onClick = { screen.popBackStack() },
- ) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.ArrowBack,
- contentDescription = null,
- )
- }
- }
- )
- },
- content = { paddingValues ->
- NetworkContent(
- modifier = Modifier.fillMaxSize(),
- paddingValues = paddingValues,
- network = viewModel.network.collectAsState(),
- onPlayerChange = viewModel::onPlayerNameChange,
- onHostChange = viewModel::onHostChange,
- onResetPortChange = viewModel::onResetPortChange,
- onPortChange = viewModel::onPortChange,
- onResetHostChange = viewModel::onResetHostChange,
- onConnect = { scope.launch { viewModel.connect() } },
- onDisconnect = viewModel::disconnect,
- )
- }
- )
- }
-
- AnimatedContent(
- modifier = Modifier.size(size = 64.dp),
- targetState = viewModel.isLoading.value,
- transitionSpec = { fadeIn() togetherWith fadeOut() },
- ) {
- when (it) {
- true -> CircularProgressIndicator()
- else -> Box(modifier = Modifier)
- }
- }
- }
-
- LaunchedEffect(Unit) {
- viewModel.message.collect {
- snack.showSnackbar(
- message = it,
- duration = SnackbarDuration.Short,
- )
- }
- }
-
- ErrorSnack(
- error = viewModel.networkError,
- )
- }
-}
-
-@Composable
-fun NetworkPage(
+fun NetworkDialog(
modifier: Modifier = Modifier,
viewModel: NetworkViewModel = koinViewModel(),
) {
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkFactory.kt
similarity index 92%
rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkFactory.kt
rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkFactory.kt
index 1c2f209..3738445 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkFactory.kt
@@ -1,4 +1,4 @@
-package com.pixelized.desktop.lwa.ui.screen.network
+package com.pixelized.desktop.lwa.ui.screen.campaign.network
import com.pixelized.desktop.lwa.repository.network.NetworkRepository.Status
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkViewModel.kt
similarity index 98%
rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkViewModel.kt
rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkViewModel.kt
index 0b521fa..fa64620 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/network/NetworkViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/network/NetworkViewModel.kt
@@ -1,4 +1,4 @@
-package com.pixelized.desktop.lwa.ui.screen.network
+package com.pixelized.desktop.lwa.ui.screen.campaign.network
import androidx.compose.material.SnackbarDuration
import androidx.compose.runtime.State
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbar.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbar.kt
index 6a45ed9..d6bd5d1 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbar.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbar.kt
@@ -1,13 +1,18 @@
package com.pixelized.desktop.lwa.ui.screen.campaign.toolbar
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
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.Text
+import androidx.compose.material.TextButton
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.MoreVert
@@ -17,33 +22,32 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
-import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToOldMainPage
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToSettings
+import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToGameMasterWindow
import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToRollHistory
-import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkPage
-import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
+import com.pixelized.desktop.lwa.ui.screen.campaign.network.NetworkDialog
import com.pixelized.desktop.lwa.ui.theme.lwa
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.ic_settings_24dp
-import lwacharactersheet.composeapp.generated.resources.ic_table_24dp
import lwacharactersheet.composeapp.generated.resources.ic_timeline_24dp
import lwacharactersheet.composeapp.generated.resources.ic_wifi_24dp
import lwacharactersheet.composeapp.generated.resources.ic_wifi_off_24dp
import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
+import lwacharactersheet.composeapp.generated.resources.settings__title
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
@Composable
fun CampaignToolbar(
- campaignViewModel: CampaignViewModel = koinViewModel(),
- networkViewModel: NetworkViewModel = koinViewModel(),
+ viewModel: CampaignToolbarViewModel = koinViewModel(),
) {
val windows = LocalWindowController.current
val screen = LocalScreenController.current
@@ -51,60 +55,31 @@ fun CampaignToolbar(
val isOverflowMenuOpen = remember { mutableStateOf(false) }
val isNetworkMenuOpen = remember { mutableStateOf(false) }
+ val title = viewModel.title.collectAsState()
+ val status = viewModel.status.collectAsState()
+ val isGM = viewModel.isGM.collectAsState()
+
CampaignToolbarContent(
- title = campaignViewModel.title.collectAsState(initial = ""),
- networkStatus = campaignViewModel.networkStatus.collectAsState(),
+ title = title,
+ status = status,
+ isGM = isGM,
isNetworkMenuOpen = isNetworkMenuOpen,
isOverflowMenuOpen = isOverflowMenuOpen,
- networkMenu = {
- NetworkPage(
- modifier = Modifier.size(384.dp + 96.dp, 240.dp),
- viewModel = networkViewModel
- )
- },
- overflowMenu = {
- DropdownMenuItem(
- onClick = {
- isOverflowMenuOpen.value = false
- windows.navigateToRollHistory()
- },
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_timeline_24dp),
- tint = MaterialTheme.lwa.colorScheme.base.primary,
- contentDescription = null,
- )
- Text(
- modifier = Modifier.padding(start = 8.dp),
- color = MaterialTheme.colors.primary,
- text = stringResource(Res.string.main_page__roll_history_action),
- )
- }
- DropdownMenuItem(
- onClick = {
- isOverflowMenuOpen.value = false
- screen.navigateToOldMainPage()
- },
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_table_24dp),
- tint = MaterialTheme.lwa.colorScheme.base.primary,
- contentDescription = null,
- )
- Text(
- modifier = Modifier.padding(start = 8.dp),
- color = MaterialTheme.colors.primary,
- text = "Ancienne interface utilisateur",
- )
- }
+ onGM = {
+ windows.navigateToGameMasterWindow()
},
onNetwork = {
isNetworkMenuOpen.value = true
},
onOverflow = {
- isOverflowMenuOpen.value = isOverflowMenuOpen.value.not()
+ isOverflowMenuOpen.value = true
+ },
+ onRollHistory = {
+ isOverflowMenuOpen.value = false
+ windows.navigateToRollHistory()
},
onSettings = {
+ isOverflowMenuOpen.value = false
screen.navigateToSettings()
},
onDismissNetworkMenu = {
@@ -120,13 +95,14 @@ fun CampaignToolbar(
private fun CampaignToolbarContent(
modifier: Modifier = Modifier,
title: State,
- networkStatus: State,
+ status: State,
+ isGM: State,
isNetworkMenuOpen: State,
isOverflowMenuOpen: State,
- networkMenu: @Composable () -> Unit,
- overflowMenu: @Composable () -> Unit,
+ onGM: () -> Unit,
onNetwork: () -> Unit,
onOverflow: () -> Unit,
+ onRollHistory: () -> Unit,
onSettings: () -> Unit,
onDismissNetworkMenu: () -> Unit,
onDismissOverflowMenu: () -> Unit,
@@ -139,38 +115,38 @@ private fun CampaignToolbarContent(
)
},
actions = {
+ AnimatedVisibility(
+ visible = isGM.value,
+ enter = fadeIn(),
+ exit = fadeOut(),
+ ) {
+ TextButton(
+ modifier = Modifier.size(size = 48.dp).clip(shape = CircleShape),
+ onClick = onGM,
+ ) {
+ Text(
+ fontWeight = FontWeight.SemiBold,
+ text = "GM",
+ )
+ }
+ }
IconButton(
- onClick = onNetwork
+ onClick = onNetwork,
) {
Icon(
painter = painterResource(
- when (networkStatus.value) {
+ when (status.value) {
NetworkRepository.Status.CONNECTED -> Res.drawable.ic_wifi_24dp
NetworkRepository.Status.DISCONNECTED -> Res.drawable.ic_wifi_off_24dp
}
),
- tint = when (networkStatus.value) {
+ tint = when (status.value) {
NetworkRepository.Status.CONNECTED -> MaterialTheme.lwa.colorScheme.base.primary
NetworkRepository.Status.DISCONNECTED -> MaterialTheme.lwa.colorScheme.base.error
},
contentDescription = null,
)
}
- DropdownMenu(
- offset = remember { DpOffset(x = -(48.dp * 2 + 8.dp), y = 8.dp) },
- expanded = isNetworkMenuOpen.value,
- onDismissRequest = onDismissNetworkMenu,
- content = { networkMenu() },
- )
- IconButton(
- onClick = onSettings
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_settings_24dp),
- tint = MaterialTheme.lwa.colorScheme.base.primary,
- contentDescription = null,
- )
- }
IconButton(
onClick = onOverflow,
) {
@@ -180,11 +156,50 @@ private fun CampaignToolbarContent(
contentDescription = null,
)
}
+ DropdownMenu(
+ offset = remember { DpOffset(x = -(48.dp + 8.dp), y = 8.dp) },
+ expanded = isNetworkMenuOpen.value,
+ onDismissRequest = onDismissNetworkMenu,
+ content = {
+ NetworkDialog(
+ modifier = Modifier.size(384.dp + 96.dp, 240.dp),
+ )
+ },
+ )
DropdownMenu(
offset = remember { DpOffset(x = (-8).dp, y = 8.dp) },
expanded = isOverflowMenuOpen.value,
onDismissRequest = onDismissOverflowMenu,
- content = { overflowMenu() },
+ content = {
+ DropdownMenuItem(
+ onClick = onRollHistory,
+ ) {
+ Icon(
+ painter = painterResource(Res.drawable.ic_timeline_24dp),
+ tint = MaterialTheme.lwa.colorScheme.base.primary,
+ contentDescription = null,
+ )
+ Text(
+ modifier = Modifier.padding(start = 8.dp),
+ color = MaterialTheme.colors.primary,
+ text = stringResource(Res.string.main_page__roll_history_action),
+ )
+ }
+ DropdownMenuItem(
+ onClick = onSettings,
+ ) {
+ Icon(
+ painter = painterResource(Res.drawable.ic_settings_24dp),
+ tint = MaterialTheme.lwa.colorScheme.base.primary,
+ contentDescription = null,
+ )
+ Text(
+ modifier = Modifier.padding(start = 8.dp),
+ color = MaterialTheme.colors.primary,
+ text = stringResource(Res.string.settings__title),
+ )
+ }
+ },
)
},
)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbarViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbarViewModel.kt
new file mode 100644
index 0000000..0bf23c9
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/toolbar/CampaignToolbarViewModel.kt
@@ -0,0 +1,35 @@
+package com.pixelized.desktop.lwa.ui.screen.campaign.toolbar
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
+import com.pixelized.desktop.lwa.repository.network.NetworkRepository
+import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+class CampaignToolbarViewModel(
+ campaignRepository: CampaignRepository,
+ networkRepository: NetworkRepository,
+ settingsRepository: SettingsRepository,
+) : ViewModel() {
+
+ val status = networkRepository.status
+
+ val title = campaignRepository.campaignFlow
+ .map { it.scene.name }
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.Lazily,
+ initialValue = "",
+ )
+
+ val isGM = settingsRepository.settingsFlow()
+ .map { it.isGM }
+ .stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.Lazily,
+ initialValue = false,
+ )
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt
index 1a093ff..0cf3826 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt
@@ -94,7 +94,7 @@ class CharacterSheetViewModel(
characterId = argument.characterInstanceId.characterSheetId
) ?: return
_displayDeleteConfirmationDialog.value = CharacterSheetDeleteConfirmationDialogUio(
- id = preview.id,
+ id = preview.characterSheetId,
name = preview.name,
)
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt
new file mode 100644
index 0000000..703efc8
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt
@@ -0,0 +1,35 @@
+package com.pixelized.desktop.lwa.ui.screen.gamemaster
+
+import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio.Action
+
+class GameMasterActionUseCase(
+ private val campaignRepository: CampaignRepository,
+) {
+ suspend fun handleAction(
+ characterSheetId: String,
+ action: Action,
+ ) {
+ when (action) {
+ Action.DisplayPortrait -> TODO()
+
+ Action.AddToGroup -> campaignRepository.addCharacter(
+ characterSheetId = characterSheetId,
+ )
+
+ Action.AddToNpc -> campaignRepository.addNpc(
+ characterSheetId = characterSheetId,
+ )
+
+ is Action.RemoveFromGroup -> campaignRepository.removeCharacter(
+ characterSheetId = characterSheetId,
+ instanceId = action.instanceId
+ )
+
+ is Action.RemoveFromNpc -> campaignRepository.removeNpc(
+ characterSheetId = characterSheetId,
+ instanceId = action.instanceId
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt
new file mode 100644
index 0000000..ddca343
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt
@@ -0,0 +1,119 @@
+package com.pixelized.desktop.lwa.ui.screen.gamemaster
+
+import com.pixelized.desktop.lwa.repository.campaign.model.CharacterSheetPreview
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio.Action
+import com.pixelized.shared.lwa.model.campaign.Campaign
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_label
+import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_search
+import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_label
+import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_search
+import org.jetbrains.compose.resources.getString
+import java.text.Normalizer
+
+class GameMasterFactory {
+
+ suspend fun convertToGMCharacterPreviewUio(
+ campaign: Campaign,
+ characters: List,
+ filter: String,
+ ): List {
+ val normalizedFilter = Normalizer.normalize(filter, Normalizer.Form.NFD)
+
+ return characters.mapNotNull {
+ convertToGMCharacterPreviewUio(
+ campaign = campaign,
+ character = it,
+ filter = normalizedFilter,
+ )
+ }
+ }
+
+ private suspend fun convertToGMCharacterPreviewUio(
+ campaign: Campaign,
+ character: CharacterSheetPreview,
+ filter: String,
+ ): GMCharacterPreviewUio? {
+ val characterId = campaign.characters.keys.firstOrNull {
+ it.characterSheetId == character.characterSheetId
+ }
+
+ val npcIds = campaign.npcs.keys.filter {
+ it.characterSheetId == character.characterSheetId
+ }
+
+ var playerTagHighlighted = false
+ var npcTagHighlighted = false
+
+ // Filter process.
+ if (filter.isNotEmpty()) {
+ val normalizedName = Normalizer.normalize(character.name, Normalizer.Form.NFD)
+ // If the filter is not empty and the character is not
+ val playerTag = getString(Res.string.game_master__character_tag__character_search)
+ val npcTag = getString(Res.string.game_master__character_tag__npc_search)
+
+ playerTagHighlighted = playerTag.contains(other = filter, ignoreCase = true)
+ if (playerTagHighlighted && characterId == null) {
+ return null
+ }
+
+ npcTagHighlighted = npcTag.contains(other = filter, ignoreCase = true)
+ if (npcTagHighlighted && npcIds.isEmpty()) {
+ return null
+ }
+
+ val nameHighlight = normalizedName.contains(other = filter, ignoreCase = true)
+ if (nameHighlight.not() && playerTagHighlighted.not() && npcTagHighlighted.not()) {
+ return null
+ }
+ }
+
+ val tags = buildList {
+ if (characterId != null) {
+ add(
+ GMCharacterPreviewUio.Tag(
+ label = getString(
+ Res.string.game_master__character_tag__character_label,
+ characterId.instanceId,
+ ),
+ highlight = playerTagHighlighted,
+ )
+ )
+ }
+ addAll(
+ npcIds.map { npcId ->
+ GMCharacterPreviewUio.Tag(
+ label = getString(
+ Res.string.game_master__character_tag__npc_label,
+ npcId.instanceId
+ ),
+ highlight = npcTagHighlighted,
+ )
+ }
+ )
+ }
+
+ val actions = buildList {
+ add(
+ when (characterId) {
+ null -> Action.AddToGroup
+ else -> Action.RemoveFromGroup(instanceId = characterId.instanceId)
+ }
+ )
+ add(Action.AddToNpc)
+ addAll(
+ npcIds.map { npcId ->
+ Action.RemoveFromNpc(instanceId = npcId.instanceId)
+ }
+ )
+ }
+
+ return GMCharacterPreviewUio(
+ characterSheetId = character.characterSheetId,
+ name = character.name, level = character.level,
+ tags = tags,
+ actions = actions,
+ )
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..0698ad4
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt
@@ -0,0 +1,118 @@
+package com.pixelized.desktop.lwa.ui.screen.gamemaster
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.lazy.items
+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.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.collectAsState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+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.gamemaster.items.GMCharacterPreview
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
+import com.pixelized.desktop.lwa.ui.theme.lwa
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
+import org.jetbrains.compose.resources.painterResource
+import org.koin.compose.viewmodel.koinViewModel
+
+@Composable
+fun GameMasterScreen(
+ viewModel: GameMasterViewModel = koinViewModel(),
+) {
+ val characters = viewModel.characters.collectAsState()
+
+ Surface(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ GameMasterContent(
+ modifier = Modifier.fillMaxSize(),
+ filter = viewModel.filter,
+ characters = characters,
+ onCharacterAction = viewModel::onCharacterAction,
+ )
+ }
+}
+
+@Composable
+private fun GameMasterContent(
+ modifier: Modifier = Modifier,
+ filter: LwaTextFieldUio,
+ characters: State>,
+ onCharacterAction: (String, GMCharacterPreviewUio.Action) -> Unit,
+) {
+ Scaffold(
+ modifier = modifier,
+ topBar = {
+ TopAppBar(
+ title = {
+ Text(
+ text = "",
+ )
+ }
+ )
+ },
+ content = { paddingValues ->
+ Column(
+ modifier = Modifier.padding(paddingValues = paddingValues)
+ ) {
+ LwaTextField(
+ modifier = Modifier.fillMaxWidth(),
+ field = filter,
+ trailingIcon = {
+ val value = filter.valueFlow.collectAsState()
+ AnimatedVisibility(
+ visible = value.value.isNotBlank(),
+ enter = fadeIn(),
+ exit = fadeOut(),
+ ) {
+ IconButton(
+ onClick = { filter.onValueChange.invoke("") },
+ ) {
+ Icon(
+ painter = painterResource(Res.drawable.ic_cancel_24dp),
+ tint = MaterialTheme.lwa.colorScheme.base.primary,
+ contentDescription = null,
+ )
+ }
+ }
+ }
+ )
+ LazyColumn(
+ modifier = Modifier.weight(1f),
+ contentPadding = PaddingValues(all = 8.dp),
+ verticalArrangement = Arrangement.spacedBy(space = 8.dp),
+ ) {
+ items(
+ items = characters.value,
+ ) { character ->
+ GMCharacterPreview(
+ modifier = Modifier.fillMaxWidth(),
+ character = character,
+ onAction = { action ->
+ onCharacterAction(character.characterSheetId, action)
+ }
+ )
+ }
+ }
+ }
+ }
+ )
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterViewModel.kt
new file mode 100644
index 0000000..ddf37ad
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterViewModel.kt
@@ -0,0 +1,57 @@
+package com.pixelized.desktop.lwa.ui.screen.gamemaster
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
+import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
+import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+class GameMasterViewModel(
+ private val campaignRepository: CampaignRepository,
+ private val characterSheetRepository: CharacterSheetRepository,
+ private val gameMasterFactory: GameMasterFactory,
+ private val useCase: GameMasterActionUseCase,
+) : ViewModel() {
+
+ private val _filter = MutableStateFlow("")
+ val filter = LwaTextFieldUio(
+ enable = true,
+ labelFlow = MutableStateFlow("Filtre"),
+ valueFlow = _filter,
+ placeHolderFlow = MutableStateFlow(null),
+ onValueChange = { _filter.value = it },
+ )
+
+ val characters = combine(
+ campaignRepository.campaignFlow,
+ characterSheetRepository.characterSheetPreviewFlow,
+ filter.valueFlow,
+ gameMasterFactory::convertToGMCharacterPreviewUio,
+ ).stateIn(
+ scope = viewModelScope,
+ started = SharingStarted.Eagerly,
+ initialValue = emptyList(),
+ )
+
+ fun onCharacterAction(
+ characterSheetId: String,
+ action: GMCharacterPreviewUio.Action,
+ ) {
+ viewModelScope.launch {
+ try {
+ useCase.handleAction(
+ characterSheetId = characterSheetId,
+ action = action,
+ )
+ } catch (exception: Exception) {
+ // TODO
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacterPreview.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacterPreview.kt
new file mode 100644
index 0000000..34a8945
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacterPreview.kt
@@ -0,0 +1,226 @@
+package com.pixelized.desktop.lwa.ui.screen.gamemaster.items
+
+import androidx.compose.foundation.background
+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.calculateStartPadding
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+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.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.mutableStateOf
+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.platform.LocalLayoutDirection
+import androidx.compose.ui.unit.DpOffset
+import androidx.compose.ui.unit.dp
+import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio.Action
+import com.pixelized.desktop.lwa.ui.theme.lwa
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.game_master__character_action__add_to_group
+import lwacharactersheet.composeapp.generated.resources.game_master__character_action__add_to_npc
+import lwacharactersheet.composeapp.generated.resources.game_master__character_action__display_portrait
+import lwacharactersheet.composeapp.generated.resources.game_master__character_action__remove_from_group
+import lwacharactersheet.composeapp.generated.resources.game_master__character_action__remove_from_npc
+import lwacharactersheet.composeapp.generated.resources.game_master__character_level__label
+import org.jetbrains.compose.resources.stringResource
+
+@Stable
+data class GMCharacterPreviewUio(
+ val characterSheetId: String,
+ val name: String,
+ val level: Int,
+ val tags: List,
+ val actions: List,
+) {
+ @Stable
+ data class Tag(
+ val label: String,
+ val highlight: Boolean,
+ )
+
+ @Stable
+ sealed class Action {
+ @Stable
+ data object DisplayPortrait : Action()
+
+ @Stable
+ data object AddToGroup : Action()
+
+ @Stable
+ data class RemoveFromGroup(val instanceId: Int) : Action()
+
+ @Stable
+ data object AddToNpc : Action()
+
+ @Stable
+ data class RemoveFromNpc(val instanceId: Int) : Action()
+ }
+}
+
+object GMCharacterPreviewDefault {
+ val padding = PaddingValues(horizontal = 16.dp)
+}
+
+@Composable
+fun GMCharacterPreview(
+ modifier: Modifier = Modifier,
+ padding: PaddingValues = GMCharacterPreviewDefault.padding,
+ character: GMCharacterPreviewUio,
+ onAction: (Action) -> Unit,
+) {
+ val layoutDirection = LocalLayoutDirection.current
+ val startPadding = padding.calculateStartPadding(layoutDirection)
+
+ Box(
+ modifier = Modifier
+ .clip(shape = remember { RoundedCornerShape(8.dp) })
+ .background(color = MaterialTheme.lwa.colorScheme.elevated.base1dp)
+ .then(other = modifier),
+ ) {
+ Column {
+ Row(
+ modifier = Modifier.padding(start = startPadding),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Row(
+ modifier = Modifier.weight(weight = 1f),
+ horizontalArrangement = Arrangement.spacedBy(4.dp),
+ ) {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.base.body1,
+ text = character.name,
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.base.caption,
+ text = stringResource(
+ Res.string.game_master__character_level__label,
+ character.level,
+ ),
+ )
+ }
+ OverflowActionMenu(
+ character = character,
+ onAction = onAction,
+ )
+ }
+ Row(
+ modifier = Modifier
+ .padding(paddingValues = padding)
+ .padding(bottom = 16.dp),
+ horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
+ ) {
+ character.tags.forEach { tag ->
+ Tag(tag = tag)
+ }
+ }
+ }
+ }
+}
+
+@Composable
+private fun OverflowActionMenu(
+ modifier: Modifier = Modifier,
+ character: GMCharacterPreviewUio,
+ onAction: (Action) -> Unit,
+) {
+ val overflowMenu = remember(character) {
+ mutableStateOf(false)
+ }
+ IconButton(
+ modifier = modifier,
+ onClick = {
+ overflowMenu.value = true
+ },
+ ) {
+ Icon(
+ imageVector = Icons.Default.MoreVert,
+ 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)
+ },
+ ) {
+ 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,
+ )
+
+ is Action.RemoveFromGroup -> stringResource(
+ Res.string.game_master__character_action__remove_from_group,
+ action.instanceId,
+ )
+
+ is Action.RemoveFromNpc -> stringResource(
+ Res.string.game_master__character_action__remove_from_npc,
+ action.instanceId,
+ )
+ }
+ )
+ }
+ }
+ },
+ )
+}
+
+
+@Composable
+private fun Tag(
+ modifier: Modifier = Modifier,
+ padding: PaddingValues = PaddingValues(horizontal = 8.dp, vertical = 2.dp),
+ tag: GMCharacterPreviewUio.Tag,
+) {
+ Text(
+ modifier = modifier
+ .background(
+ color = MaterialTheme.lwa.colorScheme.elevated.base4dp,
+ shape = CircleShape,
+ )
+ .padding(paddingValues = padding),
+ style = MaterialTheme.lwa.typography.base.caption,
+ color = when (tag.highlight) {
+ true -> MaterialTheme.lwa.colorScheme.base.secondary
+ else -> MaterialTheme.lwa.colorScheme.base.onSurface
+ },
+ text = tag.label,
+ )
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/main/MainPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/main/MainPage.kt
deleted file mode 100644
index b8a7c37..0000000
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/main/MainPage.kt
+++ /dev/null
@@ -1,294 +0,0 @@
-package com.pixelized.desktop.lwa.ui.screen.main
-
-import androidx.compose.foundation.ScrollState
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.Icon
-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.runtime.Composable
-import androidx.compose.runtime.Stable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.collectAsState
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.style.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.navigation.screen.LocalScreenController
-import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToMainPage
-import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToNetwork
-import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheet
-import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheetEdit
-import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToRollHistory
-import com.pixelized.shared.lwa.model.campaign.Campaign
-import kotlinx.coroutines.runBlocking
-import lwacharactersheet.composeapp.generated.resources.Res
-import lwacharactersheet.composeapp.generated.resources.app_name
-import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__create__title
-import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
-import lwacharactersheet.composeapp.generated.resources.ic_file_24dp
-import lwacharactersheet.composeapp.generated.resources.ic_folder_24dp
-import lwacharactersheet.composeapp.generated.resources.ic_swords_24dp
-import lwacharactersheet.composeapp.generated.resources.ic_table_24dp
-import lwacharactersheet.composeapp.generated.resources.main_page__create_action
-import lwacharactersheet.composeapp.generated.resources.main_page__network_action
-import lwacharactersheet.composeapp.generated.resources.main_page__open_save_directory
-import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
-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 CharacterUio(
- val id: Campaign.CharacterInstance.Id,
- val name: String,
-)
-
-@Composable
-fun OldMainPage(
- viewModel: MainPageViewModel = koinViewModel(),
-) {
- val window = LocalWindowController.current
- val screen = LocalScreenController.current
- val characters = viewModel.characters.collectAsState()
- val npcs = viewModel.npcs.collectAsState()
- val enableRollHistory = viewModel.enableRollHistoryFlow.collectAsState()
-
- Surface(
- modifier = Modifier.fillMaxSize(),
- ) {
- MainPageContent(
- characters = characters,
- npcs = npcs,
- enableRollHistory = enableRollHistory,
- onCharacter = {
- window.navigateToCharacterSheet(
- characterId = it.id,
- title = it.name,
- )
- },
- onCreateCharacter = {
- window.navigateToCharacterSheetEdit(
- characterId = null,
- title = runBlocking { getString(Res.string.character_sheet_edit__create__title) },
- )
- },
- onRollHistory = {
- window.navigateToRollHistory()
- },
- onOpenSaveDirectory = {
- viewModel.openSaveDirectory()
- },
- onNetwork = {
- screen.navigateToNetwork()
- },
- onMainPage = {
- screen.navigateToMainPage()
- }
- )
- }
-}
-
-@Composable
-fun MainPageContent(
- modifier: Modifier = Modifier,
- scrollState: ScrollState = rememberScrollState(),
- characters: State>,
- npcs: State>,
- enableRollHistory: State,
- onCharacter: (CharacterUio) -> Unit,
- onCreateCharacter: () -> Unit,
- onRollHistory: () -> Unit,
- onOpenSaveDirectory: () -> Unit,
- onNetwork: () -> Unit,
- onMainPage: () -> Unit,
-) {
- Scaffold(
- modifier = modifier,
- topBar = {
- TopAppBar(
- title = {
- Text(
- text = runBlocking { getString(Res.string.app_name) },
- )
- },
- actions = {
- TextButton(
- onClick = onMainPage,
- ) {
- Row(
- horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_swords_24dp),
- contentDescription = null,
- )
- Text(
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- maxLines = 1,
- text = "Nouvelle interface utilisateur",
- )
- }
- }
- }
- )
- },
- content = {
- Column {
- Box(
- modifier = Modifier
- .verticalScroll(state = scrollState)
- .fillMaxSize()
- .padding(horizontal = 16.dp),
- contentAlignment = Alignment.Center,
- ) {
- Column {
- if (characters.value.isNotEmpty()) {
- Column {
- characters.value.forEach { sheet ->
- TextButton(
- onClick = { onCharacter(sheet) },
- ) {
- Text(
- modifier = Modifier.fillMaxWidth(),
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- maxLines = 1,
- text = sheet.name,
- )
- }
- }
- }
- }
-
- if (characters.value.isNotEmpty() && npcs.value.isNotEmpty()) {
- Spacer(modifier = Modifier.height(height = 24.dp))
- }
-
- if (npcs.value.isNotEmpty()) {
- Column {
- npcs.value.forEach { sheet ->
- TextButton(
- onClick = { onCharacter(sheet) },
- ) {
- Text(
- modifier = Modifier.fillMaxWidth(),
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- maxLines = 1,
- text = sheet.name,
- )
- }
- }
- }
- }
-
- Spacer(modifier = Modifier.height(height = 24.dp))
-
- TextButton(
- onClick = onCreateCharacter,
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_file_24dp),
- contentDescription = null,
- )
- Text(
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- text = stringResource(Res.string.main_page__create_action),
- )
- }
- }
-
- TextButton(
- onClick = onOpenSaveDirectory,
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_folder_24dp),
- contentDescription = null,
- )
- Text(
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- text = stringResource(Res.string.main_page__open_save_directory),
- )
- }
- }
-
- TextButton(
- enabled = enableRollHistory.value,
- onClick = onRollHistory,
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_d20_24dp),
- contentDescription = null,
- )
- Text(
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- text = stringResource(Res.string.main_page__roll_history_action),
- )
- }
- }
-
- TextButton(
- onClick = onNetwork,
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
- verticalAlignment = Alignment.CenterVertically,
- ) {
- Icon(
- painter = painterResource(Res.drawable.ic_table_24dp),
- contentDescription = null,
- )
- Text(
- overflow = TextOverflow.Ellipsis,
- textAlign = TextAlign.Start,
- maxLines = 1,
- text = stringResource(Res.string.main_page__network_action),
- )
- }
- }
- }
- }
- }
- },
- )
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/main/MainPageViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/main/MainPageViewModel.kt
deleted file mode 100644
index 4101021..0000000
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/main/MainPageViewModel.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.pixelized.desktop.lwa.ui.screen.main
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import com.lordcodes.turtle.shellRun
-import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
-import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
-import com.pixelized.desktop.lwa.repository.network.NetworkRepository
-import com.pixelized.shared.lwa.utils.OperatingSystem
-import com.pixelized.shared.lwa.utils.PathProvider
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.flatMapMerge
-import kotlinx.coroutines.flow.flowOf
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-class MainPageViewModel(
- private val pathProvider: PathProvider,
- private val characterSheetRepository: CharacterSheetRepository,
- private val campaignRepository: CampaignRepository,
- networkRepository: NetworkRepository,
-) : ViewModel() {
-
- @OptIn(ExperimentalCoroutinesApi::class)
- val characters: StateFlow> = campaignRepository.campaignFlow
- .flatMapMerge { campaign ->
- combine(
- campaign.characters
- .map { entry ->
- characterSheetRepository
- .characterDetailFlow(characterSheetId = entry.key.characterSheetId)
- .map transform@{ sheet ->
- if (sheet == null) return@transform null
- CharacterUio(id = entry.key, name = sheet.name)
- }
- }
- .ifEmpty {
- listOf(flowOf(null))
- }
- ) { data ->
- data.mapNotNull { it }
- }
- }
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.Eagerly,
- initialValue = emptyList(),
- )
-
- @OptIn(ExperimentalCoroutinesApi::class)
- val npcs: StateFlow> = campaignRepository.campaignFlow
- .flatMapMerge { campaign ->
- combine(
- campaign.npcs
- .map { entry ->
- characterSheetRepository
- .characterDetailFlow(characterSheetId = entry.key.characterSheetId)
- .map transform@{ sheet ->
- if (sheet == null) return@transform null
- CharacterUio(id = entry.key, name = sheet.name)
- }
- }
- .ifEmpty {
- listOf(flowOf(null))
- }
- ) { data ->
- data.mapNotNull { it }
- }
- }
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.Eagerly,
- initialValue = emptyList(),
- )
-
- val enableRollHistoryFlow = networkRepository.status
- .map { it == NetworkRepository.Status.CONNECTED }
- .stateIn(
- scope = viewModelScope,
- started = SharingStarted.Lazily,
- initialValue = false,
- )
-
- fun openSaveDirectory(
- os: OperatingSystem = OperatingSystem.current,
- ) {
- val path = pathProvider.storePath(os = os)
- when (os) {
- OperatingSystem.Windows -> shellRun("explorer.exe", listOf(path))
- OperatingSystem.Macintosh -> shellRun("open", listOf(path))
- }
- }
-}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/rollhistory/RollHistoryViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/rollhistory/RollHistoryViewModel.kt
index 2547c1c..51a1d0d 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/rollhistory/RollHistoryViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/rollhistory/RollHistoryViewModel.kt
@@ -18,7 +18,7 @@ class RollHistoryViewModel(
characterRepository.characterSheetPreviewFlow,
rollRepository.rolls,
) { sheets, message ->
- val name = sheets.firstOrNull { it.id == message.characterSheetId }?.name ?: ""
+ val name = sheets.firstOrNull { it.characterSheetId == message.characterSheetId }?.name ?: ""
val roll = RollHistoryItemUio(
character = name,
skillLabel = message.skillLabel,
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt
index 7d46183..eff28b5 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt
@@ -13,6 +13,7 @@ class SettingsUseCase {
autoHideDelay = 8,
autoShowChat = true,
autoScrollChat = true,
+ isGM = false,
)
companion object {
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt
index 2661132..bea1a98 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/model/campaign/CampaignService.kt
@@ -33,7 +33,11 @@ class CampaignService(
initialValue = factory.convertToJson(campaignFlow.value),
)
- fun campaign(): CampaignJson {
+ fun campaign(): Campaign {
+ return campaignFlow.value
+ }
+
+ fun campaignJson(): CampaignJson {
return campaignJsonFlow.value
}
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt
index e2a949c..8dc0403 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/GET_Campaign.kt
@@ -5,6 +5,6 @@ import io.ktor.server.response.respond
fun Engine.getCampaign(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
- call.respond(campaignService.campaign())
+ call.respond(campaignService.campaignJson())
}
}
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_character.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_character.kt
index bd9f4a8..c5368bb 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_character.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_character.kt
@@ -9,30 +9,43 @@ import io.ktor.server.response.respondText
fun Engine.putCampaignCharacter(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
- val characterSheetId = call.queryParameters["characterSheetId"]
- val instanceId = call.queryParameters["instanceId"]?.toIntOrNull()
- val id = if (characterSheetId != null && instanceId != null) {
- Campaign.CharacterInstance.Id(
+ try {
+ val characterSheetId = call.queryParameters["characterSheetId"]
+ ?: error("missing character sheet id")
+
+ val instanceId = campaignService.campaign().characters.keys
+ .firstOrNull { key -> key.characterSheetId == characterSheetId }
+
+ if (instanceId != null) {
+ error("Character Already in party")
+ }
+
+ val id = Campaign.CharacterInstance.Id(
characterSheetId = characterSheetId,
- instanceId = instanceId
+ instanceId = 0,
)
- } else {
- null
- }
- val updated = id?.let { campaignService.addCharacter(it) } ?: false
- val code = when (updated) {
- true -> HttpStatusCode.Accepted
- else -> HttpStatusCode.UnprocessableEntity
- }
- call.respondText(
- text = "$code",
- status = code,
- )
- webSocket.emit(
- Message(
- from = "Server",
- value = RestSynchronisation.Campaign,
+
+ if (campaignService.addCharacter(id).not()) {
+ error("Unexpected error occurred when the character instance was added to the party")
+ }
+
+ call.respondText(
+ text = "Character $characterSheetId successfully added to the party",
+ status = HttpStatusCode.Accepted,
)
- )
+ webSocket.emit(
+ Message(
+ from = "Server",
+ value = RestSynchronisation.Campaign,
+ )
+ )
+ } catch (exception: Exception) {
+ call.run {
+ respondText(
+ text = "${exception.message}",
+ status = HttpStatusCode.UnprocessableEntity,
+ )
+ }
+ }
}
}
\ No newline at end of file
diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_npc.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_npc.kt
index 4f73a89..dcc1248 100644
--- a/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_npc.kt
+++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/rest/campaign/PUT_Campaign_npc.kt
@@ -9,35 +9,46 @@ import io.ktor.server.response.respondText
fun Engine.putCampaignNpc(): suspend io.ktor.server.routing.RoutingContext.() -> Unit {
return {
- val characterSheetId = call.queryParameters["characterSheetId"]
- val instanceId = call.queryParameters["instanceId"]?.toIntOrNull()
+ try {
+ val characterSheetId = call.queryParameters["characterSheetId"]
+ ?: error("missing character sheet id")
- val id = if (characterSheetId != null && instanceId != null) {
- Campaign.CharacterInstance.Id(
+ val instanceId = campaignService.campaign().npcs.keys
+ .filter { it.characterSheetId == characterSheetId }
+ .reduceOrNull { acc, id ->
+ if (acc.instanceId < id.instanceId) {
+ id
+ } else {
+ acc
+ }
+ }
+
+ val id = Campaign.CharacterInstance.Id(
characterSheetId = characterSheetId,
- instanceId = instanceId
+ instanceId = instanceId?.let { it.instanceId + 1 } ?: 0,
)
- } else {
- null
- }
- val updated = id?.let { campaignService.addNpc(it) } ?: false
+ if (campaignService.addNpc(id).not()) {
+ error("Unexpected error occurred when the character instance was added to the npcs")
+ }
- val code = when (updated) {
- true -> HttpStatusCode.Accepted
- else -> HttpStatusCode.UnprocessableEntity
- }
-
- call.respondText(
- text = "$code",
- status = code,
- )
-
- webSocket.emit(
- Message(
- from = "Server",
- value = RestSynchronisation.Campaign,
+ call.respondText(
+ text = "Character $characterSheetId successfully added to the npcs",
+ status = HttpStatusCode.Accepted,
)
- )
+ webSocket.emit(
+ Message(
+ from = "Server",
+ value = RestSynchronisation.Campaign,
+ )
+ )
+ } catch (exception: Exception) {
+ call.run {
+ respondText(
+ text = "${exception.message}",
+ status = HttpStatusCode.UnprocessableEntity,
+ )
+ }
+ }
}
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonFactory.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonFactory.kt
index 669fba3..58af874 100644
--- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonFactory.kt
+++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonFactory.kt
@@ -87,6 +87,8 @@ class CharacterSheetJsonFactory(
): CharacterPreviewJson {
return CharacterPreviewJson(
id = sheet.id,
+ portrait = sheet.portrait,
+ thumbnail = sheet.thumbnail,
name = sheet.name,
level = sheet.level,
)
@@ -98,8 +100,8 @@ class CharacterSheetJsonFactory(
val json = CharacterSheetJsonV1(
id = sheet.id,
name = sheet.name,
- thumbnail = sheet.thumbnail,
portrait = sheet.portrait,
+ thumbnail = sheet.thumbnail,
level = sheet.level,
shouldLevelUp = sheet.shouldLevelUp,
strength = sheet.strength,
diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/CharacterPreviewJson.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/CharacterPreviewJson.kt
index 632d77b..76e14a2 100644
--- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/CharacterPreviewJson.kt
+++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/rest/CharacterPreviewJson.kt
@@ -5,6 +5,8 @@ import kotlinx.serialization.Serializable
@Serializable
class CharacterPreviewJson(
val id: String,
+ val portrait: String?,
+ val thumbnail: String?,
val name: String,
val level: Int,
)
\ No newline at end of file