temporal potentially working variant (bot not building

This commit is contained in:
InsanusMokrassar 2022-03-26 14:19:20 +06:00
parent 51cdfb320b
commit 37114f0ddb
17 changed files with 216 additions and 31 deletions

View File

@ -12,7 +12,6 @@ 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.status.client")
api project(":postssystem.features.auth.common") api project(":postssystem.features.auth.common")
} }

View File

@ -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.client.ui.AuthUIError
import dev.inmo.postssystem.features.auth.common.AuthCreds 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 dev.inmo.postssystem.features.users.common.User
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@ -11,7 +10,6 @@ import org.koin.core.module.Module
interface AuthSettings { interface AuthSettings {
val authorizedDIModule: StateFlow<Module?> val authorizedDIModule: StateFlow<Module?>
val user: StateFlow<User?> val user: StateFlow<User?>
val userRoles: StateFlow<List<Role>>
val loadingJob: Job val loadingJob: Job
suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError? suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError?

View File

@ -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.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.*
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.status.client.StatusFeatureClient
import dev.inmo.postssystem.features.users.common.User 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.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.micro_utils.repos.*
import dev.inmo.postssystem.features.auth.client.createAuthorizedFeaturesDIModule import dev.inmo.postssystem.features.auth.client.createAuthorizedFeaturesDIModule
import dev.inmo.postssystem.features.common.common.DBDropper import dev.inmo.postssystem.features.common.common.DBDropper
@ -29,8 +25,6 @@ data class DefaultAuthSettings(
override val authorizedDIModule: StateFlow<Module?> = _authorizedDIModule.asStateFlow() override val authorizedDIModule: StateFlow<Module?> = _authorizedDIModule.asStateFlow()
private val _user = MutableStateFlow<User?>(null) private val _user = MutableStateFlow<User?>(null)
override val user: StateFlow<User?> = _user.asStateFlow() 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 getCurrentServerURL() = repo.get(SERVER_URL_FIELD) as? String
private suspend fun getCurrentUsername() = repo.get(USERNAME_FIELD) as? String private suspend fun getCurrentUsername() = repo.get(USERNAME_FIELD) as? String
@ -42,18 +36,6 @@ data class DefaultAuthSettings(
updateModule(serverUrl, token.either()) 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? { override suspend fun auth(serverUrl: String, creds: AuthCreds): AuthUIError? {
return runCatching { return runCatching {
if (getCurrentServerURL() != serverUrl || getCurrentUsername() != creds.username.string) { if (getCurrentServerURL() != serverUrl || getCurrentUsername() != creds.username.string) {

View File

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

View File

@ -1,12 +1,15 @@
package dev.inmo.postssystem.features.content.binary.client package dev.inmo.postssystem.features.content.binary.client
import androidx.compose.runtime.* import androidx.compose.runtime.*
import dev.inmo.jsuikit.elements.DefaultButton import dev.inmo.jsuikit.elements.*
import dev.inmo.jsuikit.modifiers.UIKitWidth import dev.inmo.jsuikit.modifiers.UIKitWidth
import dev.inmo.micro_utils.common.selectFile 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.common.common.*
import dev.inmo.postssystem.features.content.client.ContentClientProvider import dev.inmo.postssystem.features.content.client.ContentClientProvider
import dev.inmo.postssystem.features.content.common.* 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 import org.koin.core.module.Module
object LoadingClientModule : ModuleLoader { 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
}
} }

View File

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

View File

@ -1,12 +1,14 @@
package dev.inmo.postssystem.features.content.text.client package dev.inmo.postssystem.features.content.text.client
import androidx.compose.runtime.* import androidx.compose.runtime.*
import dev.inmo.jsuikit.elements.Tile
import dev.inmo.jsuikit.modifiers.UIKitWidth import dev.inmo.jsuikit.modifiers.UIKitWidth
import dev.inmo.jsuikit.modifiers.include import dev.inmo.jsuikit.modifiers.include
import dev.inmo.postssystem.features.common.common.* import dev.inmo.postssystem.features.common.common.*
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.features.content.text.common.TextContent 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.jetbrains.compose.web.dom.TextArea
import org.koin.core.module.Module import org.koin.core.module.Module
@ -36,4 +38,17 @@ object TextContentClientProvider : ContentClientProvider {
onInput { state.value = TextContent(it.value) } 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
}
} }

View File

@ -2,7 +2,9 @@ package dev.inmo.postssystem.features.posts.common
import com.soywiz.klock.DateTime import com.soywiz.klock.DateTime
import dev.inmo.postssystem.features.common.common.DateTimeSerializer 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 dev.inmo.postssystem.features.content.common.ContentId
import kotlinx.serialization.Polymorphic
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlin.jvm.JvmInline import kotlin.jvm.JvmInline
@ -45,3 +47,15 @@ data class RegisteredPost(
@Serializable(DateTimeSerializer::class) @Serializable(DateTimeSerializer::class)
val creationDate: DateTime val creationDate: DateTime
) : Post() ) : Post()
@Serializable
data class PostWithContent(
val post: Post,
val content: List<Content>
)
@Serializable
data class RegisteredPostWithContent(
val post: RegisteredPost,
val content: List<@Polymorphic Content>
)

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +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.ui.fsm.UIFSMState import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState
import kotlinx.serialization.Serializable
@Serializable
data class PostsCreateUIFSMState( data class PostsCreateUIFSMState(
override val from: UIFSMState? = null, override val from: UIFSMState? = null,
override val context: String = "main" override val context: String = "main"

View File

@ -1,9 +1,7 @@
package dev.inmo.postssystem.services.posts.client.ui.list package dev.inmo.postssystem.services.posts.client.ui.list
import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState import dev.inmo.postssystem.features.common.common.ui.fsm.UIFSMState
import kotlinx.serialization.Serializable
@Serializable
data class PostsListUIFSMState( data class PostsListUIFSMState(
override val from: UIFSMState? = null, override val from: UIFSMState? = null,
override val context: String = "main" override val context: String = "main"

View File

@ -1,6 +1,6 @@
package dev.inmo.postssystem.services.posts.client.ui.list 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 import kotlinx.serialization.Serializable
@Serializable @Serializable
@ -10,7 +10,7 @@ sealed class PostsListUIState {
@Serializable @Serializable
data class Show( data class Show(
val posts: List<Post> val posts: List<RegisteredPostWithContent>
) : PostsListUIState() ) : PostsListUIState()
} }

View File

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

View File

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