temporal potentially working variant (bot not building
This commit is contained in:
features
auth
client
common
client
src
jsMain
kotlin
dev
inmo
postssystem
features
common
common
content
binary
client
src
jsMain
kotlin
dev
inmo
postssystem
features
content
binary
client
src
jsMain
kotlin
dev
inmo
postssystem
features
content
client
text
client
src
jsMain
kotlin
dev
inmo
postssystem
features
content
text
posts
common
src
commonMain
kotlin
dev
inmo
postssystem
features
posts
common
roles
client
src
commonMain
kotlin
dev
inmo
postssystem
features
services/posts/client/src
commonMain
kotlin
dev
inmo
postssystem
services
jsMain
kotlin
dev
inmo
postssystem
services
posts
client
@ -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) {
|
||||
|
18
features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DateTimeView.kt
Normal file
18
features/common/client/src/jsMain/kotlin/dev/inmo/postssystem/features/common/common/ui/DateTimeView.kt
Normal 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))
|
||||
}
|
||||
}
|
@ -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>
|
||||
)
|
||||
|
31
features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/DefaultRolesSettings.kt
Normal file
31
features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/DefaultRolesSettings.kt
Normal 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)
|
||||
}
|
||||
}
|
@ -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()) }
|
||||
}
|
||||
|
8
features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/RolesSettings.kt
Normal file
8
features/roles/client/src/commonMain/kotlin/dev/inmo/postssystem/features/roles/client/RolesSettings.kt
Normal 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>>
|
||||
}
|
@ -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()
|
||||
|
||||
}
|
||||
|
11
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIViewModel.kt
Normal file
11
services/posts/client/src/commonMain/kotlin/dev/inmo/postssystem/services/posts/client/ui/list/PostsListUIViewModel.kt
Normal 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
|
||||
}
|
90
services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostsListView.kt
Normal file
90
services/posts/client/src/jsMain/kotlin/dev/inmo/postssystem/services/posts/client/PostsListView.kt
Normal 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()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user