Some small UI adjustment to the level UP screen & RollOverlay.
This commit is contained in:
parent
fce085f70d
commit
35396b6069
23 changed files with 530 additions and 166 deletions
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="generic__arrow">▸</string>
|
||||
|
||||
<string name="error__missing_character_sheet__label">La feuille de personnage est introuvable</string>
|
||||
<string name="error__default__action">Ok</string>
|
||||
|
||||
|
|
@ -112,36 +114,20 @@
|
|||
<string name="character_sheet__delete_dialog__description">Êtes-vous sûr de vouloir supprimer "%1$s" ?</string>
|
||||
|
||||
<string name="tooltip__characteristics__characteristics">Les caractéristiques constituent les aptitudes innées d’un personnage comme son intelligence, sa force, son charisme, etc. Elles ne sont pas acquises, mais peuvent être parfois augmentées par un entraînement ou une utilisation réussie. Les caractéristiques des humains normaux varient de 2 (niveau extrêmement bas) à 20 (maximum du potentiel humain), avec une moyenne de 10 ou 11. Plus une caractéristique est élevée plus le personnage est puissant dans cette aptitude.\nÀ la création de votre personnage, répartissez les valeurs suivantes dans les différentes caractéristiques : 15, 15, 13, 11, 10, 9 et 7.</string>
|
||||
<string name="tooltip__characteristics__strength">La Force représente essentiellement la puissance musculaire du personnage. Elle ne décrit pas nécessairement la masse musculaire brute, mais l’efficacité avec laquelle le personnage exerce ses muscles pour accomplir des actions physiques pénibles.</string>
|
||||
<string name="tooltip__characteristics__constitution">La Constitution est une mesure de la ténacité et de la résilience du personnage. Elle sert à résister aux maladies. Mais son aspect le plus important réside dans la détermination du nombre de dommages qu’un personnage peut supporter avant de succomber.</string>
|
||||
<string name="tooltip__characteristics__height">La Taille est une mesure de la masse du personnage. Elle ne représente pas forcément la taille en centimètres, mais une idée générale de sa masse physique. Un personnage à la TAI élevée peut être très grand et mince, ou petit et massif, ou de taille moyenne en surpoids.</string>
|
||||
<string name="tooltip__characteristics__intelligence">L’Intelligence représente la capacité de discernement du personnage. Elle ne mesure pas nécessairement la somme d’informations mémorisées, mais l’aptitude au raisonnement, l’acuité intellectuelle, la capacité à résoudre des problèmes et l’intuition.</string>
|
||||
<string name="tooltip__characteristics__power">Le Pouvoir est une mesure presque intangible de la force de volonté, du dynamisme intérieur et de l’énergie spirituelle. Il représente également le potentiel magique du personnage.</string>
|
||||
<string name="tooltip__characteristics__dexterity">La Dextérité mesure la coordination œil-main, la vitesse physique et l’agilité générale. La DEX détermine à quelle vitesse un personnage peut agir en combat.</string>
|
||||
<string name="tooltip__characteristics__charisma">Il représente plusieurs aspects allant de la grâce à la beauté en passant par l’attraction que le personnage exerce sur les autres. Un personnage avec un CHA élevé se remarque dans une foule en raison d’une intangible combinaison de charme et de présence.</string>
|
||||
<string name="tooltip__characteristics__strength">La Force représente essentiellement la puissance musculaire du personnage. Elle ne décrit pas nécessairement la masse musculaire brute, mais l’efficacité avec laquelle le personnage exerce ses muscles pour accomplir des actions physiques pénibles.\n\n- Bonus aux dégats\n- Athlétisme\n- Lancer\n- Saisie</string>
|
||||
<string name="tooltip__characteristics__constitution">La Constitution est une mesure de la ténacité et de la résilience du personnage. Elle sert à résister aux maladies. Mais son aspect le plus important réside dans la détermination du nombre de dommages qu’un personnage peut supporter avant de succomber.\n\n- Point de vie maximum\n- Athlétisme\n- Acrobatie</string>
|
||||
<string name="tooltip__characteristics__height">La Taille est une mesure de la masse du personnage. Elle ne représente pas forcément la taille en centimètres, mais une idée générale de sa masse physique. Un personnage à la TAI élevée peut être très grand et mince, ou petit et massif, ou de taille moyenne en surpoids.\n\n- Bonus aux dégats\n- Point de vie maximum\n- Saisie\n- Intimidation\n- Discrétion (impact négatif)</string>
|
||||
<string name="tooltip__characteristics__intelligence">L’Intelligence représente la capacité de discernement du personnage. Elle ne mesure pas nécessairement la somme d’informations mémorisées, mais l’aptitude au raisonnement, l’acuité intellectuelle, la capacité à résoudre des problèmes et l’intuition.\n\n- Bonus d'apprentissage\n- Perception\n- Recherche\n- Empathie\n- Baratin\n- Premiers soins</string>
|
||||
<string name="tooltip__characteristics__power">Le Pouvoir est une mesure presque intangible de la force de volonté, du dynamisme intérieur et de l’énergie spirituelle. Il représente également le potentiel magique du personnage.\n\n- Points de pouvoir maximum\n- Intimidation</string>
|
||||
<string name="tooltip__characteristics__dexterity">La Dextérité mesure la coordination œil-main, la vitesse physique et l’agilité générale. La DEX détermine à quelle vitesse un personnage peut agir en combat.\n\n- Initiative\n- Bagarre\n- Esquive\n- Lancer\n- Acrobatie\n- Discrétion\n- Escamotage\n- Premiers soins</string>
|
||||
<string name="tooltip__characteristics__charisma">Il représente plusieurs aspects allant de la grâce à la beauté en passant par l’attraction que le personnage exerce sur les autres. Un personnage avec un CHA élevé se remarque dans une foule en raison d’une intangible combinaison de charme et de présence.\n\n- Empathie\n- Persuasion\n- Persuasion\n- Intimidation\n- Baratin\n- Marchandage\n- Discrétion</string>
|
||||
<string name="tooltip__sub_characteristics__movement">Le Déplacement (DEP) est une valeur de jeu qui détermine la distance que peut parcourir un personnage en un round de combat. Tous les humains ont un DEP de 10. Le DEP a une valeur réelle flexible, mais généralement, chaque point de DEP équivaut à un déplacement d’un mètre. En course, un point équivaut à trois mètres.</string>
|
||||
<string name="tooltip__sub_characteristics__hit_point">Les points de vie (PV) sont égaux à la somme CON+TAI du personnage, divisée par deux (arrondie au supérieur). Ils sont soustraits lorsque le personnage subit des dommages. Quand les points de vie tombent à 0, le personnage sombre dans l’inconscience. S'il reste inconscient trop longtemps, il meurt. Tous les points de vie régénèrent naturellement après une nuit de repos.</string>
|
||||
<string name="tooltip__sub_characteristics__power_point">les points de pouvoir sont égaux au POU et sont dépensés pour utiliser la magie ou d’autres pouvoirs. Tous les points de pouvoir régénèrent naturellement après une nuit de repos.</string>
|
||||
<string name="tooltip__sub_characteristics__bonus_damage">Les personnages plus massifs ou plus forts infligent plus de dégâts quand ils frappent leurs ennemis en combat au corps à corps. Le modificateur s’applique aux dégâts infligés par toute attaque portée par les personnages avec des armes de mêlée (BDC). La moitié de ce bonus s'applique aux attaques de lancer (BDD).</string>
|
||||
<string name="tooltip__sub_characteristics__bonus_damage">Les personnages plus massifs ou plus forts infligent plus de dégâts quand ils frappent leurs ennemis. Le modificateur s’applique aux dégâts infligés par toute attaque portée par les personnages avec des armes de mêlée (BDC). La moitié de ce bonus s'applique aux attaques de lancer (BDD).\n\nBonus aux dégâts : Force + Taille\n- 2 à 12 : -1d6\n- 12 à 17 : -1d4\n- 18 à 22 : 0\n- 23 à 29 : +1d4\n- 30 à 39 : +1d6\n- Au delà : +2d6</string>
|
||||
<string name="tooltip__sub_characteristics__armor">Une armure protège son porteur des blessures. Lorsqu’un personnage est touché en combat par une attaque non magique, soustrayez les points d’armure aux points de dégâts infligés. Les dommages au-delà de la protection de l’armure surpassent celle-ci et sont infligés au personnage, réduisant ses points de vie actuels.</string>
|
||||
<string name="tooltip__sub_characteristics__learning">Plus un personnage est intelligent, plus il assimile rapidement les connaissances et plus il digère son expérience efficacement. Ce modificateur s'applique au score des compétences nouvellement acquises et aux jets d'expériences. Il est égal à (INT - 10) x 2 avec une valeur minimale de zéro.</string>
|
||||
<string name="tooltip__sub_characteristics__hp_grow">Plus un personnage est de bonne constitution, plus son corps se renforce rapidement. Ce modificateur indique le nombre de "PV" maximum que le personnage gagne à chaque progression. Il est égal à CON / 3, arrondi à l'inférieur.</string>
|
||||
<string name="tooltip__skills__combat">Attaque en combat à mains nues. Une attaque réussie inflige 1D3 + BDGT.</string>
|
||||
<string name="tooltip__skills__dodge">Éviter une attaque, un projectile, etc.</string>
|
||||
<string name="tooltip__skills__grab">Maitriser/immobiliser un adversaire.</string>
|
||||
<string name="tooltip__skills__throw">Viser et lancer quelque chose à travers les airs et vers une cible.</string>
|
||||
<string name="tooltip__skills__athletics">Réaliser un mouvement nécessitant une certaine force (Enfoncer une porte, nager à contre-courant, etc.).</string>
|
||||
<string name="tooltip__skills__acrobatics">Réaliser un mouvement nécessitant une certaine agilité (Marcher sur une corde, courir sur la glace, etc.).</string>
|
||||
<string name="tooltip__skills__perception">Aptitude à percevoir via ses sens ou à percevoir un détail difficile à remarquer.</string>
|
||||
<string name="tooltip__skills__search">Aptitude à trouver des indices et à émettre des suppositions sur la base de ceux-ci.</string>
|
||||
<string name="tooltip__skills__empathy">Évaluer les pensées et/ou les motivations cachées d’un autre personnage en se basant sur des signaux subliminaux.</string>
|
||||
<string name="tooltip__skills__persuasion">Influencer quelqu'un ou un groupe de personnes avec tact, grâce, ou de bonnes manières.</string>
|
||||
<string name="tooltip__skills__intimidation">Influencer quelqu'un ou un groupe de personnes par des menaces, des actions hostiles, ou de la violence physique.</string>
|
||||
<string name="tooltip__skills__spiel">Mentir ou cacher la vérité avec efficacité, soit verbalement, soit par vos actions.</string>
|
||||
<string name="tooltip__skills__bargain">Négocier les prix.</string>
|
||||
<string name="tooltip__skills__discretion">Passer inaperçu.</string>
|
||||
<string name="tooltip__skills__sleight_of_hand">Réaliser une manipulation ou une fourberie, comme prendre quelque chose à quelqu'un ou dissimuler un objet sur vous-même.</string>
|
||||
<string name="tooltip__skills__aid">Traiter les blessures légères. Une réussite rétablit 1D3 points de vie. Une réussite spéciale restaure 1D3+3 points de vie.</string>
|
||||
|
||||
<string name="network__title">Configuration de la table</string>
|
||||
<string name="network__player_name__label">Nom du joueur</string>
|
||||
|
|
@ -156,6 +142,7 @@
|
|||
<string name="network__socket__type_server">Serveur</string>
|
||||
<string name="network__socket__type_client">Client</string>
|
||||
<string name="network__socket__type_none">Aucun</string>
|
||||
<string name="network__require__player_name">Un nom de joueur est requis</string>
|
||||
<string name="network__connect__message">Vous êtes connecté au serveur</string>
|
||||
<string name="network__disconnect__message">Vous êtes déconnecté du serveur</string>
|
||||
<string name="network__message__action">Ok</string>
|
||||
|
|
@ -186,7 +173,10 @@
|
|||
|
||||
<string name="level_up__title">Montée de niveau</string>
|
||||
<string name="level_up__action">Level Up !</string>
|
||||
<string name="level_up__character_level_description">Passage du niveau %1$d au niveau supérieur : %2$d</string>
|
||||
<string name="level_up__character__label">niv : %1$d▸%2$d</string>
|
||||
<string name="level_up__character_level_description">Passage du niveau %1$d ▸ %2$d</string>
|
||||
<string name="level_up__skill_level">niv : %1$d -</string>
|
||||
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
@ -32,9 +32,6 @@ import androidx.compose.ui.unit.min
|
|||
import androidx.compose.ui.window.ApplicationScope
|
||||
import androidx.compose.ui.window.Window
|
||||
import androidx.compose.ui.window.rememberWindowState
|
||||
import coil3.ImageLoader
|
||||
import coil3.compose.setSingletonImageLoaderFactory
|
||||
import coil3.request.crossfade
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository.Status
|
||||
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent
|
||||
|
|
@ -53,17 +50,18 @@ import com.pixelized.desktop.lwa.ui.navigation.window.destination.CharacterSheet
|
|||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.NetworkWindows
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.destination.RollHistoryWindow
|
||||
import com.pixelized.desktop.lwa.ui.navigation.window.rememberMaxWindowHeight
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollHostState
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollOverlay
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.CampaignChatViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbon
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.CharacterSheetMainNavHost
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkPage
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollHostState
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollOverlay
|
||||
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryPage
|
||||
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryViewModel
|
||||
import com.pixelized.desktop.lwa.ui.theme.LwaTheme
|
||||
import com.pixelized.desktop.lwa.utils.InstallCoil
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
|
|
@ -102,7 +100,7 @@ val LocalBlurController = compositionLocalOf<BlurContentController> {
|
|||
|
||||
@Composable
|
||||
@Preview
|
||||
fun ApplicationScope.App() {
|
||||
fun ApplicationScope.LwaApplication() {
|
||||
val maxWindowHeight = rememberMaxWindowHeight()
|
||||
val snackHostState = remember { SnackbarHostState() }
|
||||
val errorSnackHostState = remember { SnackbarHostState() }
|
||||
|
|
@ -120,12 +118,13 @@ fun ApplicationScope.App() {
|
|||
),
|
||||
)
|
||||
|
||||
// Coil configuration
|
||||
setSingletonImageLoaderFactory { context ->
|
||||
ImageLoader.Builder(context)
|
||||
.crossfade(enable = false)
|
||||
.build()
|
||||
}
|
||||
// Coil configuration.
|
||||
InstallCoil(
|
||||
crossfade = false,
|
||||
diskCachePath = { provider ->
|
||||
provider.imagesStorePath()
|
||||
}
|
||||
)
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalApplicationScope provides this,
|
||||
|
|
@ -150,16 +149,18 @@ fun ApplicationScope.App() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun MainWindowScreen(
|
||||
campaignViewModel: CampaignViewModel = koinViewModel(),
|
||||
dataSyncViewModel: DataSyncViewModel = koinViewModel(),
|
||||
networkViewModel: NetworkViewModel = koinViewModel(),
|
||||
campaignViewModel: CampaignViewModel = koinViewModel(),
|
||||
campaignChatViewModel: CampaignChatViewModel = koinViewModel(),
|
||||
rollViewModel: RollHistoryViewModel = koinViewModel(),
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
networkViewModel.connect()
|
||||
campaignViewModel.init()
|
||||
dataSyncViewModel.autoConnect()
|
||||
dataSyncViewModel.synchronise()
|
||||
}
|
||||
|
||||
val snackHostState = LocalSnackHost.current
|
||||
|
|
@ -205,15 +206,12 @@ private fun MainWindowScreen(
|
|||
content = {
|
||||
BlurContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
controller = blurController
|
||||
controller = blurController,
|
||||
) {
|
||||
MainNavHost(
|
||||
campaignViewModel = campaignViewModel,
|
||||
networkViewModel = networkViewModel,
|
||||
campaignChatViewModel = campaignChatViewModel,
|
||||
)
|
||||
MainNavHost()
|
||||
}
|
||||
RollOverlay(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
hostState = rollHostState,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package com.pixelized.desktop.lwa
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
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.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
||||
class DataSyncViewModel(
|
||||
private val characterRepository: CharacterSheetRepository,
|
||||
private val alterationRepository: AlterationRepository,
|
||||
private val campaignRepository: CampaignRepository,
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val networkRepository: NetworkRepository,
|
||||
) : ViewModel() {
|
||||
|
||||
fun autoConnect() {
|
||||
val settings = settingsRepository.settings()
|
||||
|
||||
if (settings.playerName.isEmpty()) return
|
||||
|
||||
networkRepository.connect(
|
||||
host = settings.host,
|
||||
port = settings.port,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun synchronise() = coroutineScope {
|
||||
|
||||
networkRepository.status
|
||||
.filter { status -> status == NetworkRepository.Status.CONNECTED }
|
||||
.onEach { campaignRepository.update() }
|
||||
.launchIn(this)
|
||||
|
||||
networkRepository.status
|
||||
.filter { status -> status == NetworkRepository.Status.CONNECTED }
|
||||
.combine(campaignRepository.campaignFlow) { _, campaign: Campaign -> campaign }
|
||||
.onEach { campaign ->
|
||||
campaign.characters.keys.forEach { id ->
|
||||
characterRepository.characterDetail(
|
||||
characterSheetId = id.characterSheetId,
|
||||
forceUpdate = true,
|
||||
)
|
||||
alterationRepository.updateActiveAlterations(
|
||||
characterInstanceId = id,
|
||||
)
|
||||
}
|
||||
}
|
||||
.launchIn(this)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,8 +15,8 @@ import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
|||
import com.pixelized.desktop.lwa.repository.settings.SettingsStore
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel
|
||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogFactory
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.LevelUpViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.CampaignChatViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.TextMessageFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailFactory
|
||||
|
|
@ -30,10 +30,10 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEdi
|
|||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEditViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.LevelUpFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.LevelUpViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.main.MainPageViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.settings.SettingsViewModel
|
||||
import com.pixelized.desktop.lwa.usecase.SettingsUseCase
|
||||
|
|
@ -116,6 +116,7 @@ val factoryDependencies
|
|||
|
||||
val viewModelDependencies
|
||||
get() = module {
|
||||
viewModelOf(::DataSyncViewModel)
|
||||
viewModelOf(::CampaignViewModel)
|
||||
viewModelOf(::MainPageViewModel)
|
||||
viewModelOf(::CharacterSheetViewModel)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Surface
|
||||
|
|
@ -40,7 +41,12 @@ fun TooltipLayout(
|
|||
|
||||
else -> TooltipArea(
|
||||
modifier = modifier,
|
||||
tooltip = { Tooltip(tooltip = tooltip) },
|
||||
tooltip = {
|
||||
Tooltip(
|
||||
modifier = Modifier.width(width = 448.dp),
|
||||
tooltip = tooltip,
|
||||
)
|
||||
},
|
||||
content = content,
|
||||
delayMillis = delayMillis,
|
||||
tooltipPlacement = tooltipPlacement,
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ val LocalScreenController = compositionLocalOf<NavHostController> {
|
|||
@Composable
|
||||
fun MainNavHost(
|
||||
controller: NavHostController = rememberNavController(),
|
||||
campaignViewModel: CampaignViewModel,
|
||||
networkViewModel: NetworkViewModel,
|
||||
campaignChatViewModel: CampaignChatViewModel,
|
||||
startDestination: String = MainDestination.navigationRoute(),
|
||||
) {
|
||||
CompositionLocalProvider(
|
||||
|
|
@ -35,11 +32,7 @@ fun MainNavHost(
|
|||
navController = controller,
|
||||
startDestination = startDestination,
|
||||
) {
|
||||
composableMainPage(
|
||||
campaignViewModel = campaignViewModel,
|
||||
networkViewModel = networkViewModel,
|
||||
campaignChatViewModel = campaignChatViewModel,
|
||||
)
|
||||
composableMainPage()
|
||||
composableSettingsPage()
|
||||
composableLevelUp()
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@ package com.pixelized.desktop.lwa.ui.navigation.screen.destination
|
|||
import androidx.navigation.NavGraphBuilder
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.composable
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignScreen
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.chat.CampaignChatViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
|
||||
object MainDestination {
|
||||
private const val ROUTE = "main"
|
||||
|
|
@ -15,19 +12,11 @@ object MainDestination {
|
|||
fun navigationRoute() = ROUTE
|
||||
}
|
||||
|
||||
fun NavGraphBuilder.composableMainPage(
|
||||
campaignViewModel: CampaignViewModel,
|
||||
networkViewModel: NetworkViewModel,
|
||||
campaignChatViewModel: CampaignChatViewModel,
|
||||
) {
|
||||
fun NavGraphBuilder.composableMainPage() {
|
||||
composable(
|
||||
route = MainDestination.baseRoute(),
|
||||
) {
|
||||
CampaignScreen(
|
||||
campaignViewModel = campaignViewModel,
|
||||
networkViewModel = networkViewModel,
|
||||
campaignChatViewModel = campaignChatViewModel,
|
||||
)
|
||||
CampaignScreen()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.koin.compose.viewmodel.koinViewModel
|
|||
@Composable
|
||||
fun RollOverlay(
|
||||
viewModel: RollViewModel = koinViewModel(),
|
||||
modifier: Modifier = Modifier,
|
||||
hostState: RollHostState,
|
||||
) {
|
||||
val blur = LocalBlurController.current
|
||||
|
|
@ -43,7 +44,7 @@ fun RollOverlay(
|
|||
}
|
||||
|
||||
AnimatedContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
modifier = modifier,
|
||||
targetState = hostState.rollAction.value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { 64 }
|
||||
|
|
|
|||
|
|
@ -61,13 +61,11 @@ fun CampaignScreen(
|
|||
campaignViewModel: CampaignViewModel = koinViewModel(),
|
||||
networkViewModel: NetworkViewModel = koinViewModel(),
|
||||
campaignChatViewModel: CampaignChatViewModel = koinViewModel(),
|
||||
rollViewModel: RollViewModel = koinViewModel(),
|
||||
) {
|
||||
val screen = LocalScreenController.current
|
||||
val blurController = rememberBlurContentController()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
|
||||
KeyHandler {
|
||||
when {
|
||||
it.type == KeyEventType.KeyUp && it.key == Key.Escape -> {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ data class CharacterDetailHeaderUio(
|
|||
@Composable
|
||||
fun CharacterDetailHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
iconSize: Dp = 14.dp,
|
||||
iconSize: Dp = MaterialTheme.lwa.size.sheet.subCategory,
|
||||
header: State<CharacterDetailHeaderUio?>,
|
||||
onDismissRequest: () -> Unit,
|
||||
onDiminished: () -> Unit,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ fun CharacterDetailSheet(
|
|||
) {
|
||||
sheet.value?.characteristics?.forEach {
|
||||
CharacterDetailSheetCharacteristic(
|
||||
modifier = Modifier.size(size = MaterialTheme.lwa.size.characteristic),
|
||||
modifier = Modifier.size(size = MaterialTheme.lwa.size.sheet.characteristic),
|
||||
characteristic = it,
|
||||
onClick = { onCharacteristic(it) },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ import androidx.compose.foundation.layout.Box
|
|||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
|
@ -55,6 +57,7 @@ import androidx.compose.ui.input.key.key
|
|||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import coil3.compose.AsyncImage
|
||||
|
|
@ -68,6 +71,8 @@ import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpCharacteristic
|
|||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpCharacteristicUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSkill
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSkillUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSubCharacteristic
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSubCharacteristicUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
|
|
@ -75,7 +80,7 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet__skills_
|
|||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__magic_title
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__special_title
|
||||
import lwacharactersheet.composeapp.generated.resources.level_up__action
|
||||
import lwacharactersheet.composeapp.generated.resources.level_up__character_level_description
|
||||
import lwacharactersheet.composeapp.generated.resources.level_up__character__label
|
||||
import lwacharactersheet.composeapp.generated.resources.level_up__title
|
||||
import org.jetbrains.compose.resources.StringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
|
@ -86,6 +91,11 @@ data class LevelUpHeaderUio(
|
|||
val name: String,
|
||||
val level: Int,
|
||||
val portrait: String?,
|
||||
val hp: LevelUpSubCharacteristicUio,
|
||||
val pp: LevelUpSubCharacteristicUio,
|
||||
val bonus: LevelUpSubCharacteristicUio,
|
||||
val grow: LevelUpSubCharacteristicUio,
|
||||
val learn: LevelUpSubCharacteristicUio,
|
||||
)
|
||||
|
||||
@Stable
|
||||
|
|
@ -217,18 +227,49 @@ private fun LevelUpContent(
|
|||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.lwa.typography.base.h5,
|
||||
text = header.value?.name ?: ""
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.lwa.typography.base.body1,
|
||||
text = (header.value?.level ?: 0).let {
|
||||
stringResource(
|
||||
Res.string.level_up__character_level_description, it, it + 1
|
||||
)
|
||||
},
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h5,
|
||||
text = header.value?.name ?: "",
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.lwa.typography.base.caption,
|
||||
text = (header.value?.level ?: 0).let { level ->
|
||||
stringResource(
|
||||
resource = Res.string.level_up__character__label,
|
||||
level, level + 1
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 16.dp),
|
||||
) {
|
||||
LevelUpSubCharacteristic(
|
||||
characteristic = header.value?.hp,
|
||||
)
|
||||
LevelUpSubCharacteristic(
|
||||
characteristic = header.value?.pp,
|
||||
)
|
||||
Spacer(
|
||||
modifier = Modifier.weight(weight = 1f)
|
||||
)
|
||||
LevelUpSubCharacteristic(
|
||||
characteristic = header.value?.bonus,
|
||||
)
|
||||
LevelUpSubCharacteristic(
|
||||
characteristic = header.value?.grow,
|
||||
)
|
||||
LevelUpSubCharacteristic(
|
||||
characteristic = header.value?.learn,
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(state = scrollState),
|
||||
|
|
@ -251,7 +292,7 @@ private fun LevelUpContent(
|
|||
key = { it.characteristicId }
|
||||
) {
|
||||
LevelUpCharacteristic(
|
||||
modifier = Modifier.size(size = MaterialTheme.lwa.size.characteristic),
|
||||
modifier = Modifier.size(size = MaterialTheme.lwa.size.sheet.characteristic),
|
||||
characteristic = it,
|
||||
onClick = { onCharacteristic(it) },
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,10 +5,14 @@ import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio
|
|||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpCharacteristicUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSkillUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSubCharacteristicUio
|
||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheet
|
||||
import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory
|
||||
import com.pixelized.shared.lwa.model.alteration.Alteration
|
||||
import com.pixelized.shared.lwa.model.alteration.FieldAlteration
|
||||
import com.pixelized.shared.lwa.model.campaign.Campaign
|
||||
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
|
||||
import com.pixelized.shared.lwa.parser.expression.Expression
|
||||
import com.pixelized.shared.lwa.usecase.ExpressionUseCase
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__cha
|
||||
|
|
@ -18,6 +22,20 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet__charact
|
|||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__int
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__pow
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__characteristics__str
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__armor
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__damage_bonus
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hit_point
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__hp_grow
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__learning
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__movement
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__sub_characteristics__power_point
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_cognition_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_heart_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_heart_plus_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_near_me
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_shield_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_swords_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_water_drop_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__constitution
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__dexterity
|
||||
|
|
@ -25,6 +43,13 @@ import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics
|
|||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__intelligence
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__power
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__strength
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__armor
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__bonus_damage
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hit_point
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hp_grow
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__learning
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__movement
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__power_point
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class LevelUpFactory(
|
||||
|
|
@ -32,14 +57,96 @@ class LevelUpFactory(
|
|||
private val expressionUseCase: ExpressionUseCase,
|
||||
) {
|
||||
|
||||
fun convertToLevelUpHeaderUio(
|
||||
suspend fun convertToLevelUpHeaderUio(
|
||||
characterSheet: CharacterSheet?,
|
||||
selectedCharacteristicId: String?,
|
||||
): LevelUpHeaderUio? {
|
||||
if (characterSheet == null) return null
|
||||
|
||||
val levelAlteration = FieldAlteration(
|
||||
alterationId = CharacterSheet.CharacteristicId.LVL,
|
||||
metadata = Alteration.MetaData(
|
||||
name = "LevelUp-${CharacterSheet.CharacteristicId.LVL}",
|
||||
description = "Fake alteration for a levelUp simulation. Alter the ${CharacterSheet.CharacteristicId.LVL} stat."
|
||||
),
|
||||
expression = Expression.Flat(1),
|
||||
)
|
||||
|
||||
val alteredCharacterSheet = alteredCharacterSheetFactory.sheet(
|
||||
characterSheet = characterSheet,
|
||||
alterations = emptyMap(),
|
||||
)
|
||||
val levelUpCharacterSheet = alteredCharacterSheetFactory.sheet(
|
||||
characterSheet = characterSheet,
|
||||
alterations = selectedCharacteristicId
|
||||
?.let {
|
||||
val characteristic = FieldAlteration(
|
||||
alterationId = it,
|
||||
metadata = Alteration.MetaData(
|
||||
name = "LevelUp-$it",
|
||||
description = "Fake alteration for a levelUp simulation. Alter the $it stat."
|
||||
),
|
||||
expression = Expression.Flat(1),
|
||||
)
|
||||
mapOf(
|
||||
CharacterSheet.CharacteristicId.LVL to listOf(levelAlteration),
|
||||
it to listOf(characteristic),
|
||||
)
|
||||
}
|
||||
?: mapOf(
|
||||
CharacterSheet.CharacteristicId.LVL to listOf(levelAlteration),
|
||||
),
|
||||
)
|
||||
|
||||
return LevelUpHeaderUio(
|
||||
name = characterSheet.name,
|
||||
portrait = characterSheet.portrait,
|
||||
level = characterSheet.level,
|
||||
hp = LevelUpSubCharacteristicUio(
|
||||
icon = Res.drawable.ic_heart_24dp,
|
||||
base = "${alteredCharacterSheet.maxHp}",
|
||||
levelUp = "${levelUpCharacterSheet.maxHp}",
|
||||
tooltip = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__hit_point),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__hit_point)
|
||||
),
|
||||
),
|
||||
pp = LevelUpSubCharacteristicUio(
|
||||
icon = Res.drawable.ic_water_drop_24dp,
|
||||
base = "${alteredCharacterSheet.maxPp}",
|
||||
levelUp = "${levelUpCharacterSheet.maxPp}",
|
||||
tooltip = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__power_point),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__power_point)
|
||||
)
|
||||
),
|
||||
bonus = LevelUpSubCharacteristicUio(
|
||||
icon = Res.drawable.ic_swords_24dp,
|
||||
base = alteredCharacterSheet.damageBonus,
|
||||
levelUp = levelUpCharacterSheet.damageBonus,
|
||||
tooltip = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__damage_bonus),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__bonus_damage)
|
||||
),
|
||||
),
|
||||
grow = LevelUpSubCharacteristicUio(
|
||||
icon = Res.drawable.ic_heart_plus_24dp,
|
||||
base = "${alteredCharacterSheet.hpGrow}",
|
||||
levelUp = "${levelUpCharacterSheet.hpGrow}",
|
||||
tooltip = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__hp_grow),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__hp_grow)
|
||||
),
|
||||
),
|
||||
learn = LevelUpSubCharacteristicUio(
|
||||
icon = Res.drawable.ic_cognition_24dp,
|
||||
base = "${alteredCharacterSheet.learning}",
|
||||
levelUp = "${levelUpCharacterSheet.learning}",
|
||||
tooltip = TooltipUio(
|
||||
title = getString(Res.string.character_sheet__sub_characteristics__learning),
|
||||
description = getString(Res.string.tooltip__sub_characteristics__learning)
|
||||
),
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -204,6 +311,12 @@ class LevelUpFactory(
|
|||
level = skill.level,
|
||||
levelUp = results.isSkillLeveledUp(skillId = skill.id),
|
||||
occupation = skill.occupation,
|
||||
tooltips = skill.description?.let {
|
||||
TooltipUio(
|
||||
title = skill.label,
|
||||
description = it,
|
||||
)
|
||||
},
|
||||
roll = when (results[skill.id]) {
|
||||
null -> RollActionUio(
|
||||
characterInstanceId = characterInstanceId,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.SharedFlow
|
|||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.error__default__action
|
||||
|
|
@ -35,14 +34,15 @@ class LevelUpViewModel(
|
|||
private val results = MutableStateFlow<Map<String, RollResult>>(emptyMap())
|
||||
private val selectedCharacteristicId = MutableStateFlow<String?>(null)
|
||||
|
||||
val header: StateFlow<LevelUpHeaderUio?> = characterSheetRepository
|
||||
.characterDetailFlow(characterSheetId = argument.characterInstanceId.characterSheetId)
|
||||
.map(levelUpFactory::convertToLevelUpHeaderUio)
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = null,
|
||||
)
|
||||
val header = combine(
|
||||
characterSheetRepository.characterDetailFlow(characterSheetId = argument.characterInstanceId.characterSheetId),
|
||||
selectedCharacteristicId,
|
||||
levelUpFactory::convertToLevelUpHeaderUio
|
||||
).stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Lazily,
|
||||
initialValue = null,
|
||||
)
|
||||
|
||||
val characteristics = combine(
|
||||
characterSheetRepository.characterDetailFlow(characterSheetId = argument.characterInstanceId.characterSheetId),
|
||||
|
|
|
|||
|
|
@ -64,11 +64,7 @@ fun LevelUpCharacteristic(
|
|||
.fillMaxWidth()
|
||||
.align(alignment = Alignment.Center),
|
||||
targetState = characteristic.selected,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { -16 }
|
||||
val exit = fadeOut() + slideOutVertically { 16 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.compose.animation.fadeOut
|
|||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
|
|
@ -23,6 +24,8 @@ 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.composable.shapes.MasteryShape
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||
import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
|
|
@ -37,9 +40,11 @@ data class LevelUpSkillUio(
|
|||
val level: Int,
|
||||
val levelUp: Boolean,
|
||||
val occupation: Boolean,
|
||||
val tooltips: TooltipUio?,
|
||||
val roll: RollActionUio?,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun LevelUpSkill(
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -53,7 +58,7 @@ fun LevelUpSkill(
|
|||
else -> MaterialTheme.lwa.colorScheme.base.primary
|
||||
}
|
||||
)
|
||||
Row(
|
||||
TooltipLayout(
|
||||
modifier = Modifier
|
||||
.let {
|
||||
when (skill.roll) {
|
||||
|
|
@ -63,60 +68,65 @@ fun LevelUpSkill(
|
|||
}
|
||||
.padding(paddingValues = paddingValues)
|
||||
.then(other = modifier),
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
tooltip = skill.tooltips,
|
||||
) {
|
||||
MasteryShape(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
multiplier = if (skill.occupation) 1 else 0,
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline().weight(1f),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = skill.label
|
||||
MasteryShape(
|
||||
modifier = Modifier.padding(top = 4.dp),
|
||||
multiplier = if (skill.occupation) 1 else 0,
|
||||
)
|
||||
AnimatedContent(
|
||||
targetState = skill.levelUp,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { -16 }
|
||||
val exit = fadeOut() + slideOutVertically { 16 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline().weight(1f),
|
||||
style = MaterialTheme.typography.body1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = skill.label
|
||||
)
|
||||
AnimatedContent(
|
||||
targetState = skill.levelUp,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { -16 }
|
||||
val exit = fadeOut() + slideOutVertically { 16 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(
|
||||
resource = Res.string.level_up__skill_level,
|
||||
when (it) {
|
||||
true -> skill.level + 1
|
||||
else -> skill.level
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.caption,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
text = stringResource(
|
||||
resource = Res.string.level_up__skill_level,
|
||||
when (it) {
|
||||
true -> skill.level + 1
|
||||
else -> skill.level
|
||||
},
|
||||
)
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = when (it) {
|
||||
true -> MaterialTheme.lwa.colorScheme.base.secondary
|
||||
else -> valueColor.value
|
||||
},
|
||||
text = when (it) {
|
||||
true -> "${skill.value + 5}"
|
||||
else -> "${skill.value}"
|
||||
},
|
||||
)
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.body1,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = when (it) {
|
||||
true -> MaterialTheme.lwa.colorScheme.base.secondary
|
||||
else -> valueColor.value
|
||||
},
|
||||
text = when (it) {
|
||||
true -> "${skill.value + 5}"
|
||||
else -> "${skill.value}"
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.levelup.items
|
||||
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.SizeTransform
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.generic__arrow
|
||||
import org.jetbrains.compose.resources.DrawableResource
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
|
||||
|
||||
@Stable
|
||||
data class LevelUpSubCharacteristicUio(
|
||||
val icon: DrawableResource,
|
||||
val base: String,
|
||||
val levelUp: String,
|
||||
val tooltip: TooltipUio,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun LevelUpSubCharacteristic(
|
||||
modifier: Modifier = Modifier,
|
||||
characteristic: LevelUpSubCharacteristicUio?,
|
||||
) {
|
||||
TooltipLayout(
|
||||
modifier = modifier,
|
||||
tooltip = characteristic?.tooltip,
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
if (characteristic?.icon != null) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 4.dp, end = 2.dp)
|
||||
.size(size = MaterialTheme.lwa.size.sheet.subCategory),
|
||||
painter = painterResource(characteristic.icon),
|
||||
contentDescription = null
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 4.dp, end = 2.dp)
|
||||
.size(size = MaterialTheme.lwa.size.sheet.subCategory),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 3.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Thin,
|
||||
text = characteristic?.base ?: "",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = 3.dp),
|
||||
style = MaterialTheme.typography.caption,
|
||||
fontWeight = FontWeight.Thin,
|
||||
text = stringResource(Res.string.generic__arrow),
|
||||
)
|
||||
AnimatedContent(
|
||||
targetState = characteristic?.levelUp ?: "",
|
||||
transitionSpec = {
|
||||
val enter = fadeIn() + slideInVertically { -16 }
|
||||
val exit = fadeOut() + slideOutVertically { 16 }
|
||||
enter togetherWith exit using SizeTransform(clip = false)
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.colorScheme.base.secondary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ import androidx.compose.runtime.LaunchedEffect
|
|||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
|
|
@ -50,6 +51,7 @@ import com.pixelized.desktop.lwa.ui.composable.blur.BlurContent
|
|||
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnack
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController
|
||||
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 lwacharactersheet.composeapp.generated.resources.network__host__label
|
||||
|
|
@ -103,6 +105,7 @@ fun NetworkScreen(
|
|||
) {
|
||||
val screen = LocalScreenController.current
|
||||
val snack = LocalSnackHost.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Surface(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
|
|
@ -148,7 +151,7 @@ fun NetworkScreen(
|
|||
onResetPortChange = viewModel::onResetPortChange,
|
||||
onPortChange = viewModel::onPortChange,
|
||||
onResetHostChange = viewModel::onResetHostChange,
|
||||
onConnect = viewModel::connect,
|
||||
onConnect = { scope.launch { viewModel.connect() } },
|
||||
onDisconnect = viewModel::disconnect,
|
||||
)
|
||||
}
|
||||
|
|
@ -188,6 +191,7 @@ fun NetworkPage(
|
|||
viewModel: NetworkViewModel = koinViewModel(),
|
||||
) {
|
||||
val snack = LocalSnackHost.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
Box(
|
||||
modifier = modifier,
|
||||
|
|
@ -205,7 +209,7 @@ fun NetworkPage(
|
|||
onResetHostChange = viewModel::onResetHostChange,
|
||||
onPortChange = viewModel::onPortChange,
|
||||
onResetPortChange = viewModel::onResetPortChange,
|
||||
onConnect = viewModel::connect,
|
||||
onConnect = { scope.launch { viewModel.connect() } },
|
||||
onDisconnect = viewModel::disconnect,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.network
|
||||
|
||||
import androidx.compose.material.SnackbarDuration
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
|
@ -9,7 +10,6 @@ import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
|||
import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController
|
||||
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
|
@ -20,6 +20,10 @@ import kotlinx.coroutines.flow.launchIn
|
|||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.network__message__action
|
||||
import lwacharactersheet.composeapp.generated.resources.network__require__player_name
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class NetworkViewModel(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
|
|
@ -64,11 +68,13 @@ class NetworkViewModel(
|
|||
)
|
||||
|
||||
init {
|
||||
settingsRepository.settingsFlow().onEach {
|
||||
nameFlow.value = it.playerName
|
||||
hostFlow.value = it.host
|
||||
portFlow.value = it.port
|
||||
}.launchIn(viewModelScope)
|
||||
settingsRepository.settingsFlow()
|
||||
.onEach {
|
||||
nameFlow.value = it.playerName
|
||||
hostFlow.value = it.host
|
||||
portFlow.value = it.port
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
fun onPlayerNameChange(player: String) {
|
||||
|
|
@ -91,7 +97,7 @@ class NetworkViewModel(
|
|||
hostFlow.value = settings.host
|
||||
}
|
||||
|
||||
fun connect() {
|
||||
suspend fun connect() {
|
||||
blurController.show()
|
||||
_isLoading.value = true
|
||||
|
||||
|
|
@ -109,6 +115,19 @@ class NetworkViewModel(
|
|||
)
|
||||
}
|
||||
|
||||
if (nameFlow.value.isBlank()) {
|
||||
_networkError.emit(
|
||||
ErrorSnackUio(
|
||||
message = getString(Res.string.network__require__player_name),
|
||||
action = getString(Res.string.network__message__action),
|
||||
duration = SnackbarDuration.Short,
|
||||
)
|
||||
)
|
||||
blurController.hide()
|
||||
_isLoading.value = false
|
||||
return
|
||||
}
|
||||
|
||||
networkRepository.connect(
|
||||
host = hostFlow.value,
|
||||
port = portFlow.value,
|
||||
|
|
|
|||
|
|
@ -3,20 +3,30 @@ package com.pixelized.desktop.lwa.ui.theme.size
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Stable
|
||||
|
||||
data class LwaSize(
|
||||
val characteristic: DpSize,
|
||||
)
|
||||
val sheet: Sheet,
|
||||
) {
|
||||
@Stable
|
||||
data class Sheet(
|
||||
val subCategory: Dp,
|
||||
val characteristic: DpSize,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun lwaSize(
|
||||
characteristic: DpSize = DpSize(width = 76.dp, height = 110.dp),
|
||||
sheet: LwaSize.Sheet = LwaSize.Sheet(
|
||||
subCategory = 14.dp,
|
||||
characteristic = DpSize(width = 76.dp, height = 110.dp),
|
||||
),
|
||||
) = remember {
|
||||
LwaSize(
|
||||
characteristic = characteristic,
|
||||
sheet = sheet,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.pixelized.desktop.lwa.utils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import coil3.ImageLoader
|
||||
import coil3.compose.setSingletonImageLoaderFactory
|
||||
import coil3.disk.DiskCache
|
||||
import coil3.request.crossfade
|
||||
import com.pixelized.shared.lwa.utils.PathProvider
|
||||
import okio.Path.Companion.toPath
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@Composable
|
||||
fun InstallCoil(
|
||||
pathProvider: PathProvider = koinInject(),
|
||||
crossfade: Boolean,
|
||||
diskCachePath: (PathProvider) -> String,
|
||||
) {
|
||||
setSingletonImageLoaderFactory { context ->
|
||||
ImageLoader.Builder(context)
|
||||
.crossfade(enable = crossfade)
|
||||
.diskCache {
|
||||
DiskCache.Builder()
|
||||
.directory(directory = diskCachePath(pathProvider).toPath())
|
||||
.build()
|
||||
}
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ fun main() {
|
|||
}
|
||||
application {
|
||||
KoinContext {
|
||||
App()
|
||||
LwaApplication()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,16 @@ class PathProvider(
|
|||
}
|
||||
}
|
||||
|
||||
fun imagesStorePath(
|
||||
os: OperatingSystem = this.operatingSystem,
|
||||
app: String = this.appName,
|
||||
): String {
|
||||
return when (os) {
|
||||
OperatingSystem.Windows -> "${storePath(os = os, app = app)}_images\\"
|
||||
OperatingSystem.Macintosh -> "${storePath(os = os, app = app)}_images/"
|
||||
}
|
||||
}
|
||||
|
||||
fun characterStorePath(
|
||||
os: OperatingSystem = this.operatingSystem,
|
||||
app: String = this.appName,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue