Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kmp #31

Merged
merged 3 commits into from
Sep 10, 2024
Merged

Kmp #31

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/release_compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ jobs:
- name: Publish Library
run: |
echo "Publishing library🚀"
./gradlew :mvi-compose:publish --no-daemon --no-parallel
./gradlew :mvi-compose:publishAndReleaseToMavenCentral --no-configuration-cache
echo "Published✅"
echo "Releasing repository...🚀"
./gradlew closeAndReleaseRepository
echo "Released✅"
env:
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_PASSWORD }}
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/release_kotest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ jobs:
- name: Publish Library
run: |
echo "Publishing library🚀"
./gradlew :mvi-kotest:publish --no-daemon --no-parallel
./gradlew :mvi-kotest:publishAndReleaseToMavenCentral --no-configuration-cache
echo "Published✅"
echo "Releasing repository...🚀"
./gradlew closeAndReleaseRepository
echo "Released✅"
env:
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_PASSWORD }}
Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/release_mvi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,8 @@ jobs:
- name: Publish Library
run: |
echo "Publishing library🚀"
./gradlew :mvi:publish --no-daemon --no-parallel
./gradlew :mvi:publishAndReleaseToMavenCentral --no-configuration-cache
echo "Published✅"
echo "Releasing repository...🚀"
./gradlew closeAndReleaseRepository
echo "Released✅"
env:
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.GPG_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.GPG_PASSWORD }}
Expand Down
7 changes: 4 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ plugins {
alias(libs.plugins.kotlin) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.android.library) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.mavenPublish)
}

