diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index f17faa1..1c3b949 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -157,4 +157,9 @@
Historique des lancers
lance
Difficulté
+
+ %1$s passe à %2$d d\'état diminuée
+ %1$s passe à %2$d %3$s
+ Hp
+ Pp
\ 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 10bc5ac..7b34129 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt
@@ -28,7 +28,6 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.max
import androidx.compose.ui.unit.min
import androidx.compose.ui.window.ApplicationScope
import androidx.compose.ui.window.Window
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 c509289..23e5558 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
@@ -33,6 +33,7 @@ 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.roll.RollViewModel
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
import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory
import com.pixelized.shared.lwa.utils.PathProvider
@@ -124,6 +125,7 @@ val viewModelDependencies
viewModelOf(::CharacterDiminishedViewModel)
viewModelOf(::CharacterDetailCharacteristicDialogViewModel)
viewModelOf(::CampaignChatViewModel)
+ viewModelOf(::SettingsViewModel)
}
val useCaseDependencies
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 5d6303b..c98cc3a 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
@@ -17,6 +17,10 @@ class CampaignRepository(
val campaignFlow get() = store.campaignFlow
+ suspend fun update() {
+ store.update()
+ }
+
fun characterInstanceFlow(
id: Campaign.CharacterInstance.Id,
): StateFlow {
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 d924209..61dddfe 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
@@ -37,7 +37,7 @@ class CampaignStore(
}
}
- private suspend fun update() {
+ suspend fun update() {
_campaignFlow.value = load()
}
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 e85735a..b5a5916 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
@@ -16,6 +16,10 @@ class SettingsFactory(
host = settings.host,
port = settings.port,
playerName = settings.playerName,
+ dynamicDice = settings.dynamicDice,
+ autoHideChat = settings.autoHideChat,
+ autoShowChat = settings.autoShowChat,
+ autoScrollChat = settings.autoScrollChat,
)
}
@@ -34,7 +38,11 @@ class SettingsFactory(
return Settings(
host = json.host ?: default.host,
port = json.port ?: default.port,
- playerName = json.playerName ?: default.playerName
+ playerName = json.playerName ?: default.playerName,
+ dynamicDice = json.dynamicDice ?: default.dynamicDice,
+ autoHideChat = json.autoHideChat ?: default.autoHideChat,
+ autoShowChat = json.autoShowChat ?: default.autoShowChat,
+ autoScrollChat = json.autoScrollChat ?: default.autoScrollChat,
)
}
}
\ 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 8d2b853..7af6816 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
@@ -4,6 +4,10 @@ data class Settings(
val host: String,
val port: Int,
val playerName: String,
+ val dynamicDice: Boolean,
+ val autoHideChat: Boolean,
+ val autoShowChat: Boolean,
+ val autoScrollChat: 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 4aee3e5..bbc4f26 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
@@ -7,4 +7,8 @@ data class SettingsJsonV1(
val host: String?,
val port: Int?,
val playerName: String?,
+ val dynamicDice: Boolean?,
+ val autoHideChat: Boolean?,
+ val autoShowChat: Boolean?,
+ val autoScrollChat: Boolean?,
) : SettingsJson
\ No newline at end of file
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 f6afe13..1bd2842 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
@@ -92,6 +92,7 @@ fun MainPage(
top = {
CampaignToolbar(
campaignViewModel = campaignViewModel,
+ networkViewModel = networkViewModel,
)
},
bottom = {
@@ -103,7 +104,7 @@ fun MainPage(
chat = {
CampaignChat(
modifier = Modifier.padding(all = 8.dp),
- campaignChatViewModel = campaignChatViewModel,
+ chatViewModel = campaignChatViewModel,
)
},
leftOverlay = {
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
index 02447fa..de9a871 100644
--- 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
@@ -26,21 +26,30 @@ class CampaignViewModel(
fun init() {
viewModelScope.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,
- )
+ 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,
+ )
+ }
}
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChat.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChat.kt
index 13e4fa3..cfd0e49 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChat.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChat.kt
@@ -32,9 +32,14 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.compose.ui.unit.min
import androidx.compose.ui.window.WindowState
+import com.pixelized.desktop.lwa.repository.settings.model.Settings
import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindowState
import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignLayoutScope
import com.pixelized.desktop.lwa.ui.screen.campaign.LocalCampaignLayoutScope
+import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.CharacteristicTextMessage
+import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.CharacteristicTextMessageUio
+import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.DiminishedTextMessage
+import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.DiminishedTextMessageUio
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.RollTextMessage
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.RollTextMessageUio
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.TextMessage
@@ -47,19 +52,21 @@ import org.koin.compose.viewmodel.koinViewModel
@Composable
fun CampaignChat(
modifier: Modifier = Modifier,
- campaignChatViewModel: CampaignChatViewModel = koinViewModel(),
+ chatViewModel: CampaignChatViewModel = koinViewModel(),
) {
val scope = rememberCoroutineScope()
val lazyState = rememberLazyListState()
val animatedChatWidth = rememberAnimatedChatWidth()
val colorScheme = MaterialTheme.lwa.colorScheme
- val messages = campaignChatViewModel.messages.collectAsState()
+ val messages = chatViewModel.messages.collectAsState()
+ val settings = chatViewModel.settings.collectAsState()
ChatScrollDownEffect(
lazyState = lazyState,
messages = messages,
- displayChat = campaignChatViewModel::displayChat,
- hideChat = campaignChatViewModel::hideChat,
+ settings = settings,
+ displayChat = chatViewModel::displayChat,
+ hideChat = chatViewModel::hideChat,
)
Box(
@@ -69,17 +76,19 @@ fun CampaignChat(
height = PlayerRibbon.Default.size.height * 2 + 8.dp,
)
.graphicsLayer {
- alpha = campaignChatViewModel.chatAnimatedVisibility.value
+ alpha = chatViewModel.chatAnimatedVisibility.value
}
.background(
shape = remember { RoundedCornerShape(8.dp) },
color = remember { colorScheme.elevated.base1dp.copy(alpha = 0.5f) },
)
.onPointerEvent(eventType = PointerEventType.Enter) {
- scope.launch { campaignChatViewModel.displayChat() }
+ scope.launch { chatViewModel.displayChat() }
}
.onPointerEvent(eventType = PointerEventType.Exit) {
- scope.launch { campaignChatViewModel.hideChat() }
+ if (settings.value.autoHideChat) {
+ scope.launch { chatViewModel.hideChat() }
+ }
},
) {
LazyColumn(
@@ -98,6 +107,8 @@ fun CampaignChat(
) {
when (it) {
is RollTextMessageUio -> RollTextMessage(message = it)
+ is DiminishedTextMessageUio -> DiminishedTextMessage(message = it)
+ is CharacteristicTextMessageUio -> CharacteristicTextMessage(message = it)
}
}
}
@@ -108,6 +119,7 @@ fun CampaignChat(
private fun ChatScrollDownEffect(
lazyState: LazyListState,
messages: State>,
+ settings: State,
displayChat: suspend () -> Unit,
hideChat: suspend () -> Unit,
) {
@@ -115,11 +127,17 @@ private fun ChatScrollDownEffect(
key1 = messages.value.lastOrNull()?.id,
) {
if (messages.value.isNotEmpty()) {
- displayChat()
- lazyState.animateScrollToItem(
- index = messages.value.lastIndex + 1,
- )
- hideChat()
+ if (settings.value.autoShowChat) {
+ displayChat()
+ }
+ if (settings.value.autoScrollChat) {
+ lazyState.animateScrollToItem(
+ index = messages.value.lastIndex + 1,
+ )
+ }
+ if (settings.value.autoHideChat) {
+ hideChat()
+ }
}
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt
index 160843a..8c8e72e 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt
@@ -5,6 +5,7 @@ import androidx.compose.animation.core.tween
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
+import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.TextMessage
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -15,8 +16,11 @@ import kotlinx.coroutines.flow.stateIn
class CampaignChatViewModel(
networkRepository: NetworkRepository,
textMessageFactory: TextMessageFactory,
+ settingsRepository: SettingsRepository,
) : ViewModel() {
+ val settings = settingsRepository.settingsFlow()
+
val chatAnimatedVisibility = Animatable(0f)
private var _messages = emptyList()
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/TextMessageFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/TextMessageFactory.kt
index bc8d5df..b7674a5 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/TextMessageFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/TextMessageFactory.kt
@@ -1,26 +1,40 @@
package com.pixelized.desktop.lwa.ui.screen.campaign.chat
+import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
+import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.CharacteristicTextMessageUio
+import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.DiminishedTextMessageUio
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.RollTextMessageUio
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.text.TextMessage
+import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
+import com.pixelized.shared.lwa.model.campaign.Campaign
+import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Damage
+import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Power
import com.pixelized.shared.lwa.protocol.websocket.Message
import com.pixelized.shared.lwa.protocol.websocket.payload.CampaignMessage
import com.pixelized.shared.lwa.protocol.websocket.payload.RestSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.payload.RollMessage
import com.pixelized.shared.lwa.protocol.websocket.payload.UpdateSkillUsageMessage
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.chat__characteristic__hp
+import lwacharactersheet.composeapp.generated.resources.chat__characteristic__pp
+import org.jetbrains.compose.resources.getString
import java.text.SimpleDateFormat
class TextMessageFactory(
private val characterSheetRepository: CharacterSheetRepository,
+ private val alterationRepository: AlterationRepository,
+ private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory,
) {
private val formatId = SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS")
private val formatTime = SimpleDateFormat("HH:mm:ss")
- fun convertToTextMessage(
+ suspend fun convertToTextMessage(
message: Message,
): TextMessage? {
val time = System.currentTimeMillis()
val id = formatId.format(time)
+
return when (val payload = message.value) {
is RollMessage -> {
val sheetPreview = characterSheetRepository
@@ -47,8 +61,54 @@ class TextMessageFactory(
)
}
- is CampaignMessage.UpdateCharacteristic -> null
- is CampaignMessage.UpdateDiminished -> null
+ is CampaignMessage.UpdateDiminished -> {
+ val characterInstanceId = Campaign.CharacterInstance.Id(
+ characterSheetId = payload.characterSheetId,
+ instanceId = payload.instanceId,
+ )
+
+ val sheetPreview = characterSheetRepository
+ .characterPreview(characterId = payload.characterSheetId)
+ ?: return null
+
+ DiminishedTextMessageUio(
+ id = id,
+ timestamp = formatTime.format(time),
+ character = sheetPreview.name,
+ diminished = payload.diminished,
+ )
+ }
+
+ is CampaignMessage.UpdateCharacteristic -> {
+ val sheet = characterSheetRepository.characterDetail(
+ characterSheetId = payload.characterSheetId,
+ ) ?: return null
+ val characterInstanceId = Campaign.CharacterInstance.Id(
+ characterSheetId = payload.characterSheetId,
+ instanceId = payload.instanceId,
+ )
+ val alterations = alterationRepository.alterations(
+ characterInstanceId = characterInstanceId,
+ )
+ val alteredSheet = alteredCharacterSheetFactory.sheet(
+ characterSheet = sheet,
+ alterations = alterations,
+ )
+ CharacteristicTextMessageUio(
+ id = id,
+ timestamp = formatTime.format(time),
+ character = sheet.name,
+ value = when (payload.characteristic) {
+ Damage -> alteredSheet.maxHp - payload.value
+ Power -> alteredSheet.maxPp - payload.value
+ },
+ characteristic = when (payload.characteristic) {
+ Damage -> getString(Res.string.chat__characteristic__hp)
+ Power -> getString(Res.string.chat__characteristic__pp)
+ },
+ )
+ }
+
RestSynchronisation.Campaign -> null
is RestSynchronisation.CharacterDelete -> null
is RestSynchronisation.CharacterUpdate -> null
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/CharacteristicTextMessage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/CharacteristicTextMessage.kt
new file mode 100644
index 0000000..9328aee
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/CharacteristicTextMessage.kt
@@ -0,0 +1,64 @@
+package com.pixelized.desktop.lwa.ui.screen.campaign.chat.text
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.pixelized.desktop.lwa.ui.theme.lwa
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.chat__characteristic_change
+import org.jetbrains.compose.resources.stringResource
+
+@Stable
+data class CharacteristicTextMessageUio(
+ override val id: String,
+ override val timestamp: String,
+ val character: String,
+ val value: Int,
+ val characteristic: String,
+) : TextMessage
+
+@Composable
+fun CharacteristicTextMessage(
+ modifier: Modifier = Modifier,
+ message: CharacteristicTextMessageUio,
+) {
+ Row(
+ modifier = modifier,
+ horizontalArrangement = Arrangement.spacedBy(space = 3.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.chat.timestamp,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = message.timestamp,
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.chat.timestamp,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = ">",
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.chat.text,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = stringResource(
+ Res.string.chat__characteristic_change,
+ message.character,
+ message.value,
+ message.characteristic,
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/DiminishedTextMessage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/DiminishedTextMessage.kt
new file mode 100644
index 0000000..9da5f99
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/DiminishedTextMessage.kt
@@ -0,0 +1,62 @@
+package com.pixelized.desktop.lwa.ui.screen.campaign.chat.text
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.pixelized.desktop.lwa.ui.theme.lwa
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.chat__diminished_change
+import org.jetbrains.compose.resources.stringResource
+
+@Stable
+data class DiminishedTextMessageUio(
+ override val id: String,
+ override val timestamp: String,
+ val character: String,
+ val diminished: Int,
+) : TextMessage
+
+@Composable
+fun DiminishedTextMessage(
+ modifier: Modifier = Modifier,
+ message: DiminishedTextMessageUio,
+) {
+ Row(
+ modifier = modifier,
+ horizontalArrangement = Arrangement.spacedBy(space = 3.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.chat.timestamp,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = message.timestamp,
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.chat.timestamp,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = ">",
+ )
+ Text(
+ modifier = Modifier.alignByBaseline(),
+ style = MaterialTheme.lwa.typography.chat.text,
+ overflow = TextOverflow.Ellipsis,
+ maxLines = 1,
+ text = stringResource(
+ Res.string.chat__diminished_change,
+ message.character,
+ message.diminished
+ ),
+ )
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/RollText.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/RollTextMessage.kt
similarity index 100%
rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/RollText.kt
rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/text/RollTextMessage.kt
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt
index abfd139..0391b5b 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt
@@ -1,26 +1,43 @@
package com.pixelized.desktop.lwa.ui.screen.settings
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
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.IconButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
+import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingItemUio
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingSection
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingSectionUio
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingToggleItem
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingToggleItemUio
+import org.koin.compose.viewmodel.koinViewModel
+
@Composable
-fun SettingsScreen() {
+fun SettingsScreen(
+ viewModel: SettingsViewModel = koinViewModel(),
+) {
val screen = LocalScreenController.current
Surface {
SettingsContent(
modifier = Modifier.fillMaxSize(),
+ items = viewModel.items,
onBack = {
screen.popBackStack()
},
@@ -31,13 +48,18 @@ fun SettingsScreen() {
@Composable
private fun SettingsContent(
modifier: Modifier = Modifier,
+ state: ScrollState = rememberScrollState(),
+ spacing: Dp = 8.dp,
+ items: List,
onBack: () -> Unit,
) {
Scaffold(
modifier = modifier,
topBar = {
TopAppBar(
- title = { },
+ title = {
+ Text(text = "Paramètres de l\'application")
+ },
navigationIcon = {
IconButton(
onClick = onBack,
@@ -52,10 +74,24 @@ private fun SettingsContent(
},
content = { paddingValues ->
Column(
- modifier = Modifier.padding(paddingValues = paddingValues),
+ modifier = Modifier
+ .padding(paddingValues = paddingValues)
+ .verticalScroll(state = state),
+ verticalArrangement = Arrangement.spacedBy(space = spacing),
) {
+ items.forEach {
+ when (it) {
+ is SettingSectionUio -> {
+ SettingSection(item = it)
+ }
+ is SettingToggleItemUio -> {
+ SettingToggleItem(item = it)
+ }
+ }
+ }
}
}
)
-}
\ No newline at end of file
+}
+
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt
new file mode 100644
index 0000000..2f728b3
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt
@@ -0,0 +1,81 @@
+package com.pixelized.desktop.lwa.ui.screen.settings
+
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingSectionUio
+import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingToggleItemUio
+import kotlinx.coroutines.launch
+
+class SettingsViewModel(
+ private val settingsRepository: SettingsRepository,
+) : ViewModel() {
+ private val settings = settingsRepository.settingsFlow()
+ private val states = hashMapOf>()
+
+ val items = listOf(
+ SettingSectionUio(
+ title = "Portrait joueurs."
+ ),
+ SettingToggleItemUio(
+ title = "Dés dynamiques",
+ description = "Affiche un dés à côté du portrait d'un personnage lorsqu\'un jet est fait par ce dernier.",
+ checked = states.dynamicDice,
+ onToggle = {
+ settingsRepository.update(settings = settings.value.copy(dynamicDice = it))
+ },
+ ),
+ SettingSectionUio(
+ title = "Chatlog options."
+ ),
+ SettingToggleItemUio(
+ title = "Afficher automatiquement",
+ description = "Affiche automatiquement le chat lors de la réception d'un message.",
+ checked = states.autoShowChat,
+ onToggle = {
+ settingsRepository.update(settings = settings.value.copy(autoShowChat = it))
+ },
+ ),
+ SettingToggleItemUio(
+ title = "Cacher automatiquement",
+ description = "Cache automatiquement le chat au bout d'un certain temps.",
+ checked = states.autoHideChat,
+ onToggle = {
+ settingsRepository.update(settings = settings.value.copy(autoHideChat = it))
+ },
+ ),
+ SettingToggleItemUio(
+ title = "Défilement automatique",
+ description = "Défilement automatique de chat vers le dernier message reçu lors de la réception de ce dernier.",
+ checked = states.autoScrollChat,
+ onToggle = {
+ settingsRepository.update(settings = settings.value.copy(autoScrollChat = it))
+ },
+ ),
+ )
+
+ init {
+ viewModelScope.launch {
+ settingsRepository.settingsFlow().collect { settings ->
+ states.dynamicDice.value = settings.dynamicDice
+ states.autoShowChat.value = settings.autoShowChat
+ states.autoHideChat.value = settings.autoHideChat
+ states.autoScrollChat.value = settings.autoScrollChat
+ }
+ }
+ }
+
+ private val HashMap>.dynamicDice
+ get() = getOrPut("DYNAMIC_DICE") { mutableStateOf(settings.value.dynamicDice) }
+
+ private val HashMap>.autoShowChat
+ get() = getOrPut("AUTO_SHOW_CHAT") { mutableStateOf(settings.value.autoShowChat) }
+
+ private val HashMap>.autoHideChat
+ get() = getOrPut("AUTO_HIDE_CHAT") { mutableStateOf(settings.value.autoHideChat) }
+
+ private val HashMap>.autoScrollChat
+ get() = getOrPut("AUTO_SCROLL_CHAT") { mutableStateOf(settings.value.autoScrollChat) }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingItemUio.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingItemUio.kt
new file mode 100644
index 0000000..4660a2e
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingItemUio.kt
@@ -0,0 +1,6 @@
+package com.pixelized.desktop.lwa.ui.screen.settings.composable
+
+import androidx.compose.runtime.Stable
+
+@Stable
+sealed interface SettingItemUio
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt
new file mode 100644
index 0000000..6086799
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt
@@ -0,0 +1,30 @@
+package com.pixelized.desktop.lwa.ui.screen.settings.composable
+
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.pixelized.desktop.lwa.ui.theme.lwa
+
+@Stable
+data class SettingSectionUio(
+ val title: String,
+) : SettingItemUio
+
+@Composable
+fun SettingSection(
+ modifier: Modifier = Modifier,
+ padding: PaddingValues = PaddingValues(start = 16.dp, top = 32.dp, end = 16.dp),
+ item: SettingSectionUio,
+) {
+ Text(
+ modifier = modifier.padding(paddingValues = padding),
+ style = MaterialTheme.lwa.typography.base.h6,
+ maxLines = 1,
+ text = item.title,
+ )
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt
new file mode 100644
index 0000000..514415e
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt
@@ -0,0 +1,64 @@
+package com.pixelized.desktop.lwa.ui.screen.settings.composable
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Switch
+import androidx.compose.material.SwitchDefaults
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.State
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.pixelized.desktop.lwa.ui.theme.lwa
+
+@Stable
+data class SettingToggleItemUio(
+ val title: String,
+ val description: String,
+ val checked: State,
+ val onToggle: (Boolean) -> Unit,
+) : SettingItemUio
+
+@Composable
+fun SettingToggleItem(
+ modifier: Modifier = Modifier,
+ padding: PaddingValues = PaddingValues(start = 16.dp, top = 8.dp, end = 16.dp),
+ spacing: Dp = 8.dp,
+ item: SettingToggleItemUio,
+) {
+ Row(
+ modifier = modifier.padding(paddingValues = padding),
+ horizontalArrangement = Arrangement.spacedBy(space = spacing),
+ ) {
+ Column(
+ modifier = Modifier.weight(weight = 1f),
+ verticalArrangement = Arrangement.spacedBy(space = spacing),
+ ) {
+ Text(
+ style = MaterialTheme.lwa.typography.base.body1,
+ maxLines = 1,
+ text = item.title,
+ )
+ Text(
+ style = MaterialTheme.lwa.typography.base.caption,
+ fontStyle = FontStyle.Italic,
+ text = item.description,
+ )
+ }
+
+ Switch(
+ colors = SwitchDefaults.colors(
+ checkedThumbColor = MaterialTheme.lwa.colorScheme.base.primary,
+ ),
+ onCheckedChange = item.onToggle,
+ checked = item.checked.value
+ )
+ }
+}
\ No newline at end of file
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 2a71f22..df53702 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
@@ -8,6 +8,10 @@ class SettingsUseCase {
host = DEFAULT_HOST,
port = DEFAULT_PORT,
playerName = "",
+ dynamicDice = true,
+ autoHideChat = true,
+ autoShowChat = true,
+ autoScrollChat = true,
)
companion object {