Add filter chip to the gamemaster character screen.
This commit is contained in:
parent
a59444c610
commit
662e270f3f
6 changed files with 196 additions and 75 deletions
|
|
@ -178,10 +178,10 @@
|
||||||
<string name="level_up__skill_level">niv : %1$d -</string>
|
<string name="level_up__skill_level">niv : %1$d -</string>
|
||||||
|
|
||||||
<string name="game_master__character_level__label">niv: %1$d</string>
|
<string name="game_master__character_level__label">niv: %1$d</string>
|
||||||
<string name="game_master__character_tag__character_search">joueur</string>
|
<string name="game_master__character_tag__character_search">Joueur</string>
|
||||||
<string name="game_master__character_tag__character_label">joueur: %1$d</string>
|
<string name="game_master__character_tag__character_label">Joueur-%1$d</string>
|
||||||
<string name="game_master__character_tag__npc_search">npc</string>
|
<string name="game_master__character_tag__npc_search">Npc</string>
|
||||||
<string name="game_master__character_tag__npc_label">npc: %1$d</string>
|
<string name="game_master__character_tag__npc_label">Npc-%1$d</string>
|
||||||
<string name="game_master__character_action__display_portrait">Afficher le portrait</string>
|
<string name="game_master__character_action__display_portrait">Afficher le portrait</string>
|
||||||
<string name="game_master__character_action__add_to_group">Ajouter au groupe</string>
|
<string name="game_master__character_action__add_to_group">Ajouter au groupe</string>
|
||||||
<string name="game_master__character_action__remove_from_group">Retirer du groupe (id: %1$d)</string>
|
<string name="game_master__character_action__remove_from_group">Retirer du groupe (id: %1$d)</string>
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,11 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster
|
||||||
import com.pixelized.desktop.lwa.repository.campaign.model.CharacterSheetPreview
|
import com.pixelized.desktop.lwa.repository.campaign.model.CharacterSheetPreview
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio.Action
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio.Action
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio
|
||||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_label
|
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_label
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_search
|
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_label
|
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_label
|
||||||
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_search
|
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
import java.text.Normalizer
|
import java.text.Normalizer
|
||||||
|
|
||||||
|
|
@ -18,6 +17,7 @@ class GameMasterFactory {
|
||||||
campaign: Campaign,
|
campaign: Campaign,
|
||||||
characters: List<CharacterSheetPreview>,
|
characters: List<CharacterSheetPreview>,
|
||||||
filter: String,
|
filter: String,
|
||||||
|
tags: Map<GMTagUio.TagId, Boolean>,
|
||||||
): List<GMCharacterPreviewUio> {
|
): List<GMCharacterPreviewUio> {
|
||||||
val normalizedFilter = Normalizer.normalize(filter, Normalizer.Form.NFD)
|
val normalizedFilter = Normalizer.normalize(filter, Normalizer.Form.NFD)
|
||||||
|
|
||||||
|
|
@ -26,6 +26,7 @@ class GameMasterFactory {
|
||||||
campaign = campaign,
|
campaign = campaign,
|
||||||
character = it,
|
character = it,
|
||||||
filter = normalizedFilter,
|
filter = normalizedFilter,
|
||||||
|
tags = tags,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -34,71 +35,67 @@ class GameMasterFactory {
|
||||||
campaign: Campaign,
|
campaign: Campaign,
|
||||||
character: CharacterSheetPreview,
|
character: CharacterSheetPreview,
|
||||||
filter: String,
|
filter: String,
|
||||||
|
tags: Map<GMTagUio.TagId, Boolean>,
|
||||||
): GMCharacterPreviewUio? {
|
): GMCharacterPreviewUio? {
|
||||||
val characterId = campaign.characters.keys.firstOrNull {
|
// get the characterInstanceId from the player list corresponding to this CharacterSheet if any
|
||||||
it.characterSheetId == character.characterSheetId
|
val characterInstanceId: Campaign.CharacterInstance.Id? =
|
||||||
}
|
campaign.characters.keys.firstOrNull {
|
||||||
|
it.characterSheetId == character.characterSheetId
|
||||||
|
}
|
||||||
|
// get all characterInstanceId from the npcs list corresponding to this CharacterSheet if any
|
||||||
val npcIds = campaign.npcs.keys.filter {
|
val npcIds = campaign.npcs.keys.filter {
|
||||||
it.characterSheetId == character.characterSheetId
|
it.characterSheetId == character.characterSheetId
|
||||||
}
|
}
|
||||||
|
// Filter process : Name.
|
||||||
var playerTagHighlighted = false
|
|
||||||
var npcTagHighlighted = false
|
|
||||||
|
|
||||||
// Filter process.
|
|
||||||
if (filter.isNotEmpty()) {
|
if (filter.isNotEmpty()) {
|
||||||
val normalizedName = Normalizer.normalize(character.name, Normalizer.Form.NFD)
|
val normalizedName = Normalizer.normalize(character.name, Normalizer.Form.NFD)
|
||||||
// If the filter is not empty and the character is not
|
// If the filter is not empty and the character is not
|
||||||
val playerTag = getString(Res.string.game_master__character_tag__character_search)
|
|
||||||
val npcTag = getString(Res.string.game_master__character_tag__npc_search)
|
|
||||||
|
|
||||||
playerTagHighlighted = playerTag.contains(other = filter, ignoreCase = true)
|
|
||||||
if (playerTagHighlighted && characterId == null) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
npcTagHighlighted = npcTag.contains(other = filter, ignoreCase = true)
|
|
||||||
if (npcTagHighlighted && npcIds.isEmpty()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val nameHighlight = normalizedName.contains(other = filter, ignoreCase = true)
|
val nameHighlight = normalizedName.contains(other = filter, ignoreCase = true)
|
||||||
if (nameHighlight.not() && playerTagHighlighted.not() && npcTagHighlighted.not()) {
|
if (nameHighlight.not()) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Tag filter process : Player.
|
||||||
val tags = buildList {
|
if (tags[GMTagUio.TagId.PLAYER] == true && characterInstanceId == null) {
|
||||||
if (characterId != null) {
|
return null
|
||||||
|
}
|
||||||
|
// Tag filter process : Npc.
|
||||||
|
if (tags[GMTagUio.TagId.NPC] == true && npcIds.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
// Build the call tag list.
|
||||||
|
val previewTagsList = buildList {
|
||||||
|
if (characterInstanceId != null) {
|
||||||
add(
|
add(
|
||||||
GMCharacterPreviewUio.Tag(
|
GMTagUio(
|
||||||
|
id = GMTagUio.TagId.PLAYER,
|
||||||
label = getString(
|
label = getString(
|
||||||
Res.string.game_master__character_tag__character_label,
|
Res.string.game_master__character_tag__character_label,
|
||||||
characterId.instanceId,
|
characterInstanceId.instanceId,
|
||||||
),
|
),
|
||||||
highlight = playerTagHighlighted,
|
highlight = tags[GMTagUio.TagId.PLAYER] ?: false,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
addAll(
|
addAll(
|
||||||
npcIds.map { npcId ->
|
npcIds.map { npcId ->
|
||||||
GMCharacterPreviewUio.Tag(
|
GMTagUio(
|
||||||
|
id = GMTagUio.TagId.NPC,
|
||||||
label = getString(
|
label = getString(
|
||||||
Res.string.game_master__character_tag__npc_label,
|
Res.string.game_master__character_tag__npc_label,
|
||||||
npcId.instanceId
|
npcId.instanceId
|
||||||
),
|
),
|
||||||
highlight = npcTagHighlighted,
|
highlight = tags[GMTagUio.TagId.NPC] ?: false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// build the cell action list
|
||||||
val actions = buildList {
|
val actions = buildList {
|
||||||
add(
|
add(
|
||||||
when (characterId) {
|
when (characterInstanceId) {
|
||||||
null -> Action.AddToGroup
|
null -> Action.AddToGroup
|
||||||
else -> Action.RemoveFromGroup(instanceId = characterId.instanceId)
|
else -> Action.RemoveFromGroup(instanceId = characterInstanceId.instanceId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
add(Action.AddToNpc)
|
add(Action.AddToNpc)
|
||||||
|
|
@ -108,11 +105,11 @@ class GameMasterFactory {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// return the cell UIO.
|
||||||
return GMCharacterPreviewUio(
|
return GMCharacterPreviewUio(
|
||||||
characterSheetId = character.characterSheetId,
|
characterSheetId = character.characterSheetId,
|
||||||
name = character.name, level = character.level,
|
name = character.name, level = character.level,
|
||||||
tags = tags,
|
tags = previewTagsList,
|
||||||
actions = actions,
|
actions = actions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
|
import androidx.compose.foundation.gestures.draggable
|
||||||
|
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||||
|
import androidx.compose.foundation.gestures.scrollBy
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
|
@ -10,7 +15,10 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.IconButton
|
import androidx.compose.material.IconButton
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
|
|
@ -21,13 +29,18 @@ import androidx.compose.material.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
|
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
|
||||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreview
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreview
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTag
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio
|
||||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
|
|
@ -38,6 +51,7 @@ fun GameMasterScreen(
|
||||||
viewModel: GameMasterViewModel = koinViewModel(),
|
viewModel: GameMasterViewModel = koinViewModel(),
|
||||||
) {
|
) {
|
||||||
val characters = viewModel.characters.collectAsState()
|
val characters = viewModel.characters.collectAsState()
|
||||||
|
val tags = viewModel.tags.collectAsState()
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier.fillMaxSize()
|
||||||
|
|
@ -45,7 +59,9 @@ fun GameMasterScreen(
|
||||||
GameMasterContent(
|
GameMasterContent(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
filter = viewModel.filter,
|
filter = viewModel.filter,
|
||||||
|
tags = tags,
|
||||||
characters = characters,
|
characters = characters,
|
||||||
|
onTag = viewModel::onTag,
|
||||||
onCharacterAction = viewModel::onCharacterAction,
|
onCharacterAction = viewModel::onCharacterAction,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -54,10 +70,15 @@ fun GameMasterScreen(
|
||||||
@Composable
|
@Composable
|
||||||
private fun GameMasterContent(
|
private fun GameMasterContent(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
filterChipsState: LazyListState = rememberLazyListState(),
|
||||||
filter: LwaTextFieldUio,
|
filter: LwaTextFieldUio,
|
||||||
|
tags: State<List<GMTagUio>>,
|
||||||
characters: State<List<GMCharacterPreviewUio>>,
|
characters: State<List<GMCharacterPreviewUio>>,
|
||||||
|
onTag: (GMTagUio.TagId) -> Unit,
|
||||||
onCharacterAction: (String, GMCharacterPreviewUio.Action) -> Unit,
|
onCharacterAction: (String, GMCharacterPreviewUio.Action) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = {
|
topBar = {
|
||||||
|
|
@ -95,9 +116,32 @@ private fun GameMasterContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
LazyRow(
|
||||||
|
modifier = Modifier.draggable(
|
||||||
|
orientation = Orientation.Horizontal,
|
||||||
|
state = rememberDraggableState { delta ->
|
||||||
|
scope.launch {
|
||||||
|
filterChipsState.scrollBy(-delta)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
state = filterChipsState,
|
||||||
|
contentPadding = remember { PaddingValues(all = 8.dp) },
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||||
|
) {
|
||||||
|
items(
|
||||||
|
items = tags.value,
|
||||||
|
) { tag ->
|
||||||
|
GMTag(
|
||||||
|
style = MaterialTheme.lwa.typography.base.body1,
|
||||||
|
tag = tag,
|
||||||
|
onTag = { onTag(tag.id) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
contentPadding = PaddingValues(all = 8.dp),
|
contentPadding = remember { PaddingValues(all = 8.dp) },
|
||||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||||
) {
|
) {
|
||||||
items(
|
items(
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,18 @@ import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
|
||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
||||||
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterPreviewUio
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio
|
||||||
|
import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio.TagId
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_search
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_search
|
||||||
|
import org.jetbrains.compose.resources.getString
|
||||||
|
|
||||||
class GameMasterViewModel(
|
class GameMasterViewModel(
|
||||||
private val campaignRepository: CampaignRepository,
|
private val campaignRepository: CampaignRepository,
|
||||||
|
|
@ -28,10 +35,34 @@ class GameMasterViewModel(
|
||||||
onValueChange = { _filter.value = it },
|
onValueChange = { _filter.value = it },
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val _tags = MutableStateFlow(mapOf(TagId.PLAYER to false, TagId.NPC to false))
|
||||||
|
val tags = _tags.map { it: Map<TagId, Boolean> ->
|
||||||
|
it.map { (tag, highlight) ->
|
||||||
|
when (tag) {
|
||||||
|
TagId.PLAYER -> GMTagUio(
|
||||||
|
id = TagId.PLAYER,
|
||||||
|
label = getString(Res.string.game_master__character_tag__character_search),
|
||||||
|
highlight = highlight,
|
||||||
|
)
|
||||||
|
|
||||||
|
TagId.NPC -> GMTagUio(
|
||||||
|
id = TagId.NPC,
|
||||||
|
label = getString(Res.string.game_master__character_tag__npc_search),
|
||||||
|
highlight = highlight,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.Eagerly,
|
||||||
|
initialValue = emptyList(),
|
||||||
|
)
|
||||||
|
|
||||||
val characters = combine(
|
val characters = combine(
|
||||||
campaignRepository.campaignFlow,
|
campaignRepository.campaignFlow,
|
||||||
characterSheetRepository.characterSheetPreviewFlow,
|
characterSheetRepository.characterSheetPreviewFlow,
|
||||||
filter.valueFlow,
|
filter.valueFlow,
|
||||||
|
_tags,
|
||||||
gameMasterFactory::convertToGMCharacterPreviewUio,
|
gameMasterFactory::convertToGMCharacterPreviewUio,
|
||||||
).stateIn(
|
).stateIn(
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
|
|
@ -54,4 +85,12 @@ class GameMasterViewModel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onTag(
|
||||||
|
id: TagId,
|
||||||
|
) {
|
||||||
|
_tags.value = _tags.value.toMutableMap().also {
|
||||||
|
it[id] = it.getOrPut(id) { true }.not()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.calculateStartPadding
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.DropdownMenu
|
import androidx.compose.material.DropdownMenu
|
||||||
import androidx.compose.material.DropdownMenuItem
|
import androidx.compose.material.DropdownMenuItem
|
||||||
|
|
@ -44,15 +43,9 @@ data class GMCharacterPreviewUio(
|
||||||
val characterSheetId: String,
|
val characterSheetId: String,
|
||||||
val name: String,
|
val name: String,
|
||||||
val level: Int,
|
val level: Int,
|
||||||
val tags: List<Tag>,
|
val tags: List<GMTagUio>,
|
||||||
val actions: List<Action>,
|
val actions: List<Action>,
|
||||||
) {
|
) {
|
||||||
@Stable
|
|
||||||
data class Tag(
|
|
||||||
val label: String,
|
|
||||||
val highlight: Boolean,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
sealed class Action {
|
sealed class Action {
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -127,7 +120,10 @@ fun GMCharacterPreview(
|
||||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||||
) {
|
) {
|
||||||
character.tags.forEach { tag ->
|
character.tags.forEach { tag ->
|
||||||
Tag(tag = tag)
|
GMTag(
|
||||||
|
style = MaterialTheme.lwa.typography.base.caption,
|
||||||
|
tag = tag,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -201,26 +197,3 @@ private fun OverflowActionMenu(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun Tag(
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
padding: PaddingValues = PaddingValues(horizontal = 8.dp, vertical = 2.dp),
|
|
||||||
tag: GMCharacterPreviewUio.Tag,
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
modifier = modifier
|
|
||||||
.background(
|
|
||||||
color = MaterialTheme.lwa.colorScheme.elevated.base4dp,
|
|
||||||
shape = CircleShape,
|
|
||||||
)
|
|
||||||
.padding(paddingValues = padding),
|
|
||||||
style = MaterialTheme.lwa.typography.base.caption,
|
|
||||||
color = when (tag.highlight) {
|
|
||||||
true -> MaterialTheme.lwa.colorScheme.base.secondary
|
|
||||||
else -> MaterialTheme.lwa.colorScheme.base.onSurface
|
|
||||||
},
|
|
||||||
text = tag.label,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.screen.gamemaster.items
|
||||||
|
|
||||||
|
import androidx.compose.animation.animateColorAsState
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
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.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.text.TextStyle
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
|
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
data class GMTagUio(
|
||||||
|
val id: TagId,
|
||||||
|
val label: String,
|
||||||
|
val highlight: Boolean,
|
||||||
|
) {
|
||||||
|
@Stable
|
||||||
|
enum class TagId {
|
||||||
|
PLAYER, NPC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
object GmTagDefault {
|
||||||
|
val padding = PaddingValues(horizontal = 8.dp, vertical = 2.dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GMTag(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
padding: PaddingValues = GmTagDefault.padding,
|
||||||
|
shape: Shape = CircleShape,
|
||||||
|
elevation: Dp = 2.dp,
|
||||||
|
style: TextStyle,
|
||||||
|
tag: GMTagUio,
|
||||||
|
onTag: (() -> Unit)? = null,
|
||||||
|
) {
|
||||||
|
val animatedColor = animateColorAsState(
|
||||||
|
when (tag.highlight) {
|
||||||
|
true -> MaterialTheme.lwa.colorScheme.base.secondary
|
||||||
|
else -> MaterialTheme.lwa.colorScheme.base.onSurface
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Surface(
|
||||||
|
modifier = modifier,
|
||||||
|
shape = shape,
|
||||||
|
elevation = elevation,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(enabled = onTag != null) { onTag?.invoke() }
|
||||||
|
.padding(paddingValues = padding),
|
||||||
|
style = style,
|
||||||
|
color = animatedColor.value,
|
||||||
|
text = tag.label,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue