From 9f0198ce5316bf7762cf2a527d5491d1a8c731ac Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Thu, 11 Dec 2025 11:02:35 +0100 Subject: [PATCH] Add static resource managment to (image) to the client. --- .../com/pixelized/desktop/lwa/Module.kt | 8 ++-- .../resources/ImageResourcesRepository.kt | 6 +-- .../repository/settings/SettingsFactory.kt | 4 +- .../repository/settings/SettingsRepository.kt | 4 +- .../lwa/repository/settings/SettingsStore.kt | 4 +- .../composable/image/ImagerModelConverter.kt | 25 ---------- .../lwa/ui/composable/image/LwaAsyncImage.kt | 3 +- .../screen/campaign/chatbox/CampaignChat.kt | 4 +- .../ui/screen/settings/SettingsViewModel.kt | 6 +-- .../desktop/lwa/usecase/ImagerModelLogic.kt | 46 +++++++++++++++++++ .../{SettingsUseCase.kt => SettingsLogic.kt} | 2 +- .../com/pixelized/server/lwa/server/Server.kt | 1 - 12 files changed, 67 insertions(+), 46 deletions(-) delete mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/ImagerModelConverter.kt create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/ImagerModelLogic.kt rename composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/{SettingsUseCase.kt => SettingsLogic.kt} (96%) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt index 98bf693..91ab3fc 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt @@ -34,7 +34,7 @@ import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogFa import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogViewModel import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogFactory import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel -import com.pixelized.desktop.lwa.ui.composable.image.ImagerModelConverter +import com.pixelized.desktop.lwa.usecase.ImagerModelLogic import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlayViewModel import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel import com.pixelized.desktop.lwa.ui.screen.admin.AdminViewModel @@ -77,7 +77,7 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.network.NetworkViewM 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.settings.SettingsViewModel -import com.pixelized.desktop.lwa.usecase.SettingsUseCase +import com.pixelized.desktop.lwa.usecase.SettingsLogic import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory import com.pixelized.shared.lwa.utils.PathProvider import io.ktor.client.HttpClient @@ -122,7 +122,7 @@ val toolsDependencies single { PathProvider(appName = "LwaClient") } - singleOf(::ImagerModelConverter) + singleOf(::ImagerModelLogic) } val storeDependencies @@ -218,6 +218,6 @@ val viewModelDependencies val useCaseDependencies get() = module { - factoryOf(::SettingsUseCase) + factoryOf(::SettingsLogic) factoryOf(::GMActionUseCase) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/resources/ImageResourcesRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/resources/ImageResourcesRepository.kt index 686ec62..ef54e01 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/resources/ImageResourcesRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/resources/ImageResourcesRepository.kt @@ -2,7 +2,7 @@ package com.pixelized.desktop.lwa.repository.resources import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.toComposeImageBitmap -import com.pixelized.desktop.lwa.ui.composable.image.ImagerModelConverter +import com.pixelized.desktop.lwa.usecase.ImagerModelLogic import io.ktor.client.HttpClient import io.ktor.client.request.get import io.ktor.client.statement.readRawBytes @@ -10,11 +10,11 @@ import org.jetbrains.skia.Image class ImageResourcesRepository( private val httpClient: HttpClient, - private val googleImageConverter: ImagerModelConverter, + private val imageConverter: ImagerModelLogic, ) { suspend fun load(url: String): ImageBitmap { try { - val unwrapUri = googleImageConverter.unwrap(model = url) + val unwrapUri = imageConverter.unwrap(model = url) val byteArray = httpClient.get(unwrapUri).readRawBytes() val skiaImage = Image.makeFromEncoded(byteArray) return skiaImage.toComposeImageBitmap() diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt index f9b4f03..0dfc724 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsFactory.kt @@ -4,11 +4,11 @@ import com.pixelized.desktop.lwa.repository.settings.model.Settings import com.pixelized.desktop.lwa.repository.settings.model.SettingsJson import com.pixelized.desktop.lwa.repository.settings.model.SettingsJsonV1 import com.pixelized.desktop.lwa.repository.settings.model.SettingsJsonV2 -import com.pixelized.desktop.lwa.usecase.SettingsUseCase +import com.pixelized.desktop.lwa.usecase.SettingsLogic class SettingsFactory( - private val useCase: SettingsUseCase, + private val useCase: SettingsLogic, ) { fun convertToJson( settings: Settings, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsRepository.kt index 07e1c68..daf39bd 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsRepository.kt @@ -1,12 +1,12 @@ package com.pixelized.desktop.lwa.repository.settings import com.pixelized.desktop.lwa.repository.settings.model.Settings -import com.pixelized.desktop.lwa.usecase.SettingsUseCase +import com.pixelized.desktop.lwa.usecase.SettingsLogic import kotlinx.coroutines.flow.StateFlow class SettingsRepository( private val store: SettingsStore, - private val useCase: SettingsUseCase, + private val useCase: SettingsLogic, ) { fun settingsFlow(): StateFlow = store.settingsFlow diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsStore.kt index 2bfc10f..e58679b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsStore.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/settings/SettingsStore.kt @@ -2,7 +2,7 @@ package com.pixelized.desktop.lwa.repository.settings import com.pixelized.desktop.lwa.repository.settings.model.Settings import com.pixelized.desktop.lwa.repository.settings.model.SettingsJson -import com.pixelized.desktop.lwa.usecase.SettingsUseCase +import com.pixelized.desktop.lwa.usecase.SettingsLogic import com.pixelized.shared.lwa.utils.PathProvider import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -13,7 +13,7 @@ import java.io.File class SettingsStore( private val pathProvider: PathProvider, private val factory: SettingsFactory, - private val useCase: SettingsUseCase, + private val useCase: SettingsLogic, private val jsonFormatter: Json, ) { private val _settingsFlow = MutableStateFlow(value = useCase.defaultSettings()) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/ImagerModelConverter.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/ImagerModelConverter.kt deleted file mode 100644 index 83ff6f8..0000000 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/ImagerModelConverter.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.pixelized.desktop.lwa.ui.composable.image - -class ImagerModelConverter { - - val googleDriveUrlRegex = Regex("""drive\.google\.com/file/d/([^/]*)""") - val workingGoogleDriveUri = "https://drive.google.com/uc?export=view&id=" - - fun convert( - model: Any?, - ): Any? { - return when (model) { - is String -> unwrap(model = model) - else -> model - } - } - - fun unwrap( - model: String, - ): String { - return googleDriveUrlRegex.find(model)?.let { - val id = it.groupValues.getOrNull(1) - "$workingGoogleDriveUri$id" - } ?: model - } -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/LwaAsyncImage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/LwaAsyncImage.kt index 5ea6cae..279a6e6 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/LwaAsyncImage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/image/LwaAsyncImage.kt @@ -11,12 +11,13 @@ import androidx.compose.ui.layout.ContentScale import coil3.compose.AsyncImage import coil3.compose.AsyncImagePainter.Companion.DefaultTransform import coil3.compose.AsyncImagePainter.State +import com.pixelized.desktop.lwa.usecase.ImagerModelLogic import org.koin.compose.koinInject @Composable fun LwaAsyncImage( model: Any?, - modelConverter: ImagerModelConverter? = koinInject(), + modelConverter: ImagerModelLogic? = koinInject(), contentDescription: String?, modifier: Modifier = Modifier, transform: (State) -> State = DefaultTransform, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chatbox/CampaignChat.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chatbox/CampaignChat.kt index f4c505a..00df24d 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chatbox/CampaignChat.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/chatbox/CampaignChat.kt @@ -52,7 +52,7 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.chatbox.messages.RollTextMes import com.pixelized.desktop.lwa.ui.screen.campaign.chatbox.messages.RollTextMessageUio import com.pixelized.desktop.lwa.ui.screen.campaign.chatbox.messages.TextMessage import com.pixelized.desktop.lwa.ui.theme.lwa -import com.pixelized.desktop.lwa.usecase.SettingsUseCase +import com.pixelized.desktop.lwa.usecase.SettingsLogic import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.ic_more_down_24dp import org.jetbrains.compose.resources.painterResource @@ -64,7 +64,7 @@ data class ChatSettingsUio( val autoScroll: Boolean, ) { companion object { - fun default() = with(SettingsUseCase().defaultSettings()) { + fun default() = with(SettingsLogic().defaultSettings()) { ChatSettingsUio( show = chat.showChat, autoScroll = chat.autoScrollChat, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt index 42fd420..d050c55 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/settings/SettingsViewModel.kt @@ -8,7 +8,7 @@ import com.pixelized.desktop.lwa.repository.settings.SettingsRepository import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingNumberItemUio import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingSectionUio import com.pixelized.desktop.lwa.ui.screen.settings.composable.SettingToggleItemUio -import com.pixelized.desktop.lwa.usecase.SettingsUseCase +import com.pixelized.desktop.lwa.usecase.SettingsLogic import kotlinx.coroutines.launch import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.ic_fan_focus_24dp @@ -29,7 +29,7 @@ import lwacharactersheet.composeapp.generated.resources.settings__player_portrai class SettingsViewModel( private val settingsRepository: SettingsRepository, - private val settingsUseCase: SettingsUseCase, + private val settingsLogic: SettingsLogic, ) : ViewModel() { private val settings = settingsRepository.settingsFlow() private val booleanStates = hashMapOf>() @@ -132,7 +132,7 @@ class SettingsViewModel( fun onReset() { val current = settingsRepository.settings() settingsRepository.update( - settings = settingsUseCase.defaultSettings().copy( + settings = settingsLogic.defaultSettings().copy( playerName = current.playerName, ) ) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/ImagerModelLogic.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/ImagerModelLogic.kt new file mode 100644 index 0000000..6a7d159 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/ImagerModelLogic.kt @@ -0,0 +1,46 @@ +package com.pixelized.desktop.lwa.usecase + +import com.pixelized.desktop.lwa.repository.settings.SettingsRepository +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn + +class ImagerModelLogic( + settingsRepo: SettingsRepository, // not sure about those import into a Logic class. + settingsLogic: SettingsLogic, +) { + val googleDriveUrlRegex = Regex("""drive\.google\.com/file/d/([^/]*)""") + val workingGoogleDriveUri = "https://drive.google.com/uc?export=view&id=" + + val localUrlRegex = Regex("""^/resources/.*$""") + val workingLocalUrl = settingsRepo.settingsFlow() + .map { it.network.root } + .stateIn( + scope = CoroutineScope(Dispatchers.IO + Job()), + started = SharingStarted.Eagerly, + initialValue = settingsLogic.defaultSettings(), + ) + + fun convert( + model: Any?, + ): Any? { + return when (model) { + is String -> unwrap(model = model) + else -> model + } + } + + fun unwrap( + model: String, + ): String { + return googleDriveUrlRegex.find(model)?.let { + val id = it.groupValues.getOrNull(1) + "$workingGoogleDriveUri$id" + } ?: localUrlRegex.find(model)?.let { + "${workingLocalUrl.value}$model" + } ?: model + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsLogic.kt similarity index 96% rename from composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt rename to composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsLogic.kt index d4e325b..730f74d 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsUseCase.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/usecase/SettingsLogic.kt @@ -2,7 +2,7 @@ package com.pixelized.desktop.lwa.usecase import com.pixelized.desktop.lwa.repository.settings.model.Settings -class SettingsUseCase { +class SettingsLogic { fun defaultSettings(): Settings = Settings( playerName = "", diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt index b279a0e..af5daae 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/Server.kt @@ -148,7 +148,6 @@ class LocalServer { staticFiles( remotePath = "/resources", dir = File(pathProvider.resourcesPath()), - index = null, ) route(path = "/campaign") { get(