Refactor the setting data class + change the roll text message
This commit is contained in:
		
							parent
							
								
									353183f0f5
								
							
						
					
					
						commit
						07ed4ce579
					
				
					 15 changed files with 216 additions and 93 deletions
				
			
		| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    android:width="24dp"
 | 
			
		||||
    android:height="24dp"
 | 
			
		||||
    android:viewportWidth="960"
 | 
			
		||||
    android:viewportHeight="960">
 | 
			
		||||
  <path
 | 
			
		||||
      android:pathData="M120,880v-60h100v-30h-60v-60h60v-30L120,700v-60h120q17,0 28.5,11.5T280,680v40q0,17 -11.5,28.5T240,760q17,0 28.5,11.5T280,800v40q0,17 -11.5,28.5T240,880L120,880ZM120,600v-110q0,-17 11.5,-28.5T160,450h60v-30L120,420v-60h120q17,0 28.5,11.5T280,400v70q0,17 -11.5,28.5T240,510h-60v30h100v60L120,600ZM180,320v-180h-60v-60h120v240h-60ZM360,760v-80h480v80L360,760ZM360,520v-80h480v80L360,520ZM360,280v-80h480v80L360,280Z"
 | 
			
		||||
      android:fillColor="#5f6368"/>
 | 
			
		||||
