temporal potentially working variant (bot not building

This commit is contained in:
2022-03-26 14:19:20 +06:00
parent 51cdfb320b
commit 37114f0ddb
17 changed files with 216 additions and 31 deletions
features
auth
client
build.gradle
src
commonMain
kotlin
dev
inmo
postssystem
features
common
client
src
jsMain
kotlin
dev
inmo
postssystem
features
common
content
binary
client
src
jsMain
kotlin
dev
inmo
postssystem
features
client
src
jsMain
kotlin
dev
inmo
postssystem
features
text
client
src
jsMain
kotlin
dev
inmo
postssystem
features
posts
common
src
commonMain
kotlin
dev
inmo
postssystem
features
posts
common
roles
client
src
commonMain
kotlin
dev
services/posts/client/src
commonMain
jsMain
kotlin
dev
inmo
postssystem
services
posts

@ -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")
}

@ -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<Module?>
val user: StateFlow<User?>
val userRoles: StateFlow<List<Role>>
val loadingJob: Job
suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError?

@ -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<Module?> = _authorizedDIModule.asStateFlow()
private val _user = MutableStateFlow<User?>(null)
override val user: StateFlow<User?> = _user.asStateFlow()
private val _userRoles = MutableStateFlow<List<Role>>(emptyList())
override val userRoles: StateFlow<List<Role>> = _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<RolesStorage<Role>>().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) {

@ -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))
}
}

@ -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
}
}

@ -10,4 +10,7 @@ interface ContentClientProvider {
@Composable
fun renderNewInstance(state: MutableState<Content?>)
@Composable
fun renderPreview(content: Content): Boolean
}

@ -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
}
}

@ -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<Content>
)
@Serializable
data class RegisteredPostWithContent(
val post: RegisteredPost,
val content: List<@Polymorphic Content>
)

@ -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<List<Role>>(emptyList())
override val userRoles: StateFlow<List<Role>> = _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<RolesStorage<Role>>().getRoles(user.id)
}
println(user)
println(userRoles.value)
}
}

@ -6,5 +6,6 @@ import dev.inmo.postssystem.features.roles.common.Role
import dev.inmo.postssystem.features.roles.common.RolesStorage
val loader = AuthorizedModuleLoader {
single<RolesSettings> { DefaultRolesSettings(getKoin(), get(), get()) }
single<RolesStorage<Role>> { ClientRolesStorage(get(AuthorizedQualifiers.ServerUrlQualifier), get(), Role.serializer()) }
}

@ -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<List<Role>>
}

@ -14,9 +14,6 @@ val loader = AuthorizedModuleLoader {
WritePostsService::class
)
UIFSMStateSerializer.include("posts_create", PostsCreateUIFSMState.serializer())
UIFSMStateSerializer.include("posts_list", PostsListUIFSMState.serializer())
factory<PostCreateUIModel> { DefaultPostCreateUIModel(get(), get()) }
factory { PostCreateUIViewModel(get()) }
}

@ -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"

@ -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"

@ -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<Post>
val posts: List<RegisteredPostWithContent>
) : PostsListUIState()
}

@ -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<PostsListUIState> {
override val currentState: StateFlow<PostsListUIState>
get() = model.currentState
}

@ -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> {
UIFSMHandler.Registrator {
registerAfterAuthHandler(getKoin(), PostsListView::class)
}
}
}
class PostsListView(
private val model: PostsListUIViewModel,
private val contentClientProviders: List<ContentClientProvider>,
private val uiScope: CoroutineScope,
defaultExceptionsHandlers: Iterable<UIFSMExceptionHandler>
) : JSView<PostsCreateUIFSMState>(defaultExceptionsHandlers) {
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
htmlElement: HTMLElement,
state: PostsCreateUIFSMState
): UIFSMState? {
val result = CompletableDeferred<UIFSMState?>()
val loadingState = mutableStateOf(true)
val postsState = mutableStateListOf<RegisteredPostWithContent>()
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()
}
}