Add some chat log messages (diminished + hp/pp changes)
This commit is contained in:
parent
7a9dd97123
commit
f60a58f71e
22 changed files with 503 additions and 38 deletions
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class CampaignStore(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun update() {
|
||||
suspend fun update() {
|
||||
_campaignFlow.value = load()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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://")}"
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.settings.composable
|
||||
|
||||
import androidx.compose.runtime.Stable
|
||||
|
||||
@Stable
|
||||
sealed interface SettingItemUio
|
||||
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,10 @@ class SettingsUseCase {
|
|||
host = DEFAULT_HOST,
|
||||
port = DEFAULT_PORT,
|
||||
playerName = "",
|
||||
dynamicDice = true,
|
||||
autoHideChat = true,
|
||||
autoShowChat = true,
|
||||
autoScrollChat = true,
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue