From 37114f0ddb8bb443dbf3cef59796eef9a2466e3c Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Sat, 26 Mar 2022 14:19:20 +0600 Subject: [PATCH] temporal potentially working variant (bot not building --- features/auth/client/build.gradle | 1 - .../auth/client/settings/AuthSettings.kt | 2 - .../client/settings/DefaultAuthSettings.kt | 18 ---- .../features/common/common/ui/DateTimeView.kt | 18 ++++ .../client/BinaryContentClientProvider.kt | 24 ++++- .../content/client/ContentClientProvider.kt | 3 + .../text/client/TextContentClientProvider.kt | 15 ++++ .../postssystem/features/posts/common/Post.kt | 14 +++ .../roles/client/DefaultRolesSettings.kt | 31 +++++++ .../features/roles/client/ModuleLoader.kt | 1 + .../features/roles/client/RolesSettings.kt | 8 ++ .../services/posts/client/ModuleLoader.kt | 3 - .../client/ui/create/PostsCreateUIFSMState.kt | 2 - .../client/ui/list/PostsListUIFSMState.kt | 2 - .../posts/client/ui/list/PostsListUIState.kt | 4 +- .../client/ui/list/PostsListUIViewModel.kt | 11 +++ .../services/posts/client/PostsListView.kt | 90 +++++++++++++++++++ 17 files changed, 216 insertions(+), 31 deletions(-) create mode 100644 features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DateTimeView.kt create mode 100644 features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/DefaultRolesSettings.kt create mode 100644 features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/RolesSettings.kt create mode 100644 services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIViewModel.kt create mode 100644 services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostsListView.kt diff --git a/features/auth/client/build.gradle b/features/auth/client/build.gradle index e0086cea..611d9b31 100644 --- a/features/auth/client/build.gradle +++ b/features/auth/client/build.gradle @@ -12,7 +12,6 @@ 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") } diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt index 7a527fb2..694ccb0b 100644 --- a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/AuthSettings.kt @@ -2,7 +2,6 @@ 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 -import dev.inmo.postssystem.features.roles.common.Role import dev.inmo.postssystem.features.users.common.User import kotlinx.coroutines.Job import kotlinx.coroutines.flow.StateFlow @@ -11,7 +10,6 @@ import org.koin.core.module.Module interface AuthSettings { val authorizedDIModule: StateFlow val user: StateFlow - val userRoles: StateFlow> val loadingJob: Job suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError? diff --git a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt index 27e9a68d..747d60fc 100644 --- a/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt +++ b/features/auth/client/src/commonMain/kotlin/dev/inmo/postssystem/features/auth/client/settings/DefaultAuthSettings.kt @@ -3,14 +3,10 @@ package dev.inmo.postssystem.features.auth.client.settings import dev.inmo.postssystem.features.auth.client.AuthUnavailableException import dev.inmo.postssystem.features.auth.client.ui.* import dev.inmo.postssystem.features.auth.common.* -import dev.inmo.postssystem.features.roles.common.Role -import dev.inmo.postssystem.features.roles.common.RolesStorage import dev.inmo.postssystem.features.status.client.StatusFeatureClient import dev.inmo.postssystem.features.users.common.User import dev.inmo.micro_utils.common.Either 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 @@ -29,8 +25,6 @@ data class DefaultAuthSettings( override val authorizedDIModule: StateFlow = _authorizedDIModule.asStateFlow() private val _user = MutableStateFlow(null) override val user: StateFlow = _user.asStateFlow() - private val _userRoles = MutableStateFlow>(emptyList()) - override val userRoles: StateFlow> = _userRoles.asStateFlow() private suspend fun getCurrentServerURL() = repo.get(SERVER_URL_FIELD) as? String private suspend fun getCurrentUsername() = repo.get(USERNAME_FIELD) as? String @@ -42,18 +36,6 @@ data class DefaultAuthSettings( updateModule(serverUrl, token.either()) } - val rolesUpdatingJob = (user + authorizedDIModule).subscribeSafelyWithoutExceptions(scope) { - val user = user.value - - if (user == null || authorizedDIModule.value == null) { - _userRoles.value = emptyList() - } else { - _userRoles.value = koin.get>().getRoles(user.id) - } - println(user) - println(userRoles.value) - } - override suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError? { return runCatching { if (getCurrentServerURL() != serverUrl || getCurrentUsername() != creds.username.string) { diff --git a/features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DateTimeView.kt b/features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DateTimeView.kt new file mode 100644 index 00000000..8130bc09 --- /dev/null +++ b/features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DateTimeView.kt @@ -0,0 +1,18 @@ +package dev.inmo.postssystem.features.common.common.ui + +import androidx.compose.runtime.Composable +import com.soywiz.klock.DateTime +import com.soywiz.klock.ISO8601 +import org.jetbrains.compose.web.dom.Text + +object DateTimeView { + val simpleFormat = ISO8601.BaseIsoDateTimeFormat( + "DD.MM.YYYY, hh:mm" + ) + @Composable + fun Simple( + dateTime: DateTime + ) { + Text(dateTime.local.format(simpleFormat)) + } +} 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 a033fdec..31da0799 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 @@ -1,12 +1,15 @@ package dev.inmo.postssystem.features.content.binary.client import androidx.compose.runtime.* -import dev.inmo.jsuikit.elements.DefaultButton +import dev.inmo.jsuikit.elements.* import dev.inmo.jsuikit.modifiers.UIKitWidth import dev.inmo.micro_utils.common.selectFile +import dev.inmo.micro_utils.mime_types.KnownMimeTypes import dev.inmo.postssystem.features.common.common.* import dev.inmo.postssystem.features.content.client.ContentClientProvider import dev.inmo.postssystem.features.content.common.* +import org.jetbrains.compose.web.dom.Img +import org.jetbrains.compose.web.dom.Text import org.koin.core.module.Module object LoadingClientModule : ModuleLoader { @@ -41,4 +44,23 @@ object BinaryContentClientProvider : ContentClientProvider { } } } + + @Composable + override fun renderPreview(content: Content): Boolean { + if (content is BinaryContent) { + Tile { + Card( + header = { + CardTitle { + Text(content.filename.name) + } + } + ) {} + } + + return true + } + + return false + } } diff --git a/features/content/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/client/ContentClientProvider.kt b/features/content/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/client/ContentClientProvider.kt index fb72cefc..d11d3984 100644 --- a/features/content/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/client/ContentClientProvider.kt +++ b/features/content/client/src/jsMain/kotlin/dev/inmo/postssystem/features/content/client/ContentClientProvider.kt @@ -10,4 +10,7 @@ interface ContentClientProvider { @Composable fun renderNewInstance(state: MutableState) + + @Composable + fun renderPreview(content: Content): Boolean } 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 c913c07b..cf83a046 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 @@ -1,12 +1,14 @@ package dev.inmo.postssystem.features.content.text.client import androidx.compose.runtime.* +import dev.inmo.jsuikit.elements.Tile import dev.inmo.jsuikit.modifiers.UIKitWidth import dev.inmo.jsuikit.modifiers.include import dev.inmo.postssystem.features.common.common.* import dev.inmo.postssystem.features.content.client.ContentClientProvider import dev.inmo.postssystem.features.content.common.Content import dev.inmo.postssystem.features.content.text.common.TextContent +import org.jetbrains.compose.web.dom.Text import org.jetbrains.compose.web.dom.TextArea import org.koin.core.module.Module @@ -36,4 +38,17 @@ object TextContentClientProvider : ContentClientProvider { onInput { state.value = TextContent(it.value) } } } + + @Composable + override fun renderPreview(content: Content): Boolean { + if (content is TextContent) { + Tile { + Text(content.text) + } + + return true + } + + return false + } } diff --git a/features/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/features/posts/common/Post.kt b/features/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/features/posts/common/Post.kt index a5576f3e..aa2a6f84 100644 --- a/features/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/features/posts/common/Post.kt +++ b/features/posts/common/src/commonMain/kotlin/dev/inmo/postssystem/features/posts/common/Post.kt @@ -2,7 +2,9 @@ package dev.inmo.postssystem.features.posts.common import com.soywiz.klock.DateTime import dev.inmo.postssystem.features.common.common.DateTimeSerializer +import dev.inmo.postssystem.features.content.common.Content import dev.inmo.postssystem.features.content.common.ContentId +import kotlinx.serialization.Polymorphic import kotlinx.serialization.Serializable import kotlin.jvm.JvmInline @@ -45,3 +47,15 @@ data class RegisteredPost( @Serializable(DateTimeSerializer::class) val creationDate: DateTime ) : Post() + +@Serializable +data class PostWithContent( + val post: Post, + val content: List +) + +@Serializable +data class RegisteredPostWithContent( + val post: RegisteredPost, + val content: List<@Polymorphic Content> +) diff --git a/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/DefaultRolesSettings.kt b/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/DefaultRolesSettings.kt new file mode 100644 index 00000000..ab1cddcc --- /dev/null +++ b/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/DefaultRolesSettings.kt @@ -0,0 +1,31 @@ +package dev.inmo.postssystem.features.roles.client + +import dev.inmo.micro_utils.coroutines.plus +import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions +import dev.inmo.postssystem.features.auth.client.settings.AuthSettings +import dev.inmo.postssystem.features.roles.common.Role +import dev.inmo.postssystem.features.roles.common.RolesStorage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.* +import org.koin.core.Koin + +class DefaultRolesSettings( + private val koin: Koin, + private val authSettings: AuthSettings, + private val scope: CoroutineScope +) : RolesSettings { + private val _userRoles = MutableStateFlow>(emptyList()) + override val userRoles: StateFlow> = _userRoles.asStateFlow() + + val rolesUpdatingJob = (authSettings.user + authSettings.authorizedDIModule).subscribeSafelyWithoutExceptions(scope) { + val user = authSettings.user.value + + if (user == null || authSettings.authorizedDIModule.value == null) { + _userRoles.value = emptyList() + } else { + _userRoles.value = koin.get>().getRoles(user.id) + } + println(user) + println(userRoles.value) + } +} 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 index 8b4fef65..a058766e 100644 --- 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 @@ -6,5 +6,6 @@ import dev.inmo.postssystem.features.roles.common.Role import dev.inmo.postssystem.features.roles.common.RolesStorage val loader = AuthorizedModuleLoader { + single { DefaultRolesSettings(getKoin(), get(), get()) } single> { ClientRolesStorage(get(AuthorizedQualifiers.ServerUrlQualifier), get(), Role.serializer()) } } diff --git a/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/RolesSettings.kt b/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/RolesSettings.kt new file mode 100644 index 00000000..8be1dc29 --- /dev/null +++ b/features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/RolesSettings.kt @@ -0,0 +1,8 @@ +package dev.inmo.postssystem.features.roles.client + +import dev.inmo.postssystem.features.roles.common.Role +import kotlinx.coroutines.flow.StateFlow + +interface RolesSettings { + val userRoles: StateFlow> +} 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 index f811f71c..db18c19f 100644 --- 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 @@ -14,9 +14,6 @@ val loader = AuthorizedModuleLoader { WritePostsService::class ) - UIFSMStateSerializer.include("posts_create", PostsCreateUIFSMState.serializer()) - UIFSMStateSerializer.include("posts_list", PostsListUIFSMState.serializer()) - factory { DefaultPostCreateUIModel(get(), get()) } factory { PostCreateUIViewModel(get()) } } diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostsCreateUIFSMState.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostsCreateUIFSMState.kt index 6414fa6b..259f3ea9 100644 --- a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostsCreateUIFSMState.kt +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/create/PostsCreateUIFSMState.kt @@ -1,9 +1,7 @@ package dev.inmo.postssystem.services.posts.client.ui.create import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState -import kotlinx.serialization.Serializable -@Serializable data class PostsCreateUIFSMState( override val from: UIFSMState? = null, override val context: String = "main" diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIFSMState.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIFSMState.kt index 8f56f3bb..2b8d72b8 100644 --- a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIFSMState.kt +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIFSMState.kt @@ -1,9 +1,7 @@ package dev.inmo.postssystem.services.posts.client.ui.list import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState -import kotlinx.serialization.Serializable -@Serializable data class PostsListUIFSMState( override val from: UIFSMState? = null, override val context: String = "main" diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIState.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIState.kt index c12d1e0a..82e61f3d 100644 --- a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIState.kt +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIState.kt @@ -1,6 +1,6 @@ package dev.inmo.postssystem.services.posts.client.ui.list -import dev.inmo.postssystem.features.posts.common.Post +import dev.inmo.postssystem.features.posts.common.RegisteredPostWithContent import kotlinx.serialization.Serializable @Serializable @@ -10,7 +10,7 @@ sealed class PostsListUIState { @Serializable data class Show( - val posts: List + val posts: List ) : PostsListUIState() } diff --git a/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIViewModel.kt b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIViewModel.kt new file mode 100644 index 00000000..6ebd292d --- /dev/null +++ b/services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIViewModel.kt @@ -0,0 +1,11 @@ +package dev.inmo.postssystem.services.posts.client.ui.list + +import dev.inmo.postssystem.features.common.common.ui.UIViewModel +import kotlinx.coroutines.flow.StateFlow + +class PostsListUIViewModel( + private val model: PostsListUIModel +) : UIViewModel { + override val currentState: StateFlow + get() = model.currentState +} diff --git a/services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostsListView.kt b/services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostsListView.kt new file mode 100644 index 00000000..55ecb252 --- /dev/null +++ b/services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostsListView.kt @@ -0,0 +1,90 @@ +package dev.inmo.postssystem.services.posts.client + +import androidx.compose.runtime.mutableStateListOf +import androidx.compose.runtime.mutableStateOf +import dev.inmo.jsuikit.elements.* +import dev.inmo.micro_utils.common.applyDiff +import dev.inmo.micro_utils.coroutines.compose.renderComposableAndLinkToContextAndRoot +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.features.auth.client.registerAfterAuthHandler +import dev.inmo.postssystem.features.common.common.* +import dev.inmo.postssystem.features.common.common.ui.DateTimeView +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.posts.common.RegisteredPostWithContent +import dev.inmo.postssystem.services.posts.client.ui.create.PostsCreateUIFSMState +import dev.inmo.postssystem.services.posts.client.ui.list.* +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineScope +import org.w3c.dom.HTMLElement + +val postsListViewLoader = DefaultModuleLoader { + factory { PostsListView(get(), getAllDistinct(), get(), getAllDistinct()) } + + singleWithRandomQualifier { + UIFSMHandler.Registrator { + registerAfterAuthHandler(getKoin(), PostsListView::class) + } + } +} + +class PostsListView( + private val model: PostsListUIViewModel, + private val contentClientProviders: List, + private val uiScope: CoroutineScope, + defaultExceptionsHandlers: Iterable +) : JSView(defaultExceptionsHandlers) { + override suspend fun StatesMachine.safeHandleState( + htmlElement: HTMLElement, + state: PostsCreateUIFSMState + ): UIFSMState? { + val result = CompletableDeferred() + + val loadingState = mutableStateOf(true) + val postsState = mutableStateListOf() + + renderComposableAndLinkToContextAndRoot(htmlElement) { + if (loadingState.value) { + Spinner() + } else { + postsState.forEach { + Card( + header = { + CardTitle { + DateTimeView.Simple(it.post.creationDate) + } + Icon.App.Plus.drawAsButton { + uiScope.launchSafelyWithoutExceptions { + startChain(PostsCreateUIFSMState(state)) + } + } + } + ) { + it.content.forEach { + for (provider in contentClientProviders) { + if (provider.renderPreview(it)) { + break + } + } + } + } + } + } + } + + model.currentState.subscribeSafelyWithoutExceptions(uiScope) { + loadingState.value = it == PostsListUIState.Loading + when (it) { + PostsListUIState.Loading -> {} + is PostsListUIState.Show -> { + postsState.applyDiff(it.posts) + } + } + } + + return result.await() + } +}