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="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_label">joueur: %1$d</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__character_search">Joueur</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_label">Npc-%1$d</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__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.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.GMTagUio
 | 
			
		||||
import com.pixelized.shared.lwa.model.campaign.Campaign
 | 
			
		||||
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_search
 | 
			
		||||
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 java.text.Normalizer
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,6 +17,7 @@ class GameMasterFactory {
 | 
			
		|||
        campaign: Campaign,
 | 
			
		||||
        characters: List<CharacterSheetPreview>,
 | 
			
		||||
        filter: String,
 | 
			
		||||
        tags: Map<GMTagUio.TagId, Boolean>,
 | 
			
		||||
    ): List<GMCharacterPreviewUio> {
 | 
			
		||||
        val normalizedFilter = Normalizer.normalize(filter, Normalizer.Form.NFD)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ class GameMasterFactory {
 | 
			
		|||
                campaign = campaign,
 | 
			
		||||
                character = it,
 | 
			
		||||
                filter = normalizedFilter,
 | 
			
		||||
                tags = tags,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -34,71 +35,67 @@ class GameMasterFactory {
 | 
			
		|||
        campaign: Campaign,
 | 
			
		||||
        character: CharacterSheetPreview,
 | 
			
		||||
        filter: String,
 | 
			
		||||
        tags: Map<GMTagUio.TagId, Boolean>,
 | 
			
		||||
    ): GMCharacterPreviewUio? {
 | 
			
		||||
        val characterId = campaign.characters.keys.firstOrNull {
 | 
			
		||||
            it.characterSheetId == character.characterSheetId
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // get the characterInstanceId from the player list corresponding to this CharacterSheet if any
 | 
			
		||||
        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 {
 | 
			
		||||
            it.characterSheetId == character.characterSheetId
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var playerTagHighlighted = false
 | 
			
		||||
        var npcTagHighlighted = false
 | 
			
		||||
 | 
			
		||||
        // Filter process.
 | 
			
		||||
        // Filter process : Name.
 | 
			
		||||
        if (filter.isNotEmpty()) {
 | 
			
		||||
            val normalizedName = Normalizer.normalize(character.name, Normalizer.Form.NFD)
 | 
			
		||||
            // 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)
 | 
			
		||||
            if (nameHighlight.not() && playerTagHighlighted.not() && npcTagHighlighted.not()) {
 | 
			
		||||
            if (nameHighlight.not()) {
 | 
			
		||||
                return null
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val tags = buildList {
 | 
			
		||||
            if (characterId != null) {
 | 
			
		||||
        // Tag filter process : Player.
 | 
			
		||||
        if (tags[GMTagUio.TagId.PLAYER] == true && characterInstanceId == 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(
 | 
			
		||||
                    GMCharacterPreviewUio.Tag(
 | 
			
		||||
                    GMTagUio(
 | 
			
		||||
                        id = GMTagUio.TagId.PLAYER,
 | 
			
		||||
                        label = getString(
 | 
			
		||||
                            Res.string.game_master__character_tag__character_label,
 | 
			
		||||
                            characterId.instanceId,
 | 
			
		||||
                            characterInstanceId.instanceId,
 | 
			
		||||
                        ),
 | 
			
		||||
                        highlight = playerTagHighlighted,
 | 
			
		||||
                        highlight = tags[GMTagUio.TagId.PLAYER] ?: false,
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            addAll(
 | 
			
		||||
                npcIds.map { npcId ->
 | 
			
		||||
                    GMCharacterPreviewUio.Tag(
 | 
			
		||||
                    GMTagUio(
 | 
			
		||||
                        id = GMTagUio.TagId.NPC,
 | 
			
		||||
                        label = getString(
 | 
			
		||||
                            Res.string.game_master__character_tag__npc_label,
 | 
			
		||||
                            npcId.instanceId
 | 
			
		||||
                        ),
 | 
			
		||||
                        highlight = npcTagHighlighted,
 | 
			
		||||
                        highlight = tags[GMTagUio.TagId.NPC] ?: false,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // build the cell action list
 | 
			
		||||
        val actions = buildList {
 | 
			
		||||
            add(
 | 
			
		||||
                when (characterId) {
 | 
			
		||||
                when (characterInstanceId) {
 | 
			
		||||
                    null -> Action.AddToGroup
 | 
			
		||||
                    else -> Action.RemoveFromGroup(instanceId = characterId.instanceId)
 | 
			
		||||
                    else -> Action.RemoveFromGroup(instanceId = characterInstanceId.instanceId)
 | 
			
		||||
                }
 | 
			
		||||
            )
 | 
			
		||||
            add(Action.AddToNpc)
 | 
			
		||||
| 
						 | 
				
			
			@ -108,11 +105,11 @@ class GameMasterFactory {
 | 
			
		|||
                }
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // return the cell UIO.
 | 
			
		||||
        return GMCharacterPreviewUio(
 | 
			
		||||
            characterSheetId = character.characterSheetId,
 | 
			
		||||
            name = character.name, level = character.level,
 | 
			
		||||
            tags = tags,
 | 
			
		||||
            tags = previewTagsList,
 | 
			
		||||
            actions = actions,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,11 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster
 | 
			
		|||
import androidx.compose.animation.AnimatedVisibility
 | 
			
		||||
import androidx.compose.animation.fadeIn
 | 
			
		||||
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.Column
 | 
			
		||||
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.padding
 | 
			
		||||
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.rememberLazyListState
 | 
			
		||||
import androidx.compose.material.Icon
 | 
			
		||||
import androidx.compose.material.IconButton
 | 
			
		||||
import androidx.compose.material.MaterialTheme
 | 
			
		||||
| 
						 | 
				
			
			@ -21,13 +29,18 @@ import androidx.compose.material.TopAppBar
 | 
			
		|||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.runtime.collectAsState
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.runtime.rememberCoroutineScope
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
 | 
			
		||||
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.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 kotlinx.coroutines.launch
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.Res
 | 
			
		||||
import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
 | 
			
		||||
import org.jetbrains.compose.resources.painterResource
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +51,7 @@ fun GameMasterScreen(
 | 
			
		|||
    viewModel: GameMasterViewModel = koinViewModel(),
 | 
			
		||||
) {
 | 
			
		||||
    val characters = viewModel.characters.collectAsState()
 | 
			
		||||
    val tags = viewModel.tags.collectAsState()
 | 
			
		||||
 | 
			
		||||
    Surface(
 | 
			
		||||
        modifier = Modifier.fillMaxSize()
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +59,9 @@ fun GameMasterScreen(
 | 
			
		|||
        GameMasterContent(
 | 
			
		||||
            modifier = Modifier.fillMaxSize(),
 | 
			
		||||
            filter = viewModel.filter,
 | 
			
		||||
            tags = tags,
 | 
			
		||||
            characters = characters,
 | 
			
		||||
            onTag = viewModel::onTag,
 | 
			
		||||
            onCharacterAction = viewModel::onCharacterAction,
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -54,10 +70,15 @@ fun GameMasterScreen(
 | 
			
		|||
@Composable
 | 
			
		||||
private fun GameMasterContent(
 | 
			
		||||
    modifier: Modifier = Modifier,
 | 
			
		||||
    filterChipsState: LazyListState = rememberLazyListState(),
 | 
			
		||||
    filter: LwaTextFieldUio,
 | 
			
		||||
    tags: State<List<GMTagUio>>,
 | 
			
		||||
    characters: State<List<GMCharacterPreviewUio>>,
 | 
			
		||||
    onTag: (GMTagUio.TagId) -> Unit,
 | 
			
		||||
    onCharacterAction: (String, GMCharacterPreviewUio.Action) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    val scope = rememberCoroutineScope()
 | 
			
		||||
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        modifier = modifier,
 | 
			
		||||
        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(
 | 
			
		||||
                    modifier = Modifier.weight(1f),
 | 
			
		||||
                    contentPadding = PaddingValues(all = 8.dp),
 | 
			
		||||
                    contentPadding = remember { PaddingValues(all = 8.dp) },
 | 
			
		||||
                    verticalArrangement = Arrangement.spacedBy(space = 8.dp),
 | 
			
		||||
                ) {
 | 
			
		||||
                    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.ui.composable.textfield.LwaTextFieldUio
 | 
			
		||||
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.SharingStarted
 | 
			
		||||
import kotlinx.coroutines.flow.combine
 | 
			
		||||
import kotlinx.coroutines.flow.map
 | 
			
		||||
import kotlinx.coroutines.flow.stateIn
 | 
			
		||||
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(
 | 
			
		||||
    private val campaignRepository: CampaignRepository,
 | 
			
		||||
| 
						 | 
				
			
			@ -28,10 +35,34 @@ class GameMasterViewModel(
 | 
			
		|||
        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(
 | 
			
		||||
        campaignRepository.campaignFlow,
 | 
			
		||||
        characterSheetRepository.characterSheetPreviewFlow,
 | 
			
		||||
        filter.valueFlow,
 | 
			
		||||
        _tags,
 | 
			
		||||
        gameMasterFactory::convertToGMCharacterPreviewUio,
 | 
			
		||||
    ).stateIn(
 | 
			
		||||
        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.calculateStartPadding
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.shape.CircleShape
 | 
			
		||||
import androidx.compose.foundation.shape.RoundedCornerShape
 | 
			
		||||
import androidx.compose.material.DropdownMenu
 | 
			
		||||
import androidx.compose.material.DropdownMenuItem
 | 
			
		||||
| 
						 | 
				
			
			@ -44,15 +43,9 @@ data class GMCharacterPreviewUio(
 | 
			
		|||
    val characterSheetId: String,
 | 
			
		||||
    val name: String,
 | 
			
		||||
    val level: Int,
 | 
			
		||||
    val tags: List<Tag>,
 | 
			
		||||
    val tags: List<GMTagUio>,
 | 
			
		||||
    val actions: List<Action>,
 | 
			
		||||
) {
 | 
			
		||||
    @Stable
 | 
			
		||||
    data class Tag(
 | 
			
		||||
        val label: String,
 | 
			
		||||
        val highlight: Boolean,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @Stable
 | 
			
		||||
    sealed class Action {
 | 
			
		||||
        @Stable
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +120,10 @@ fun GMCharacterPreview(
 | 
			
		|||
                horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
 | 
			
		||||
            ) {
 | 
			
		||||
                character.tags.forEach { tag ->
 | 
			
		||||
                    Tag(tag = tag)
 | 
			
		||||
                    GMTag(
 | 
			
		||||
                        style = MaterialTheme.lwa.typography.base.caption,
 | 
			
		||||
                        tag = tag,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -200,27 +196,4 @@ 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