configure(subprojects) {

allprojects {
pluginManager.withPlugin("com.vanniktech.maven.publish") {
mavenPublishing {
publishToMavenCentral(SonatypeHost.S01)
publishToMavenCentral(SonatypeHost.S01, automaticRelease = true)
signAllPublications()
}
}
Expand Down
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img style='width: 500px' src="assets/mvi_logo.png" alt="adidas mvi Logo"/>
</div>

[![Kotlin](https://img.shields.io/badge/Kotlin-1.9.22-blue.svg?style=flat&logo=kotlin)](https://kotlinlang.org)
[![Kotlin](https://img.shields.io/badge/Kotlin-2.0.0-blue.svg?style=flat&logo=kotlin)](https://kotlinlang.org)
![Test workflow](https://github.com/adidas/mvi/actions/workflows/deploy_docs.yml/badge.svg)
[![adidas official](https://img.shields.io/badge/adidas-official-000000)](https://github.com/adidas)

Expand Down
39 changes: 24 additions & 15 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,32 +1,35 @@
[versions]
ksp = "1.9.23-1.0.19"
appcompat = "1.6.1"
koin = "3.5.3"
ksp = "2.0.20-1.0.25"
appcompat = "1.7.0"
koin = "3.5.6"
koin-annotations = "1.3.1"
koin-android = "3.5.3"
koin-compose = "3.5.3"
kotlin = "1.9.23"
coroutines = "1.8.0"
kotest = "5.8.1"
material = "1.6.5"
koin-android = "3.5.6"
koin-compose = "3.5.6"
kotlin = "2.0.0"
coroutines = "1.8.1"
kotest = "5.9.0"
material = "1.7.0"
mvi = "1.7.0"
mvi-compose = "0.0.3"
activity = "1.8.2"
lifecycle = "2.7.0"
activity = "1.9.2"
lifecycle = "2.8.5"
ktlint-gradle = "12.1.0"
android-library = "8.3.1"
maven-publish = "0.25.2"
ui = "1.6.5"
mockk = "1.13.10"
android-library = "8.3.2"
maven-publish = "0.29.0"
ui = "1.7.0"
mockk = "1.13.11"
mvi-kotest = "0.0.2"

# its beeing used outside this file
ktlint-lib = "1.2.1"

[libraries]
appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" }
coroutinesCore = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
coroutinesTest = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
kotest-framework-engine = { module = "io.kotest:kotest-framework-engine", version.ref = "kotest" }
kotestRunner = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" }
kotest-assertions = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" }
kotlinBom = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
mvi = { module = "com.adidas.mvi:mvi", version.ref = "mvi" }
mviCompose = { module = "com.adidas.mvi:mvi-compose", version.ref = "mvi-compose" }
Expand All @@ -49,3 +52,9 @@ mavenPublish = { id = "com.vanniktech.maven.publish", version.ref = "maven-publi
android-library = { id = "com.android.library", version.ref = "android-library" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
kotest = { id = "io.kotest.multiplatform", version.ref = "kotest" }
atomicfu = { id = "org.jetbrains.kotlinx.atomicfu", version = "0.25.0" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }


5 changes: 1 addition & 4 deletions mvi-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.mavenPublish)
alias(libs.plugins.compose.compiler)
}

kotlin {
Expand Down Expand Up @@ -39,10 +40,6 @@ android {
buildFeatures {
compose = true
}

composeOptions {
kotlinCompilerExtensionVersion = "1.5.11"
}
}

dependencies {
Expand Down
5 changes: 1 addition & 4 deletions mvi-sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ plugins {
id("kotlin-android")
id("kotlin-kapt")
alias(libs.plugins.ksp)
alias(libs.plugins.compose.compiler)
}

android {
Expand Down Expand Up @@ -37,10 +38,6 @@ android {
jvmTarget = JavaVersion.VERSION_17.toString()
}

composeOptions {
kotlinCompilerExtensionVersion = "1.5.11"
}

buildFeatures {
compose = true
}
Expand Down
54 changes: 40 additions & 14 deletions mvi/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,31 +1,57 @@
import org.jlleitschuh.gradle.ktlint.KtlintExtension

plugins {
kotlin("jvm") version libs.versions.kotlin.get()
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.ktlint)
alias(libs.plugins.mavenPublish)
alias(libs.plugins.kotest)
alias(libs.plugins.atomicfu)
}

kotlin {
explicitApi()
}

val compileTestKotlin: org.jetbrains.kotlin.gradle.tasks.KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
freeCompilerArgs += "-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi"
jvm {
withJava()
}

iosX64()
iosArm64()
iosSimulatorArm64()

macosX64()
macosArm64()

watchosArm32()
watchosArm64()
watchosDeviceArm64()
watchosSimulatorArm64()
watchosX64()

tvosArm64()
tvosSimulatorArm64()
tvosX64()

sourceSets {
commonMain.dependencies {
implementation(libs.coroutinesCore)
}

jvmTest.dependencies {
implementation(libs.kotest.framework.engine)
implementation(libs.kotest.assertions)
implementation(libs.coroutinesTest)
implementation(libs.kotestRunner)
}
}
}

configure<KtlintExtension> {
version.set(libs.versions.ktlint.lib.get())
}

tasks.getByName<Test>("test") {
useJUnitPlatform()
}

dependencies {
implementation(libs.coroutinesCore)

testImplementation(libs.kotestRunner)
testImplementation(libs.coroutinesTest)
tasks {
withType<Test> {
useJUnitPlatform()
}
}
2 changes: 1 addition & 1 deletion mvi/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
POM_ARTIFACT_ID=mvi
GROUP=com.adidas.mvi
VERSION_CODE=1
VERSION_NAME=1.7.0
VERSION_NAME=1.8.0
POM_NAME=Adidas MVI
POM_DESCRIPTION=Adidas MVI
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.adidas.mvi

import java.util.Collections
import kotlin.reflect.KClass

internal class Multimap<TKey : Any, TValue> {
private val innerMap = hashMapOf<TKey, MutableList<MultimapEntry<TKey, TValue>>>()

val keys: Collection<TKey>
get() = Collections.unmodifiableSet(innerMap.keys)
get() = innerMap.keys.toSet()

fun put(
key: TKey,
Expand All @@ -29,7 +28,7 @@ internal class Multimap<TKey : Any, TValue> {
innerMap[key] = MutableList(values.size) { values[it] }
}

operator fun get(key: TKey): List<MultimapEntry<TKey, TValue>> = innerMap[key]?.let(Collections::unmodifiableList) ?: listOf()
operator fun get(key: TKey): List<MultimapEntry<TKey, TValue>> = innerMap[key]?.toList() ?: listOf()

operator fun <T : TKey> get(keyClass: KClass<T>): List<MultimapEntry<TKey, TValue>> =
keys
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package com.adidas.mvi

import kotlinx.coroutines.CancellationException

internal class TerminatedIntentException : CancellationException()
internal class TerminatedIntentException : CancellationException("Terminated intent")
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public fun <TIntent : Intent, TInnerState : LoggableState, TAction> Reducer(
@Suppress("UNCHECKED_CAST")
public inline fun <reified TView : Any> Reducer<*, *>.requireView(): TView =
(state.value as State<TView, *>).view.apply {
if (this.javaClass != TView::class.java) {
throw ClassCastException("Required view of ${TView::class.java} type, but found ${this.javaClass}")
if (!TView::class.isInstance(this)) {
throw ClassCastException("Required view of ${TView::class} type, but found $this")
}
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
package com.adidas.mvi.sideeffects

import java.util.LinkedList
import java.util.Queue
import kotlinx.atomicfu.AtomicRef
import kotlinx.atomicfu.atomic

/**
* A thread-safe side effect container
* It only returns each SideEffect once, if you use it as an [Iterable] it will emit each SideEffect and remove them so it's a perfect case for one shot SideEffects.
* It locks itself, so you can't add and read at the same time, also it's not possible to read it at the same time from different threads, being completely thread-safe.
*/

public class SideEffects<T>() : Iterable<T> {
private val sideEffects: Queue<T> = LinkedList()
private val sideEffects: AtomicRef<MutableList<T>> = atomic(ArrayList())

// Private constructor to initialize from an Iterable
private constructor(sideEffects: Iterable<T>) : this() {
this.sideEffects.addAll(sideEffects)
this.sideEffects.value.addAll(sideEffects)
}

public fun add(vararg sideEffectsToAdd: T): SideEffects<T> {
return SideEffects(sideEffects + sideEffectsToAdd)
val newList = sideEffects.value.toMutableList()
newList.addAll(sideEffectsToAdd)
return SideEffects(newList)
}

public fun clear(): SideEffects<T> {
Expand All @@ -25,9 +29,11 @@ public class SideEffects<T>() : Iterable<T> {

override fun iterator(): Iterator<T> =
iterator {
do {
val nextSideEffect: T? = sideEffects.poll()
while (true) {
val currentList = sideEffects.value
if (currentList.isEmpty()) break
val nextSideEffect = currentList.removeFirstOrNull()
nextSideEffect?.let { yield(it) }
} while (nextSideEffect != null)
}
}
}
38 changes: 38 additions & 0 deletions mvi/src/jvmTest/kotlin/com/adidas/mvi/CoroutineListener.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.adidas.mvi

import io.kotest.core.listeners.TestListener
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.test.TestCoroutineScheduler
import kotlinx.coroutines.test.TestDispatcher
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.setMain

internal class CoroutineListener(
internal val testCoroutineDispatcher: TestDispatcher =
UnconfinedTestDispatcher(
TestCoroutineScheduler(),
),
) : TestListener {
internal val dispatchersContainer: DispatchersContainer =
FixedDispatchersContainer(testCoroutineDispatcher)

override suspend fun beforeContainer(testCase: TestCase) {
Dispatchers.setMain(testCoroutineDispatcher)
}

override suspend fun afterContainer(
testCase: TestCase,
result: TestResult,
) {
Dispatchers.resetMain()
testCoroutineDispatcher.scheduler.cancel()
}

public fun advanceUntilIdle() {
testCoroutineDispatcher.scheduler.advanceUntilIdle()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,7 @@ private fun createIntentExecutorContainer(
flowOf(TestTransform.Transform1)
}

private fun createIntentExecutorContainer(
exception: java.lang.Exception,
): (TestIntent) -> Flow<StateTransform<State<TestState, TestSideEffect>>> =
private fun createIntentExecutorContainer(exception: Throwable): (TestIntent) -> Flow<StateTransform<State<TestState, TestSideEffect>>> =
{
if (it is TestIntent.SimpleIntent) throw exception
emptyFlow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.adidas.mvi.reducer.logger

import com.adidas.mvi.Loggable
import com.adidas.mvi.Logger
import java.lang.StringBuilder

private const val SPACE = " "
internal const val SUCCESSFUL_INTENT = "SuccessfulIntent:"
Expand Down
Loading
Loading