mirror of
				https://github.com/InsanusMokrassar/MicroUtils.git
				synced 2025-11-04 06:00:22 +00:00 
			
		
		
		
	Compare commits
	
		
			51 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 9a0b67f938 | |||
| 303e1e6281 | |||
| ff59b0cc9c | |||
| be5d2ee715 | |||
| 8dd2e3f6f9 | |||
| 2eedd196d2 | |||
| 759a3f2784 | |||
| 386fa830c3 | |||
| c382423d77 | |||
| bb466ce66c | |||
| 72cd3dd8a1 | |||
| 
						 | 
					595cedaaf1 | ||
| eeaceb6cf5 | |||
| 1bd671685b | |||
| 48d3fe41f2 | |||
| 7ab21871cd | |||
| 65d01b1fb3 | |||
| 6230accb68 | |||
| c6ed821934 | |||
| 10e03bb951 | |||
| aa4f392948 | |||
| f51b59ec02 | |||
| 8c76834ae4 | |||
| 4a454f3d67 | |||
| 151aa1863d | |||
| 3bf6896296 | |||
| 0d01561476 | |||
| f6ded92251 | |||
| d01b735cc6 | |||
| 6c12001080 | |||
| 1afbf03606 | |||
| f6ef5c61c5 | |||
| c18fee8107 | |||
| d9df7a4384 | |||
| 87c2230e8e | |||
| da7eb6de0a | |||
| ed3815118f | |||
| be726f42bd | |||
| a91006132f | |||
| 9a9f741a0b | |||
| 5028f130e9 | |||
| 77fa019651 | |||
| 9715da9384 | |||
| f6d5035c1a | |||
| 43e782ab6f | |||
| f3f9920bfb | |||
| 2bfd615812 | |||
| ebfacb3659 | |||
| c71d557eec | |||
| e0398cef21 | |||
| f91599e9c6 | 
							
								
								
									
										62
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,5 +1,67 @@
 | 
				
			|||||||
