mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-10-31 04:05:32 +00:00 
			
		
		
		
	Compare commits
	
		
			3 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ccc1dd7857 | |||
| 5d450e0632 | |||
| cd3838f321 | 
							
								
								
									
										2
									
								
								.github/workflows/packages_push.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/packages_push.yml
									
									
									
									
										vendored
									
									
								
							| @@ -22,7 +22,7 @@ jobs: | |||||||
|         run: ./gradlew build |         run: ./gradlew build | ||||||
|       - name: Publish |       - name: Publish | ||||||
|         continue-on-error: true |         continue-on-error: true | ||||||
|         run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository |         run: ./gradlew --no-parallel publishAllPublicationsToGithubPackagesRepository -x signJsPublication -x signJvmPublication -x signKotlinMultiplatformPublication -x signAndroidDebugPublication -x signAndroidReleasePublication -x signKotlinMultiplatformPublication | ||||||
|         env: |         env: | ||||||
|           GITHUBPACKAGES_USER: ${{ github.actor }} |           GITHUBPACKAGES_USER: ${{ github.actor }} | ||||||
|           GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }} |           GITHUBPACKAGES_PASSWORD: ${{ secrets.GITHUB_TOKEN }} | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,71 +1,5 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
| ## 0.9.13 |  | ||||||
|  |  | ||||||
| * `Versions`: |  | ||||||
|     * `Compose`: `1.1.0` -> `1.1.1` |  | ||||||
|  |  | ||||||
| ## 0.9.12 |  | ||||||
|  |  | ||||||
| * `Common`: |  | ||||||
|     * `JS`: |  | ||||||
|         * New function `openLink` |  | ||||||
|         * New function `selectFile` |  | ||||||
|         * New function `triggerDownloadFile` |  | ||||||
|     * `Compose`: |  | ||||||
|         * Created :) |  | ||||||
|         * `Common`: |  | ||||||
|             * `DefaultDisposableEffectResult` as a default realization of `DisposableEffectResult` |  | ||||||
|         * `JS`: |  | ||||||
|             * `openLink` on top of `openLink` with `String` target from common |  | ||||||
| * `Coroutines`: |  | ||||||
|     * `Compose`: |  | ||||||
|         * `Common`: |  | ||||||
|             * New extension `Flow.toMutableState` |  | ||||||
|             * New extension `StateFlow.toMutableState` |  | ||||||
|         * `JS`: |  | ||||||
|             * New function `selectFileOrThrow` on top of `selectFile` from `common` |  | ||||||
|             * New function `selectFileOrNull` on top of `selectFile` from `common` |  | ||||||
|  |  | ||||||
| ## 0.9.11 |  | ||||||
|  |  | ||||||
| * `Versions`: |  | ||||||
|     * `Klock`: `2.6.1` -> `2.6.2` |  | ||||||
| * `Coroutines`: |  | ||||||
|     * `Compose`: |  | ||||||
|         * Created :) |  | ||||||
|         * New extensions and function: |  | ||||||
|             * `Composition#linkWithJob` |  | ||||||
|             * `Composition#linkWithContext` |  | ||||||
|             * `renderComposableAndLinkToContext` |  | ||||||
|  |  | ||||||
| ## 0.9.10 |  | ||||||
|  |  | ||||||
| * `Versions`: |  | ||||||
|     * `Klock`: `2.5.2` -> `2.6.1` |  | ||||||
| * Ktor: |  | ||||||
|     * Client: |  | ||||||
|         * New function `UnifiedRequester#createStandardWebsocketFlow` without `checkReconnection` arg |  | ||||||
|     * Server: |  | ||||||
|         * Now it is possible to filter data in `Route#includeWebsocketHandling` |  | ||||||
|         * Callback in `Route#includeWebsocketHandling` and dependent methods is `suspend` since now |  | ||||||
|         * Add `URLProtocol` support in `Route#includeWebsocketHandling` and dependent methods |  | ||||||
|  |  | ||||||
| ## 0.9.9 |  | ||||||
|  |  | ||||||
| * `Versions`: |  | ||||||
|     * `Klock`: `2.5.1` -> `2.5.2` |  | ||||||
| * `Common`: |  | ||||||
|     * Add new diff tool - `applyDiff` |  | ||||||
|     * Implementation of `IntersectionObserver` in JS part (copypaste of [this](https://youtrack.jetbrains.com/issue/KT-43157#focus=Comments-27-4498582.0-0) comment) |  | ||||||
|  |  | ||||||
| ## 0.9.8 |  | ||||||
|  |  | ||||||
| * `Versions`: |  | ||||||
|     * `Exposed`: `0.37.2` -> `0.37.3` |  | ||||||
|     * `Klock`: `2.4.13` -> `2.5.1` |  | ||||||
|     * `AppCompat`: `1.4.0` -> `1.4.1` |  | ||||||
|  |  | ||||||
| ## 0.9.7 | ## 0.9.7 | ||||||
|  |  | ||||||
| * `Repos`: | * `Repos`: | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ kotlin { | |||||||
|     sourceSets { |     sourceSets { | ||||||
|         androidMain { |         androidMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.android.appCompat.resources |                 api "androidx.appcompat:appcompat-resources:$appcompat_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -10,13 +10,13 @@ kotlin { | |||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.kt.coroutines |                 api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" | ||||||
|                 api project(":micro_utils.common") |                 api project(":micro_utils.common") | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         androidMain { |         androidMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.android.recyclerView |                 api "androidx.recyclerview:recyclerview:$androidx_recycler_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								build.gradle
									
									
									
									
									
								
							| @@ -7,12 +7,12 @@ buildscript { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     dependencies { |     dependencies { | ||||||
|         classpath libs.buildscript.kt.gradle |         classpath 'com.android.tools.build:gradle:7.0.4' | ||||||
|         classpath libs.buildscript.kt.serialization |         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||||||
|         classpath libs.buildscript.jb.dokka |         classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" | ||||||
|         classpath libs.buildscript.gh.release |         classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:$dexcount_version" | ||||||
|         classpath libs.buildscript.android.gradle |         classpath "com.github.breadmoirai:github-release:$github_release_plugin_version" | ||||||
|         classpath libs.buildscript.android.dexcount |         classpath "org.jetbrains.dokka:dokka-gradle-plugin:$dokka_version" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,18 +0,0 @@ | |||||||
| plugins { |  | ||||||
|     id "org.jetbrains.kotlin.multiplatform" |  | ||||||
|     id "org.jetbrains.kotlin.plugin.serialization" |  | ||||||
|     id "com.android.library" |  | ||||||
|     alias(libs.plugins.jb.compose) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| apply from: "$mppProjectWithSerializationAndComposePresetPath" |  | ||||||
|  |  | ||||||
| kotlin { |  | ||||||
|     sourceSets { |  | ||||||
|         commonMain { |  | ||||||
|             dependencies { |  | ||||||
|                 api project(":micro_utils.common") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.common.compose |  | ||||||
|  |  | ||||||
| import androidx.compose.runtime.DisposableEffectResult |  | ||||||
|  |  | ||||||
| class DefaultDisposableEffectResult( |  | ||||||
|     private val onDispose: () -> Unit |  | ||||||
| ) : DisposableEffectResult { |  | ||||||
|     override fun dispose() { |  | ||||||
|         onDispose() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     companion object { |  | ||||||
|         val DoNothing = DefaultDisposableEffectResult {} |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.common.compose |  | ||||||
|  |  | ||||||
| import org.jetbrains.compose.web.attributes.ATarget |  | ||||||
|  |  | ||||||
| fun openLink(link: String, mode: ATarget = ATarget.Blank, features: String = "") = dev.inmo.micro_utils.common.openLink( |  | ||||||
|     link, |  | ||||||
|     mode.targetStr, |  | ||||||
|     features |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| <manifest package="dev.inmo.micro_utils.common.compose"/> |  | ||||||
| @@ -153,22 +153,3 @@ inline fun <T> StrictDiff(old: Iterable<T>, new: Iterable<T>) = old.calculateDif | |||||||
| inline fun <T> Iterable<T>.calculateStrictDiff( | inline fun <T> Iterable<T>.calculateStrictDiff( | ||||||
|     other: Iterable<T> |     other: Iterable<T> | ||||||
| ) = calculateDiff(other, strictComparison = true) | ) = calculateDiff(other, strictComparison = true) | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * This method call [calculateDiff] with strict mode [strictComparison] and then apply differences to [this] |  | ||||||
|  * mutable list |  | ||||||
|  */ |  | ||||||
| fun <T> MutableList<T>.applyDiff( |  | ||||||
|     source: Iterable<T>, |  | ||||||
|     strictComparison: Boolean = false |  | ||||||
| ) = calculateDiff(source, strictComparison).let { |  | ||||||
|     for (i in it.removed.indices.sortedDescending()) { |  | ||||||
|         removeAt(it.removed[i].index) |  | ||||||
|     } |  | ||||||
|     it.added.forEach { (i, t) -> |  | ||||||
|         add(i, t) |  | ||||||
|     } |  | ||||||
|     it.replaced.forEach { (_, new) -> |  | ||||||
|         set(new.index, new.value) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ class DiffUtilsTests { | |||||||
|         val oldList = (0 until 10).map { it.toString() } |         val oldList = (0 until 10).map { it.toString() } | ||||||
|         val withIndex = oldList.withIndex() |         val withIndex = oldList.withIndex() | ||||||
|  |  | ||||||
|         for (step in oldList.indices) { |         for (step in 0 until oldList.size) { | ||||||
|             for ((i, v) in withIndex) { |             for ((i, v) in withIndex) { | ||||||
|                 val mutable = oldList.toMutableList() |                 val mutable = oldList.toMutableList() | ||||||
|                 val changes = ( |                 val changes = ( | ||||||
| @@ -73,78 +73,4 @@ class DiffUtilsTests { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Test |  | ||||||
|     fun testThatSimpleRemoveApplyWorks() { |  | ||||||
|         val oldList = (0 until 10).toList() |  | ||||||
|         val withIndex = oldList.withIndex() |  | ||||||
|  |  | ||||||
|         for (count in 1 .. (floor(oldList.size.toFloat() / 2).toInt())) { |  | ||||||
|             for ((i, _) in withIndex) { |  | ||||||
|                 if (i + count > oldList.lastIndex) { |  | ||||||
|                     continue |  | ||||||
|                 } |  | ||||||
|                 val removedSublist = oldList.subList(i, i + count) |  | ||||||
|                 val mutableOldList = oldList.toMutableList() |  | ||||||
|                 val targetList = oldList - removedSublist |  | ||||||
|  |  | ||||||
|                 mutableOldList.applyDiff(targetList) |  | ||||||
|  |  | ||||||
|                 assertEquals( |  | ||||||
|                     targetList, |  | ||||||
|                     mutableOldList |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Test |  | ||||||
|     fun testThatSimpleAddApplyWorks() { |  | ||||||
|         val oldList = (0 until 10).map { it.toString() } |  | ||||||
|         val withIndex = oldList.withIndex() |  | ||||||
|  |  | ||||||
|         for (count in 1 .. (floor(oldList.size.toFloat() / 2).toInt())) { |  | ||||||
|             for ((i, v) in withIndex) { |  | ||||||
|                 if (i + count > oldList.lastIndex) { |  | ||||||
|                     continue |  | ||||||
|                 } |  | ||||||
|                 val addedSublist = oldList.subList(i, i + count).map { "added$it" } |  | ||||||
|                 val mutable = oldList.toMutableList() |  | ||||||
|                 mutable.addAll(i, addedSublist) |  | ||||||
|                 val mutableOldList = oldList.toMutableList() |  | ||||||
|  |  | ||||||
|                 mutableOldList.applyDiff(mutable) |  | ||||||
|  |  | ||||||
|                 assertEquals( |  | ||||||
|                     mutable, |  | ||||||
|                     mutableOldList |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Test |  | ||||||
|     fun testThatSimpleChangesApplyWorks() { |  | ||||||
|         val oldList = (0 until 10).map { it.toString() } |  | ||||||
|         val withIndex = oldList.withIndex() |  | ||||||
|  |  | ||||||
|         for (step in oldList.indices) { |  | ||||||
|             for ((i, v) in withIndex) { |  | ||||||
|                 val mutable = oldList.toMutableList() |  | ||||||
|                 val changes = ( |  | ||||||
|                     if (step == 0) i until oldList.size else (i until oldList.size step step) |  | ||||||
|                 ).map { index -> |  | ||||||
|                     IndexedValue(index, mutable[index]) to IndexedValue(index, "changed$index").also { |  | ||||||
|                         mutable[index] = it.value |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 val mutableOldList = oldList.toMutableList() |  | ||||||
|                 mutableOldList.applyDiff(mutable) |  | ||||||
|                 assertEquals( |  | ||||||
|                     mutable, |  | ||||||
|                     mutableOldList |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,124 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.common |  | ||||||
|  |  | ||||||
| import org.w3c.dom.DOMRectReadOnly |  | ||||||
| import org.w3c.dom.Element |  | ||||||
|  |  | ||||||
| external interface IntersectionObserverOptions { |  | ||||||
|     /** |  | ||||||
|      * 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: Array<Number>? |  | ||||||
| } |  | ||||||
| fun IntersectionObserverOptions( |  | ||||||
|     block: IntersectionObserverOptions.() -> Unit = {} |  | ||||||
| ): IntersectionObserverOptions = js("{}").unsafeCast<IntersectionObserverOptions>().apply(block) |  | ||||||
|  |  | ||||||
| external interface IntersectionObserverEntry { |  | ||||||
|     /** |  | ||||||
|      * 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: Number |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 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: Array<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) { |  | ||||||
|     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: Array<Number> |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 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(): Array<IntersectionObserverEntry> |  | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * Tells the IntersectionObserver to stop observing a particular target element. |  | ||||||
|      */ |  | ||||||
|     fun unobserve(targetElement: Element) |  | ||||||
| } |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| 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() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,30 +0,0 @@ | |||||||
| 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() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| 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() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| @@ -10,17 +10,12 @@ kotlin { | |||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.kt.coroutines |                 api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         jsMain { |  | ||||||
|             dependencies { |  | ||||||
|                 api project(":micro_utils.common") |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         androidMain { |         androidMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.kt.coroutines.android |                 api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,19 +0,0 @@ | |||||||
| plugins { |  | ||||||
|     id "org.jetbrains.kotlin.multiplatform" |  | ||||||
|     id "org.jetbrains.kotlin.plugin.serialization" |  | ||||||
|     id "com.android.library" |  | ||||||
|     alias(libs.plugins.jb.compose) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| apply from: "$mppProjectWithSerializationAndComposePresetPath" |  | ||||||
|  |  | ||||||
| kotlin { |  | ||||||
|     sourceSets { |  | ||||||
|         commonMain { |  | ||||||
|             dependencies { |  | ||||||
|                 api libs.kt.coroutines |  | ||||||
|                 api project(":micro_utils.coroutines") |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.coroutines.compose |  | ||||||
|  |  | ||||||
| import androidx.compose.runtime.MutableState |  | ||||||
| import androidx.compose.runtime.mutableStateOf |  | ||||||
| import dev.inmo.micro_utils.coroutines.subscribeSafelyWithoutExceptions |  | ||||||
| import kotlinx.coroutines.CoroutineScope |  | ||||||
| import kotlinx.coroutines.flow.Flow |  | ||||||
| import kotlinx.coroutines.flow.StateFlow |  | ||||||
|  |  | ||||||
| fun <T> Flow<T>.toMutableState( |  | ||||||
|     initial: T, |  | ||||||
|     scope: CoroutineScope |  | ||||||
| ): MutableState<T> { |  | ||||||
|     val state = mutableStateOf(initial) |  | ||||||
|     subscribeSafelyWithoutExceptions(scope) { state.value = it } |  | ||||||
|     return state |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline fun <T> StateFlow<T>.toMutableState( |  | ||||||
|     scope: CoroutineScope |  | ||||||
| ): MutableState<T> = toMutableState(value, scope) |  | ||||||
|  |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.coroutines.compose |  | ||||||
|  |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import kotlinx.coroutines.Job |  | ||||||
| import kotlinx.coroutines.job |  | ||||||
| import kotlin.coroutines.CoroutineContext |  | ||||||
|  |  | ||||||
| fun Composition.linkWithJob(job: Job) { |  | ||||||
|     job.invokeOnCompletion { |  | ||||||
|         this@linkWithJob.dispose() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| fun Composition.linkWithContext(coroutineContext: CoroutineContext) = linkWithJob(coroutineContext.job) |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.coroutines.compose |  | ||||||
|  |  | ||||||
| import androidx.compose.runtime.* |  | ||||||
| import kotlinx.coroutines.* |  | ||||||
| import org.jetbrains.compose.web.dom.DOMScope |  | ||||||
| import org.w3c.dom.Element |  | ||||||
|  |  | ||||||
| suspend fun <TElement : Element> renderComposableAndLinkToContext( |  | ||||||
|     root: TElement, |  | ||||||
|     monotonicFrameClock: MonotonicFrameClock = DefaultMonotonicFrameClock, |  | ||||||
|     content: @Composable DOMScope<TElement>.() -> Unit |  | ||||||
| ): Composition = org.jetbrains.compose.web.renderComposable(root, monotonicFrameClock, content).apply { |  | ||||||
|     linkWithContext( |  | ||||||
|         currentCoroutineContext() |  | ||||||
|     ) |  | ||||||
| } |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| <manifest package="dev.inmo.micro_utils.coroutines.compose"/> |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| package dev.inmo.micro_utils.coroutines |  | ||||||
|  |  | ||||||
| import dev.inmo.micro_utils.common.MPPFile |  | ||||||
| import dev.inmo.micro_utils.common.selectFile |  | ||||||
| import kotlinx.coroutines.CompletableDeferred |  | ||||||
| import org.w3c.dom.HTMLInputElement |  | ||||||
|  |  | ||||||
| suspend fun selectFileOrThrow( |  | ||||||
|     inputSetup: (HTMLInputElement) -> Unit = {} |  | ||||||
| ): MPPFile { |  | ||||||
|     val result = CompletableDeferred<MPPFile>() |  | ||||||
|  |  | ||||||
|     selectFile( |  | ||||||
|         inputSetup, |  | ||||||
|         { |  | ||||||
|             result.completeExceptionally(it) |  | ||||||
|         } |  | ||||||
|     ) { |  | ||||||
|         result.complete(it) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return result.await() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| suspend fun selectFileOrNull( |  | ||||||
|     inputSetup: (HTMLInputElement) -> Unit = {}, |  | ||||||
|     onFailure: (Throwable) -> Unit = {} |  | ||||||
| ): MPPFile? { |  | ||||||
|     val result = CompletableDeferred<MPPFile?>() |  | ||||||
|  |  | ||||||
|     selectFile( |  | ||||||
|         inputSetup, |  | ||||||
|         { |  | ||||||
|             result.complete(null) |  | ||||||
|             onFailure(it) |  | ||||||
|         } |  | ||||||
|     ) { |  | ||||||
|         result.complete(it) |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return result.await() |  | ||||||
| } |  | ||||||
| @@ -26,12 +26,12 @@ ext { | |||||||
| } | } | ||||||
|  |  | ||||||
| android { | android { | ||||||
|     compileSdkVersion libs.versions.android.props.compileSdk.get().toInteger() |     compileSdkVersion "$android_compileSdkVersion".toInteger() | ||||||
|     buildToolsVersion libs.versions.android.props.buildTools.get() |     buildToolsVersion "$android_buildToolsVersion" | ||||||
|  |  | ||||||
|     defaultConfig { |     defaultConfig { | ||||||
|         minSdkVersion libs.versions.android.props.minSdk.get().toInteger() |         minSdkVersion "$android_minSdkVersion".toInteger() | ||||||
|         targetSdkVersion libs.versions.android.props.compileSdk.get().toInteger() |         targetSdkVersion "$android_compileSdkVersion".toInteger() | ||||||
|         versionCode "${android_code_version}".toInteger() |         versionCode "${android_code_version}".toInteger() | ||||||
|         versionName "$version" |         versionName "$version" | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -21,7 +21,6 @@ allprojects { | |||||||
|         releaseMode = (project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true" |         releaseMode = (project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true" | ||||||
|  |  | ||||||
|         mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle" |         mppProjectWithSerializationPresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerialization.gradle" | ||||||
|         mppProjectWithSerializationAndComposePresetPath = "${rootProject.projectDir.absolutePath}/mppProjectWithSerializationAndCompose.gradle" |  | ||||||
|         mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle" |         mppJavaProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppJavaProject.gradle" | ||||||
|         mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle" |         mppAndroidProjectPresetPath = "${rootProject.projectDir.absolutePath}/mppAndroidProject.gradle" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,12 +7,43 @@ android.useAndroidX=true | |||||||
| android.enableJetifier=true | android.enableJetifier=true | ||||||
| org.gradle.jvmargs=-Xmx2g | org.gradle.jvmargs=-Xmx2g | ||||||
|  |  | ||||||
|  | kotlin_version=1.6.10 | ||||||
|  | kotlin_coroutines_version=1.6.0 | ||||||
|  | kotlin_serialisation_core_version=1.3.2 | ||||||
|  | kotlin_exposed_version=0.37.2 | ||||||
|  |  | ||||||
|  | ktor_version=1.6.7 | ||||||
|  |  | ||||||
|  | klockVersion=2.4.13 | ||||||
|  |  | ||||||
|  | github_release_plugin_version=2.2.12 | ||||||
|  |  | ||||||
|  | uuidVersion=0.4.0 | ||||||
|  |  | ||||||
|  | # ANDROID | ||||||
|  |  | ||||||
|  | core_ktx_version=1.7.0 | ||||||
|  | androidx_recycler_version=1.2.1 | ||||||
|  | appcompat_version=1.4.0 | ||||||
|  |  | ||||||
|  | android_minSdkVersion=19 | ||||||
|  | android_compileSdkVersion=32 | ||||||
|  | android_buildToolsVersion=32.0.0 | ||||||
|  | dexcount_version=3.0.1 | ||||||
|  | junit_version=4.12 | ||||||
|  | test_ext_junit_version=1.1.2 | ||||||
|  | espresso_core=3.3.0 | ||||||
|  |  | ||||||
| # JS NPM | # JS NPM | ||||||
|  |  | ||||||
| crypto_js_version=4.1.1 | crypto_js_version=4.1.1 | ||||||
|  |  | ||||||
|  | # Dokka | ||||||
|  |  | ||||||
|  | dokka_version=1.6.10 | ||||||
|  |  | ||||||
| # Project data | # Project data | ||||||
|  |  | ||||||
| group=dev.inmo | group=dev.inmo | ||||||
| version=0.9.13 | version=0.9.7 | ||||||
| android_code_version=103 | android_code_version=97 | ||||||
|   | |||||||
| @@ -1,77 +0,0 @@ | |||||||
| [versions] |  | ||||||
|  |  | ||||||
| kt = "1.6.10" |  | ||||||
| kt-serialization = "1.3.2" |  | ||||||
| kt-coroutines = "1.6.0" |  | ||||||
|  |  | ||||||
| jb-compose = "1.1.1" |  | ||||||
| jb-exposed = "0.37.3" |  | ||||||
| jb-dokka = "1.6.10" |  | ||||||
|  |  | ||||||
| klock = "2.6.2" |  | ||||||
| uuid = "0.4.0" |  | ||||||
|  |  | ||||||
| ktor = "1.6.7" |  | ||||||
|  |  | ||||||
| gh-release = "2.2.12" |  | ||||||
|  |  | ||||||
| android-gradle = "7.0.4" |  | ||||||
| dexcount = "3.0.1" |  | ||||||
|  |  | ||||||
| android-coreKtx = "1.7.0" |  | ||||||
| android-recyclerView = "1.2.1" |  | ||||||
| android-appCompat = "1.4.1" |  | ||||||
| android-espresso = "3.3.0" |  | ||||||
| android-test = "1.1.2" |  | ||||||
|  |  | ||||||
| android-props-minSdk = "19" |  | ||||||
| android-props-compileSdk = "32" |  | ||||||
| android-props-buildTools = "32.0.0" |  | ||||||
|  |  | ||||||
| [libraries] |  | ||||||
|  |  | ||||||
| kt-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kt" } |  | ||||||
|  |  | ||||||
| kt-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kt-serialization" } |  | ||||||
| kt-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-cbor", version.ref = "kt-serialization" } |  | ||||||
|  |  | ||||||
| kt-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kt-coroutines" } |  | ||||||
| kt-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kt-coroutines" } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ktor-client = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } |  | ||||||
| ktor-client-java = { module = "io.ktor:ktor-client-java", version.ref = "ktor" } |  | ||||||
| ktor-server = { module = "io.ktor:ktor-server", version.ref = "ktor" } |  | ||||||
| ktor-server-cio = { module = "io.ktor:ktor-server-cio", version.ref = "ktor" } |  | ||||||
| ktor-server-host-common = { module = "io.ktor:ktor-server-host-common", version.ref = "ktor" } |  | ||||||
| ktor-websockets = { module = "io.ktor:ktor-websockets", version.ref = "ktor" } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" } |  | ||||||
| uuid = { module = "com.benasher44:uuid", version.ref = "uuid" } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| jb-exposed = { module = "org.jetbrains.exposed:exposed-core", version.ref = "jb-exposed" } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "android-coreKtx" } |  | ||||||
| android-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "android-recyclerView" } |  | ||||||
| android-appCompat-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "android-appCompat" } |  | ||||||
| android-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "android-espresso" } |  | ||||||
| android-test-junit = { module = "androidx.test.ext:junit", version.ref = "android-test" } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| kt-test-js = { module = "org.jetbrains.kotlin:kotlin-test-js", version.ref = "kt" } |  | ||||||
| kt-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kt" } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| buildscript-kt-gradle = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kt" } |  | ||||||
| buildscript-kt-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kt" } |  | ||||||
| buildscript-jb-dokka = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "jb-dokka" } |  | ||||||
| buildscript-gh-release = { module = "com.github.breadmoirai:github-release", version.ref = "gh-release" } |  | ||||||
| buildscript-android-gradle = { module = "com.android.tools.build:gradle", version.ref = "android-gradle" } |  | ||||||
| buildscript-android-dexcount = { module = "com.getkeepsafe.dexcount:dexcount-gradle-plugin", version.ref = "dexcount" } |  | ||||||
|  |  | ||||||
| [plugins] |  | ||||||
|  |  | ||||||
| jb-compose = { id = "org.jetbrains.compose", version.ref = "jb-compose" } |  | ||||||
							
								
								
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								gradle/wrapper/gradle-wrapper.properties
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| distributionBase=GRADLE_USER_HOME | distributionBase=GRADLE_USER_HOME | ||||||
| distributionPath=wrapper/dists | distributionPath=wrapper/dists | ||||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip | ||||||
| zipStoreBase=GRADLE_USER_HOME | zipStoreBase=GRADLE_USER_HOME | ||||||
| zipStorePath=wrapper/dists | zipStorePath=wrapper/dists | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ kotlin { | |||||||
|             dependencies { |             dependencies { | ||||||
|                 api internalProject("micro_utils.ktor.common") |                 api internalProject("micro_utils.ktor.common") | ||||||
|                 api internalProject("micro_utils.coroutines") |                 api internalProject("micro_utils.coroutines") | ||||||
|                 api libs.ktor.client |                 api "io.ktor:ktor-client-core:$ktor_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -4,7 +4,6 @@ import dev.inmo.micro_utils.coroutines.safely | |||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import io.ktor.client.HttpClient | import io.ktor.client.HttpClient | ||||||
| import io.ktor.client.features.websocket.ws | import io.ktor.client.features.websocket.ws | ||||||
| import io.ktor.client.request.HttpRequestBuilder |  | ||||||
| import io.ktor.http.cio.websocket.Frame | import io.ktor.http.cio.websocket.Frame | ||||||
| import io.ktor.http.cio.websocket.readBytes | import io.ktor.http.cio.websocket.readBytes | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| @@ -18,7 +17,6 @@ import kotlinx.serialization.DeserializationStrategy | |||||||
| inline fun <T> HttpClient.createStandardWebsocketFlow( | inline fun <T> HttpClient.createStandardWebsocketFlow( | ||||||
|     url: String, |     url: String, | ||||||
|     crossinline checkReconnection: (Throwable?) -> Boolean = { true }, |     crossinline checkReconnection: (Throwable?) -> Boolean = { true }, | ||||||
|     noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}, |  | ||||||
|     crossinline conversation: suspend (StandardKtorSerialInputData) -> T |     crossinline conversation: suspend (StandardKtorSerialInputData) -> T | ||||||
| ): Flow<T> { | ): Flow<T> { | ||||||
|     val correctedUrl = url.asCorrectWebSocketUrl |     val correctedUrl = url.asCorrectWebSocketUrl | ||||||
| @@ -28,7 +26,7 @@ inline fun <T> HttpClient.createStandardWebsocketFlow( | |||||||
|         do { |         do { | ||||||
|             val reconnect = try { |             val reconnect = try { | ||||||
|                 safely { |                 safely { | ||||||
|                     ws(correctedUrl, requestBuilder) { |                     ws(correctedUrl) { | ||||||
|                         for (received in incoming) { |                         for (received in incoming) { | ||||||
|                             when (received) { |                             when (received) { | ||||||
|                                 is Frame.Binary -> producerScope.send(conversation(received.readBytes())) |                                 is Frame.Binary -> producerScope.send(conversation(received.readBytes())) | ||||||
| @@ -67,12 +65,10 @@ inline fun <T> HttpClient.createStandardWebsocketFlow( | |||||||
|     url: String, |     url: String, | ||||||
|     crossinline checkReconnection: (Throwable?) -> Boolean = { true }, |     crossinline checkReconnection: (Throwable?) -> Boolean = { true }, | ||||||
|     deserializer: DeserializationStrategy<T>, |     deserializer: DeserializationStrategy<T>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat | ||||||
|     noinline requestBuilder: HttpRequestBuilder.() -> Unit = {}, |  | ||||||
| ) = createStandardWebsocketFlow( | ) = createStandardWebsocketFlow( | ||||||
|     url, |     url, | ||||||
|     checkReconnection, |     checkReconnection | ||||||
|     requestBuilder |  | ||||||
| ) { | ) { | ||||||
|     serialFormat.decodeDefault(deserializer, it) |     serialFormat.decodeDefault(deserializer, it) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -85,16 +85,9 @@ class UnifiedRequester( | |||||||
|  |  | ||||||
|     fun <T> createStandardWebsocketFlow( |     fun <T> createStandardWebsocketFlow( | ||||||
|         url: String, |         url: String, | ||||||
|         checkReconnection: (Throwable?) -> Boolean, |         checkReconnection: (Throwable?) -> Boolean = { true }, | ||||||
|         deserializer: DeserializationStrategy<T>, |         deserializer: DeserializationStrategy<T> | ||||||
|         requestBuilder: HttpRequestBuilder.() -> Unit = {}, |     ) = client.createStandardWebsocketFlow(url, checkReconnection, deserializer, serialFormat) | ||||||
|     ) = client.createStandardWebsocketFlow(url, checkReconnection, deserializer, serialFormat, requestBuilder) |  | ||||||
|  |  | ||||||
|     fun <T> createStandardWebsocketFlow( |  | ||||||
|         url: String, |  | ||||||
|         deserializer: DeserializationStrategy<T>, |  | ||||||
|         requestBuilder: HttpRequestBuilder.() -> Unit = {}, |  | ||||||
|     ) = createStandardWebsocketFlow(url, { true  }, deserializer, requestBuilder) |  | ||||||
| } | } | ||||||
|  |  | ||||||
| val defaultRequester = UnifiedRequester() | val defaultRequester = UnifiedRequester() | ||||||
|   | |||||||
| @@ -11,8 +11,8 @@ kotlin { | |||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api internalProject("micro_utils.common") |                 api internalProject("micro_utils.common") | ||||||
|                 api libs.kt.serialization.cbor |                 api "org.jetbrains.kotlinx:kotlinx-serialization-cbor:$kotlin_serialisation_core_version" | ||||||
|                 api libs.klock |                 api "com.soywiz.korlibs.klock:klock:$klockVersion" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -16,10 +16,10 @@ kotlin { | |||||||
|  |  | ||||||
|         jvmMain { |         jvmMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.ktor.server |                 api "io.ktor:ktor-server:$ktor_version" | ||||||
|                 api libs.ktor.server.cio |                 api "io.ktor:ktor-server-cio:$ktor_version" | ||||||
|                 api libs.ktor.server.host.common |                 api "io.ktor:ktor-server-host-common:$ktor_version" | ||||||
|                 api libs.ktor.websockets |                 api "io.ktor:ktor-websockets:$ktor_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -4,29 +4,25 @@ import dev.inmo.micro_utils.coroutines.safely | |||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import io.ktor.application.featureOrNull | import io.ktor.application.featureOrNull | ||||||
| import io.ktor.application.install | import io.ktor.application.install | ||||||
| import io.ktor.http.URLProtocol |  | ||||||
| import io.ktor.http.cio.websocket.* | import io.ktor.http.cio.websocket.* | ||||||
| import io.ktor.routing.Route | import io.ktor.routing.Route | ||||||
| import io.ktor.routing.application | import io.ktor.routing.application | ||||||
| import io.ktor.websocket.* | import io.ktor.websocket.webSocket | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.serialization.SerializationStrategy | import kotlinx.serialization.SerializationStrategy | ||||||
|  |  | ||||||
| fun <T> Route.includeWebsocketHandling( | fun <T> Route.includeWebsocketHandling( | ||||||
|     suburl: String, |     suburl: String, | ||||||
|     flow: Flow<T>, |     flow: Flow<T>, | ||||||
|     protocol: URLProtocol = URLProtocol.WS, |     converter: (T) -> StandardKtorSerialInputData | ||||||
|     converter: suspend WebSocketServerSession.(T) -> StandardKtorSerialInputData? |  | ||||||
| ) { | ) { | ||||||
|     application.apply { |     application.apply { | ||||||
|         featureOrNull(io.ktor.websocket.WebSockets) ?: install(io.ktor.websocket.WebSockets) |         featureOrNull(io.ktor.websocket.WebSockets) ?: install(io.ktor.websocket.WebSockets) | ||||||
|     } |     } | ||||||
|     webSocket(suburl, protocol.name) { |     webSocket(suburl) { | ||||||
|         safely { |         safely { | ||||||
|             flow.collect { |             flow.collect { | ||||||
|                 converter(it) ?.let { data -> |                 send(converter(it)) | ||||||
|                     send(data) |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -36,24 +32,10 @@ fun <T> Route.includeWebsocketHandling( | |||||||
|     suburl: String, |     suburl: String, | ||||||
|     flow: Flow<T>, |     flow: Flow<T>, | ||||||
|     serializer: SerializationStrategy<T>, |     serializer: SerializationStrategy<T>, | ||||||
|     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat, |     serialFormat: StandardKtorSerialFormat = standardKtorSerialFormat | ||||||
|     protocol: URLProtocol = URLProtocol.WS, |  | ||||||
|     filter: (suspend WebSocketServerSession.(T) -> Boolean)? = null |  | ||||||
| ) = includeWebsocketHandling( | ) = includeWebsocketHandling( | ||||||
|     suburl, |     suburl, | ||||||
|     flow, |     flow | ||||||
|     protocol, | ) { | ||||||
|     converter = if (filter == null) { |     serialFormat.encodeDefault(serializer, it) | ||||||
|         { | } | ||||||
|             serialFormat.encodeDefault(serializer, it) |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         { |  | ||||||
|             if (filter(it)) { |  | ||||||
|                 serialFormat.encodeDefault(serializer, it) |  | ||||||
|             } else { |  | ||||||
|                 null |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| ) |  | ||||||
|   | |||||||
| @@ -5,7 +5,8 @@ import dev.inmo.micro_utils.coroutines.safely | |||||||
| import dev.inmo.micro_utils.ktor.common.* | import dev.inmo.micro_utils.ktor.common.* | ||||||
| import io.ktor.application.ApplicationCall | import io.ktor.application.ApplicationCall | ||||||
| import io.ktor.application.call | import io.ktor.application.call | ||||||
| import io.ktor.http.* | import io.ktor.http.ContentType | ||||||
|  | import io.ktor.http.HttpStatusCode | ||||||
| import io.ktor.http.content.PartData | import io.ktor.http.content.PartData | ||||||
| import io.ktor.http.content.forEachPart | import io.ktor.http.content.forEachPart | ||||||
| import io.ktor.request.receive | import io.ktor.request.receive | ||||||
| @@ -17,7 +18,6 @@ import io.ktor.util.asStream | |||||||
| import io.ktor.util.cio.writeChannel | import io.ktor.util.cio.writeChannel | ||||||
| import io.ktor.util.pipeline.PipelineContext | import io.ktor.util.pipeline.PipelineContext | ||||||
| import io.ktor.utils.io.core.* | import io.ktor.utils.io.core.* | ||||||
| import io.ktor.websocket.WebSocketServerSession |  | ||||||
| import kotlinx.coroutines.flow.Flow | import kotlinx.coroutines.flow.Flow | ||||||
| import kotlinx.serialization.* | import kotlinx.serialization.* | ||||||
| import java.io.File | import java.io.File | ||||||
| @@ -30,10 +30,8 @@ class UnifiedRouter( | |||||||
|     fun <T> Route.includeWebsocketHandling( |     fun <T> Route.includeWebsocketHandling( | ||||||
|         suburl: String, |         suburl: String, | ||||||
|         flow: Flow<T>, |         flow: Flow<T>, | ||||||
|         serializer: SerializationStrategy<T>, |         serializer: SerializationStrategy<T> | ||||||
|         protocol: URLProtocol = URLProtocol.WS, |     ) = includeWebsocketHandling(suburl, flow, serializer, serialFormat) | ||||||
|         filter: (suspend WebSocketServerSession.(T) -> Boolean)? = null |  | ||||||
|     ) = includeWebsocketHandling(suburl, flow, serializer, serialFormat, protocol, filter) |  | ||||||
|  |  | ||||||
|     suspend fun <T> PipelineContext<*, ApplicationCall>.unianswer( |     suspend fun <T> PipelineContext<*, ApplicationCall>.unianswer( | ||||||
|         answerSerializer: SerializationStrategy<T>, |         answerSerializer: SerializationStrategy<T>, | ||||||
|   | |||||||
| @@ -4,8 +4,8 @@ buildscript { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     dependencies { |     dependencies { | ||||||
|         classpath libs.buildscript.kt.gradle |         classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" | ||||||
|         classpath libs.buildscript.kt.serialization |         classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -16,11 +16,11 @@ plugins { | |||||||
| } | } | ||||||
|  |  | ||||||
| dependencies { | dependencies { | ||||||
|     implementation libs.kt.stdlib |     implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" | ||||||
|     implementation libs.kt.serialization |     implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version" | ||||||
|  |  | ||||||
|     implementation libs.ktor.client |     implementation "io.ktor:ktor-client-core:$ktor_version" | ||||||
|     implementation libs.ktor.client.java |     implementation "io.ktor:ktor-client-java:$ktor_version" | ||||||
| } | } | ||||||
|  |  | ||||||
| mainClassName="MainKt" | mainClassName="MainKt" | ||||||
|   | |||||||
| @@ -23,7 +23,7 @@ kotlin { | |||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 implementation kotlin('stdlib') |                 implementation kotlin('stdlib') | ||||||
|                 implementation libs.kt.serialization |                 api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialisation_core_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         commonTest { |         commonTest { | ||||||
| @@ -46,8 +46,8 @@ kotlin { | |||||||
|         androidTest { |         androidTest { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 implementation kotlin('test-junit') |                 implementation kotlin('test-junit') | ||||||
|                 implementation libs.android.test.junit |                 implementation "androidx.test.ext:junit:$test_ext_junit_version" | ||||||
|                 implementation libs.android.espresso |                 implementation "androidx.test.espresso:espresso-core:$espresso_core" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,72 +0,0 @@ | |||||||
| project.version = "$version" |  | ||||||
| project.group = "$group" |  | ||||||
|  |  | ||||||
| apply from: "$publishGradlePath" |  | ||||||
|  |  | ||||||
| kotlin { |  | ||||||
|     jvm { |  | ||||||
|         compilations.main { |  | ||||||
|             kotlinOptions { |  | ||||||
|                 jvmTarget = "1.8" |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     js (IR) { |  | ||||||
|         browser() |  | ||||||
|         nodejs() |  | ||||||
|     } |  | ||||||
|     android { |  | ||||||
|         publishAllLibraryVariants() |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sourceSets { |  | ||||||
|         commonMain { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation kotlin('stdlib') |  | ||||||
|                 implementation libs.kt.serialization |  | ||||||
|                 implementation compose.runtime |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         commonTest { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation kotlin('test-common') |  | ||||||
|                 implementation kotlin('test-annotations-common') |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         jvmMain { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation compose.desktop.currentOs |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         jvmTest { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation kotlin('test-junit') |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         jsMain { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation compose.web.core |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         jsTest { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation kotlin('test-js') |  | ||||||
|                 implementation kotlin('test-junit') |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         androidTest { |  | ||||||
|             dependencies { |  | ||||||
|                 implementation kotlin('test-junit') |  | ||||||
|                 implementation libs.android.test.junit |  | ||||||
|                 implementation libs.android.espresso |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| apply from: "$defaultAndroidSettingsPresetPath" |  | ||||||
|  |  | ||||||
| java { |  | ||||||
|     sourceCompatibility = JavaVersion.VERSION_1_8 |  | ||||||
|     targetCompatibility = JavaVersion.VERSION_1_8 |  | ||||||
| } |  | ||||||
| @@ -14,7 +14,7 @@ kotlin { | |||||||
|         } |         } | ||||||
|         jvmMain { |         jvmMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.jb.exposed |                 api "org.jetbrains.exposed:exposed-core:$kotlin_exposed_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -15,8 +15,8 @@ kotlin { | |||||||
|  |  | ||||||
|         jvmMain { |         jvmMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.ktor.server |                 api "io.ktor:ktor-server:$ktor_version" | ||||||
|                 api libs.ktor.server.host.common |                 api "io.ktor:ktor-server-host-common:$ktor_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -10,10 +10,10 @@ kotlin { | |||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.kt.coroutines |                 api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" | ||||||
|                 api internalProject("micro_utils.pagination.common") |                 api internalProject("micro_utils.pagination.common") | ||||||
|  |  | ||||||
|                 api libs.uuid |                 api "com.benasher44:uuid:$uuidVersion" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -24,7 +24,7 @@ kotlin { | |||||||
|         } |         } | ||||||
|         androidMain { |         androidMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.android.coreKtx |                 api "androidx.core:core-ktx:$core_ktx_version" | ||||||
|                 api internalProject("micro_utils.common") |                 api internalProject("micro_utils.common") | ||||||
|                 api internalProject("micro_utils.coroutines") |                 api internalProject("micro_utils.coroutines") | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ kotlin { | |||||||
|     sourceSets { |     sourceSets { | ||||||
|         commonMain { |         commonMain { | ||||||
|             dependencies { |             dependencies { | ||||||
|                 api libs.kt.coroutines |                 api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ rootProject.name='micro_utils' | |||||||
|  |  | ||||||
| String[] includes = [ | String[] includes = [ | ||||||
|     ":common", |     ":common", | ||||||
|     ":common:compose", |  | ||||||
|     ":matrix", |     ":matrix", | ||||||
|     ":crypto", |     ":crypto", | ||||||
|     ":selector:common", |     ":selector:common", | ||||||
| @@ -24,7 +23,6 @@ String[] includes = [ | |||||||
|     ":ktor:common", |     ":ktor:common", | ||||||
|     ":ktor:client", |     ":ktor:client", | ||||||
|     ":coroutines", |     ":coroutines", | ||||||
|     ":coroutines:compose", |  | ||||||
|     ":android:recyclerview", |     ":android:recyclerview", | ||||||
|     ":android:alerts:common", |     ":android:alerts:common", | ||||||
|     ":android:alerts:recyclerview", |     ":android:alerts:recyclerview", | ||||||
| @@ -40,13 +38,11 @@ String[] includes = [ | |||||||
|  |  | ||||||
|  |  | ||||||
| includes.each { originalName -> | includes.each { originalName -> | ||||||
|     String projectDirectory = "${rootProject.projectDir.getAbsolutePath()}${originalName.replace(":", File.separator)}" |     String projectDirectory = "${rootProject.projectDir.getAbsolutePath()}${originalName.replaceAll(":", File.separator)}" | ||||||
|     String projectName = "${rootProject.name}${originalName.replace(":", ".")}" |     String projectName = "${rootProject.name}${originalName.replaceAll(":", ".")}" | ||||||
|     String projectIdentifier = ":${projectName}" |     String projectIdentifier = ":${projectName}" | ||||||
|     include projectIdentifier |     include projectIdentifier | ||||||
|     ProjectDescriptor project = project(projectIdentifier) |     ProjectDescriptor project = project(projectIdentifier) | ||||||
|     project.name = projectName |     project.name = projectName | ||||||
|     project.projectDir = new File(projectDirectory) |     project.projectDir = new File(projectDirectory) | ||||||
| } | } | ||||||
|  |  | ||||||
| enableFeaturePreview("VERSION_CATALOGS") |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user