Add some chat log messages (diminished + hp/pp changes)

This commit is contained in:
Thomas Andres Gomez 2025-03-03 22:49:29 +01:00
parent 7a9dd97123
commit f60a58f71e
22 changed files with 503 additions and 38 deletions

View file

@ -157,4 +157,9 @@
<string name="roll_history__title">Historique des lancers</string>
<string name="roll_history__item__throw">lance</string>
<string name="roll_history__item__difficulty">Difficulté</string>
<string name="chat__diminished_change">%1$s passe à %2$d d\'état diminuée</string>
<string name="chat__characteristic_change">%1$s passe à %2$d %3$s</string>
<string name="chat__characteristic__hp">Hp</string>
<string name="chat__characteristic__pp">Pp</string>
</resources>

View file

@ -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

View file

@ -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

View file

@ -17,6 +17,10 @@ class CampaignRepository(
val campaignFlow get() = store.campaignFlow
suspend fun update() {
store.update()
}
fun characterInstanceFlow(
id: Campaign.CharacterInstance.Id,
): StateFlow<Campaign.CharacterInstance> {

View file

@ -37,7 +37,7 @@ class CampaignStore(
}
}
private suspend fun update() {
suspend fun update() {
_campaignFlow.value = load()
}

View file

@ -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,
)
}
}

View file

@ -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://")}"
}

View file

@ -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

View file

@ -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 = {

View file

@ -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,
)
}
}
}
}

View file

@ -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<List<TextMessage>>,
settings: State<Settings>,
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()
}
}
}
}

View file

@ -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<TextMessage>()

View file

@ -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

View file

@ -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,
),
)
}
}

View file

@ -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
),
)
}
}

View file

@ -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<SettingItemUio>,
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)
}
}
}
}
}
)
}
}

View file

@ -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<String, MutableState<Boolean>>()
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<String, MutableState<Boolean>>.dynamicDice
get() = getOrPut("DYNAMIC_DICE") { mutableStateOf(settings.value.dynamicDice) }
private val HashMap<String, MutableState<Boolean>>.autoShowChat
get() = getOrPut("AUTO_SHOW_CHAT") { mutableStateOf(settings.value.autoShowChat) }
private val HashMap<String, MutableState<Boolean>>.autoHideChat
get() = getOrPut("AUTO_HIDE_CHAT") { mutableStateOf(settings.value.autoHideChat) }
private val HashMap<String, MutableState<Boolean>>.autoScrollChat
get() = getOrPut("AUTO_SCROLL_CHAT") { mutableStateOf(settings.value.autoScrollChat) }
}

View file

@ -0,0 +1,6 @@
package com.pixelized.desktop.lwa.ui.screen.settings.composable
import androidx.compose.runtime.Stable
@Stable
sealed interface SettingItemUio

View file

@ -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,
)
}

View file

@ -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<Boolean>,
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
)
}
}

View file

@ -8,6 +8,10 @@ class SettingsUseCase {
host = DEFAULT_HOST,
port = DEFAULT_PORT,
playerName = "",
dynamicDice = true,
autoHideChat = true,
autoShowChat = true,
autoScrollChat = true,
)
companion object {