diff --git a/client/build.gradle b/client/build.gradle index dc8a06fd..7fc6a451 100644 --- a/client/build.gradle +++ b/client/build.gradle @@ -32,9 +32,6 @@ kotlin { api project(":postssystem.features.content.binary.client") api project(":postssystem.services.posts.client") - - api libs.microutils.fsm.common - api libs.microutils.fsm.repos.common api libs.microutils.crypto implementation compose.runtime diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt deleted file mode 100644 index 5623a857..00000000 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DI.kt +++ /dev/null @@ -1,148 +0,0 @@ -package dev.inmo.postssystem.client - -import dev.inmo.postssystem.client.ui.fsm.* -import dev.inmo.postssystem.features.auth.client.installClientAuthenticator -import dev.inmo.postssystem.features.auth.common.* -import dev.inmo.postssystem.features.files.client.ClientReadFilesStorage -import dev.inmo.postssystem.features.files.common.storage.ReadFilesStorage -import dev.inmo.postssystem.features.roles.common.Role -import dev.inmo.postssystem.features.roles.common.RolesStorage -import dev.inmo.postssystem.features.roles.client.ClientRolesStorage -import dev.inmo.postssystem.features.roles.manager.common.RolesManagerRoleSerializer -import dev.inmo.postssystem.features.users.client.UsersStorageKtorClient -import dev.inmo.postssystem.features.users.common.ReadUsersStorage -import dev.inmo.postssystem.features.users.common.User -import dev.inmo.micro_utils.common.Either -import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope -import dev.inmo.micro_utils.fsm.common.StatesMachine -import dev.inmo.micro_utils.fsm.common.dsl.FSMBuilder -import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo -import dev.inmo.micro_utils.ktor.client.UnifiedRequester -import dev.inmo.micro_utils.repos.KeyValueRepo -import dev.inmo.postssystem.client.settings.DefaultSettings -import dev.inmo.postssystem.client.settings.Settings -import dev.inmo.postssystem.client.settings.auth.AuthSettings -import dev.inmo.postssystem.client.settings.auth.DefaultAuthSettings -import dev.inmo.postssystem.features.common.common.* -import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator -import dev.inmo.postssystem.features.content.common.OtherContentSerializerModuleConfigurator -import dev.inmo.postssystem.features.content.text.common.TextContentSerializerModuleConfigurator -import dev.inmo.postssystem.features.status.client.StatusFeatureClient -import dev.inmo.postssystem.publicators.simple.client.SimplePublicatorService -import dev.inmo.postssystem.publicators.simple.client.SimplePublicatorServiceClient -import dev.inmo.postssystem.services.posts.client.ClientPostsService -import dev.inmo.postssystem.services.posts.common.* -import io.ktor.client.HttpClient -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.serialization.BinaryFormat -import kotlinx.serialization.StringFormat -import kotlinx.serialization.cbor.Cbor -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule -import org.koin.core.Koin -import org.koin.core.context.startKoin -import org.koin.core.module.Module -import org.koin.core.qualifier.* -import org.koin.core.scope.Scope -import org.koin.dsl.binds -import org.koin.dsl.module - -val UIScopeQualifier = StringQualifier("CoroutineScopeUI") -val SettingsQualifier = StringQualifier("Settings") -val RolesQualifier = StringQualifier("Roles") -private val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder") - -val defaultSerialFormat = Json { - ignoreUnknownKeys = true -} - -/** - * Entrypoint for getting [org.koin.core.Koin] DI for the client - * - * @param repoFactory Factory for creating of [DefaultStatesManagerRepo] for [dev.inmo.postssystem.client.ui.fsm.UIFSM] - */ -fun baseKoin( - defaultScope: CoroutineScope, - settingsFactory: Scope.() -> KeyValueRepo, - repoFactory: Scope.() -> DefaultStatesManagerRepo, - handlersSetter: Pair>.() -> Unit -): Koin = startKoin { - modules( - module { - singleWithRandomQualifier { OtherContentSerializerModuleConfigurator } - singleWithRandomQualifier { TextContentSerializerModuleConfigurator } - singleWithRandomQualifier { ContentSerializersModuleConfigurator(getAll()) } - single { SerializersModuleConfigurator(getAll()) } - - single { - Json { - ignoreUnknownKeys = true - serializersModule = SerializersModule { get().apply { invoke() } } - } - } - single { get() } - - single(SettingsQualifier) { settingsFactory() } - single { DBDropper(get(SettingsQualifier)) } - single(FSMHandlersBuilderQualifier) { handlersSetter } - single { repoFactory() } - single { defaultScope } - single(UIScopeQualifier) { get().LinkedSupervisorScope(Dispatchers.Main) } - single>(UIFSMQualifier) { UIFSM(get()) { (this@single to this@UIFSM).apply(get( - FSMHandlersBuilderQualifier - )) } } - single { DefaultAuthSettings(get(SettingsQualifier), get(), koin, get()) } - single { DefaultSettings(get()) } - - AdditionalModules.modules.forEach { - it.apply { load() } - } - } - ) -}.koin.apply { - loadModules( - listOf( - module { single { this@apply } } - ) - ) - RolesManagerRoleSerializer // Just to activate it in JS client -} - -fun getAuthorizedFeaturesDIModule( - serverUrl: String, - initialAuthKey: Either, - onAuthKeyUpdated: suspend (AuthTokenInfo) -> Unit, - onUserRetrieved: suspend (User?) -> Unit, - onAuthKeyInvalidated: suspend () -> Unit -): Module { - val serverUrlQualifier = StringQualifier("serverUrl") - val credsQualifier = StringQualifier("creds") - - return module { - single(createdAtStart = true) { - HttpClient { - installClientAuthenticator(serverUrl, get(), get(credsQualifier), onAuthKeyUpdated, onUserRetrieved, onAuthKeyInvalidated) - } - } - single(credsQualifier) { initialAuthKey } - single(serverUrlQualifier) { serverUrl } - single { - Cbor { - serializersModule = SerializersModule { get().apply { invoke() } } - } - } - single { UnifiedRequester(get(), get()) } - - single { StatusFeatureClient(get(serverUrlQualifier), get()) } - - single { ClientReadFilesStorage(get(serverUrlQualifier), get(), get()) } - single { UsersStorageKtorClient(get(serverUrlQualifier), get()) } - single> { ClientRolesStorage(get(serverUrlQualifier), get(), Role.serializer()) } - single { ClientPostsService(get(serverUrlQualifier), get()) } binds arrayOf( - ReadPostsService::class, - WritePostsService::class - ) - single { SimplePublicatorServiceClient(get(serverUrlQualifier), get()) } - } -} diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/DefaultSettings.kt b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/DefaultSettings.kt deleted file mode 100644 index af3afffc..00000000 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/DefaultSettings.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.inmo.postssystem.client.settings - -import dev.inmo.postssystem.client.settings.auth.AuthSettings - - -data class DefaultSettings( - override val authSettings: AuthSettings -) : Settings diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/Settings.kt b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/Settings.kt deleted file mode 100644 index a8b21f08..00000000 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/Settings.kt +++ /dev/null @@ -1,12 +0,0 @@ -package dev.inmo.postssystem.client.settings - -import dev.inmo.postssystem.client.settings.auth.AuthSettings -import kotlinx.coroutines.flow.StateFlow -import org.koin.core.module.Module - -interface Settings { - val authSettings: AuthSettings - - val authorizedDIModule: StateFlow - get() = authSettings.authorizedDIModule -} diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSMHandler.kt b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSMHandler.kt deleted file mode 100644 index c4d287fe..00000000 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSMHandler.kt +++ /dev/null @@ -1,27 +0,0 @@ -package dev.inmo.postssystem.client.ui.fsm - -import dev.inmo.postssystem.features.auth.client.AuthUnavailableException -import dev.inmo.micro_utils.fsm.common.* - -interface UIFSMHandler : StatesHandler { - suspend fun StatesMachine.safeHandleState(state: T): UIFSMState? - override suspend fun StatesMachine.handleState(state: T): UIFSMState? { - return runCatching { - safeHandleState(state).also(::println) - }.getOrElse { - errorToNextStep(state, it) ?.let { return it } ?: throw it - }.also(::println) - } - - suspend fun errorToNextStep( - currentState: T, - e: Throwable - ): UIFSMState? = when (e) { - is AuthUnavailableException -> if (currentState is AuthUIFSMState) { - currentState - } else { - AuthUIFSMState(currentState) - } - else -> null - } -} diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSMState.kt b/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSMState.kt deleted file mode 100644 index a56f4e79..00000000 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSMState.kt +++ /dev/null @@ -1,30 +0,0 @@ -package dev.inmo.postssystem.client.ui.fsm - -import dev.inmo.micro_utils.fsm.common.State -import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer -import kotlinx.serialization.* - -@Serializable(UIFSMStateSerializer::class) -sealed interface UIFSMState : State { - val from: UIFSMState? - get() = null - override val context: String - get() = "main" -} - -object UIFSMStateSerializer : KSerializer by TypedSerializer( - "auth" to AuthUIFSMState.serializer(), -) - -@Serializable -data class AuthUIFSMState( - override val from: UIFSMState? = CreatePostUIFSMState(), - override val context: String = "main" -) : UIFSMState -val DefaultAuthUIFSMState = AuthUIFSMState() - -@Serializable -data class CreatePostUIFSMState( - override val from: UIFSMState? = null, - override val context: String = "main" -) : UIFSMState diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSDI.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSDI.kt index 60adbb7a..c814d93f 100644 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSDI.kt +++ b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSDI.kt @@ -1,23 +1,23 @@ package dev.inmo.postssystem.client import dev.inmo.postssystem.client.fsm.ui.* -import dev.inmo.postssystem.client.ui.* -import dev.inmo.postssystem.client.ui.fsm.* -import dev.inmo.postssystem.client.ui.fsm.UIFSMStateSerializer -import dev.inmo.postssystem.features.auth.client.ui.AuthUIModel -import dev.inmo.postssystem.features.auth.client.ui.AuthUIViewModel import dev.inmo.postssystem.features.auth.common.AuthTokenInfo import dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler import dev.inmo.micro_utils.fsm.common.CheckableHandlerHolder import dev.inmo.micro_utils.fsm.common.StatesMachine import dev.inmo.micro_utils.repos.mappers.withMapper import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer -import dev.inmo.postssystem.client.settings.auth.AuthSettings +import dev.inmo.postssystem.features.auth.client.settings.AuthSettings +import dev.inmo.postssystem.features.auth.client.ui.* +import dev.inmo.postssystem.features.common.common.baseKoin import dev.inmo.postssystem.features.common.common.getAllDistinct +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMHandler +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMStateSerializer import dev.inmo.postssystem.services.posts.client.ui.create.* import kotlinx.browser.* import kotlinx.coroutines.* import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.Json import kotlinx.serialization.serializer import org.koin.core.Koin import org.koin.core.context.loadKoinModules @@ -38,6 +38,9 @@ val defaultTypedSerializer = TypedSerializer( "Double" to Double.serializer(), "UIFSMState" to UIFSMStateSerializer ) +val defaultSerialFormat = Json { + ignoreUnknownKeys = true +} fun baseKoin(): Koin { val anyToString: suspend Any.() -> String = { @@ -81,66 +84,19 @@ fun baseKoin(): Koin { JSUIFSMStatesRepo(window.history) } ) { + val scope = first first.apply { second.apply { loadKoinModules( module { factory { document.getElementById("main") as HTMLElement } - - factory { DefaultAuthUIModel(get(), get()) } - factory { AuthUIViewModel(get()) } - factory { AuthView(get(), get(UIScopeQualifier)) } - - factory { DefaultPostCreateUIModel(get(), get()) } - factory { PostCreateUIViewModel(get()) } - factory { PostCreateView(get(), getAllDistinct(), get(UIScopeQualifier)) } } ) - strictlyOn(get()) - - // Костыль, в JS на момент Пн дек 6 14:19:29 +06 2021 если использовать strictlyOn генерируются - // некорректные безымянные классы (у них отсутствует метод handleState) - class DefaultStateHandlerWrapper( - private val klass: KClass>, - private val stateKlass: KClass, - private val qualifier: Qualifier? = null, - private val parameters: ((T) -> ParametersHolder)? = null - ) : CheckableHandlerHolder { - override suspend fun StatesMachine.handleState(state: UIFSMState): UIFSMState? { - @Suppress("UNCHECKED_CAST", "NAME_SHADOWING") - val state = state as T - return runCatching { - val authSettings = get() - authSettings.loadingJob.join() - if (authSettings.authorizedDIModule.value == null) { - error("Can't perform state $state: Auth module was not initialized") - } else { - get>(klass, qualifier, parameters ?.let { { it(state) } }).run { - handleState(state) - } - } - }.getOrElse { e -> - e.printStackTrace() - AuthUIFSMState(state) - } + getAllDistinct().forEach { + with(it) { + include() } - - override suspend fun checkHandleable(state: UIFSMState): Boolean = stateKlass.isInstance(state) } - inline fun registerHandler( - klass: KClass>, - qualifier: Qualifier? = null, - parameters: ((T) -> ParametersHolder)? = null - ) = add( - DefaultStateHandlerWrapper( - klass, - T::class, - qualifier, - parameters - ) - ) - - registerHandler(PostCreateView::class) } } } diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSUIFSMStatesRepo.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSUIFSMStatesRepo.kt index b95306c3..e0d289f2 100644 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSUIFSMStatesRepo.kt +++ b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/JSUIFSMStatesRepo.kt @@ -1,7 +1,7 @@ package dev.inmo.postssystem.client -import dev.inmo.postssystem.client.ui.fsm.* import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState import kotlinx.browser.window import kotlinx.serialization.StringFormat import org.w3c.dom.* diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/Main.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/Main.kt index afd3c3e2..40386662 100644 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/Main.kt +++ b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/Main.kt @@ -1,14 +1,13 @@ package dev.inmo.postssystem.client - -import dev.inmo.postssystem.client.ui.fsm.UIFSMQualifier -import dev.inmo.postssystem.client.ui.fsm.UIFSMState import dev.inmo.micro_utils.fsm.common.StatesMachine +import dev.inmo.postssystem.features.common.common.DefaultQualifiers +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState import kotlinx.browser.window fun main() { window.addEventListener("load", { val koin = baseKoin() - val uiStatesMachine = koin.get>(UIFSMQualifier) + val uiStatesMachine = koin.get>(DefaultQualifiers.UIFSMQualifier) uiStatesMachine.start(koin.get()) }) } diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/Container.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/Container.kt deleted file mode 100644 index 6ccbc6ab..00000000 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/Container.kt +++ /dev/null @@ -1,7 +0,0 @@ -package dev.inmo.postssystem.client.fsm.ui - -import kotlinx.browser.document -import org.w3c.dom.Element - -val mainContainer: Element - get() = document.getElementById("main")!! diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/DownloadFile.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/DownloadFile.kt deleted file mode 100644 index b8cc2f68..00000000 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/DownloadFile.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.inmo.postssystem.client.utils - -import dev.inmo.postssystem.features.files.common.FullFileInfo -import dev.inmo.micro_utils.common.toArrayBuffer -import io.ktor.utils.io.core.readBytes -import kotlinx.browser.document -import org.w3c.dom.HTMLAnchorElement -import org.w3c.dom.url.URL -import org.w3c.files.Blob - -fun triggerDownloadFile(fullFileInfo: FullFileInfo) { - val hiddenElement = document.createElement("a") as HTMLAnchorElement - - val url = URL.createObjectURL(Blob(arrayOf(fullFileInfo.inputProvider().readBytes().toArrayBuffer()))) - hiddenElement.href = url - hiddenElement.target = "_blank" - hiddenElement.download = fullFileInfo.name.name - hiddenElement.click() -} diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/LinkCompositionToJob.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/LinkCompositionToJob.kt deleted file mode 100644 index 9e8a9522..00000000 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/LinkCompositionToJob.kt +++ /dev/null @@ -1,25 +0,0 @@ -package dev.inmo.postssystem.client.utils - -import androidx.compose.runtime.* -import kotlinx.coroutines.* -import org.jetbrains.compose.web.dom.DOMScope -import org.w3c.dom.Element -import kotlin.coroutines.CoroutineContext - -fun Composition.linkWithJob(job: Job) { - job.invokeOnCompletion { - this@linkWithJob.dispose() - } -} - -fun Composition.linkWithContext(coroutineContext: CoroutineContext) = linkWithJob(coroutineContext.job) - -suspend fun renderComposableAndLinkToContext( - root: TElement, - monotonicFrameClock: MonotonicFrameClock = DefaultMonotonicFrameClock, - content: @Composable DOMScope.() -> Unit -): Composition = org.jetbrains.compose.web.renderComposable(root, monotonicFrameClock, content).apply { - linkWithContext( - currentCoroutineContext() - ) -} diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/UploadFile.kt b/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/UploadFile.kt deleted file mode 100644 index 0ac0df03..00000000 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/utils/UploadFile.kt +++ /dev/null @@ -1,77 +0,0 @@ -package dev.inmo.postssystem.client.utils - -import androidx.compose.runtime.MutableState -import dev.inmo.postssystem.features.files.common.FullFileInfo -import dev.inmo.micro_utils.common.* -import dev.inmo.micro_utils.mime_types.KnownMimeTypes -import dev.inmo.micro_utils.mime_types.findBuiltinMimeType -import dev.inmo.postssystem.features.common.common.BytesBasedInputProvider -import io.ktor.utils.io.core.ByteReadPacket -import kotlinx.coroutines.flow.MutableStateFlow -import org.khronos.webgl.ArrayBuffer -import org.w3c.dom.HTMLInputElement -import org.w3c.dom.events.Event -import org.w3c.files.FileReader -import org.w3c.files.get - -fun uploadFileCallbackForHTMLInputChange( - onSet: (FullFileInfo) -> Unit -): (Event) -> Unit = { - (it.target as? HTMLInputElement) ?.apply { - files ?.also { files -> - files[0] ?.also { file -> - val reader: FileReader = FileReader() - - reader.onload = { - val bytes = ((it.target.asDynamic()).result as ArrayBuffer).toByteArray() - onSet( - FullFileInfo( - FileName(file.name), - findBuiltinMimeType(file.type) ?: KnownMimeTypes.Any, - BytesBasedInputProvider(bytes) - ) - ) - } - - reader.readAsArrayBuffer(file) - } - } - } -} - -fun fileCallbackForHTMLInputChange( - onSet: (MPPFile) -> Unit -): (Event) -> Unit = { - (it.target as? HTMLInputElement) ?.apply { - files ?.also { files -> - files[0] ?.also { file -> - onSet(file) - } - } - } -} - -fun uploadFileCallbackForHTMLInputChange( - output: MutableState -): (Event) -> Unit = uploadFileCallbackForHTMLInputChange { - output.value = it -} - -fun uploadFileCallbackForHTMLInputChange( - output: MutableStateFlow -): (Event) -> Unit = uploadFileCallbackForHTMLInputChange { - output.value = it -} - -fun fileCallbackForHTMLInputChange( - output: MutableState -): (Event) -> Unit = fileCallbackForHTMLInputChange { - output.value = it -} - -fun fileCallbackForHTMLInputChange( - output: MutableStateFlow -): (Event) -> Unit = fileCallbackForHTMLInputChange { - output.value = it -} - diff --git a/features/auth/client/build.gradle b/features/auth/client/build.gradle index 68e48b37..e0086cea 100644 --- a/features/auth/client/build.gradle +++ b/features/auth/client/build.gradle @@ -2,6 +2,7 @@ plugins { id "org.jetbrains.kotlin.multiplatform" id "org.jetbrains.kotlin.plugin.serialization" id "com.android.library" + alias(libs.plugins.compose) } apply from: "$mppProjectWithSerializationPresetPath" @@ -11,8 +12,14 @@ kotlin { commonMain { dependencies { api project(":postssystem.features.common.client") + api project(":postssystem.features.roles.client") + api project(":postssystem.features.status.client") api project(":postssystem.features.auth.common") } } + clientMain { + dependencies { + } + } } } diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedFeaturesModules.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedFeaturesModules.kt new file mode 100644 index 00000000..5fda8a90 --- /dev/null +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedFeaturesModules.kt @@ -0,0 +1,39 @@ +package dev.inmo.postssystem.features.auth.client + +import dev.inmo.micro_utils.common.Either +import dev.inmo.micro_utils.ktor.client.UnifiedRequester +import dev.inmo.postssystem.features.auth.common.AuthKey +import dev.inmo.postssystem.features.auth.common.AuthTokenInfo +import dev.inmo.postssystem.features.common.common.AdditionalModules +import dev.inmo.postssystem.features.status.client.StatusFeatureClient +import dev.inmo.postssystem.features.users.common.User +import io.ktor.client.HttpClient +import org.koin.core.module.Module +import org.koin.dsl.module + +fun createAuthorizedFeaturesDIModule( + serverUrl: String, + initialAuthKey: Either, + onAuthKeyUpdated: suspend (AuthTokenInfo) -> Unit, + onUserRetrieved: suspend (User?) -> Unit, + onAuthKeyInvalidated: suspend () -> Unit +): Module { + return module { + single(AuthorizedQualifiers.CredsQualifier) { initialAuthKey } + single(AuthorizedQualifiers.ServerUrlQualifier) { serverUrl } + + single (createdAtStart = true) { + HttpClient { + installClientAuthenticator(serverUrl, get(), get(AuthorizedQualifiers.CredsQualifier), onAuthKeyUpdated, onUserRetrieved, onAuthKeyInvalidated) + } + } + single { UnifiedRequester(get(), get()) } + single { StatusFeatureClient(get(AuthorizedQualifiers.ServerUrlQualifier), get()) } + + AdditionalModules.Authorized.modules.forEach { + with(it) { + load() + } + } + } +} diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedModuleLoader.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedModuleLoader.kt new file mode 100644 index 00000000..77f41809 --- /dev/null +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedModuleLoader.kt @@ -0,0 +1,15 @@ +package dev.inmo.postssystem.features.auth.client + +import dev.inmo.postssystem.features.common.common.AdditionalModules +import dev.inmo.postssystem.features.common.common.ModuleLoader +import org.koin.core.module.Module + +private val AuthorizedAdditionalModules = AdditionalModules() +val AdditionalModules.Companion.Authorized: AdditionalModules + get() = AuthorizedAdditionalModules + +fun AuthorizedModuleLoader(loadingBlock: Module.() -> Unit): ModuleLoader.ByCallback { + val newModuleLoader = ModuleLoader.ByCallback(loadingBlock) + AdditionalModules.Authorized.addModule(newModuleLoader) + return newModuleLoader +} diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedQualifiers.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedQualifiers.kt new file mode 100644 index 00000000..6cc2fe8e --- /dev/null +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedQualifiers.kt @@ -0,0 +1,8 @@ +package dev.inmo.postssystem.features.auth.client + +import org.koin.core.qualifier.StringQualifier + +object AuthorizedQualifiers { + val CredsQualifier = StringQualifier("creds") + val ServerUrlQualifier = StringQualifier("serverUrl") +} diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/BehindAuthUIFSMHandler.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/BehindAuthUIFSMHandler.kt new file mode 100644 index 00000000..e0c60824 --- /dev/null +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/BehindAuthUIFSMHandler.kt @@ -0,0 +1,59 @@ +package dev.inmo.postssystem.features.auth.client + +import dev.inmo.micro_utils.fsm.common.CheckableHandlerHolder +import dev.inmo.micro_utils.fsm.common.StatesMachine +import dev.inmo.micro_utils.fsm.common.dsl.FSMBuilder +import dev.inmo.postssystem.features.auth.client.settings.AuthSettings +import dev.inmo.postssystem.features.auth.client.ui.AuthUIFSMState +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMHandler +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState +import org.koin.core.Koin +import org.koin.core.parameter.ParametersHolder +import org.koin.core.qualifier.Qualifier +import org.koin.core.scope.Scope +import kotlin.reflect.KClass + +// Костыль, в JS на момент Пн дек 6 14:19:29 +06 2021 если использовать strictlyOn генерируются +// некорректные безымянные классы (у них отсутствует метод handleState) +class DefaultStateHandlerWrapper( + private val klass: KClass>, + private val koin: Koin, + private val stateKlass: KClass, + private val qualifier: Qualifier? = null, + private val parameters: ((T) -> ParametersHolder)? = null +) : CheckableHandlerHolder { + override suspend fun StatesMachine.handleState(state: UIFSMState): UIFSMState? { + @Suppress("UNCHECKED_CAST", "NAME_SHADOWING") + val state = state as T + return runCatching { + val authSettings = koin.get() + authSettings.loadingJob.join() + if (authSettings.authorizedDIModule.value == null) { + error("Can't perform state $state: Auth module was not initialized") + } else { + koin.get>(klass, qualifier, parameters ?.let { { it(state) } }).run { + handleState(state) + } + } + }.getOrElse { e -> + e.printStackTrace() + AuthUIFSMState(state) + } + } + + override suspend fun checkHandleable(state: UIFSMState): Boolean = stateKlass.isInstance(state) +} +inline fun FSMBuilder.registerAfterAuthHandler( + koin: Koin, + klass: KClass>, + qualifier: Qualifier? = null, + noinline parameters: ((T) -> ParametersHolder)? = null +) = add( + DefaultStateHandlerWrapper( + klass, + koin, + T::class, + qualifier, + parameters + ) +) diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ModuleLoader.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ModuleLoader.kt new file mode 100644 index 00000000..7de13c6e --- /dev/null +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ModuleLoader.kt @@ -0,0 +1,27 @@ +package dev.inmo.postssystem.features.auth.client + +import dev.inmo.micro_utils.common.Optional +import dev.inmo.micro_utils.common.optional +import dev.inmo.postssystem.features.auth.client.settings.AuthSettings +import dev.inmo.postssystem.features.auth.client.settings.DefaultAuthSettings +import dev.inmo.postssystem.features.auth.client.ui.* +import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMExceptionHandler +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState + +val defaultModuleLoader = DefaultModuleLoader { + single { DefaultAuthSettings(get(DefaultQualifiers.SettingsQualifier), get(), getKoin(), get()) } + + singleWithRandomQualifier { + UIFSMExceptionHandler { currentState, exception -> + if (exception is AuthUnavailableException) { + Optional.presented(AuthUIFSMState(currentState)) + } else { + Optional.absent() + } + } + } + + factory { DefaultAuthUIModel(get(), get()) } + factory { AuthUIViewModel(get()) } +} diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/auth/AuthSettings.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt similarity index 90% rename from client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/auth/AuthSettings.kt rename to features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt index 56a56215..7a527fb2 100644 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/auth/AuthSettings.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt @@ -1,4 +1,4 @@ -package dev.inmo.postssystem.client.settings.auth +package dev.inmo.postssystem.features.auth.client.settings import dev.inmo.postssystem.features.auth.client.ui.AuthUIError import dev.inmo.postssystem.features.auth.common.AuthCreds diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/auth/DefaultAuthSettings.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt similarity index 94% rename from client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/auth/DefaultAuthSettings.kt rename to features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt index 2570b54d..27e9a68d 100644 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/settings/auth/DefaultAuthSettings.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt @@ -1,7 +1,5 @@ -package dev.inmo.postssystem.client.settings.auth +package dev.inmo.postssystem.features.auth.client.settings -import dev.inmo.postssystem.client.DBDropper -import dev.inmo.postssystem.client.getAuthorizedFeaturesDIModule import dev.inmo.postssystem.features.auth.client.AuthUnavailableException import dev.inmo.postssystem.features.auth.client.ui.* import dev.inmo.postssystem.features.auth.common.* @@ -14,6 +12,8 @@ import dev.inmo.micro_utils.common.either import dev.inmo.micro_utils.coroutines.plus import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.repos.* +import dev.inmo.postssystem.features.auth.client.createAuthorizedFeaturesDIModule +import dev.inmo.postssystem.features.common.common.DBDropper import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import org.koin.core.Koin @@ -73,7 +73,7 @@ data class DefaultAuthSettings( initialAuthKey: Either, ): AuthUIError? { val currentModule = authorizedDIModule.value - val newModule = getAuthorizedFeaturesDIModule( + val newModule = createAuthorizedFeaturesDIModule( serverUrl, initialAuthKey, { diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIFSMState.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIFSMState.kt new file mode 100644 index 00000000..25830c75 --- /dev/null +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIFSMState.kt @@ -0,0 +1,14 @@ +package dev.inmo.postssystem.features.auth.client.ui + +import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState +import kotlinx.serialization.Serializable + +@Serializable +data class AuthUIFSMState( + override val from: UIFSMState?, + override val context: String = "main" +) : UIFSMState { + companion object { + val default = AuthUIFSMState(null) + } +} diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIModel.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIModel.kt index ef48152a..b704d717 100644 --- a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIModel.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIModel.kt @@ -1,7 +1,7 @@ package dev.inmo.postssystem.features.auth.client.ui import dev.inmo.postssystem.features.auth.common.AuthCreds -import dev.inmo.postssystem.features.common.common.UIModel +import dev.inmo.postssystem.features.common.common.ui.UIModel interface AuthUIModel : UIModel { suspend fun initAuth(serverUrl: String, creds: AuthCreds) diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIViewModel.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIViewModel.kt index be1d3945..ccbc7b00 100644 --- a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIViewModel.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIViewModel.kt @@ -1,7 +1,7 @@ package dev.inmo.postssystem.features.auth.client.ui import dev.inmo.postssystem.features.auth.common.AuthCreds -import dev.inmo.postssystem.features.common.common.UIViewModel +import dev.inmo.postssystem.features.common.common.ui.UIViewModel import dev.inmo.postssystem.features.users.common.Username import kotlinx.coroutines.flow.StateFlow diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/DefaultAuthUIModel.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/DefaultAuthUIModel.kt similarity index 82% rename from client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/DefaultAuthUIModel.kt rename to features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/DefaultAuthUIModel.kt index 959bb8c5..65de6bf1 100644 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/DefaultAuthUIModel.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/DefaultAuthUIModel.kt @@ -1,9 +1,8 @@ -package dev.inmo.postssystem.client.ui +package dev.inmo.postssystem.features.auth.client.ui -import dev.inmo.postssystem.client.settings.auth.AuthSettings -import dev.inmo.postssystem.features.auth.client.ui.* +import dev.inmo.postssystem.features.auth.client.settings.AuthSettings import dev.inmo.postssystem.features.auth.common.AuthCreds -import dev.inmo.postssystem.features.common.common.AbstractUIModel +import dev.inmo.postssystem.features.common.common.ui.AbstractUIModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/AuthView.kt b/features/auth/client/src/jsMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthView.kt similarity index 81% rename from client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/AuthView.kt rename to features/auth/client/src/jsMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthView.kt index 0f60e976..7b516807 100644 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/AuthView.kt +++ b/features/auth/client/src/jsMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthView.kt @@ -1,28 +1,38 @@ -package dev.inmo.postssystem.client.fsm.ui +package dev.inmo.postssystem.features.auth.client import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import dev.inmo.jsuikit.elements.* import dev.inmo.jsuikit.modifiers.* import dev.inmo.jsuikit.utils.Attrs -import dev.inmo.postssystem.client.ui.fsm.* +import dev.inmo.micro_utils.coroutines.compose.renderComposableAndLinkToContextAndRoot import dev.inmo.postssystem.features.auth.client.ui.* import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.fsm.common.StatesMachine -import dev.inmo.postssystem.client.utils.renderComposableAndLinkToContext +import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.common.common.ui.JSView +import dev.inmo.postssystem.features.common.common.ui.fsm.* import kotlinx.browser.document import kotlinx.coroutines.* import kotlinx.dom.* import org.jetbrains.compose.web.attributes.InputType -import org.jetbrains.compose.web.dom.* import org.jetbrains.compose.web.dom.Text import org.w3c.dom.* +val loader = DefaultModuleLoader { + factory { AuthView(get(), get(DefaultQualifiers.UIScopeQualifier), getAllDistinct()) } + singleWithRandomQualifier { + UIFSMHandler.Registrator { + strictlyOn(get()) + } + } +} + class AuthView( private val viewModel: AuthUIViewModel, - private val uiScope: CoroutineScope -) : JSView() { + private val uiScope: CoroutineScope, + defaultExceptionsHandlers: Iterable +) : JSView(defaultExceptionsHandlers) { override suspend fun StatesMachine.safeHandleState( htmlElement: HTMLElement, @@ -36,7 +46,7 @@ class AuthView( val errorText = mutableStateOf(null) val root = htmlElement.appendElement("div") {} - val composition = renderComposableAndLinkToContext(root) { + val composition = renderComposableAndLinkToContextAndRoot(root) { val authBtnDisabled = usernameState.value.isBlank() || passwordState.value.isBlank() Flex( diff --git a/features/common/client/build.gradle b/features/common/client/build.gradle index 46b55ea2..7fc2be43 100644 --- a/features/common/client/build.gradle +++ b/features/common/client/build.gradle @@ -16,6 +16,11 @@ kotlin { api "io.ktor:ktor-client-auth:$ktor_version" api "io.ktor:ktor-client-logging:$ktor_version" + api libs.microutils.common.compose + api libs.microutils.coroutines.compose + api libs.microutils.fsm.common + api libs.microutils.fsm.repos.common + api compose.runtime } } diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/AdditionalModules.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/AdditionalModules.kt index 18bd469a..44f0d06e 100644 --- a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/AdditionalModules.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/AdditionalModules.kt @@ -1,6 +1,6 @@ package dev.inmo.postssystem.features.common.common -object AdditionalModules { +class AdditionalModules { private val additionalModules = mutableListOf() val modules: List get() = additionalModules.toList() @@ -8,4 +8,8 @@ object AdditionalModules { fun addModule(moduleLoader: ModuleLoader): Boolean { return additionalModules.add(moduleLoader) } + + companion object { + val Default = AdditionalModules() + } } diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DBDropper.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DBDropper.kt similarity index 84% rename from client/src/commonMain/kotlin/dev/inmo/postssystem/client/DBDropper.kt rename to features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DBDropper.kt index 66496163..3e6168c2 100644 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/DBDropper.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DBDropper.kt @@ -1,4 +1,4 @@ -package dev.inmo.postssystem.client +package dev.inmo.postssystem.features.common.common import dev.inmo.micro_utils.pagination.utils.getAllByWithNextPaging import dev.inmo.micro_utils.repos.KeyValueRepo diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultModules.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultModules.kt new file mode 100644 index 00000000..ed3f8c1d --- /dev/null +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultModules.kt @@ -0,0 +1,67 @@ +package dev.inmo.postssystem.features.common.common + +import dev.inmo.micro_utils.coroutines.LinkedSupervisorScope +import dev.inmo.micro_utils.fsm.common.StatesMachine +import dev.inmo.micro_utils.fsm.common.dsl.FSMBuilder +import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo +import dev.inmo.micro_utils.repos.KeyValueRepo +import dev.inmo.postssystem.features.common.common.ui.fsm.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.serialization.BinaryFormat +import kotlinx.serialization.StringFormat +import kotlinx.serialization.cbor.Cbor +import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule +import org.koin.core.Koin +import org.koin.core.context.startKoin +import org.koin.core.scope.Scope +import org.koin.dsl.module + +/** + * Entrypoint for getting [org.koin.core.Koin] DI for the client + * + * @param repoFactory Factory for creating of [DefaultStatesManagerRepo] for [dev.inmo.postssystem.client.ui.fsm.UIFSM] + */ +fun baseKoin( + defaultScope: CoroutineScope, + settingsFactory: Scope.() -> KeyValueRepo, + repoFactory: Scope.() -> DefaultStatesManagerRepo, + handlersSetter: Pair>.() -> Unit +): Koin = startKoin { + modules( + module { + single { + Json { + ignoreUnknownKeys = true + serializersModule = SerializersModule { get().apply { invoke() } } + } + } + single { get() } + single { + Cbor { serializersModule = SerializersModule { get().apply { invoke() } } } + } + single { get() } + + single(DefaultQualifiers.SettingsQualifier) { settingsFactory() } + single { DBDropper(get(DefaultQualifiers.SettingsQualifier)) } + single(DefaultQualifiers.FSMHandlersBuilderQualifier) { handlersSetter } + single { repoFactory() } + single { defaultScope } + single(DefaultQualifiers.UIScopeQualifier) { get().LinkedSupervisorScope(Dispatchers.Main) } + single>(UIFSMQualifier) { UIFSM(get()) { (this@single to this@UIFSM).apply(get( + DefaultQualifiers.FSMHandlersBuilderQualifier + )) } } + + AdditionalModules.Default.modules.forEach { + it.apply { load() } + } + } + ) +}.koin.apply { + loadModules( + listOf( + module { single { this@apply } } + ) + ) +} diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultQualifiers.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultQualifiers.kt new file mode 100644 index 00000000..112d503d --- /dev/null +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultQualifiers.kt @@ -0,0 +1,10 @@ +package dev.inmo.postssystem.features.common.common + +import org.koin.core.qualifier.StringQualifier + +object DefaultQualifiers { + val SettingsQualifier = StringQualifier("Settings") + val FSMHandlersBuilderQualifier = StringQualifier("FSMHandlersBuilder") + val UIScopeQualifier = StringQualifier("CoroutineScopeUI") + val UIFSMQualifier = StringQualifier("FSM") +} diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ModuleLoader.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ModuleLoader.kt index bf35ccc9..653cbd49 100644 --- a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ModuleLoader.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ModuleLoader.kt @@ -2,6 +2,18 @@ package dev.inmo.postssystem.features.common.common import org.koin.core.module.Module -fun interface ModuleLoader { +interface ModuleLoader { fun Module.load() + + class ByCallback(private val loadingBlock: Module.() -> Unit) : ModuleLoader { + override fun Module.load() { + loadingBlock() + } + } +} + +fun DefaultModuleLoader(loadingBlock: Module.() -> Unit): ModuleLoader.ByCallback { + val newModuleLoader = ModuleLoader.ByCallback(loadingBlock) + AdditionalModules.Default.addModule(newModuleLoader) + return newModuleLoader } diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIView.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIView.kt deleted file mode 100644 index 3e2be96a..00000000 --- a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIView.kt +++ /dev/null @@ -1,4 +0,0 @@ -package dev.inmo.postssystem.features.common.common - -interface UIView { -} diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultUIFlow.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DefaultUIFlow.kt similarity index 70% rename from features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultUIFlow.kt rename to features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DefaultUIFlow.kt index f9fe1895..815833fd 100644 --- a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultUIFlow.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DefaultUIFlow.kt @@ -1,4 +1,4 @@ -package dev.inmo.postssystem.features.common.common +package dev.inmo.postssystem.features.common.common.ui import kotlinx.coroutines.flow.MutableStateFlow diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIModel.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIModel.kt similarity index 88% rename from features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIModel.kt rename to features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIModel.kt index 970fc36c..33a6026b 100644 --- a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIModel.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIModel.kt @@ -1,4 +1,4 @@ -package dev.inmo.postssystem.features.common.common +package dev.inmo.postssystem.features.common.common.ui import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIView.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIView.kt new file mode 100644 index 00000000..fa6213d8 --- /dev/null +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIView.kt @@ -0,0 +1,4 @@ +package dev.inmo.postssystem.features.common.common.ui + +interface UIView { +} diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIViewModel.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIViewModel.kt similarity index 64% rename from features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIViewModel.kt rename to features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIViewModel.kt index 306d5260..3de4c939 100644 --- a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIViewModel.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIViewModel.kt @@ -1,4 +1,4 @@ -package dev.inmo.postssystem.features.common.common +package dev.inmo.postssystem.features.common.common.ui import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -7,9 +7,7 @@ interface UIViewModel { val currentState: StateFlow } -abstract class AbstractUIViewModel : UIViewModel { - protected val _currentState = DefaultMVVMStateFlow(initState()) +abstract class AbstractUIViewModel(initState: StateType) : UIViewModel { + protected val _currentState = DefaultMVVMStateFlow(initState) override val currentState: StateFlow = _currentState.asStateFlow() - - abstract fun initState(): StateType } diff --git a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSM.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSM.kt similarity index 90% rename from client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSM.kt rename to features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSM.kt index 0255095b..ceec5541 100644 --- a/client/src/commonMain/kotlin/dev/inmo/postssystem/client/ui/fsm/UIFSM.kt +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSM.kt @@ -1,4 +1,4 @@ -package dev.inmo.postssystem.client.ui.fsm +package dev.inmo.postssystem.features.common.common.ui.fsm import dev.inmo.micro_utils.fsm.common.dsl.FSMBuilder import dev.inmo.micro_utils.fsm.common.dsl.buildFSM diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMExceptionHandler.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMExceptionHandler.kt new file mode 100644 index 00000000..ac7994ef --- /dev/null +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMExceptionHandler.kt @@ -0,0 +1,7 @@ +package dev.inmo.postssystem.features.common.common.ui.fsm + +import dev.inmo.micro_utils.common.Optional + +fun interface UIFSMExceptionHandler { + suspend fun handle(currentState: UIFSMState, exception: Throwable): Optional +} diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMHandler.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMHandler.kt new file mode 100644 index 00000000..5aa61c04 --- /dev/null +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMHandler.kt @@ -0,0 +1,34 @@ +package dev.inmo.postssystem.features.common.common.ui.fsm + +import dev.inmo.micro_utils.common.onPresented +import dev.inmo.micro_utils.fsm.common.* +import dev.inmo.micro_utils.fsm.common.dsl.FSMBuilder +import org.koin.core.scope.Scope + +interface UIFSMHandler : StatesHandler { + fun interface Registrator { + fun FSMBuilder.include() + } + val defaultExceptionsHandlers: Iterable + + suspend fun StatesMachine.safeHandleState(state: T): UIFSMState? + override suspend fun StatesMachine.handleState(state: T): UIFSMState? { + return runCatching { + safeHandleState(state).also(::println) + }.getOrElse { + errorToNextStep(state, it) ?.let { return it } ?: throw it + }.also(::println) + } + + suspend fun errorToNextStep( + currentState: T, + e: Throwable + ): UIFSMState? { + defaultExceptionsHandlers.forEach { + it.handle(currentState, e).onPresented { state -> + return state + } + } + return null + } +} diff --git a/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMState.kt b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMState.kt new file mode 100644 index 00000000..7dd5eae4 --- /dev/null +++ b/features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMState.kt @@ -0,0 +1,17 @@ +package dev.inmo.postssystem.features.common.common.ui.fsm + +import dev.inmo.micro_utils.fsm.common.State +import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer +import kotlinx.serialization.* + +@Serializable(UIFSMStateSerializer::class) +interface UIFSMState : State { + val from: UIFSMState? + get() = null + override val context: String + get() = "main" +} + +object UIFSMStateSerializer : KSerializer, TypedSerializer( + UIFSMState::class +) diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/JSView.kt b/features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/JSView.kt similarity index 65% rename from client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/JSView.kt rename to features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/JSView.kt index 925563d0..b716eac0 100644 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/JSView.kt +++ b/features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/JSView.kt @@ -1,12 +1,13 @@ -package dev.inmo.postssystem.client.fsm.ui +package dev.inmo.postssystem.features.common.common.ui -import dev.inmo.postssystem.client.ui.fsm.UIFSMHandler -import dev.inmo.postssystem.client.ui.fsm.UIFSMState import dev.inmo.micro_utils.fsm.common.StatesMachine +import dev.inmo.postssystem.features.common.common.ui.fsm.* import kotlinx.browser.document import org.w3c.dom.HTMLElement -abstract class JSView : UIFSMHandler { +abstract class JSView( + override val defaultExceptionsHandlers: Iterable +) : UIFSMHandler { open suspend fun StatesMachine.safeHandleState( htmlElement: HTMLElement, state: T diff --git a/features/content/binary/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/binary/client/BinaryContentClientProvider.kt b/features/content/binary/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/binary/client/BinaryContentClientProvider.kt index c368c34b..a033fdec 100644 --- a/features/content/binary/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/binary/client/BinaryContentClientProvider.kt +++ b/features/content/binary/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/binary/client/BinaryContentClientProvider.kt @@ -11,7 +11,7 @@ import org.koin.core.module.Module object LoadingClientModule : ModuleLoader { init { - AdditionalModules.addModule(this) + AdditionalModules.Default.addModule(this) } override fun Module.load() { diff --git a/features/content/client/src/commonMain/kotlin/dev/inmo/postssystem/features/content/client/ModuleLoader.kt b/features/content/client/src/commonMain/kotlin/dev/inmo/postssystem/features/content/client/ModuleLoader.kt new file mode 100644 index 00000000..e1921743 --- /dev/null +++ b/features/content/client/src/commonMain/kotlin/dev/inmo/postssystem/features/content/client/ModuleLoader.kt @@ -0,0 +1,11 @@ +package dev.inmo.postssystem.features.content.client + +import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.content.common.ContentSerializersModuleConfigurator +import dev.inmo.postssystem.features.content.common.OtherContentSerializerModuleConfigurator + +val loader = DefaultModuleLoader { + singleWithRandomQualifier { OtherContentSerializerModuleConfigurator } + singleWithRandomQualifier { ContentSerializersModuleConfigurator(getAll()) } + single { SerializersModuleConfigurator(getAll()) } +} diff --git a/features/content/text/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/text/client/TextContentClientProvider.kt b/features/content/text/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/text/client/TextContentClientProvider.kt index 5a89050e..c913c07b 100644 --- a/features/content/text/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/text/client/TextContentClientProvider.kt +++ b/features/content/text/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/text/client/TextContentClientProvider.kt @@ -12,7 +12,7 @@ import org.koin.core.module.Module object LoadingClientModule : ModuleLoader { init { - AdditionalModules.addModule(this) + AdditionalModules.Default.addModule(this) } override fun Module.load() { diff --git a/features/files/client/build.gradle b/features/files/client/build.gradle index 06f00298..10a10946 100644 --- a/features/files/client/build.gradle +++ b/features/files/client/build.gradle @@ -12,6 +12,7 @@ kotlin { dependencies { api project(":postssystem.features.files.common") api project(":postssystem.features.common.client") + api project(":postssystem.features.auth.client") } } } diff --git a/features/files/client/src/commonMain/kotlin/dev/inmo/postssystem/features/files/client/ModuleLoader.kt b/features/files/client/src/commonMain/kotlin/dev/inmo/postssystem/features/files/client/ModuleLoader.kt new file mode 100644 index 00000000..d535be20 --- /dev/null +++ b/features/files/client/src/commonMain/kotlin/dev/inmo/postssystem/features/files/client/ModuleLoader.kt @@ -0,0 +1,9 @@ +package dev.inmo.postssystem.features.files.client + +import dev.inmo.postssystem.features.auth.client.AuthorizedModuleLoader +import dev.inmo.postssystem.features.auth.client.AuthorizedQualifiers +import dev.inmo.postssystem.features.files.common.storage.ReadFilesStorage + +val loader = AuthorizedModuleLoader { + single { ClientReadFilesStorage(get(AuthorizedQualifiers.ServerUrlQualifier), get(), get()) } +} diff --git a/features/roles/client/build.gradle b/features/roles/client/build.gradle index dcc31f41..1d75a244 100644 --- a/features/roles/client/build.gradle +++ b/features/roles/client/build.gradle @@ -12,6 +12,7 @@ kotlin { dependencies { api project(":postssystem.features.roles.common") api project(":postssystem.features.common.client") + api project(":postssystem.features.auth.client") } } } diff --git a/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/ModuleLoader.kt b/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/ModuleLoader.kt new file mode 100644 index 00000000..8b4fef65 --- /dev/null +++ b/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/ModuleLoader.kt @@ -0,0 +1,10 @@ +package dev.inmo.postssystem.features.roles.client + +import dev.inmo.postssystem.features.auth.client.AuthorizedModuleLoader +import dev.inmo.postssystem.features.auth.client.AuthorizedQualifiers +import dev.inmo.postssystem.features.roles.common.Role +import dev.inmo.postssystem.features.roles.common.RolesStorage + +val loader = AuthorizedModuleLoader { + single> { ClientRolesStorage(get(AuthorizedQualifiers.ServerUrlQualifier), get(), Role.serializer()) } +} diff --git a/features/roles/manager/common/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/manager/common/RolesManagerRole.kt b/features/roles/manager/common/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/manager/common/RolesManagerRole.kt index 4ca607e0..bb500ae0 100644 --- a/features/roles/manager/common/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/manager/common/RolesManagerRole.kt +++ b/features/roles/manager/common/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/manager/common/RolesManagerRole.kt @@ -5,6 +5,8 @@ import dev.inmo.postssystem.features.roles.common.RoleSerializer import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer import kotlinx.serialization.Serializable +private val justForLoading = RolesManagerRoleSerializer + @Serializable(RolesManagerRoleSerializer::class) interface RolesManagerRole : Role { companion object { diff --git a/features/users/client/build.gradle b/features/users/client/build.gradle index 32f19276..cfaba223 100644 --- a/features/users/client/build.gradle +++ b/features/users/client/build.gradle @@ -12,6 +12,7 @@ kotlin { dependencies { api project(":postssystem.features.users.common") api project(":postssystem.features.common.client") + api project(":postssystem.features.auth.client") } } } diff --git a/features/users/client/src/commonMain/kotlin/dev/inmo/postssystem/features/users/client/ModuleLoader.kt b/features/users/client/src/commonMain/kotlin/dev/inmo/postssystem/features/users/client/ModuleLoader.kt new file mode 100644 index 00000000..ec061aed --- /dev/null +++ b/features/users/client/src/commonMain/kotlin/dev/inmo/postssystem/features/users/client/ModuleLoader.kt @@ -0,0 +1,9 @@ +package dev.inmo.postssystem.features.users.client + +import dev.inmo.postssystem.features.auth.client.AuthorizedModuleLoader +import dev.inmo.postssystem.features.auth.client.AuthorizedQualifiers +import dev.inmo.postssystem.features.users.common.ReadUsersStorage + +val loader = AuthorizedModuleLoader { + single { UsersStorageKtorClient(get(AuthorizedQualifiers.ServerUrlQualifier), get()) } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7a8df218..7081be4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ kotlin-serialization = "1.3.2" jsuikit = "0.0.45" compose = "1.1.1" microutils = "0.9.16" -tgbotapi = "0.38.7" +tgbotapi = "0.38.9" ktor = "1.6.8" klock = "2.6.3" exposed = "0.37.3" @@ -44,6 +44,7 @@ microutils-repos-ktor-server = { module = "dev.inmo:micro_utils.repos.ktor.serve microutils-repos-exposed = { module = "dev.inmo:micro_utils.repos.exposed", version.ref = "microutils" } microutils-mimetypes = { module = "dev.inmo:micro_utils.mime_types", version.ref = "microutils" } microutils-coroutines = { module = "dev.inmo:micro_utils.coroutines", version.ref = "microutils" } +microutils-coroutines-compose = { module = "dev.inmo:micro_utils.coroutines.compose", version.ref = "microutils" } microutils-ktor-server = { module = "dev.inmo:micro_utils.ktor.server", version.ref = "microutils" } microutils-serialization-typedserializer = { module = "dev.inmo:micro_utils.serialization.typed_serializer", version.ref = "microutils" } diff --git a/publicators/simple/client/build.gradle b/publicators/simple/client/build.gradle index 5dbf458e..7b4ad6bc 100644 --- a/publicators/simple/client/build.gradle +++ b/publicators/simple/client/build.gradle @@ -11,6 +11,7 @@ kotlin { commonMain { dependencies { api project(":postssystem.publicators.simple.common") + api project(":postssystem.features.auth.client") api project(":postssystem.features.publication.client") } } diff --git a/publicators/simple/client/src/commonMain/kotlin/dev/inmo/postssystem/publicators/simple/client/ModuleLoader.kt b/publicators/simple/client/src/commonMain/kotlin/dev/inmo/postssystem/publicators/simple/client/ModuleLoader.kt new file mode 100644 index 00000000..fc4d3603 --- /dev/null +++ b/publicators/simple/client/src/commonMain/kotlin/dev/inmo/postssystem/publicators/simple/client/ModuleLoader.kt @@ -0,0 +1,8 @@ +package dev.inmo.postssystem.publicators.simple.client + +import dev.inmo.postssystem.features.auth.client.AuthorizedModuleLoader +import dev.inmo.postssystem.features.auth.client.AuthorizedQualifiers + +val loader = AuthorizedModuleLoader { + single { SimplePublicatorServiceClient(get(AuthorizedQualifiers.ServerUrlQualifier), get()) } +} diff --git a/services/posts/client/build.gradle b/services/posts/client/build.gradle index 7e2f18d9..260a1384 100644 --- a/services/posts/client/build.gradle +++ b/services/posts/client/build.gradle @@ -13,6 +13,8 @@ kotlin { api project(":postssystem.features.common.client") api project(":postssystem.services.posts.common") api project(":postssystem.features.posts.client") + api project(":postssystem.features.auth.client") + api project(":postssystem.features.content.client") api project(":postssystem.publicators.simple.client") } } diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ModuleLoader.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ModuleLoader.kt new file mode 100644 index 00000000..3e589582 --- /dev/null +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ModuleLoader.kt @@ -0,0 +1,20 @@ +package dev.inmo.postssystem.services.posts.client + +import dev.inmo.postssystem.features.auth.client.AuthorizedModuleLoader +import dev.inmo.postssystem.features.auth.client.AuthorizedQualifiers +import dev.inmo.postssystem.features.common.common.DefaultQualifiers +import dev.inmo.postssystem.features.common.common.getAllDistinct +import dev.inmo.postssystem.services.posts.client.ui.create.* +import dev.inmo.postssystem.services.posts.common.* +import org.koin.core.qualifier.Qualifier +import org.koin.dsl.binds + +val loader = AuthorizedModuleLoader { + single { ClientPostsService(get(AuthorizedQualifiers.ServerUrlQualifier), get()) } binds arrayOf( + ReadPostsService::class, + WritePostsService::class + ) + + factory { DefaultPostCreateUIModel(get(), get()) } + factory { PostCreateUIViewModel(get()) } +} diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/DefaultPostCreateUIModel.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/DefaultPostCreateUIModel.kt index 9477c65c..44d17ad9 100644 --- a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/DefaultPostCreateUIModel.kt +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/DefaultPostCreateUIModel.kt @@ -1,6 +1,6 @@ package dev.inmo.postssystem.services.posts.client.ui.create -import dev.inmo.postssystem.features.common.common.AbstractUIModel +import dev.inmo.postssystem.features.common.common.ui.AbstractUIModel import dev.inmo.postssystem.features.content.common.Content import dev.inmo.postssystem.publicators.simple.client.SimplePublicatorService import dev.inmo.postssystem.services.posts.common.FullNewPost diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIModel.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIModel.kt index c1de12ee..eefb1527 100644 --- a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIModel.kt +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIModel.kt @@ -1,7 +1,7 @@ package dev.inmo.postssystem.services.posts.client.ui.create -import dev.inmo.postssystem.features.common.common.UIModel -import dev.inmo.postssystem.features.common.common.UIViewModel +import dev.inmo.postssystem.features.common.common.ui.UIModel +import dev.inmo.postssystem.features.common.common.ui.UIViewModel import dev.inmo.postssystem.features.content.common.Content interface PostCreateUIModel : UIModel, UIViewModel { diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIViewModel.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIViewModel.kt index e7e6d2b8..791e2f87 100644 --- a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIViewModel.kt +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostCreateUIViewModel.kt @@ -1,6 +1,6 @@ package dev.inmo.postssystem.services.posts.client.ui.create -import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.common.common.ui.UIViewModel import dev.inmo.postssystem.features.content.common.Content import kotlinx.coroutines.flow.StateFlow diff --git a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/PostCreateView.kt b/services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostCreateView.kt similarity index 73% rename from client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/PostCreateView.kt rename to services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostCreateView.kt index 2ca86394..7dc65f26 100644 --- a/client/src/jsMain/kotlin/dev/inmo/postssystem/client/fsm/ui/PostCreateView.kt +++ b/services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostCreateView.kt @@ -1,28 +1,48 @@ -package dev.inmo.postssystem.client.fsm.ui +package dev.inmo.postssystem.services.posts.client import androidx.compose.runtime.* import dev.inmo.jsuikit.elements.* import dev.inmo.jsuikit.modifiers.* import dev.inmo.jsuikit.utils.Attrs +import dev.inmo.micro_utils.coroutines.compose.renderComposableAndLinkToContextAndRoot import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.micro_utils.fsm.common.StatesMachine -import dev.inmo.postssystem.client.ui.fsm.CreatePostUIFSMState -import dev.inmo.postssystem.client.ui.fsm.UIFSMState -import dev.inmo.postssystem.client.utils.renderComposableAndLinkToContext +import dev.inmo.postssystem.features.auth.client.registerAfterAuthHandler +import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.common.common.ui.JSView +import dev.inmo.postssystem.features.common.common.ui.fsm.* import dev.inmo.postssystem.features.content.client.ContentClientProvider import dev.inmo.postssystem.features.content.common.Content import dev.inmo.postssystem.services.posts.client.ui.create.PostCreateUIViewModel import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope +import kotlinx.serialization.Serializable import org.jetbrains.compose.web.dom.Div import org.jetbrains.compose.web.dom.Text import org.w3c.dom.HTMLElement +val jsLoader = DefaultModuleLoader { + factory { PostCreateView(get(), getAllDistinct(), get(DefaultQualifiers.UIScopeQualifier), getAllDistinct()) } + + singleWithRandomQualifier { + UIFSMHandler.Registrator { + registerAfterAuthHandler(getKoin(), PostCreateView::class) + } + } +} + +@Serializable +data class CreatePostUIFSMState( + override val from: UIFSMState? = null, + override val context: String = "main" +) : UIFSMState + class PostCreateView( private val createPostCreateUIModel: PostCreateUIViewModel, private val contentClientProviders: List, - private val uiScope: CoroutineScope -) : JSView() { + private val uiScope: CoroutineScope, + defaultExceptionsHandlers: Iterable +) : JSView(defaultExceptionsHandlers) { override suspend fun StatesMachine.safeHandleState( htmlElement: HTMLElement, state: CreatePostUIFSMState @@ -31,7 +51,7 @@ class PostCreateView( val contentProvidersList = mutableStateListOf>>() - renderComposableAndLinkToContext(htmlElement) { + renderComposableAndLinkToContextAndRoot(htmlElement) { Flex( UIKitFlex.Alignment.Horizontal.Center ) { diff --git a/targets/telegram/loader/client/src/commonMain/kotlin/dev/inmo/postssystem/targets/telegram/loader/client/TelegramTargetModuleLoader.kt b/targets/telegram/loader/client/src/commonMain/kotlin/dev/inmo/postssystem/targets/telegram/loader/client/TelegramTargetModuleLoader.kt index 25e2f4e5..2a749326 100644 --- a/targets/telegram/loader/client/src/commonMain/kotlin/dev/inmo/postssystem/targets/telegram/loader/client/TelegramTargetModuleLoader.kt +++ b/targets/telegram/loader/client/src/commonMain/kotlin/dev/inmo/postssystem/targets/telegram/loader/client/TelegramTargetModuleLoader.kt @@ -9,7 +9,7 @@ val defaultTelegramTargetModuleLoader = TelegramTargetModuleLoader object TelegramTargetModuleLoader : ModuleLoader { init { - AdditionalModules.addModule(this) + AdditionalModules.Default.addModule(this) } override fun Module.load() {