diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_fan_focus_24dp.xml b/composeApp/src/commonMain/composeResources/drawable/ic_fan_focus_24dp.xml new file mode 100644 index 0000000..7ae04e6 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/ic_fan_focus_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_ifl_24dp.xml b/composeApp/src/commonMain/composeResources/drawable/ic_ifl_24dp.xml new file mode 100644 index 0000000..d91598a --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/ic_ifl_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_timer_24dp.xml b/composeApp/src/commonMain/composeResources/drawable/ic_timer_24dp.xml new file mode 100644 index 0000000..793edb2 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/ic_timer_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_visibility_24dp.xml b/composeApp/src/commonMain/composeResources/drawable/ic_visibility_24dp.xml new file mode 100644 index 0000000..c22b6d7 --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/ic_visibility_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_visibility_off_24dp.xml b/composeApp/src/commonMain/composeResources/drawable/ic_visibility_off_24dp.xml new file mode 100644 index 0000000..b758ece --- /dev/null +++ b/composeApp/src/commonMain/composeResources/drawable/ic_visibility_off_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index 1c3b949..352544a 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -158,8 +158,24 @@ lance Difficulté - %1$s passe à %2$d d\'état diminuée + %1$s passe à %2$d d'état diminuée %1$s passe à %2$d %3$s Hp Pp + + Paramètres de l'application + Paramètres par défault + Portrait joueur + Dés dynamiques + Affiche un dé à côté du portrait d'un personnage lorsqu'un jet est fait par ce dernier. + Chatlog options + Afficher automatiquement le chat + Affiche automatiquement le chat lors de la réception d'un message + Cacher automatiquement le chat + Cache automatiquement le chat au bout d'un certain temps + Délai pour cacher le chat + Délai après lequel le chat disparaît + Défilement automatique + Défilement automatique du chat vers le dernier message reçu lors de la réception de ce dernier. + \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt index b5a5916..9c8c92b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt @@ -18,6 +18,7 @@ class SettingsFactory( playerName = settings.playerName, dynamicDice = settings.dynamicDice, autoHideChat = settings.autoHideChat, + autoHideDelay = settings.autoHideDelay, autoShowChat = settings.autoShowChat, autoScrollChat = settings.autoScrollChat, ) @@ -41,6 +42,7 @@ class SettingsFactory( 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, ) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt index 7af6816..2693887 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/Settings.kt @@ -6,6 +6,7 @@ data class Settings( val playerName: String, val dynamicDice: Boolean, val autoHideChat: Boolean, + val autoHideDelay: Int, val autoShowChat: Boolean, val autoScrollChat: Boolean, ) { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt index bbc4f26..b83937e 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/model/SettingsJsonV1.kt @@ -9,6 +9,7 @@ data class SettingsJsonV1( val playerName: String?, val dynamicDice: Boolean?, val autoHideChat: Boolean?, + val autoHideDelay: Int?, val autoShowChat: Boolean?, val autoScrollChat: Boolean?, ) : SettingsJson \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt index 8c8e72e..43267e2 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chat/CampaignChatViewModel.kt @@ -42,10 +42,18 @@ class CampaignChatViewModel( ) suspend fun displayChat() { - chatAnimatedVisibility.animateTo(1f) + chatAnimatedVisibility.animateTo( + targetValue = 1f, + ) } suspend fun hideChat() { - chatAnimatedVisibility.animateTo(0f, animationSpec = tween(2000, delayMillis = 8000)) + chatAnimatedVisibility.animateTo( + targetValue = 0f, + animationSpec = tween( + durationMillis = 2000, + delayMillis = settings.value.autoHideDelay * 1000, + ) + ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt index 964c95d..77705cf 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt @@ -12,6 +12,7 @@ import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository +import com.pixelized.desktop.lwa.repository.settings.SettingsRepository import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -24,6 +25,7 @@ import java.text.Collator class PlayerRibbonViewModel( private val rollHistoryRepository: RollHistoryRepository, + private val settingsRepository: SettingsRepository, characterRepository: CharacterSheetRepository, alterationRepository: AlterationRepository, private val ribbonFactory: PlayerRibbonFactory, @@ -68,12 +70,14 @@ class PlayerRibbonViewModel( val state = rolls.getOrPut(characterSheetId) { mutableStateOf(null) } LaunchedEffect(characterSheetId) { rollHistoryRepository.rolls.collect { roll -> - if (roll.characterId == characterSheetId) { - state.value = PlayerPortraitRollUio( - characterId = characterSheetId, - value = roll.rollValue, - label = roll.resultLabel?.split(" ")?.joinToString(separator = "\n") { it } - ) + if (settingsRepository.settings().dynamicDice) { + if (roll.characterId == characterSheetId) { + state.value = PlayerPortraitRollUio( + characterId = characterSheetId, + value = roll.rollValue, + label = roll.resultLabel?.split(" ")?.joinToString(separator = "\n") { it } + ) + } } } } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt index 0391b5b..a41d28a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsScreen.kt @@ -3,6 +3,7 @@ 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.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState @@ -12,21 +13,38 @@ import androidx.compose.material.IconButton import androidx.compose.material.Scaffold import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.TextButton import androidx.compose.material.TopAppBar import androidx.compose.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.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.type import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController +import com.pixelized.desktop.lwa.ui.navigation.screen.destination.SettingsDestination import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingItemUio +import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingNumberItem +import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingNumberItemUio 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 lwacharactersheet.composeapp.generated.resources.Res +import lwacharactersheet.composeapp.generated.resources.settings__reset_action +import lwacharactersheet.composeapp.generated.resources.settings__title +import org.jetbrains.compose.resources.stringResource import org.koin.compose.viewmodel.koinViewModel +object SettingsScreenDefault { + val margin: PaddingValues = PaddingValues(horizontal = 16.dp) + val padding: PaddingValues = PaddingValues(start = 16.dp, top = 8.dp, end = 8.dp, bottom = 8.dp) +} @Composable fun SettingsScreen( @@ -34,13 +52,25 @@ fun SettingsScreen( ) { val screen = LocalScreenController.current + KeyHandler { + when { + it.type == KeyEventType.KeyUp && it.key == Key.Escape -> { + screen.popBackStack(route = SettingsDestination.baseRoute(), inclusive = true) + true + } + + else -> false + } + } + Surface { SettingsContent( modifier = Modifier.fillMaxSize(), items = viewModel.items, onBack = { - screen.popBackStack() + screen.popBackStack(route = SettingsDestination.baseRoute(), inclusive = true) }, + onReset = viewModel::onReset ) } } @@ -52,13 +82,14 @@ private fun SettingsContent( spacing: Dp = 8.dp, items: List, onBack: () -> Unit, + onReset: () -> Unit, ) { Scaffold( modifier = modifier, topBar = { TopAppBar( title = { - Text(text = "Paramètres de l\'application") + Text(text = stringResource(Res.string.settings__title)) }, navigationIcon = { IconButton( @@ -69,7 +100,14 @@ private fun SettingsContent( contentDescription = null, ) } - } + }, + actions = { + TextButton( + onClick = onReset, + ) { + Text(text = stringResource(Res.string.settings__reset_action)) + } + }, ) }, content = { paddingValues -> @@ -81,17 +119,12 @@ private fun SettingsContent( ) { items.forEach { when (it) { - is SettingSectionUio -> { - SettingSection(item = it) - } - - is SettingToggleItemUio -> { - SettingToggleItem(item = it) - } + is SettingSectionUio -> SettingSection(item = it) + is SettingToggleItemUio -> SettingToggleItem(item = it) + is SettingNumberItemUio -> SettingNumberItem(item = it) } } } } ) -} - +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt index 2f728b3..56b3926 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt @@ -5,51 +5,90 @@ 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.SettingNumberItemUio import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingSectionUio import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingToggleItemUio +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_ifl_24dp +import lwacharactersheet.composeapp.generated.resources.ic_timer_24dp +import lwacharactersheet.composeapp.generated.resources.ic_visibility_24dp +import lwacharactersheet.composeapp.generated.resources.ic_visibility_off_24dp +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_hide_delay_description +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_hide_delay_title +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_hide_description +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_hide_title +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_scroll_description +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_scroll_title +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_show_description +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__auto_show_title +import lwacharactersheet.composeapp.generated.resources.settings__chat_log__section +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 + class SettingsViewModel( private val settingsRepository: SettingsRepository, + private val settingsUseCase: SettingsUseCase, ) : ViewModel() { private val settings = settingsRepository.settingsFlow() - private val states = hashMapOf>() + private val booleanStates = hashMapOf>() + private val intStates = hashMapOf>() val items = listOf( SettingSectionUio( - title = "Portrait joueurs." + title = Res.string.settings__player_portrait__section, ), 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, + icon = Res.drawable.ic_ifl_24dp, + title = Res.string.settings__player_portrait__dyn_dice_tile, + description = Res.string.settings__player_portrait__dyn_dice_description, + checked = booleanStates.dynamicDice, onToggle = { settingsRepository.update(settings = settings.value.copy(dynamicDice = it)) }, ), SettingSectionUio( - title = "Chatlog options." + title = Res.string.settings__chat_log__section, ), SettingToggleItemUio( - title = "Afficher automatiquement", - description = "Affiche automatiquement le chat lors de la réception d'un message.", - checked = states.autoShowChat, + icon = Res.drawable.ic_visibility_24dp, + title = Res.string.settings__chat_log__auto_show_title, + description = Res.string.settings__chat_log__auto_show_description, + checked = booleanStates.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, + icon = Res.drawable.ic_visibility_off_24dp, + title = Res.string.settings__chat_log__auto_hide_title, + description = Res.string.settings__chat_log__auto_hide_description, + checked = booleanStates.autoHideChat, onToggle = { settingsRepository.update(settings = settings.value.copy(autoHideChat = it)) }, ), + SettingNumberItemUio( + icon = Res.drawable.ic_timer_24dp, + title = Res.string.settings__chat_log__auto_hide_delay_title, + description = Res.string.settings__chat_log__auto_hide_delay_description, + enable = booleanStates.autoHideChat, + value = intStates.autoHideDelay, + onValueChange = { + if (it in 0..999) { + settingsRepository.update(settings = settings.value.copy(autoHideDelay = 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, + icon = Res.drawable.ic_fan_focus_24dp, + title = Res.string.settings__chat_log__auto_scroll_title, + description = Res.string.settings__chat_log__auto_scroll_description, + checked = booleanStates.autoScrollChat, onToggle = { settingsRepository.update(settings = settings.value.copy(autoScrollChat = it)) }, @@ -59,14 +98,19 @@ class SettingsViewModel( 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 + 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 } } } + fun onReset() { + settingsRepository.update(settings = settingsUseCase.defaultSettings()) + } + private val HashMap>.dynamicDice get() = getOrPut("DYNAMIC_DICE") { mutableStateOf(settings.value.dynamicDice) } @@ -76,6 +120,9 @@ class SettingsViewModel( private val HashMap>.autoHideChat get() = getOrPut("AUTO_HIDE_CHAT") { mutableStateOf(settings.value.autoHideChat) } + private val HashMap>.autoHideDelay + get() = getOrPut("AUTO_HIDE_DELAY") { mutableStateOf(settings.value.autoHideDelay) } + private val HashMap>.autoScrollChat get() = getOrPut("AUTO_SCROLL_CHAT") { mutableStateOf(settings.value.autoScrollChat) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingNumberItem.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingNumberItem.kt new file mode 100644 index 0000000..dbbd591 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingNumberItem.kt @@ -0,0 +1,138 @@ +package com.pixelized.desktop.lwa.ui.screen.settings.composable + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Icon +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.onFocusChanged +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.screen.settings.SettingsScreenDefault +import com.pixelized.desktop.lwa.ui.theme.lwa +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource + +@Stable +data class SettingNumberItemUio( + val icon: DrawableResource, + val title: StringResource, + val description: StringResource, + val enable: State, + val value: State, + val onValueChange: (Int) -> Unit, +) : SettingItemUio + +@Composable +fun SettingNumberItem( + modifier: Modifier = Modifier, + margin: PaddingValues = SettingsScreenDefault.margin, + padding: PaddingValues = SettingsScreenDefault.padding, + spacing: DpSize = DpSize(width = 16.dp, height = 8.dp), + item: SettingNumberItemUio, +) { + val colorScheme = MaterialTheme.lwa.colorScheme + + Surface( + modifier = modifier.padding(paddingValues = margin), + shape = MaterialTheme.lwa.shapes.settings, + elevation = 1.dp, + ) { + Row( + modifier = Modifier.padding(paddingValues = padding), + horizontalArrangement = Arrangement.spacedBy(space = spacing.width), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + modifier = Modifier.size(size = 24.dp), + painter = painterResource(item.icon), + contentDescription = null, + ) + + Column( + modifier = Modifier.weight(weight = 1f), + verticalArrangement = Arrangement.spacedBy(space = spacing.height), + ) { + Text( + style = MaterialTheme.lwa.typography.settings.title, + maxLines = 1, + text = stringResource(resource = item.title), + ) + Text( + style = MaterialTheme.lwa.typography.settings.description, + fontStyle = FontStyle.Italic, + text = stringResource(resource = item.description), + ) + } + + Column( + modifier = Modifier.padding(end = 8.dp), + verticalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + val focused = remember { + mutableStateOf(false) + } + val textColor = remember(item) { + derivedStateOf { + when (item.enable.value) { + true -> colorScheme.base.primary + else -> colorScheme.base.onSurface.copy(alpha = 0.3f) + } + } + } + val borderColor = remember(item, focused) { + derivedStateOf { + when (focused.value) { + true -> colorScheme.base.primary + else -> colorScheme.base.onSurface.copy(alpha = 0.3f) + } + } + } + BasicTextField( + modifier = Modifier + .onFocusChanged { focused.value = it.isFocused } + .width(width = 44.dp) + .padding(horizontal = 2.dp), + textStyle = MaterialTheme.lwa.typography.settings.input.copy( + color = textColor.value, + ), + cursorBrush = SolidColor(MaterialTheme.colors.primary), + keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done), + singleLine = true, + enabled = item.enable.value, + value = "${item.value.value}", + onValueChange = { item.onValueChange(it.toIntOrNull() ?: 0) }, + ) + Box( + modifier = Modifier + .background(color = borderColor.value) + .size(width = 48.dp, height = 2.dp), + ) + } + } + } + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt index 6086799..c02674b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingSection.kt @@ -8,23 +8,26 @@ 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.screen.settings.SettingsScreenDefault import com.pixelized.desktop.lwa.ui.theme.lwa +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.stringResource @Stable data class SettingSectionUio( - val title: String, + val title: StringResource, ) : SettingItemUio @Composable fun SettingSection( modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues(start = 16.dp, top = 32.dp, end = 16.dp), + padding: PaddingValues = PaddingValues(start = 16.dp, top = 32.dp, end = 16.dp, bottom = 16.dp), item: SettingSectionUio, ) { Text( modifier = modifier.padding(paddingValues = padding), - style = MaterialTheme.lwa.typography.base.h6, + style = MaterialTheme.lwa.typography.settings.section, maxLines = 1, - text = item.title, + text = stringResource(resource = item.title), ) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt index 514415e..a760175 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/composable/SettingToggleItem.kt @@ -5,23 +5,34 @@ 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.foundation.layout.size +import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface 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.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.text.font.FontStyle -import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.screen.settings.SettingsScreenDefault import com.pixelized.desktop.lwa.ui.theme.lwa +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource @Stable data class SettingToggleItemUio( - val title: String, - val description: String, + val icon: DrawableResource, + val title: StringResource, + val description: StringResource, val checked: State, val onToggle: (Boolean) -> Unit, ) : SettingItemUio @@ -29,36 +40,49 @@ data class SettingToggleItemUio( @Composable fun SettingToggleItem( modifier: Modifier = Modifier, - padding: PaddingValues = PaddingValues(start = 16.dp, top = 8.dp, end = 16.dp), - spacing: Dp = 8.dp, + margin: PaddingValues = SettingsScreenDefault.margin, + padding: PaddingValues = SettingsScreenDefault.padding, + spacing: DpSize = DpSize(width = 16.dp, height = 8.dp), item: SettingToggleItemUio, ) { - Row( - modifier = modifier.padding(paddingValues = padding), - horizontalArrangement = Arrangement.spacedBy(space = spacing), + Surface( + modifier = modifier.padding(paddingValues = margin), + shape = MaterialTheme.lwa.shapes.settings, + elevation = 1.dp, ) { - Column( - modifier = Modifier.weight(weight = 1f), - verticalArrangement = Arrangement.spacedBy(space = spacing), + Row( + modifier = Modifier.padding(paddingValues = padding), + horizontalArrangement = Arrangement.spacedBy(space = spacing.width), + verticalAlignment = Alignment.CenterVertically, ) { - Text( - style = MaterialTheme.lwa.typography.base.body1, - maxLines = 1, - text = item.title, + Icon( + modifier = Modifier.size(size = 24.dp), + painter = painterResource(item.icon), + contentDescription = null, ) - Text( - style = MaterialTheme.lwa.typography.base.caption, - fontStyle = FontStyle.Italic, - text = item.description, + Column( + modifier = Modifier.weight(weight = 1f), + verticalArrangement = Arrangement.spacedBy(space = spacing.height), + ) { + Text( + style = MaterialTheme.lwa.typography.settings.title, + maxLines = 1, + text = stringResource(resource = item.title), + ) + Text( + style = MaterialTheme.lwa.typography.settings.description, + fontStyle = FontStyle.Italic, + text = stringResource(resource = item.description), + ) + } + + Switch( + colors = SwitchDefaults.colors( + checkedThumbColor = MaterialTheme.lwa.colorScheme.base.primary, + ), + onCheckedChange = item.onToggle, + checked = item.checked.value ) } - - Switch( - colors = SwitchDefaults.colors( - checkedThumbColor = MaterialTheme.lwa.colorScheme.base.primary, - ), - onCheckedChange = item.onToggle, - checked = item.checked.value - ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt index 73ca61e..97ef035 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/LwaTheme.kt @@ -8,6 +8,8 @@ import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.remember import com.pixelized.desktop.lwa.ui.theme.color.LwaColors import com.pixelized.desktop.lwa.ui.theme.color.darkLwaColorTheme +import com.pixelized.desktop.lwa.ui.theme.shapes.LwaShapes +import com.pixelized.desktop.lwa.ui.theme.shapes.lwaShapes import com.pixelized.desktop.lwa.ui.theme.typography.LwaTypography import com.pixelized.desktop.lwa.ui.theme.typography.lwaTypography @@ -24,6 +26,7 @@ val MaterialTheme.lwa: LwaTheme data class LwaTheme( val colorScheme: LwaColors, val typography: LwaTypography, + val shapes: LwaShapes, ) @Composable @@ -32,11 +35,13 @@ fun LwaTheme( ) { val lwaColors = darkLwaColorTheme() val lwaTypography = lwaTypography(colors = lwaColors) + val lwaShapes = lwaShapes() val theme = remember { LwaTheme( colorScheme = lwaColors, typography = lwaTypography, + shapes = lwaShapes, ) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt new file mode 100644 index 0000000..a139ba1 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/shapes/LwaShapes.kt @@ -0,0 +1,23 @@ +package com.pixelized.desktop.lwa.ui.theme.shapes + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.unit.dp + +@Stable +data class LwaShapes( + val settings: Shape, +) + +@Stable +@Composable +fun lwaShapes( + settings: Shape = RoundedCornerShape(8.dp), +): LwaShapes = remember { + LwaShapes( + settings = settings, + ) +} diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/typography/LwaTypography.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/typography/LwaTypography.kt index affabe4..a550f0f 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/typography/LwaTypography.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/typography/LwaTypography.kt @@ -6,9 +6,12 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.sp import com.pixelized.desktop.lwa.ui.theme.color.LwaColors +import com.pixelized.desktop.lwa.ui.theme.typography.LwaTypography.Settings import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.consola_mono_bold import lwacharactersheet.composeapp.generated.resources.consola_mono_book @@ -18,12 +21,21 @@ import org.jetbrains.compose.resources.Font data class LwaTypography( val base: Typography, val chat: Chat, + val settings: Settings, ) { @Stable data class Chat( val timestamp: TextStyle, val text: TextStyle, ) + + @Stable + data class Settings( + val section: TextStyle, + val title: TextStyle, + val input: TextStyle, + val description: TextStyle, + ) } @Composable @@ -62,6 +74,22 @@ fun lwaTypography( letterSpacing = 0.4.sp, color = colors.chat.text, ), + ), + settings = Settings( + section = base.h6, + title = base.body1.copy( + fontWeight = FontWeight.SemiBold, + ), + input = base.body1.copy( + fontWeight = FontWeight.SemiBold, + fontSize = 18.sp, + lineHeight = 26.sp, + textAlign = TextAlign.End, + ), + description = base.caption.copy( + fontStyle = FontStyle.Italic, + color = colors.base.onSurface.copy(alpha = 0.7f), + ), ) ) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt index df53702..7d46183 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt @@ -10,6 +10,7 @@ class SettingsUseCase { playerName = "", dynamicDice = true, autoHideChat = true, + autoHideDelay = 8, autoShowChat = true, autoScrollChat = true, )