mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 14:14:51 +00:00 
			
		
		
		
	Compare commits
	
		
			31 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| de999e197f | |||
| 9d95687d3c | |||
| aa9dfb4ab8 | |||
| 9c5b44efb3 | |||
| ac587a67e6 | |||
| 59428140a8 | |||
| 60bdb59d71 | |||
| be52871de8 | |||
| b7934cf357 | |||
| dbfbeef90a | |||
| 00943c9cdf | |||
| 8745c6a16a | |||
| 433ba4b58f | |||
| d40376e524 | |||
| a2982f88f5 | |||
| 1642f7abd9 | |||
| a10d2184ff | |||
| 522435f096 | |||
| 79b30290c0 | |||
| f8b8626859 | |||
| b061b85a08 | |||
| 3870db1c88 | |||
| 1be1070eb4 | |||
| 2696e663cf | |||
| 1e1f7df86d | |||
| 1d8ded8fd3 | |||
| 197825123a | |||
| 422b2e6db1 | |||
| 1973e0b5bf | |||
| 8258cf93a9 | |||
| 1d49bd5947 | 
							
								
								
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,5 +1,52 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.12.16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					  * `Android`:
 | 
				
			||||||
 | 
					    * Add class `FlowOnHierarchyChangeListener`
 | 
				
			||||||
 | 
					    * Add `ViewGroup#setOnHierarchyChangeListenerRecursively(OnHierarchyChangeListener)`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.12.15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Common`:
 | 
				
			||||||
 | 
					    * `applyDiff` will return `Diff` object since this release
 | 
				
			||||||
 | 
					    * `Android`:
 | 
				
			||||||
 | 
					      * New functions/extensions `findViewsByTag` and `findViewsByTagInActivity`
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					    * Add `Flow` extensions `flatMap`, `flatMapNotNull` and `flatten`
 | 
				
			||||||
 | 
					    * Add `Flow` extensions `takeNotNull` and `filterNotNull`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.12.14
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					  * `Android CoreKTX`: `1.8.0` -> `1.9.0`
 | 
				
			||||||
 | 
					  * `Android AppCompat`: `1.4.2` -> `1.5.1`
 | 
				
			||||||
 | 
					  * Android Compile SDK: 32 -> 33
 | 
				
			||||||
 | 
					  * Android Build Tools: 32.0.0 -> 33.0.0
 | 
				
			||||||
 | 
					* `Common`:
 | 
				
			||||||
 | 
					  * `Android`:
 | 
				
			||||||
 | 
					    * Add `argumentOrNull`/`argumentOrThrow` delegates for fragments
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					  * Rewrite `awaitFirstWithDeferred` onto `CompletableDeferred` instead of coroutines suspending
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.12.13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					  * Add opportunity to use markers in actors (solution of [#160](https://github.com/InsanusMokrassar/MicroUtils/issues/160))
 | 
				
			||||||
 | 
					* `Koin`:
 | 
				
			||||||
 | 
					  * Module inited :)
 | 
				
			||||||
 | 
					* `Repos`:
 | 
				
			||||||
 | 
					  * `Android`:
 | 
				
			||||||
 | 
					    * Add typealias `KeyValueSPRepo` and opportunity to create shared preferences `KeyValue` repo with `KeyValueStore(...)` (fix of [#155](https://github.com/InsanusMokrassar/MicroUtils/issues/155))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.12.12
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Common`:
 | 
				
			||||||
 | 
					  * `Compose`:
 | 
				
			||||||
 | 
					    * `JS`:
 | 
				
			||||||
 | 
					      * Add `SkeletonAnimation` stylesheet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.12.11
 | 
					## 0.12.11
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `Repos`:
 | 
					* `Repos`:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,6 +16,7 @@ kotlin {
 | 
				
			|||||||
        androidMain {
 | 
					        androidMain {
 | 
				
			||||||
            dependencies {
 | 
					            dependencies {
 | 
				
			||||||
                api project(":micro_utils.coroutines")
 | 
					                api project(":micro_utils.coroutines")
 | 
				
			||||||
 | 
					                api libs.android.fragment
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.common.compose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.jetbrains.compose.web.css.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object SkeletonAnimation : StyleSheet() {
 | 
				
			||||||
 | 
					    val skeletonKeyFrames: CSSNamedKeyframes by keyframes {
 | 
				
			||||||
 | 
					        to { backgroundPosition("-20% 0") }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun CSSBuilder.includeSkeletonStyle(
 | 
				
			||||||
 | 
					        duration: CSSSizeValue<out CSSUnitTime> = 2.s,
 | 
				
			||||||
 | 
					        timingFunction: AnimationTimingFunction = AnimationTimingFunction.EaseInOut,
 | 
				
			||||||
 | 
					        iterationCount: Int? = null,
 | 
				
			||||||
 | 
					        direction: AnimationDirection = AnimationDirection.Normal,
 | 
				
			||||||
 | 
					        keyFrames: CSSNamedKeyframes = skeletonKeyFrames,
 | 
				
			||||||
 | 
					        hideChildren: Boolean = true,
 | 
				
			||||||
 | 
					        hideText: Boolean = hideChildren
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        backgroundImage("linear-gradient(110deg, rgb(236, 236, 236) 40%, rgb(245, 245, 245) 50%, rgb(236, 236, 236) 65%)")
 | 
				
			||||||
 | 
					        backgroundSize("200% 100%")
 | 
				
			||||||
 | 
					        backgroundPosition("180% 0")
 | 
				
			||||||
 | 
					        animation(keyFrames) {
 | 
				
			||||||
 | 
					            duration(duration)
 | 
				
			||||||
 | 
					            timingFunction(timingFunction)
 | 
				
			||||||
 | 
					            iterationCount(iterationCount)
 | 
				
			||||||
 | 
					            direction(direction)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (hideText) {
 | 
				
			||||||
 | 
					            property("color", "${Color.transparent} !important")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (hideChildren) {
 | 
				
			||||||
 | 
					            child(self, universal) style {
 | 
				
			||||||
 | 
					                property("visibility", "hidden")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val skeleton by style {
 | 
				
			||||||
 | 
					        includeSkeletonStyle()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,6 +14,14 @@ private inline fun <T> getObject(
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Diff object which contains information about differences between two [Iterable]s
 | 
					 * Diff object which contains information about differences between two [Iterable]s
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 | 
					 * See tests for more info
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param removed The objects which has been presented in the old collection but absent in new one. Index here is the index in the old collection
 | 
				
			||||||
 | 
					 * @param added The object which appear in new collection only. Indexes here show the index in the new collection
 | 
				
			||||||
 | 
					 * @param replaced Pair of old-new changes. First object has been presented in the old collection on its
 | 
				
			||||||
 | 
					 * [IndexedValue.index] place, the second one is the object in new collection. Both have indexes due to the fact that in
 | 
				
			||||||
 | 
					 * case when some value has been replaced after adds or removes in original collection the object index will be changed
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @see calculateDiff
 | 
					 * @see calculateDiff
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
data class Diff<T> internal constructor(
 | 
					data class Diff<T> internal constructor(
 | 
				
			||||||
@@ -165,7 +173,7 @@ inline fun <T> Iterable<T>.calculateStrictDiff(
 | 
				
			|||||||
fun <T> MutableList<T>.applyDiff(
 | 
					fun <T> MutableList<T>.applyDiff(
 | 
				
			||||||
    source: Iterable<T>,
 | 
					    source: Iterable<T>,
 | 
				
			||||||
    strictComparison: Boolean = false
 | 
					    strictComparison: Boolean = false
 | 
				
			||||||
) = calculateDiff(source, strictComparison).let {
 | 
					): Diff<T> = calculateDiff(source, strictComparison).also {
 | 
				
			||||||
    for (i in it.removed.indices.sortedDescending()) {
 | 
					    for (i in it.removed.indices.sortedDescending()) {
 | 
				
			||||||
        removeAt(it.removed[i].index)
 | 
					        removeAt(it.removed[i].index)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.os.Bundle
 | 
				
			||||||
 | 
					import android.os.Parcelable
 | 
				
			||||||
 | 
					import androidx.fragment.app.Fragment
 | 
				
			||||||
 | 
					import java.io.Serializable
 | 
				
			||||||
 | 
					import kotlin.reflect.KProperty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ArgumentPropertyNullableDelegate {
 | 
				
			||||||
 | 
					    operator fun <T: Any> getValue(thisRef: Fragment, property: KProperty<*>): T? {
 | 
				
			||||||
 | 
					        val arguments = thisRef.arguments ?: return null
 | 
				
			||||||
 | 
					        val key = property.name
 | 
				
			||||||
 | 
					        return when (property.getter.returnType.classifier) {
 | 
				
			||||||
 | 
					            // Scalars
 | 
				
			||||||
 | 
					            String::class -> arguments.getString(key)
 | 
				
			||||||
 | 
					            Boolean::class -> arguments.getBoolean(key)
 | 
				
			||||||
 | 
					            Byte::class -> arguments.getByte(key)
 | 
				
			||||||
 | 
					            Char::class -> arguments.getChar(key)
 | 
				
			||||||
 | 
					            Double::class -> arguments.getDouble(key)
 | 
				
			||||||
 | 
					            Float::class -> arguments.getFloat(key)
 | 
				
			||||||
 | 
					            Int::class -> arguments.getInt(key)
 | 
				
			||||||
 | 
					            Long::class -> arguments.getLong(key)
 | 
				
			||||||
 | 
					            Short::class -> arguments.getShort(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // References
 | 
				
			||||||
 | 
					            Bundle::class -> arguments.getBundle(key)
 | 
				
			||||||
 | 
					            CharSequence::class -> arguments.getCharSequence(key)
 | 
				
			||||||
 | 
					            Parcelable::class -> arguments.getParcelable(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Scalar arrays
 | 
				
			||||||
 | 
					            BooleanArray::class -> arguments.getBooleanArray(key)
 | 
				
			||||||
 | 
					            ByteArray::class -> arguments.getByteArray(key)
 | 
				
			||||||
 | 
					            CharArray::class -> arguments.getCharArray(key)
 | 
				
			||||||
 | 
					            DoubleArray::class -> arguments.getDoubleArray(key)
 | 
				
			||||||
 | 
					            FloatArray::class -> arguments.getFloatArray(key)
 | 
				
			||||||
 | 
					            IntArray::class -> arguments.getIntArray(key)
 | 
				
			||||||
 | 
					            LongArray::class -> arguments.getLongArray(key)
 | 
				
			||||||
 | 
					            ShortArray::class -> arguments.getShortArray(key)
 | 
				
			||||||
 | 
					            Array::class -> {
 | 
				
			||||||
 | 
					                val componentType = property.returnType.classifier ?.javaClass ?.componentType!!
 | 
				
			||||||
 | 
					                @Suppress("UNCHECKED_CAST") // Checked by reflection.
 | 
				
			||||||
 | 
					                when {
 | 
				
			||||||
 | 
					                    Parcelable::class.java.isAssignableFrom(componentType) -> {
 | 
				
			||||||
 | 
					                        arguments.getParcelableArray(key)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    String::class.java.isAssignableFrom(componentType) -> {
 | 
				
			||||||
 | 
					                        arguments.getStringArray(key)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    CharSequence::class.java.isAssignableFrom(componentType) -> {
 | 
				
			||||||
 | 
					                        arguments.getCharSequenceArray(key)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    Serializable::class.java.isAssignableFrom(componentType) -> {
 | 
				
			||||||
 | 
					                        arguments.getSerializable(key)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    else -> {
 | 
				
			||||||
 | 
					                        val valueType = componentType.canonicalName
 | 
				
			||||||
 | 
					                        throw IllegalArgumentException(
 | 
				
			||||||
 | 
					                            "Illegal value array type $valueType for key \"$key\""
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Serializable::class -> arguments.getSerializable(key)
 | 
				
			||||||
 | 
					            else -> null
 | 
				
			||||||
 | 
					        } as? T
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ArgumentPropertyNonNullableDelegate {
 | 
				
			||||||
 | 
					    operator fun <T: Any> getValue(thisRef: Fragment, property: KProperty<*>): T {
 | 
				
			||||||
 | 
					        return ArgumentPropertyNullableDelegate.getValue<T>(thisRef, property)!!
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun argumentOrNull() = ArgumentPropertyNullableDelegate
 | 
				
			||||||
 | 
					fun argumentOrThrow() = ArgumentPropertyNonNullableDelegate
 | 
				
			||||||
@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.app.Activity
 | 
				
			||||||
 | 
					import android.view.View
 | 
				
			||||||
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import androidx.core.view.children
 | 
				
			||||||
 | 
					import androidx.fragment.app.Fragment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun findViewsByTag(viewGroup: ViewGroup, tag: Any?): List<View> {
 | 
				
			||||||
 | 
					    return viewGroup.children.flatMap {
 | 
				
			||||||
 | 
					        findViewsByTag(it, tag)
 | 
				
			||||||
 | 
					    }.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun findViewsByTag(viewGroup: ViewGroup, key: Int, tag: Any?): List<View> {
 | 
				
			||||||
 | 
					    return viewGroup.children.flatMap {
 | 
				
			||||||
 | 
					        findViewsByTag(it, key, tag)
 | 
				
			||||||
 | 
					    }.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun findViewsByTag(view: View, tag: Any?): List<View> {
 | 
				
			||||||
 | 
					    val result = mutableListOf<View>()
 | 
				
			||||||
 | 
					    if (view.tag == tag) {
 | 
				
			||||||
 | 
					        result.add(view)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (view is ViewGroup) {
 | 
				
			||||||
 | 
					        result.addAll(findViewsByTag(view, tag))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun findViewsByTag(view: View, key: Int, tag: Any?): List<View> {
 | 
				
			||||||
 | 
					    val result = mutableListOf<View>()
 | 
				
			||||||
 | 
					    if (view.getTag(key) == tag) {
 | 
				
			||||||
 | 
					        result.add(view)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (view is ViewGroup) {
 | 
				
			||||||
 | 
					        result.addAll(findViewsByTag(view, key, tag))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return result.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Activity.findViewsByTag(tag: Any?) = rootView ?.let {
 | 
				
			||||||
 | 
					    findViewsByTag(it, tag)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Activity.findViewsByTag(key: Int, tag: Any?) = rootView ?.let {
 | 
				
			||||||
 | 
					    findViewsByTag(it, key, tag)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Fragment.findViewsByTag(tag: Any?) = view ?.let {
 | 
				
			||||||
 | 
					    findViewsByTag(it, tag)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Fragment.findViewsByTag(key: Int, tag: Any?) = view ?.let {
 | 
				
			||||||
 | 
					    findViewsByTag(it, key, tag)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Fragment.findViewsByTagInActivity(tag: Any?) = activity ?.findViewsByTag(tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Fragment.findViewsByTagInActivity(key: Int, tag: Any?) = activity ?.findViewsByTag(key, tag)
 | 
				
			||||||
@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.app.Activity
 | 
				
			||||||
 | 
					import android.view.View
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val Activity.rootView: View?
 | 
				
			||||||
 | 
					    get() = findViewById<View?>(android.R.id.content) ?.rootView ?: window.decorView.findViewById<View?>(android.R.id.content) ?.rootView
 | 
				
			||||||
@@ -1,19 +1,15 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.coroutines
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.*
 | 
				
			||||||
import kotlinx.coroutines.channels.Channel
 | 
					import kotlinx.coroutines.channels.Channel
 | 
				
			||||||
import kotlinx.coroutines.launch
 | 
					import kotlinx.coroutines.flow.consumeAsFlow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <T> CoroutineScope.actor(
 | 
					fun <T> CoroutineScope.actor(
 | 
				
			||||||
    channelCapacity: Int = Channel.UNLIMITED,
 | 
					    channelCapacity: Int = Channel.UNLIMITED,
 | 
				
			||||||
    block: suspend (T) -> Unit
 | 
					    block: suspend (T) -> Unit
 | 
				
			||||||
): Channel<T> {
 | 
					): Channel<T> {
 | 
				
			||||||
    val channel = Channel<T>(channelCapacity)
 | 
					    val channel = Channel<T>(channelCapacity)
 | 
				
			||||||
    launch {
 | 
					    channel.consumeAsFlow().subscribe(this, block)
 | 
				
			||||||
        for (data in channel) {
 | 
					 | 
				
			||||||
            block(data)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return channel
 | 
					    return channel
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.*
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.Channel
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.consumeAsFlow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> CoroutineScope.actorAsync(
 | 
				
			||||||
 | 
					    channelCapacity: Int = Channel.UNLIMITED,
 | 
				
			||||||
 | 
					    markerFactory: suspend (T) -> Any? = { null },
 | 
				
			||||||
 | 
					    block: suspend (T) -> Unit
 | 
				
			||||||
 | 
					): Channel<T> {
 | 
				
			||||||
 | 
					    val channel = Channel<T>(channelCapacity)
 | 
				
			||||||
 | 
					    channel.consumeAsFlow().subscribeAsync(this, markerFactory, block)
 | 
				
			||||||
 | 
					    return channel
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <T> CoroutineScope.safeActorAsync(
 | 
				
			||||||
 | 
					    channelCapacity: Int = Channel.UNLIMITED,
 | 
				
			||||||
 | 
					    noinline onException: ExceptionHandler<Unit> = defaultSafelyExceptionHandler,
 | 
				
			||||||
 | 
					    noinline markerFactory: suspend (T) -> Any? = { null },
 | 
				
			||||||
 | 
					    crossinline block: suspend (T) -> Unit
 | 
				
			||||||
 | 
					): Channel<T> = actorAsync(
 | 
				
			||||||
 | 
					    channelCapacity,
 | 
				
			||||||
 | 
					    markerFactory
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    safely(onException) {
 | 
				
			||||||
 | 
					        block(it)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,23 +6,19 @@ import kotlin.coroutines.*
 | 
				
			|||||||
suspend fun <T> Iterable<Deferred<T>>.awaitFirstWithDeferred(
 | 
					suspend fun <T> Iterable<Deferred<T>>.awaitFirstWithDeferred(
 | 
				
			||||||
    scope: CoroutineScope,
 | 
					    scope: CoroutineScope,
 | 
				
			||||||
    cancelOnResult: Boolean = true
 | 
					    cancelOnResult: Boolean = true
 | 
				
			||||||
): Pair<Deferred<T>, T> = suspendCoroutine<Pair<Deferred<T>, T>> { continuation ->
 | 
					): Pair<Deferred<T>, T> {
 | 
				
			||||||
    scope.launch(SupervisorJob()) {
 | 
					    val resultDeferred = CompletableDeferred<Pair<Deferred<T>, T>>()
 | 
				
			||||||
        val scope = this
 | 
					    val scope = scope.LinkedSupervisorScope()
 | 
				
			||||||
        forEach {
 | 
					    forEach {
 | 
				
			||||||
            scope.launch {
 | 
					        scope.launch {
 | 
				
			||||||
                continuation.resume(it to it.await())
 | 
					            resultDeferred.complete(it to it.await())
 | 
				
			||||||
                scope.cancel()
 | 
					            scope.cancel()
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}.also {
 | 
					    return resultDeferred.await().also {
 | 
				
			||||||
    if (cancelOnResult) {
 | 
					        if (cancelOnResult) {
 | 
				
			||||||
        forEach {
 | 
					            forEach {
 | 
				
			||||||
            try {
 | 
					                runCatchingSafely { it.cancel() }
 | 
				
			||||||
                it.cancel()
 | 
					 | 
				
			||||||
            } catch (e: IllegalStateException) {
 | 
					 | 
				
			||||||
                e.printStackTrace()
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
 | 
					import kotlin.js.JsName
 | 
				
			||||||
 | 
					import kotlin.jvm.JvmName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <T, R> Flow<Flow<T>>.flatMap(
 | 
				
			||||||
 | 
					    crossinline mapper: suspend (T) -> R
 | 
				
			||||||
 | 
					) = flow {
 | 
				
			||||||
 | 
					    collect {
 | 
				
			||||||
 | 
					        it.collect {
 | 
				
			||||||
 | 
					            emit(mapper(it))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@JsName("flatMapIterable")
 | 
				
			||||||
 | 
					@JvmName("flatMapIterable")
 | 
				
			||||||
 | 
					inline fun <T, R> Flow<Iterable<T>>.flatMap(
 | 
				
			||||||
 | 
					    crossinline mapper: suspend (T) -> R
 | 
				
			||||||
 | 
					) = map {
 | 
				
			||||||
 | 
					    it.asFlow()
 | 
				
			||||||
 | 
					}.flatMap(mapper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <T, R> Flow<Flow<T>>.flatMapNotNull(
 | 
				
			||||||
 | 
					    crossinline mapper: suspend (T) -> R
 | 
				
			||||||
 | 
					) = flatMap(mapper).takeNotNull()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@JsName("flatMapNotNullIterable")
 | 
				
			||||||
 | 
					@JvmName("flatMapNotNullIterable")
 | 
				
			||||||
 | 
					inline fun <T, R> Flow<Iterable<T>>.flatMapNotNull(
 | 
				
			||||||
 | 
					    crossinline mapper: suspend (T) -> R
 | 
				
			||||||
 | 
					) = flatMap(mapper).takeNotNull()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> Flow<Flow<T>>.flatten() = flatMap { it }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@JsName("flattenIterable")
 | 
				
			||||||
 | 
					@JvmName("flattenIterable")
 | 
				
			||||||
 | 
					fun <T> Flow<Iterable<T>>.flatten() = flatMap { it }
 | 
				
			||||||
@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun <T> Flow<T>.takeNotNull() = mapNotNull { it }
 | 
				
			||||||
 | 
					fun <T> Flow<T>.filterNotNull() = takeNotNull()
 | 
				
			||||||
							
								
								
									
										50
									
								
								coroutines/src/main/kotlin/FlowOnHierarchyChangeListener.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								coroutines/src/main/kotlin/FlowOnHierarchyChangeListener.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.view.View
 | 
				
			||||||
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.MutableSharedFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.asSharedFlow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * [kotlinx.coroutines.flow.Flow]-based [android.view.ViewGroup.OnHierarchyChangeListener]
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param recursive If set, any call of [onChildViewAdded] will check if child [View] is [ViewGroup] and subscribe to this
 | 
				
			||||||
 | 
					 * [ViewGroup] too
 | 
				
			||||||
 | 
					 * @param [_onChildViewAdded] Internal [MutableSharedFlow] which will be used to pass data to [onChildViewAdded] flow
 | 
				
			||||||
 | 
					 * @param [_onChildViewRemoved] Internal [MutableSharedFlow] which will be used to pass data to [onChildViewRemoved] flow
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class FlowOnHierarchyChangeListener(
 | 
				
			||||||
 | 
					    private val recursive: Boolean = false,
 | 
				
			||||||
 | 
					    private val _onChildViewAdded: MutableSharedFlow<Pair<View, View>> = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE),
 | 
				
			||||||
 | 
					    private val _onChildViewRemoved: MutableSharedFlow<Pair<View, View>> = MutableSharedFlow(extraBufferCapacity = Int.MAX_VALUE)
 | 
				
			||||||
 | 
					) : ViewGroup.OnHierarchyChangeListener {
 | 
				
			||||||
 | 
					    val onChildViewAdded = _onChildViewAdded.asSharedFlow()
 | 
				
			||||||
 | 
					    val onChildViewRemoved = _onChildViewRemoved.asSharedFlow()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Will emit data into [onChildViewAdded] flow. If [recursive] is true and [child] is [ViewGroup] will also
 | 
				
			||||||
 | 
					     * subscribe to [child] hierarchy changes.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Due to the fact that this method is not suspendable, [FlowOnHierarchyChangeListener] will use
 | 
				
			||||||
 | 
					     * [MutableSharedFlow.tryEmit] to send data into [_onChildViewAdded]. That is why its default extraBufferCapacity is
 | 
				
			||||||
 | 
					     * [Int.MAX_VALUE]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    override fun onChildViewAdded(parent: View, child: View) {
 | 
				
			||||||
 | 
					        _onChildViewAdded.tryEmit(parent to child)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (recursive && child is ViewGroup) {
 | 
				
			||||||
 | 
					            child.setOnHierarchyChangeListener(this)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Just emit data into [onChildViewRemoved]
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Due to the fact that this method is not suspendable, [FlowOnHierarchyChangeListener] will use
 | 
				
			||||||
 | 
					     * [MutableSharedFlow.tryEmit] to send data into [_onChildViewRemoved]. That is why its default extraBufferCapacity is
 | 
				
			||||||
 | 
					     * [Int.MAX_VALUE]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    override fun onChildViewRemoved(parent: View, child: View) {
 | 
				
			||||||
 | 
					        _onChildViewRemoved.tryEmit(parent to child)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								coroutines/src/main/kotlin/RecursiveHierarchySubscriber.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								coroutines/src/main/kotlin/RecursiveHierarchySubscriber.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.coroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.view.ViewGroup
 | 
				
			||||||
 | 
					import android.view.ViewGroup.OnHierarchyChangeListener
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Use [ViewGroup.setOnHierarchyChangeListener] recursively for all available [ViewGroup]s starting with [this].
 | 
				
			||||||
 | 
					 * This extension DO NOT guarantee that recursive subscription will happen after this method call
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun ViewGroup.setOnHierarchyChangeListenerRecursively(
 | 
				
			||||||
 | 
					    listener: OnHierarchyChangeListener
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    setOnHierarchyChangeListener(listener)
 | 
				
			||||||
 | 
					    (0 until childCount).forEach {
 | 
				
			||||||
 | 
					        (getChildAt(it) as? ViewGroup) ?.setOnHierarchyChangeListenerRecursively(listener)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -14,5 +14,5 @@ crypto_js_version=4.1.1
 | 
				
			|||||||
# Project data
 | 
					# Project data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group=dev.inmo
 | 
					group=dev.inmo
 | 
				
			||||||
version=0.12.11
 | 
					version=0.12.16
 | 
				
			||||||
android_code_version=150
 | 
					android_code_version=155
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,22 +15,26 @@ ktor = "2.1.1"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
gh-release = "2.4.1"
 | 
					gh-release = "2.4.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					koin = "3.2.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-gradle = "7.2.2"
 | 
					android-gradle = "7.2.2"
 | 
				
			||||||
dexcount = "3.1.0"
 | 
					dexcount = "3.1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-coreKtx = "1.8.0"
 | 
					android-coreKtx = "1.9.0"
 | 
				
			||||||
android-recyclerView = "1.2.1"
 | 
					android-recyclerView = "1.2.1"
 | 
				
			||||||
android-appCompat = "1.4.2"
 | 
					android-appCompat = "1.5.1"
 | 
				
			||||||
 | 
					android-fragment = "1.5.3"
 | 
				
			||||||
android-espresso = "3.4.0"
 | 
					android-espresso = "3.4.0"
 | 
				
			||||||
android-test = "1.1.3"
 | 
					android-test = "1.1.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-props-minSdk = "21"
 | 
					android-props-minSdk = "21"
 | 
				
			||||||
android-props-compileSdk = "32"
 | 
					android-props-compileSdk = "33"
 | 
				
			||||||
android-props-buildTools = "32.0.0"
 | 
					android-props-buildTools = "33.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[libraries]
 | 
					[libraries]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kt-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kt" }
 | 
					kt-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kt" }
 | 
				
			||||||
 | 
					kt-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kt" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kt-serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kt-serialization" }
 | 
					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-serialization-cbor = { module = "org.jetbrains.kotlinx:kotlinx-serialization-cbor", version.ref = "kt-serialization" }
 | 
				
			||||||
@@ -59,6 +63,7 @@ ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negoti
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
 | 
					klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "klock" }
 | 
				
			||||||
uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
 | 
					uuid = { module = "com.benasher44:uuid", version.ref = "uuid" }
 | 
				
			||||||
 | 
					koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jb-exposed = { module = "org.jetbrains.exposed:exposed-core", version.ref = "jb-exposed" }
 | 
					jb-exposed = { module = "org.jetbrains.exposed:exposed-core", version.ref = "jb-exposed" }
 | 
				
			||||||
@@ -67,6 +72,7 @@ jb-exposed = { module = "org.jetbrains.exposed:exposed-core", version.ref = "jb-
 | 
				
			|||||||
android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "android-coreKtx" }
 | 
					android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "android-coreKtx" }
 | 
				
			||||||
android-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "android-recyclerView" }
 | 
					android-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "android-recyclerView" }
 | 
				
			||||||
android-appCompat-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "android-appCompat" }
 | 
					android-appCompat-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "android-appCompat" }
 | 
				
			||||||
 | 
					android-fragment = { module = "androidx.fragment:fragment", version.ref = "android-fragment" }
 | 
				
			||||||
android-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "android-espresso" }
 | 
					android-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "android-espresso" }
 | 
				
			||||||
android-test-junit = { module = "androidx.test.ext:junit", version.ref = "android-test" }
 | 
					android-test-junit = { module = "androidx.test.ext:junit", version.ref = "android-test" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								koin/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								koin/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.multiplatform"
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.plugin.serialization"
 | 
				
			||||||
 | 
					    id "com.android.library"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apply from: "$mppProjectWithSerializationPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kotlin {
 | 
				
			||||||
 | 
					    sourceSets {
 | 
				
			||||||
 | 
					        commonMain {
 | 
				
			||||||
 | 
					            dependencies {
 | 
				
			||||||
 | 
					                api libs.koin
 | 
				
			||||||
 | 
					                api libs.uuid
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        jvmMain {
 | 
				
			||||||
 | 
					            dependencies {
 | 
				
			||||||
 | 
					                api libs.kt.reflect
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        androidMain {
 | 
				
			||||||
 | 
					            dependencies {
 | 
				
			||||||
 | 
					                api libs.kt.reflect
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										12
									
								
								koin/src/commonMain/kotlin/FactoryWithRandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								koin/src/commonMain/kotlin/FactoryWithRandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 :)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.factoryWithRandomQualifier(
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					) = factory(RandomQualifier(), definition)
 | 
				
			||||||
							
								
								
									
										12
									
								
								koin/src/commonMain/kotlin/FactoryWithStringQualifier.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								koin/src/commonMain/kotlin/FactoryWithStringQualifier.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.definition.Definition
 | 
				
			||||||
 | 
					import org.koin.core.module.Module
 | 
				
			||||||
 | 
					import org.koin.core.qualifier.StringQualifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.factory(
 | 
				
			||||||
 | 
					    qualifier: String,
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					) = factory(StringQualifier(qualifier), definition)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								koin/src/commonMain/kotlin/GetAllDistinct.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								koin/src/commonMain/kotlin/GetAllDistinct.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.Koin
 | 
				
			||||||
 | 
					import org.koin.core.scope.Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Scope.getAllDistinct() = getAll<T>().distinct()
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Koin.getAllDistinct() = getAll<T>().distinct()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										8
									
								
								koin/src/commonMain/kotlin/GetAny.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								koin/src/commonMain/kotlin/GetAny.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.Koin
 | 
				
			||||||
 | 
					import org.koin.core.scope.Scope
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Scope.getAny() = getAll<T>().first()
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Koin.getAny() = getAll<T>().first()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										6
									
								
								koin/src/commonMain/kotlin/RandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								koin/src/commonMain/kotlin/RandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.benasher44.uuid.uuid4
 | 
				
			||||||
 | 
					import org.koin.core.qualifier.StringQualifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun RandomQualifier(randomFun: () -> String = { uuid4().toString() }) = StringQualifier(randomFun())
 | 
				
			||||||
							
								
								
									
										13
									
								
								koin/src/commonMain/kotlin/SingleWithRandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								koin/src/commonMain/kotlin/SingleWithRandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 :)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.singleWithRandomQualifier(
 | 
				
			||||||
 | 
					    createdAtStart: Boolean = false,
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					) = single(RandomQualifier(), createdAtStart, definition)
 | 
				
			||||||
							
								
								
									
										12
									
								
								koin/src/commonMain/kotlin/SingleWithStringQualifier.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								koin/src/commonMain/kotlin/SingleWithStringQualifier.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.definition.Definition
 | 
				
			||||||
 | 
					import org.koin.core.module.Module
 | 
				
			||||||
 | 
					import org.koin.core.qualifier.StringQualifier
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.single(
 | 
				
			||||||
 | 
					    qualifier: String,
 | 
				
			||||||
 | 
					    createdAtStart: Boolean = false,
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					) = single(StringQualifier(qualifier), createdAtStart, definition)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										27
									
								
								koin/src/jvmMain/kotlin/FactoryWithBinds.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								koin/src/jvmMain/kotlin/FactoryWithBinds.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.definition.Definition
 | 
				
			||||||
 | 
					import org.koin.core.instance.InstanceFactory
 | 
				
			||||||
 | 
					import org.koin.core.module.Module
 | 
				
			||||||
 | 
					import org.koin.core.qualifier.Qualifier
 | 
				
			||||||
 | 
					import org.koin.dsl.binds
 | 
				
			||||||
 | 
					import kotlin.reflect.KClass
 | 
				
			||||||
 | 
					import kotlin.reflect.full.allSuperclasses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.factoryWithBinds(
 | 
				
			||||||
 | 
					    qualifier: Qualifier? = null,
 | 
				
			||||||
 | 
					    bindFilter: (KClass<*>) -> Boolean = { true },
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					): Pair<Module, InstanceFactory<*>> {
 | 
				
			||||||
 | 
					    return factory(qualifier, definition) binds (T::class.allSuperclasses.filter(bindFilter).toTypedArray())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.factoryWithBinds(
 | 
				
			||||||
 | 
					    qualifier: String,
 | 
				
			||||||
 | 
					    bindFilter: (KClass<*>) -> Boolean = { true },
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					): Pair<Module, InstanceFactory<*>> {
 | 
				
			||||||
 | 
					    return factory(qualifier, definition) binds (T::class.allSuperclasses.filter(bindFilter).toTypedArray())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.definition.Definition
 | 
				
			||||||
 | 
					import org.koin.core.instance.InstanceFactory
 | 
				
			||||||
 | 
					import org.koin.core.module.Module
 | 
				
			||||||
 | 
					import kotlin.reflect.KClass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.factoryWithRandomQualifierAndBinds(
 | 
				
			||||||
 | 
					    bindFilter: (KClass<*>) -> Boolean = { true },
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					): Pair<Module, InstanceFactory<*>> {
 | 
				
			||||||
 | 
					    return factoryWithBinds(RandomQualifier(), bindFilter, definition)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										30
									
								
								koin/src/jvmMain/kotlin/SignleWithBinds.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								koin/src/jvmMain/kotlin/SignleWithBinds.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.definition.Definition
 | 
				
			||||||
 | 
					import org.koin.core.instance.InstanceFactory
 | 
				
			||||||
 | 
					import org.koin.core.module.Module
 | 
				
			||||||
 | 
					import org.koin.core.qualifier.Qualifier
 | 
				
			||||||
 | 
					import org.koin.dsl.binds
 | 
				
			||||||
 | 
					import kotlin.reflect.KClass
 | 
				
			||||||
 | 
					import kotlin.reflect.full.allSuperclasses
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.singleWithBinds(
 | 
				
			||||||
 | 
					    qualifier: Qualifier? = null,
 | 
				
			||||||
 | 
					    createdAtStart: Boolean = false,
 | 
				
			||||||
 | 
					    bindFilter: (KClass<*>) -> Boolean = { true },
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					): Pair<Module, InstanceFactory<*>> {
 | 
				
			||||||
 | 
					    return single(qualifier, createdAtStart, definition) binds (T::class.allSuperclasses.filter(bindFilter).toTypedArray())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.singleWithBinds(
 | 
				
			||||||
 | 
					    qualifier: String,
 | 
				
			||||||
 | 
					    createdAtStart: Boolean = false,
 | 
				
			||||||
 | 
					    bindFilter: (KClass<*>) -> Boolean = { true },
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					): Pair<Module, InstanceFactory<*>> {
 | 
				
			||||||
 | 
					    return single(qualifier, createdAtStart, definition) binds (T::class.allSuperclasses.filter(bindFilter).toTypedArray())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								koin/src/jvmMain/kotlin/SingleWithBindsAndRandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								koin/src/jvmMain/kotlin/SingleWithBindsAndRandomQualifier.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.koin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.koin.core.definition.Definition
 | 
				
			||||||
 | 
					import org.koin.core.instance.InstanceFactory
 | 
				
			||||||
 | 
					import org.koin.core.module.Module
 | 
				
			||||||
 | 
					import kotlin.reflect.KClass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun <reified T : Any> Module.singleWithRandomQualifierAndBinds(
 | 
				
			||||||
 | 
					    createdAtStart: Boolean = false,
 | 
				
			||||||
 | 
					    bindFilter: (KClass<*>) -> Boolean = { true },
 | 
				
			||||||
 | 
					    noinline definition: Definition<T>
 | 
				
			||||||
 | 
					): Pair<Module, InstanceFactory<*>> {
 | 
				
			||||||
 | 
					    return singleWithBinds(RandomQualifier(), createdAtStart, bindFilter, definition)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								koin/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								koin/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<manifest package="dev.inmo.micro_utils.koin"/>
 | 
				
			||||||
@@ -17,7 +17,7 @@ fun <T : Any> Context.keyValueStore(
 | 
				
			|||||||
): KeyValueRepo<String, T> {
 | 
					): KeyValueRepo<String, T> {
 | 
				
			||||||
    @Suppress("UNCHECKED_CAST")
 | 
					    @Suppress("UNCHECKED_CAST")
 | 
				
			||||||
    return cache.getOrPut(name) {
 | 
					    return cache.getOrPut(name) {
 | 
				
			||||||
        KeyValueStore<T>(this, name, cacheValues)
 | 
					        KeyValueStore<T>(c = this, preferencesName = name, useCache = cacheValues)
 | 
				
			||||||
    } as KeyValueStore<T>
 | 
					    } as KeyValueStore<T>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -149,6 +149,14 @@ class KeyValueStore<T : Any> internal constructor (
 | 
				
			|||||||
            _onValueRemovedFlow.emit(it)
 | 
					            _onValueRemovedFlow.emit(it)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        operator fun <T : Any> invoke(
 | 
				
			||||||
 | 
					            context: Context,
 | 
				
			||||||
 | 
					            name: String = "default",
 | 
				
			||||||
 | 
					            cacheValues: Boolean = false
 | 
				
			||||||
 | 
					        ) = context.keyValueStore<T>(name, cacheValues)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline fun <T : Any> SharedPreferencesKeyValueRepo(
 | 
					inline fun <T : Any> SharedPreferencesKeyValueRepo(
 | 
				
			||||||
@@ -156,3 +164,5 @@ inline fun <T : Any> SharedPreferencesKeyValueRepo(
 | 
				
			|||||||
    name: String = "default",
 | 
					    name: String = "default",
 | 
				
			||||||
    cacheValues: Boolean = false
 | 
					    cacheValues: Boolean = false
 | 
				
			||||||
) = context.keyValueStore<T>(name, cacheValues)
 | 
					) = context.keyValueStore<T>(name, cacheValues)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typealias KeyValueSPRepo<T> = KeyValueStore<T>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ String[] includes = [
 | 
				
			|||||||
    ":common:compose",
 | 
					    ":common:compose",
 | 
				
			||||||
    ":matrix",
 | 
					    ":matrix",
 | 
				
			||||||
    ":crypto",
 | 
					    ":crypto",
 | 
				
			||||||
 | 
					    ":koin",
 | 
				
			||||||
    ":selector:common",
 | 
					    ":selector:common",
 | 
				
			||||||
    ":pagination:common",
 | 
					    ":pagination:common",
 | 
				
			||||||
    ":pagination:exposed",
 | 
					    ":pagination:exposed",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user