temporal potentially working variant (bot not building
This commit is contained in:
parent
51cdfb320b
commit
37114f0ddb
@ -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()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user