Add koin dependencies injections.

This commit is contained in:
Thomas Andres Gomez 2024-11-15 21:18:45 +01:00
parent f459877d55
commit 7fc99f5799
21 changed files with 181 additions and 74 deletions

View file

@ -15,6 +15,7 @@ kotlin {
val desktopMain by getting
commonMain.dependencies {
// compose
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
@ -24,6 +25,11 @@ kotlin {
implementation(libs.androidx.lifecycle.viewmodel)
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)
// network.
implementation(libs.kotlinx.serialization.json)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.cio)

View file

@ -59,6 +59,8 @@
<string name="character_sheet_edit__magic__add_action">Ajouter une compétence magique</string>
<string name="character_sheet__diminished__label">État diminuer</string>
<string name="character_sheet__edit__label">Modifier</string>
<string name="character_sheet__delete__label">Supprimer</string>
<string name="character_sheet__characteristics__str">Force</string>
<string name="character_sheet__characteristics__dex">Dextérité</string>
<string name="character_sheet__characteristics__con">Constitution</string>

View file

@ -46,6 +46,7 @@ import lwacharactersheet.composeapp.generated.resources.network__connect__messag
import lwacharactersheet.composeapp.generated.resources.network__disconnect__message
import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.ui.tooling.preview.Preview
import org.koin.compose.koinInject
val LocalWindowController = compositionLocalOf<WindowController> {
error("Local Window Controller is not yet ready")
@ -155,10 +156,11 @@ private fun WindowsHandler(
private fun NetworkSnackHandler(
snack: SnackbarHostState,
) {
val networkRepository = koinInject<NetworkRepository>()
LaunchedEffect(Unit) {
launch {
var ignoreInitial = true
NetworkRepository.status.collect {
networkRepository.status.collect {
if (ignoreInitial) {
ignoreInitial = false
} else {

View file

@ -0,0 +1,51 @@
package com.pixelized.desktop.lwa
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetStore
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetFactory
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetViewModel
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditViewModel
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditFactory
import com.pixelized.desktop.lwa.screen.main.MainPageViewModel
import com.pixelized.desktop.lwa.screen.network.NetworkFactory
import com.pixelized.desktop.lwa.screen.network.NetworkViewModel
import com.pixelized.desktop.lwa.screen.roll.RollViewModel
import com.pixelized.desktop.lwa.screen.rollhistory.RollHistoryViewModel
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
get() = listOf(
repositoryDependencies,
factoryDependencies,
viewModelDependencies,
)
val repositoryDependencies
get() = module {
singleOf(::CharacterSheetStore)
singleOf(::NetworkRepository)
singleOf(::CharacterSheetRepository)
singleOf(::RollHistoryRepository)
}
val factoryDependencies
get() = module {
factoryOf(::CharacterSheetFactory)
factoryOf(::CharacterSheetEditFactory)
factoryOf(::NetworkFactory)
}
val viewModelDependencies
get() = module {
viewModelOf(::MainPageViewModel)
viewModelOf(::CharacterSheetViewModel)
viewModelOf(::CharacterSheetEditViewModel)
viewModelOf(::RollViewModel)
viewModelOf(::RollHistoryViewModel)
viewModelOf(::NetworkViewModel)
}

View file

@ -8,9 +8,10 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
object CharacterSheetRepository {
class CharacterSheetRepository(
private val store: CharacterSheetStore,
) {
private val scope = CoroutineScope(Dispatchers.IO)
private val store = CharacterSheetStore()
private val sheets = store.loadFlow()
.stateIn(

View file

@ -26,9 +26,11 @@ import kotlinx.serialization.json.encodeToJsonElement
typealias Server = EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration>
typealias Client = HttpClient
object NetworkRepository {
const val DEFAULT_PORT = 16030
const val DEFAULT_HOST = "pixelized.freeboxos.fr"
class NetworkRepository {
companion object {
const val DEFAULT_PORT = 16030
const val DEFAULT_HOST = "pixelized.freeboxos.fr"
}
private val scope = CoroutineScope(Dispatchers.IO)
private var networkJob: Job? = null

View file

@ -11,9 +11,10 @@ import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
object RollHistoryRepository {
class RollHistoryRepository(
private val network: NetworkRepository,
) {
private val scope = CoroutineScope(Dispatchers.IO)
private val network = NetworkRepository
val rolls: SharedFlow<Message> = network.data
.mapNotNull { it.takeIf { it.value is RollMessage } }

View file

@ -12,7 +12,6 @@ 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.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
@ -27,6 +26,8 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Checkbox
import androidx.compose.material.CheckboxDefaults
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
@ -37,9 +38,11 @@ import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
@ -48,8 +51,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.composable.blur.BlurContent
import com.pixelized.desktop.lwa.composable.blur.BlurContentController
@ -64,6 +65,8 @@ import com.pixelized.desktop.lwa.screen.roll.RollPage
import com.pixelized.desktop.lwa.screen.roll.RollViewModel
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet__delete__label
import lwacharactersheet.composeapp.generated.resources.character_sheet__edit__label
import lwacharactersheet.composeapp.generated.resources.character_sheet__magics__title
import lwacharactersheet.composeapp.generated.resources.character_sheet__occupations_title
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__title
@ -72,6 +75,8 @@ import lwacharactersheet.composeapp.generated.resources.ic_d20_32dp
import lwacharactersheet.composeapp.generated.resources.ic_skull_32dp
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
@Stable
data class CharacterSheetPageUio(
@ -106,12 +111,11 @@ data class CharacterSheetPageUio(
)
}
@OptIn(KoinExperimentalAPI::class)
@Composable
fun CharacterSheetPage(
viewModel: CharacterSheetViewModel = viewModel {
CharacterSheetViewModel(savedStateHandle = createSavedStateHandle())
},
rollViewModel: RollViewModel = viewModel { RollViewModel() },
viewModel: CharacterSheetViewModel = koinViewModel(),
rollViewModel: RollViewModel = koinViewModel(),
) {
val windowController = LocalWindowController.current
val window = LocalWindow.current
@ -273,6 +277,7 @@ fun CharacterSheetPageContent(
)
},
actions = {
var showMenu = remember { mutableStateOf(false) }
Box {
IconButton(
onClick = onDiminished,
@ -301,24 +306,53 @@ fun CharacterSheetPageContent(
)
}
}
IconButton(
onClick = onEdit,
onClick = { showMenu.value = showMenu.value.not() },
) {
Icon(
imageVector = Icons.Default.Edit,
imageVector = Icons.Default.MoreVert,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
}
IconButton(
onClick = onDelete,
DropdownMenu(
expanded = showMenu.value,
onDismissRequest = { showMenu.value = false }
) {
Icon(
imageVector = Icons.Default.Delete,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
DropdownMenuItem(
onClick = {
showMenu.value = false
onEdit()
},
) {
Icon(
imageVector = Icons.Default.Edit,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
Text(
modifier = Modifier.padding(start = 8.dp),
color = MaterialTheme.colors.primary,
text = stringResource(Res.string.character_sheet__edit__label),
)
}
DropdownMenuItem(
onClick = {
showMenu.value = false
onDelete()
},
) {
Icon(
imageVector = Icons.Default.Delete,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
Text(
modifier = Modifier.padding(start = 8.dp),
color = MaterialTheme.colors.primary,
text = stringResource(Res.string.character_sheet__delete__label),
)
}
}
},
)

View file

@ -30,12 +30,12 @@ import kotlin.math.min
private typealias CSDCDialogUio = CharacterSheetDeleteConfirmationDialogUio
class CharacterSheetViewModel(
private val repository: CharacterSheetRepository,
private val factory: CharacterSheetFactory,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val argument = CharacterSheetDestination.Argument(savedStateHandle)
private val repository = CharacterSheetRepository
private val factory = CharacterSheetFactory()
private val _displayDeleteConfirmationDialog = mutableStateOf<CSDCDialogUio?>(null)
val displayDeleteConfirmationDialog: State<CSDCDialogUio?> get() = _displayDeleteConfirmationDialog

View file

@ -28,8 +28,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.composable.decoratedBox.DecoratedBox
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
@ -42,6 +40,8 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__ad
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__save_action
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__title
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
@Stable
data class CharacterSheetEditPageUio(
@ -69,14 +69,10 @@ data class CharacterSheetEditPageUio(
}
}
@OptIn(KoinExperimentalAPI::class)
@Composable
fun CharacterSheetEditPage(
viewModel: CharacterSheetEditViewModel = viewModel {
CharacterSheetEditViewModel(
savedStateHandle = createSavedStateHandle()
)
},
viewModel: CharacterSheetEditViewModel = koinViewModel(),
) {
val windowController = LocalWindowController.current
val window = LocalWindow.current

View file

@ -11,17 +11,17 @@ import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio
import kotlinx.coroutines.runBlocking
class CharacterSheetEditViewModel(
private val characterSheetRepository: CharacterSheetRepository,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val argument = CharacterSheetEditDestination.Argument(savedStateHandle)
private val repository = CharacterSheetRepository
private val factory = CharacterSheetEditFactory()
val enableBack = argument.enableBack
private val _characterSheet = mutableStateOf(
repository.characterSheetFlow(id = argument.id).value.let {
characterSheetRepository.characterSheetFlow(id = argument.id).value.let {
runBlocking { factory.convertToUio(it) }
}
)
@ -78,6 +78,6 @@ class CharacterSheetEditViewModel(
suspend fun save() {
val sheet = _characterSheet.value
val model = factory.convertToModel(sheet = sheet)
repository.save(characterSheet = model)
characterSheetRepository.save(characterSheet = model)
}
}

View file

@ -19,7 +19,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.destination.navigateToNetwork
@ -31,6 +30,8 @@ import lwacharactersheet.composeapp.generated.resources.main_page__create_action
import lwacharactersheet.composeapp.generated.resources.main_page__network_action
import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
@Stable
data class CharacterUio(
@ -38,9 +39,10 @@ data class CharacterUio(
val name: String,
)
@OptIn(KoinExperimentalAPI::class)
@Composable
fun MainPage(
viewModel: MainPageViewModel = viewModel { MainPageViewModel() },
viewModel: MainPageViewModel = koinViewModel(),
) {
val window = LocalWindowController.current
val screen = LocalScreenController.current

View file

@ -7,10 +7,9 @@ import androidx.lifecycle.ViewModel
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.utils.extention.collectAsState
class MainPageViewModel : ViewModel() {
// using a variable to help with later injection.
private val repository = CharacterSheetRepository
class MainPageViewModel(
private val repository: CharacterSheetRepository
) : ViewModel() {
val characters: State<List<CharacterUio>>
@Composable
@Stable

View file

@ -1,11 +1,8 @@
package com.pixelized.desktop.lwa.screen.network
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.ScrollState
import androidx.compose.foundation.layout.Arrangement
@ -41,12 +38,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.LocalSnackHost
import com.pixelized.desktop.lwa.composable.blur.BlurContent
import com.pixelized.desktop.lwa.composable.error.snack.ErrorSnack
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import kotlinx.io.InternalIoApi
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.network__host__label
import lwacharactersheet.composeapp.generated.resources.network__player_name__label
@ -56,6 +51,8 @@ import lwacharactersheet.composeapp.generated.resources.network__socket__disconn
import lwacharactersheet.composeapp.generated.resources.network__socket__host_action
import lwacharactersheet.composeapp.generated.resources.network__title
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
@Stable
data class NetworkPageUio(
@ -67,9 +64,10 @@ data class NetworkPageUio(
val enableCancel: Boolean,
)
@OptIn(KoinExperimentalAPI::class)
@Composable
fun NetworkPage(
viewModel: NetworkViewModel = viewModel { NetworkViewModel() },
viewModel: NetworkViewModel = koinViewModel(),
) {
val screen = LocalScreenController.current
val snack = LocalSnackHost.current

View file

@ -15,14 +15,11 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.network__connect__message
import lwacharactersheet.composeapp.generated.resources.network__disconnect__message
import org.jetbrains.compose.resources.getString
class NetworkViewModel : ViewModel() {
private val repository = NetworkRepository
private val factory = NetworkFactory()
class NetworkViewModel(
private val repository: NetworkRepository,
private val factory: NetworkFactory
) : ViewModel() {
private val host = mutableStateOf(NetworkRepository.DEFAULT_HOST)
private val port = mutableStateOf(NetworkRepository.DEFAULT_PORT)

View file

@ -59,6 +59,8 @@ import lwacharactersheet.composeapp.generated.resources.roll_page__roll__label
import lwacharactersheet.composeapp.generated.resources.roll_page__roll__success_label
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
@Stable
data class RollTitleUio(
@ -82,9 +84,10 @@ data class DifficultyUio(
}
}
@OptIn(KoinExperimentalAPI::class)
@Composable
fun RollPage(
viewModel: RollViewModel = viewModel { RollViewModel() },
viewModel: RollViewModel = koinViewModel(),
onDismissRequest: () -> Unit,
) {
val scope = rememberCoroutineScope()

View file

@ -30,9 +30,10 @@ import lwacharactersheet.composeapp.generated.resources.roll_page__special_succe
import lwacharactersheet.composeapp.generated.resources.roll_page__success
import org.jetbrains.compose.resources.getString
class RollViewModel : ViewModel() {
private val sheetRepository = CharacterSheetRepository
private val repository = RollHistoryRepository
class RollViewModel(
private val characterSheetRepository: CharacterSheetRepository,
private val rollHistoryRepository: RollHistoryRepository,
) : ViewModel() {
private lateinit var sheet: CharacterSheet
private lateinit var rollAction: String
@ -55,7 +56,7 @@ class RollViewModel : ViewModel() {
sheet: CharacterSheetPageUio,
characteristic: CharacterSheetPageUio.Characteristic,
) {
val diminished = sheetRepository.characterDiminishedFlow(id = sheet.id).value
val diminished = characterSheetRepository.characterDiminishedFlow(id = sheet.id).value
prepareRoll(
sheet = sheet,
label = characteristic.label,
@ -96,7 +97,7 @@ class RollViewModel : ViewModel() {
) {
runBlocking { rollRotation.snapTo(0f) }
this.sheet = CharacterSheetRepository.characterSheetFlow(id = sheet.id).value!!
this.sheet = characterSheetRepository.characterSheetFlow(id = sheet.id).value!!
this.rollAction = rollAction
this.rollSuccessValue = rollSuccessValue
@ -167,7 +168,7 @@ class RollViewModel : ViewModel() {
value = roll,
)
launch {
repository.share(
rollHistoryRepository.share(
skillLabel = _rollTitle.value.label,
rollDifficulty = when (_rollDifficulty.value?.difficulty) {
Difficulty.EASY -> getString(Res.string.roll_page__dc_easy__label)

View file

@ -25,11 +25,14 @@ import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.roll_history__title
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
import org.koin.core.annotation.KoinExperimentalAPI
@OptIn(KoinExperimentalAPI::class)
@Composable
fun RollHistoryPage(
viewModel: RollHistoryViewModel = viewModel { RollHistoryViewModel() }
viewModel: RollHistoryViewModel = koinViewModel(),
) {
val screen = LocalScreenController.current

View file

@ -8,9 +8,9 @@ import com.pixelized.desktop.lwa.repository.network.protocol.RollMessage
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
import kotlinx.coroutines.launch
class RollHistoryViewModel : ViewModel() {
private val repository = RollHistoryRepository
class RollHistoryViewModel(
private val repository: RollHistoryRepository
) : ViewModel() {
private val _rolls = mutableStateOf((emptyList<RollHistoryItemUio>()))
val rolls: State<List<RollHistoryItemUio>> get() = _rolls

View file

@ -1,10 +1,16 @@
package com.pixelized.desktop.lwa
import androidx.compose.ui.window.application
import com.pixelized.desktop.lwa.business.SkillStepUseCase
import org.koin.compose.KoinContext
import org.koin.core.context.startKoin
fun main() {
startKoin {
modules(modules = moduleDependencies)
}
application {
App()
KoinContext {
App()
}
}
}

View file

@ -2,29 +2,32 @@
kotlin = "2.0.21"
kotlinx-coroutines = "1.9.0"
kotlinx-json = "1.7.3"
junit = "4.13.2"
compose-multiplatform = "1.7.0"
androidx-lifecycle = "2.8.3"
androidx-navigation = "2.8.0-alpha10"
ktor_version = "3.0.0"
koin = "4.0.0"
koinComposeMultiplatform = "1.2.0-Beta4"
[plugins]
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotlinKtor = { id = "io.ktor.plugin", version.ref = "ktor_version"}
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-lifecycle-viewmodel = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-viewmodel", version.ref = "androidx-lifecycle" }
androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
androidx-navigation-compose = { group = "org.jetbrains.androidx.navigation", name = "navigation-compose", version.ref = "androidx-navigation" }
kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-json" }
koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor_version" }
ktor-client-cio = { group = 'io.ktor', name = "ktor-client-cio", version.ref = "ktor_version" }
ktor-client-websockets = { group = 'io.ktor', name = "ktor-client-websockets", version.ref = "ktor_version" }