mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00:22 +00:00 
			
		
		
		
	Compare commits
	
		
			85 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fce47897d5 | |||
| 0b701a3e99 | |||
| 9dad353957 | |||
| 89e16b7bdb | |||
| c2965da341 | |||
| ffb072dc5f | |||
| a247dbcb02 | |||
| 1dd71175f4 | |||
| bbe62c0e7b | |||
| 9822ff321b | |||
| 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 | |||
| b1a96b6ecb | |||
| 66dac2086c | |||
| e269d0d206 | |||
| 5d95c3eb9c | |||
| 26650e9b6c | |||
| 7339dd8354 | |||
| 8ae983971a | 
							
								
								
									
										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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,5 +1,109 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
## 0.26.7
 | 
			
		||||
 | 
			
		||||
## 0.26.6
 | 
			
		||||
 | 
			
		||||
* `Versions`:
 | 
			
		||||
    * `Ktor`: `3.3.0` -> `3.3.1`
 | 
			
		||||
    * `Okio`: `3.16.0` -> `3.16.2`
 | 
			
		||||
 | 
			
		||||
## 0.26.5
 | 
			
		||||
 | 
			
		||||
* `Versions`:
 | 
			
		||||
    * `Kotlin`: `2.2.10` -> `2.2.20`
 | 
			
		||||
    * `KSLog`: `1.5.0` -> `1.5.1`
 | 
			
		||||
    * `Ktor`: `3.2.3` -> `3.3.0`
 | 
			
		||||
    * `KotlinX Browser`: `0.3` -> `0.5.0`
 | 
			
		||||
    * `Koin`: `4.1.0` -> `4.1.1`
 | 
			
		||||
 | 
			
		||||
## 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`:
 | 
			
		||||
  * `Ktor`: `3.1.1` -> `3.1.2`
 | 
			
		||||
  * `Koin`: `4.0.2` -> `4.0.4`
 | 
			
		||||
* `Coroutines`:
 | 
			
		||||
  * Add `SmartKeyRWLocker.withWriteLocks` extension with vararg keys
 | 
			
		||||
* `Transactions`:
 | 
			
		||||
  * Fix order of rollback actions calling
 | 
			
		||||
 | 
			
		||||
## 0.25.3
 | 
			
		||||
 | 
			
		||||
* `Coroutines`:
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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>
 | 
			
		||||
@@ -221,4 +221,6 @@ suspend inline fun <T, R> SmartKeyRWLocker<T>.withWriteLocks(keys: Iterable<T>,
 | 
			
		||||
            unlockWrite(it)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
suspend inline fun <T, R> SmartKeyRWLocker<T>.withWriteLocks(vararg keys: T, action: () -> R): R = withWriteLocks(keys.asIterable(), action)
 | 
			
		||||
 
 | 
			
		||||
@@ -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.3
 | 
			
		||||
android_code_version=293
 | 
			
		||||
version=0.26.7
 | 
			
		||||
android_code_version=306
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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,50 @@
 | 
			
		||||
[versions]
 | 
			
		||||
 | 
			
		||||
kt = "2.1.20"
 | 
			
		||||
kt-serialization = "1.8.0"
 | 
			
		||||
kt-coroutines = "1.10.1"
 | 
			
		||||
kt = "2.2.20"
 | 
			
		||||
kt-serialization = "1.9.0"
 | 
			
		||||
kt-coroutines = "1.10.2"
 | 
			
		||||
 | 
			
		||||
kslog = "1.4.1"
 | 
			
		||||
kotlinx-browser = "0.5.0"
 | 
			
		||||
 | 
			
		||||
jb-compose = "1.7.3"
 | 
			
		||||
jb-exposed = "0.60.0"
 | 
			
		||||
jb-dokka = "2.0.0"
 | 
			
		||||
kslog = "1.5.1"
 | 
			
		||||
 | 
			
		||||
sqlite = "3.49.1.0"
 | 
			
		||||
jb-compose = "1.8.2"
 | 
			
		||||
jb-exposed = "0.61.0"
 | 
			
		||||
jb-dokka = "2.1.0"
 | 
			
		||||
 | 
			
		||||
# 3.50.3.0 contains bug https://github.com/InsanusMokrassar/MicroUtils/actions/runs/18138301958/job/51629588088
 | 
			
		||||
sqlite = "3.50.1.0"
 | 
			
		||||
 | 
			
		||||
korlibs = "5.4.0"
 | 
			
		||||
uuid = "0.8.4"
 | 
			
		||||
 | 
			
		||||
ktor = "3.1.1"
 | 
			
		||||
ktor = "3.3.1"
 | 
			
		||||
 | 
			
		||||
gh-release = "2.5.2"
 | 
			
		||||
 | 
			
		||||
koin = "4.0.2"
 | 
			
		||||
koin = "4.1.1"
 | 
			
		||||
 | 
			
		||||
okio = "3.10.2"
 | 
			
		||||
okio = "3.16.2"
 | 
			
		||||
 | 
			
		||||
ksp = "2.1.20-1.0.31"
 | 
			
		||||
kotlin-poet = "1.18.1"
 | 
			
		||||
ksp = "2.2.20-2.0.3"
 | 
			
		||||
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 +59,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 +125,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.14.3-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 {
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user