Add koin dependencies injections.
This commit is contained in:
parent
f459877d55
commit
7fc99f5799
21 changed files with 181 additions and 74 deletions
|
|
@ -15,6 +15,7 @@ kotlin {
|
||||||
val desktopMain by getting
|
val desktopMain by getting
|
||||||
|
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
|
// compose
|
||||||
implementation(compose.runtime)
|
implementation(compose.runtime)
|
||||||
implementation(compose.foundation)
|
implementation(compose.foundation)
|
||||||
implementation(compose.material)
|
implementation(compose.material)
|
||||||
|
|
@ -24,6 +25,11 @@ kotlin {
|
||||||
implementation(libs.androidx.lifecycle.viewmodel)
|
implementation(libs.androidx.lifecycle.viewmodel)
|
||||||
implementation(libs.androidx.lifecycle.runtime.compose)
|
implementation(libs.androidx.lifecycle.runtime.compose)
|
||||||
implementation(libs.androidx.navigation.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.kotlinx.serialization.json)
|
||||||
implementation(libs.ktor.client.core)
|
implementation(libs.ktor.client.core)
|
||||||
implementation(libs.ktor.client.cio)
|
implementation(libs.ktor.client.cio)
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@
|
||||||
<string name="character_sheet_edit__magic__add_action">Ajouter une compétence magique</string>
|
<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__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__str">Force</string>
|
||||||
<string name="character_sheet__characteristics__dex">Dextérité</string>
|
<string name="character_sheet__characteristics__dex">Dextérité</string>
|
||||||
<string name="character_sheet__characteristics__con">Constitution</string>
|
<string name="character_sheet__characteristics__con">Constitution</string>
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ import lwacharactersheet.composeapp.generated.resources.network__connect__messag
|
||||||
import lwacharactersheet.composeapp.generated.resources.network__disconnect__message
|
import lwacharactersheet.composeapp.generated.resources.network__disconnect__message
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||||
|
import org.koin.compose.koinInject
|
||||||
|
|
||||||
val LocalWindowController = compositionLocalOf<WindowController> {
|
val LocalWindowController = compositionLocalOf<WindowController> {
|
||||||
error("Local Window Controller is not yet ready")
|
error("Local Window Controller is not yet ready")
|
||||||
|
|
@ -155,10 +156,11 @@ private fun WindowsHandler(
|
||||||
private fun NetworkSnackHandler(
|
private fun NetworkSnackHandler(
|
||||||
snack: SnackbarHostState,
|
snack: SnackbarHostState,
|
||||||
) {
|
) {
|
||||||
|
val networkRepository = koinInject<NetworkRepository>()
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
launch {
|
launch {
|
||||||
var ignoreInitial = true
|
var ignoreInitial = true
|
||||||
NetworkRepository.status.collect {
|
networkRepository.status.collect {
|
||||||
if (ignoreInitial) {
|
if (ignoreInitial) {
|
||||||
ignoreInitial = false
|
ignoreInitial = false
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -8,9 +8,10 @@ import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
|
||||||
object CharacterSheetRepository {
|
class CharacterSheetRepository(
|
||||||
|
private val store: CharacterSheetStore,
|
||||||
|
) {
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
private val store = CharacterSheetStore()
|
|
||||||
|
|
||||||
private val sheets = store.loadFlow()
|
private val sheets = store.loadFlow()
|
||||||
.stateIn(
|
.stateIn(
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,11 @@ import kotlinx.serialization.json.encodeToJsonElement
|
||||||
typealias Server = EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration>
|
typealias Server = EmbeddedServer<NettyApplicationEngine, NettyApplicationEngine.Configuration>
|
||||||
typealias Client = HttpClient
|
typealias Client = HttpClient
|
||||||
|
|
||||||
object NetworkRepository {
|
class NetworkRepository {
|
||||||
const val DEFAULT_PORT = 16030
|
companion object {
|
||||||
const val DEFAULT_HOST = "pixelized.freeboxos.fr"
|
const val DEFAULT_PORT = 16030
|
||||||
|
const val DEFAULT_HOST = "pixelized.freeboxos.fr"
|
||||||
|
}
|
||||||
|
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
private var networkJob: Job? = null
|
private var networkJob: Job? = null
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,10 @@ import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
object RollHistoryRepository {
|
class RollHistoryRepository(
|
||||||
|
private val network: NetworkRepository,
|
||||||
|
) {
|
||||||
private val scope = CoroutineScope(Dispatchers.IO)
|
private val scope = CoroutineScope(Dispatchers.IO)
|
||||||
private val network = NetworkRepository
|
|
||||||
|
|
||||||
val rolls: SharedFlow<Message> = network.data
|
val rolls: SharedFlow<Message> = network.data
|
||||||
.mapNotNull { it.takeIf { it.value is RollMessage } }
|
.mapNotNull { it.takeIf { it.value is RollMessage } }
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.IntrinsicSize
|
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
|
@ -27,6 +26,8 @@ import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.Checkbox
|
import androidx.compose.material.Checkbox
|
||||||
import androidx.compose.material.CheckboxDefaults
|
import androidx.compose.material.CheckboxDefaults
|
||||||
|
import androidx.compose.material.DropdownMenu
|
||||||
|
import androidx.compose.material.DropdownMenuItem
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.IconButton
|
import androidx.compose.material.IconButton
|
||||||
import androidx.compose.material.MaterialTheme
|
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.Icons
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Edit
|
import androidx.compose.material.icons.filled.Edit
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
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.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
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.LocalWindowController
|
||||||
import com.pixelized.desktop.lwa.composable.blur.BlurContent
|
import com.pixelized.desktop.lwa.composable.blur.BlurContent
|
||||||
import com.pixelized.desktop.lwa.composable.blur.BlurContentController
|
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 com.pixelized.desktop.lwa.screen.roll.RollViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
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__magics__title
|
||||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__occupations_title
|
import lwacharactersheet.composeapp.generated.resources.character_sheet__occupations_title
|
||||||
import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__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 lwacharactersheet.composeapp.generated.resources.ic_skull_32dp
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
import org.koin.core.annotation.KoinExperimentalAPI
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacterSheetPageUio(
|
data class CharacterSheetPageUio(
|
||||||
|
|
@ -106,12 +111,11 @@ data class CharacterSheetPageUio(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(KoinExperimentalAPI::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CharacterSheetPage(
|
fun CharacterSheetPage(
|
||||||
viewModel: CharacterSheetViewModel = viewModel {
|
viewModel: CharacterSheetViewModel = koinViewModel(),
|
||||||
CharacterSheetViewModel(savedStateHandle = createSavedStateHandle())
|
rollViewModel: RollViewModel = koinViewModel(),
|
||||||
},
|
|
||||||
rollViewModel: RollViewModel = viewModel { RollViewModel() },
|
|
||||||
) {
|
) {
|
||||||
val windowController = LocalWindowController.current
|
val windowController = LocalWindowController.current
|
||||||
val window = LocalWindow.current
|
val window = LocalWindow.current
|
||||||
|
|
@ -273,6 +277,7 @@ fun CharacterSheetPageContent(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
|
var showMenu = remember { mutableStateOf(false) }
|
||||||
Box {
|
Box {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onDiminished,
|
onClick = onDiminished,
|
||||||
|
|
@ -301,24 +306,53 @@ fun CharacterSheetPageContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = onEdit,
|
onClick = { showMenu.value = showMenu.value.not() },
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Edit,
|
imageVector = Icons.Default.MoreVert,
|
||||||
tint = MaterialTheme.colors.primary,
|
tint = MaterialTheme.colors.primary,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
IconButton(
|
DropdownMenu(
|
||||||
onClick = onDelete,
|
expanded = showMenu.value,
|
||||||
|
onDismissRequest = { showMenu.value = false }
|
||||||
) {
|
) {
|
||||||
Icon(
|
DropdownMenuItem(
|
||||||
imageVector = Icons.Default.Delete,
|
onClick = {
|
||||||
tint = MaterialTheme.colors.primary,
|
showMenu.value = false
|
||||||
contentDescription = null,
|
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),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@ import kotlin.math.min
|
||||||
private typealias CSDCDialogUio = CharacterSheetDeleteConfirmationDialogUio
|
private typealias CSDCDialogUio = CharacterSheetDeleteConfirmationDialogUio
|
||||||
|
|
||||||
class CharacterSheetViewModel(
|
class CharacterSheetViewModel(
|
||||||
|
private val repository: CharacterSheetRepository,
|
||||||
|
private val factory: CharacterSheetFactory,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val argument = CharacterSheetDestination.Argument(savedStateHandle)
|
private val argument = CharacterSheetDestination.Argument(savedStateHandle)
|
||||||
private val repository = CharacterSheetRepository
|
|
||||||
private val factory = CharacterSheetFactory()
|
|
||||||
|
|
||||||
private val _displayDeleteConfirmationDialog = mutableStateOf<CSDCDialogUio?>(null)
|
private val _displayDeleteConfirmationDialog = mutableStateOf<CSDCDialogUio?>(null)
|
||||||
val displayDeleteConfirmationDialog: State<CSDCDialogUio?> get() = _displayDeleteConfirmationDialog
|
val displayDeleteConfirmationDialog: State<CSDCDialogUio?> get() = _displayDeleteConfirmationDialog
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
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.LocalWindowController
|
||||||
import com.pixelized.desktop.lwa.composable.decoratedBox.DecoratedBox
|
import com.pixelized.desktop.lwa.composable.decoratedBox.DecoratedBox
|
||||||
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
|
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__save_action
|
||||||
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__title
|
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__title
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
import org.koin.core.annotation.KoinExperimentalAPI
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacterSheetEditPageUio(
|
data class CharacterSheetEditPageUio(
|
||||||
|
|
@ -69,14 +69,10 @@ data class CharacterSheetEditPageUio(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(KoinExperimentalAPI::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun CharacterSheetEditPage(
|
fun CharacterSheetEditPage(
|
||||||
viewModel: CharacterSheetEditViewModel = viewModel {
|
viewModel: CharacterSheetEditViewModel = koinViewModel(),
|
||||||
CharacterSheetEditViewModel(
|
|
||||||
savedStateHandle = createSavedStateHandle()
|
|
||||||
)
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
val windowController = LocalWindowController.current
|
val windowController = LocalWindowController.current
|
||||||
val window = LocalWindow.current
|
val window = LocalWindow.current
|
||||||
|
|
|
||||||
|
|
@ -11,17 +11,17 @@ import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
class CharacterSheetEditViewModel(
|
class CharacterSheetEditViewModel(
|
||||||
|
private val characterSheetRepository: CharacterSheetRepository,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val argument = CharacterSheetEditDestination.Argument(savedStateHandle)
|
private val argument = CharacterSheetEditDestination.Argument(savedStateHandle)
|
||||||
private val repository = CharacterSheetRepository
|
|
||||||
private val factory = CharacterSheetEditFactory()
|
private val factory = CharacterSheetEditFactory()
|
||||||
|
|
||||||
val enableBack = argument.enableBack
|
val enableBack = argument.enableBack
|
||||||
|
|
||||||
private val _characterSheet = mutableStateOf(
|
private val _characterSheet = mutableStateOf(
|
||||||
repository.characterSheetFlow(id = argument.id).value.let {
|
characterSheetRepository.characterSheetFlow(id = argument.id).value.let {
|
||||||
runBlocking { factory.convertToUio(it) }
|
runBlocking { factory.convertToUio(it) }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -78,6 +78,6 @@ class CharacterSheetEditViewModel(
|
||||||
suspend fun save() {
|
suspend fun save() {
|
||||||
val sheet = _characterSheet.value
|
val sheet = _characterSheet.value
|
||||||
val model = factory.convertToModel(sheet = sheet)
|
val model = factory.convertToModel(sheet = sheet)
|
||||||
repository.save(characterSheet = model)
|
characterSheetRepository.save(characterSheet = model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,6 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import com.pixelized.desktop.lwa.LocalWindowController
|
import com.pixelized.desktop.lwa.LocalWindowController
|
||||||
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
|
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
|
||||||
import com.pixelized.desktop.lwa.navigation.screen.destination.navigateToNetwork
|
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__network_action
|
||||||
import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
|
import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
import org.koin.core.annotation.KoinExperimentalAPI
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacterUio(
|
data class CharacterUio(
|
||||||
|
|
@ -38,9 +39,10 @@ data class CharacterUio(
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@OptIn(KoinExperimentalAPI::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainPage(
|
fun MainPage(
|
||||||
viewModel: MainPageViewModel = viewModel { MainPageViewModel() },
|
viewModel: MainPageViewModel = koinViewModel(),
|
||||||
) {
|
) {
|
||||||
val window = LocalWindowController.current
|
val window = LocalWindowController.current
|
||||||
val screen = LocalScreenController.current
|
val screen = LocalScreenController.current
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,9 @@ import androidx.lifecycle.ViewModel
|
||||||
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
|
||||||
import com.pixelized.desktop.lwa.utils.extention.collectAsState
|
import com.pixelized.desktop.lwa.utils.extention.collectAsState
|
||||||
|
|
||||||
class MainPageViewModel : ViewModel() {
|
class MainPageViewModel(
|
||||||
// using a variable to help with later injection.
|
private val repository: CharacterSheetRepository
|
||||||
private val repository = CharacterSheetRepository
|
) : ViewModel() {
|
||||||
|
|
||||||
val characters: State<List<CharacterUio>>
|
val characters: State<List<CharacterUio>>
|
||||||
@Composable
|
@Composable
|
||||||
@Stable
|
@Stable
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
package com.pixelized.desktop.lwa.screen.network
|
package com.pixelized.desktop.lwa.screen.network
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.animation.SizeTransform
|
|
||||||
import androidx.compose.animation.fadeIn
|
import androidx.compose.animation.fadeIn
|
||||||
import androidx.compose.animation.fadeOut
|
import androidx.compose.animation.fadeOut
|
||||||
import androidx.compose.animation.slideInVertically
|
|
||||||
import androidx.compose.animation.slideOutVertically
|
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
|
@ -41,12 +38,10 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
|
||||||
import com.pixelized.desktop.lwa.LocalSnackHost
|
import com.pixelized.desktop.lwa.LocalSnackHost
|
||||||
import com.pixelized.desktop.lwa.composable.blur.BlurContent
|
import com.pixelized.desktop.lwa.composable.blur.BlurContent
|
||||||
import com.pixelized.desktop.lwa.composable.error.snack.ErrorSnack
|
import com.pixelized.desktop.lwa.composable.error.snack.ErrorSnack
|
||||||
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
|
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
|
||||||
import kotlinx.io.InternalIoApi
|
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.network__host__label
|
import lwacharactersheet.composeapp.generated.resources.network__host__label
|
||||||
import lwacharactersheet.composeapp.generated.resources.network__player_name__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__socket__host_action
|
||||||
import lwacharactersheet.composeapp.generated.resources.network__title
|
import lwacharactersheet.composeapp.generated.resources.network__title
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
import org.koin.core.annotation.KoinExperimentalAPI
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class NetworkPageUio(
|
data class NetworkPageUio(
|
||||||
|
|
@ -67,9 +64,10 @@ data class NetworkPageUio(
|
||||||
val enableCancel: Boolean,
|
val enableCancel: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@OptIn(KoinExperimentalAPI::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NetworkPage(
|
fun NetworkPage(
|
||||||
viewModel: NetworkViewModel = viewModel { NetworkViewModel() },
|
viewModel: NetworkViewModel = koinViewModel(),
|
||||||
) {
|
) {
|
||||||
val screen = LocalScreenController.current
|
val screen = LocalScreenController.current
|
||||||
val snack = LocalSnackHost.current
|
val snack = LocalSnackHost.current
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,11 @@ import com.pixelized.desktop.lwa.repository.network.NetworkRepository
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.launch
|
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() {
|
class NetworkViewModel(
|
||||||
private val repository = NetworkRepository
|
private val repository: NetworkRepository,
|
||||||
private val factory = NetworkFactory()
|
private val factory: NetworkFactory
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
private val host = mutableStateOf(NetworkRepository.DEFAULT_HOST)
|
private val host = mutableStateOf(NetworkRepository.DEFAULT_HOST)
|
||||||
private val port = mutableStateOf(NetworkRepository.DEFAULT_PORT)
|
private val port = mutableStateOf(NetworkRepository.DEFAULT_PORT)
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,8 @@ import lwacharactersheet.composeapp.generated.resources.roll_page__roll__label
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__roll__success_label
|
import lwacharactersheet.composeapp.generated.resources.roll_page__roll__success_label
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
import org.koin.core.annotation.KoinExperimentalAPI
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
data class RollTitleUio(
|
data class RollTitleUio(
|
||||||
|
|
@ -82,9 +84,10 @@ data class DifficultyUio(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(KoinExperimentalAPI::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun RollPage(
|
fun RollPage(
|
||||||
viewModel: RollViewModel = viewModel { RollViewModel() },
|
viewModel: RollViewModel = koinViewModel(),
|
||||||
onDismissRequest: () -> Unit,
|
onDismissRequest: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
|
||||||
|
|
@ -30,9 +30,10 @@ import lwacharactersheet.composeapp.generated.resources.roll_page__special_succe
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_page__success
|
import lwacharactersheet.composeapp.generated.resources.roll_page__success
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
|
|
||||||
class RollViewModel : ViewModel() {
|
class RollViewModel(
|
||||||
private val sheetRepository = CharacterSheetRepository
|
private val characterSheetRepository: CharacterSheetRepository,
|
||||||
private val repository = RollHistoryRepository
|
private val rollHistoryRepository: RollHistoryRepository,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
private lateinit var sheet: CharacterSheet
|
private lateinit var sheet: CharacterSheet
|
||||||
private lateinit var rollAction: String
|
private lateinit var rollAction: String
|
||||||
|
|
@ -55,7 +56,7 @@ class RollViewModel : ViewModel() {
|
||||||
sheet: CharacterSheetPageUio,
|
sheet: CharacterSheetPageUio,
|
||||||
characteristic: CharacterSheetPageUio.Characteristic,
|
characteristic: CharacterSheetPageUio.Characteristic,
|
||||||
) {
|
) {
|
||||||
val diminished = sheetRepository.characterDiminishedFlow(id = sheet.id).value
|
val diminished = characterSheetRepository.characterDiminishedFlow(id = sheet.id).value
|
||||||
prepareRoll(
|
prepareRoll(
|
||||||
sheet = sheet,
|
sheet = sheet,
|
||||||
label = characteristic.label,
|
label = characteristic.label,
|
||||||
|
|
@ -96,7 +97,7 @@ class RollViewModel : ViewModel() {
|
||||||
) {
|
) {
|
||||||
runBlocking { rollRotation.snapTo(0f) }
|
runBlocking { rollRotation.snapTo(0f) }
|
||||||
|
|
||||||
this.sheet = CharacterSheetRepository.characterSheetFlow(id = sheet.id).value!!
|
this.sheet = characterSheetRepository.characterSheetFlow(id = sheet.id).value!!
|
||||||
this.rollAction = rollAction
|
this.rollAction = rollAction
|
||||||
this.rollSuccessValue = rollSuccessValue
|
this.rollSuccessValue = rollSuccessValue
|
||||||
|
|
||||||
|
|
@ -167,7 +168,7 @@ class RollViewModel : ViewModel() {
|
||||||
value = roll,
|
value = roll,
|
||||||
)
|
)
|
||||||
launch {
|
launch {
|
||||||
repository.share(
|
rollHistoryRepository.share(
|
||||||
skillLabel = _rollTitle.value.label,
|
skillLabel = _rollTitle.value.label,
|
||||||
rollDifficulty = when (_rollDifficulty.value?.difficulty) {
|
rollDifficulty = when (_rollDifficulty.value?.difficulty) {
|
||||||
Difficulty.EASY -> getString(Res.string.roll_page__dc_easy__label)
|
Difficulty.EASY -> getString(Res.string.roll_page__dc_easy__label)
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,14 @@ import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
import lwacharactersheet.composeapp.generated.resources.roll_history__title
|
import lwacharactersheet.composeapp.generated.resources.roll_history__title
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
|
import org.koin.core.annotation.KoinExperimentalAPI
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(KoinExperimentalAPI::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun RollHistoryPage(
|
fun RollHistoryPage(
|
||||||
viewModel: RollHistoryViewModel = viewModel { RollHistoryViewModel() }
|
viewModel: RollHistoryViewModel = koinViewModel(),
|
||||||
) {
|
) {
|
||||||
val screen = LocalScreenController.current
|
val screen = LocalScreenController.current
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ import com.pixelized.desktop.lwa.repository.network.protocol.RollMessage
|
||||||
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
|
import com.pixelized.desktop.lwa.repository.roll.RollHistoryRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class RollHistoryViewModel : ViewModel() {
|
class RollHistoryViewModel(
|
||||||
|
private val repository: RollHistoryRepository
|
||||||
private val repository = RollHistoryRepository
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _rolls = mutableStateOf((emptyList<RollHistoryItemUio>()))
|
private val _rolls = mutableStateOf((emptyList<RollHistoryItemUio>()))
|
||||||
val rolls: State<List<RollHistoryItemUio>> get() = _rolls
|
val rolls: State<List<RollHistoryItemUio>> get() = _rolls
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
package com.pixelized.desktop.lwa
|
package com.pixelized.desktop.lwa
|
||||||
|
|
||||||
import androidx.compose.ui.window.application
|
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() {
|
fun main() {
|
||||||
|
startKoin {
|
||||||
|
modules(modules = moduleDependencies)
|
||||||
|
}
|
||||||
application {
|
application {
|
||||||
App()
|
KoinContext {
|
||||||
|
App()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,29 +2,32 @@
|
||||||
kotlin = "2.0.21"
|
kotlin = "2.0.21"
|
||||||
kotlinx-coroutines = "1.9.0"
|
kotlinx-coroutines = "1.9.0"
|
||||||
kotlinx-json = "1.7.3"
|
kotlinx-json = "1.7.3"
|
||||||
junit = "4.13.2"
|
|
||||||
compose-multiplatform = "1.7.0"
|
compose-multiplatform = "1.7.0"
|
||||||
androidx-lifecycle = "2.8.3"
|
androidx-lifecycle = "2.8.3"
|
||||||
androidx-navigation = "2.8.0-alpha10"
|
androidx-navigation = "2.8.0-alpha10"
|
||||||
ktor_version = "3.0.0"
|
ktor_version = "3.0.0"
|
||||||
|
koin = "4.0.0"
|
||||||
|
koinComposeMultiplatform = "1.2.0-Beta4"
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
|
||||||
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||||
kotlinKtor = { id = "io.ktor.plugin", version.ref = "ktor_version"}
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
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-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-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" }
|
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-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" }
|
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-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-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" }
|
ktor-client-websockets = { group = 'io.ktor', name = "ktor-client-websockets", version.ref = "ktor_version" }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue