almost complete rework of ui up to module ui
This commit is contained in:
client
features
auth
client
common
client
content
binary
client
src
jsMain
kotlin
dev
inmo
postssystem
features
content
binary
client
src
commonMain
kotlin
dev
inmo
postssystem
features
content
client
text
client
src
jsMain
kotlin
dev
inmo
postssystem
features
content
text
files
client
roles
client
manager
common
src
commonMain
kotlin
dev
inmo
postssystem
features
roles
manager
common
users
client
gradle
publicators/simple/client
services/posts/client
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
services
jsMain
kotlin
dev
inmo
postssystem
services
posts
client
targets/telegram/loader/client/src/commonMain/kotlin/dev/inmo/postssystem/targets/telegram/loader/client
@ -32,9 +32,6 @@ kotlin {
|
|||||||
api project(":postssystem.features.content.binary.client")
|
api project(":postssystem.features.content.binary.client")
|
||||||
|
|
||||||
api project(":postssystem.services.posts.client")
|
api project(":postssystem.services.posts.client")
|
||||||
|
|
||||||
api libs.microutils.fsm.common
|
|
||||||
api libs.microutils.fsm.repos.common
|
|
||||||
api libs.microutils.crypto
|
api libs.microutils.crypto
|
||||||
|
|
||||||
implementation compose.runtime
|
implementation compose.runtime
|
||||||
|
@ -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<String, Any>,
|
|
||||||
repoFactory: Scope.() -> DefaultStatesManagerRepo<UIFSMState>,
|
|
||||||
handlersSetter: Pair<Scope, FSMBuilder<UIFSMState>>.() -> Unit
|
|
||||||
): Koin = startKoin {
|
|
||||||
modules(
|
|
||||||
module {
|
|
||||||
singleWithRandomQualifier<ContentSerializersModuleConfigurator.Element> { OtherContentSerializerModuleConfigurator }
|
|
||||||
singleWithRandomQualifier<ContentSerializersModuleConfigurator.Element> { TextContentSerializerModuleConfigurator }
|
|
||||||
singleWithRandomQualifier<SerializersModuleConfigurator.Element> { ContentSerializersModuleConfigurator(getAll()) }
|
|
||||||
single { SerializersModuleConfigurator(getAll()) }
|
|
||||||
|
|
||||||
single {
|
|
||||||
Json {
|
|
||||||
ignoreUnknownKeys = true
|
|
||||||
serializersModule = SerializersModule { get<SerializersModuleConfigurator>().apply { invoke() } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
single<StringFormat> { get<Json>() }
|
|
||||||
|
|
||||||
single(SettingsQualifier) { settingsFactory() }
|
|
||||||
single { DBDropper(get(SettingsQualifier)) }
|
|
||||||
single(FSMHandlersBuilderQualifier) { handlersSetter }
|
|
||||||
single { repoFactory() }
|
|
||||||
single { defaultScope }
|
|
||||||
single(UIScopeQualifier) { get<CoroutineScope>().LinkedSupervisorScope(Dispatchers.Main) }
|
|
||||||
single<StatesMachine<UIFSMState>>(UIFSMQualifier) { UIFSM(get()) { (this@single to this@UIFSM).apply(get(
|
|
||||||
FSMHandlersBuilderQualifier
|
|
||||||
)) } }
|
|
||||||
single<AuthSettings> { DefaultAuthSettings(get(SettingsQualifier), get(), koin, get()) }
|
|
||||||
single<Settings> { DefaultSettings(get()) }
|
|
||||||
|
|
||||||
AdditionalModules.modules.forEach {
|
|
||||||
it.apply { load() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}.koin.apply {
|
|
||||||
loadModules(
|
|
||||||
listOf(
|
|
||||||
module { single<Koin> { this@apply } }
|
|
||||||
)
|
|
||||||
)
|
|
||||||
RolesManagerRoleSerializer // Just to activate it in JS client
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getAuthorizedFeaturesDIModule(
|
|
||||||
serverUrl: String,
|
|
||||||
initialAuthKey: Either<AuthKey, AuthTokenInfo>,
|
|
||||||
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<BinaryFormat> {
|
|
||||||
Cbor {
|
|
||||||
serializersModule = SerializersModule { get<SerializersModuleConfigurator>().apply { invoke() } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
single { UnifiedRequester(get(), get()) }
|
|
||||||
|
|
||||||
single { StatusFeatureClient(get(serverUrlQualifier), get()) }
|
|
||||||
|
|
||||||
single<ReadFilesStorage> { ClientReadFilesStorage(get(serverUrlQualifier), get(), get()) }
|
|
||||||
single<ReadUsersStorage> { UsersStorageKtorClient(get(serverUrlQualifier), get()) }
|
|
||||||
single<RolesStorage<Role>> { ClientRolesStorage(get(serverUrlQualifier), get(), Role.serializer()) }
|
|
||||||
single<PostsService> { ClientPostsService(get(serverUrlQualifier), get()) } binds arrayOf(
|
|
||||||
ReadPostsService::class,
|
|
||||||
WritePostsService::class
|
|
||||||
)
|
|
||||||
single<SimplePublicatorService> { SimplePublicatorServiceClient(get(serverUrlQualifier), get()) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
@ -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<Module?>
|
|
||||||
get() = authSettings.authorizedDIModule
|
|
||||||
}
|
|
@ -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<T : UIFSMState> : StatesHandler<T, UIFSMState> {
|
|
||||||
suspend fun StatesMachine<in UIFSMState>.safeHandleState(state: T): UIFSMState?
|
|
||||||
override suspend fun StatesMachine<in UIFSMState>.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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<UIFSMState> 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
|
|
@ -1,23 +1,23 @@
|
|||||||
package dev.inmo.postssystem.client
|
package dev.inmo.postssystem.client
|
||||||
|
|
||||||
import dev.inmo.postssystem.client.fsm.ui.*
|
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.postssystem.features.auth.common.AuthTokenInfo
|
||||||
import dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler
|
import dev.inmo.micro_utils.coroutines.ContextSafelyExceptionHandler
|
||||||
import dev.inmo.micro_utils.fsm.common.CheckableHandlerHolder
|
import dev.inmo.micro_utils.fsm.common.CheckableHandlerHolder
|
||||||
import dev.inmo.micro_utils.fsm.common.StatesMachine
|
import dev.inmo.micro_utils.fsm.common.StatesMachine
|
||||||
import dev.inmo.micro_utils.repos.mappers.withMapper
|
import dev.inmo.micro_utils.repos.mappers.withMapper
|
||||||
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
|
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.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 dev.inmo.postssystem.services.posts.client.ui.create.*
|
||||||
import kotlinx.browser.*
|
import kotlinx.browser.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.serialization.builtins.serializer
|
import kotlinx.serialization.builtins.serializer
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.serializer
|
import kotlinx.serialization.serializer
|
||||||
import org.koin.core.Koin
|
import org.koin.core.Koin
|
||||||
import org.koin.core.context.loadKoinModules
|
import org.koin.core.context.loadKoinModules
|
||||||
@ -38,6 +38,9 @@ val defaultTypedSerializer = TypedSerializer<Any>(
|
|||||||
"Double" to Double.serializer(),
|
"Double" to Double.serializer(),
|
||||||
"UIFSMState" to UIFSMStateSerializer
|
"UIFSMState" to UIFSMStateSerializer
|
||||||
)
|
)
|
||||||
|
val defaultSerialFormat = Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
}
|
||||||
|
|
||||||
fun baseKoin(): Koin {
|
fun baseKoin(): Koin {
|
||||||
val anyToString: suspend Any.() -> String = {
|
val anyToString: suspend Any.() -> String = {
|
||||||
@ -81,66 +84,19 @@ fun baseKoin(): Koin {
|
|||||||
JSUIFSMStatesRepo(window.history)
|
JSUIFSMStatesRepo(window.history)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
|
val scope = first
|
||||||
first.apply {
|
first.apply {
|
||||||
second.apply {
|
second.apply {
|
||||||
loadKoinModules(
|
loadKoinModules(
|
||||||
module {
|
module {
|
||||||
factory { document.getElementById("main") as HTMLElement }
|
factory { document.getElementById("main") as HTMLElement }
|
||||||
|
|
||||||
factory<AuthUIModel> { DefaultAuthUIModel(get(), get()) }
|
|
||||||
factory { AuthUIViewModel(get()) }
|
|
||||||
factory { AuthView(get(), get(UIScopeQualifier)) }
|
|
||||||
|
|
||||||
factory<PostCreateUIModel> { DefaultPostCreateUIModel(get(), get()) }
|
|
||||||
factory { PostCreateUIViewModel(get()) }
|
|
||||||
factory { PostCreateView(get(), getAllDistinct(), get(UIScopeQualifier)) }
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
strictlyOn<AuthUIFSMState>(get<AuthView>())
|
getAllDistinct<UIFSMHandler.Registrator>().forEach {
|
||||||
|
with(it) {
|
||||||
// Костыль, в JS на момент Пн дек 6 14:19:29 +06 2021 если использовать strictlyOn генерируются
|
include()
|
||||||
// некорректные безымянные классы (у них отсутствует метод handleState)
|
|
||||||
class DefaultStateHandlerWrapper<T : UIFSMState>(
|
|
||||||
private val klass: KClass<out UIFSMHandler<T>>,
|
|
||||||
private val stateKlass: KClass<T>,
|
|
||||||
private val qualifier: Qualifier? = null,
|
|
||||||
private val parameters: ((T) -> ParametersHolder)? = null
|
|
||||||
) : CheckableHandlerHolder<UIFSMState, UIFSMState> {
|
|
||||||
override suspend fun StatesMachine<in UIFSMState>.handleState(state: UIFSMState): UIFSMState? {
|
|
||||||
@Suppress("UNCHECKED_CAST", "NAME_SHADOWING")
|
|
||||||
val state = state as T
|
|
||||||
return runCatching {
|
|
||||||
val authSettings = get<AuthSettings>()
|
|
||||||
authSettings.loadingJob.join()
|
|
||||||
if (authSettings.authorizedDIModule.value == null) {
|
|
||||||
error("Can't perform state $state: Auth module was not initialized")
|
|
||||||
} else {
|
|
||||||
get<UIFSMHandler<T>>(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 <reified T : UIFSMState> registerHandler(
|
|
||||||
klass: KClass<out UIFSMHandler<T>>,
|
|
||||||
qualifier: Qualifier? = null,
|
|
||||||
parameters: ((T) -> ParametersHolder)? = null
|
|
||||||
) = add(
|
|
||||||
DefaultStateHandlerWrapper<T>(
|
|
||||||
klass,
|
|
||||||
T::class,
|
|
||||||
qualifier,
|
|
||||||
parameters
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
registerHandler(PostCreateView::class)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.postssystem.client
|
package dev.inmo.postssystem.client
|
||||||
|
|
||||||
import dev.inmo.postssystem.client.ui.fsm.*
|
|
||||||
import dev.inmo.micro_utils.fsm.common.managers.DefaultStatesManagerRepo
|
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.browser.window
|
||||||
import kotlinx.serialization.StringFormat
|
import kotlinx.serialization.StringFormat
|
||||||
import org.w3c.dom.*
|
import org.w3c.dom.*
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
package dev.inmo.postssystem.client
|
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.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
|
import kotlinx.browser.window
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
window.addEventListener("load", {
|
window.addEventListener("load", {
|
||||||
val koin = baseKoin()
|
val koin = baseKoin()
|
||||||
val uiStatesMachine = koin.get<StatesMachine<UIFSMState>>(UIFSMQualifier)
|
val uiStatesMachine = koin.get<StatesMachine<UIFSMState>>(DefaultQualifiers.UIFSMQualifier)
|
||||||
uiStatesMachine.start(koin.get())
|
uiStatesMachine.start(koin.get())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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")!!
|
|
@ -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()
|
|
||||||
}
|
|
@ -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 <TElement : Element> renderComposableAndLinkToContext(
|
|
||||||
root: TElement,
|
|
||||||
monotonicFrameClock: MonotonicFrameClock = DefaultMonotonicFrameClock,
|
|
||||||
content: @Composable DOMScope<TElement>.() -> Unit
|
|
||||||
): Composition = org.jetbrains.compose.web.renderComposable(root, monotonicFrameClock, content).apply {
|
|
||||||
linkWithContext(
|
|
||||||
currentCoroutineContext()
|
|
||||||
)
|
|
||||||
}
|
|
@ -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<FullFileInfo?>
|
|
||||||
): (Event) -> Unit = uploadFileCallbackForHTMLInputChange {
|
|
||||||
output.value = it
|
|
||||||
}
|
|
||||||
|
|
||||||
fun uploadFileCallbackForHTMLInputChange(
|
|
||||||
output: MutableStateFlow<FullFileInfo?>
|
|
||||||
): (Event) -> Unit = uploadFileCallbackForHTMLInputChange {
|
|
||||||
output.value = it
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fileCallbackForHTMLInputChange(
|
|
||||||
output: MutableState<MPPFile?>
|
|
||||||
): (Event) -> Unit = fileCallbackForHTMLInputChange {
|
|
||||||
output.value = it
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fileCallbackForHTMLInputChange(
|
|
||||||
output: MutableStateFlow<MPPFile?>
|
|
||||||
): (Event) -> Unit = fileCallbackForHTMLInputChange {
|
|
||||||
output.value = it
|
|
||||||
}
|
|
||||||
|
|
@ -2,6 +2,7 @@ plugins {
|
|||||||
id "org.jetbrains.kotlin.multiplatform"
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
id "org.jetbrains.kotlin.plugin.serialization"
|
id "org.jetbrains.kotlin.plugin.serialization"
|
||||||
id "com.android.library"
|
id "com.android.library"
|
||||||
|
alias(libs.plugins.compose)
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$mppProjectWithSerializationPresetPath"
|
apply from: "$mppProjectWithSerializationPresetPath"
|
||||||
@ -11,8 +12,14 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":postssystem.features.common.client")
|
api project(":postssystem.features.common.client")
|
||||||
|
api project(":postssystem.features.roles.client")
|
||||||
|
api project(":postssystem.features.status.client")
|
||||||
api project(":postssystem.features.auth.common")
|
api project(":postssystem.features.auth.common")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
clientMain {
|
||||||
|
dependencies {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
39
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedFeaturesModules.kt
Normal file
39
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedFeaturesModules.kt
Normal file
@ -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<AuthKey, AuthTokenInfo>,
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedModuleLoader.kt
Normal file
15
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedModuleLoader.kt
Normal file
@ -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
|
||||||
|
}
|
8
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedQualifiers.kt
Normal file
8
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/AuthorizedQualifiers.kt
Normal file
@ -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")
|
||||||
|
}
|
59
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/BehindAuthUIFSMHandler.kt
Normal file
59
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/BehindAuthUIFSMHandler.kt
Normal file
@ -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<T : UIFSMState>(
|
||||||
|
private val klass: KClass<out UIFSMHandler<T>>,
|
||||||
|
private val koin: Koin,
|
||||||
|
private val stateKlass: KClass<T>,
|
||||||
|
private val qualifier: Qualifier? = null,
|
||||||
|
private val parameters: ((T) -> ParametersHolder)? = null
|
||||||
|
) : CheckableHandlerHolder<UIFSMState, UIFSMState> {
|
||||||
|
override suspend fun StatesMachine<in UIFSMState>.handleState(state: UIFSMState): UIFSMState? {
|
||||||
|
@Suppress("UNCHECKED_CAST", "NAME_SHADOWING")
|
||||||
|
val state = state as T
|
||||||
|
return runCatching {
|
||||||
|
val authSettings = koin.get<AuthSettings>()
|
||||||
|
authSettings.loadingJob.join()
|
||||||
|
if (authSettings.authorizedDIModule.value == null) {
|
||||||
|
error("Can't perform state $state: Auth module was not initialized")
|
||||||
|
} else {
|
||||||
|
koin.get<UIFSMHandler<T>>(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 <reified T : UIFSMState> FSMBuilder<UIFSMState>.registerAfterAuthHandler(
|
||||||
|
koin: Koin,
|
||||||
|
klass: KClass<out UIFSMHandler<T>>,
|
||||||
|
qualifier: Qualifier? = null,
|
||||||
|
noinline parameters: ((T) -> ParametersHolder)? = null
|
||||||
|
) = add(
|
||||||
|
DefaultStateHandlerWrapper<T>(
|
||||||
|
klass,
|
||||||
|
koin,
|
||||||
|
T::class,
|
||||||
|
qualifier,
|
||||||
|
parameters
|
||||||
|
)
|
||||||
|
)
|
27
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ModuleLoader.kt
Normal file
27
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ModuleLoader.kt
Normal file
@ -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<AuthSettings> { DefaultAuthSettings(get(DefaultQualifiers.SettingsQualifier), get(), getKoin(), get()) }
|
||||||
|
|
||||||
|
singleWithRandomQualifier {
|
||||||
|
UIFSMExceptionHandler { currentState, exception ->
|
||||||
|
if (exception is AuthUnavailableException) {
|
||||||
|
Optional.presented(AuthUIFSMState(currentState))
|
||||||
|
} else {
|
||||||
|
Optional.absent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
factory<AuthUIModel> { DefaultAuthUIModel(get(), get()) }
|
||||||
|
factory { AuthUIViewModel(get()) }
|
||||||
|
}
|
@ -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.client.ui.AuthUIError
|
||||||
import dev.inmo.postssystem.features.auth.common.AuthCreds
|
import dev.inmo.postssystem.features.auth.common.AuthCreds
|
@ -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.AuthUnavailableException
|
||||||
import dev.inmo.postssystem.features.auth.client.ui.*
|
import dev.inmo.postssystem.features.auth.client.ui.*
|
||||||
import dev.inmo.postssystem.features.auth.common.*
|
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.plus
|
||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
import dev.inmo.micro_utils.repos.*
|
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.*
|
||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import org.koin.core.Koin
|
import org.koin.core.Koin
|
||||||
@ -73,7 +73,7 @@ data class DefaultAuthSettings(
|
|||||||
initialAuthKey: Either<AuthKey, AuthTokenInfo>,
|
initialAuthKey: Either<AuthKey, AuthTokenInfo>,
|
||||||
): AuthUIError? {
|
): AuthUIError? {
|
||||||
val currentModule = authorizedDIModule.value
|
val currentModule = authorizedDIModule.value
|
||||||
val newModule = getAuthorizedFeaturesDIModule(
|
val newModule = createAuthorizedFeaturesDIModule(
|
||||||
serverUrl,
|
serverUrl,
|
||||||
initialAuthKey,
|
initialAuthKey,
|
||||||
{
|
{
|
14
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIFSMState.kt
Normal file
14
features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/ui/AuthUIFSMState.kt
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.postssystem.features.auth.client.ui
|
package dev.inmo.postssystem.features.auth.client.ui
|
||||||
|
|
||||||
import dev.inmo.postssystem.features.auth.common.AuthCreds
|
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<AuthUIState> {
|
interface AuthUIModel : UIModel<AuthUIState> {
|
||||||
suspend fun initAuth(serverUrl: String, creds: AuthCreds)
|
suspend fun initAuth(serverUrl: String, creds: AuthCreds)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.postssystem.features.auth.client.ui
|
package dev.inmo.postssystem.features.auth.client.ui
|
||||||
|
|
||||||
import dev.inmo.postssystem.features.auth.common.AuthCreds
|
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 dev.inmo.postssystem.features.users.common.Username
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
@ -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.settings.AuthSettings
|
||||||
import dev.inmo.postssystem.features.auth.client.ui.*
|
|
||||||
import dev.inmo.postssystem.features.auth.common.AuthCreds
|
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.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -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.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import dev.inmo.jsuikit.elements.*
|
import dev.inmo.jsuikit.elements.*
|
||||||
import dev.inmo.jsuikit.modifiers.*
|
import dev.inmo.jsuikit.modifiers.*
|
||||||
import dev.inmo.jsuikit.utils.Attrs
|
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.postssystem.features.auth.client.ui.*
|
||||||
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
|
||||||
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
|
||||||
import dev.inmo.micro_utils.fsm.common.StatesMachine
|
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.browser.document
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.dom.*
|
import kotlinx.dom.*
|
||||||
import org.jetbrains.compose.web.attributes.InputType
|
import org.jetbrains.compose.web.attributes.InputType
|
||||||
import org.jetbrains.compose.web.dom.*
|
|
||||||
import org.jetbrains.compose.web.dom.Text
|
import org.jetbrains.compose.web.dom.Text
|
||||||
import org.w3c.dom.*
|
import org.w3c.dom.*
|
||||||
|
|
||||||
|
val loader = DefaultModuleLoader {
|
||||||
|
factory { AuthView(get(), get(DefaultQualifiers.UIScopeQualifier), getAllDistinct()) }
|
||||||
|
singleWithRandomQualifier<UIFSMHandler.Registrator> {
|
||||||
|
UIFSMHandler.Registrator {
|
||||||
|
strictlyOn(get<AuthView>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class AuthView(
|
class AuthView(
|
||||||
private val viewModel: AuthUIViewModel,
|
private val viewModel: AuthUIViewModel,
|
||||||
private val uiScope: CoroutineScope
|
private val uiScope: CoroutineScope,
|
||||||
) : JSView<AuthUIFSMState>() {
|
defaultExceptionsHandlers: Iterable<UIFSMExceptionHandler>
|
||||||
|
) : JSView<AuthUIFSMState>(defaultExceptionsHandlers) {
|
||||||
|
|
||||||
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
|
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
|
||||||
htmlElement: HTMLElement,
|
htmlElement: HTMLElement,
|
||||||
@ -36,7 +46,7 @@ class AuthView(
|
|||||||
val errorText = mutableStateOf<String?>(null)
|
val errorText = mutableStateOf<String?>(null)
|
||||||
|
|
||||||
val root = htmlElement.appendElement("div") {}
|
val root = htmlElement.appendElement("div") {}
|
||||||
val composition = renderComposableAndLinkToContext(root) {
|
val composition = renderComposableAndLinkToContextAndRoot(root) {
|
||||||
val authBtnDisabled = usernameState.value.isBlank() || passwordState.value.isBlank()
|
val authBtnDisabled = usernameState.value.isBlank() || passwordState.value.isBlank()
|
||||||
|
|
||||||
Flex(
|
Flex(
|
@ -16,6 +16,11 @@ kotlin {
|
|||||||
api "io.ktor:ktor-client-auth:$ktor_version"
|
api "io.ktor:ktor-client-auth:$ktor_version"
|
||||||
api "io.ktor:ktor-client-logging:$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
|
api compose.runtime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.inmo.postssystem.features.common.common
|
package dev.inmo.postssystem.features.common.common
|
||||||
|
|
||||||
object AdditionalModules {
|
class AdditionalModules {
|
||||||
private val additionalModules = mutableListOf<ModuleLoader>()
|
private val additionalModules = mutableListOf<ModuleLoader>()
|
||||||
val modules: List<ModuleLoader>
|
val modules: List<ModuleLoader>
|
||||||
get() = additionalModules.toList()
|
get() = additionalModules.toList()
|
||||||
@ -8,4 +8,8 @@ object AdditionalModules {
|
|||||||
fun addModule(moduleLoader: ModuleLoader): Boolean {
|
fun addModule(moduleLoader: ModuleLoader): Boolean {
|
||||||
return additionalModules.add(moduleLoader)
|
return additionalModules.add(moduleLoader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Default = AdditionalModules()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.pagination.utils.getAllByWithNextPaging
|
||||||
import dev.inmo.micro_utils.repos.KeyValueRepo
|
import dev.inmo.micro_utils.repos.KeyValueRepo
|
67
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultModules.kt
Normal file
67
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultModules.kt
Normal file
@ -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<String, Any>,
|
||||||
|
repoFactory: Scope.() -> DefaultStatesManagerRepo<UIFSMState>,
|
||||||
|
handlersSetter: Pair<Scope, FSMBuilder<UIFSMState>>.() -> Unit
|
||||||
|
): Koin = startKoin {
|
||||||
|
modules(
|
||||||
|
module {
|
||||||
|
single {
|
||||||
|
Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
serializersModule = SerializersModule { get<SerializersModuleConfigurator>().apply { invoke() } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
single<StringFormat> { get<Json>() }
|
||||||
|
single {
|
||||||
|
Cbor { serializersModule = SerializersModule { get<SerializersModuleConfigurator>().apply { invoke() } } }
|
||||||
|
}
|
||||||
|
single<BinaryFormat> { get<Cbor>() }
|
||||||
|
|
||||||
|
single(DefaultQualifiers.SettingsQualifier) { settingsFactory() }
|
||||||
|
single { DBDropper(get(DefaultQualifiers.SettingsQualifier)) }
|
||||||
|
single(DefaultQualifiers.FSMHandlersBuilderQualifier) { handlersSetter }
|
||||||
|
single { repoFactory() }
|
||||||
|
single { defaultScope }
|
||||||
|
single(DefaultQualifiers.UIScopeQualifier) { get<CoroutineScope>().LinkedSupervisorScope(Dispatchers.Main) }
|
||||||
|
single<StatesMachine<UIFSMState>>(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<Koin> { this@apply } }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
10
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultQualifiers.kt
Normal file
10
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/DefaultQualifiers.kt
Normal file
@ -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")
|
||||||
|
}
|
@ -2,6 +2,18 @@ package dev.inmo.postssystem.features.common.common
|
|||||||
|
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
|
|
||||||
fun interface ModuleLoader {
|
interface ModuleLoader {
|
||||||
fun Module.load()
|
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
|
||||||
}
|
}
|
||||||
|
4
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIView.kt
4
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/UIView.kt
@ -1,4 +0,0 @@
|
|||||||
package dev.inmo.postssystem.features.common.common
|
|
||||||
|
|
||||||
interface UIView {
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package dev.inmo.postssystem.features.common.common
|
package dev.inmo.postssystem.features.common.common.ui
|
||||||
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -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.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
4
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIView.kt
Normal file
4
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/UIView.kt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
package dev.inmo.postssystem.features.common.common.ui
|
||||||
|
|
||||||
|
interface UIView {
|
||||||
|
}
|
@ -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.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@ -7,9 +7,7 @@ interface UIViewModel<StateType> {
|
|||||||
val currentState: StateFlow<StateType>
|
val currentState: StateFlow<StateType>
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractUIViewModel<StateType> : UIViewModel<StateType> {
|
abstract class AbstractUIViewModel<StateType>(initState: StateType) : UIViewModel<StateType> {
|
||||||
protected val _currentState = DefaultMVVMStateFlow(initState())
|
protected val _currentState = DefaultMVVMStateFlow(initState)
|
||||||
override val currentState: StateFlow<StateType> = _currentState.asStateFlow()
|
override val currentState: StateFlow<StateType> = _currentState.asStateFlow()
|
||||||
|
|
||||||
abstract fun initState(): StateType
|
|
||||||
}
|
}
|
@ -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.FSMBuilder
|
||||||
import dev.inmo.micro_utils.fsm.common.dsl.buildFSM
|
import dev.inmo.micro_utils.fsm.common.dsl.buildFSM
|
7
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMExceptionHandler.kt
Normal file
7
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMExceptionHandler.kt
Normal file
@ -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<UIFSMState?>
|
||||||
|
}
|
34
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMHandler.kt
Normal file
34
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMHandler.kt
Normal file
@ -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<T : UIFSMState> : StatesHandler<T, UIFSMState> {
|
||||||
|
fun interface Registrator {
|
||||||
|
fun FSMBuilder<UIFSMState>.include()
|
||||||
|
}
|
||||||
|
val defaultExceptionsHandlers: Iterable<UIFSMExceptionHandler>
|
||||||
|
|
||||||
|
suspend fun StatesMachine<in UIFSMState>.safeHandleState(state: T): UIFSMState?
|
||||||
|
override suspend fun StatesMachine<in UIFSMState>.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
|
||||||
|
}
|
||||||
|
}
|
17
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMState.kt
Normal file
17
features/common/client/src/commonMain/kotlin/dev/inmo/postssystem/features/common/common/ui/fsm/UIFSMState.kt
Normal file
@ -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<UIFSMState>, TypedSerializer<UIFSMState>(
|
||||||
|
UIFSMState::class
|
||||||
|
)
|
@ -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.micro_utils.fsm.common.StatesMachine
|
||||||
|
import dev.inmo.postssystem.features.common.common.ui.fsm.*
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
abstract class JSView<T : UIFSMState> : UIFSMHandler<T> {
|
abstract class JSView<T : UIFSMState>(
|
||||||
|
override val defaultExceptionsHandlers: Iterable<UIFSMExceptionHandler>
|
||||||
|
) : UIFSMHandler<T> {
|
||||||
open suspend fun StatesMachine<in UIFSMState>.safeHandleState(
|
open suspend fun StatesMachine<in UIFSMState>.safeHandleState(
|
||||||
htmlElement: HTMLElement,
|
htmlElement: HTMLElement,
|
||||||
state: T
|
state: T
|
@ -11,7 +11,7 @@ import org.koin.core.module.Module
|
|||||||
|
|
||||||
object LoadingClientModule : ModuleLoader {
|
object LoadingClientModule : ModuleLoader {
|
||||||
init {
|
init {
|
||||||
AdditionalModules.addModule(this)
|
AdditionalModules.Default.addModule(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Module.load() {
|
override fun Module.load() {
|
||||||
|
11
features/content/client/src/commonMain/kotlin/dev/inmo/postssystem/features/content/client/ModuleLoader.kt
Normal file
11
features/content/client/src/commonMain/kotlin/dev/inmo/postssystem/features/content/client/ModuleLoader.kt
Normal file
@ -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<ContentSerializersModuleConfigurator.Element> { OtherContentSerializerModuleConfigurator }
|
||||||
|
singleWithRandomQualifier<SerializersModuleConfigurator.Element> { ContentSerializersModuleConfigurator(getAll()) }
|
||||||
|
single { SerializersModuleConfigurator(getAll()) }
|
||||||
|
}
|
@ -12,7 +12,7 @@ import org.koin.core.module.Module
|
|||||||
|
|
||||||
object LoadingClientModule : ModuleLoader {
|
object LoadingClientModule : ModuleLoader {
|
||||||
init {
|
init {
|
||||||
AdditionalModules.addModule(this)
|
AdditionalModules.Default.addModule(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Module.load() {
|
override fun Module.load() {
|
||||||
|
@ -12,6 +12,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
api project(":postssystem.features.files.common")
|
api project(":postssystem.features.files.common")
|
||||||
api project(":postssystem.features.common.client")
|
api project(":postssystem.features.common.client")
|
||||||
|
api project(":postssystem.features.auth.client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
features/files/client/src/commonMain/kotlin/dev/inmo/postssystem/features/files/client/ModuleLoader.kt
Normal file
9
features/files/client/src/commonMain/kotlin/dev/inmo/postssystem/features/files/client/ModuleLoader.kt
Normal file
@ -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<ReadFilesStorage> { ClientReadFilesStorage(get(AuthorizedQualifiers.ServerUrlQualifier), get(), get()) }
|
||||||
|
}
|
@ -12,6 +12,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
api project(":postssystem.features.roles.common")
|
api project(":postssystem.features.roles.common")
|
||||||
api project(":postssystem.features.common.client")
|
api project(":postssystem.features.common.client")
|
||||||
|
api project(":postssystem.features.auth.client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/ModuleLoader.kt
Normal file
10
features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/ModuleLoader.kt
Normal file
@ -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<RolesStorage<Role>> { ClientRolesStorage(get(AuthorizedQualifiers.ServerUrlQualifier), get(), Role.serializer()) }
|
||||||
|
}
|
@ -5,6 +5,8 @@ import dev.inmo.postssystem.features.roles.common.RoleSerializer
|
|||||||
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
|
import dev.inmo.micro_utils.serialization.typed_serializer.TypedSerializer
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
private val justForLoading = RolesManagerRoleSerializer
|
||||||
|
|
||||||
@Serializable(RolesManagerRoleSerializer::class)
|
@Serializable(RolesManagerRoleSerializer::class)
|
||||||
interface RolesManagerRole : Role {
|
interface RolesManagerRole : Role {
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -12,6 +12,7 @@ kotlin {
|
|||||||
dependencies {
|
dependencies {
|
||||||
api project(":postssystem.features.users.common")
|
api project(":postssystem.features.users.common")
|
||||||
api project(":postssystem.features.common.client")
|
api project(":postssystem.features.common.client")
|
||||||
|
api project(":postssystem.features.auth.client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
features/users/client/src/commonMain/kotlin/dev/inmo/postssystem/features/users/client/ModuleLoader.kt
Normal file
9
features/users/client/src/commonMain/kotlin/dev/inmo/postssystem/features/users/client/ModuleLoader.kt
Normal file
@ -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<ReadUsersStorage> { UsersStorageKtorClient(get(AuthorizedQualifiers.ServerUrlQualifier), get()) }
|
||||||
|
}
|
@ -5,7 +5,7 @@ kotlin-serialization = "1.3.2"
|
|||||||
jsuikit = "0.0.45"
|
jsuikit = "0.0.45"
|
||||||
compose = "1.1.1"
|
compose = "1.1.1"
|
||||||
microutils = "0.9.16"
|
microutils = "0.9.16"
|
||||||
tgbotapi = "0.38.7"
|
tgbotapi = "0.38.9"
|
||||||
ktor = "1.6.8"
|
ktor = "1.6.8"
|
||||||
klock = "2.6.3"
|
klock = "2.6.3"
|
||||||
exposed = "0.37.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-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-mimetypes = { module = "dev.inmo:micro_utils.mime_types", version.ref = "microutils" }
|
||||||
microutils-coroutines = { module = "dev.inmo:micro_utils.coroutines", 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-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" }
|
microutils-serialization-typedserializer = { module = "dev.inmo:micro_utils.serialization.typed_serializer", version.ref = "microutils" }
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ kotlin {
|
|||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api project(":postssystem.publicators.simple.common")
|
api project(":postssystem.publicators.simple.common")
|
||||||
|
api project(":postssystem.features.auth.client")
|
||||||
api project(":postssystem.features.publication.client")
|
api project(":postssystem.features.publication.client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
publicators/simple/client/src/commonMain/kotlin/dev/inmo/postssystem/publicators/simple/client/ModuleLoader.kt
Normal file
8
publicators/simple/client/src/commonMain/kotlin/dev/inmo/postssystem/publicators/simple/client/ModuleLoader.kt
Normal file
@ -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<SimplePublicatorService> { SimplePublicatorServiceClient(get(AuthorizedQualifiers.ServerUrlQualifier), get()) }
|
||||||
|
}
|
@ -13,6 +13,8 @@ kotlin {
|
|||||||
api project(":postssystem.features.common.client")
|
api project(":postssystem.features.common.client")
|
||||||
api project(":postssystem.services.posts.common")
|
api project(":postssystem.services.posts.common")
|
||||||
api project(":postssystem.features.posts.client")
|
api project(":postssystem.features.posts.client")
|
||||||
|
api project(":postssystem.features.auth.client")
|
||||||
|
api project(":postssystem.features.content.client")
|
||||||
api project(":postssystem.publicators.simple.client")
|
api project(":postssystem.publicators.simple.client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ModuleLoader.kt
Normal file
20
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ModuleLoader.kt
Normal file
@ -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<PostsService> { ClientPostsService(get(AuthorizedQualifiers.ServerUrlQualifier), get()) } binds arrayOf(
|
||||||
|
ReadPostsService::class,
|
||||||
|
WritePostsService::class
|
||||||
|
)
|
||||||
|
|
||||||
|
factory<PostCreateUIModel> { DefaultPostCreateUIModel(get(), get()) }
|
||||||
|
factory { PostCreateUIViewModel(get()) }
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package dev.inmo.postssystem.services.posts.client.ui.create
|
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.features.content.common.Content
|
||||||
import dev.inmo.postssystem.publicators.simple.client.SimplePublicatorService
|
import dev.inmo.postssystem.publicators.simple.client.SimplePublicatorService
|
||||||
import dev.inmo.postssystem.services.posts.common.FullNewPost
|
import dev.inmo.postssystem.services.posts.common.FullNewPost
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package dev.inmo.postssystem.services.posts.client.ui.create
|
package dev.inmo.postssystem.services.posts.client.ui.create
|
||||||
|
|
||||||
import dev.inmo.postssystem.features.common.common.UIModel
|
import dev.inmo.postssystem.features.common.common.ui.UIModel
|
||||||
import dev.inmo.postssystem.features.common.common.UIViewModel
|
import dev.inmo.postssystem.features.common.common.ui.UIViewModel
|
||||||
import dev.inmo.postssystem.features.content.common.Content
|
import dev.inmo.postssystem.features.content.common.Content
|
||||||
|
|
||||||
interface PostCreateUIModel : UIModel<PostCreateUIState>, UIViewModel<PostCreateUIState> {
|
interface PostCreateUIModel : UIModel<PostCreateUIState>, UIViewModel<PostCreateUIState> {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package dev.inmo.postssystem.services.posts.client.ui.create
|
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 dev.inmo.postssystem.features.content.common.Content
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
|
@ -1,28 +1,48 @@
|
|||||||
package dev.inmo.postssystem.client.fsm.ui
|
package dev.inmo.postssystem.services.posts.client
|
||||||
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import dev.inmo.jsuikit.elements.*
|
import dev.inmo.jsuikit.elements.*
|
||||||
import dev.inmo.jsuikit.modifiers.*
|
import dev.inmo.jsuikit.modifiers.*
|
||||||
import dev.inmo.jsuikit.utils.Attrs
|
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.coroutines.launchSafelyWithoutExceptions
|
||||||
import dev.inmo.micro_utils.fsm.common.StatesMachine
|
import dev.inmo.micro_utils.fsm.common.StatesMachine
|
||||||
import dev.inmo.postssystem.client.ui.fsm.CreatePostUIFSMState
|
import dev.inmo.postssystem.features.auth.client.registerAfterAuthHandler
|
||||||
import dev.inmo.postssystem.client.ui.fsm.UIFSMState
|
import dev.inmo.postssystem.features.common.common.*
|
||||||
import dev.inmo.postssystem.client.utils.renderComposableAndLinkToContext
|
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.client.ContentClientProvider
|
||||||
import dev.inmo.postssystem.features.content.common.Content
|
import dev.inmo.postssystem.features.content.common.Content
|
||||||
import dev.inmo.postssystem.services.posts.client.ui.create.PostCreateUIViewModel
|
import dev.inmo.postssystem.services.posts.client.ui.create.PostCreateUIViewModel
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import org.jetbrains.compose.web.dom.Div
|
import org.jetbrains.compose.web.dom.Div
|
||||||
import org.jetbrains.compose.web.dom.Text
|
import org.jetbrains.compose.web.dom.Text
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
|
val jsLoader = DefaultModuleLoader {
|
||||||
|
factory { PostCreateView(get(), getAllDistinct(), get(DefaultQualifiers.UIScopeQualifier), getAllDistinct()) }
|
||||||
|
|
||||||
|
singleWithRandomQualifier<UIFSMHandler.Registrator> {
|
||||||
|
UIFSMHandler.Registrator {
|
||||||
|
registerAfterAuthHandler(getKoin(), PostCreateView::class)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class CreatePostUIFSMState(
|
||||||
|
override val from: UIFSMState? = null,
|
||||||
|
override val context: String = "main"
|
||||||
|
) : UIFSMState
|
||||||
|
|
||||||
class PostCreateView(
|
class PostCreateView(
|
||||||
private val createPostCreateUIModel: PostCreateUIViewModel,
|
private val createPostCreateUIModel: PostCreateUIViewModel,
|
||||||
private val contentClientProviders: List<ContentClientProvider>,
|
private val contentClientProviders: List<ContentClientProvider>,
|
||||||
private val uiScope: CoroutineScope
|
private val uiScope: CoroutineScope,
|
||||||
) : JSView<CreatePostUIFSMState>() {
|
defaultExceptionsHandlers: Iterable<UIFSMExceptionHandler>
|
||||||
|
) : JSView<CreatePostUIFSMState>(defaultExceptionsHandlers) {
|
||||||
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
|
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
|
||||||
htmlElement: HTMLElement,
|
htmlElement: HTMLElement,
|
||||||
state: CreatePostUIFSMState
|
state: CreatePostUIFSMState
|
||||||
@ -31,7 +51,7 @@ class PostCreateView(
|
|||||||
|
|
||||||
val contentProvidersList = mutableStateListOf<Pair<ContentClientProvider, MutableState<Content?>>>()
|
val contentProvidersList = mutableStateListOf<Pair<ContentClientProvider, MutableState<Content?>>>()
|
||||||
|
|
||||||
renderComposableAndLinkToContext(htmlElement) {
|
renderComposableAndLinkToContextAndRoot(htmlElement) {
|
||||||
Flex(
|
Flex(
|
||||||
UIKitFlex.Alignment.Horizontal.Center
|
UIKitFlex.Alignment.Horizontal.Center
|
||||||
) {
|
) {
|
@ -9,7 +9,7 @@ val defaultTelegramTargetModuleLoader = TelegramTargetModuleLoader
|
|||||||
|
|
||||||
object TelegramTargetModuleLoader : ModuleLoader {
|
object TelegramTargetModuleLoader : ModuleLoader {
|
||||||
init {
|
init {
|
||||||
AdditionalModules.addModule(this)
|
AdditionalModules.Default.addModule(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Module.load() {
|
override fun Module.load() {
|
||||||
|
Reference in New Issue
Block a user