# Changelog
 | 
					# Changelog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.25
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Colors`:
 | 
				
			||||||
 | 
					    * `Common`:
 | 
				
			||||||
 | 
					        * Module inited
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**Since this version depdendencies of klock and krypto replaced with `com.soywiz.korge:korlibs-time` and `com.soywiz.korge:korlibs-crypto`**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Klock` (since now `KorlibsTime`): `4.0.10` -> `5.3.0`
 | 
				
			||||||
 | 
					    * `Krypto` (since now `KorlibsCrypto`): `4.0.10` -> `5.3.0`
 | 
				
			||||||
 | 
					* `Serialization`:
 | 
				
			||||||
 | 
					    * `Mapper`:
 | 
				
			||||||
 | 
					        * `Mapper` pass decoder into callback of deserialization strategy
 | 
				
			||||||
 | 
					        * `Mapper` pass encoder into callback of serialization strategy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Koin`: `3.5.0` -> `3.5.3`
 | 
				
			||||||
 | 
					    * `Okio`: `3.6.0` -> `3.7.0`
 | 
				
			||||||
 | 
					* `LanguageCodes`:
 | 
				
			||||||
 | 
					    * Fixes in intermediate language codes (like `Chinese.Hans`)
 | 
				
			||||||
 | 
					    * Rename `IetfLanguageCode` to `IetfLang`
 | 
				
			||||||
 | 
					        * Rename all subsequent functions (including serializer)
 | 
				
			||||||
 | 
					    * New lazy properties `knownLanguageCodesMap`, `knownLanguageCodesMapByLowerCasedKeys` and several others
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.22
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Common`:
 | 
				
			||||||
 | 
					    * Add opportunity to create own `Diff` with base constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.21
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Resources`:
 | 
				
			||||||
 | 
					    * Inited
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Repos`:
 | 
				
			||||||
 | 
					    * `Exposed`:
 | 
				
			||||||
 | 
					        * Add opportunity for setup flows in `AbstractExposedCRUDRepo`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.19
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Ktor`: `2.3.6` -> `2.3.7`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Coroutines`:
 | 
				
			||||||
 | 
					    * `SpecialMutableStateFlow` now extends `MutableStateFlow`
 | 
				
			||||||
 | 
					    * `Compose`:
 | 
				
			||||||
 | 
					        * Deprecate `FlowState` due to its complexity in fixes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 0.20.17
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* `Versions`:
 | 
				
			||||||
 | 
					    * `Serialization`: `1.6.1` -> `1.6.2`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.20.16
 | 
					## 0.20.16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `Versions`:
 | 
					* `Versions`:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,7 @@ allprojects {
 | 
				
			|||||||
        mavenCentral()
 | 
					        mavenCentral()
 | 
				
			||||||
        google()
 | 
					        google()
 | 
				
			||||||
        maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
 | 
					        maven { url "https://maven.pkg.jetbrains.space/public/p/compose/dev" }
 | 
				
			||||||
        maven { url "https://git.inmo.dev/api/packages/InsanusMokrassar/maven" }
 | 
					        maven { url "https://nexus.inmo.dev/repository/maven-releases/" }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // temporal crutch until legacy tests will be stabled or legacy target will be removed
 | 
					    // temporal crutch until legacy tests will be stabled or legacy target will be removed
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										7
									
								
								colors/common/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								colors/common/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.multiplatform"
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.plugin.serialization"
 | 
				
			||||||
 | 
					    id "com.android.library"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64ProjectPresetPath"
 | 
				
			||||||
							
								
								
									
										141
									
								
								colors/common/src/commonMain/kotlin/HEXAColor.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								colors/common/src/commonMain/kotlin/HEXAColor.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.colors.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					import kotlin.jvm.JvmInline
 | 
				
			||||||
 | 
					import kotlin.math.floor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Wrapper for RGBA colors. Receiving [UInt] in main constructor. Each part in main constructor
 | 
				
			||||||
 | 
					 * configured with `0x00 - 0xff` range. Examples:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * * Red: `0xff0000ffu`
 | 
				
			||||||
 | 
					 * * Red (0.5 capacity): `0xff000088u`
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Anyway it is recommended to use
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					@Serializable
 | 
				
			||||||
 | 
					@JvmInline
 | 
				
			||||||
 | 
					value class HEXAColor (
 | 
				
			||||||
 | 
					    val uint: UInt
 | 
				
			||||||
 | 
					) : Comparable<HEXAColor> {
 | 
				
			||||||
 | 
					    val hexa: String
 | 
				
			||||||
 | 
					        get() = "#${uint.toString(16).padStart(8, '0')}"
 | 
				
			||||||
 | 
					    val hex: String
 | 
				
			||||||
 | 
					        get() = hexa.take(7)
 | 
				
			||||||
 | 
					    val rgba: String
 | 
				
			||||||
 | 
					        get() = "rgba($r,$g,$b,${aOfOne.toString().take(5)})"
 | 
				
			||||||
 | 
					    val rgb: String
 | 
				
			||||||
 | 
					        get() = "rgb($r,$g,$b)"
 | 
				
			||||||
 | 
					    val shortHex: String
 | 
				
			||||||
 | 
					        get() = "#${r.shortPart()}${g.shortPart()}${b.shortPart()}"
 | 
				
			||||||
 | 
					    val shortHexa: String
 | 
				
			||||||
 | 
					        get() = "$shortHex${a.shortPart()}"
 | 
				
			||||||
 | 
					    val rgbInt: Int
 | 
				
			||||||
 | 
					        get() = (uint shr 2).toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val r: Int
 | 
				
			||||||
 | 
					        get() = ((uint and 0xff000000u) / 0x1000000u).toInt()
 | 
				
			||||||
 | 
					    val g: Int
 | 
				
			||||||
 | 
					        get() = ((uint and 0x00ff0000u) / 0x10000u).toInt()
 | 
				
			||||||
 | 
					    val b: Int
 | 
				
			||||||
 | 
					        get() = ((uint and 0x0000ff00u) / 0x100u).toInt()
 | 
				
			||||||
 | 
					    val a: Int
 | 
				
			||||||
 | 
					        get() = ((uint and 0x000000ffu)).toInt()
 | 
				
			||||||
 | 
					    val aOfOne: Float
 | 
				
			||||||
 | 
					        get() = a.toFloat() / (0xff)
 | 
				
			||||||
 | 
					    init {
 | 
				
			||||||
 | 
					        require(uint in 0u ..0xffffffffu)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(r: Int, g: Int, b: Int, a: Int) : this(
 | 
				
			||||||
 | 
					        ((r * 0x1000000).toLong() + g * 0x10000 + b * 0x100 + a).toUInt()
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        require(r in 0 ..0xff)
 | 
				
			||||||
 | 
					        require(g in 0 ..0xff)
 | 
				
			||||||
 | 
					        require(b in 0 ..0xff)
 | 
				
			||||||
 | 
					        require(a in 0 ..0xff)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(r: Int, g: Int, b: Int, aOfOne: Float = 1f) : this(
 | 
				
			||||||
 | 
					        r = r, g = g, b = b, a = (aOfOne * 0xff).toInt()
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun toString(): String {
 | 
				
			||||||
 | 
					        return hexa
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun compareTo(other: HEXAColor): Int = (uint - other.uint).coerceIn(Int.MIN_VALUE.toUInt(), Int.MAX_VALUE.toLong().toUInt()).toInt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun copy(
 | 
				
			||||||
 | 
					        r: Int = this.r,
 | 
				
			||||||
 | 
					        g: Int = this.g,
 | 
				
			||||||
 | 
					        b: Int = this.b,
 | 
				
			||||||
 | 
					        aOfOne: Float = this.aOfOne
 | 
				
			||||||
 | 
					    ) = HEXAColor(r = r, g = g, b = b, aOfOne = aOfOne)
 | 
				
			||||||
 | 
					    fun copy(
 | 
				
			||||||
 | 
					        r: Int = this.r,
 | 
				
			||||||
 | 
					        g: Int = this.g,
 | 
				
			||||||
 | 
					        b: Int = this.b,
 | 
				
			||||||
 | 
					        a: Int
 | 
				
			||||||
 | 
					    ) = HEXAColor(r = r, g = g, b = b, a = a)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Parsing color from [color]
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Supported formats samples (on Red color based):
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * * `#f00`
 | 
				
			||||||
 | 
					         * * `#f00f`
 | 
				
			||||||
 | 
					         * * `#ff0000`
 | 
				
			||||||
 | 
					         * * `#ff0000ff`
 | 
				
			||||||
 | 
					         * * `rgb(255, 0, 0)`
 | 
				
			||||||
 | 
					         * * `rgba(255, 0, 0, 1)`
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        fun parseStringColor(color: String): HEXAColor = when {
 | 
				
			||||||
 | 
					            color.startsWith("#") -> color.removePrefix("#").let { color ->
 | 
				
			||||||
 | 
					                when (color.length) {
 | 
				
			||||||
 | 
					                    3 -> color.map { "$it$it" }.joinToString(separator = "", postfix = "ff")
 | 
				
			||||||
 | 
					                    4 -> color.take(3).map { "$it$it" }.joinToString(separator = "", postfix = color.takeLast(1).let { "${it}0" })
 | 
				
			||||||
 | 
					                    6 -> "${color}ff"
 | 
				
			||||||
 | 
					                    8 -> color
 | 
				
			||||||
 | 
					                    else -> error("Malfurmed color string: $color. It is expected that color started with # will contains 3, 6 or 8 valuable parts")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            color.startsWith("rgb(") -> color
 | 
				
			||||||
 | 
					                .removePrefix("rgb(")
 | 
				
			||||||
 | 
					                .removeSuffix(")")
 | 
				
			||||||
 | 
					                .replace(Regex("\\s"), "")
 | 
				
			||||||
 | 
					                .split(",")
 | 
				
			||||||
 | 
					                .joinToString("", postfix = "ff") {
 | 
				
			||||||
 | 
					                    it.toInt().toString(16).padStart(2, '0')
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            color.startsWith("rgba(") -> color
 | 
				
			||||||
 | 
					                .removePrefix("rgba(")
 | 
				
			||||||
 | 
					                .removeSuffix(")")
 | 
				
			||||||
 | 
					                .replace(Regex("\\s"), "")
 | 
				
			||||||
 | 
					                .split(",").let {
 | 
				
			||||||
 | 
					                    it.take(3).map { it.toInt().toString(16).padStart(2, '0') } + (it.last().toFloat() * 0xff).toInt().toString(16).padStart(2, '0')
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                .joinToString("")
 | 
				
			||||||
 | 
					            else -> color
 | 
				
			||||||
 | 
					        }.lowercase().toUInt(16).let(::HEXAColor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * Parsing color from [color]
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * Supported formats samples (on Red color based):
 | 
				
			||||||
 | 
					         *
 | 
				
			||||||
 | 
					         * * `#f00`
 | 
				
			||||||
 | 
					         * * `#ff0000`
 | 
				
			||||||
 | 
					         * * `#ff0000ff`
 | 
				
			||||||
 | 
					         * * `rgb(255, 0, 0)`
 | 
				
			||||||
 | 
					         * * `rgba(255, 0, 0, 1)`
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        operator fun invoke(color: String) = parseStringColor(color)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private fun Int.shortPart(): String {
 | 
				
			||||||
 | 
					            return (floor(toFloat() / 16)).toInt().toString(16)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										175
									
								
								colors/common/src/commonTest/kotlin/HexColorTests.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								colors/common/src/commonTest/kotlin/HexColorTests.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.colors.common
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlin.math.floor
 | 
				
			||||||
 | 
					import kotlin.test.Test
 | 
				
			||||||
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					import kotlin.test.assertTrue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HexColorTests {
 | 
				
			||||||
 | 
					    val alphaRgbaPrecision = 5
 | 
				
			||||||
 | 
					    class TestColor(
 | 
				
			||||||
 | 
					        val color: HEXAColor,
 | 
				
			||||||
 | 
					        val shortHex: String,
 | 
				
			||||||
 | 
					        val shortHexa: String,
 | 
				
			||||||
 | 
					        val hex: String,
 | 
				
			||||||
 | 
					        val hexa: String,
 | 
				
			||||||
 | 
					        val rgb: String,
 | 
				
			||||||
 | 
					        val rgba: String,
 | 
				
			||||||
 | 
					        val r: Int,
 | 
				
			||||||
 | 
					        val g: Int,
 | 
				
			||||||
 | 
					        val b: Int,
 | 
				
			||||||
 | 
					        val a: Int,
 | 
				
			||||||
 | 
					        vararg val additionalRGBAVariants: String
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    val testColors: List<TestColor>
 | 
				
			||||||
 | 
					        get() = listOf(
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(uint = 0xff0000ffu),
 | 
				
			||||||
 | 
					                shortHex = "#f00",
 | 
				
			||||||
 | 
					                shortHexa = "#f00f",
 | 
				
			||||||
 | 
					                hex = "#ff0000",
 | 
				
			||||||
 | 
					                hexa = "#ff0000ff",
 | 
				
			||||||
 | 
					                rgb = "rgb(255,0,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(255,0,0,1.0)",
 | 
				
			||||||
 | 
					                r = 0xff,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0xff,
 | 
				
			||||||
 | 
					                "rgba(255,0,0,1)",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(uint = 0x00ff00ffu),
 | 
				
			||||||
 | 
					                shortHex = "#0f0",
 | 
				
			||||||
 | 
					                shortHexa = "#0f0f",
 | 
				
			||||||
 | 
					                hex = "#00ff00",
 | 
				
			||||||
 | 
					                hexa = "#00ff00ff",
 | 
				
			||||||
 | 
					                rgb = "rgb(0,255,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,255,0,1.0)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0xff,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0xff,
 | 
				
			||||||
 | 
					                "rgba(0,255,0,1)"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x0000ffffu),
 | 
				
			||||||
 | 
					                shortHex = "#00f",
 | 
				
			||||||
 | 
					                shortHexa = "#00ff",
 | 
				
			||||||
 | 
					                hex = "#0000ff",
 | 
				
			||||||
 | 
					                hexa = "#0000ffff",
 | 
				
			||||||
 | 
					                rgb = "rgb(0,0,255)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,0,255,1.0)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0xff,
 | 
				
			||||||
 | 
					                a = 0xff,
 | 
				
			||||||
 | 
					                "rgba(0,0,255,1)"
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0xff000088u),
 | 
				
			||||||
 | 
					                shortHex = "#f00",
 | 
				
			||||||
 | 
					                shortHexa = "#f008",
 | 
				
			||||||
 | 
					                hex = "#ff0000",
 | 
				
			||||||
 | 
					                hexa = "#ff000088",
 | 
				
			||||||
 | 
					                rgb = "rgb(255,0,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(255,0,0,0.533)",
 | 
				
			||||||
 | 
					                r = 0xff,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x88,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x00ff0088u),
 | 
				
			||||||
 | 
					                shortHex = "#0f0",
 | 
				
			||||||
 | 
					                shortHexa = "#0f08",
 | 
				
			||||||
 | 
					                hex = "#00ff00",
 | 
				
			||||||
 | 
					                hexa = "#00ff0088",
 | 
				
			||||||
 | 
					                rgb = "rgb(0,255,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,255,0,0.533)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0xff,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x88,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x0000ff88u),
 | 
				
			||||||
 | 
					                shortHex = "#00f",
 | 
				
			||||||
 | 
					                shortHexa = "#00f8",
 | 
				
			||||||
 | 
					                hex = "#0000ff",
 | 
				
			||||||
 | 
					                hexa = "#0000ff88",
 | 
				
			||||||
 | 
					                rgb = "rgb(0,0,255)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,0,255,0.533)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0xff,
 | 
				
			||||||
 | 
					                a = 0x88,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0xff000022u),
 | 
				
			||||||
 | 
					                shortHex = "#f00",
 | 
				
			||||||
 | 
					                shortHexa = "#f002",
 | 
				
			||||||
 | 
					                hex = "#ff0000",
 | 
				
			||||||
 | 
					                hexa = "#ff000022",
 | 
				
			||||||
 | 
					                rgb = "rgb(255,0,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(255,0,0,0.133)",
 | 
				
			||||||
 | 
					                r = 0xff,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x22,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x00ff0022u),
 | 
				
			||||||
 | 
					                shortHex = "#0f0",
 | 
				
			||||||
 | 
					                shortHexa = "#0f02",
 | 
				
			||||||
 | 
					                hex = "#00ff00",
 | 
				
			||||||
 | 
					                hexa = "#00ff0022",
 | 
				
			||||||
 | 
					                rgb = "rgb(0,255,0)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,255,0,0.133)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0xff,
 | 
				
			||||||
 | 
					                b = 0x00,
 | 
				
			||||||
 | 
					                a = 0x22,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            TestColor(
 | 
				
			||||||
 | 
					                color = HEXAColor(0x0000ff22u),
 | 
				
			||||||
 | 
					                shortHex = "#00f",
 | 
				
			||||||
 | 
					                shortHexa = "#00f2",
 | 
				
			||||||
 | 
					                hex = "#0000ff",
 | 
				
			||||||
 | 
					                hexa = "#0000ff22",
 | 
				
			||||||
 | 
					                rgb = "rgb(0,0,255)",
 | 
				
			||||||
 | 
					                rgba = "rgba(0,0,255,0.133)",
 | 
				
			||||||
 | 
					                r = 0x00,
 | 
				
			||||||
 | 
					                g = 0x00,
 | 
				
			||||||
 | 
					                b = 0xff,
 | 
				
			||||||
 | 
					                a = 0x22,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun baseTest() {
 | 
				
			||||||
 | 
					        testColors.forEach {
 | 
				
			||||||
 | 
					            assertEquals(it.hex, it.color.hex)
 | 
				
			||||||
 | 
					            assertEquals(it.hexa, it.color.hexa)
 | 
				
			||||||
 | 
					            assertEquals(it.shortHex, it.color.shortHex)
 | 
				
			||||||
 | 
					            assertEquals(it.shortHexa, it.color.shortHexa)
 | 
				
			||||||
 | 
					            assertEquals(it.rgb, it.color.rgb)
 | 
				
			||||||
 | 
					            assertTrue(it.rgba == it.color.rgba || it.color.rgba in it.additionalRGBAVariants)
 | 
				
			||||||
 | 
					            assertEquals(it.r, it.color.r)
 | 
				
			||||||
 | 
					            assertEquals(it.g, it.color.g)
 | 
				
			||||||
 | 
					            assertEquals(it.b, it.color.b)
 | 
				
			||||||
 | 
					            assertEquals(it.a, it.color.a)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun testHexParseColor() {
 | 
				
			||||||
 | 
					        testColors.forEach {
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(aOfOne = 1f), HEXAColor.parseStringColor(it.hex))
 | 
				
			||||||
 | 
					            assertEquals(it.color, HEXAColor.parseStringColor(it.hexa))
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(aOfOne = 1f), HEXAColor.parseStringColor(it.rgb))
 | 
				
			||||||
 | 
					            assertTrue(it.color.uint.toInt() - HEXAColor.parseStringColor(it.rgba).uint.toInt() in -0x1 .. 0x1, )
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(aOfOne = 1f), HEXAColor.parseStringColor(it.shortHex))
 | 
				
			||||||
 | 
					            assertEquals(it.color.copy(a = floor(it.color.a.toFloat() / 16).toInt() * 0x10), HEXAColor.parseStringColor(it.shortHexa))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -27,7 +27,7 @@ private inline fun <T> getObject(
 | 
				
			|||||||
 * @see calculateDiff
 | 
					 * @see calculateDiff
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
data class Diff<T> internal constructor(
 | 
					data class Diff<T> @Warning(warning) constructor(
 | 
				
			||||||
    val removed: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>,
 | 
					    val removed: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>,
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Old-New values pairs
 | 
					     * Old-New values pairs
 | 
				
			||||||
@@ -36,6 +36,10 @@ data class Diff<T> internal constructor(
 | 
				
			|||||||
    val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>
 | 
					    val added: List<@Serializable(IndexedValueSerializer::class) IndexedValue<T>>
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    fun isEmpty(): Boolean = removed.isEmpty() && replaced.isEmpty() && added.isEmpty()
 | 
					    fun isEmpty(): Boolean = removed.isEmpty() && replaced.isEmpty() && added.isEmpty()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					        private const val warning = "This feature can be changed without any warranties. Use with caution and only in case you know what you are doing"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun <T> emptyDiff(): Diff<T> = Diff(emptyList(), emptyList(), emptyList())
 | 
					fun <T> emptyDiff(): Diff<T> = Diff(emptyList(), emptyList(), emptyList())
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,7 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.coroutines.compose
 | 
					package dev.inmo.micro_utils.coroutines.compose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import androidx.compose.runtime.MutableState
 | 
					import androidx.compose.runtime.MutableState
 | 
				
			||||||
import androidx.compose.runtime.State
 | 
					 | 
				
			||||||
import androidx.compose.runtime.derivedStateOf
 | 
					 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
 | 
					import dev.inmo.micro_utils.coroutines.SpecialMutableStateFlow
 | 
				
			||||||
import dev.inmo.micro_utils.coroutines.doInUI
 | 
					 | 
				
			||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -12,6 +9,7 @@ import kotlinx.coroutines.Dispatchers
 | 
				
			|||||||
 * This type works like [MutableState], [kotlinx.coroutines.flow.StateFlow] and [kotlinx.coroutines.flow.MutableSharedFlow].
 | 
					 * This type works like [MutableState], [kotlinx.coroutines.flow.StateFlow] and [kotlinx.coroutines.flow.MutableSharedFlow].
 | 
				
			||||||
 * Based on [SpecialMutableStateFlow]
 | 
					 * Based on [SpecialMutableStateFlow]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated("Will be removed soon")
 | 
				
			||||||
class FlowState<T>(
 | 
					class FlowState<T>(
 | 
				
			||||||
    initial: T,
 | 
					    initial: T,
 | 
				
			||||||
    internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
@@ -25,9 +23,9 @@ class FlowState<T>(
 | 
				
			|||||||
            tryEmit(value)
 | 
					            tryEmit(value)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override suspend fun onChange(value: T) {
 | 
					    override fun onChangeWithoutSync(value: T) {
 | 
				
			||||||
        internalValue = value
 | 
					        internalValue = value
 | 
				
			||||||
        super.onChange(value)
 | 
					        super.onChangeWithoutSync(value)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun component1(): T = value
 | 
					    override fun component1(): T = value
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,14 @@ package dev.inmo.micro_utils.coroutines
 | 
				
			|||||||
import kotlinx.coroutines.CoroutineScope
 | 
					import kotlinx.coroutines.CoroutineScope
 | 
				
			||||||
import kotlinx.coroutines.Dispatchers
 | 
					import kotlinx.coroutines.Dispatchers
 | 
				
			||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
					import kotlinx.coroutines.ExperimentalCoroutinesApi
 | 
				
			||||||
 | 
					import kotlinx.coroutines.InternalCoroutinesApi
 | 
				
			||||||
import kotlinx.coroutines.channels.BufferOverflow
 | 
					import kotlinx.coroutines.channels.BufferOverflow
 | 
				
			||||||
import kotlinx.coroutines.flow.FlowCollector
 | 
					import kotlinx.coroutines.flow.FlowCollector
 | 
				
			||||||
import kotlinx.coroutines.flow.MutableSharedFlow
 | 
					import kotlinx.coroutines.flow.MutableSharedFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.flow.MutableStateFlow
 | 
				
			||||||
import kotlinx.coroutines.flow.StateFlow
 | 
					import kotlinx.coroutines.flow.StateFlow
 | 
				
			||||||
 | 
					import kotlinx.coroutines.internal.SynchronizedObject
 | 
				
			||||||
 | 
					import kotlinx.coroutines.internal.synchronized
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Works like [StateFlow], but guarantee that latest value update will always be delivered to
 | 
					 * Works like [StateFlow], but guarantee that latest value update will always be delivered to
 | 
				
			||||||
@@ -15,7 +19,9 @@ import kotlinx.coroutines.flow.StateFlow
 | 
				
			|||||||
open class SpecialMutableStateFlow<T>(
 | 
					open class SpecialMutableStateFlow<T>(
 | 
				
			||||||
    initialValue: T,
 | 
					    initialValue: T,
 | 
				
			||||||
    internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
					    internalScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
 | 
				
			||||||
) : StateFlow<T>, FlowCollector<T>, MutableSharedFlow<T> {
 | 
					) : MutableStateFlow<T>, FlowCollector<T>, MutableSharedFlow<T> {
 | 
				
			||||||
 | 
					    @OptIn(InternalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    private val syncObject = SynchronizedObject()
 | 
				
			||||||
    protected val internalSharedFlow: MutableSharedFlow<T> = MutableSharedFlow(
 | 
					    protected val internalSharedFlow: MutableSharedFlow<T> = MutableSharedFlow(
 | 
				
			||||||
        replay = 0,
 | 
					        replay = 0,
 | 
				
			||||||
        extraBufferCapacity = 2,
 | 
					        extraBufferCapacity = 2,
 | 
				
			||||||
@@ -28,16 +34,13 @@ open class SpecialMutableStateFlow<T>(
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected var _value: T = initialValue
 | 
					    protected var _value: T = initialValue
 | 
				
			||||||
    override val value: T
 | 
					    override var value: T
 | 
				
			||||||
        get() = _value
 | 
					        get() = _value
 | 
				
			||||||
    protected open suspend fun onChange(value: T) {
 | 
					        set(value) {
 | 
				
			||||||
        _value = value
 | 
					            doOnChangeAction(value)
 | 
				
			||||||
        publicSharedFlow.emit(value)
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    protected val job = internalSharedFlow.subscribe(internalScope) {
 | 
					    protected val job = internalSharedFlow.subscribe(internalScope) {
 | 
				
			||||||
        if (_value != it) {
 | 
					        doOnChangeAction(it)
 | 
				
			||||||
            onChange(it)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val replayCache: List<T>
 | 
					    override val replayCache: List<T>
 | 
				
			||||||
@@ -45,6 +48,29 @@ open class SpecialMutableStateFlow<T>(
 | 
				
			|||||||
    override val subscriptionCount: StateFlow<Int>
 | 
					    override val subscriptionCount: StateFlow<Int>
 | 
				
			||||||
        get() = publicSharedFlow.subscriptionCount
 | 
					        get() = publicSharedFlow.subscriptionCount
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @OptIn(InternalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    override fun compareAndSet(expect: T, update: T): Boolean {
 | 
				
			||||||
 | 
					        return synchronized(syncObject) {
 | 
				
			||||||
 | 
					            if (expect == _value && update != _value) {
 | 
				
			||||||
 | 
					                doOnChangeAction(update)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            expect == _value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected open fun onChangeWithoutSync(value: T) {
 | 
				
			||||||
 | 
					        _value = value
 | 
				
			||||||
 | 
					        publicSharedFlow.tryEmit(value)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    @OptIn(InternalCoroutinesApi::class)
 | 
				
			||||||
 | 
					    protected open fun doOnChangeAction(value: T) {
 | 
				
			||||||
 | 
					        synchronized(syncObject) {
 | 
				
			||||||
 | 
					            if (_value != value) {
 | 
				
			||||||
 | 
					                onChangeWithoutSync(value)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @ExperimentalCoroutinesApi
 | 
					    @ExperimentalCoroutinesApi
 | 
				
			||||||
    override fun resetReplayCache() = publicSharedFlow.resetReplayCache()
 | 
					    override fun resetReplayCache() = publicSharedFlow.resetReplayCache()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ kotlin.incremental.js=true
 | 
				
			|||||||
#kotlin.experimental.tryK2=true
 | 
					#kotlin.experimental.tryK2=true
 | 
				
			||||||
android.useAndroidX=true
 | 
					android.useAndroidX=true
 | 
				
			||||||
android.enableJetifier=true
 | 
					android.enableJetifier=true
 | 
				
			||||||
org.gradle.jvmargs=-Xmx2500m
 | 
					org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2g
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# JS NPM
 | 
					# JS NPM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15,5 +15,5 @@ crypto_js_version=4.1.1
 | 
				
			|||||||
# Project data
 | 
					# Project data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
group=dev.inmo
 | 
					group=dev.inmo
 | 
				
			||||||
version=0.20.16
 | 
					version=0.20.25
 | 
				
			||||||
android_code_version=222
 | 
					android_code_version=231
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
[versions]
 | 
					[versions]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kt = "1.9.21"
 | 
					kt = "1.9.21"
 | 
				
			||||||
kt-serialization = "1.6.1"
 | 
					kt-serialization = "1.6.2"
 | 
				
			||||||
kt-coroutines = "1.7.3"
 | 
					kt-coroutines = "1.7.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
kslog = "1.3.1"
 | 
					kslog = "1.3.1"
 | 
				
			||||||
@@ -10,23 +10,23 @@ jb-compose = "1.5.11"
 | 
				
			|||||||
jb-exposed = "0.45.0"
 | 
					jb-exposed = "0.45.0"
 | 
				
			||||||
jb-dokka = "1.9.10"
 | 
					jb-dokka = "1.9.10"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
korlibs = "4.0.10"
 | 
					korlibs = "5.3.0"
 | 
				
			||||||
uuid = "0.8.2"
 | 
					uuid = "0.8.2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ktor = "2.3.6"
 | 
					ktor = "2.3.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
gh-release = "2.4.1"
 | 
					gh-release = "2.4.1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
koin = "3.5.0"
 | 
					koin = "3.5.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
okio = "3.6.0"
 | 
					okio = "3.7.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ksp = "1.9.21-1.0.15"
 | 
					ksp = "1.9.21-1.0.16"
 | 
				
			||||||
kotlin-poet = "1.15.1"
 | 
					kotlin-poet = "1.15.3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
versions = "0.50.0"
 | 
					versions = "0.50.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-gradle = "8.1.4"
 | 
					android-gradle = "8.2.0"
 | 
				
			||||||
dexcount = "4.0.0"
 | 
					dexcount = "4.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
android-coreKtx = "1.12.0"
 | 
					android-coreKtx = "1.12.0"
 | 
				
			||||||
@@ -72,8 +72,8 @@ ktor-server-content-negotiation = { module = "io.ktor:ktor-server-content-negoti
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
 | 
					kslog = { module = "dev.inmo:kslog", version.ref = "kslog" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
klock = { module = "com.soywiz.korlibs.klock:klock", version.ref = "korlibs" }
 | 
					klock = { module = "com.soywiz.korge:korlibs-time", version.ref = "korlibs" }
 | 
				
			||||||
krypto = { module = "com.soywiz.korlibs.krypto:krypto", version.ref = "korlibs" }
 | 
					krypto = { module = "com.soywiz.korge:korlibs-crypto", version.ref = "korlibs" }
 | 
				
			||||||
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" }
 | 
					koin = { module = "io.insert-koin:koin-core", version.ref = "koin" }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -68,18 +68,14 @@ publishing {
 | 
				
			|||||||
                
 | 
					                
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
 | 
					                if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
 | 
				
			||||||
                    maven {
 | 
					                    maven {
 | 
				
			||||||
                        name = "Gitea"
 | 
					                        name = "InmoNexus"
 | 
				
			||||||
                        url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
 | 
					                        url = uri("https://nexus.inmo.dev/repository/maven-releases/")
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                        credentials(HttpHeaderCredentials) {
 | 
					                        credentials {
 | 
				
			||||||
                            name = "Authorization"
 | 
					                            username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
 | 
				
			||||||
                            value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
 | 
					                            password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                
 | 
					 | 
				
			||||||
                        authentication {
 | 
					 | 
				
			||||||
                            header(HttpHeaderAuthentication)
 | 
					 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@@ -121,4 +117,21 @@ if (project.hasProperty("signing.gnupg.keyName")) {
 | 
				
			|||||||
        def signingTasks = project.getTasks().withType(Sign.class)
 | 
					        def signingTasks = project.getTasks().withType(Sign.class)
 | 
				
			||||||
        mustRunAfter(signingTasks)
 | 
					        mustRunAfter(signingTasks)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // Workaround to make test tasks use sign
 | 
				
			||||||
 | 
					    project.getTasks().withType(Sign.class).configureEach { signTask ->
 | 
				
			||||||
 | 
					        def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
 | 
				
			||||||
 | 
					        def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
 | 
				
			||||||
 | 
					        // These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def debugTestTask = tasks.findByName("linkDebugTest$pubName")
 | 
				
			||||||
 | 
					        if (debugTestTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(debugTestTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def testTask = tasks.findByName("compileTestKotlin$pubName")
 | 
				
			||||||
 | 
					        if (testTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(testTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}
 | 
					{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}},"type":"JVM"}
 | 
				
			||||||
@@ -12,9 +12,12 @@ private val json = Json {
 | 
				
			|||||||
    ignoreUnknownKeys = true
 | 
					    ignoreUnknownKeys = true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private const val baseClassName = "IetfLanguageCode"
 | 
					private const val baseClassName = "IetfLang"
 | 
				
			||||||
 | 
					private const val oldBaseClassName = "IetfLanguageCode"
 | 
				
			||||||
private const val unknownBaseClassName = "Unknown$baseClassName"
 | 
					private const val unknownBaseClassName = "Unknown$baseClassName"
 | 
				
			||||||
private const val baseClassSerializerName = "IetfLanguageCodeSerializer"
 | 
					private const val oldUnknownBaseClassName = "Unknown$oldBaseClassName"
 | 
				
			||||||
 | 
					private const val baseClassSerializerName = "${baseClassName}Serializer"
 | 
				
			||||||
 | 
					private const val oldBaseClassSerializerName = "IetfLanguageCodeSerializer"
 | 
				
			||||||
private const val baseClassSerializerAnnotationName = "@Serializable(${baseClassSerializerName}::class)"
 | 
					private const val baseClassSerializerAnnotationName = "@Serializable(${baseClassSerializerName}::class)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Serializable
 | 
					@Serializable
 | 
				
			||||||
@@ -78,14 +81,12 @@ private fun printLanguageCodeAndTags(
 | 
				
			|||||||
    indents: String = "    "
 | 
					    indents: String = "    "
 | 
				
			||||||
): String = if (tag.subtags.isEmpty()) {
 | 
					): String = if (tag.subtags.isEmpty()) {
 | 
				
			||||||
"""${indents}${baseClassSerializerAnnotationName}
 | 
					"""${indents}${baseClassSerializerAnnotationName}
 | 
				
			||||||
${indents}object ${tag.title} : ${parent ?.title ?: baseClassName}() { override val code: String = "${tag.tag}"; override val withoutDialect: String get() = ${parent ?.title ?.let { "$it.code" } ?: "code"} }"""
 | 
					${indents}object ${tag.title} : ${parent ?.title ?: baseClassName}() { override val code: String = "${tag.tag}"${parent ?.let { parent -> "; override val parentLang: ${parent.title} get() = ${parent.title};" } ?: ""} }"""
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
${indents}${baseClassSerializerAnnotationName}
 | 
					${indents}${baseClassSerializerAnnotationName}
 | 
				
			||||||
${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
 | 
					${indents}sealed class ${tag.title} : ${parent ?.title ?: baseClassName}() {
 | 
				
			||||||
${indents}    override val code: String = "${tag.tag}"
 | 
					${indents}    override val code: String = "${tag.tag}"${parent ?.let { parent -> "\n${indents}    override val parentLang: ${parent.title} get() = ${parent.title};" } ?: ""}
 | 
				
			||||||
${indents}    override val withoutDialect: String
 | 
					 | 
				
			||||||
${indents}        get() = code
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents}    ") }}
 | 
					${tag.subtags.joinToString("\n") { printLanguageCodeAndTags(it, tag, "${indents}    ") }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,7 +96,7 @@ ${indents}}
 | 
				
			|||||||
"""
 | 
					"""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun buildKtFileContent(tags: List<Tag>): String = """
 | 
					fun buildKtFileContent(tags: List<Tag>, prePackage: String): String = """
 | 
				
			||||||
import kotlinx.serialization.Serializable
 | 
					import kotlinx.serialization.Serializable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -106,20 +107,27 @@ import kotlinx.serialization.Serializable
 | 
				
			|||||||
${baseClassSerializerAnnotationName}
 | 
					${baseClassSerializerAnnotationName}
 | 
				
			||||||
sealed class $baseClassName {
 | 
					sealed class $baseClassName {
 | 
				
			||||||
    abstract val code: String
 | 
					    abstract val code: String
 | 
				
			||||||
    abstract val withoutDialect: String
 | 
					    open val parentLang: $baseClassName?
 | 
				
			||||||
 | 
					        get() = null
 | 
				
			||||||
 | 
					    open val withoutDialect: String
 | 
				
			||||||
 | 
					        get() = parentLang ?.code ?: code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = "    ") } }
 | 
					${tags.joinToString("\n") { printLanguageCodeAndTags(it, indents = "    ") } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $baseClassSerializerAnnotationName
 | 
					    $baseClassSerializerAnnotationName
 | 
				
			||||||
    data class $unknownBaseClassName (override val code: String) : $baseClassName() {
 | 
					    data class $unknownBaseClassName (override val code: String) : $baseClassName() {
 | 
				
			||||||
        override val withoutDialect: String = code.takeWhile { it != '-' }
 | 
					        override val parentLang = code.dropLastWhile { it != '-' }.removeSuffix("-").takeIf { it.length > 0 } ?.let(::$unknownBaseClassName)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    @Deprecated("Renamed", ReplaceWith("$baseClassName.$unknownBaseClassName", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassName.$unknownBaseClassName"))
 | 
				
			||||||
 | 
					    val $oldUnknownBaseClassName = $unknownBaseClassName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun toString() = code
 | 
					    override fun toString() = code
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("$baseClassName", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassName"))
 | 
				
			||||||
 | 
					typealias $oldBaseClassName = $baseClassName
 | 
				
			||||||
""".trimIndent()
 | 
					""".trimIndent()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun createStringConverterCode(tags: List<Tag>): String {
 | 
					fun createStringConverterCode(tags: List<Tag>, prePackage: String): String {
 | 
				
			||||||
    fun createDeserializeVariantForTag(
 | 
					    fun createDeserializeVariantForTag(
 | 
				
			||||||
        tag: Tag,
 | 
					        tag: Tag,
 | 
				
			||||||
        pretitle: String = baseClassName,
 | 
					        pretitle: String = baseClassName,
 | 
				
			||||||
@@ -128,19 +136,70 @@ fun createStringConverterCode(tags: List<Tag>): String {
 | 
				
			|||||||
        val currentTitle = "$pretitle.${tag.title}"
 | 
					        val currentTitle = "$pretitle.${tag.title}"
 | 
				
			||||||
        return """${indents}$currentTitle.code -> $currentTitle${if (tag.subtags.isNotEmpty()) tag.subtags.joinToString("\n", "\n") { createDeserializeVariantForTag(it, currentTitle, indents) } else ""}"""
 | 
					        return """${indents}$currentTitle.code -> $currentTitle${if (tag.subtags.isNotEmpty()) tag.subtags.joinToString("\n", "\n") { createDeserializeVariantForTag(it, currentTitle, indents) } else ""}"""
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fun createInheritorVariantForTag(
 | 
				
			||||||
 | 
					        tag: Tag,
 | 
				
			||||||
 | 
					        pretitle: String = baseClassName,
 | 
				
			||||||
 | 
					        indents: String = "        "
 | 
				
			||||||
 | 
					    ): String {
 | 
				
			||||||
 | 
					        val currentTitle = "$pretitle.${tag.title}"
 | 
				
			||||||
 | 
					        val subtags = if (tag.subtags.isNotEmpty()) {
 | 
				
			||||||
 | 
					            tag.subtags.joinToString(",\n", ",\n") { createInheritorVariantForTag(it, currentTitle, "$indents    ") }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "${indents}$currentTitle$subtags"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fun createInheritorVariantForMapForTag(
 | 
				
			||||||
 | 
					        tag: Tag,
 | 
				
			||||||
 | 
					        pretitle: String = baseClassName,
 | 
				
			||||||
 | 
					        indents: String = "        ",
 | 
				
			||||||
 | 
					        codeSuffix: String = ""
 | 
				
			||||||
 | 
					    ): String {
 | 
				
			||||||
 | 
					        val currentTitle = "$pretitle.${tag.title}"
 | 
				
			||||||
 | 
					        val subtags = if (tag.subtags.isNotEmpty()) {
 | 
				
			||||||
 | 
					            tag.subtags.joinToString(",\n", ",\n") { createInheritorVariantForMapForTag(it, currentTitle, "$indents    ", codeSuffix) }
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return "${indents}$currentTitle.code${codeSuffix} to $currentTitle$subtags"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return """fun String.as$baseClassName(): $baseClassName {
 | 
					    return """val knownLanguageCodesMap: Map<String, $baseClassName> by lazy {
 | 
				
			||||||
    return when (this) {
 | 
					    mapOf(
 | 
				
			||||||
${tags.joinToString("\n") { createDeserializeVariantForTag(it) }}
 | 
					${tags.joinToString(",\n") { createInheritorVariantForMapForTag(it, indents = "        ") }}
 | 
				
			||||||
        else -> $baseClassName.${unknownBaseClassName}(this)
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					val knownLanguageCodesMapByLowerCasedKeys: Map<String, $baseClassName> by lazy {
 | 
				
			||||||
 | 
					    mapOf(
 | 
				
			||||||
 | 
					${tags.joinToString(",\n") { createInheritorVariantForMapForTag(it, indents = "        ", codeSuffix = ".lowercase()") }}
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					val knownLanguageCodes: List<$baseClassName> by lazy {
 | 
				
			||||||
 | 
					    knownLanguageCodesMap.values.toList()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun String.as$baseClassName(): $baseClassName {
 | 
				
			||||||
 | 
					    return knownLanguageCodesMap[this] ?: $baseClassName.${unknownBaseClassName}(this)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					fun String.as${baseClassName}CaseInsensitive(): $baseClassName {
 | 
				
			||||||
 | 
					    return knownLanguageCodesMapByLowerCasedKeys[this.lowercase()] ?: $baseClassName.${unknownBaseClassName}(this)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("this.as$baseClassName()", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}as$baseClassName"))
 | 
				
			||||||
 | 
					fun String.as$oldBaseClassName(): $baseClassName = as$baseClassName()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun convertTo$baseClassName(code: String) = code.as$baseClassName()
 | 
					fun convertTo$baseClassName(code: String) = code.as$baseClassName()
 | 
				
			||||||
 | 
					fun convertTo${baseClassName}CaseInsensitive(code: String) = code.as${baseClassName}CaseInsensitive()
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("convertTo$baseClassName(code)", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}convertTo$baseClassName"))
 | 
				
			||||||
 | 
					fun convertTo$oldBaseClassName(code: String) = convertTo$baseClassName(code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun $baseClassName(code: String) = code.as$baseClassName()
 | 
					fun $baseClassName(code: String) = code.as$baseClassName()
 | 
				
			||||||
 | 
					fun ${baseClassName}CaseInsensitive(code: String) = code.as${baseClassName}CaseInsensitive()
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("$baseClassName(code)", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassName"))
 | 
				
			||||||
 | 
					fun $oldBaseClassName(code: String) = $baseClassName(code)
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun createSerializerCode(tags: List<Tag>): String {
 | 
					fun createSerializerCode(tags: List<Tag>, prePackage: String): String {
 | 
				
			||||||
    return """import kotlinx.serialization.KSerializer
 | 
					    return """import kotlinx.serialization.KSerializer
 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					import kotlinx.serialization.builtins.serializer
 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
@@ -153,16 +212,20 @@ object $baseClassSerializerName : KSerializer<$baseClassName> {
 | 
				
			|||||||
        return $baseClassName(decoder.decodeString())
 | 
					        return $baseClassName(decoder.decodeString())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: IetfLanguageCode) {
 | 
					    override fun serialize(encoder: Encoder, value: $baseClassName) {
 | 
				
			||||||
        encoder.encodeString(value.code)
 | 
					        encoder.encodeString(value.code)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("$baseClassSerializerName", "${if (prePackage.isNotEmpty()) "$prePackage." else ""}$baseClassSerializerName"))
 | 
				
			||||||
 | 
					typealias $oldBaseClassSerializerName = $baseClassSerializerName
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
suspend fun main(vararg args: String) {
 | 
					suspend fun main(vararg args: String) {
 | 
				
			||||||
    val outputFolder = args.firstOrNull() ?.let { File(it) }
 | 
					    val outputFolder = args.firstOrNull() ?.let { File(it) }
 | 
				
			||||||
    outputFolder ?.mkdirs()
 | 
					    outputFolder ?.mkdirs()
 | 
				
			||||||
 | 
					    val targetPackage = args.getOrNull(1)
 | 
				
			||||||
 | 
					    val targetPackagePrefix = targetPackage ?.let { "package $it\n\n" } ?: ""
 | 
				
			||||||
    val ietfLanguageCodesLink = "https://datahub.io/core/language-codes/r/language-codes.json"
 | 
					    val ietfLanguageCodesLink = "https://datahub.io/core/language-codes/r/language-codes.json"
 | 
				
			||||||
    val ietfLanguageCodesAdditionalTagsLink = "https://datahub.io/core/language-codes/r/ietf-language-tags.json"
 | 
					    val ietfLanguageCodesAdditionalTagsLink = "https://datahub.io/core/language-codes/r/ietf-language-tags.json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -203,18 +266,18 @@ suspend fun main(vararg args: String) {
 | 
				
			|||||||
    File(outputFolder, "LanguageCodes.kt").apply {
 | 
					    File(outputFolder, "LanguageCodes.kt").apply {
 | 
				
			||||||
        delete()
 | 
					        delete()
 | 
				
			||||||
        createNewFile()
 | 
					        createNewFile()
 | 
				
			||||||
        writeText(buildKtFileContent(tags))
 | 
					        writeText(targetPackagePrefix + buildKtFileContent(tags, targetPackage ?: ""))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    File(outputFolder, "StringToLanguageCodes.kt").apply {
 | 
					    File(outputFolder, "StringToLanguageCodes.kt").apply {
 | 
				
			||||||
        delete()
 | 
					        delete()
 | 
				
			||||||
        createNewFile()
 | 
					        createNewFile()
 | 
				
			||||||
        writeText(createStringConverterCode(tags))
 | 
					        writeText(targetPackagePrefix + createStringConverterCode(tags, targetPackage ?: ""))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    File(outputFolder, "$baseClassSerializerName.kt").apply {
 | 
					    File(outputFolder, "$baseClassSerializerName.kt").apply {
 | 
				
			||||||
        delete()
 | 
					        delete()
 | 
				
			||||||
        createNewFile()
 | 
					        createNewFile()
 | 
				
			||||||
        writeText(createSerializerCode(tags))
 | 
					        writeText(targetPackagePrefix + createSerializerCode(tags, targetPackage ?: ""))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.language_codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.KSerializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.builtins.serializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object IetfLangSerializer : KSerializer<IetfLang> {
 | 
				
			||||||
 | 
					    override val descriptor = String.serializer().descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun deserialize(decoder: Decoder): IetfLang {
 | 
				
			||||||
 | 
					        return IetfLang(decoder.decodeString())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun serialize(encoder: Encoder, value: IetfLang) {
 | 
				
			||||||
 | 
					        encoder.encodeString(value.code)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("IetfLangSerializer", "dev.inmo.micro_utils.language_codes.IetfLangSerializer"))
 | 
				
			||||||
 | 
					typealias IetfLanguageCodeSerializer = IetfLangSerializer
 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.language_codes
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.builtins.serializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
object IetfLanguageCodeSerializer : KSerializer<IetfLanguageCode> {
 | 
					 | 
				
			||||||
    override val descriptor = String.serializer().descriptor
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun deserialize(decoder: Decoder): IetfLanguageCode {
 | 
					 | 
				
			||||||
        return IetfLanguageCode(decoder.decodeString())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: IetfLanguageCode) {
 | 
					 | 
				
			||||||
        encoder.encodeString(value.code)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.language_codes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlin.test.Test
 | 
				
			||||||
 | 
					import kotlin.test.assertEquals
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UnknownIetfLanguageTests {
 | 
				
			||||||
 | 
					    @Test
 | 
				
			||||||
 | 
					    fun commonTestOfParentCode() {
 | 
				
			||||||
 | 
					        knownLanguageCodes.forEach {
 | 
				
			||||||
 | 
					            val language = IetfLang.UnknownIetfLang(it.code)
 | 
				
			||||||
 | 
					            assertEquals(it.code, language.code)
 | 
				
			||||||
 | 
					            assertEquals(it.withoutDialect, language.withoutDialect)
 | 
				
			||||||
 | 
					            assertEquals(it.parentLang ?.code, language.parentLang ?.code)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,7 +2,9 @@ package dev.inmo.micro_utils.language_codes
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.util.Locale
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun IetfLanguageCode.toJavaLocale(): Locale = Locale.forLanguageTag(code)
 | 
					fun IetfLang.toJavaLocale(): Locale = Locale.forLanguageTag(code)
 | 
				
			||||||
fun IetfLanguageCode?.toJavaLocaleOrDefault(): Locale = this ?.toJavaLocale() ?: Locale.getDefault()
 | 
					fun IetfLang?.toJavaLocaleOrDefault(): Locale = this?.toJavaLocale() ?: Locale.getDefault()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun Locale.toIetfLanguageCode(): IetfLanguageCode = IetfLanguageCode(toLanguageTag())
 | 
					fun Locale.toIetfLang(): IetfLang = IetfLang(toLanguageTag())
 | 
				
			||||||
 | 
					@Deprecated("Renamed", ReplaceWith("this.toIetfLang()", "dev.inmo.micro_utils.language_codes.toIetfLang"))
 | 
				
			||||||
 | 
					fun Locale.toIetfLanguageCode(): IetfLang = toIetfLang()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,18 +57,14 @@ publishing {
 | 
				
			|||||||
            
 | 
					            
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (project.hasProperty('GITEA_TOKEN') || System.getenv('GITEA_TOKEN') != null) {
 | 
					            if ((project.hasProperty('INMONEXUS_USER') || System.getenv('INMONEXUS_USER') != null) && (project.hasProperty('INMONEXUS_PASSWORD') || System.getenv('INMONEXUS_PASSWORD') != null)) {
 | 
				
			||||||
                maven {
 | 
					                maven {
 | 
				
			||||||
                    name = "Gitea"
 | 
					                    name = "InmoNexus"
 | 
				
			||||||
                    url = uri("https://git.inmo.dev/api/packages/InsanusMokrassar/maven")
 | 
					                    url = uri("https://nexus.inmo.dev/repository/maven-releases/")
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
                    credentials(HttpHeaderCredentials) {
 | 
					                    credentials {
 | 
				
			||||||
                        name = "Authorization"
 | 
					                        username = project.hasProperty('INMONEXUS_USER') ? project.property('INMONEXUS_USER') : System.getenv('INMONEXUS_USER')
 | 
				
			||||||
                        value = project.hasProperty('GITEA_TOKEN') ? project.property('GITEA_TOKEN') : System.getenv('GITEA_TOKEN')
 | 
					                        password = project.hasProperty('INMONEXUS_PASSWORD') ? project.property('INMONEXUS_PASSWORD') : System.getenv('INMONEXUS_PASSWORD')
 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
                    authentication {
 | 
					 | 
				
			||||||
                        header(HttpHeaderAuthentication)
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -109,4 +105,21 @@ if (project.hasProperty("signing.gnupg.keyName")) {
 | 
				
			|||||||
        def signingTasks = project.getTasks().withType(Sign.class)
 | 
					        def signingTasks = project.getTasks().withType(Sign.class)
 | 
				
			||||||
        mustRunAfter(signingTasks)
 | 
					        mustRunAfter(signingTasks)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // Workaround to make test tasks use sign
 | 
				
			||||||
 | 
					    project.getTasks().withType(Sign.class).configureEach { signTask ->
 | 
				
			||||||
 | 
					        def withoutSign = (signTask.name.startsWith("sign") ? signTask.name.minus("sign") : signTask.name)
 | 
				
			||||||
 | 
					        def pubName = withoutSign.endsWith("Publication") ? withoutSign.substring(0, withoutSign.length() - "Publication".length()) : withoutSign
 | 
				
			||||||
 | 
					        // These tasks only exist for native targets, hence findByName() to avoid trying to find them for other targets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Task ':linkDebugTest<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def debugTestTask = tasks.findByName("linkDebugTest$pubName")
 | 
				
			||||||
 | 
					        if (debugTestTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(debugTestTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // Task ':compileTestKotlin<platform>' uses this output of task ':sign<platform>Publication' without declaring an explicit or implicit dependency
 | 
				
			||||||
 | 
					        def testTask = tasks.findByName("compileTestKotlin$pubName")
 | 
				
			||||||
 | 
					        if (testTask != null) {
 | 
				
			||||||
 | 
					            signTask.mustRunAfter(testTask)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1 @@
 | 
				
			|||||||
{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"Gitea","url":"https://git.inmo.dev/api/packages/InsanusMokrassar/maven","credsType":{"type":"dev.inmo.kmppscriptbuilder.core.models.MavenPublishingRepository.CredentialsType.HttpHeaderCredentials","headerName":"Authorization","headerValueProperty":"GITEA_TOKEN"}},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
 | 
					{"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/MicroUtils/blob/master/LICENSE"}],"mavenConfig":{"name":"${project.name}","description":"It is set of projects with micro tools for avoiding of routines coding","url":"https://github.com/InsanusMokrassar/MicroUtils/","vcsUrl":"https://github.com/InsanusMokrassar/MicroUtils.git","developers":[{"id":"InsanusMokrassar","name":"Aleksei Ovsiannikov","eMail":"ovsyannikov.alexey95@gmail.com"},{"id":"000Sanya","name":"Syrov Aleksandr","eMail":"000sanya.000sanya@gmail.com"}],"repositories":[{"name":"GithubPackages","url":"https://maven.pkg.github.com/InsanusMokrassar/MicroUtils"},{"name":"InmoNexus","url":"https://nexus.inmo.dev/repository/maven-releases/"},{"name":"sonatype","url":"https://oss.sonatype.org/service/local/staging/deploy/maven2/"}],"gpgSigning":{"type":"dev.inmo.kmppscriptbuilder.core.models.GpgSigning.Optional"}}}
 | 
				
			||||||
@@ -1,14 +1,19 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.repos.exposed
 | 
					package dev.inmo.micro_utils.repos.exposed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.repos.CRUDRepo
 | 
					import dev.inmo.micro_utils.repos.CRUDRepo
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.BufferOverflow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					abstract class AbstractExposedCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    flowsChannelsSize: Int = 0,
 | 
					    flowsChannelsSize: Int = 0,
 | 
				
			||||||
    tableName: String = ""
 | 
					    tableName: String = "",
 | 
				
			||||||
 | 
					    replyCacheInFlows: Int = 0,
 | 
				
			||||||
 | 
					    onBufferOverflowBehaviour: BufferOverflow = BufferOverflow.SUSPEND
 | 
				
			||||||
) :
 | 
					) :
 | 
				
			||||||
    AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					    AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
        flowsChannelsSize,
 | 
					        flowsChannelsSize,
 | 
				
			||||||
        tableName
 | 
					        tableName,
 | 
				
			||||||
 | 
					        replyCacheInFlows,
 | 
				
			||||||
 | 
					        onBufferOverflowBehaviour
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
    ExposedCRUDRepo<ObjectType, IdType>,
 | 
					    ExposedCRUDRepo<ObjectType, IdType>,
 | 
				
			||||||
    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
					    CRUDRepo<ObjectType, IdType, InputValueType>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ package dev.inmo.micro_utils.repos.exposed
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import dev.inmo.micro_utils.repos.UpdatedValuePair
 | 
					import dev.inmo.micro_utils.repos.UpdatedValuePair
 | 
				
			||||||
import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
					import dev.inmo.micro_utils.repos.WriteCRUDRepo
 | 
				
			||||||
 | 
					import kotlinx.coroutines.channels.BufferOverflow
 | 
				
			||||||
import kotlinx.coroutines.flow.*
 | 
					import kotlinx.coroutines.flow.*
 | 
				
			||||||
import org.jetbrains.exposed.sql.*
 | 
					import org.jetbrains.exposed.sql.*
 | 
				
			||||||
import org.jetbrains.exposed.sql.statements.*
 | 
					import org.jetbrains.exposed.sql.statements.*
 | 
				
			||||||
@@ -11,19 +12,26 @@ import java.util.Objects
 | 
				
			|||||||
abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
					abstract class AbstractExposedWriteCRUDRepo<ObjectType, IdType, InputValueType>(
 | 
				
			||||||
    flowsChannelsSize: Int = 0,
 | 
					    flowsChannelsSize: Int = 0,
 | 
				
			||||||
    tableName: String = "",
 | 
					    tableName: String = "",
 | 
				
			||||||
    replyCacheInFlows: Int = 0
 | 
					    replyCacheInFlows: Int = 0,
 | 
				
			||||||
 | 
					    onBufferOverflowBehaviour: BufferOverflow = BufferOverflow.SUSPEND
 | 
				
			||||||
) :
 | 
					) :
 | 
				
			||||||
    AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName),
 | 
					    AbstractExposedReadCRUDRepo<ObjectType, IdType>(tableName),
 | 
				
			||||||
    ExposedCRUDRepo<ObjectType, IdType>,
 | 
					    ExposedCRUDRepo<ObjectType, IdType>,
 | 
				
			||||||
    WriteCRUDRepo<ObjectType, IdType, InputValueType>
 | 
					    WriteCRUDRepo<ObjectType, IdType, InputValueType>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize)
 | 
					    protected open val _newObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize, onBufferOverflowBehaviour)
 | 
				
			||||||
    protected val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize)
 | 
					    protected open val _updatedObjectsFlow = MutableSharedFlow<ObjectType>(replyCacheInFlows, flowsChannelsSize, onBufferOverflowBehaviour)
 | 
				
			||||||
    protected val _deletedObjectsIdsFlow = MutableSharedFlow<IdType>(replyCacheInFlows, flowsChannelsSize)
 | 
					    protected open val _deletedObjectsIdsFlow = MutableSharedFlow<IdType>(replyCacheInFlows, flowsChannelsSize, onBufferOverflowBehaviour)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val newObjectsFlow: Flow<ObjectType> = _newObjectsFlow.asSharedFlow()
 | 
					    override val newObjectsFlow: Flow<ObjectType> by lazy {
 | 
				
			||||||
    override val updatedObjectsFlow: Flow<ObjectType> = _updatedObjectsFlow.asSharedFlow()
 | 
					        _newObjectsFlow.asSharedFlow()
 | 
				
			||||||
    override val deletedObjectsIdsFlow: Flow<IdType> = _deletedObjectsIdsFlow.asSharedFlow()
 | 
					    }
 | 
				
			||||||
 | 
					    override val updatedObjectsFlow: Flow<ObjectType> by lazy {
 | 
				
			||||||
 | 
					        _updatedObjectsFlow.asSharedFlow()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    override val deletedObjectsIdsFlow: Flow<IdType> by lazy {
 | 
				
			||||||
 | 
					        _deletedObjectsIdsFlow.asSharedFlow()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType
 | 
					    protected abstract fun InsertStatement<Number>.asObject(value: InputValueType): ObjectType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								resources/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								resources/build.gradle
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.multiplatform"
 | 
				
			||||||
 | 
					    id "org.jetbrains.kotlin.plugin.serialization"
 | 
				
			||||||
 | 
					    id "com.android.library"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					apply from: "$mppJvmJsAndroidLinuxMingwLinuxArm64ProjectPresetPath"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					kotlin {
 | 
				
			||||||
 | 
					    sourceSets {
 | 
				
			||||||
 | 
					        commonMain {
 | 
				
			||||||
 | 
					            dependencies {
 | 
				
			||||||
 | 
					                api project(":micro_utils.language_codes")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        androidMain {
 | 
				
			||||||
 | 
					            dependsOn(jvmMain)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.content.Context
 | 
				
			||||||
 | 
					import android.content.res.Configuration
 | 
				
			||||||
 | 
					import android.content.res.Resources
 | 
				
			||||||
 | 
					import android.os.Build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun StringResource.translation(configuration: Configuration): String = translation(
 | 
				
			||||||
 | 
					    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
 | 
				
			||||||
 | 
					        configuration.locales[0]
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        configuration.locale
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					fun StringResource.translation(resources: Resources): String = translation(resources.configuration)
 | 
				
			||||||
 | 
					fun StringResource.translation(context: Context): String = translation(context.resources)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Configuration.translation(resource: StringResource): String = resource.translation(this)
 | 
				
			||||||
 | 
					fun Resources.translation(resource: StringResource): String = configuration.translation(resource)
 | 
				
			||||||
 | 
					fun Context.translation(resource: StringResource): String = resources.translation(resource)
 | 
				
			||||||
							
								
								
									
										56
									
								
								resources/src/commonMain/kotlin/StringResource.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								resources/src/commonMain/kotlin/StringResource.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.language_codes.IetfLang
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Use this class as a type of your strings object fields. For example:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * ```kotlin
 | 
				
			||||||
 | 
					 * object Strings {
 | 
				
			||||||
 | 
					 *     val someResource: StringResource
 | 
				
			||||||
 | 
					 * }
 | 
				
			||||||
 | 
					 * ```
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Use [buildStringResource] for useful creation of string resource
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @see buildStringResource
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					class StringResource(
 | 
				
			||||||
 | 
					    val default: String,
 | 
				
			||||||
 | 
					    val map: Map<IetfLang, Lazy<String>>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    class Builder(
 | 
				
			||||||
 | 
					        var default: String
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        private val map = mutableMapOf<IetfLang, Lazy<String>>()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        infix fun IetfLang.variant(value: Lazy<String>) {
 | 
				
			||||||
 | 
					            map[this] = value
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        infix fun IetfLang.variant(value: () -> String) = this variant lazy(value)
 | 
				
			||||||
 | 
					        infix fun IetfLang.variant(value: String) = this variant lazyOf(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        infix fun String.variant(value: Lazy<String>) = IetfLang(this) variant value
 | 
				
			||||||
 | 
					        infix fun String.variant(value: () -> String) = IetfLang(this) variant lazy(value)
 | 
				
			||||||
 | 
					        infix fun String.variant(value: String) = this variant lazyOf(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun build() = StringResource(default, map.toMap())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun translation(languageCode: IetfLang): String {
 | 
				
			||||||
 | 
					        map[languageCode] ?.let { return it.value }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return languageCode.parentLang ?.let {
 | 
				
			||||||
 | 
					            map[it] ?.value
 | 
				
			||||||
 | 
					        } ?: default
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline fun buildStringResource(
 | 
				
			||||||
 | 
					    default: String,
 | 
				
			||||||
 | 
					    builder: StringResource.Builder.() -> Unit
 | 
				
			||||||
 | 
					): StringResource {
 | 
				
			||||||
 | 
					    return StringResource.Builder(default).apply(builder).build()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										10
									
								
								resources/src/jvmMain/kotlin/StringResourceLocaleGetter.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								resources/src/jvmMain/kotlin/StringResourceLocaleGetter.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package dev.inmo.micro_utils.strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import dev.inmo.micro_utils.language_codes.toIetfLang
 | 
				
			||||||
 | 
					import java.util.Locale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun StringResource.translation(locale: Locale = Locale.getDefault()): String {
 | 
				
			||||||
 | 
					    return translation(locale.toIetfLang())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun Locale.translation(resource: StringResource): String = resource.translation(this)
 | 
				
			||||||
@@ -16,11 +16,16 @@ import kotlinx.serialization.encoding.Encoder
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
open class MapperDeserializationStrategy<I, O>(
 | 
					open class MapperDeserializationStrategy<I, O>(
 | 
				
			||||||
    private val base: DeserializationStrategy<I>,
 | 
					    private val base: DeserializationStrategy<I>,
 | 
				
			||||||
    private val deserialize: (I) -> O
 | 
					    private val deserialize: (Decoder, I) -> O
 | 
				
			||||||
) : DeserializationStrategy<O> {
 | 
					) : DeserializationStrategy<O> {
 | 
				
			||||||
    override val descriptor: SerialDescriptor = base.descriptor
 | 
					    override val descriptor: SerialDescriptor = base.descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        base: DeserializationStrategy<I>,
 | 
				
			||||||
 | 
					        deserialize: (I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, { _, i -> deserialize(i) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun deserialize(decoder: Decoder): O {
 | 
					    override fun deserialize(decoder: Decoder): O {
 | 
				
			||||||
        return deserialize(base.deserialize(decoder))
 | 
					        return deserialize(decoder, base.deserialize(decoder))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,7 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.serialization.mapper
 | 
					package dev.inmo.micro_utils.serialization.mapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					 | 
				
			||||||
import kotlinx.serialization.SerializationStrategy
 | 
					import kotlinx.serialization.SerializationStrategy
 | 
				
			||||||
import kotlinx.serialization.descriptors.SerialDescriptor
 | 
					import kotlinx.serialization.descriptors.SerialDescriptor
 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -11,15 +9,20 @@ import kotlinx.serialization.encoding.Encoder
 | 
				
			|||||||
 * serialization
 | 
					 * serialization
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param base Serializer for [I]
 | 
					 * @param base Serializer for [I]
 | 
				
			||||||
 * @param serialize Will be used in [serialize] method to convert incoming [O] to [I] and serialize with [base]
 | 
					 * @param internalSerialize Will be used in [internalSerialize] method to convert incoming [O] to [I] and serialize with [base]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
open class MapperSerializationStrategy<I, O>(
 | 
					open class MapperSerializationStrategy<I, O>(
 | 
				
			||||||
    private val base: SerializationStrategy<I>,
 | 
					    private val base: SerializationStrategy<I>,
 | 
				
			||||||
    private val serialize: (O) -> I
 | 
					    private val internalSerialize: (Encoder, O) -> I
 | 
				
			||||||
) : SerializationStrategy<O> {
 | 
					) : SerializationStrategy<O> {
 | 
				
			||||||
    override val descriptor: SerialDescriptor = base.descriptor
 | 
					    override val descriptor: SerialDescriptor = base.descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        base: SerializationStrategy<I>,
 | 
				
			||||||
 | 
					        serialize: (O) -> I
 | 
				
			||||||
 | 
					    ) : this(base, { _, o -> serialize(o) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: O) {
 | 
					    override fun serialize(encoder: Encoder, value: O) {
 | 
				
			||||||
        base.serialize(encoder, serialize(value))
 | 
					        base.serialize(encoder, internalSerialize(encoder, value))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,8 @@
 | 
				
			|||||||
package dev.inmo.micro_utils.serialization.mapper
 | 
					package dev.inmo.micro_utils.serialization.mapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import kotlinx.serialization.DeserializationStrategy
 | 
				
			||||||
import kotlinx.serialization.KSerializer
 | 
					import kotlinx.serialization.KSerializer
 | 
				
			||||||
 | 
					import kotlinx.serialization.SerializationStrategy
 | 
				
			||||||
import kotlinx.serialization.descriptors.SerialDescriptor
 | 
					import kotlinx.serialization.descriptors.SerialDescriptor
 | 
				
			||||||
import kotlinx.serialization.encoding.Decoder
 | 
					import kotlinx.serialization.encoding.Decoder
 | 
				
			||||||
import kotlinx.serialization.encoding.Encoder
 | 
					import kotlinx.serialization.encoding.Encoder
 | 
				
			||||||
@@ -15,16 +17,28 @@ import kotlinx.serialization.encoding.Encoder
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
open class MapperSerializer<I, O>(
 | 
					open class MapperSerializer<I, O>(
 | 
				
			||||||
    private val base: KSerializer<I>,
 | 
					    private val base: KSerializer<I>,
 | 
				
			||||||
    private val serialize: (O) -> I,
 | 
					    private val serialize: (Encoder, O) -> I,
 | 
				
			||||||
    private val deserialize: (I) -> O
 | 
					    private val deserialize: (Decoder, I) -> O
 | 
				
			||||||
) : KSerializer<O> {
 | 
					) : KSerializer<O>,
 | 
				
			||||||
 | 
					    DeserializationStrategy<O> by MapperDeserializationStrategy<I, O>(base, deserialize),
 | 
				
			||||||
 | 
					    SerializationStrategy<O> by MapperSerializationStrategy<I, O>(base, serialize) {
 | 
				
			||||||
    override val descriptor: SerialDescriptor = base.descriptor
 | 
					    override val descriptor: SerialDescriptor = base.descriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun deserialize(decoder: Decoder): O {
 | 
					    constructor(
 | 
				
			||||||
        return deserialize(base.deserialize(decoder))
 | 
					        base: KSerializer<I>,
 | 
				
			||||||
    }
 | 
					        serialize: (O) -> I,
 | 
				
			||||||
 | 
					        deserialize: (I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, { _, o -> serialize(o) }, { _, i -> deserialize(i) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun serialize(encoder: Encoder, value: O) {
 | 
					    constructor(
 | 
				
			||||||
        base.serialize(encoder, serialize(value))
 | 
					        base: KSerializer<I>,
 | 
				
			||||||
    }
 | 
					        serialize: (Encoder, O) -> I,
 | 
				
			||||||
 | 
					        deserialize: (I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, serialize, { _, i -> deserialize(i) })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(
 | 
				
			||||||
 | 
					        base: KSerializer<I>,
 | 
				
			||||||
 | 
					        serialize: (O) -> I,
 | 
				
			||||||
 | 
					        deserialize: (Decoder, I) -> O
 | 
				
			||||||
 | 
					    ) : this(base, { _, o -> serialize(o) }, deserialize)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,9 @@ String[] includes = [
 | 
				
			|||||||
    ":serialization:mapper",
 | 
					    ":serialization:mapper",
 | 
				
			||||||
    ":startup:plugin",
 | 
					    ":startup:plugin",
 | 
				
			||||||
    ":startup:launcher",
 | 
					    ":startup:launcher",
 | 
				
			||||||
 | 
					    ":colors:common",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ":resources",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ":fsm:common",
 | 
					    ":fsm:common",
 | 
				
			||||||
    ":fsm:repos:common",
 | 
					    ":fsm:repos:common",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user