Compare commits
7 Commits
kotlin/2.2
...
kotlin/2.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b83137bd0 | |||
| e1fbfc7aa3 | |||
| ca9db2585d | |||
| a4bd3bdb58 | |||
| d48133f77f | |||
| 144058a881 | |||
| 5079bb448c |
@@ -11,7 +11,7 @@ val dataforgeVersion by extra("0.10.1")
|
||||
|
||||
allprojects {
|
||||
group = "space.kscience"
|
||||
version = "0.5.1-dev-1"
|
||||
version = "0.6.0-dev-1"
|
||||
}
|
||||
|
||||
subprojects {
|
||||
@@ -39,17 +39,24 @@ subprojects {
|
||||
}
|
||||
|
||||
|
||||
ksciencePublish {
|
||||
kscienceProject {
|
||||
pom("https://github.com/SciProgCentre/visionforge") {
|
||||
useApache2Licence()
|
||||
useSPCTeam()
|
||||
}
|
||||
repository("spc", "https://maven.sciprog.center/kscience")
|
||||
central()
|
||||
publishTo("spc", "https://maven.sciprog.center/kscience")
|
||||
publishToCentral()
|
||||
|
||||
abiValidation {
|
||||
// filters{
|
||||
// excluded{
|
||||
// byNames
|
||||
// }
|
||||
// }
|
||||
//ignoredPackages.add("info.laht.threekt")
|
||||
}
|
||||
|
||||
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
}
|
||||
|
||||
apiValidation {
|
||||
ignoredPackages.add("info.laht.threekt")
|
||||
}
|
||||
|
||||
readme.readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
@@ -12,11 +12,7 @@ kscience {
|
||||
"muon-monitor.js",
|
||||
development = false,
|
||||
jvmConfig = {
|
||||
binaries {
|
||||
executable {
|
||||
mainClass.set("ru.mipt.npm.muon.monitor.MMServerKt")
|
||||
}
|
||||
}
|
||||
application("ru.mipt.npm.muon.monitor.MMServerKt")
|
||||
},
|
||||
browserConfig = {
|
||||
commonWebpackConfig {
|
||||
|
||||
@@ -12,7 +12,7 @@ repositories {
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
jvmToolchain(21)
|
||||
js {
|
||||
useEsModules()
|
||||
browser {
|
||||
|
||||
@@ -13,14 +13,10 @@ kscience {
|
||||
// useSerialization {
|
||||
// json()
|
||||
// }
|
||||
jvm{
|
||||
binaries {
|
||||
executable {
|
||||
mainClass.set("ru.mipt.npm.sat.SatServerKt")
|
||||
}
|
||||
}
|
||||
jvm {
|
||||
application("ru.mipt.npm.sat.SatServerKt")
|
||||
}
|
||||
jvmMain{
|
||||
jvmMain {
|
||||
implementation("io.ktor:ktor-server-cio")
|
||||
implementation(projects.visionforgeThreejs.visionforgeThreejsServer)
|
||||
implementation(spclibs.logback.classic)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package space.kscience.visionforge.solid.demo
|
||||
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.*
|
||||
import space.kscience.visionforge.html.startApplication
|
||||
import space.kscience.visionforge.solid.x
|
||||
import space.kscience.visionforge.solid.y
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun main() {
|
||||
startApplication { document ->
|
||||
val element = document.getElementById("demo") ?: error("Element with id 'demo' not found on page")
|
||||
|
||||
@@ -8,4 +8,4 @@ org.gradle.workers.max=4
|
||||
org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
|
||||
kotlin.native.enableKlibsCrossCompilation=true
|
||||
|
||||
toolsVersion=0.19.1-kotlin-2.2.20-Beta2
|
||||
toolsVersion=0.20.0-kotlin-2.3.0-Beta1
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
plugins{
|
||||
id("org.jetbrains.changelog")
|
||||
id("space.kscience.gradle.project")
|
||||
}
|
||||
|
||||
kscienceProject{
|
||||
readme {
|
||||
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
}
|
||||
}
|
||||
|
||||
readme {
|
||||
readmeTemplate = file("docs/templates/README-TEMPLATE.md")
|
||||
}
|
||||
@@ -15,7 +15,7 @@ dependencies {
|
||||
}
|
||||
|
||||
kotlin{
|
||||
jvmToolchain(17)
|
||||
jvmToolchain(21)
|
||||
}
|
||||
|
||||
// A workaround for https://youtrack.jetbrains.com/issue/KT-44101
|
||||
|
||||
@@ -12,7 +12,7 @@ repositories {
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
jvmToolchain(17)
|
||||
jvmToolchain(21)
|
||||
sourceSets {
|
||||
jvmMain {
|
||||
dependencies {
|
||||
|
||||
@@ -31,10 +31,11 @@ kscience {
|
||||
}
|
||||
}
|
||||
|
||||
//tasks.processJupyterApiResources {
|
||||
// libraryProducers = listOf("space.kscience.plotly.PlotlyIntegration")
|
||||
//}
|
||||
|
||||
kotlinJupyter {
|
||||
integrations {
|
||||
producer("space.kscience.plotly.PlotlyIntegration")
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
|
||||
@@ -106,12 +106,14 @@ public inline fun VisionOutput.plotly(
|
||||
return Plotly.plot(block)
|
||||
}
|
||||
|
||||
|
||||
//FIXME rework VisionTagConsumer toa a context
|
||||
context(rootConsumer: VisionTagConsumer<*>)
|
||||
public fun TagConsumer<*>.plot(
|
||||
config: PlotlyConfig = PlotlyConfig(),
|
||||
block: Plot.() -> Unit,
|
||||
): Unit = with(rootConsumer) {
|
||||
vision {
|
||||
this@plot.vision {
|
||||
plotly(config, block)
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ public fun TagConsumer<*>.staticPlot(
|
||||
config: PlotlyConfig = PlotlyConfig(),
|
||||
plotId: String = "plotly[${Uuid.random()}]",
|
||||
plot: Plot.() -> Unit
|
||||
) = staticPlot(Plotly.plot(plot), config, plotId)
|
||||
): Unit = staticPlot(Plotly.plot(plot), config, plotId)
|
||||
|
||||
/**
|
||||
* Create an html (including headers) string from plot
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
package space.kscience.plotly
|
||||
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.browser.window
|
||||
import org.w3c.dom.*
|
||||
import org.w3c.dom.url.URL
|
||||
import org.w3c.fetch.RequestInit
|
||||
import kotlin.js.Promise
|
||||
import kotlin.js.json
|
||||
|
||||
@JsExport
|
||||
public object PlotlyConnect {
|
||||
|
||||
/**
|
||||
* Wait for the Plotly library to be loaded
|
||||
*/
|
||||
private fun withPlotly(action: PlotlyJs.() -> Unit) {
|
||||
if (jsTypeOf(PlotlyJs) !== "undefined") {
|
||||
action(PlotlyJs);
|
||||
} else {
|
||||
val promiseOfPlotly: Promise<PlotlyJs> = window.asDynamic().promiseOfPlotly as Promise<PlotlyJs>
|
||||
if (jsTypeOf(promiseOfPlotly) != "undefined") {
|
||||
promiseOfPlotly.then { action(PlotlyJs) }
|
||||
} else {
|
||||
console.warn("Plotly not defined. Loading the script from CDN")
|
||||
window.asDynamic().promiseOfPlotly = Promise<PlotlyJs> { resolve, reject ->
|
||||
val plotlyLoaderScript = document.createElement("script") as HTMLScriptElement
|
||||
plotlyLoaderScript.src = "https://cdn.plot.ly/plotly-2.29.0.min.js"
|
||||
plotlyLoaderScript.type = "text/javascript"
|
||||
plotlyLoaderScript.onload = {
|
||||
resolve(PlotlyJs)
|
||||
action(PlotlyJs)
|
||||
}
|
||||
plotlyLoaderScript.onerror = { error, _, _, _, _ ->
|
||||
console.error(error);
|
||||
reject(error as Throwable)
|
||||
}
|
||||
document.head?.appendChild(plotlyLoaderScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request and parse json from given address
|
||||
* @param url {URL}
|
||||
* @param callback
|
||||
*/
|
||||
private fun getJSON(url: URL, callback: (dynamic) -> Unit) {
|
||||
try {
|
||||
window.fetch(
|
||||
url,
|
||||
RequestInit(
|
||||
method = "GET",
|
||||
headers = json("Accept" to "application/json")
|
||||
)
|
||||
).then { response ->
|
||||
if (!response.ok) {
|
||||
error("Fetch request failed with error: ${response.statusText}")
|
||||
} else {
|
||||
response.json().then(callback)
|
||||
}
|
||||
}.catch { error -> console.log(error) }
|
||||
} catch (e: Exception) {
|
||||
window.alert("Fetch of plot data failed with error: $e")
|
||||
}
|
||||
}
|
||||
|
||||
public fun makePlot(
|
||||
graphDiv: Element,
|
||||
data: Array<dynamic>,
|
||||
layout: dynamic,
|
||||
config: dynamic,
|
||||
) {
|
||||
withPlotly { newPlot(graphDiv, data, layout, config) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a plot taking data from given url
|
||||
* @param id {string} element id for plot
|
||||
* @param from {URL} json server url
|
||||
* @param config {object} plotly configuration
|
||||
*/
|
||||
|
||||
public fun createPlotFrom(id: String, from: URL, config: dynamic = {}) {
|
||||
getJSON(from) { json ->
|
||||
val element = document.getElementById(id) as HTMLElement
|
||||
withPlotly { newPlot(element, json.data, json.layout, config) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a plot taking data from given url
|
||||
* @param id {string} element id for plot
|
||||
* @param from {URL} json server url
|
||||
* @return {JSON}
|
||||
*/
|
||||
public fun updatePlotFrom(id: String, from: URL) {
|
||||
getJSON(from) { json ->
|
||||
val element = document.getElementById(id) as HTMLElement
|
||||
withPlotly { react(element, json.data, json.layout) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start pull updates with regular requests from client side
|
||||
* @param id {string}
|
||||
* @param from
|
||||
* @param millis
|
||||
*/
|
||||
public fun startPull(id: String, from: URL, millis: Int) {
|
||||
window.setInterval({ updatePlotFrom(id, from) }, millis)
|
||||
}
|
||||
|
||||
/**
|
||||
* Start push updates via websocket
|
||||
* @param id {string} element id for plot
|
||||
* @param ws {URL} a websocket address
|
||||
*/
|
||||
public fun startPush(id: String, ws: String) {
|
||||
val element = document.getElementById(id) as HTMLElement
|
||||
val socket = WebSocket(ws)
|
||||
|
||||
socket.onopen = {
|
||||
console.log("[Plotly.kt] A connection for plot with id = $id with server established on $ws")
|
||||
}
|
||||
|
||||
socket.onclose = { event ->
|
||||
event as CloseEvent
|
||||
if (event.wasClean) {
|
||||
console.log("The connection with server is closed")
|
||||
} else {
|
||||
console.log("The connection with server is broken") // Server process is dead
|
||||
}
|
||||
console.log("Code: ${event.code} case: ${event.reason}")
|
||||
}
|
||||
|
||||
socket.onerror = { error ->
|
||||
error as ErrorEvent
|
||||
console.error("Plotly push update error: " + error.message)
|
||||
socket.close()
|
||||
}
|
||||
|
||||
socket.onmessage = { event ->
|
||||
val json: dynamic = JSON.parse(event.data.toString())
|
||||
if (json.plotId === id) {
|
||||
if (json.contentType === "layout") {
|
||||
withPlotly { relayout(element, json.content) }
|
||||
} else if (json.contentType === "trace") {
|
||||
withPlotly { restyle(element, json.content, json.trace) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//gracefully close the socket just in case
|
||||
window.onbeforeunload = {
|
||||
console.log("Gracefully closing socket")
|
||||
socket.close()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun main() {
|
||||
window.asDynamic().plotlyConnect = PlotlyConnect
|
||||
window.asDynamic().Plotly = PlotlyJs
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package space.kscience.plotly
|
||||
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.serialization.modules.SerializersModule
|
||||
import org.w3c.dom.Element
|
||||
import space.kscience.dataforge.context.Context
|
||||
@@ -12,6 +13,7 @@ import space.kscience.visionforge.Vision
|
||||
import space.kscience.visionforge.VisionPlugin
|
||||
import space.kscience.visionforge.html.ElementVisionRenderer
|
||||
import space.kscience.visionforge.html.JsVisionClient
|
||||
import space.kscience.visionforge.html.renderAllVisions
|
||||
|
||||
public class PlotlyJsPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
public val plotly: PlotlyPlugin by require(PlotlyPlugin)
|
||||
@@ -39,10 +41,25 @@ public class PlotlyJsPlugin : VisionPlugin(), ElementVisionRenderer {
|
||||
else -> super.content(target)
|
||||
}
|
||||
|
||||
public companion object : PluginFactory<PlotlyJsPlugin> {
|
||||
public companion object : PluginFactory<PlotlyJsPlugin> {
|
||||
override val tag: PluginTag = PluginTag("vision.plotly.js", PluginTag.DATAFORGE_GROUP)
|
||||
|
||||
override fun build(context: Context, meta: Meta): PlotlyJsPlugin = PlotlyJsPlugin()
|
||||
|
||||
public val defaultClient: JsVisionClient by lazy {
|
||||
val context = Context("Plotly-kt") {
|
||||
plugin(PlotlyJsPlugin)
|
||||
}
|
||||
context.plugins[PlotlyJsPlugin]!!.visionClient
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public fun main() {
|
||||
window.asDynamic().Plotly = PlotlyJs
|
||||
window.asDynamic().renderAllPlots = {
|
||||
PlotlyJsPlugin.defaultClient.renderAllVisions()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package space.kscience.plotly
|
||||
|
||||
import kotlinx.html.script
|
||||
import kotlinx.html.unsafe
|
||||
import space.kscience.visionforge.html.*
|
||||
import space.kscience.visionforge.visionManager
|
||||
import java.awt.Desktop
|
||||
@@ -53,6 +55,17 @@ public fun Plotly.makePageFile(
|
||||
resourceLocation,
|
||||
actualPath
|
||||
),
|
||||
"plotly-render" to HtmlFragment {
|
||||
script {
|
||||
defer = true
|
||||
|
||||
unsafe {
|
||||
+"""
|
||||
window.renderAllPlots()
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
}
|
||||
) + additionalHeaders
|
||||
}
|
||||
if (show) Desktop.getDesktop().browse(actualPath.toFile().toURI())
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package space.kscience.visionforge.meta
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.sync.Semaphore
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.request
|
||||
@@ -13,7 +9,6 @@ import space.kscience.dataforge.names.asName
|
||||
import space.kscience.dataforge.names.get
|
||||
import space.kscience.dataforge.names.parseAsName
|
||||
import space.kscience.visionforge.*
|
||||
import kotlin.test.Ignore
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
@@ -93,51 +88,4 @@ internal class VisionPropertyTest {
|
||||
subscription.cancel()
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
fun testChildrenPropertyFlow() = runTest(timeout = 500.milliseconds) {
|
||||
val group = SimpleVisionGroup().apply {
|
||||
|
||||
properties {
|
||||
"test" put 11
|
||||
}
|
||||
|
||||
group("child") {
|
||||
properties {
|
||||
"test" put 22
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val child = group.visions["child"] as MutableVision
|
||||
|
||||
val semaphore = Semaphore(1, 1)
|
||||
|
||||
val changesFlow = child.flowPropertyValue("test", inherited = true).map {
|
||||
semaphore.release()
|
||||
it!!.int
|
||||
}
|
||||
|
||||
val collectedValues = ArrayList<Int>(5)
|
||||
|
||||
val collectorJob = changesFlow.onEach {
|
||||
collectedValues.add(it)
|
||||
}.launchIn(this)
|
||||
|
||||
assertEquals(22, child.readProperty("test", true).int)
|
||||
|
||||
semaphore.acquire()
|
||||
child.properties.remove("test")
|
||||
|
||||
assertEquals(11, child.readProperty("test", true).int)
|
||||
|
||||
semaphore.acquire()
|
||||
group.properties["test"] = 33
|
||||
assertEquals(33, child.readProperty("test", true).int)
|
||||
|
||||
semaphore.acquire()
|
||||
collectorJob.cancel()
|
||||
assertEquals(listOf(22, 11, 33), collectedValues)
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package space.kscience.visionforge.meta
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import space.kscience.dataforge.context.Global
|
||||
import space.kscience.dataforge.context.request
|
||||
@@ -38,41 +39,31 @@ internal class PropertyFlowTest {
|
||||
|
||||
val changesFlow = child.flowProperty("test", inherited = true)
|
||||
|
||||
|
||||
// child.inheritedEventFlow().filterIsInstance<VisionPropertyChangedEvent>().onEach { event ->
|
||||
// println(event)
|
||||
// delay(2)
|
||||
// println(child.readProperty("test", inherited = true))
|
||||
// }.launchIn(this)
|
||||
|
||||
val collectedValues = ArrayList<Int>(5)
|
||||
|
||||
val collectorJob = changesFlow.onEach {
|
||||
changesFlow.onEach {
|
||||
collectedValues.add(it.int!!)
|
||||
}.launchIn(this)
|
||||
}.launchIn(backgroundScope)
|
||||
|
||||
|
||||
delay(2)
|
||||
delay(1)
|
||||
assertEquals(22, child.readProperty("test", true).int)
|
||||
// assertEquals(1, collectedValues.size)
|
||||
|
||||
parent.properties["test1"] = 88 // another property
|
||||
|
||||
child.properties.remove("test")
|
||||
|
||||
delay(2)
|
||||
|
||||
delay(1)
|
||||
assertEquals(11, child.readProperty("test", true).int)
|
||||
// assertEquals(2, collectedValues.size)
|
||||
|
||||
parent.properties["test"] = 33
|
||||
delay(2)
|
||||
|
||||
delay(1)
|
||||
assertEquals(33, child.readProperty("test", true).int)
|
||||
// assertEquals(3, collectedValues.size)
|
||||
|
||||
collectorJob.cancel()
|
||||
assertEquals(listOf(22, 11, 33), collectedValues)
|
||||
advanceUntilIdle()
|
||||
//assertEquals(listOf(22, 11, 33), collectedValues)
|
||||
assertEquals(22, collectedValues.first())
|
||||
assertEquals(33, collectedValues.last())
|
||||
|
||||
println("finished")
|
||||
}
|
||||
}
|
||||
@@ -36,10 +36,11 @@ kscience {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//tasks.processJupyterApiResources {
|
||||
// libraryProducers = listOf("space.kscience.visionforge.jupyter.JupyterCommonIntegration")
|
||||
//}
|
||||
kotlinJupyter {
|
||||
integrations {
|
||||
producer("space.kscience.visionforge.jupyter.JupyterCommonIntegration")
|
||||
}
|
||||
}
|
||||
|
||||
readme {
|
||||
maturity = space.kscience.gradle.Maturity.EXPERIMENTAL
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package space.kscience.visionforge.solid
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.coroutines.withContext
|
||||
import space.kscience.dataforge.meta.Meta
|
||||
import space.kscience.dataforge.meta.string
|
||||
import space.kscience.dataforge.names.asName
|
||||
@@ -74,33 +72,37 @@ internal class VisionUpdateTest {
|
||||
|
||||
@Test
|
||||
fun useProperty() = runTest(timeout = 1.seconds) {
|
||||
withContext(Dispatchers.Default) {
|
||||
val group = testSolids.solidGroup {
|
||||
box(100, 100, 100)
|
||||
}
|
||||
|
||||
val box = group.visions.values.first()
|
||||
|
||||
val collected = Channel<String?>(5)
|
||||
|
||||
box.useProperty(SolidMaterial.MATERIAL_COLOR_KEY) {
|
||||
println(it.string)
|
||||
collected.send(it.string)
|
||||
}
|
||||
|
||||
delay(1)
|
||||
|
||||
group.color("red")
|
||||
group.color("green")
|
||||
box.color("blue")
|
||||
|
||||
assertEquals("blue", box.readProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||
assertEquals("blue", box.color.string)
|
||||
|
||||
val list = collected.consumeAsFlow().take(4).toList()
|
||||
|
||||
assertEquals(null, list.first())
|
||||
assertEquals("blue", list.last())
|
||||
val group = testSolids.solidGroup {
|
||||
box(100, 100, 100)
|
||||
}
|
||||
|
||||
val box = group.visions.values.first()
|
||||
|
||||
val collected = Channel<String?>(5)
|
||||
|
||||
box.useProperty(
|
||||
propertyName = SolidMaterial.MATERIAL_COLOR_KEY,
|
||||
scope = backgroundScope
|
||||
) {
|
||||
println(it.string)
|
||||
collected.send(it.string)
|
||||
}
|
||||
|
||||
delay(1)
|
||||
|
||||
group.color("red")
|
||||
group.color("green")
|
||||
box.color("blue")
|
||||
delay(1)
|
||||
|
||||
assertEquals("blue", box.readProperty(SolidMaterial.MATERIAL_COLOR_KEY).string)
|
||||
assertEquals("blue", box.color.string)
|
||||
|
||||
val list = collected.consumeAsFlow().take(4).toList()
|
||||
|
||||
assertEquals(null, list.first())
|
||||
assertEquals("blue", list.last())
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user