</vector>
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +207,8 @@
 | 
			
		|||
    <string name="settings__chat_log__auto_hide_delay_description">Délai après lequel le chat disparaît</string>
 | 
			
		||||
    <string name="settings__chat_log__auto_scroll_title">Défilement automatique</string>
 | 
			
		||||
    <string name="settings__chat_log__auto_scroll_description">Défilement automatique du chat vers le dernier message reçu lors de la réception de ce dernier.</string>
 | 
			
		||||
    <string name="settings__chat_log__line_count_title">Nombre de lignes de textes visibles</string>
 | 
			
		||||
    <string name="settings__chat_log__line_count_description">Limite le nombre maximale de messages affichés par le chat.</string>
 | 
			
		||||
 | 
			
		||||
    <string name="level_up__title">Montée de niveau</string>
 | 
			
		||||
    <string name="level_up__action">Level Up !</string>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,8 +28,8 @@ class DataSyncViewModel(
 | 
			
		|||
        if (settings.playerName.isEmpty()) return
 | 
			
		||||
 | 
			
		||||
        networkRepository.connect(
 | 
			
		||||
            host = settings.host,
 | 
			
		||||
            port = settings.port,
 | 
			
		||||
            host = settings.network.host,
 | 
			
		||||
            port = settings.network.port,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ class LwaClientImpl(
 | 
			
		|||
    private val client: HttpClient,
 | 
			
		||||
    setting: SettingsRepository,
 | 
			
		||||
) : LwaClient {
 | 
			
		||||
    private val root = setting.settings().root
 | 
			
		||||
    private val root = setting.settings().network.root
 | 
			
		||||
 | 
			
		||||
    override suspend fun characters(): List<CharacterPreviewJson> = client
 | 
			
		||||
        .get("$root/characters")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,14 +13,15 @@ class SettingsFactory(
 | 
			
		|||
        settings: Settings,
 | 
			
		||||
    ): SettingsJson {
 | 
			
		||||
        return SettingsJsonV1(
 | 
			
		||||
            host = settings.host,
 | 
			
		||||
            port = settings.port,
 | 
			
		||||
            host = settings.network.host,
 | 
			
		||||
            port = settings.network.port,
 | 
			
		||||
            playerName = settings.playerName,
 | 
			
		||||
            dynamicDice = settings.dynamicDice,
 | 
			
		||||
            autoHideChat = settings.autoHideChat,
 | 
			
		||||
            autoHideDelay = settings.autoHideDelay,
 | 
			
		||||
            autoShowChat = settings.autoShowChat,
 | 
			
		||||
            autoScrollChat = settings.autoScrollChat,
 | 
			
		||||
            dynamicDice = settings.portrait.dynamicDice,
 | 
			
		||||
            autoHideChat = settings.chat.autoHideChat,
 | 
			
		||||
            autoHideDelay = settings.chat.autoHideDelay,
 | 
			
		||||
            autoShowChat = settings.chat.autoShowChat,
 | 
			
		||||
            autoScrollChat = settings.chat.autoScrollChat,
 | 
			
		||||
            maxLineCount = settings.chat.maxLineCount,
 | 
			
		||||
            isAdmin = settings.isAdmin,
 | 
			
		||||
            isGameMaster = settings.isGameMaster,
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			@ -39,14 +40,21 @@ class SettingsFactory(
 | 
			
		|||
    ): Settings {
 | 
			
		||||
        val default = useCase.defaultSettings()
 | 
			
		||||
        return Settings(
 | 
			
		||||
            host = json.host ?: default.host,
 | 
			
		||||
            port = json.port ?: default.port,
 | 
			
		||||
            playerName = json.playerName ?: default.playerName,
 | 
			
		||||
            dynamicDice = json.dynamicDice ?: default.dynamicDice,
 | 
			
		||||
            autoHideChat = json.autoHideChat ?: default.autoHideChat,
 | 
			
		||||
            autoHideDelay = json.autoHideDelay ?: default.autoHideDelay,
 | 
			
		||||
            autoShowChat = json.autoShowChat ?: default.autoShowChat,
 | 
			
		||||
            autoScrollChat = json.autoScrollChat ?: default.autoScrollChat,
 | 
			
		||||
            network = Settings.Network(
 | 
			
		||||
                host = json.host ?: default.network.host,
 | 
			
		||||
                port = json.port ?: default.network.port,
 | 
			
		||||
            ),
 | 
			
		||||
            portrait = Settings.Portrait(
 | 
			
		||||
                dynamicDice = json.dynamicDice ?: default.portrait.dynamicDice,
 | 
			
		||||
            ),
 | 
			
		||||
            chat = Settings.Chat(
 | 
			
		||||
                autoHideChat = json.autoHideChat ?: default.chat.autoHideChat,
 | 
			
		||||
                autoHideDelay = json.autoHideDelay ?: default.chat.autoHideDelay,
 | 
			
		||||
                autoShowChat = json.autoShowChat ?: default.chat.autoShowChat,
 | 
			
		||||
                autoScrollChat = json.autoScrollChat ?: default.chat.autoScrollChat,
 | 
			
		||||
                maxLineCount = json.maxLineCount ?: default.chat.maxLineCount,
 | 
			
		||||
            ),
 | 
			
		||||
            isAdmin = json.isAdmin ?: default.isAdmin,
 | 
			
		||||
            isGameMaster = json.isGameMaster ?: default.isGameMaster,
 | 
			
		||||
        )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,16 +1,29 @@
 | 
			
		|||
package com.pixelized.desktop.lwa.repository.settings.model
 | 
			
		||||
 | 
			
		||||
data class Settings(
 | 
			
		||||
    val host: String,
 | 
			
		||||
    val port: Int,
 | 
			
		||||
    val playerName: String,
 | 
			
		||||
    val dynamicDice: Boolean,
 | 
			
		||||
    val autoHideChat: Boolean,
 | 
			
		||||
    val autoHideDelay: Int,
 | 
			
		||||
    val autoShowChat: Boolean,
 | 
			
		||||
    val autoScrollChat: Boolean,
 | 
			
		||||
    val portrait: Portrait,
 | 
			
		||||
    val chat: Chat,
 | 
			
		||||
    val network: Network,
 | 
			
		||||
    val isAdmin: Boolean? = null,
 | 
			
		||||
    val isGameMaster: Boolean? = null,
 | 
			
		||||
) {
 | 
			
		||||
    val root: String get() = "http://${"${host}:${port}".removePrefix("http://")}"
 | 
			
		||||
    data class Portrait(
 | 
			
		||||
        val dynamicDice: Boolean,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    data class Chat(
 | 
			
		||||
        val autoHideChat: Boolean,
 | 
			
		||||
        val autoHideDelay: Int,
 | 
			
		||||
        val autoShowChat: Boolean,
 | 
			
		||||
        val autoScrollChat: Boolean,
 | 
			
		||||
        val maxLineCount: Int,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    data class Network(
 | 
			
		||||
        val host: String,
 | 
			
		||||
        val port: Int,
 | 
			
		||||
    ) {
 | 
			
		||||
        val root: String get() = "http://${"${host}:${port}".removePrefix("http://")}"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ data class SettingsJsonV1(
 | 
			
		|||
    val autoHideDelay: Int?,
 | 
			
		||||
    val autoShowChat: Boolean?,
 | 
			
		||||
    val autoScrollChat: Boolean?,
 | 
			
		||||
    val maxLineCount: Int?,
 | 
			
		||||
    val isGameMaster: Boolean?,
 | 
			
		||||
    val isAdmin: Boolean?,
 | 
			
		||||
) : SettingsJson
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ 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.repository.settings.model.Settings
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
 | 
			
		||||
import kotlinx.coroutines.CancellationException
 | 
			
		||||
| 
						 | 
				
			
			@ -32,8 +33,8 @@ class NetworkViewModel(
 | 
			
		|||
) : ViewModel() {
 | 
			
		||||
    private val settings = settingsRepository.settings()
 | 
			
		||||
    private val nameFlow = MutableStateFlow(settings.playerName)
 | 
			
		||||
    private val hostFlow = MutableStateFlow(settings.host)
 | 
			
		||||
    private val portFlow = MutableStateFlow(settings.port)
 | 
			
		||||
    private val hostFlow = MutableStateFlow(settings.network.host)
 | 
			
		||||
    private val portFlow = MutableStateFlow(settings.network.port)
 | 
			
		||||
 | 
			
		||||
    private val _networkError = MutableSharedFlow<ErrorSnackUio>()
 | 
			
		||||
    val networkError: SharedFlow<ErrorSnackUio> get() = _networkError
 | 
			
		||||
| 
						 | 
				
			
			@ -57,9 +58,9 @@ class NetworkViewModel(
 | 
			
		|||
            player = name,
 | 
			
		||||
            status = status,
 | 
			
		||||
            host = host,
 | 
			
		||||
            resetHost = settings.host != host,
 | 
			
		||||
            resetHost = settings.network.host != host,
 | 
			
		||||
            port = port,
 | 
			
		||||
            resetPort = settings.port != port,
 | 
			
		||||
            resetPort = settings.network.port != port,
 | 
			
		||||
        )
 | 
			
		||||
    }.stateIn(
 | 
			
		||||
        scope = viewModelScope,
 | 
			
		||||
| 
						 | 
				
			
			@ -71,8 +72,8 @@ class NetworkViewModel(
 | 
			
		|||
        settingsRepository.settingsFlow()
 | 
			
		||||
            .onEach {
 | 
			
		||||
                nameFlow.value = it.playerName
 | 
			
		||||
                hostFlow.value = it.host
 | 
			
		||||
                portFlow.value = it.port
 | 
			
		||||
                hostFlow.value = it.network.host
 | 
			
		||||
                portFlow.value = it.network.port
 | 
			
		||||
            }
 | 
			
		||||
            .launchIn(viewModelScope)
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +87,7 @@ class NetworkViewModel(
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    fun onResetPortChange() {
 | 
			
		||||
        portFlow.value = settings.port
 | 
			
		||||
        portFlow.value = settings.network.port
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun onHostChange(host: String) {
 | 
			
		||||
| 
						 | 
				
			
			@ -94,7 +95,7 @@ class NetworkViewModel(
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    fun onResetHostChange() {
 | 
			
		||||
        hostFlow.value = settings.host
 | 
			
		||||
        hostFlow.value = settings.network.host
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun connect() {
 | 
			
		||||
| 
						 | 
				
			
			@ -103,14 +104,16 @@ class NetworkViewModel(
 | 
			
		|||
 | 
			
		||||
        if (
 | 
			
		||||
            settings.playerName != nameFlow.value ||
 | 
			
		||||
            settings.host != hostFlow.value ||
 | 
			
		||||
            settings.port != portFlow.value
 | 
			
		||||
            settings.network.host != hostFlow.value ||
 | 
			
		||||
            settings.network.port != portFlow.value
 | 
			
		||||
        ) {
 | 
			
		||||
            settingsRepository.update(
 | 
			
		||||
                settings = settings.copy(
 | 
			
		||||
                    playerName = nameFlow.value,
 | 
			
		||||
                    host = hostFlow.value,
 | 
			
		||||
                    port = portFlow.value
 | 
			
		||||
                    network = Settings.Network(
 | 
			
		||||
                        host = hostFlow.value,
 | 
			
		||||
                        port = portFlow.value,
 | 
			
		||||
                    ),
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -117,7 +117,7 @@ abstract class CharacterRibbonViewModel(
 | 
			
		|||
                settingsRepository.settingsFlow(),
 | 
			
		||||
                rollHistoryRepository.rolls,
 | 
			
		||||
            ) { settings, roll ->
 | 
			
		||||
                if (settings.dynamicDice &&
 | 
			
		||||
                if (settings.portrait.dynamicDice &&
 | 
			
		||||
                    characterId.equals(roll.prefix, roll.characterSheetId, roll.instanceId)
 | 
			
		||||
                ) {
 | 
			
		||||
                    state.value = CharacterPortraitRollUio(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,7 +32,6 @@ 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
 | 
			
		||||
| 
						 | 
				
			
			@ -45,9 +44,27 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessag
 | 
			
		|||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessageUio
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.TextMessage
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.theme.lwa
 | 
			
		||||
import com.pixelized.desktop.lwa.usecase.SettingsUseCase
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import org.koin.compose.viewmodel.koinViewModel
 | 
			
		||||
 | 
			
		||||
@Stable
 | 
			
		||||
data class ChatSettingsUio(
 | 
			
		||||
    val autoShowChat: Boolean,
 | 
			
		||||
    val autoScrollChat: Boolean,
 | 
			
		||||
    val autoHideChat: Boolean,
 | 
			
		||||
) {
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun default() = with(SettingsUseCase().defaultSettings()) {
 | 
			
		||||
            ChatSettingsUio(
 | 
			
		||||
                autoShowChat = chat.autoShowChat,
 | 
			
		||||
                autoScrollChat = chat.autoScrollChat,
 | 
			
		||||
                autoHideChat = chat.autoHideChat,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@OptIn(ExperimentalComposeUiApi::class)
 | 
			
		||||
@Composable
 | 
			
		||||
fun CampaignChat(
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +136,7 @@ fun CampaignChat(
 | 
			
		|||
private fun ChatScrollDownEffect(
 | 
			
		||||
    lazyState: LazyListState,
 | 
			
		||||
    messages: State<List<TextMessage>>,
 | 
			
		||||
    settings: State<Settings>,
 | 
			
		||||
    settings: State<ChatSettingsUio>,
 | 
			
		||||
    displayChat: suspend () -> Unit,
 | 
			
		||||
    hideChat: suspend () -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,40 +6,54 @@ 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.text.messages.TextMessage
 | 
			
		||||
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
 | 
			
		||||
import kotlinx.coroutines.flow.SharingStarted
 | 
			
		||||
import kotlinx.coroutines.flow.StateFlow
 | 
			
		||||
import kotlinx.coroutines.flow.mapNotNull
 | 
			
		||||
import kotlinx.coroutines.flow.combine
 | 
			
		||||
import kotlinx.coroutines.flow.map
 | 
			
		||||
import kotlinx.coroutines.flow.runningFold
 | 
			
		||||
import kotlinx.coroutines.flow.stateIn
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CampaignChatViewModel(
 | 
			
		||||
    private val settingsRepository: SettingsRepository,
 | 
			
		||||
    networkRepository: NetworkRepository,
 | 
			
		||||
    textMessageFactory: TextMessageFactory,
 | 
			
		||||
    settingsRepository: SettingsRepository,
 | 
			
		||||
) : ViewModel() {
 | 
			
		||||
 | 
			
		||||
    val settings = settingsRepository.settingsFlow()
 | 
			
		||||
 | 
			
		||||
    val chatAnimatedVisibility = Animatable(0f)
 | 
			
		||||
 | 
			
		||||
    private var _messages = emptyList<TextMessage>()
 | 
			
		||||
    val messages: StateFlow<List<TextMessage>> = networkRepository.data
 | 
			
		||||
        .mapNotNull { message ->
 | 
			
		||||
            val text = textMessageFactory
 | 
			
		||||
                .convertToTextMessage(message = message)
 | 
			
		||||
                ?: return@mapNotNull _messages
 | 
			
		||||
 | 
			
		||||
            _messages = _messages.toMutableList().also {
 | 
			
		||||
                it.add(index = it.lastIndex + 1, element = text)
 | 
			
		||||
            }
 | 
			
		||||
            _messages
 | 
			
		||||
        }
 | 
			
		||||
        .stateIn(
 | 
			
		||||
            scope = viewModelScope,
 | 
			
		||||
            started = SharingStarted.Eagerly,
 | 
			
		||||
            initialValue = _messages,
 | 
			
		||||
    val settings = settingsRepository.settingsFlow().map {
 | 
			
		||||
        ChatSettingsUio(
 | 
			
		||||
            autoShowChat = it.chat.autoShowChat,
 | 
			
		||||
            autoScrollChat = it.chat.autoScrollChat,
 | 
			
		||||
            autoHideChat = it.chat.autoHideChat,
 | 
			
		||||
        )
 | 
			
		||||
    }.stateIn(
 | 
			
		||||
        scope = viewModelScope,
 | 
			
		||||
        started = SharingStarted.Eagerly,
 | 
			
		||||
        initialValue = ChatSettingsUio.default(),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    val messages = combine(
 | 
			
		||||
        settingsRepository.settingsFlow(),
 | 
			
		||||
        networkRepository.data.runningFold(
 | 
			
		||||
            initial = mutableListOf(),
 | 
			
		||||
            operation = List<SocketMessage>::plus
 | 
			
		||||
        )
 | 
			
		||||
    ) { settings, messages ->
 | 
			
		||||
        messages.mapNotNull { message ->
 | 
			
		||||
            textMessageFactory.convertToTextMessage(
 | 
			
		||||
                settings = settings,
 | 
			
		||||
                message = message,
 | 
			
		||||
            )
 | 
			
		||||
        }.takeLast(
 | 
			
		||||
            n = settings.chat.maxLineCount,
 | 
			
		||||
        )
 | 
			
		||||
    }.stateIn(
 | 
			
		||||
        scope = viewModelScope,
 | 
			
		||||
        started = SharingStarted.Eagerly,
 | 
			
		||||
        initialValue = emptyList(),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    suspend fun displayChat() {
 | 
			
		||||
        chatAnimatedVisibility.animateTo(
 | 
			
		||||
| 
						 | 
				
			
			@ -48,11 +62,12 @@ class CampaignChatViewModel(
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    suspend fun hideChat() {
 | 
			
		||||
        val settings = settingsRepository.settingsFlow().value
 | 
			
		||||
        chatAnimatedVisibility.animateTo(
 | 
			
		||||
            targetValue = 0f,
 | 
			
		||||
            animationSpec = tween(
 | 
			
		||||
                durationMillis = 2000,
 | 
			
		||||
                delayMillis = settings.value.autoHideDelay * 1000,
 | 
			
		||||
                delayMillis = settings.chat.autoHideDelay * 1000,
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,11 @@
 | 
			
		|||
package com.pixelized.desktop.lwa.ui.screen.campaign.text
 | 
			
		||||
 | 
			
		||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
 | 
			
		||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
 | 
			
		||||
import com.pixelized.desktop.lwa.repository.settings.model.Settings
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.CharacteristicTextMessageUio
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.DiminishedTextMessageUio
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessageUio
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.TextMessage
 | 
			
		||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
 | 
			
		||||
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.CampaignMessage
 | 
			
		||||
| 
						 | 
				
			
			@ -26,13 +25,12 @@ import kotlin.math.abs
 | 
			
		|||
 | 
			
		||||
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")
 | 
			
		||||
 | 
			
		||||
    suspend fun convertToTextMessage(
 | 
			
		||||
        settings: Settings,
 | 
			
		||||
        message: SocketMessage,
 | 
			
		||||
    ): TextMessage? {
 | 
			
		||||
        val time = message.timestamp
 | 
			
		||||
| 
						 | 
				
			
			@ -44,6 +42,8 @@ class TextMessageFactory(
 | 
			
		|||
                    .characterPreview(characterId = message.characterSheetId)
 | 
			
		||||
                    ?: return null
 | 
			
		||||
 | 
			
		||||
                val isGm = settings.isGameMaster ?: false
 | 
			
		||||
 | 
			
		||||
                RollTextMessageUio(
 | 
			
		||||
                    id = "${message.uuid}-${message.timestamp}",
 | 
			
		||||
                    timestamp = formatTime.format(time),
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ class TextMessageFactory(
 | 
			
		|||
                    skillLabel = message.skillLabel,
 | 
			
		||||
                    rollDifficulty = message.rollDifficulty,
 | 
			
		||||
                    rollValue = message.rollValue,
 | 
			
		||||
                    rollSuccessLimit = message.rollSuccessLimit,
 | 
			
		||||
                    rollSuccessLimit = takeIf { isGm }?.let { message.rollSuccessLimit },
 | 
			
		||||
                    resultLabel = message.resultLabel,
 | 
			
		||||
                    resultType = when (message.critical) {
 | 
			
		||||
                        RollMessage.Critical.CRITICAL_SUCCESS -> RollTextMessageUio.Critical.CRITICAL_SUCCESS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ 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.font.FontWeight
 | 
			
		||||
import androidx.compose.ui.text.style.TextOverflow
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.theme.lwa
 | 
			
		||||
| 
						 | 
				
			
			@ -72,7 +71,6 @@ fun RollTextMessage(
 | 
			
		|||
        Text(
 | 
			
		||||
            modifier = Modifier.alignByBaseline(),
 | 
			
		||||
            style = MaterialTheme.lwa.typography.chat.text,
 | 
			
		||||
            fontWeight = FontWeight.ExtraLight,
 | 
			
		||||
            overflow = TextOverflow.Ellipsis,
 | 
			
		||||
            maxLines = 1,
 | 
			
		||||
            text = stringResource(Res.string.roll_history__item__throw),
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +112,7 @@ fun RollTextMessage(
 | 
			
		|||
                style = MaterialTheme.lwa.typography.chat.text,
 | 
			
		||||
                overflow = TextOverflow.Ellipsis,
 | 
			
		||||
                maxLines = 1,
 | 
			
		||||
                text = "${message.rollValue}",
 | 
			
		||||
                text = "(${message.rollValue}",
 | 
			
		||||
            )
 | 
			
		||||
            message.rollSuccessLimit?.let {
 | 
			
		||||
                Text(
 | 
			
		||||
| 
						 | 
				
			
			@ -125,6 +123,13 @@ fun RollTextMessage(
 | 
			
		|||
                    text = "/$it",
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            Text(
 | 
			
		||||
                modifier = Modifier.alignByBaseline(),
 | 
			
		||||
                style = MaterialTheme.lwa.typography.chat.text,
 | 
			
		||||
                overflow = TextOverflow.Ellipsis,
 | 
			
		||||
                maxLines = 1,
 | 
			
		||||
                text = ")",
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        message.rollDifficulty?.let {
 | 
			
		||||
            Text(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,7 @@ import com.pixelized.desktop.lwa.usecase.SettingsUseCase
 | 
			
		|||
import kotlinx.coroutines.launch
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.Res
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.ic_fan_focus_24dp
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.ic_format_list_numbered_24dp
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.ic_ifl_24dp
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.ic_timer_24dp
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.ic_visibility_24dp
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +29,8 @@ import lwacharactersheet.composeapp.generated.resources.settings__chat_log__sect
 | 
			
		|||
import lwacharactersheet.composeapp.generated.resources.settings__player_portrait__dyn_dice_description
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.settings__player_portrait__dyn_dice_tile
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.settings__player_portrait__section
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.settings__chat_log__line_count_title
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.settings__chat_log__line_count_description
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class SettingsViewModel(
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +51,11 @@ class SettingsViewModel(
 | 
			
		|||
            description = Res.string.settings__player_portrait__dyn_dice_description,
 | 
			
		||||
            checked = booleanStates.dynamicDice,
 | 
			
		||||
            onToggle = {
 | 
			
		||||
                settingsRepository.update(settings = settings.value.copy(dynamicDice = it))
 | 
			
		||||
                settingsRepository.update(
 | 
			
		||||
                    settings = settings.value.copy(
 | 
			
		||||
                        portrait = settings.value.portrait.copy(dynamicDice = it)
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        SettingSectionUio(
 | 
			
		||||
| 
						 | 
				
			
			@ -60,7 +67,11 @@ class SettingsViewModel(
 | 
			
		|||
            description = Res.string.settings__chat_log__auto_show_description,
 | 
			
		||||
            checked = booleanStates.autoShowChat,
 | 
			
		||||
            onToggle = {
 | 
			
		||||
                settingsRepository.update(settings = settings.value.copy(autoShowChat = it))
 | 
			
		||||
                settingsRepository.update(
 | 
			
		||||
                    settings = settings.value.copy(
 | 
			
		||||
                        chat = settings.value.chat.copy(autoShowChat = it)
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        SettingToggleItemUio(
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +80,11 @@ class SettingsViewModel(
 | 
			
		|||
            description = Res.string.settings__chat_log__auto_hide_description,
 | 
			
		||||
            checked = booleanStates.autoHideChat,
 | 
			
		||||
            onToggle = {
 | 
			
		||||
                settingsRepository.update(settings = settings.value.copy(autoHideChat = it))
 | 
			
		||||
                settingsRepository.update(
 | 
			
		||||
                    settings = settings.value.copy(
 | 
			
		||||
                        chat = settings.value.chat.copy(autoHideChat = it)
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        SettingNumberItemUio(
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +95,11 @@ class SettingsViewModel(
 | 
			
		|||
            value = intStates.autoHideDelay,
 | 
			
		||||
            onValueChange = {
 | 
			
		||||
                if (it in 0..999) {
 | 
			
		||||
                    settingsRepository.update(settings = settings.value.copy(autoHideDelay = it))
 | 
			
		||||
                    settingsRepository.update(
 | 
			
		||||
                        settings = settings.value.copy(
 | 
			
		||||
                            chat = settings.value.chat.copy(autoHideDelay = it)
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ),
 | 
			
		||||
| 
						 | 
				
			
			@ -90,19 +109,40 @@ class SettingsViewModel(
 | 
			
		|||
            description = Res.string.settings__chat_log__auto_scroll_description,
 | 
			
		||||
            checked = booleanStates.autoScrollChat,
 | 
			
		||||
            onToggle = {
 | 
			
		||||
                settingsRepository.update(settings = settings.value.copy(autoScrollChat = it))
 | 
			
		||||
                settingsRepository.update(
 | 
			
		||||
                    settings = settings.value.copy(
 | 
			
		||||
                        chat = settings.value.chat.copy(autoScrollChat = it)
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        SettingNumberItemUio(
 | 
			
		||||
            icon = Res.drawable.ic_format_list_numbered_24dp,
 | 
			
		||||
            title = Res.string.settings__chat_log__line_count_title,
 | 
			
		||||
            description = Res.string.settings__chat_log__line_count_description,
 | 
			
		||||
            enable = mutableStateOf(true),
 | 
			
		||||
            value = intStates.maxLineCount,
 | 
			
		||||
            onValueChange = {
 | 
			
		||||
                if (it in 0..999) {
 | 
			
		||||
                    settingsRepository.update(
 | 
			
		||||
                        settings = settings.value.copy(
 | 
			
		||||
                            chat = settings.value.chat.copy(maxLineCount = it)
 | 
			
		||||
                        )
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        viewModelScope.launch {
 | 
			
		||||
            settingsRepository.settingsFlow().collect { settings ->
 | 
			
		||||
                booleanStates.dynamicDice.value = settings.dynamicDice
 | 
			
		||||
                booleanStates.autoShowChat.value = settings.autoShowChat
 | 
			
		||||
                booleanStates.autoHideChat.value = settings.autoHideChat
 | 
			
		||||
                intStates.autoHideDelay.value = settings.autoHideDelay
 | 
			
		||||
                booleanStates.autoScrollChat.value = settings.autoScrollChat
 | 
			
		||||
                booleanStates.dynamicDice.value = settings.portrait.dynamicDice
 | 
			
		||||
                booleanStates.autoShowChat.value = settings.chat.autoShowChat
 | 
			
		||||
                booleanStates.autoHideChat.value = settings.chat.autoHideChat
 | 
			
		||||
                intStates.autoHideDelay.value = settings.chat.autoHideDelay
 | 
			
		||||
                booleanStates.autoScrollChat.value = settings.chat.autoScrollChat
 | 
			
		||||
                intStates.maxLineCount.value = settings.chat.maxLineCount
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -120,17 +160,20 @@ class SettingsViewModel(
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    private val HashMap<String, MutableState<Boolean>>.dynamicDice
 | 
			
		||||
        get() = getOrPut("DYNAMIC_DICE") { mutableStateOf(settings.value.dynamicDice) }
 | 
			
		||||
        get() = getOrPut("DYNAMIC_DICE") { mutableStateOf(settings.value.portrait.dynamicDice) }
 | 
			
		||||
 | 
			
		||||
    private val HashMap<String, MutableState<Boolean>>.autoShowChat
 | 
			
		||||
        get() = getOrPut("AUTO_SHOW_CHAT") { mutableStateOf(settings.value.autoShowChat) }
 | 
			
		||||
        get() = getOrPut("AUTO_SHOW_CHAT") { mutableStateOf(settings.value.chat.autoShowChat) }
 | 
			
		||||
 | 
			
		||||
    private val HashMap<String, MutableState<Boolean>>.autoHideChat
 | 
			
		||||
        get() = getOrPut("AUTO_HIDE_CHAT") { mutableStateOf(settings.value.autoHideChat) }
 | 
			
		||||
        get() = getOrPut("AUTO_HIDE_CHAT") { mutableStateOf(settings.value.chat.autoHideChat) }
 | 
			
		||||
 | 
			
		||||
    private val HashMap<String, MutableState<Int>>.autoHideDelay
 | 
			
		||||
        get() = getOrPut("AUTO_HIDE_DELAY") { mutableStateOf(settings.value.autoHideDelay) }
 | 
			
		||||
        get() = getOrPut("AUTO_HIDE_DELAY") { mutableStateOf(settings.value.chat.autoHideDelay) }
 | 
			
		||||
 | 
			
		||||
    private val HashMap<String, MutableState<Boolean>>.autoScrollChat
 | 
			
		||||
        get() = getOrPut("AUTO_SCROLL_CHAT") { mutableStateOf(settings.value.autoScrollChat) }
 | 
			
		||||
        get() = getOrPut("AUTO_SCROLL_CHAT") { mutableStateOf(settings.value.chat.autoScrollChat) }
 | 
			
		||||
 | 
			
		||||
    private val HashMap<String, MutableState<Int>>.maxLineCount
 | 
			
		||||
        get() = getOrPut("MAX_LINE_COUNT") { mutableStateOf(settings.value.chat.maxLineCount) }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,14 +5,21 @@ import com.pixelized.desktop.lwa.repository.settings.model.Settings
 | 
			
		|||
class SettingsUseCase {
 | 
			
		||||
 | 
			
		||||
    fun defaultSettings(): Settings = Settings(
 | 
			
		||||
        host = DEFAULT_HOST,
 | 
			
		||||
        port = DEFAULT_PORT,
 | 
			
		||||
        playerName = "",
 | 
			
		||||
        dynamicDice = true,
 | 
			
		||||
        autoHideChat = true,
 | 
			
		||||
        autoHideDelay = 8,
 | 
			
		||||
        autoShowChat = true,
 | 
			
		||||
        autoScrollChat = true,
 | 
			
		||||
        portrait = Settings.Portrait(
 | 
			
		||||
            dynamicDice = true
 | 
			
		||||
        ),
 | 
			
		||||
        chat = Settings.Chat(
 | 
			
		||||
            autoHideChat = true,
 | 
			
		||||
            autoHideDelay = 8,
 | 
			
		||||
            autoShowChat = true,
 | 
			
		||||
            autoScrollChat = true,
 | 
			
		||||
            maxLineCount = 200,
 | 
			
		||||
        ),
 | 
			
		||||
        network = Settings.Network(
 | 
			
		||||
            host = DEFAULT_HOST,
 | 
			
		||||
            port = DEFAULT_PORT,
 | 
			
		||||
        ),
 | 
			
		||||
        isAdmin = null,
 | 
			
		||||
        isGameMaster = null,
 | 
			
		||||
    )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue