mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2025-09-17 14:29:24 +00:00
Compare commits
68 Commits
Author | SHA1 | Date | |
---|---|---|---|
b485d485ef | |||
0b3d445109 | |||
d7e48940bc | |||
1049eb0fe7 | |||
c871ef5635 | |||
7edfcb20c4 | |||
7a1438a2c0 | |||
2af8cba8cd | |||
27d74c0a62 | |||
f86d1bfe06 | |||
7cc5972ff7 | |||
3bbf978b00 | |||
ed36467600 | |||
dd0de327fc | |||
dccd3ce8fd | |||
fa45e7b696 | |||
57f009e8aa | |||
04b633a5ea | |||
20d42b05bb | |||
91ba50f1ff | |||
f4476c99f9 | |||
50f3f586ab | |||
36a2d7ec8e | |||
4890b5833e | |||
e20ab89688 | |||
e557ba8184 | |||
8540e21d5a | |||
76c04a8506 | |||
128632770e | |||
31e0800e81 | |||
00ca96eec8 | |||
077ef2c639 | |||
e3ea7be0e7 | |||
05fd1c2b14 | |||
affcffe270 | |||
62930231e4 | |||
ad651631ec | |||
cf1c8f13db | |||
9acc69b897 | |||
9bc7cbdb50 | |||
2ed8443e28 | |||
94f598c2b4 | |||
d83d30af06 | |||
284e763f0d | |||
3bfa172533 | |||
b5b1fd6d5f | |||
05e0d9b7d2 | |||
1ae1f8dee2 | |||
1bf479a0b7 | |||
9d04d49628 | |||
3de324519b | |||
4be90d0ea5 | |||
041f35ed6c | |||
9c463d0338 | |||
5ec0a46089 | |||
979d0ee4ca | |||
448686b399 | |||
|
0ff149a3d3 | ||
50a90d6e96 | |||
5f93706d91 | |||
39415550f5 | |||
|
4586ad65b5 | ||
8c5678e26f | |||
5dff373d5f | |||
e17868a085 | |||
97bb6d0936 | |||
|
54576d8dec | ||
282bb24c71 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.idea
|
||||
.vscode
|
||||
.kotlin
|
||||
out/*
|
||||
*.iml
|
||||
@@ -9,6 +10,7 @@ settings.xml
|
||||
.gradle/
|
||||
build/
|
||||
out/
|
||||
bin/
|
||||
|
||||
secret.gradle
|
||||
local.properties
|
||||
|
77
CHANGELOG.md
77
CHANGELOG.md
@@ -1,5 +1,82 @@
|
||||
# Changelog
|
||||
|
||||
## 0.26.4
|
||||
|
||||
* `Common`:
|
||||
* Add expect/actual `MPPFilePathSeparator`
|
||||
* Fix `FileName` realization to take care about system file path separator
|
||||
|
||||
## 0.26.3
|
||||
|
||||
* `Versions`:
|
||||
* `Kotlin`: `2.2.0` -> `2.2.10`
|
||||
* `KSP`: `2.2.0-2.0.2` -> `2.2.10-2.0.2`
|
||||
* `Android CoreKTX`: `1.16.0` -> `1.17.0`
|
||||
* `Android Fragment`: `1.8.8` -> `1.8.9`
|
||||
|
||||
## 0.26.2
|
||||
|
||||
* `Versions`:
|
||||
* `Ktor`: `3.2.2` -> `3.2.3`
|
||||
* `Okio`: `3.15.0` -> `3.16.0`
|
||||
* `Coroutines`:
|
||||
* Rename `SpecialMutableStateFlow` to `MutableRedeliverStateFlow`
|
||||
|
||||
## 0.26.1
|
||||
|
||||
* `Versions`:
|
||||
* `Compose`: `1.8.1` -> `1.8.2`
|
||||
* `Ktor`: `3.2.1` -> `3.2.2`
|
||||
* `Coroutines`:
|
||||
* Add opportunity to pass logger in subscribe async
|
||||
|
||||
## 0.26.0
|
||||
|
||||
**WARNING!!! SINCE THIS VERSION IF YOU WANT TO USE SOME OF KSP MODULES, SET `ksp.useKSP2=false` IN YOUR `gradle.properties`** (see [gh issue 2491](https://github.com/google/ksp/issues/2491))
|
||||
|
||||
* `Versions`:
|
||||
* `Kotlin`: `2.1.21` -> `2.2.0`
|
||||
* `Serialization`: `1.8.1` -> `1.9.0`
|
||||
* `KSLog`: `1.4.2` -> `1.5.0`
|
||||
* `Ktor`: `3.1.3` -> `3.2.1`
|
||||
* `Koin`: `4.0.4` -> `4.1.0`
|
||||
* `Okio`: `3.12.0` -> `3.15.0`
|
||||
* `KSP`: `2.1.20-1.0.31` -> `2.2.0-2.0.2`
|
||||
* `kotlin-poet`: `1.18.1` -> `2.2.0`
|
||||
|
||||
## 0.25.8
|
||||
|
||||
* `Pagination`:
|
||||
* `Compose`:
|
||||
* New function `rememberInfinityPagedComponentContext` to create `InfinityPagedComponentContext`
|
||||
* New variants of `InfinityPagedComponent` component
|
||||
|
||||
## 0.25.7
|
||||
|
||||
* `Versions`:
|
||||
* `Compose`: `1.8.0` -> `1.8.1`
|
||||
* `Xerial SQLite`: `3.49.1.0` -> `3.50.1.0`
|
||||
* `Okio`: `3.11.0` -> `3.12.0`
|
||||
* `Android AppCompat`: `1.7.0` -> `1.7.1`
|
||||
* `Android Fragment`: `1.8.6` -> `1.8.8`
|
||||
|
||||
## 0.25.6
|
||||
|
||||
* `Versions`:
|
||||
* `Kotlin`: `2.1.20` -> `2.1.21`
|
||||
* `KSLog`: `1.4.1` -> `1.4.2`
|
||||
* `Compose`: `1.7.3` -> `1.8.0`
|
||||
* `Okio`: `3.10.2` -> `3.11.0`
|
||||
|
||||
## 0.25.5
|
||||
|
||||
* `Versions`:
|
||||
* `Exposed`: `0.60.0` -> `0.61.0`
|
||||
* `Serialization`: `1.8.0` -> `1.8.1`
|
||||
* `Coroutines`: `1.10.1` -> `1.10.2`
|
||||
* `Common`:
|
||||
* Small performance optimization of `MutableMap.applyDiff`
|
||||
|
||||
## 0.25.4
|
||||
|
||||
* `Versions`:
|
||||
|
48
README.md
48
README.md
@@ -35,3 +35,51 @@ Most of complex modules are built with next hierarchy:
|
||||
* `common` part contains routes which are common for clients and servers
|
||||
* `client` submodule contains clients which are usually using `UnifiedRequester` to make requests using routes from `ktor/common` module and some internal logic of requests
|
||||
* `server` submodule (in most cases `JVM`-only) contains some extensions for `Route` instances which usually will give opportunity to proxy internet requests from `ktor/client` realization to some proxy object
|
||||
|
||||
## Gradle Templates
|
||||
|
||||
All templates can be used by applying them in your project's build.gradle files using the `apply from` directive. For example:
|
||||
|
||||
```gradle
|
||||
apply from: "$defaultProject"
|
||||
```
|
||||
|
||||
In the sample has been used `defaultProject.gradle` as a basic template.
|
||||
|
||||
The project includes a collection of Gradle templates to simplify project setup and configuration. These templates are located in the `gradle/templates` directory and can be used to quickly set up different types of projects:
|
||||
|
||||
### Project Setup Templates
|
||||
|
||||
* `defaultProject.gradle` (usage `apply from: "$defaultProject"`) - Basic project configuration
|
||||
* `defaultProjectWithSerialization.gradle` (usage `apply from: "$defaultProjectWithSerialization"`) - Project configuration with Kotlin Serialization support
|
||||
* `mppJavaProject.gradle` (usage `apply from: "$mppJavaProject"`) - Multiplatform project with Java support
|
||||
* `mppAndroidProject.gradle` (usage `apply from: "$mppAndroidProject"`) - Multiplatform project with Android support
|
||||
|
||||
### Multiplatform Configuration Templates
|
||||
|
||||
* `enableMPPAndroid.gradle` (usage `apply from: "$enableMPPAndroid"`) - Enable Android target in multiplatform project
|
||||
* `enableMPPJs.gradle` (usage `apply from: "$enableMPPJs"`) - Enable JavaScript target in multiplatform project
|
||||
* `enableMPPJvm.gradle` (usage `apply from: "$enableMPPJvm"`) - Enable JVM target in multiplatform project
|
||||
* `enableMPPNativeArm64.gradle` (usage `apply from: "$enableMPPNativeArm64"`) - Enable ARM64 native target
|
||||
* `enableMPPNativeX64.gradle` (usage `apply from: "$enableMPPNativeX64"`) - Enable x64 native target
|
||||
* `enableMPPWasmJs.gradle` (usage `apply from: "$enableMPPWasmJs"`) - Enable WebAssembly JavaScript target
|
||||
|
||||
### Compose Integration Templates
|
||||
|
||||
* `addCompose.gradle` (usage `apply from: "$addCompose"`) - Basic Compose configuration
|
||||
* `addComposeForAndroid.gradle` (usage `apply from: "$addComposeForAndroid"`) - Compose configuration for Android
|
||||
* `addComposeForDesktop.gradle` (usage `apply from: "$addComposeForDesktop"`) - Compose configuration for Desktop
|
||||
* `addComposeForJs.gradle` (usage `apply from: "$addComposeForJs"`) - Compose configuration for JavaScript
|
||||
|
||||
### Publishing Templates
|
||||
|
||||
* `publish.gradle` (usage `apply from: "$publish"`) - General publishing configuration
|
||||
* `publish_jvm.gradle` (usage `apply from: "$publish_jvm"`) - JVM-specific publishing configuration
|
||||
* `publish.kpsb` and `publish_jvm.kpsb` (usage `apply from: "$publish_kpsb"` and `apply from: "$publish_jvm_kpsb"`) - Publishing configuration for Kotlin Multiplatform and JVM
|
||||
|
||||
### Combined Project Templates
|
||||
|
||||
* `mppJvmJsWasmJsLinuxMingwProject.gradle` (usage `apply from: "$mppJvmJsWasmJsLinuxMingwProject"`) - Multiplatform project for JVM, JS, Wasm, Linux, and MinGW
|
||||
* `mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project.gradle` (usage `apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"`) - Multiplatform project with additional Android and ARM64 support
|
||||
* `mppComposeJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project.gradle` (usage `apply from: "$mppComposeJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"`) - Multiplatform project with Compose support
|
||||
* `mppProjectWithSerializationAndCompose.gradle` (usage `apply from: "$mppProjectWithSerializationAndCompose"`) - Multiplatform project with both Serialization and Compose support
|
||||
|
17
build.gradle
17
build.gradle
@@ -19,15 +19,30 @@ buildscript {
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.versions)
|
||||
alias(libs.plugins.nmcp.aggregation)
|
||||
}
|
||||
|
||||
|
||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||
nmcpAggregation {
|
||||
centralPortal {
|
||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
validationTimeout = Duration.ofHours(4)
|
||||
publishingType = System.getenv('PUBLISHING_TYPE') != "" ? System.getenv('PUBLISHING_TYPE') : "USER_MANAGED"
|
||||
}
|
||||
|
||||
publishAllProjectsProbablyBreakingProjectIsolation()
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
google()
|
||||
maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
|
||||
maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -4,4 +4,4 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
@@ -29,5 +29,12 @@ kotlin {
|
||||
api libs.okio
|
||||
}
|
||||
}
|
||||
|
||||
wasmJsMain {
|
||||
dependencies {
|
||||
api libs.kotlinx.browser
|
||||
api libs.kt.coroutines
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,7 @@ plugins {
|
||||
alias(libs.plugins.kt.jb.compose)
|
||||
}
|
||||
|
||||
apply from: "$mppComposeJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppComposeJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -2,11 +2,9 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.runComposeUiTest
|
||||
import dev.inmo.micro_utils.common.compose.LoadableComponent
|
||||
import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import dev.inmo.micro_utils.coroutines.MutableRedeliverStateFlow
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.firstOrNull
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
@@ -16,8 +14,8 @@ class LoadableComponentTests {
|
||||
@Test
|
||||
@TestOnly
|
||||
fun testSimpleLoad() = runComposeUiTest {
|
||||
val loadingFlow = SpecialMutableStateFlow<Int>(0)
|
||||
val loadedFlow = SpecialMutableStateFlow<Int>(0)
|
||||
val loadingFlow = MutableRedeliverStateFlow<Int>(0)
|
||||
val loadedFlow = MutableRedeliverStateFlow<Int>(0)
|
||||
setContent {
|
||||
LoadableComponent<Int>({
|
||||
loadingFlow.filter { it == 1 }.first()
|
||||
|
@@ -7,7 +7,7 @@ import kotlin.jvm.JvmInline
|
||||
@JvmInline
|
||||
value class FileName(val string: String) {
|
||||
val name: String
|
||||
get() = withoutSlashAtTheEnd.takeLastWhile { it != '/' }
|
||||
get() = withoutSlashAtTheEnd.takeLastWhile { it != MPPFilePathSeparator }
|
||||
val extension: String
|
||||
get() = name.takeLastWhile { it != '.' }
|
||||
val nameWithoutExtension: String
|
||||
@@ -18,7 +18,7 @@ value class FileName(val string: String) {
|
||||
} ?: filename
|
||||
}
|
||||
val withoutSlashAtTheEnd: String
|
||||
get() = string.dropLastWhile { it == '/' }
|
||||
get() = string.dropLastWhile { it == MPPFilePathSeparator }
|
||||
override fun toString(): String = string
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ value class FileName(val string: String) {
|
||||
expect class MPPFile
|
||||
|
||||
expect val MPPFile.filename: FileName
|
||||
expect val MPPFilePathSeparator: Char
|
||||
expect val MPPFile.filesize: Long
|
||||
expect val MPPFile.bytesAllocatorSync: ByteArrayAllocator
|
||||
expect val MPPFile.bytesAllocator: SuspendByteArrayAllocator
|
||||
|
@@ -82,13 +82,11 @@ fun <K, V> MutableMap<K, V>.applyDiff(
|
||||
mapDiff: MapDiff<K, V>
|
||||
) {
|
||||
mapDiff.apply {
|
||||
removed.keys.forEach { remove(it) }
|
||||
keys.removeAll(removed.keys)
|
||||
changed.forEach { (k, oldNew) ->
|
||||
put(k, oldNew.second)
|
||||
}
|
||||
added.forEach { (k, new) ->
|
||||
put(k, new)
|
||||
}
|
||||
putAll(added)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,6 +35,10 @@ private suspend fun MPPFile.dirtyReadBytes(): ByteArray = readBytesPromise().awa
|
||||
*/
|
||||
actual val MPPFile.filename: FileName
|
||||
get() = FileName(name)
|
||||
|
||||
actual val MPPFilePathSeparator: Char
|
||||
get() = '/'
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
|
@@ -14,6 +14,10 @@ actual typealias MPPFile = File
|
||||
*/
|
||||
actual val MPPFile.filename: FileName
|
||||
get() = FileName(name)
|
||||
|
||||
actual val MPPFilePathSeparator: Char
|
||||
get() = File.separatorChar
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
|
@@ -11,6 +11,10 @@ actual typealias MPPFile = Path
|
||||
*/
|
||||
actual val MPPFile.filename: FileName
|
||||
get() = FileName(toString())
|
||||
|
||||
|
||||
actual val MPPFilePathSeparator: Char = Path.DIRECTORY_SEPARATOR.first()
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
|
@@ -0,0 +1,15 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import org.khronos.webgl.*
|
||||
|
||||
fun DataView.toByteArray() = ByteArray(this.byteLength) {
|
||||
getInt8(it)
|
||||
}
|
||||
|
||||
fun ArrayBuffer.toByteArray() = Int8Array(this).toByteArray()
|
||||
|
||||
fun ByteArray.toDataView() = DataView(ArrayBuffer(size)).also {
|
||||
forEachIndexed { i, byte -> it.setInt8(i, byte) }
|
||||
}
|
||||
|
||||
fun ByteArray.toArrayBuffer() = toDataView().buffer
|
@@ -0,0 +1,13 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.window
|
||||
|
||||
fun copyToClipboard(text: String): Boolean {
|
||||
return runCatching {
|
||||
window.navigator.clipboard.writeText(
|
||||
text
|
||||
)
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}.isSuccess
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.window
|
||||
import kotlinx.coroutines.await
|
||||
import org.w3c.fetch.Response
|
||||
import org.w3c.files.Blob
|
||||
import org.w3c.files.BlobPropertyBag
|
||||
|
||||
external class ClipboardItem(data: JsAny?) : JsAny
|
||||
|
||||
fun createBlobData(blob: Blob): JsAny = js("""({[blob.type]: blob})""")
|
||||
|
||||
inline fun Blob.convertToClipboardItem(): ClipboardItem {
|
||||
return ClipboardItem(createBlobData(this))
|
||||
}
|
||||
|
||||
suspend fun copyImageURLToClipboard(imageUrl: String): Boolean {
|
||||
return runCatching {
|
||||
val response = window.fetch(imageUrl).await<Response>()
|
||||
val blob = response.blob().await<Blob>()
|
||||
val data = arrayOf(
|
||||
Blob(
|
||||
arrayOf(blob).toJsArray().unsafeCast(),
|
||||
BlobPropertyBag("image/png")
|
||||
).convertToClipboardItem()
|
||||
).toJsArray()
|
||||
window.navigator.clipboard.write(data.unsafeCast())
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}.isSuccess
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.document
|
||||
import org.w3c.dom.*
|
||||
|
||||
private fun createMutationObserverInit(childList: Boolean, subtree: Boolean): JsAny = js("({childList, subtree})")
|
||||
|
||||
fun Node.onRemoved(block: () -> Unit): MutationObserver {
|
||||
lateinit var observer: MutationObserver
|
||||
|
||||
observer = MutationObserver { _, _ ->
|
||||
fun checkIfRemoved(node: Node): Boolean {
|
||||
return node.parentNode != document && (node.parentNode ?.let { checkIfRemoved(it) } ?: true)
|
||||
}
|
||||
|
||||
if (checkIfRemoved(this)) {
|
||||
observer.disconnect()
|
||||
block()
|
||||
}
|
||||
}
|
||||
|
||||
observer.observe(document, createMutationObserverInit(childList = true, subtree = true).unsafeCast())
|
||||
return observer
|
||||
}
|
||||
|
||||
fun Element.onVisibilityChanged(block: IntersectionObserverEntry.(Float, IntersectionObserver) -> Unit): IntersectionObserver {
|
||||
var previousIntersectionRatio = -1f
|
||||
val observer = IntersectionObserver { entries, observer ->
|
||||
entries.toArray().forEach {
|
||||
if (previousIntersectionRatio.toDouble() != it.intersectionRatio.toDouble()) {
|
||||
previousIntersectionRatio = it.intersectionRatio.toDouble().toFloat()
|
||||
it.block(previousIntersectionRatio, observer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
observer.observe(this)
|
||||
return observer
|
||||
}
|
||||
|
||||
fun Element.onVisible(block: Element.(IntersectionObserver) -> Unit) {
|
||||
var previous = -1f
|
||||
onVisibilityChanged { intersectionRatio, observer ->
|
||||
if (previous != intersectionRatio) {
|
||||
if (intersectionRatio > 0 && previous == 0f) {
|
||||
block(observer)
|
||||
}
|
||||
previous = intersectionRatio
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Element.onInvisible(block: Element.(IntersectionObserver) -> Unit): IntersectionObserver {
|
||||
var previous = -1f
|
||||
return onVisibilityChanged { intersectionRatio, observer ->
|
||||
if (previous != intersectionRatio) {
|
||||
if (intersectionRatio == 0f && previous != 0f) {
|
||||
block(observer)
|
||||
}
|
||||
previous = intersectionRatio
|
||||
}
|
||||
}
|
||||
}
|
@@ -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
|
@@ -0,0 +1,127 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import org.w3c.dom.DOMRectReadOnly
|
||||
import org.w3c.dom.Element
|
||||
|
||||
external interface IntersectionObserverOptions: JsAny {
|
||||
/**
|
||||
* An Element or Document object which is an ancestor of the intended target, whose bounding rectangle will be
|
||||
* considered the viewport. Any part of the target not visible in the visible area of the root is not considered
|
||||
* visible.
|
||||
*/
|
||||
var root: Element?
|
||||
|
||||
/**
|
||||
* A string which specifies a set of offsets to add to the root's bounding_box when calculating intersections,
|
||||
* effectively shrinking or growing the root for calculation purposes. The syntax is approximately the same as that
|
||||
* for the CSS margin property; see The root element and root margin in Intersection Observer API for more
|
||||
* information on how the margin works and the syntax. The default is "0px 0px 0px 0px".
|
||||
*/
|
||||
var rootMargin: String?
|
||||
|
||||
/**
|
||||
* Either a single number or an array of numbers between 0.0 and 1.0, specifying a ratio of intersection area to
|
||||
* total bounding box area for the observed target. A value of 0.0 means that even a single visible pixel counts as
|
||||
* the target being visible. 1.0 means that the entire target element is visible. See Thresholds in Intersection
|
||||
* Observer API for a more in-depth description of how thresholds are used. The default is a threshold of 0.0.
|
||||
*/
|
||||
var threshold: JsArray<JsNumber>?
|
||||
}
|
||||
|
||||
private fun createEmptyJsObject(): JsAny = js("{}")
|
||||
|
||||
fun IntersectionObserverOptions(
|
||||
block: IntersectionObserverOptions.() -> Unit = {}
|
||||
): IntersectionObserverOptions = createEmptyJsObject().unsafeCast<IntersectionObserverOptions>().apply(block)
|
||||
|
||||
external interface IntersectionObserverEntry: JsAny {
|
||||
/**
|
||||
* Returns the bounds rectangle of the target element as a DOMRectReadOnly. The bounds are computed as described in
|
||||
* the documentation for Element.getBoundingClientRect().
|
||||
*/
|
||||
val boundingClientRect: DOMRectReadOnly
|
||||
|
||||
/**
|
||||
* Returns the ratio of the intersectionRect to the boundingClientRect.
|
||||
*/
|
||||
val intersectionRatio: JsNumber
|
||||
|
||||
/**
|
||||
* Returns a DOMRectReadOnly representing the target's visible area.
|
||||
*/
|
||||
val intersectionRect: DOMRectReadOnly
|
||||
|
||||
/**
|
||||
* A Boolean value which is true if the target element intersects with the intersection observer's root. If this is
|
||||
* true, then, the IntersectionObserverEntry describes a transition into a state of intersection; if it's false,
|
||||
* then you know the transition is from intersecting to not-intersecting.
|
||||
*/
|
||||
val isIntersecting: Boolean
|
||||
|
||||
/**
|
||||
* Returns a DOMRectReadOnly for the intersection observer's root.
|
||||
*/
|
||||
val rootBounds: DOMRectReadOnly
|
||||
|
||||
/**
|
||||
* The Element whose intersection with the root changed.
|
||||
*/
|
||||
val target: Element
|
||||
|
||||
/**
|
||||
* A DOMHighResTimeStamp indicating the time at which the intersection was recorded, relative to the
|
||||
* IntersectionObserver's time origin.
|
||||
*/
|
||||
val time: Double
|
||||
}
|
||||
|
||||
typealias IntersectionObserverCallback = (entries: JsArray<IntersectionObserverEntry>, observer: IntersectionObserver) -> Unit
|
||||
|
||||
/**
|
||||
* This is just an implementation from [this commentary](https://youtrack.jetbrains.com/issue/KT-43157#focus=Comments-27-4498582.0-0)
|
||||
* of Kotlin JS issue related to the absence of [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver)
|
||||
*/
|
||||
external class IntersectionObserver(callback: IntersectionObserverCallback): JsAny {
|
||||
constructor(callback: IntersectionObserverCallback, options: IntersectionObserverOptions)
|
||||
|
||||
/**
|
||||
* The Element or Document whose bounds are used as the bounding box when testing for intersection. If no root value
|
||||
* was passed to the constructor or its value is null, the top-level document's viewport is used.
|
||||
*/
|
||||
val root: Element
|
||||
|
||||
/**
|
||||
* An offset rectangle applied to the root's bounding box when calculating intersections, effectively shrinking or
|
||||
* growing the root for calculation purposes. The value returned by this property may not be the same as the one
|
||||
* specified when calling the constructor as it may be changed to match internal requirements. Each offset can be
|
||||
* expressed in pixels (px) or as a percentage (%). The default is "0px 0px 0px 0px".
|
||||
*/
|
||||
val rootMargin: String
|
||||
|
||||
/**
|
||||
* A list of thresholds, sorted in increasing numeric order, where each threshold is a ratio of intersection area to
|
||||
* bounding box area of an observed target. Notifications for a target are generated when any of the thresholds are
|
||||
* crossed for that target. If no value was passed to the constructor, 0 is used.
|
||||
*/
|
||||
val thresholds: JsArray<JsNumber>
|
||||
|
||||
/**
|
||||
* Stops the IntersectionObserver object from observing any target.
|
||||
*/
|
||||
fun disconnect()
|
||||
|
||||
/**
|
||||
* Tells the IntersectionObserver a target element to observe.
|
||||
*/
|
||||
fun observe(targetElement: Element)
|
||||
|
||||
/**
|
||||
* Returns an array of IntersectionObserverEntry objects for all observed targets.
|
||||
*/
|
||||
fun takeRecords(): JsArray<IntersectionObserverEntry>
|
||||
|
||||
/**
|
||||
* Tells the IntersectionObserver to stop observing a particular target element.
|
||||
*/
|
||||
fun unobserve(targetElement: Element)
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import org.w3c.dom.Element
|
||||
|
||||
inline val Element.isOverflowWidth
|
||||
get() = scrollWidth > clientWidth
|
||||
|
||||
inline val Element.isOverflowHeight
|
||||
get() = scrollHeight > clientHeight
|
||||
|
||||
inline val Element.isOverflow
|
||||
get() = isOverflowHeight || isOverflowWidth
|
@@ -0,0 +1,62 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.coroutines.await
|
||||
import org.khronos.webgl.ArrayBuffer
|
||||
import org.w3c.dom.ErrorEvent
|
||||
import org.w3c.files.*
|
||||
import kotlin.js.Promise
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
actual typealias MPPFile = File
|
||||
|
||||
private fun createJsError(message: String): JsAny = js("Error(message)")
|
||||
|
||||
fun MPPFile.readBytesPromise() = Promise { success, failure ->
|
||||
val reader = FileReader()
|
||||
reader.onload = {
|
||||
success((reader.result as ArrayBuffer))
|
||||
}
|
||||
reader.onerror = {
|
||||
val message = (it as ErrorEvent).message
|
||||
failure(createJsError(message))
|
||||
}
|
||||
reader.readAsArrayBuffer(this)
|
||||
}
|
||||
|
||||
fun MPPFile.readBytes(): ByteArray {
|
||||
val reader = FileReaderSync()
|
||||
return reader.readAsArrayBuffer(this).toByteArray()
|
||||
}
|
||||
|
||||
private suspend fun MPPFile.dirtyReadBytes(): ByteArray = readBytesPromise().await<ArrayBuffer>().toByteArray()
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
actual val MPPFile.filename: FileName
|
||||
get() = FileName(name)
|
||||
|
||||
actual val MPPFilePathSeparator: Char
|
||||
get() = '/'
|
||||
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
actual val MPPFile.filesize: Long
|
||||
get() = jsNumberToBigInt(size).toLong()
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
@Warning("That is not optimized version of bytes allocator. Use asyncBytesAllocator everywhere you can")
|
||||
actual val MPPFile.bytesAllocatorSync: ByteArrayAllocator
|
||||
get() = ::readBytes
|
||||
/**
|
||||
* @suppress
|
||||
*/
|
||||
@Warning("That is not optimized version of bytes allocator. Use asyncBytesAllocator everywhere you can")
|
||||
actual val MPPFile.bytesAllocator: SuspendByteArrayAllocator
|
||||
get() = ::dirtyReadBytes
|
||||
|
||||
private fun jsNumberToBigInt(number: JsNumber): JsBigInt = js("BigInt(number)")
|
@@ -0,0 +1,41 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.document
|
||||
import org.w3c.dom.*
|
||||
import org.w3c.dom.events.Event
|
||||
import org.w3c.dom.events.EventListener
|
||||
|
||||
private fun createEventListener(listener: (Event) -> Unit): JsAny = js("({handleEvent: listener})")
|
||||
|
||||
fun Element.onActionOutside(type: String, options: AddEventListenerOptions? = null, callback: (Event) -> Unit): EventListener {
|
||||
lateinit var observer: MutationObserver
|
||||
val listener = createEventListener { it: Event ->
|
||||
val elementsToCheck = mutableListOf(this@onActionOutside)
|
||||
while (it.target != this@onActionOutside && elementsToCheck.isNotEmpty()) {
|
||||
val childrenGettingElement = elementsToCheck.removeFirst()
|
||||
for (i in 0 until childrenGettingElement.childElementCount) {
|
||||
elementsToCheck.add(childrenGettingElement.children[i] ?: continue)
|
||||
}
|
||||
}
|
||||
if (elementsToCheck.isEmpty()) {
|
||||
callback(it)
|
||||
}
|
||||
}.unsafeCast<EventListener>()
|
||||
|
||||
if (options == null) {
|
||||
document.addEventListener(type, listener)
|
||||
} else {
|
||||
document.addEventListener(type, listener, options)
|
||||
}
|
||||
observer = onRemoved {
|
||||
if (options == null) {
|
||||
document.removeEventListener(type, listener)
|
||||
} else {
|
||||
document.removeEventListener(type, listener, options)
|
||||
}
|
||||
observer.disconnect()
|
||||
}
|
||||
return listener
|
||||
}
|
||||
|
||||
fun Element.onClickOutside(options: AddEventListenerOptions? = null, callback: (Event) -> Unit) = onActionOutside("click", options, callback)
|
@@ -0,0 +1,8 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.window
|
||||
|
||||
fun openLink(link: String, target: String = "_blank", features: String = "") {
|
||||
window.open(link, target, features) ?.focus()
|
||||
}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import org.w3c.dom.*
|
||||
|
||||
external class ResizeObserver(
|
||||
callback: (JsArray<ResizeObserverEntry>, ResizeObserver) -> Unit
|
||||
): JsAny {
|
||||
fun observe(target: Element, options: JsAny = definedExternally)
|
||||
|
||||
fun unobserve(target: Element)
|
||||
|
||||
fun disconnect()
|
||||
}
|
||||
|
||||
private fun createObserveOptions(jsBox: JsString?): JsAny = js("({box: jsBox})")
|
||||
|
||||
external interface ResizeObserverSize: JsAny {
|
||||
val blockSize: Float
|
||||
val inlineSize: Float
|
||||
}
|
||||
|
||||
external interface ResizeObserverEntry: JsAny {
|
||||
val borderBoxSize: JsArray<ResizeObserverSize>
|
||||
val contentBoxSize: JsArray<ResizeObserverSize>
|
||||
val devicePixelContentBoxSize: JsArray<ResizeObserverSize>
|
||||
val contentRect: DOMRectReadOnly
|
||||
val target: Element
|
||||
}
|
||||
|
||||
fun ResizeObserver.observe(target: Element, options: ResizeObserverObserveOptions) = observe(
|
||||
target,
|
||||
createObserveOptions(options.box?.name?.toJsString())
|
||||
)
|
||||
|
||||
class ResizeObserverObserveOptions(
|
||||
val box: Box? = null
|
||||
) {
|
||||
sealed interface Box {
|
||||
val name: String
|
||||
|
||||
object Content : Box {
|
||||
override val name: String
|
||||
get() = "content-box"
|
||||
}
|
||||
|
||||
object Border : Box {
|
||||
override val name: String
|
||||
get() = "border-box"
|
||||
}
|
||||
|
||||
object DevicePixelContent : Box {
|
||||
override val name: String
|
||||
get() = "device-pixel-content-box"
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.document
|
||||
import kotlinx.dom.createElement
|
||||
import org.w3c.dom.HTMLElement
|
||||
import org.w3c.dom.HTMLInputElement
|
||||
import org.w3c.files.get
|
||||
|
||||
fun selectFile(
|
||||
inputSetup: (HTMLInputElement) -> Unit = {},
|
||||
onFailure: (Throwable) -> Unit = {},
|
||||
onFile: (MPPFile) -> Unit
|
||||
) {
|
||||
(document.createElement("input") {
|
||||
(this as HTMLInputElement).apply {
|
||||
type = "file"
|
||||
onchange = {
|
||||
runCatching {
|
||||
files ?.get(0) ?: error("File must not be null")
|
||||
}.onSuccess {
|
||||
onFile(it)
|
||||
}.onFailure {
|
||||
onFailure(it)
|
||||
}
|
||||
}
|
||||
inputSetup(this)
|
||||
}
|
||||
} as HTMLElement).click()
|
||||
}
|
||||
|
@@ -0,0 +1,14 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
import kotlinx.browser.document
|
||||
import org.w3c.dom.HTMLAnchorElement
|
||||
|
||||
fun triggerDownloadFile(filename: String, fileLink: String) {
|
||||
val hiddenElement = document.createElement("a") as HTMLAnchorElement
|
||||
|
||||
hiddenElement.href = fileLink
|
||||
hiddenElement.target = "_blank"
|
||||
hiddenElement.download = filename
|
||||
hiddenElement.click()
|
||||
}
|
||||
|
@@ -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
|
||||
data object Visible : Visibility()
|
||||
data object Invisible : Visibility()
|
||||
data 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
|
@@ -0,0 +1,11 @@
|
||||
package dev.inmo.micro_utils.common
|
||||
|
||||
actual fun Float.fixed(signs: Int): Float {
|
||||
return jsToFixed(toDouble().toJsNumber(), signs.coerceIn(FixedSignsRange)).toString().toFloat()
|
||||
}
|
||||
|
||||
actual fun Double.fixed(signs: Int): Double {
|
||||
return jsToFixed(toJsNumber(), signs.coerceIn(FixedSignsRange)).toString().toDouble()
|
||||
}
|
||||
|
||||
private fun jsToFixed(number: JsNumber, signs: Int): JsString = js("number.toFixed(signs)")
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -6,7 +6,7 @@ plugins {
|
||||
alias(libs.plugins.kt.jb.compose)
|
||||
}
|
||||
|
||||
apply from: "$mppComposeJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppComposeJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -3,7 +3,7 @@ package dev.inmo.micro_utils.coroutines.compose
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.remember
|
||||
import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
|
||||
import dev.inmo.micro_utils.coroutines.MutableRedeliverStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
@@ -16,7 +16,7 @@ import org.jetbrains.compose.web.css.StyleSheet
|
||||
* to add `Style(stylesheet)` on every compose function call
|
||||
*/
|
||||
object StyleSheetsAggregator {
|
||||
private val _stylesFlow = SpecialMutableStateFlow<Set<CSSRulesHolder>>(emptySet())
|
||||
private val _stylesFlow = MutableRedeliverStateFlow<Set<CSSRulesHolder>>(emptySet())
|
||||
val stylesFlow: StateFlow<Set<CSSRulesHolder>> = _stylesFlow.asStateFlow()
|
||||
|
||||
@Composable
|
||||
|
@@ -2,7 +2,7 @@ import androidx.compose.material.Button
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.ui.test.*
|
||||
import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
|
||||
import dev.inmo.micro_utils.coroutines.MutableRedeliverStateFlow
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import kotlin.test.Test
|
||||
|
||||
@@ -11,7 +11,7 @@ class FlowStateTests {
|
||||
@Test
|
||||
@TestOnly
|
||||
fun simpleTest() = runComposeUiTest {
|
||||
val flowState = SpecialMutableStateFlow(0)
|
||||
val flowState = MutableRedeliverStateFlow(0)
|
||||
setContent {
|
||||
Button({ flowState.value++ }) { Text("Click") }
|
||||
Text(flowState.collectAsState().value.toString())
|
||||
|
@@ -4,6 +4,15 @@ import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
|
||||
/**
|
||||
* Creates an actor using coroutines that processes incoming messages of type [T].
|
||||
* An actor is a computational entity that processes messages sequentially in response to messages it receives.
|
||||
*
|
||||
* @param T The type of messages this actor will process
|
||||
* @param channelCapacity The capacity of the [Channel] used for message delibery to the actor. Defaults to [Channel.UNLIMITED]
|
||||
* @param block The processing logic to be applied to each received message
|
||||
* @return A [Channel] that can be used to send messages to this actor or cancel it
|
||||
*/
|
||||
fun <T> CoroutineScope.actor(
|
||||
channelCapacity: Int = Channel.UNLIMITED,
|
||||
block: suspend (T) -> Unit
|
||||
@@ -13,6 +22,16 @@ fun <T> CoroutineScope.actor(
|
||||
return channel
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a safe actor that catches and handles exceptions during message processing.
|
||||
* This variant wraps the processing logic in a safety mechanism to prevent actor failure due to exceptions.
|
||||
*
|
||||
* @param T The type of messages this actor will process
|
||||
* @param channelCapacity The capacity of the [Channel] used for message processing. Defaults to [Channel.UNLIMITED]
|
||||
* @param onException Handler for exceptions that occur during message processing. Defaults to [defaultSafelyExceptionHandler]
|
||||
* @param block The processing logic to be applied to each received message
|
||||
* @return A [Channel] that can be used to send messages to this actor
|
||||
*/
|
||||
inline fun <T> CoroutineScope.safeActor(
|
||||
channelCapacity: Int = Channel.UNLIMITED,
|
||||
noinline onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import dev.inmo.kslog.common.KSLog
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.consumeAsFlow
|
||||
@@ -7,13 +8,15 @@ import kotlinx.coroutines.flow.consumeAsFlow
|
||||
fun <T> CoroutineScope.actorAsync(
|
||||
channelCapacity: Int = Channel.UNLIMITED,
|
||||
markerFactory: suspend (T) -> Any? = { null },
|
||||
logger: KSLog = KSLog,
|
||||
block: suspend (T) -> Unit
|
||||
): Channel<T> {
|
||||
val channel = Channel<T>(channelCapacity)
|
||||
channel.consumeAsFlow().subscribeAsync(this, markerFactory, block)
|
||||
channel.consumeAsFlow().subscribeAsync(this, markerFactory, logger, block)
|
||||
return channel
|
||||
}
|
||||
|
||||
@Deprecated("Use standard actosAsync instead", ReplaceWith("actorAsync(channelCapacity, markerFactory, block = block)", "dev.inmo.micro_utils.coroutines.actorAsync"))
|
||||
inline fun <T> CoroutineScope.safeActorAsync(
|
||||
channelCapacity: Int = Channel.UNLIMITED,
|
||||
noinline onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler,
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import dev.inmo.kslog.common.KSLog
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.*
|
||||
import kotlinx.coroutines.flow.*
|
||||
@@ -8,6 +9,7 @@ import kotlinx.coroutines.sync.withLock
|
||||
|
||||
private class SubscribeAsyncReceiver<T>(
|
||||
val scope: CoroutineScope,
|
||||
val logger: KSLog,
|
||||
output: suspend SubscribeAsyncReceiver<T>.(T) -> Unit
|
||||
) {
|
||||
private val dataChannel: Channel<T> = Channel(Channel.UNLIMITED)
|
||||
@@ -15,7 +17,7 @@ private class SubscribeAsyncReceiver<T>(
|
||||
get() = dataChannel
|
||||
|
||||
init {
|
||||
scope.launchLoggingDropExceptions {
|
||||
scope.launchLoggingDropExceptions(logger = logger) {
|
||||
for (data in dataChannel) {
|
||||
output(data)
|
||||
}
|
||||
@@ -33,13 +35,16 @@ private data class AsyncSubscriptionCommandData<T, M>(
|
||||
val scope: CoroutineScope,
|
||||
val markerFactory: suspend (T) -> M,
|
||||
val block: suspend (T) -> Unit,
|
||||
val logger: KSLog,
|
||||
val onEmpty: suspend (M) -> Unit
|
||||
) : AsyncSubscriptionCommand<T, M> {
|
||||
override suspend fun invoke(markersMap: MutableMap<M, SubscribeAsyncReceiver<T>>) {
|
||||
val marker = markerFactory(data)
|
||||
markersMap.getOrPut(marker) {
|
||||
SubscribeAsyncReceiver(scope.LinkedSupervisorScope()) {
|
||||
safelyWithoutExceptions { block(it) }
|
||||
SubscribeAsyncReceiver(scope.LinkedSupervisorScope(), logger) {
|
||||
runCatchingLogging(logger = logger) {
|
||||
block(it)
|
||||
}
|
||||
if (isEmpty()) {
|
||||
onEmpty(marker)
|
||||
}
|
||||
@@ -63,6 +68,7 @@ private data class AsyncSubscriptionCommandClearReceiver<T, M>(
|
||||
fun <T, M> Flow<T>.subscribeAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
logger: KSLog = KSLog,
|
||||
block: suspend (T) -> Unit
|
||||
): Job {
|
||||
val subscope = scope.LinkedSupervisorScope()
|
||||
@@ -71,8 +77,14 @@ fun <T, M> Flow<T>.subscribeAsync(
|
||||
it.invoke(markersMap)
|
||||
}
|
||||
|
||||
val job = subscribeLoggingDropExceptions(subscope) { data ->
|
||||
val dataCommand = AsyncSubscriptionCommandData(data, subscope, markerFactory, block) { marker ->
|
||||
val job = subscribeLoggingDropExceptions(subscope, logger = logger) { data ->
|
||||
val dataCommand = AsyncSubscriptionCommandData(
|
||||
data = data,
|
||||
scope = subscope,
|
||||
markerFactory = markerFactory,
|
||||
block = block,
|
||||
logger = logger
|
||||
) { marker ->
|
||||
actor.send(
|
||||
AsyncSubscriptionCommandClearReceiver(marker)
|
||||
)
|
||||
@@ -85,17 +97,20 @@ fun <T, M> Flow<T>.subscribeAsync(
|
||||
return job
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("subscribeLoggingDropExceptionsAsync(scope, markerFactory, block = block)", "dev.inmo.micro_utils.coroutines.subscribeLoggingDropExceptionsAsync"))
|
||||
fun <T, M> Flow<T>.subscribeSafelyAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler,
|
||||
logger: KSLog = KSLog,
|
||||
block: suspend (T) -> Unit
|
||||
) = subscribeAsync(scope, markerFactory) {
|
||||
) = subscribeAsync(scope, markerFactory, logger) {
|
||||
safely(onException) {
|
||||
block(it)
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("subscribeLoggingDropExceptionsAsync(scope, markerFactory, block = block)", "dev.inmo.micro_utils.coroutines.subscribeLoggingDropExceptionsAsync"))
|
||||
fun <T, M> Flow<T>.subscribeSafelyWithoutExceptionsAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
@@ -107,11 +122,22 @@ fun <T, M> Flow<T>.subscribeSafelyWithoutExceptionsAsync(
|
||||
}
|
||||
}
|
||||
|
||||
fun <T, M> Flow<T>.subscribeLoggingDropExceptionsAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
logger: KSLog = KSLog,
|
||||
block: suspend (T) -> Unit
|
||||
) = subscribeAsync(scope, markerFactory, logger) {
|
||||
block(it)
|
||||
}
|
||||
|
||||
@Deprecated("Renamed", ReplaceWith("subscribeLoggingDropExceptionsAsync(scope, markerFactory, logger, block = block)", "dev.inmo.micro_utils.coroutines.subscribeLoggingDropExceptionsAsync"))
|
||||
fun <T, M> Flow<T>.subscribeSafelySkippingExceptionsAsync(
|
||||
scope: CoroutineScope,
|
||||
markerFactory: suspend (T) -> M,
|
||||
logger: KSLog = KSLog,
|
||||
block: suspend (T) -> Unit
|
||||
) = subscribeAsync(scope, markerFactory) {
|
||||
) = subscribeAsync(scope, markerFactory, logger) {
|
||||
safelyWithoutExceptions({ /* do nothing */}) {
|
||||
block(it)
|
||||
}
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.InternalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
@@ -11,13 +9,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.internal.SynchronizedObject
|
||||
import kotlinx.coroutines.internal.synchronized
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
/**
|
||||
* Works like [StateFlow], but guarantee that latest value update will always be delivered to
|
||||
* each active subscriber
|
||||
*/
|
||||
open class SpecialMutableStateFlow<T>(
|
||||
open class MutableRedeliverStateFlow<T>(
|
||||
initialValue: T
|
||||
) : MutableStateFlow<T>, FlowCollector<T>, MutableSharedFlow<T> {
|
||||
@OptIn(InternalCoroutinesApi::class)
|
||||
@@ -68,3 +65,6 @@ open class SpecialMutableStateFlow<T>(
|
||||
|
||||
override suspend fun collect(collector: FlowCollector<T>) = sharingFlow.collect(collector)
|
||||
}
|
||||
|
||||
@Deprecated("Renamed to MutableRedeliverStateFlow", ReplaceWith("MutableRedeliverStateFlow<T>"))
|
||||
typealias SpecialMutableStateFlow<T> = MutableRedeliverStateFlow<T>
|
@@ -1,7 +1,6 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
@@ -44,7 +43,7 @@ sealed interface SmartMutex {
|
||||
* @param locked Preset state of [isLocked] and its internal [_lockStateFlow]
|
||||
*/
|
||||
class Mutable(locked: Boolean = false) : SmartMutex {
|
||||
private val _lockStateFlow = SpecialMutableStateFlow<Boolean>(locked)
|
||||
private val _lockStateFlow = MutableRedeliverStateFlow<Boolean>(locked)
|
||||
override val lockStateFlow: StateFlow<Boolean> = _lockStateFlow.asStateFlow()
|
||||
|
||||
private val internalChangesMutex = Mutex()
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package dev.inmo.micro_utils.coroutines
|
||||
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.first
|
||||
@@ -47,7 +46,7 @@ sealed interface SmartSemaphore {
|
||||
*/
|
||||
class Mutable(permits: Int, acquiredPermits: Int = 0) : SmartSemaphore {
|
||||
override val maxPermits: Int = permits
|
||||
private val _freePermitsStateFlow = SpecialMutableStateFlow<Int>(permits - acquiredPermits)
|
||||
private val _freePermitsStateFlow = MutableRedeliverStateFlow<Int>(permits - acquiredPermits)
|
||||
override val permitsStateFlow: StateFlow<Int> = _freePermitsStateFlow.asStateFlow()
|
||||
|
||||
private val internalChangesMutex = Mutex(false)
|
||||
|
@@ -1,33 +1,31 @@
|
||||
import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
|
||||
import dev.inmo.micro_utils.coroutines.asDeferred
|
||||
import dev.inmo.micro_utils.coroutines.MutableRedeliverStateFlow
|
||||
import dev.inmo.micro_utils.coroutines.subscribe
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class SpecialMutableStateFlowTests {
|
||||
@Test
|
||||
fun simpleTest() = runTest {
|
||||
val specialMutableStateFlow = SpecialMutableStateFlow(0)
|
||||
specialMutableStateFlow.value = 1
|
||||
specialMutableStateFlow.first { it == 1 }
|
||||
assertEquals(1, specialMutableStateFlow.value)
|
||||
val mutableRedeliverStateFlow = MutableRedeliverStateFlow(0)
|
||||
mutableRedeliverStateFlow.value = 1
|
||||
mutableRedeliverStateFlow.first { it == 1 }
|
||||
assertEquals(1, mutableRedeliverStateFlow.value)
|
||||
}
|
||||
@Test
|
||||
fun specialTest() = runTest {
|
||||
val specialMutableStateFlow = SpecialMutableStateFlow(0)
|
||||
val mutableRedeliverStateFlow = MutableRedeliverStateFlow(0)
|
||||
lateinit var subscriberJob: Job
|
||||
subscriberJob = specialMutableStateFlow.subscribe(this) {
|
||||
subscriberJob = mutableRedeliverStateFlow.subscribe(this) {
|
||||
when (it) {
|
||||
1 -> specialMutableStateFlow.value = 2
|
||||
1 -> mutableRedeliverStateFlow.value = 2
|
||||
2 -> subscriberJob.cancel()
|
||||
}
|
||||
}
|
||||
specialMutableStateFlow.value = 1
|
||||
mutableRedeliverStateFlow.value = 1
|
||||
subscriberJob.join()
|
||||
assertEquals(2, specialMutableStateFlow.value)
|
||||
assertEquals(2, mutableRedeliverStateFlow.value)
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -30,3 +30,13 @@ allprojects {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("getPublishableModules") {
|
||||
doLast {
|
||||
rootProject.subprojects.each { project ->
|
||||
if (project.plugins.hasPlugin('maven-publish')) {
|
||||
println(":${project.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -11,12 +11,20 @@ private String getCurrentVersionChangelog() {
|
||||
return changelogDataOS.toString().trim()
|
||||
}
|
||||
|
||||
if (new File(projectDir, "secret.gradle").exists()) {
|
||||
apply from: './secret.gradle'
|
||||
|
||||
def githubTokenVariableName = "GITHUB_RELEASE_TOKEN"
|
||||
def githubTokenVariableFromEnv = System.getenv(githubTokenVariableName)
|
||||
|
||||
def secretFile = new File(projectDir, "secret.gradle")
|
||||
if (secretFile.exists() || project.hasProperty(githubTokenVariableName) || (githubTokenVariableFromEnv != "" && githubTokenVariableFromEnv != null)) {
|
||||
if (secretFile.exists()) {
|
||||
apply from: './secret.gradle'
|
||||
}
|
||||
apply plugin: "com.github.breadmoirai.github-release"
|
||||
def githubReleaseToken = project.hasProperty(githubTokenVariableName) ? project.property(githubTokenVariableName).toString() : githubTokenVariableFromEnv
|
||||
|
||||
githubRelease {
|
||||
token "${project.property('GITHUB_RELEASE_TOKEN')}"
|
||||
token githubReleaseToken
|
||||
|
||||
owner = "InsanusMokrassar"
|
||||
repo = "MicroUtils"
|
||||
|
@@ -8,6 +8,9 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g
|
||||
|
||||
# https://github.com/google/ksp/issues/2491
|
||||
ksp.useKSP2=false
|
||||
|
||||
# JS NPM
|
||||
|
||||
crypto_js_version=4.1.1
|
||||
@@ -15,5 +18,5 @@ crypto_js_version=4.1.1
|
||||
# Project data
|
||||
|
||||
group=dev.inmo
|
||||
version=0.25.4
|
||||
android_code_version=294
|
||||
version=0.26.4
|
||||
android_code_version=303
|
||||
|
7
gradle/karma.config.d/timeout.js
Normal file
7
gradle/karma.config.d/timeout.js
Normal file
@@ -0,0 +1,7 @@
|
||||
config.set({
|
||||
client: {
|
||||
mocha: {
|
||||
timeout: 240000
|
||||
}
|
||||
}
|
||||
});
|
@@ -1,46 +1,49 @@
|
||||
[versions]
|
||||
|
||||
kt = "2.1.20"
|
||||
kt-serialization = "1.8.0"
|
||||
kt-coroutines = "1.10.1"
|
||||
kt = "2.2.10"
|
||||
kt-serialization = "1.9.0"
|
||||
kt-coroutines = "1.10.2"
|
||||
|
||||
kslog = "1.4.1"
|
||||
kotlinx-browser = "0.3"
|
||||
|
||||
jb-compose = "1.7.3"
|
||||
jb-exposed = "0.60.0"
|
||||
kslog = "1.5.0"
|
||||
|
||||
jb-compose = "1.8.2"
|
||||
jb-exposed = "0.61.0"
|
||||
jb-dokka = "2.0.0"
|
||||
|
||||
sqlite = "3.49.1.0"
|
||||
sqlite = "3.50.1.0"
|
||||
|
||||
korlibs = "5.4.0"
|
||||
uuid = "0.8.4"
|
||||
|
||||
ktor = "3.1.2"
|
||||
ktor = "3.2.3"
|
||||
|
||||
gh-release = "2.5.2"
|
||||
|
||||
koin = "4.0.4"
|
||||
koin = "4.1.0"
|
||||
|
||||
okio = "3.10.2"
|
||||
okio = "3.16.0"
|
||||
|
||||
ksp = "2.1.20-1.0.31"
|
||||
kotlin-poet = "1.18.1"
|
||||
ksp = "2.2.10-2.0.2"
|
||||
kotlin-poet = "2.2.0"
|
||||
|
||||
versions = "0.51.0"
|
||||
versions = "0.52.0"
|
||||
nmcp = "1.1.0"
|
||||
|
||||
android-gradle = "8.7.+"
|
||||
android-gradle = "8.10.+"
|
||||
dexcount = "4.0.0"
|
||||
|
||||
android-coreKtx = "1.15.0"
|
||||
android-coreKtx = "1.17.0"
|
||||
android-recyclerView = "1.4.0"
|
||||
android-appCompat = "1.7.0"
|
||||
android-fragment = "1.8.6"
|
||||
android-espresso = "3.6.1"
|
||||
android-test = "1.2.1"
|
||||
android-appCompat = "1.7.1"
|
||||
android-fragment = "1.8.9"
|
||||
android-espresso = "3.7.0"
|
||||
android-test = "1.3.0"
|
||||
|
||||
android-props-minSdk = "21"
|
||||
android-props-compileSdk = "35"
|
||||
android-props-buildTools = "35.0.0"
|
||||
android-props-compileSdk = "36"
|
||||
android-props-buildTools = "36.0.0"
|
||||
|
||||
[libraries]
|
||||
|
||||
@@ -55,6 +58,7 @@ kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-and
|
||||
kt-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kt-coroutines" }
|
||||
kt-coroutines-debug = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-debug", version.ref = "kt-coroutines" }
|
||||
|
||||
kotlinx-browser = { module = "org.jetbrains.kotlinx:kotlinx-browser-wasm-js", version.ref = "kotlinx-browser" }
|
||||
|
||||
ktor-io = { module = "io.ktor:ktor-io", version.ref = "ktor" }
|
||||
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
|
||||
@@ -120,3 +124,4 @@ jb-compose = { id = "org.jetbrains.compose", version.ref = "jb-compose" }
|
||||
kt-jb-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kt" }
|
||||
|
||||
versions = { id = "com.github.ben-manes.versions", version.ref = "versions" }
|
||||
nmcp-aggregation = { id = "com.gradleup.nmcp.aggregation", version.ref = "nmcp" }
|
||||
|
9
gradle/templates/addCompose.gradle
Normal file
9
gradle/templates/addCompose.gradle
Normal file
@@ -0,0 +1,9 @@
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation compose.runtime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
gradle/templates/addComposeForAndroid.gradle
Normal file
9
gradle/templates/addComposeForAndroid.gradle
Normal file
@@ -0,0 +1,9 @@
|
||||
kotlin {
|
||||
sourceSets {
|
||||
androidUnitTest {
|
||||
dependencies {
|
||||
implementation compose.uiTest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
gradle/templates/addComposeForDesktop.gradle
Normal file
15
gradle/templates/addComposeForDesktop.gradle
Normal file
@@ -0,0 +1,15 @@
|
||||
kotlin {
|
||||
sourceSets {
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation compose.desktop.currentOs
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation compose.uiTest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
9
gradle/templates/addComposeForJs.gradle
Normal file
9
gradle/templates/addComposeForJs.gradle
Normal file
@@ -0,0 +1,9 @@
|
||||
kotlin {
|
||||
sourceSets {
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation compose.web.core
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
gradle/templates/defaultProject.gradle
Normal file
24
gradle/templates/defaultProject.gradle
Normal file
@@ -0,0 +1,24 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
25
gradle/templates/defaultProjectWithSerialization.gradle
Normal file
25
gradle/templates/defaultProjectWithSerialization.gradle
Normal file
@@ -0,0 +1,25 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
api libs.kt.serialization
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
31
gradle/templates/enableMPPAndroid.gradle
Normal file
31
gradle/templates/enableMPPAndroid.gradle
Normal file
@@ -0,0 +1,31 @@
|
||||
kotlin {
|
||||
androidTarget {
|
||||
publishAllLibraryVariants()
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
androidUnitTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation libs.android.test.junit
|
||||
implementation libs.android.espresso
|
||||
}
|
||||
}
|
||||
androidInstrumentedTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation libs.android.test.junit
|
||||
implementation libs.android.espresso
|
||||
}
|
||||
}
|
||||
|
||||
androidMain.dependsOn jvmMain
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "$defaultAndroidSettings"
|
30
gradle/templates/enableMPPJs.gradle
Normal file
30
gradle/templates/enableMPPJs.gradle
Normal file
@@ -0,0 +1,30 @@
|
||||
kotlin {
|
||||
js (IR) {
|
||||
browser {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodejs {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
jsMain {
|
||||
dependencies {
|
||||
}
|
||||
}
|
||||
jsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
21
gradle/templates/enableMPPJvm.gradle
Normal file
21
gradle/templates/enableMPPJvm.gradle
Normal file
@@ -0,0 +1,21 @@
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
jvmMain {
|
||||
dependencies {
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
8
gradle/templates/enableMPPNativeArm64.gradle
Normal file
8
gradle/templates/enableMPPNativeArm64.gradle
Normal file
@@ -0,0 +1,8 @@
|
||||
kotlin {
|
||||
linuxArm64()
|
||||
|
||||
sourceSets {
|
||||
nativeMain.dependsOn commonMain
|
||||
linuxArm64Main.dependsOn nativeMain
|
||||
}
|
||||
}
|
10
gradle/templates/enableMPPNativeX64.gradle
Normal file
10
gradle/templates/enableMPPNativeX64.gradle
Normal file
@@ -0,0 +1,10 @@
|
||||
kotlin {
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
|
||||
sourceSets {
|
||||
nativeMain.dependsOn commonMain
|
||||
linuxX64Main.dependsOn nativeMain
|
||||
mingwX64Main.dependsOn nativeMain
|
||||
}
|
||||
}
|
27
gradle/templates/enableMPPWasmJs.gradle
Normal file
27
gradle/templates/enableMPPWasmJs.gradle
Normal file
@@ -0,0 +1,27 @@
|
||||
kotlin {
|
||||
wasmJs {
|
||||
browser {
|
||||
testTask {
|
||||
useKarma {
|
||||
useChromeHeadless()
|
||||
useConfigDirectory(rootProject.relativeProjectPath("gradle/karma.config.d"))
|
||||
}
|
||||
}
|
||||
}
|
||||
nodejs {
|
||||
testTask {
|
||||
timeout = Duration.ofSeconds(240)
|
||||
nodeJsArgs.add("--unhandled-rejections=warn")
|
||||
nodeJsArgs.add("--trace-warnings")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
wasmJsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-wasm-js')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,37 +1,6 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
apply from: "$defaultProject"
|
||||
apply from: "$enableMPPJvm"
|
||||
apply from: "$enableMPPJs"
|
||||
apply from: "$enableMPPWasmJs"
|
||||
apply from: "$enableMPPAndroid"
|
||||
apply from: "$publish"
|
||||
|
||||
kotlin {
|
||||
androidTarget {
|
||||
publishAllLibraryVariants()
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "$defaultAndroidSettings"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
@@ -1,108 +0,0 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
apply from: "$publish"
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
js (IR) {
|
||||
browser {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodejs {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
androidTarget {
|
||||
publishAllLibraryVariants()
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
linuxArm64()
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
implementation compose.runtime
|
||||
api libs.kt.serialization
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
|
||||
androidUnitTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation libs.android.test.junit
|
||||
implementation libs.android.espresso
|
||||
implementation compose.uiTest
|
||||
}
|
||||
}
|
||||
androidInstrumentedTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation libs.android.test.junit
|
||||
implementation libs.android.espresso
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation compose.desktop.currentOs
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation compose.uiTest
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation compose.web.core
|
||||
}
|
||||
}
|
||||
jsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
nativeMain.dependsOn commonMain
|
||||
linuxX64Main.dependsOn nativeMain
|
||||
mingwX64Main.dependsOn nativeMain
|
||||
linuxArm64Main.dependsOn nativeMain
|
||||
|
||||
androidMain.dependsOn jvmMain
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "$defaultAndroidSettings"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
apply from: "$defaultProjectWithSerialization"
|
||||
apply from: "$enableMPPJvm"
|
||||
apply from: "$enableMPPJs"
|
||||
apply from: "$enableMPPWasmJs"
|
||||
apply from: "$enableMPPAndroid"
|
||||
apply from: "$enableMPPNativeX64"
|
||||
apply from: "$enableMPPNativeArm64"
|
||||
apply from: "$addCompose"
|
||||
apply from: "$addComposeForAndroid"
|
||||
apply from: "$addComposeForDesktop"
|
||||
apply from: "$addComposeForJs"
|
||||
apply from: "$publish"
|
@@ -1,40 +1,3 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
apply from: "$defaultProject"
|
||||
apply from: "$enableMPPJvm"
|
||||
apply from: "$publish"
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
@@ -1,88 +0,0 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
apply from: "$publish"
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
js (IR) {
|
||||
browser {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodejs {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
androidTarget {
|
||||
publishAllLibraryVariants()
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
linuxArm64()
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
api libs.kt.serialization
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
|
||||
androidUnitTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation libs.android.test.junit
|
||||
implementation libs.android.espresso
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
}
|
||||
}
|
||||
jsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
nativeMain.dependsOn commonMain
|
||||
linuxX64Main.dependsOn nativeMain
|
||||
mingwX64Main.dependsOn nativeMain
|
||||
linuxArm64Main.dependsOn nativeMain
|
||||
|
||||
androidMain.dependsOn jvmMain
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "$defaultAndroidSettings"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
@@ -1,70 +0,0 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
apply from: "$publish"
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
js (IR) {
|
||||
browser {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodejs {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
linuxX64()
|
||||
mingwX64()
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
api libs.kt.serialization
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
}
|
||||
}
|
||||
jsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
|
||||
nativeMain.dependsOn commonMain
|
||||
linuxX64Main.dependsOn nativeMain
|
||||
mingwX64Main.dependsOn nativeMain
|
||||
|
||||
androidMain.dependsOn jvmMain
|
||||
}
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
apply from: "$defaultProjectWithSerialization"
|
||||
apply from: "$enableMPPJvm"
|
||||
apply from: "$enableMPPJs"
|
||||
apply from: "$enableMPPWasmJs"
|
||||
apply from: "$enableMPPAndroid"
|
||||
apply from: "$enableMPPNativeX64"
|
||||
apply from: "$enableMPPNativeArm64"
|
||||
apply from: "$publish"
|
6
gradle/templates/mppJvmJsWasmJsLinuxMingwProject.gradle
Normal file
6
gradle/templates/mppJvmJsWasmJsLinuxMingwProject.gradle
Normal file
@@ -0,0 +1,6 @@
|
||||
apply from: "$defaultProjectWithSerialization"
|
||||
apply from: "$enableMPPJvm"
|
||||
apply from: "$enableMPPJs"
|
||||
apply from: "$enableMPPWasmJs"
|
||||
apply from: "$enableMPPNativeX64"
|
||||
apply from: "$publish"
|
@@ -1,98 +1,10 @@
|
||||
project.version = "$version"
|
||||
project.group = "$group"
|
||||
|
||||
apply from: "$defaultProjectWithSerialization"
|
||||
apply from: "$enableMPPJvm"
|
||||
apply from: "$enableMPPJs"
|
||||
apply from: "$enableMPPWasmJs"
|
||||
apply from: "$enableMPPAndroid"
|
||||
apply from: "$addCompose"
|
||||
apply from: "$addComposeForAndroid"
|
||||
apply from: "$addComposeForDesktop"
|
||||
apply from: "$addComposeForJs"
|
||||
apply from: "$publish"
|
||||
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
js (IR) {
|
||||
browser {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
nodejs {
|
||||
testTask {
|
||||
useMocha {
|
||||
timeout = "240000"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
androidTarget {
|
||||
publishAllLibraryVariants()
|
||||
compilations.all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "17"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin('stdlib')
|
||||
implementation compose.runtime
|
||||
api libs.kt.serialization
|
||||
}
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-common')
|
||||
implementation kotlin('test-annotations-common')
|
||||
implementation libs.kt.coroutines.test
|
||||
}
|
||||
}
|
||||
jvmMain {
|
||||
dependencies {
|
||||
implementation compose.desktop.currentOs
|
||||
}
|
||||
}
|
||||
jvmTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation compose.uiTest
|
||||
}
|
||||
}
|
||||
jsMain {
|
||||
dependencies {
|
||||
implementation compose.web.core
|
||||
}
|
||||
}
|
||||
jsTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-js')
|
||||
}
|
||||
}
|
||||
androidUnitTest {
|
||||
dependencies {
|
||||
implementation kotlin('test-junit')
|
||||
implementation libs.android.test.junit
|
||||
implementation libs.android.espresso
|
||||
implementation compose.uiTest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply from: "$defaultAndroidSettings"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
|
||||
//compose {
|
||||
// if (composePluginKotlinVersion != null && !composePluginKotlinVersion.isEmpty()) {
|
||||
// kotlinCompilerPlugin.set(composePluginKotlinVersion)
|
||||
// }
|
||||
//}
|
||||
|
@@ -1,7 +1,3 @@
|
||||
if (ext.getProperties()["do_publish"] == false) {
|
||||
return
|
||||
}
|
||||
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
task javadocsJar(type: Jar) {
|
||||
@@ -23,72 +19,64 @@ publishing {
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id = "InsanusMokrassar"
|
||||
name = "Aleksei Ovsiannikov"
|
||||
email = "ovsyannikov.alexey95@gmail.com"
|
||||
}
|
||||
|
||||
developer {
|
||||
id = "InsanusMokrassar"
|
||||
name = "Aleksei Ovsiannikov"
|
||||
email = "ovsyannikov.alexey95@gmail.com"
|
||||
}
|
||||
|
||||
|
||||
developer {
|
||||
id = "000Sanya"
|
||||
name = "Syrov Aleksandr"
|
||||
email = "000sanya.000sanya@gmail.com"
|
||||
}
|
||||
|
||||
developer {
|
||||
id = "000Sanya"
|
||||
name = "Syrov Aleksandr"
|
||||
email = "000sanya.000sanya@gmail.com"
|
||||
}
|
||||
}
|
||||
|
||||
licenses {
|
||||
|
||||
license {
|
||||
name = "Apache Software License 2.0"
|
||||
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
|
||||
}
|
||||
|
||||
license {
|
||||
name = "Apache Software License 2.0"
|
||||
url = "https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "GithubPackages"
|
||||
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
repositories {
|
||||
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "GithubPackages"
|
||||
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||
}
|
||||
}
|
||||
if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "InmoNexus"
|
||||
url = uri("https://nexus.inmo.dev/repository/maven-releases/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
|
||||
password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "InmoNexus"
|
||||
url = uri("https://nexus.inmo.dev/repository/maven-releases/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
|
||||
password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
|
||||
}
|
||||
}
|
||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (project.hasProperty("signing.gnupg.keyName")) {
|
||||
apply plugin: 'signing'
|
||||
|
||||
|
@@ -1 +1 @@
|
||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
|
||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"},"includeCentralSonatypeUploadingScript":false}}
|
@@ -1,5 +1,6 @@
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
|
||||
task javadocJar(type: Jar) {
|
||||
from javadoc
|
||||
archiveClassifier = 'javadoc'
|
||||
@@ -55,42 +56,39 @@ publishing {
|
||||
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "GithubPackages"
|
||||
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
if ((project.hasProperty('GITHUBPACKAGES_USER') || System.getenv('GITHUBPACKAGES_USER') != null) && (project.hasProperty('GITHUBPACKAGES_PASSWORD') || System.getenv('GITHUBPACKAGES_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "GithubPackages"
|
||||
url = uri("https://maven.pkg.github.com/InsanusMokrassar/MicroUtils")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('GITHUBPACKAGES_USER') ? project.property('GITHUBPACKAGES_USER') : System.getenv('GITHUBPACKAGES_USER')
|
||||
password = project.hasProperty('GITHUBPACKAGES_PASSWORD') ? project.property('GITHUBPACKAGES_PASSWORD') : System.getenv('GITHUBPACKAGES_PASSWORD')
|
||||
}
|
||||
if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "InmoNexus"
|
||||
url = uri("https://nexus.inmo.dev/repository/maven-releases/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
|
||||
password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "InmoNexus"
|
||||
url = uri("https://nexus.inmo.dev/repository/maven-releases/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
|
||||
password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
|
||||
}
|
||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((project.hasProperty('SONATYPE_USER') || System.getenv('SONATYPE_USER') != null) && (project.hasProperty('SONATYPE_PASSWORD') || System.getenv('SONATYPE_PASSWORD') != null)) {
|
||||
maven {
|
||||
name = "sonatype"
|
||||
url = uri("https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/")
|
||||
|
||||
credentials {
|
||||
username = project.hasProperty('SONATYPE_USER') ? project.property('SONATYPE_USER') : System.getenv('SONATYPE_USER')
|
||||
password = project.hasProperty('SONATYPE_PASSWORD') ? project.property('SONATYPE_PASSWORD') : System.getenv('SONATYPE_PASSWORD')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,13 +97,13 @@ publishing {
|
||||
|
||||
if (project.hasProperty("signing.gnupg.keyName")) {
|
||||
apply plugin: 'signing'
|
||||
|
||||
|
||||
signing {
|
||||
useGpgCmd()
|
||||
|
||||
|
||||
sign publishing.publications
|
||||
}
|
||||
|
||||
|
||||
task signAll {
|
||||
tasks.withType(Sign).forEach {
|
||||
dependsOn(it)
|
||||
|
@@ -1 +1 @@
|
||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}
|
||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"},"includeCentralSonatypeUploadingScript":false},"type":"JVM"}
|
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.12.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -10,6 +10,7 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
api project(":micro_utils.koin")
|
||||
api project(":micro_utils.ksp.generator")
|
||||
api libs.kotlin.poet
|
||||
api libs.ksp
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import com.squareup.kotlinpoet.asTypeName
|
||||
import com.squareup.kotlinpoet.ksp.toClassName
|
||||
import com.squareup.kotlinpoet.ksp.toTypeName
|
||||
import com.squareup.kotlinpoet.ksp.writeTo
|
||||
import dev.inmo.micro_ksp.generator.safeClassName
|
||||
import dev.inmo.micro_utils.koin.annotations.GenerateGenericKoinDefinition
|
||||
import dev.inmo.micro_utils.koin.annotations.GenerateKoinDefinition
|
||||
import org.koin.core.Koin
|
||||
@@ -237,15 +238,7 @@ class Processor(
|
||||
""".trimIndent()
|
||||
)
|
||||
ksFile.getAnnotationsByType(GenerateKoinDefinition::class).forEach {
|
||||
val type = runCatching {
|
||||
it.type.asTypeName()
|
||||
}.getOrElse { e ->
|
||||
if (e is KSTypeNotPresentException) {
|
||||
e.ksType.toClassName()
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
val type = safeClassName { it.type }
|
||||
val targetType = runCatching {
|
||||
type.parameterizedBy(*(it.typeArgs.takeIf { it.isNotEmpty() } ?.map { it.asTypeName() } ?.toTypedArray() ?: return@runCatching type))
|
||||
}.getOrElse { e ->
|
||||
|
@@ -5,7 +5,7 @@ plugins {
|
||||
id "com.google.devtools.ksp"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
kotlin {
|
||||
|
@@ -5,7 +5,6 @@ package dev.inmo.micro_utils.koin.generator.test
|
||||
|
||||
import kotlin.Any
|
||||
import kotlin.Boolean
|
||||
import kotlin.Deprecated
|
||||
import kotlin.String
|
||||
import org.koin.core.Koin
|
||||
import org.koin.core.definition.Definition
|
||||
@@ -30,95 +29,59 @@ public val Koin.sampleInfo: Test<String>
|
||||
/**
|
||||
* @return Definition by key "sampleInfo" with [parameters]
|
||||
*/
|
||||
public inline fun Scope.sampleInfo(noinline parameters: ParametersDefinition): Test<String> =
|
||||
get(named("sampleInfo"), parameters)
|
||||
public inline fun Scope.sampleInfo(noinline parameters: ParametersDefinition): Test<String> = get(named("sampleInfo"), parameters)
|
||||
|
||||
/**
|
||||
* @return Definition by key "sampleInfo" with [parameters]
|
||||
*/
|
||||
public inline fun Koin.sampleInfo(noinline parameters: ParametersDefinition): Test<String> =
|
||||
get(named("sampleInfo"), parameters)
|
||||
public inline fun Koin.sampleInfo(noinline parameters: ParametersDefinition): Test<String> = get(named("sampleInfo"), parameters)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.single] and key "sampleInfo"
|
||||
*/
|
||||
@Deprecated(
|
||||
"This definition is old style and should not be used anymore. Use singleSampleInfo instead",
|
||||
ReplaceWith("singleSampleInfo"),
|
||||
)
|
||||
public fun Module.sampleInfoSingle(createdAtStart: Boolean = false,
|
||||
definition: Definition<Test<String>>): KoinDefinition<Test<String>> =
|
||||
single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.single] and key "sampleInfo"
|
||||
*/
|
||||
public fun Module.singleSampleInfo(createdAtStart: Boolean = false,
|
||||
definition: Definition<Test<String>>): KoinDefinition<Test<String>> =
|
||||
single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition)
|
||||
public fun Module.singleSampleInfo(createdAtStart: Boolean = false, definition: Definition<Test<String>>): KoinDefinition<Test<String>> = single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.factory] and key "sampleInfo"
|
||||
*/
|
||||
@Deprecated(
|
||||
"This definition is old style and should not be used anymore. Use factorySampleInfo instead",
|
||||
ReplaceWith("factorySampleInfo"),
|
||||
)
|
||||
public fun Module.sampleInfoFactory(definition: Definition<Test<String>>):
|
||||
KoinDefinition<Test<String>> = factory(named("sampleInfo"), definition = definition)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.factory] and key "sampleInfo"
|
||||
*/
|
||||
public fun Module.factorySampleInfo(definition: Definition<Test<String>>):
|
||||
KoinDefinition<Test<String>> = factory(named("sampleInfo"), definition = definition)
|
||||
public fun Module.factorySampleInfo(definition: Definition<Test<String>>): KoinDefinition<Test<String>> = factory(named("sampleInfo"), definition = definition)
|
||||
|
||||
/**
|
||||
* @return Definition by key "test" with [parameters]
|
||||
*/
|
||||
public inline fun <reified T : Any> Scope.test(noinline parameters: ParametersDefinition? = null): T
|
||||
= get(named("test"), parameters)
|
||||
public inline fun <reified T : Any> Scope.test(noinline parameters: ParametersDefinition? = null): T = get(named("test"), parameters)
|
||||
|
||||
/**
|
||||
* @return Definition by key "test" with [parameters]
|
||||
*/
|
||||
public inline fun <reified T : Any> Koin.test(noinline parameters: ParametersDefinition? = null): T
|
||||
= get(named("test"), parameters)
|
||||
public inline fun <reified T : Any> Koin.test(noinline parameters: ParametersDefinition? = null): T = get(named("test"), parameters)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.single] and key "test"
|
||||
*/
|
||||
public inline fun <reified T : Any> Module.singleTest(createdAtStart: Boolean = false, noinline
|
||||
definition: Definition<T>): KoinDefinition<T> = single(named("test"), createdAtStart =
|
||||
createdAtStart, definition = definition)
|
||||
public inline fun <reified T : Any> Module.singleTest(createdAtStart: Boolean = false, noinline definition: Definition<T>): KoinDefinition<T> = single(named("test"), createdAtStart = createdAtStart, definition = definition)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.factory] and key "test"
|
||||
*/
|
||||
public inline fun <reified T : Any> Module.factoryTest(noinline definition: Definition<T>):
|
||||
KoinDefinition<T> = factory(named("test"), definition = definition)
|
||||
public inline fun <reified T : Any> Module.factoryTest(noinline definition: Definition<T>): KoinDefinition<T> = factory(named("test"), definition = definition)
|
||||
|
||||
/**
|
||||
* @return Definition by key "testNullable" with [parameters]
|
||||
*/
|
||||
public inline fun <reified T : Any> Scope.testNullable(noinline parameters: ParametersDefinition? =
|
||||
null): T? = getOrNull(named("testNullable"), parameters)
|
||||
public inline fun <reified T : Any> Scope.testNullable(noinline parameters: ParametersDefinition? = null): T? = getOrNull(named("testNullable"), parameters)
|
||||
|
||||
/**
|
||||
* @return Definition by key "testNullable" with [parameters]
|
||||
*/
|
||||
public inline fun <reified T : Any> Koin.testNullable(noinline parameters: ParametersDefinition? =
|
||||
null): T? = getOrNull(named("testNullable"), parameters)
|
||||
public inline fun <reified T : Any> Koin.testNullable(noinline parameters: ParametersDefinition? = null): T? = getOrNull(named("testNullable"), parameters)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.single] and key "testNullable"
|
||||
*/
|
||||
public inline fun <reified T : Any> Module.singleTestNullable(createdAtStart: Boolean = false,
|
||||
noinline definition: Definition<T>): KoinDefinition<T> = single(named("testNullable"),
|
||||
createdAtStart = createdAtStart, definition = definition)
|
||||
public inline fun <reified T : Any> Module.singleTestNullable(createdAtStart: Boolean = false, noinline definition: Definition<T>): KoinDefinition<T> = single(named("testNullable"), createdAtStart = createdAtStart, definition = definition)
|
||||
|
||||
/**
|
||||
* Will register [definition] with [org.koin.core.module.Module.factory] and key "testNullable"
|
||||
*/
|
||||
public inline fun <reified T : Any> Module.factoryTestNullable(noinline definition: Definition<T>):
|
||||
KoinDefinition<T> = factory(named("testNullable"), definition = definition)
|
||||
public inline fun <reified T : Any> Module.factoryTestNullable(noinline definition: Definition<T>): KoinDefinition<T> = factory(named("testNullable"), definition = definition)
|
||||
|
@@ -4,8 +4,14 @@ import org.koin.core.definition.Definition
|
||||
import org.koin.core.module.Module
|
||||
|
||||
/**
|
||||
* Will be useful in case you need to declare some singles with one type several types, but need to separate them and do
|
||||
* not care about how :)
|
||||
* Declares a factory with a random qualifier in the Koin module.
|
||||
* This is useful when you need to declare multiple factory definitions of the same type
|
||||
* but want them to be uniquely identifiable without manually specifying qualifiers.
|
||||
* Unlike singles, factories create a new instance each time they are requested.
|
||||
*
|
||||
* @param T The type of instance to be created by the factory
|
||||
* @param definition The definition function that creates new instances
|
||||
* @return A Koin definition for the factory with a random qualifier
|
||||
*/
|
||||
inline fun <reified T : Any> Module.factoryWithRandomQualifier(
|
||||
noinline definition: Definition<T>
|
||||
|
@@ -4,6 +4,16 @@ import org.koin.core.definition.Definition
|
||||
import org.koin.core.module.Module
|
||||
import org.koin.core.qualifier.StringQualifier
|
||||
|
||||
/**
|
||||
* Declares a factory with a string qualifier in the Koin module.
|
||||
* This is a convenience function that wraps the string qualifier in a [StringQualifier].
|
||||
* Unlike singles, factories create a new instance each time they are requested.
|
||||
*
|
||||
* @param T The type of instance to be created by the factory
|
||||
* @param qualifier The string value to be used as a qualifier
|
||||
* @param definition The definition function that creates new instances
|
||||
* @return A Koin definition for the factory with the specified string qualifier
|
||||
*/
|
||||
inline fun <reified T : Any> Module.factory(
|
||||
qualifier: String,
|
||||
noinline definition: Definition<T>
|
||||
|
@@ -3,6 +3,21 @@ package dev.inmo.micro_utils.koin
|
||||
import org.koin.core.Koin
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
/**
|
||||
* Retrieves all instances of type [T] from the current [Scope] and returns them as a distinct list.
|
||||
* This function is useful when you want to avoid duplicate instances of the same type.
|
||||
*
|
||||
* @param T The type of instances to retrieve
|
||||
* @return A list of distinct instances of type [T]
|
||||
*/
|
||||
inline fun <reified T : Any> Scope.getAllDistinct() = getAll<T>().distinct()
|
||||
|
||||
/**
|
||||
* Retrieves all instances of type [T] from the [Koin] container and returns them as a distinct list.
|
||||
* This function is useful when you want to avoid duplicate instances of the same type.
|
||||
*
|
||||
* @param T The type of instances to retrieve
|
||||
* @return A list of distinct instances of type [T]
|
||||
*/
|
||||
inline fun <reified T : Any> Koin.getAllDistinct() = getAll<T>().distinct()
|
||||
|
||||
|
@@ -3,6 +3,23 @@ package dev.inmo.micro_utils.koin
|
||||
import org.koin.core.Koin
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
/**
|
||||
* Retrieves the first available instance of type [T] from the current scope.
|
||||
* This is useful when you need any instance of a type and don't care which one.
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @return The first available instance of type [T]
|
||||
* @throws NoSuchElementException if no instances of type [T] are available
|
||||
*/
|
||||
inline fun <reified T : Any> Scope.getAny() = getAll<T>().first()
|
||||
|
||||
/**
|
||||
* Retrieves the first available instance of type [T] from the Koin container.
|
||||
* This is useful when you need any instance of a type and don't care which one.
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @return The first available instance of type [T]
|
||||
* @throws NoSuchElementException if no instances of type [T] are available
|
||||
*/
|
||||
inline fun <reified T : Any> Koin.getAny() = getAll<T>().first()
|
||||
|
||||
|
@@ -7,33 +7,81 @@ import org.koin.core.instance.InstanceFactory
|
||||
import org.koin.core.parameter.ParametersDefinition
|
||||
import org.koin.core.scope.Scope
|
||||
|
||||
/**
|
||||
* Retrieves an instance of type [T] from the Koin container using a [BeanDefinition].
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @param definition The bean definition to use for instance retrieval
|
||||
* @param parameters Optional parameters to pass to the instance constructor
|
||||
* @return An instance of type [T]
|
||||
*/
|
||||
fun <T> Koin.get(definition: BeanDefinition<T>, parameters: ParametersDefinition? = null): T = get(
|
||||
definition.primaryType,
|
||||
definition.qualifier,
|
||||
parameters
|
||||
)
|
||||
|
||||
/**
|
||||
* Retrieves an instance of type [T] from the Koin container using an [InstanceFactory].
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @param definition The instance factory to use for instance retrieval
|
||||
* @param parameters Optional parameters to pass to the instance constructor
|
||||
* @return An instance of type [T]
|
||||
*/
|
||||
fun <T> Koin.get(definition: InstanceFactory<T>, parameters: ParametersDefinition? = null): T = get(
|
||||
definition.beanDefinition,
|
||||
parameters
|
||||
)
|
||||
|
||||
/**
|
||||
* Retrieves an instance of type [T] from the Koin container using a [KoinDefinition].
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @param definition The Koin definition to use for instance retrieval
|
||||
* @param parameters Optional parameters to pass to the instance constructor
|
||||
* @return An instance of type [T]
|
||||
*/
|
||||
fun <T> Koin.get(definition: KoinDefinition<T>, parameters: ParametersDefinition? = null): T = get(
|
||||
definition.factory,
|
||||
parameters
|
||||
)
|
||||
|
||||
/**
|
||||
* Retrieves an instance of type [T] from the current scope using a [BeanDefinition].
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @param definition The bean definition to use for instance retrieval
|
||||
* @param parameters Optional parameters to pass to the instance constructor
|
||||
* @return An instance of type [T]
|
||||
*/
|
||||
fun <T> Scope.get(definition: BeanDefinition<T>, parameters: ParametersDefinition? = null): T = get(
|
||||
definition.primaryType,
|
||||
definition.qualifier,
|
||||
parameters
|
||||
)
|
||||
|
||||
/**
|
||||
* Retrieves an instance of type [T] from the current scope using an [InstanceFactory].
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @param definition The instance factory to use for instance retrieval
|
||||
* @param parameters Optional parameters to pass to the instance constructor
|
||||
* @return An instance of type [T]
|
||||
*/
|
||||
fun <T> Scope.get(definition: InstanceFactory<T>, parameters: ParametersDefinition? = null): T = get(
|
||||
definition.beanDefinition,
|
||||
parameters
|
||||
)
|
||||
|
||||
/**
|
||||
* Retrieves an instance of type [T] from the current scope using a [KoinDefinition].
|
||||
*
|
||||
* @param T The type of instance to retrieve
|
||||
* @param definition The Koin definition to use for instance retrieval
|
||||
* @param parameters Optional parameters to pass to the instance constructor
|
||||
* @return An instance of type [T]
|
||||
*/
|
||||
fun <T> Scope.get(definition: KoinDefinition<T>, parameters: ParametersDefinition? = null): T = get(
|
||||
definition.factory,
|
||||
parameters
|
||||
|
@@ -3,4 +3,10 @@ package dev.inmo.micro_utils.koin
|
||||
import com.benasher44.uuid.uuid4
|
||||
import org.koin.core.qualifier.StringQualifier
|
||||
|
||||
/**
|
||||
* Creates a [StringQualifier] with a random string value.
|
||||
*
|
||||
* @param randomFun A function that generates a random string. By default, it uses UUID4 string representation.
|
||||
* @return A [StringQualifier] with a randomly generated string value
|
||||
*/
|
||||
fun RandomQualifier(randomFun: () -> String = { uuid4().toString() }) = StringQualifier(randomFun())
|
||||
|
@@ -4,8 +4,14 @@ import org.koin.core.definition.Definition
|
||||
import org.koin.core.module.Module
|
||||
|
||||
/**
|
||||
* Will be useful in case you need to declare some singles with one type several types, but need to separate them and do
|
||||
* not care about how :)
|
||||
* Declares a single instance with a random qualifier in the Koin module.
|
||||
* This is useful when you need to declare multiple instances of the same type
|
||||
* but want them to be uniquely identifiable without manually specifying qualifiers.
|
||||
*
|
||||
* @param T The type of instance to be created
|
||||
* @param createdAtStart Whether the instance should be created when the Koin module starts (default: false)
|
||||
* @param definition The definition function that creates the instance
|
||||
* @return A Koin definition for the single instance with a random qualifier
|
||||
*/
|
||||
inline fun <reified T : Any> Module.singleWithRandomQualifier(
|
||||
createdAtStart: Boolean = false,
|
||||
|
@@ -4,6 +4,16 @@ import org.koin.core.definition.Definition
|
||||
import org.koin.core.module.Module
|
||||
import org.koin.core.qualifier.StringQualifier
|
||||
|
||||
/**
|
||||
* Declares a single instance with a string qualifier in the Koin module.
|
||||
* This is a convenience function that wraps the string qualifier in a [StringQualifier].
|
||||
*
|
||||
* @param T The type of instance to be created
|
||||
* @param qualifier The string value to be used as a qualifier
|
||||
* @param createdAtStart Whether the instance should be created when the Koin module starts (default: false)
|
||||
* @param definition The definition function that creates the instance
|
||||
* @return A Koin definition for the single instance with the specified string qualifier
|
||||
*/
|
||||
inline fun <reified T : Any> Module.single(
|
||||
qualifier: String,
|
||||
createdAtStart: Boolean = false,
|
||||
|
@@ -4,4 +4,4 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
@@ -7,7 +7,7 @@ plugins {
|
||||
|
||||
ext.do_publish = false
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
kotlin {
|
||||
|
23
ksp/generator/src/main/kotlin/KClassTypeName.kt
Normal file
23
ksp/generator/src/main/kotlin/KClassTypeName.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
package dev.inmo.micro_ksp.generator
|
||||
|
||||
import com.google.devtools.ksp.KSTypeNotPresentException
|
||||
import com.google.devtools.ksp.KspExperimental
|
||||
import com.squareup.kotlinpoet.ClassName
|
||||
import com.squareup.kotlinpoet.asTypeName
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@OptIn(KspExperimental::class)
|
||||
inline fun safeClassName(classnameGetter: () -> KClass<*>) = runCatching {
|
||||
classnameGetter().asTypeName()
|
||||
}.getOrElse { e ->
|
||||
if (e is KSTypeNotPresentException) {
|
||||
ClassName(
|
||||
e.ksType.declaration.packageName.asString(),
|
||||
e.ksType.declaration.qualifiedName ?.asString() ?.replaceFirst(e.ksType.declaration.packageName.asString(), "")
|
||||
?: e.ksType.declaration.simpleName.asString()
|
||||
)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
@@ -4,4 +4,4 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
@@ -7,7 +7,7 @@ plugins {
|
||||
|
||||
ext.do_publish = false
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
kotlin {
|
||||
|
@@ -4,4 +4,4 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
@@ -7,7 +7,7 @@ plugins {
|
||||
|
||||
ext.do_publish = false
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
|
||||
kotlin {
|
||||
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -0,0 +1,63 @@
|
||||
package dev.inmo.micro_utils.ktor.client
|
||||
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import dev.inmo.micro_utils.ktor.common.TemporalFileId
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.content.*
|
||||
import kotlinx.coroutines.*
|
||||
import org.w3c.xhr.*
|
||||
import org.w3c.xhr.XMLHttpRequest.Companion.DONE
|
||||
|
||||
suspend fun tempUpload(
|
||||
fullTempUploadDraftPath: String,
|
||||
file: MPPFile,
|
||||
onUpload: ProgressListener
|
||||
): TemporalFileId {
|
||||
val formData = FormData()
|
||||
val answer = CompletableDeferred<TemporalFileId>(currentCoroutineContext().job)
|
||||
val subscope = CoroutineScope(currentCoroutineContext().LinkedSupervisorJob())
|
||||
|
||||
formData.append(
|
||||
"data",
|
||||
file
|
||||
)
|
||||
|
||||
val request = XMLHttpRequest()
|
||||
request.responseType = XMLHttpRequestResponseType.TEXT
|
||||
request.upload.onprogress = {
|
||||
subscope.launchLoggingDropExceptions { onUpload.onProgress(it.loaded.toString().toLong(), it.total.toString().toLong()) }
|
||||
}
|
||||
request.onload = {
|
||||
if (request.status == 200.toShort()) {
|
||||
answer.complete(TemporalFileId(request.responseText))
|
||||
} else {
|
||||
answer.completeExceptionally(Exception("Something went wrong: $it"))
|
||||
}
|
||||
}
|
||||
request.onerror = {
|
||||
answer.completeExceptionally(Exception("Something went wrong: $it"))
|
||||
}
|
||||
request.open("POST", fullTempUploadDraftPath, true)
|
||||
request.send(formData)
|
||||
|
||||
answer.invokeOnCompletion {
|
||||
runCatching {
|
||||
if (request.readyState != DONE) {
|
||||
request.abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return answer.await().also {
|
||||
subscope.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
actual suspend fun HttpClient.tempUpload(
|
||||
fullTempUploadDraftPath: String,
|
||||
file: MPPFile,
|
||||
onUpload: ProgressListener
|
||||
): TemporalFileId = dev.inmo.micro_utils.ktor.client.tempUpload(fullTempUploadDraftPath, file, onUpload)
|
@@ -0,0 +1,97 @@
|
||||
package dev.inmo.micro_utils.ktor.client
|
||||
|
||||
import dev.inmo.micro_utils.common.MPPFile
|
||||
import dev.inmo.micro_utils.coroutines.LinkedSupervisorJob
|
||||
import dev.inmo.micro_utils.coroutines.launchLoggingDropExceptions
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.content.*
|
||||
import io.ktor.http.Headers
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.coroutines.job
|
||||
import kotlinx.io.readByteArray
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.StringFormat
|
||||
import kotlinx.serialization.encodeToString
|
||||
import org.khronos.webgl.toInt8Array
|
||||
import org.w3c.files.Blob
|
||||
import org.w3c.xhr.FormData
|
||||
import org.w3c.xhr.TEXT
|
||||
import org.w3c.xhr.XMLHttpRequest
|
||||
import org.w3c.xhr.XMLHttpRequestResponseType
|
||||
|
||||
/**
|
||||
* Will execute submitting of multipart data request
|
||||
*
|
||||
* @param data [Map] where keys will be used as names for multipart parts and values as values. If you will pass
|
||||
* [dev.inmo.micro_utils.common.MPPFile] (File from JS or JVM platform). Also you may pass [UniUploadFileInfo] as value
|
||||
* in case you wish to pass other source of multipart binary data than regular file
|
||||
* @suppress
|
||||
*/
|
||||
actual suspend fun <T> HttpClient.uniUpload(
|
||||
url: String,
|
||||
data: Map<String, Any>,
|
||||
resultDeserializer: DeserializationStrategy<T>,
|
||||
headers: Headers,
|
||||
stringFormat: StringFormat,
|
||||
onUpload: ProgressListener
|
||||
): T? {
|
||||
val formData = FormData()
|
||||
val answer = CompletableDeferred<T?>(currentCoroutineContext().job)
|
||||
val subscope = CoroutineScope(currentCoroutineContext().LinkedSupervisorJob())
|
||||
|
||||
data.forEach { (k, v) ->
|
||||
when (v) {
|
||||
is MPPFile -> formData.append(
|
||||
k,
|
||||
v
|
||||
)
|
||||
is UniUploadFileInfo -> formData.append(
|
||||
k,
|
||||
Blob(arrayOf(v.inputAllocator().readByteArray().toInt8Array()).toJsArray().unsafeCast()),
|
||||
v.fileName.name
|
||||
)
|
||||
else -> formData.append(
|
||||
k,
|
||||
stringFormat.encodeToString(v)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val request = XMLHttpRequest()
|
||||
headers.forEach { s, strings ->
|
||||
request.setRequestHeader(s, strings.joinToString())
|
||||
}
|
||||
request.responseType = XMLHttpRequestResponseType.TEXT
|
||||
request.upload.onprogress = {
|
||||
subscope.launchLoggingDropExceptions { onUpload.onProgress(it.loaded.toString().toLong(), it.total.toString().toLong()) }
|
||||
}
|
||||
request.onload = {
|
||||
if (request.status == 200.toShort()) {
|
||||
answer.complete(
|
||||
stringFormat.decodeFromString(resultDeserializer, request.responseText)
|
||||
)
|
||||
} else {
|
||||
answer.completeExceptionally(Exception("Something went wrong: $it"))
|
||||
}
|
||||
}
|
||||
request.onerror = {
|
||||
answer.completeExceptionally(Exception("Something went wrong: $it"))
|
||||
}
|
||||
request.open("POST", url, true)
|
||||
request.send(formData)
|
||||
|
||||
answer.invokeOnCompletion {
|
||||
runCatching {
|
||||
if (request.readyState != XMLHttpRequest.DONE) {
|
||||
request.abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return answer.await().also {
|
||||
subscope.cancel()
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@ plugins {
|
||||
id "com.android.library"
|
||||
}
|
||||
|
||||
apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
apply from: "$mppJvmJsWasmJsAndroidLinuxMingwLinuxArm64Project"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
|
@@ -0,0 +1,7 @@
|
||||
package dev.inmo.micro_utils.ktor.common
|
||||
|
||||
import dev.inmo.micro_utils.common.*
|
||||
import io.ktor.utils.io.core.ByteReadPacket
|
||||
import io.ktor.utils.io.core.Input
|
||||
|
||||
actual fun MPPFile.input(): Input = ByteReadPacket(readBytes())
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user