Refactor project data to allow server handling.
This commit is contained in:
parent
3c8eecdab5
commit
1e5f0d88ae
58 changed files with 742 additions and 469 deletions
|
|
@ -14,6 +14,8 @@ kotlin {
|
|||
val desktopMain by getting
|
||||
|
||||
commonMain.dependencies {
|
||||
// common
|
||||
implementation(projects.shared)
|
||||
// compose
|
||||
implementation(compose.runtime)
|
||||
implementation(compose.foundation)
|
||||
|
|
@ -26,19 +28,18 @@ kotlin {
|
|||
implementation(libs.androidx.lifecycle.runtime.compose)
|
||||
implementation(libs.androidx.navigation.compose)
|
||||
// injection
|
||||
api(libs.koin.core)
|
||||
implementation(libs.koin.compose)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
// composable component.
|
||||
implementation(libs.coil.compose)
|
||||
implementation(libs.coil.network)
|
||||
// common
|
||||
implementation(projects.shared)
|
||||
// network
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
implementation(libs.ktor.serialization.json)
|
||||
implementation(libs.ktor.client.core)
|
||||
implementation(libs.ktor.client.cio)
|
||||
implementation(libs.ktor.client.okhttp)
|
||||
implementation(libs.ktor.client.websockets)
|
||||
implementation(libs.ktor.client.negotiation)
|
||||
// shell
|
||||
implementation(libs.turtle)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,4 +10,8 @@
|
|||
-keep class kotlinx.coroutines.** { *; }
|
||||
|
||||
# OkHttp comming from COIL.
|
||||
-dontwarn okhttp3.internal.platform.**
|
||||
-dontwarn okhttp3.internal.platform.**
|
||||
|
||||
# Serialization
|
||||
-keep class io.ktor.serialization.kotlinx.json.** { *; }
|
||||
-keep class com.pixelized.shared.lwa.model.** { *; }
|
||||
|
|
@ -44,6 +44,7 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository.Status
|
|||
import com.pixelized.desktop.lwa.ui.navigation.screen.MainNavHost
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.CampaignScreen
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.CharacterSheetMainNavHost
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryPage
|
||||
import com.pixelized.desktop.lwa.ui.theme.LwaTheme
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
@ -53,6 +54,7 @@ import lwacharactersheet.composeapp.generated.resources.network__disconnect__mes
|
|||
import org.jetbrains.compose.resources.getString
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
import org.koin.compose.koinInject
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
val LocalWindowController = compositionLocalOf<WindowController> {
|
||||
error("Local Window Controller is not yet ready")
|
||||
|
|
@ -125,8 +127,8 @@ fun ApplicationScope.App() {
|
|||
}
|
||||
},
|
||||
content = {
|
||||
// MainNavHost()
|
||||
CampaignScreen()
|
||||
MainNavHost()
|
||||
// CampaignScreen()
|
||||
}
|
||||
)
|
||||
NetworkSnackHandler(
|
||||
|
|
|
|||
|
|
@ -1,21 +1,24 @@
|
|||
package com.pixelized.desktop.lwa
|
||||
|
||||
import com.pixelized.desktop.lwa.business.CharacterSheetUseCase
|
||||
import com.pixelized.desktop.lwa.business.ExpressionUseCase
|
||||
import com.pixelized.desktop.lwa.business.RollUseCase
|
||||
import com.pixelized.desktop.lwa.business.SettingsUseCase
|
||||
import com.pixelized.desktop.lwa.business.SkillStepUseCase
|
||||
import com.pixelized.desktop.lwa.business.ExpressionUseCase
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetJsonFactory
|
||||
import com.pixelized.desktop.lwa.parser.dice.DiceParser
|
||||
import com.pixelized.desktop.lwa.parser.expression.ExpressionParser
|
||||
import com.pixelized.desktop.lwa.parser.word.WordParser
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationStore
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetStore
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
|
||||
import com.pixelized.desktop.lwa.repository.settings.SettingsFactory
|
||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationStore
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
||||
import com.pixelized.desktop.lwa.repository.settings.SettingsStore
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDiminishedViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbonViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.CharacterSheetEditFactory
|
||||
|
|
@ -26,32 +29,48 @@ import com.pixelized.desktop.lwa.ui.screen.network.NetworkFactory
|
|||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.roll.RollViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryViewModel
|
||||
import com.pixelized.desktop.lwa.parser.dice.DiceParser
|
||||
import com.pixelized.desktop.lwa.parser.word.WordParser
|
||||
import com.pixelized.desktop.lwa.parser.expression.ExpressionParser
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDiminishedViewModel
|
||||
import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbonViewModel
|
||||
import kotlinx.serialization.json.Json
|
||||
import com.pixelized.shared.lwa.model.campaign.CampaignRepository
|
||||
import com.pixelized.shared.lwa.model.campaign.model.CampaignFactory
|
||||
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.engine.okhttp.OkHttp
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.plugins.websocket.WebSockets
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import org.koin.core.module.dsl.factoryOf
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.dsl.viewModelOf
|
||||
import org.koin.dsl.module
|
||||
|
||||
val moduleDependencies
|
||||
val appModuleDependencies
|
||||
get() = listOf(
|
||||
toolsDependencies,
|
||||
parserDependencies,
|
||||
factoryDependencies,
|
||||
useCaseDependencies,
|
||||
storeDependencies,
|
||||
repositoryDependencies,
|
||||
viewModelDependencies,
|
||||
toolsDependencies,
|
||||
)
|
||||
|
||||
val toolsDependencies
|
||||
get() = module {
|
||||
factory { Json { explicitNulls = false } }
|
||||
single<HttpClientEngine> {
|
||||
OkHttp.create()
|
||||
}
|
||||
single {
|
||||
HttpClient(
|
||||
engine = get()
|
||||
) {
|
||||
install(WebSockets) {
|
||||
pingIntervalMillis = 20_000
|
||||
}
|
||||
install(ContentNegotiation) {
|
||||
json(get())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val storeDependencies
|
||||
|
|
@ -68,17 +87,17 @@ val repositoryDependencies
|
|||
singleOf(::RollHistoryRepository)
|
||||
singleOf(::SettingsRepository)
|
||||
singleOf(::AlterationRepository)
|
||||
singleOf(::CampaignRepository)
|
||||
}
|
||||
|
||||
val factoryDependencies
|
||||
get() = module {
|
||||
factoryOf(::CharacterSheetFactory)
|
||||
factoryOf(::CharacterSheetEditFactory)
|
||||
factoryOf(::CharacterSheetJsonFactory)
|
||||
factoryOf(::NetworkFactory)
|
||||
factoryOf(::SkillFieldFactory)
|
||||
factoryOf(::SkillDescriptionFactory)
|
||||
factoryOf(::SettingsFactory)
|
||||
factoryOf(::CampaignFactory)
|
||||
}
|
||||
|
||||
val viewModelDependencies
|
||||
|
|
@ -106,6 +125,6 @@ val useCaseDependencies
|
|||
factoryOf(::SkillStepUseCase)
|
||||
factoryOf(::RollUseCase)
|
||||
factoryOf(::ExpressionUseCase)
|
||||
factoryOf(::CharacterSheetUseCase)
|
||||
factoryOf(::SettingsUseCase)
|
||||
factoryOf(::CharacterSheetUseCase)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.business
|
||||
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.max
|
||||
|
||||
class CharacterSheetUseCase {
|
||||
|
||||
fun normalize(value: Int): Int {
|
||||
return value - value % 5 // (truncate(value.toFloat() / 5f) * 5f).toInt()
|
||||
}
|
||||
|
||||
fun defaultMovement(): Int = 10
|
||||
|
||||
fun defaultMaxHp(
|
||||
constitution: Int,
|
||||
height: Int,
|
||||
): Int {
|
||||
return (ceil((constitution + height) / 2f).toInt())
|
||||
}
|
||||
|
||||
fun defaultMaxPower(
|
||||
power: Int,
|
||||
): Int {
|
||||
return power
|
||||
}
|
||||
|
||||
fun defaultDamageBonus(
|
||||
strength: Int,
|
||||
height: Int,
|
||||
): String {
|
||||
return defaultDamageBonus(sum = strength + height)
|
||||
}
|
||||
|
||||
fun defaultDamageBonus(
|
||||
sum: Int,
|
||||
): String {
|
||||
return when {
|
||||
sum < 12 -> "-1d6"
|
||||
sum in 12..17 -> "-1d4"
|
||||
sum in 18..22 -> "+0"
|
||||
sum in 23..29 -> "+1d4"
|
||||
sum in 30..39 -> "+1d6"
|
||||
else -> "+2d6"
|
||||
}
|
||||
}
|
||||
|
||||
fun defaultArmor(): Int = 0
|
||||
|
||||
fun defaultLearning(intelligence: Int): Int {
|
||||
return max(0, (intelligence - 10) * 2)
|
||||
}
|
||||
|
||||
fun defaultHpGrow(constitution: Int): Int {
|
||||
return (constitution / 3)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,7 @@ package com.pixelized.desktop.lwa.business
|
|||
import com.pixelized.desktop.lwa.parser.expression.Expression
|
||||
import com.pixelized.desktop.lwa.parser.expression.ExpressionParser
|
||||
import com.pixelized.desktop.lwa.parser.word.Word
|
||||
import com.pixelized.desktop.lwa.repository.alteration.model.FieldAlteration
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.repository
|
||||
|
||||
enum class OperatingSystem(
|
||||
val home: String = System.getProperty("user.home"),
|
||||
) {
|
||||
Windows,
|
||||
Macintosh;
|
||||
|
||||
companion object {
|
||||
val current: OperatingSystem = run {
|
||||
val name = System.getProperty("os.name")
|
||||
when {
|
||||
name.contains(other = "win", ignoreCase = true) -> Windows
|
||||
name.contains(other = "mac", ignoreCase = true) -> Macintosh
|
||||
else -> error("Unsupported operating system: $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun storePath(
|
||||
os: OperatingSystem = OperatingSystem.current,
|
||||
): String {
|
||||
return when (os) {
|
||||
OperatingSystem.Windows -> "${os.home}\\AppData\\Roaming\\Pixelized\\"
|
||||
OperatingSystem.Macintosh -> "${os.home}/Library/Pixelized/"
|
||||
}
|
||||
}
|
||||
|
||||
fun characterStorePath(
|
||||
os: OperatingSystem = OperatingSystem.current,
|
||||
): String {
|
||||
return when (os) {
|
||||
OperatingSystem.Windows -> "${storePath(os = os)}characters\\"
|
||||
OperatingSystem.Macintosh -> "${storePath(os = os)}characters/"
|
||||
}
|
||||
}
|
||||
|
|
@ -4,24 +4,24 @@ import com.pixelized.desktop.lwa.parser.expression.Expression
|
|||
import com.pixelized.desktop.lwa.parser.expression.ExpressionParser
|
||||
import com.pixelized.desktop.lwa.repository.alteration.model.Alteration
|
||||
import com.pixelized.desktop.lwa.repository.alteration.model.AlterationMetadata
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId.ARMOR
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId.DEX
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId.HEI
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId.MOV
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId.STR
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.ACROBATICS_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.AID_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.ATHLETICS_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.BARGAIN_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.COMBAT_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.DISCRETION_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.INTIMIDATION_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.PERCEPTION_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.PERSUASION_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.SPIEL_ID
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId.THROW_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId.ARMOR
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId.DEX
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId.HEI
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId.MOV
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId.STR
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.ACROBATICS_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.AID_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.ATHLETICS_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.BARGAIN_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.COMBAT_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.DISCRETION_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.INTIMIDATION_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.PERCEPTION_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.PERSUASION_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.SPIEL_ID
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CommonSkillId.THROW_ID
|
||||
|
||||
class AlterationStore(
|
||||
private val expressionParser: ExpressionParser,
|
||||
|
|
|
|||
|
|
@ -1,174 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet
|
||||
|
||||
import com.pixelized.desktop.lwa.business.CharacterSheetUseCase
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJsonV1
|
||||
|
||||
class CharacterSheetJsonFactory(
|
||||
private val skillDescriptionFactory: SkillDescriptionFactory,
|
||||
private val characterSheetUseCase: CharacterSheetUseCase,
|
||||
) {
|
||||
|
||||
fun convertToJson(
|
||||
sheet: CharacterSheet,
|
||||
): CharacterSheetJson {
|
||||
val json = CharacterSheetJsonV1(
|
||||
id = sheet.id,
|
||||
name = sheet.name,
|
||||
thumbnail = sheet.thumbnail,
|
||||
portrait = sheet.portrait,
|
||||
strength = sheet.strength,
|
||||
dexterity = sheet.dexterity,
|
||||
constitution = sheet.constitution,
|
||||
height = sheet.height,
|
||||
intelligence = sheet.intelligence,
|
||||
power = sheet.power,
|
||||
charisma = sheet.charisma,
|
||||
movement = if (sheet.overrideMovement) sheet.movement else null,
|
||||
currentHp = sheet.currentHp,
|
||||
maxHp = if (sheet.overrideMaxHp) sheet.maxHp else null,
|
||||
currentPP = sheet.currentPp,
|
||||
maxPP = if (sheet.overrideMaxPP) sheet.maxPp else null,
|
||||
damageBonus = if (sheet.overrideDamageBonus) sheet.damageBonus else null,
|
||||
armor = if (sheet.overrideArmor) sheet.armor else null,
|
||||
learning = if (sheet.overrideLearning) sheet.learning else null,
|
||||
hpGrowf = if (sheet.overrideHpGrow) sheet.hpGrow else null,
|
||||
skills = sheet.commonSkills.map {
|
||||
CharacterSheetJsonV1.Skill(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
description = null,
|
||||
base = it.base,
|
||||
bonus = it.bonus,
|
||||
level = it.level,
|
||||
occupation = it.occupation,
|
||||
used = it.used,
|
||||
)
|
||||
},
|
||||
occupations = sheet.specialSkills.map {
|
||||
CharacterSheetJsonV1.Skill(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
description = it.description,
|
||||
base = it.base,
|
||||
bonus = it.bonus,
|
||||
level = it.level,
|
||||
occupation = it.occupation,
|
||||
used = it.used,
|
||||
)
|
||||
},
|
||||
magics = sheet.magicSkills.map {
|
||||
CharacterSheetJsonV1.Skill(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
description = it.description,
|
||||
base = it.base,
|
||||
bonus = it.bonus,
|
||||
level = it.level,
|
||||
occupation = it.occupation,
|
||||
used = it.used,
|
||||
)
|
||||
},
|
||||
rolls = sheet.actions.map {
|
||||
CharacterSheetJsonV1.Roll(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
roll = it.roll,
|
||||
)
|
||||
},
|
||||
)
|
||||
return json
|
||||
}
|
||||
|
||||
suspend fun convertFromJson(
|
||||
json: CharacterSheetJson,
|
||||
): CharacterSheet {
|
||||
return when (json) {
|
||||
is CharacterSheetJsonV1 -> convertFromV1(json = json)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun convertFromV1(
|
||||
json: CharacterSheetJsonV1,
|
||||
): CharacterSheet = characterSheetUseCase.run {
|
||||
CharacterSheet(
|
||||
id = json.id,
|
||||
name = json.name,
|
||||
portrait = json.portrait,
|
||||
thumbnail = json.thumbnail,
|
||||
strength = json.strength,
|
||||
dexterity = json.dexterity,
|
||||
constitution = json.constitution,
|
||||
height = json.height,
|
||||
intelligence = json.intelligence,
|
||||
power = json.power,
|
||||
charisma = json.charisma,
|
||||
overrideMovement = json.movement != null,
|
||||
movement = json.movement ?: defaultMovement(),
|
||||
currentHp = json.currentHp,
|
||||
overrideMaxHp = json.maxHp != null,
|
||||
maxHp = json.maxHp ?: defaultMaxHp(
|
||||
constitution = json.constitution,
|
||||
height = json.height,
|
||||
),
|
||||
currentPp = json.currentPP,
|
||||
overrideMaxPP = json.maxPP != null,
|
||||
maxPp = json.maxPP ?: defaultMaxPower(power = json.power),
|
||||
overrideDamageBonus = json.damageBonus != null,
|
||||
damageBonus = json.damageBonus ?: defaultDamageBonus(
|
||||
strength = json.strength,
|
||||
height = json.height,
|
||||
),
|
||||
overrideArmor = json.armor != null,
|
||||
armor = json.armor ?: defaultArmor(),
|
||||
overrideLearning = json.learning != null,
|
||||
learning = json.learning ?: defaultLearning(intelligence = json.intelligence),
|
||||
overrideHpGrow = json.hpGrowf != null,
|
||||
hpGrow = json.hpGrowf ?: defaultHpGrow(constitution = json.constitution),
|
||||
commonSkills = json.skills.map {
|
||||
CharacterSheet.Skill(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
description = skillDescriptionFactory.baseSkillDescription(id = json.id),
|
||||
base = it.base,
|
||||
bonus = it.bonus,
|
||||
level = it.level,
|
||||
occupation = it.occupation,
|
||||
used = it.used,
|
||||
)
|
||||
},
|
||||
specialSkills = json.occupations.map {
|
||||
CharacterSheet.Skill(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
description = it.description,
|
||||
base = it.base,
|
||||
bonus = it.bonus,
|
||||
level = it.level,
|
||||
occupation = it.occupation,
|
||||
used = it.used,
|
||||
)
|
||||
},
|
||||
magicSkills = json.magics.map {
|
||||
CharacterSheet.Skill(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
description = it.description,
|
||||
base = it.base,
|
||||
bonus = it.bonus,
|
||||
level = it.level,
|
||||
occupation = it.occupation,
|
||||
used = it.used,
|
||||
)
|
||||
},
|
||||
actions = json.rolls.map {
|
||||
CharacterSheet.Roll(
|
||||
id = it.id,
|
||||
label = it.label,
|
||||
roll = it.roll,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet
|
||||
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
@ -53,11 +53,11 @@ class CharacterSheetRepository(
|
|||
}
|
||||
|
||||
fun save(characterSheet: CharacterSheet) {
|
||||
store.save(sheet = characterSheet)
|
||||
// store.save(sheet = characterSheet)
|
||||
}
|
||||
|
||||
fun delete(id: String) {
|
||||
store.delete(id = id)
|
||||
// store.delete(id = id)
|
||||
}
|
||||
|
||||
fun setDiminishedForCharacter(id: String, diminished: Int) {
|
||||
|
|
@ -65,5 +65,4 @@ class CharacterSheetRepository(
|
|||
this[id] = diminished
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,24 +1,25 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet
|
||||
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson
|
||||
import com.pixelized.desktop.lwa.repository.characterStorePath
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheetJson
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheetJsonFactory
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.serialization.kotlinx.json.json
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
import java.text.Collator
|
||||
|
||||
class CharacterSheetStore(
|
||||
private val factory: CharacterSheetJsonFactory,
|
||||
private val jsonFormatter: Json,
|
||||
private val client: HttpClient,
|
||||
) {
|
||||
private val characterDirectory = File(characterStorePath()).also { it.mkdirs() }
|
||||
private val flow = MutableStateFlow<List<CharacterSheet>>(value = emptyList())
|
||||
|
||||
init {
|
||||
|
|
@ -30,85 +31,22 @@ class CharacterSheetStore(
|
|||
|
||||
fun characterSheetFlow(): StateFlow<List<CharacterSheet>> = flow
|
||||
|
||||
@Throws(
|
||||
CharacterSheetStoreException::class,
|
||||
FileWriteException::class,
|
||||
JsonConversionException::class,
|
||||
)
|
||||
fun save(sheet: CharacterSheet) {
|
||||
// convert the character sheet into json format.
|
||||
val json = try {
|
||||
factory.convertToJson(sheet = sheet).let(jsonFormatter::encodeToString)
|
||||
} catch (exception: Exception) {
|
||||
throw JsonConversionException(root = exception)
|
||||
}
|
||||
// write the character file.
|
||||
try {
|
||||
val file = characterSheetFile(id = sheet.id)
|
||||
file.writeText(
|
||||
text = json,
|
||||
charset = Charsets.UTF_8,
|
||||
)
|
||||
} catch (exception: Exception) {
|
||||
throw FileWriteException(root = exception)
|
||||
}
|
||||
// Update the dataflow.
|
||||
flow.value = flow.value
|
||||
.toMutableList()
|
||||
.also { data ->
|
||||
val index = data.indexOfFirst { it.id == sheet.id }
|
||||
if (index >= 0) {
|
||||
data[index] = sheet
|
||||
} else {
|
||||
data.add(sheet)
|
||||
}
|
||||
}
|
||||
.sortedWith(compareBy(Collator.getInstance()) { it.name })
|
||||
|
||||
}
|
||||
|
||||
fun delete(id: String): Boolean {
|
||||
val file = characterSheetFile(id = id)
|
||||
flow.value = flow.value.toMutableList()
|
||||
.also { data ->
|
||||
data.removeIf { it.id == id }
|
||||
}
|
||||
.sortedBy {
|
||||
it.name
|
||||
}
|
||||
return file.delete()
|
||||
return false
|
||||
}
|
||||
|
||||
@Throws(
|
||||
CharacterSheetStoreException::class,
|
||||
FileReadException::class,
|
||||
JsonConversionException::class,
|
||||
)
|
||||
suspend fun load(): List<CharacterSheet> {
|
||||
return characterDirectory
|
||||
.listFiles()
|
||||
?.mapNotNull { file ->
|
||||
val json = try {
|
||||
file.readText(charset = Charsets.UTF_8)
|
||||
} catch (exception: Exception) {
|
||||
throw FileReadException(root = exception)
|
||||
}
|
||||
// Guard, if the json is blank no character have been save, ignore this file.
|
||||
if (json.isBlank()) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
try {
|
||||
val sheet = jsonFormatter.decodeFromString<CharacterSheetJson>(json)
|
||||
factory.convertFromJson(sheet)
|
||||
} catch (exception: Exception) {
|
||||
throw JsonConversionException(root = exception)
|
||||
}
|
||||
}
|
||||
?.sortedWith(compareBy(Collator.getInstance()) { it.name })
|
||||
?: emptyList()
|
||||
}
|
||||
|
||||
private fun characterSheetFile(id: String): File {
|
||||
return File("${characterStorePath()}${id}.json")
|
||||
val request: List<CharacterSheetJson> = client
|
||||
.get("http://pixelized.freeboxos.fr:16030/characters")
|
||||
.body()
|
||||
val data = request.map {
|
||||
factory.convertFromJson(json = it)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
sealed class CharacterSheetStoreException(root: Exception) : Exception(root)
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet
|
||||
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__acrobatics
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__aid
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__athletics
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__bargain
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__combat
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__discretion
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__dodge
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__empathy
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__grab
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__intimidation
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__perception
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__persuasion
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__search
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__sleight_of_hand
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__spiel
|
||||
import lwacharactersheet.composeapp.generated.resources.tooltip__skills__throw
|
||||
import org.jetbrains.compose.resources.getString
|
||||
|
||||
class SkillDescriptionFactory {
|
||||
|
||||
suspend fun baseSkillDescription(id: String): String? {
|
||||
return when (id) {
|
||||
CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.tooltip__skills__combat)
|
||||
CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.tooltip__skills__dodge)
|
||||
CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.tooltip__skills__grab)
|
||||
CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.tooltip__skills__throw)
|
||||
CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.tooltip__skills__athletics)
|
||||
CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.tooltip__skills__acrobatics)
|
||||
CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.tooltip__skills__perception)
|
||||
CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.tooltip__skills__search)
|
||||
CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.tooltip__skills__empathy)
|
||||
CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.tooltip__skills__persuasion)
|
||||
CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.tooltip__skills__intimidation)
|
||||
CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.tooltip__skills__spiel)
|
||||
CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.tooltip__skills__bargain)
|
||||
CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.tooltip__skills__discretion)
|
||||
CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.tooltip__skills__sleight_of_hand)
|
||||
CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.tooltip__skills__aid)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet.model
|
||||
|
||||
data class CharacterSheet(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val portrait: String?,
|
||||
val thumbnail: String?,
|
||||
// characteristics
|
||||
val strength: Int,
|
||||
val dexterity: Int,
|
||||
val constitution: Int,
|
||||
val height: Int,
|
||||
val intelligence: Int,
|
||||
val power: Int,
|
||||
val charisma: Int,
|
||||
// sub characteristics
|
||||
val overrideMovement: Boolean,
|
||||
val movement: Int,
|
||||
val currentHp: Int,
|
||||
val overrideMaxHp: Boolean,
|
||||
val maxHp: Int,
|
||||
val currentPp: Int,
|
||||
val overrideMaxPP: Boolean,
|
||||
val maxPp: Int,
|
||||
val overrideDamageBonus: Boolean,
|
||||
val damageBonus: String,
|
||||
val overrideArmor: Boolean,
|
||||
val armor: Int,
|
||||
val overrideLearning: Boolean,
|
||||
val learning: Int,
|
||||
val overrideHpGrow: Boolean,
|
||||
val hpGrow: Int,
|
||||
// skills
|
||||
val commonSkills: List<Skill>,
|
||||
val specialSkills: List<Skill>,
|
||||
val magicSkills: List<Skill>,
|
||||
// actions
|
||||
val actions: List<Roll>,
|
||||
) {
|
||||
data class Skill(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val description: String?,
|
||||
val base: String,
|
||||
val bonus: String?,
|
||||
val level: String?,
|
||||
val occupation: Boolean,
|
||||
val used: Boolean,
|
||||
)
|
||||
|
||||
data class Roll(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val roll: String,
|
||||
)
|
||||
|
||||
object CommonSkillId {
|
||||
const val COMBAT_ID = "COMBAT"
|
||||
const val DODGE_ID = "DODGE"
|
||||
const val GRAB_ID = "GRAB"
|
||||
const val THROW_ID = "THROW"
|
||||
const val ATHLETICS_ID = "ATHLETICS"
|
||||
const val ACROBATICS_ID = "ACROBATICS"
|
||||
const val PERCEPTION_ID = "PERCEPTION"
|
||||
const val SEARCH_ID = "SEARCH"
|
||||
const val EMPATHY_ID = "EMPATHY"
|
||||
const val PERSUASION_ID = "PERSUASION"
|
||||
const val INTIMIDATION_ID = "INTIMIDATION"
|
||||
const val SPIEL_ID = "SPIEL"
|
||||
const val BARGAIN_ID = "BARGAIN"
|
||||
const val DISCRETION_ID = "DISCRETION"
|
||||
const val SLEIGHT_OF_HAND_ID = "SLEIGHT_OF_HAND"
|
||||
const val AID_ID = "AID"
|
||||
}
|
||||
|
||||
object CharacteristicId {
|
||||
const val STR = "STR"
|
||||
const val DEX = "DEX"
|
||||
const val CON = "CON"
|
||||
const val HEI = "HEI"
|
||||
const val INT = "INT"
|
||||
const val POW = "POW"
|
||||
const val CHA = "CHA"
|
||||
const val MOV = "MOV"
|
||||
const val HP = "HP"
|
||||
const val PP = "PP"
|
||||
const val DMG = "DMG"
|
||||
const val ARMOR = "ARMOR"
|
||||
const val LB = "LEARNING"
|
||||
const val GHP = "HP_GROW"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
sealed interface CharacterSheetJson
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package com.pixelized.desktop.lwa.repository.characterSheet.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class CharacterSheetJsonV1(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val portrait: String?,
|
||||
val thumbnail: String?,
|
||||
// characteristics
|
||||
val strength: Int,
|
||||
val dexterity: Int,
|
||||
val constitution: Int,
|
||||
val height: Int,
|
||||
val intelligence: Int,
|
||||
val power: Int,
|
||||
val charisma: Int,
|
||||
// sub characteristics
|
||||
val movement: Int?,
|
||||
val currentHp: Int,
|
||||
val maxHp: Int?,
|
||||
val currentPP: Int,
|
||||
val maxPP: Int?,
|
||||
val damageBonus: String?,
|
||||
val armor: Int?,
|
||||
val learning: Int?,
|
||||
val hpGrowf: Int?,
|
||||
// skills
|
||||
val skills: List<Skill>,
|
||||
// occupations
|
||||
val occupations: List<Skill>,
|
||||
// magic skill
|
||||
val magics: List<Skill>,
|
||||
// attack
|
||||
val rolls: List<Roll>,
|
||||
) : CharacterSheetJson {
|
||||
|
||||
@Serializable
|
||||
data class Skill(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val description: String?,
|
||||
val base: String,
|
||||
val bonus: String?,
|
||||
val level: String?,
|
||||
val occupation: Boolean,
|
||||
val used: Boolean,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Roll(
|
||||
val id: String,
|
||||
val label: String,
|
||||
val roll: String,
|
||||
)
|
||||
}
|
||||
|
|
@ -1,16 +1,12 @@
|
|||
package com.pixelized.desktop.lwa.repository.network
|
||||
|
||||
//import com.pixelized.desktop.lwa.repository.network.helper.server
|
||||
//import io.ktor.server.engine.EmbeddedServer
|
||||
//import io.ktor.server.netty.NettyApplicationEngine
|
||||
import com.pixelized.desktop.lwa.repository.network.helper.client
|
||||
import com.pixelized.desktop.lwa.repository.network.helper.connectWebSocket
|
||||
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
|
||||
import com.pixelized.desktop.lwa.utils.extention.decodeFromFrame
|
||||
import com.pixelized.desktop.lwa.utils.extention.encodeToFrame
|
||||
import com.pixelized.server.lwa.SERVER_PORT
|
||||
import com.pixelized.server.lwa.protocol.Message
|
||||
import com.pixelized.server.lwa.protocol.MessageType
|
||||
import com.pixelized.shared.lwa.SERVER_PORT
|
||||
import com.pixelized.shared.lwa.protocol.Message
|
||||
import com.pixelized.shared.lwa.protocol.MessageType
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.websocket.Frame
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
@ -25,10 +21,9 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
typealias Client = HttpClient
|
||||
|
||||
class NetworkRepository(
|
||||
private val settingsRepository: SettingsRepository,
|
||||
private val client: HttpClient,
|
||||
) {
|
||||
companion object {
|
||||
const val DEFAULT_PORT = SERVER_PORT
|
||||
|
|
@ -37,7 +32,6 @@ class NetworkRepository(
|
|||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
private var networkJob: Job? = null
|
||||
private var client: Client? = null
|
||||
|
||||
private val outgoingMessageBuffer = MutableSharedFlow<Message>()
|
||||
private val incomingMessageBuffer = MutableSharedFlow<Message>()
|
||||
|
|
@ -46,7 +40,6 @@ class NetworkRepository(
|
|||
private val _status = MutableStateFlow(Status.DISCONNECTED)
|
||||
val status: StateFlow<Status> get() = _status
|
||||
|
||||
|
||||
fun connect(
|
||||
host: String,
|
||||
port: Int,
|
||||
|
|
@ -54,12 +47,10 @@ class NetworkRepository(
|
|||
onFailure: (Exception) -> Unit = { },
|
||||
onClose: () -> Unit = { },
|
||||
) {
|
||||
client = client()
|
||||
|
||||
networkJob?.cancel()
|
||||
networkJob = scope.launch {
|
||||
try {
|
||||
client?.connectWebSocket(host = host, port = port) {
|
||||
client.connectWebSocket(host = host, port = port) {
|
||||
_status.value = Status.CONNECTED
|
||||
onConnect()
|
||||
|
||||
|
|
@ -93,7 +84,7 @@ class NetworkRepository(
|
|||
fun disconnect() {
|
||||
networkJob?.cancel()
|
||||
scope.launch {
|
||||
client?.close()
|
||||
client.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +1,15 @@
|
|||
package com.pixelized.desktop.lwa.repository.network.helper
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.engine.cio.CIO
|
||||
import io.ktor.client.plugins.websocket.DefaultClientWebSocketSession
|
||||
import io.ktor.client.plugins.websocket.WebSockets
|
||||
import io.ktor.client.plugins.websocket.webSocket
|
||||
import io.ktor.http.HttpMethod
|
||||
|
||||
// https://ktor.io/docs/client-websockets.html#handle-session
|
||||
fun client(): HttpClient {
|
||||
val client = HttpClient(CIO) {
|
||||
install(WebSockets) {
|
||||
pingIntervalMillis = 20_000
|
||||
}
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
suspend fun HttpClient.connectWebSocket(
|
||||
host: String,
|
||||
port: Int,
|
||||
block: suspend DefaultClientWebSocketSession.() -> Unit
|
||||
block: suspend DefaultClientWebSocketSession.() -> Unit,
|
||||
) {
|
||||
webSocket(
|
||||
method = HttpMethod.Get,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package com.pixelized.desktop.lwa.repository.roll_history
|
||||
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.server.lwa.protocol.MessageType
|
||||
import com.pixelized.server.lwa.protocol.roll.RollMessage
|
||||
import com.pixelized.shared.lwa.protocol.MessageType
|
||||
import com.pixelized.shared.lwa.protocol.roll.RollMessage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.pixelized.desktop.lwa.repository.settings
|
|||
import com.pixelized.desktop.lwa.business.SettingsUseCase
|
||||
import com.pixelized.desktop.lwa.repository.settings.model.Settings
|
||||
import com.pixelized.desktop.lwa.repository.settings.model.SettingsJson
|
||||
import com.pixelized.desktop.lwa.repository.storePath
|
||||
import com.pixelized.shared.lwa.storePath
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.pixelized.desktop.lwa.ui.navigation.screen
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
|
|
@ -9,6 +10,8 @@ import androidx.navigation.compose.rememberNavController
|
|||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.MainDestination
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableMainPage
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.composableNetworkPage
|
||||
import com.pixelized.desktop.lwa.ui.screen.network.NetworkViewModel
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
val LocalScreenController = compositionLocalOf<NavHostController> {
|
||||
error("MainNavHost controller is not yet ready")
|
||||
|
|
@ -18,7 +21,12 @@ val LocalScreenController = compositionLocalOf<NavHostController> {
|
|||
fun MainNavHost(
|
||||
controller: NavHostController = rememberNavController(),
|
||||
startDestination: String = MainDestination.navigationRoute(),
|
||||
networkViewModel: NetworkViewModel = koinViewModel(),
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
networkViewModel.connect()
|
||||
}
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalScreenController provides controller,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -83,9 +83,7 @@ fun CampaignScreen(
|
|||
},
|
||||
leftOverlay = {
|
||||
PlayerRibbon(
|
||||
modifier = Modifier
|
||||
.padding(all = 8.dp)
|
||||
.fillMaxHeight(),
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
onCharacter = {
|
||||
characterDetailViewModel.showCharacter(id = it)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ private fun Background(
|
|||
) {
|
||||
Surface(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
color = MaterialTheme.lwa.color.elevatedSurface,
|
||||
color = MaterialTheme.lwa.colorScheme.elevatedSurface,
|
||||
) {
|
||||
// Image(
|
||||
// modifier = Modifier.fillMaxSize().drawWithContent {
|
||||
|
|
@ -200,7 +200,7 @@ private fun CharacterHeader(
|
|||
) {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_close_24dp),
|
||||
tint = MaterialTheme.lwa.color.base.primary,
|
||||
tint = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
|
|
@ -220,7 +220,7 @@ private fun CharacterHeader(
|
|||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.color.base.primary,
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = dynDetail.value.hp,
|
||||
)
|
||||
|
|
@ -243,7 +243,7 @@ private fun CharacterHeader(
|
|||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
style = MaterialTheme.typography.h6,
|
||||
color = MaterialTheme.lwa.color.base.primary,
|
||||
color = MaterialTheme.lwa.colorScheme.base.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
text = dynDetail.value.pp,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon
|
|||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
|
|
@ -20,13 +19,13 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.FilterQuality
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil3.compose.AsyncImage
|
||||
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_heart_24dp
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_water_drop_24dp
|
||||
|
|
@ -42,19 +41,15 @@ data class PlayerPortraitUio(
|
|||
val maxPp: Int,
|
||||
)
|
||||
|
||||
object PlayerPortrait {
|
||||
object Default {
|
||||
val size = DpSize(96.dp, 128.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PlayerPortrait(
|
||||
modifier: Modifier = Modifier,
|
||||
size: DpSize = PlayerPortrait.Default.size,
|
||||
size: DpSize,
|
||||
character: PlayerPortraitUio,
|
||||
onCharacter: (id: String) -> Unit,
|
||||
) {
|
||||
val colorScheme = MaterialTheme.lwa.colorScheme
|
||||
|
||||
DecoratedBox(
|
||||
modifier = modifier
|
||||
.size(size = size)
|
||||
|
|
@ -76,11 +71,11 @@ fun PlayerPortrait(
|
|||
drawRect(
|
||||
brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
Color.Black.copy(alpha = 0.0f),
|
||||
Color.Black.copy(alpha = 0.0f),
|
||||
Color.Black.copy(alpha = 0.0f),
|
||||
Color.Black.copy(alpha = 0.5f),
|
||||
Color.Black.copy(alpha = 0.8f),
|
||||
colorScheme.elevatedSurface.copy(alpha = 0.0f),
|
||||
colorScheme.elevatedSurface.copy(alpha = 0.0f),
|
||||
colorScheme.elevatedSurface.copy(alpha = 0.0f),
|
||||
colorScheme.elevatedSurface.copy(alpha = 0.5f),
|
||||
colorScheme.elevatedSurface.copy(alpha = 0.8f),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,28 +9,45 @@ import androidx.compose.animation.core.spring
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.PointerMatcher
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.onClick
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Shadow
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.PointerButton
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
|
||||
@Stable
|
||||
data class PlayerPortraitRollUio(
|
||||
val characterId: String,
|
||||
val value: Int?,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class PlayerPortraitRollAnimation(
|
||||
val alpha: Animatable<Float, AnimationVector1D> = Animatable(0f),
|
||||
|
|
@ -38,13 +55,19 @@ data class PlayerPortraitRollAnimation(
|
|||
val scale: Animatable<Float, AnimationVector1D> = Animatable(1f),
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun PlayerPortraitRoll(
|
||||
modifier: Modifier = Modifier,
|
||||
value: Int?,
|
||||
size: DpSize,
|
||||
value: PlayerPortraitRollUio?,
|
||||
onLeftClick: (PlayerPortraitRollUio) -> Unit,
|
||||
onRightClick: (PlayerPortraitRollUio) -> Unit,
|
||||
) {
|
||||
AnimatedContent(
|
||||
modifier = modifier.graphicsLayer { clip = false },
|
||||
modifier = modifier
|
||||
.size(size = size)
|
||||
.graphicsLayer { clip = false },
|
||||
targetState = value,
|
||||
transitionSpec = {
|
||||
val enter = fadeIn()
|
||||
|
|
@ -61,33 +84,41 @@ fun PlayerPortraitRoll(
|
|||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
when (it) {
|
||||
null -> Unit
|
||||
else -> {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
this.alpha = 0.8f
|
||||
this.rotationZ = animation.rotation.value
|
||||
}
|
||||
.size(48.dp),
|
||||
painter = painterResource(Res.drawable.ic_d20_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.h5.copy(
|
||||
shadow = Shadow(
|
||||
color = MaterialTheme.colors.surface,
|
||||
offset = Offset.Zero,
|
||||
blurRadius = 8f,
|
||||
)
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
text = it.toString()
|
||||
)
|
||||
}
|
||||
if (it != null) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.graphicsLayer {
|
||||
this.alpha = 0.8f
|
||||
this.rotationZ = animation.rotation.value
|
||||
}
|
||||
.fillMaxWidth()
|
||||
.aspectRatio(1f)
|
||||
.padding(all = 8.dp)
|
||||
.clip(shape = CircleShape)
|
||||
.onClick(
|
||||
matcher = PointerMatcher.mouse(PointerButton.Secondary),
|
||||
onClick = { onRightClick(it) },
|
||||
).clickable {
|
||||
onLeftClick(it)
|
||||
}
|
||||
.padding(all = 8.dp),
|
||||
painter = painterResource(Res.drawable.ic_d20_24dp),
|
||||
tint = MaterialTheme.colors.primary,
|
||||
contentDescription = null,
|
||||
)
|
||||
Text(
|
||||
style = MaterialTheme.typography.h5.copy(
|
||||
shadow = Shadow(
|
||||
color = MaterialTheme.colors.surface,
|
||||
offset = Offset.Zero,
|
||||
blurRadius = 8f,
|
||||
)
|
||||
),
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
textAlign = TextAlign.Center,
|
||||
color = MaterialTheme.colors.onSurface,
|
||||
text = it.value.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,36 @@
|
|||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
object PlayerRibbon {
|
||||
object Default {
|
||||
val size = DpSize(96.dp, 128.dp)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PlayerRibbon(
|
||||
modifier: Modifier = Modifier,
|
||||
playerRibbonViewModel: PlayerRibbonViewModel = koinViewModel(),
|
||||
padding: PaddingValues = PaddingValues(all = 8.dp),
|
||||
onCharacter: (id: String) -> Unit,
|
||||
) {
|
||||
val characters = playerRibbonViewModel.characters.collectAsState()
|
||||
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
contentPadding = padding,
|
||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
||||
) {
|
||||
items(
|
||||
|
|
@ -29,15 +39,19 @@ fun PlayerRibbon(
|
|||
) {
|
||||
Row {
|
||||
PlayerPortrait(
|
||||
size = PlayerRibbon.Default.size,
|
||||
character = it,
|
||||
onCharacter = onCharacter,
|
||||
)
|
||||
PlayerPortraitRoll(
|
||||
modifier = Modifier.size(
|
||||
width = 64.dp,
|
||||
height = PlayerPortrait.Default.size.height
|
||||
),
|
||||
size = PlayerRibbon.Default.size,
|
||||
value = playerRibbonViewModel.roll(characterId = it.id).value,
|
||||
onRightClick = {
|
||||
playerRibbonViewModel.onPortraitRollRightClick(characterId = it.characterId)
|
||||
},
|
||||
onLeftClick = {
|
||||
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@ package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
|
|
@ -38,30 +37,26 @@ class PlayerRibbonViewModel(
|
|||
initialValue = emptyList()
|
||||
)
|
||||
|
||||
private val _rolls: HashMap<String, Int?> = hashMapOf()
|
||||
val rolls: StateFlow<Map<String, Int?>> = rollHistoryRepository.rolls
|
||||
.map {
|
||||
_rolls[it.characterId] = it.rollValue
|
||||
_rolls
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.Eagerly,
|
||||
initialValue = emptyMap()
|
||||
)
|
||||
private val rolls = hashMapOf<String, MutableState<PlayerPortraitRollUio?>>()
|
||||
|
||||
@Composable
|
||||
@Stable
|
||||
fun roll(characterId: String): State<Int?> {
|
||||
val state = rememberSaveable(characterId) {
|
||||
mutableStateOf<Int?>(null)
|
||||
}
|
||||
fun roll(characterId: String): State<PlayerPortraitRollUio?> {
|
||||
val state = rolls.getOrPut(characterId) { mutableStateOf(null) }
|
||||
LaunchedEffect(characterId) {
|
||||
rollHistoryRepository.rolls.collect {
|
||||
if (it.characterId == characterId) {
|
||||
state.value = it.rollValue
|
||||
state.value = PlayerPortraitRollUio(
|
||||
characterId = characterId,
|
||||
value = it.rollValue,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
fun onPortraitRollRightClick(characterId: String) {
|
||||
rolls[characterId]?.value = null
|
||||
}
|
||||
}
|
||||
|
|
@ -3,9 +3,8 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail
|
|||
import com.pixelized.desktop.lwa.business.ExpressionUseCase
|
||||
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio
|
||||
import com.pixelized.desktop.lwa.repository.alteration.model.FieldAlteration
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Node
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
|
|
@ -42,7 +41,6 @@ import org.jetbrains.compose.resources.getString
|
|||
class CharacterSheetFactory(
|
||||
private val skillUseCase: ExpressionUseCase,
|
||||
private val expressionUseCase: ExpressionUseCase,
|
||||
private val skillDescriptionFactory: SkillDescriptionFactory,
|
||||
) {
|
||||
|
||||
suspend fun convertToUio(
|
||||
|
|
@ -213,7 +211,7 @@ class CharacterSheetFactory(
|
|||
skill = skill,
|
||||
alterations = alterations[skill.id].sum(),
|
||||
),
|
||||
tooltips = skillDescriptionFactory.baseSkillDescription(id = skill.id)?.let {
|
||||
tooltips = skill.description?.let {
|
||||
TooltipUio(
|
||||
title = skill.label,
|
||||
description = it,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetDestination
|
||||
import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.DiminishedStatDialogUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.StatChangeDialogUio
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.preview
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet.CharacteristicId
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import com.pixelized.desktop.lwa.business.CharacterSheetUseCase
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.occupation
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillFieldUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleFieldUio
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase
|
||||
import lwacharactersheet.composeapp.generated.resources.Res
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__action_label
|
||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label
|
||||
|
|
@ -54,9 +53,8 @@ import java.util.UUID
|
|||
import kotlin.math.max
|
||||
|
||||
class CharacterSheetEditFactory(
|
||||
private val characterSheetUseCase: CharacterSheetUseCase,
|
||||
private val skillFieldFactory: SkillFieldFactory,
|
||||
private val skillDescriptionFactory: SkillDescriptionFactory,
|
||||
private val characterSheetUseCase: CharacterSheetUseCase,
|
||||
) {
|
||||
suspend fun updateCharacterSheet(
|
||||
currentSheet: CharacterSheet?,
|
||||
|
|
@ -119,7 +117,7 @@ class CharacterSheetEditFactory(
|
|||
CharacterSheet.Skill(
|
||||
id = editedSkill.id,
|
||||
label = editedSkill.label,
|
||||
description = skillDescriptionFactory.baseSkillDescription(editedSkill.id),
|
||||
description = currentSkill?.description,
|
||||
base = "${editedSkill.base.value}",
|
||||
bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() },
|
||||
level = editedSkill.level.value.value.takeIf { it.isNotBlank() },
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import androidx.compose.runtime.State
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetEditDestination
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.ui.navigation.screen.destination.CharacterSheetEditDestination
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.lordcodes.turtle.shellRun
|
||||
import com.pixelized.desktop.lwa.repository.OperatingSystem
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||
import com.pixelized.desktop.lwa.repository.storePath
|
||||
import com.pixelized.desktop.lwa.utils.extention.collectAsState
|
||||
import com.pixelized.shared.lwa.OperatingSystem
|
||||
import com.pixelized.shared.lwa.storePath
|
||||
|
||||
class MainPageViewModel(
|
||||
repository: CharacterSheetRepository,
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ import androidx.compose.animation.core.spring
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.pixelized.desktop.lwa.business.SkillStepUseCase
|
||||
import com.pixelized.desktop.lwa.business.ExpressionUseCase
|
||||
import com.pixelized.desktop.lwa.business.SkillStepUseCase
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
|
||||
import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio
|
||||
import com.pixelized.desktop.lwa.ui.screen.roll.DifficultyUio.Difficulty
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.delay
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import androidx.compose.runtime.mutableStateOf
|
|||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
|
||||
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
|
||||
import com.pixelized.shared.lwa.model.characterSheet.model.CharacterSheet
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
|
@ -28,7 +28,8 @@ class RollHistoryViewModel(
|
|||
add(
|
||||
index = 0,
|
||||
element = RollHistoryItemUio(
|
||||
character = sheets.firstOrNull { it.id == content.characterId }?.name ?: "",
|
||||
character = sheets.firstOrNull { it.id == content.characterId }?.name
|
||||
?: "",
|
||||
skillLabel = content.skillLabel,
|
||||
rollDifficulty = content.rollDifficulty,
|
||||
resultLabel = content.resultLabel,
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ val MaterialTheme.lwa: LwaTheme
|
|||
|
||||
@Stable
|
||||
data class LwaTheme(
|
||||
val color: LwaColorTheme,
|
||||
val colorScheme: LwaColorTheme,
|
||||
)
|
||||
|
||||
@Composable
|
||||
|
|
@ -30,7 +30,7 @@ fun LwaTheme(
|
|||
val lwaColorTheme = darkLwaColorTheme()
|
||||
val theme = remember {
|
||||
LwaTheme(
|
||||
color = lwaColorTheme,
|
||||
colorScheme = lwaColorTheme,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.pixelized.desktop.lwa.utils.extention
|
||||
|
||||
import com.pixelized.server.lwa.protocol.Message
|
||||
import com.pixelized.shared.lwa.protocol.Message
|
||||
import io.ktor.websocket.Frame
|
||||
import io.ktor.websocket.readText
|
||||
import kotlinx.serialization.json.Json
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
package com.pixelized.desktop.lwa
|
||||
|
||||
import androidx.compose.ui.window.application
|
||||
import com.pixelized.shared.lwa.sharedModuleDependencies
|
||||
import org.koin.compose.KoinContext
|
||||
import org.koin.core.context.loadKoinModules
|
||||
import org.koin.core.context.startKoin
|
||||
import javax.swing.UIManager
|
||||
|
||||
fun main() {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
|
||||
startKoin {
|
||||
modules(modules = moduleDependencies)
|
||||
modules(modules = sharedModuleDependencies + appModuleDependencies)
|
||||
}
|
||||
application {
|
||||
KoinContext {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue