some runnable variant

This commit is contained in:
InsanusMokrassar 2022-01-22 22:59:41 +06:00
parent 0716035f0b
commit 3746efc596
12 changed files with 13 additions and 235 deletions

View File

@ -6,7 +6,6 @@ import dev.inmo.jsuikit.elements.*
import dev.inmo.jsuikit.modifiers.UIKitButton import dev.inmo.jsuikit.modifiers.UIKitButton
import dev.inmo.jsuikit.modifiers.UIKitMargin import dev.inmo.jsuikit.modifiers.UIKitMargin
import dev.inmo.postssystem.client.ui.fsm.* import dev.inmo.postssystem.client.ui.fsm.*
import dev.inmo.postssystem.client.utils.HTMLViewContainer
import dev.inmo.postssystem.features.auth.client.ui.* import dev.inmo.postssystem.features.auth.client.ui.*
import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.launchSafelyWithoutExceptions
import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions
@ -26,7 +25,6 @@ class AuthView(
override suspend fun StatesMachine<in UIFSMState>.safeHandleState( override suspend fun StatesMachine<in UIFSMState>.safeHandleState(
htmlElement: HTMLElement, htmlElement: HTMLElement,
container: HTMLViewContainer,
state: AuthUIFSMState state: AuthUIFSMState
): UIFSMState? { ): UIFSMState? {
val completion = CompletableDeferred<UIFSMState?>() val completion = CompletableDeferred<UIFSMState?>()
@ -36,12 +34,12 @@ class AuthView(
val passwordState = mutableStateOf("") val passwordState = mutableStateOf("")
val usernameDisabled = mutableStateOf(true) val usernameDisabled = mutableStateOf(true)
val passwordDisabled = mutableStateOf(true) val passwordDisabled = mutableStateOf(true)
val authBtnDisabled = remember {
usernameState.value.isNotBlank() && passwordState.value.isNotBlank()
}
val errorText = mutableStateOf<String?>(null) val errorText = mutableStateOf<String?>(null)
val composition = renderComposableAndLinkToContext(htmlElement) { val composition = renderComposableAndLinkToContext(htmlElement) {
val authBtnDisabled = remember {
usernameState.value.isNotBlank() && passwordState.value.isNotBlank()
}
Form { Form {
TextField( TextField(
InputType.Text, InputType.Text,

View File

@ -2,20 +2,17 @@ package dev.inmo.postssystem.client.fsm.ui
import dev.inmo.postssystem.client.ui.fsm.UIFSMHandler import dev.inmo.postssystem.client.ui.fsm.UIFSMHandler
import dev.inmo.postssystem.client.ui.fsm.UIFSMState import dev.inmo.postssystem.client.ui.fsm.UIFSMState
import dev.inmo.postssystem.client.utils.HTMLViewContainer
import dev.inmo.micro_utils.fsm.common.StatesMachine import dev.inmo.micro_utils.fsm.common.StatesMachine
import kotlinx.browser.document
import org.w3c.dom.HTMLElement import org.w3c.dom.HTMLElement
abstract class JSView<T : UIFSMState> : UIFSMHandler<T> { abstract class JSView<T : UIFSMState> : UIFSMHandler<T> {
open suspend fun StatesMachine<in UIFSMState>.safeHandleState( open suspend fun StatesMachine<in UIFSMState>.safeHandleState(
htmlElement: HTMLElement, htmlElement: HTMLElement,
container: HTMLViewContainer,
state: T state: T
): UIFSMState? = null ): UIFSMState? = null
override suspend fun StatesMachine<in UIFSMState>.safeHandleState(state: T): UIFSMState? { override suspend fun StatesMachine<in UIFSMState>.safeHandleState(state: T): UIFSMState? {
return HTMLViewContainer.from(state.context) ?.let { return safeHandleState(document.getElementById(state.context) as? HTMLElement ?: return null, state)
safeHandleState(it.htmlElement ?: return null, it, state)
}
} }
} }

View File

@ -1,20 +0,0 @@
package dev.inmo.postssystem.client.fsm.ui.defaults
import dev.inmo.postssystem.client.ui.fsm.UIFSMState
import kotlinx.coroutines.CompletableDeferred
import kotlinx.html.TagConsumer
import kotlinx.html.js.button
import kotlinx.html.js.onClickFunction
import org.w3c.dom.HTMLElement
fun TagConsumer<HTMLElement>.addBackButton(
completableDeferred: CompletableDeferred<UIFSMState>,
stateToBack: UIFSMState
) {
button {
+"Назад"
onClickFunction = {
completableDeferred.complete(stateToBack)
}
}
}

View File

@ -1,64 +0,0 @@
package dev.inmo.postssystem.client.utils
import com.benasher44.uuid.uuid4
import kotlinx.browser.document
import kotlinx.html.*
import kotlinx.html.dom.append
import kotlinx.html.js.*
import org.w3c.dom.*
object DialogHelper {
fun createOneFieldDialog(
title: String,
hint: String,
doneButtonText: String,
closeButtonText: String,
onClose: () -> Unit,
onSubmit: (String) -> Unit
): HTMLDialogElement {
lateinit var dialogElement: HTMLDialogElement
(document.getElementsByTagName("body").item(0) as? HTMLBodyElement) ?.append {
dialogElement = dialog("mdl-dialog") {
h4("mdl-dialog__title") {
+title
}
val id = "form_${uuid4()}_text"
div(classes = "mdl-dialog__content") {
form("#") {
div("mdl-textfield mdl-js-textfield mdl-textfield--floating-label") {
input(InputType.text, classes = "mdl-textfield__input") {
this.id = id
}
label(classes = "mdl-textfield__label") {
+hint
attributes["for"] = id
}
}
}
}
div(classes = "mdl-dialog__actions mdl-dialog__actions--full-width") {
button(classes = "mdl-button", type = ButtonType.button) {
+doneButtonText
onClickFunction = {
it.preventDefault()
val input = document.getElementById(id) as? HTMLInputElement
input ?.value ?.let {
onSubmit(it)
}
}
}
button(classes = "mdl-button", type = ButtonType.button) {
+closeButtonText
onClickFunction = {
it.preventDefault()
onClose()
}
}
}
}
}
return dialogElement
}
}

View File

@ -2,6 +2,7 @@ package dev.inmo.postssystem.client.utils
import dev.inmo.postssystem.features.files.common.FullFileInfo import dev.inmo.postssystem.features.files.common.FullFileInfo
import dev.inmo.micro_utils.common.toArrayBuffer import dev.inmo.micro_utils.common.toArrayBuffer
import io.ktor.utils.io.core.readBytes
import kotlinx.browser.document import kotlinx.browser.document
import org.w3c.dom.HTMLAnchorElement import org.w3c.dom.HTMLAnchorElement
import org.w3c.dom.url.URL import org.w3c.dom.url.URL
@ -10,7 +11,7 @@ import org.w3c.files.Blob
fun triggerDownloadFile(fullFileInfo: FullFileInfo) { fun triggerDownloadFile(fullFileInfo: FullFileInfo) {
val hiddenElement = document.createElement("a") as HTMLAnchorElement val hiddenElement = document.createElement("a") as HTMLAnchorElement
val url = URL.createObjectURL(Blob(arrayOf(fullFileInfo.inputProvider().toArrayBuffer()))) val url = URL.createObjectURL(Blob(arrayOf(fullFileInfo.inputProvider().readBytes().toArrayBuffer())))
hiddenElement.href = url hiddenElement.href = url
hiddenElement.target = "_blank" hiddenElement.target = "_blank"
hiddenElement.download = fullFileInfo.name.name hiddenElement.download = fullFileInfo.name.name

View File

@ -1,134 +0,0 @@
package dev.inmo.postssystem.client.utils
import kotlinx.browser.document
import kotlinx.dom.clear
import kotlinx.html.dom.append
import kotlinx.html.id
import kotlinx.html.js.*
import org.w3c.dom.HTMLElement
import org.w3c.dom.events.Event
object HTMLViewsConstants {
val mainContainer: MainHTMLViewContainer = MainHTMLViewContainer
val processesContainer: DrawerHTMLViewContainer = DrawerHTMLViewContainer
val toolsContainerId: ToolsHTMLViewContainer = ToolsHTMLViewContainer
}
sealed interface HTMLViewContainer {
val htmlElement: HTMLElement?
get() = document.getElementById(id) as? HTMLElement
val id: String
fun setIsLoading() {
htmlElement ?.apply {
clear()
append {
div("mdl-spinner mdl-js-spinner is-active")
}
}
}
companion object {
fun from(elementId: String) = when (elementId) {
MainHTMLViewContainer.id -> MainHTMLViewContainer
DrawerHTMLViewContainer.id -> DrawerHTMLViewContainer
ToolsHTMLViewContainer.id -> ToolsHTMLViewContainer
else -> null
}
}
}
object MainHTMLViewContainer : HTMLViewContainer {
override val id: String
get() = "main"
}
object DrawerHTMLViewContainer : HTMLViewContainer {
data class DrawerAddButtonInfo(
val text: String,
val onAddButtonClick: (Event) -> Unit,
)
override val id: String
get() = "drawer"
private val titleElement: HTMLElement?
get() = (document.getElementById("drawerTitle") ?:let {
htmlElement ?.append {
span("mdl-layout-title") {
id = "drawerTitle"
}
} ?.first()
}) as? HTMLElement
var title: String?
get() = titleElement ?.textContent
set(value) {
if (value == null) {
titleElement ?.classList ?.add("gone")
} else {
val element = titleElement ?: return
element.textContent = value
element.classList.remove("gone")
}
}
private val contentElement
get() = (document.getElementById("drawerContent") ?:let {
htmlElement ?.append {
nav("mdl-navigation") {
id = "drawerContent"
}
} ?.first()
}) as? HTMLElement
fun <T> setListContent(
title: String?,
data: Iterable<T>,
getText: (T) -> String?,
addButtonInfo: DrawerAddButtonInfo? = null,
onClick: (T) -> Unit
) {
this.title = title
val contentElement = contentElement ?: return
contentElement.clear()
contentElement.append {
fun hideDrawer() {
// Emulate clicking for hiding of drawer
(document.getElementsByClassName("mdl-layout__obfuscator").item(0) as? HTMLElement) ?.click()
}
data.forEach {
val elementTitle = getText(it) ?: return@forEach
div("mdl-navigation__link") {
+elementTitle
onClickFunction = { _ ->
onClick(it)
hideDrawer()
}
}
}
if (addButtonInfo != null) {
button(classes = "mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--accent") {
+addButtonInfo.text
onClickFunction = {
addButtonInfo.onAddButtonClick(it)
hideDrawer()
}
}
}
}
}
override fun setIsLoading() {
contentElement ?.apply {
clear()
append {
div("mdl-spinner mdl-js-spinner is-active")
}
}
}
}
object ToolsHTMLViewContainer : HTMLViewContainer {
override val id: String
get() = "tools"
}

View File

@ -1,5 +1,6 @@
package dev.inmo.postssystem.client.utils package dev.inmo.postssystem.client.utils
import androidx.compose.runtime.MutableState
import dev.inmo.postssystem.features.files.common.FullFileInfo import dev.inmo.postssystem.features.files.common.FullFileInfo
import dev.inmo.micro_utils.common.* import dev.inmo.micro_utils.common.*
import dev.inmo.micro_utils.mime_types.KnownMimeTypes import dev.inmo.micro_utils.mime_types.KnownMimeTypes

View File

@ -6,9 +6,8 @@
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css">
<link rel="stylesheet" href="styles/material.min.css" type="text/css"> <link rel="stylesheet" href="css/containers.css" type="text/css">
<link rel="stylesheet" href="styles/containers.css" type="text/css"> <link rel="stylesheet" href="css/visibility.css" type="text/css">
<link rel="stylesheet" href="styles/visibility.css" type="text/css">
</head> </head>
<body> <body>
<!-- Always shows a header, even in smaller screens. --> <!-- Always shows a header, even in smaller screens. -->

View File

@ -35,14 +35,14 @@ kotlinx_html_version=0.7.3
android_minSdkVersion=21 android_minSdkVersion=21
android_compileSdkVersion=32 android_compileSdkVersion=32
android_buildToolsVersion=32.0.0 android_buildToolsVersion=32.0.0
dexcount_version=3.0.0 dexcount_version=3.0.1
junit_version=4.12 junit_version=4.12
test_ext_junit_version=1.1.2 test_ext_junit_version=1.1.2
espresso_core=3.3.0 espresso_core=3.3.0
# Dokka # Dokka
dokka_version=1.6.0 dokka_version=1.6.10
# Project data # Project data

View File

@ -18,4 +18,4 @@ startTestPostgres:
sudo docker-compose up sudo docker-compose up
addTestUserAndAuth: addTestUserAndAuth:
docker-compose exec test_postgres psql test -U test -c "INSERT INTO Users VALUES (-1, 'test', 'test', 'test');INSERT INTO UsersAuthentications VALUES ('test', -1);" sudo docker-compose exec test_postgres psql test -U test -c "INSERT INTO Users VALUES (-1, 'test', 'test', 'test');INSERT INTO UsersAuthentications VALUES ('test', -1);"