From b2e30c9f6d29109bb21f2e630a062febfddd08ad Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 28 Oct 2020 13:55:49 +0600 Subject: [PATCH 1/6] start 0.2.3 --- CHANGELOG.md | 2 ++ gradle.properties | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0c7930620e..cb038e88fdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +## 0.2.3 + ## 0.2.2 * `Repos` diff --git a/gradle.properties b/gradle.properties index 7103c62bf89..ed317cf9359 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,4 @@ github_release_plugin_version=2.2.12 uuidVersion=0.2.2 group=dev.inmo -version=0.2.2 +version=0.2.3 From e7df21e91aa9afa4a26b79e8f8a9a9f22e792234 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 28 Oct 2020 13:57:24 +0600 Subject: [PATCH 2/6] common js visibility and on screen extensions --- CHANGELOG.md | 5 ++ .../micro_utils/common/HtmlElementOnScreen.kt | 43 +++++++++++++++++ .../dev/inmo/micro_utils/common/Visibility.kt | 48 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HtmlElementOnScreen.kt create mode 100644 common/src/jsMain/kotlin/dev/inmo/micro_utils/common/Visibility.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index cb038e88fdc..365c09a5908 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## 0.2.3 +* `Common` + * `K/JS` + * Add several extensions for `Element` objects to detect that object is on screen viewport + * Add several extensions for `Element` objects to detect object visibility + ## 0.2.2 * `Repos` diff --git a/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HtmlElementOnScreen.kt b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HtmlElementOnScreen.kt new file mode 100644 index 00000000000..93a27d3812f --- /dev/null +++ b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/HtmlElementOnScreen.kt @@ -0,0 +1,43 @@ +package dev.inmo.micro_utils.common + +import kotlinx.browser.window +import org.w3c.dom.DOMRect +import org.w3c.dom.Element + +val DOMRect.isOnScreenByLeftEdge: Boolean + get() = left >= 0 && left <= window.innerWidth +inline val Element.isOnScreenByLeftEdge + get() = getBoundingClientRect().isOnScreenByLeftEdge + +val DOMRect.isOnScreenByRightEdge: Boolean + get() = right >= 0 && right <= window.innerWidth +inline val Element.isOnScreenByRightEdge + get() = getBoundingClientRect().isOnScreenByRightEdge + +internal val DOMRect.isOnScreenHorizontally: Boolean + get() = isOnScreenByLeftEdge || isOnScreenByRightEdge + + +val DOMRect.isOnScreenByTopEdge: Boolean + get() = top >= 0 && top <= window.innerHeight +inline val Element.isOnScreenByTopEdge + get() = getBoundingClientRect().isOnScreenByTopEdge + +val DOMRect.isOnScreenByBottomEdge: Boolean + get() = bottom >= 0 && bottom <= window.innerHeight +inline val Element.isOnScreenByBottomEdge + get() = getBoundingClientRect().isOnScreenByBottomEdge + +internal val DOMRect.isOnScreenVertically: Boolean + get() = isOnScreenByLeftEdge || isOnScreenByRightEdge + + +val DOMRect.isOnScreenFully: Boolean + get() = isOnScreenByLeftEdge && isOnScreenByTopEdge && isOnScreenByRightEdge && isOnScreenByBottomEdge +val Element.isOnScreenFully: Boolean + get() = getBoundingClientRect().isOnScreenFully + +val DOMRect.isOnScreen: Boolean + get() = isOnScreenFully || (isOnScreenHorizontally && isOnScreenVertically) +inline val Element.isOnScreen: Boolean + get() = getBoundingClientRect().isOnScreen diff --git a/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/Visibility.kt b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/Visibility.kt new file mode 100644 index 00000000000..d81fef3f27d --- /dev/null +++ b/common/src/jsMain/kotlin/dev/inmo/micro_utils/common/Visibility.kt @@ -0,0 +1,48 @@ +package dev.inmo.micro_utils.common + +import kotlinx.browser.window +import org.w3c.dom.Element +import org.w3c.dom.css.CSSStyleDeclaration + +sealed class Visibility +object Visible : Visibility() +object Invisible : Visibility() +object Gone : Visibility() + +var CSSStyleDeclaration.visibilityState: Visibility + get() = when { + display == "none" -> Gone + visibility == "hidden" -> Invisible + else -> Visible + } + set(value) { + when (value) { + Visible -> { + if (display == "none") { + display = "initial" + } + visibility = "visible" + } + Invisible -> { + if (display == "none") { + display = "initial" + } + visibility = "hidden" + } + Gone -> { + display = "none" + } + } + } +inline var Element.visibilityState: Visibility + get() = window.getComputedStyle(this).visibilityState + set(value) { + window.getComputedStyle(this).visibilityState = value + } + +inline val Element.isVisible: Boolean + get() = visibilityState == Visible +inline val Element.isInvisible: Boolean + get() = visibilityState == Invisible +inline val Element.isGone: Boolean + get() = visibilityState == Gone From 4019ad7d3171764699e3e7b7fac6d56ee7aac9ab Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 28 Oct 2020 13:58:23 +0600 Subject: [PATCH 3/6] update exposed and coroutines versions --- CHANGELOG.md | 3 +++ gradle.properties | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 365c09a5908..4d9b508e394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 0.2.3 +* `Versions` + * `Coroutines`: `1.3.9` -> `1.4.0` + * `Exposed`: `0.27.1` -> `0.28.1` * `Common` * `K/JS` * Add several extensions for `Element` objects to detect that object is on screen viewport diff --git a/gradle.properties b/gradle.properties index ed317cf9359..06be361b781 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,9 +5,9 @@ kotlin.incremental=true kotlin.incremental.js=true kotlin_version=1.4.10 -kotlin_coroutines_version=1.3.9 +kotlin_coroutines_version=1.4.0 kotlin_serialisation_core_version=1.0.0 -kotlin_exposed_version=0.27.1 +kotlin_exposed_version=0.28.1 ktor_version=1.4.1 From e2d1c5d6a1e1de99a02dc1d522bee067c3626c3b Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 28 Oct 2020 14:17:39 +0600 Subject: [PATCH 4/6] corotoutines actualization --- CHANGELOG.md | 2 + .../coroutines/BroadcastStateFlow.kt | 46 ++++++++++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d9b508e394..c94ef7aaeeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ * `K/JS` * Add several extensions for `Element` objects to detect that object is on screen viewport * Add several extensions for `Element` objects to detect object visibility +* `Coroutines` + * `BroadcastStateFlow` now use different strategy for getting of state and implements `replayCache` ## 0.2.2 diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt index f8d54aab376..48b22b4f431 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt @@ -5,29 +5,51 @@ import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.* +const val defaultBroadcastStateFlowReplayCacheSize = 1 + class BroadcastStateFlow internal constructor( parentFlow: Flow, - private val stateGetter: () -> T + initial: T, + replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize, + replayScope: CoroutineScope ) : StateFlow, Flow by parentFlow { + private val deque = ArrayDeque(1).also { + it.add(initial) + } + override val replayCache: List + get() = deque.toList() override val value: T - get() = stateGetter() -} + get() = deque.last() -fun BroadcastChannel.asStateFlow(value: T, scope: CoroutineScope): StateFlow = asFlow().let { - var state: T = value - it.onEach { state = it }.launchIn(scope) - BroadcastStateFlow(it) { - state + init { + if (replayCacheSize < 1) { + error("Replay cache size can't be less than 1, but was $replayCacheSize") + } + parentFlow.onEach { + deque.addLast(it) + if (deque.size > replayCacheSize) { + deque.removeFirst() + } + }.launchIn(replayScope) } } -fun BroadcastChannel.asStateFlow(scope: CoroutineScope): StateFlow = asStateFlow(null, scope) +fun BroadcastChannel.asStateFlow( + value: T, + scope: CoroutineScope, + replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize +): StateFlow = BroadcastStateFlow(asFlow(), value, replayCacheSize, scope) -fun broadcastStateFlow(initial: T, scope: CoroutineScope, channelSize: Int = Channel.BUFFERED) = BroadcastChannel( +fun BroadcastChannel.asStateFlow( + scope: CoroutineScope, + replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize +): StateFlow = asStateFlow(null, scope, replayCacheSize) + +fun broadcastStateFlow(initial: T, scope: CoroutineScope, channelSize: Int = Channel.BUFFERED, replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize) = BroadcastChannel( channelSize ).let { - it to it.asStateFlow(initial, scope) + it to it.asStateFlow(initial, scope, replayCacheSize) } -fun broadcastStateFlow(scope: CoroutineScope, channelSize: Int = Channel.BUFFERED) = broadcastStateFlow(null, scope, channelSize) +fun broadcastStateFlow(scope: CoroutineScope, channelSize: Int = Channel.BUFFERED, replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize) = broadcastStateFlow(null, scope, channelSize, replayCacheSize) From 4582e0c817427ff864ed174c8b7d5d822c90398a Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 28 Oct 2020 14:19:57 +0600 Subject: [PATCH 5/6] small refactoring of BroadcastStateFlow --- .../micro_utils/coroutines/BroadcastStateFlow.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt index 48b22b4f431..e2ad31a4af3 100644 --- a/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt +++ b/coroutines/src/commonMain/kotlin/dev/inmo/micro_utils/coroutines/BroadcastStateFlow.kt @@ -45,11 +45,19 @@ fun BroadcastChannel.asStateFlow( replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize ): StateFlow = asStateFlow(null, scope, replayCacheSize) -fun broadcastStateFlow(initial: T, scope: CoroutineScope, channelSize: Int = Channel.BUFFERED, replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize) = BroadcastChannel( +fun broadcastStateFlow( + initial: T, scope: CoroutineScope, + channelSize: Int = Channel.BUFFERED, + replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize +) = BroadcastChannel( channelSize ).let { it to it.asStateFlow(initial, scope, replayCacheSize) } -fun broadcastStateFlow(scope: CoroutineScope, channelSize: Int = Channel.BUFFERED, replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize) = broadcastStateFlow(null, scope, channelSize, replayCacheSize) +fun broadcastStateFlow( + scope: CoroutineScope, + channelSize: Int = Channel.BUFFERED, + replayCacheSize: Int = defaultBroadcastStateFlowReplayCacheSize +) = broadcastStateFlow(null, scope, channelSize, replayCacheSize) From 5b325a8ff94d3233b3933e9a929b1194382c40a1 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 28 Oct 2020 14:47:12 +0600 Subject: [PATCH 6/6] add dokka --- dokka/build.gradle | 88 +++++++++++++++++++++++++++++++++++++++++ dokka/gradle.properties | 3 ++ settings.gradle | 4 +- 3 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 dokka/build.gradle create mode 100644 dokka/gradle.properties diff --git a/dokka/build.gradle b/dokka/build.gradle new file mode 100644 index 00000000000..b619aa90912 --- /dev/null +++ b/dokka/build.gradle @@ -0,0 +1,88 @@ +buildscript { + repositories { + mavenLocal() + jcenter() + mavenCentral() + } + + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" + classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" + } +} + +plugins { + id "org.jetbrains.kotlin.multiplatform" + id "org.jetbrains.kotlin.plugin.serialization" + id "org.jetbrains.dokka" version "$dokka_version" +} + +repositories { + mavenLocal() + jcenter() + mavenCentral() +} + +kotlin { + jvm() + js(BOTH) { + browser() + nodejs() + } + + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib') + + project.parent.subprojects.forEach { + if ( + it != project + && it.hasProperty("kotlin") + && it.kotlin.sourceSets.any { it.name.contains("commonMain") } + ) { + api it + } + } + } + } + } +} + +private List findSourcesWithName(String... approximateNames) { + return parent.subprojects + .findAll { it != project && it.hasProperty("kotlin") } + .collectMany { it.kotlin.sourceSets } + .findAll { sourceSet -> + approximateNames.any { nameToFilter -> + sourceSet.name.contains(nameToFilter) + } + }.collect { it.kotlin } +} + +tasks.dokkaHtml { + dokkaSourceSets { + configureEach { + skipDeprecated.set(true) + + sourceLink { + localDirectory.set(file("./")) + remoteUrl.set(new URL("https://github.com/InsanusMokrassar/MicroUtils/blob/master/")) + remoteLineSuffix.set("#L") + } + } + + named("commonMain") { + sourceRoots.setFrom(findSourcesWithName("commonMain")) + } + + named("jsMain") { + sourceRoots.setFrom(findSourcesWithName("jsMain", "commonMain")) + } + + named("jvmMain") { + sourceRoots.setFrom(findSourcesWithName("jvmMain", "commonMain")) + } + } +} diff --git a/dokka/gradle.properties b/dokka/gradle.properties new file mode 100644 index 00000000000..55021b5f4e7 --- /dev/null +++ b/dokka/gradle.properties @@ -0,0 +1,3 @@ +dokka_version=1.4.0 + +org.gradle.jvmargs=-Xmx1024m diff --git a/settings.gradle b/settings.gradle index 54fb4ed3371..92804fc0013 100644 --- a/settings.gradle +++ b/settings.gradle @@ -16,7 +16,9 @@ String[] includes = [ ":ktor:server", ":ktor:common", ":ktor:client", - ":coroutines" + ":coroutines", + + ":dokka" ]