Skip to content

Commit

Permalink
Add library modules
Browse files Browse the repository at this point in the history
  • Loading branch information
hkusu committed Nov 7, 2024
1 parent e027f71 commit e522d8b
Show file tree
Hide file tree
Showing 15 changed files with 869 additions and 13 deletions.
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
plugins {
alias(libs.plugins.androidLibrary) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.vanniktech.mavenPublish) apply false
}
7 changes: 5 additions & 2 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,8 @@ dependencyResolutionManagement {
}
}

rootProject.name = "multiplatform-library-template"
include(":library")
rootProject.name = "Tart"
include(":tart-core")
include(":tart-compose")
include(":tart-logging")
include(":tart-message")
86 changes: 86 additions & 0 deletions tart-compose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import com.vanniktech.maven.publish.SonatypeHost
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.vanniktech.mavenPublish)
}

group = "io.yumemi.tart"
version = "1.0.0-beta01"

kotlin {
androidTarget {
publishLibraryVariants("release")
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)
}
}
// FIXME: comment out iOS because build error
// iosX64()
// iosArm64()
// iosSimulatorArm64()

sourceSets {
val commonMain by getting {
dependencies {
// put your multiplatform dependencies here
implementation(project(":tart-core"))
implementation(libs.compose.runtime)
}
}
val commonTest by getting {
dependencies {
implementation(libs.kotlin.test)
}
}
}
}

android {
namespace = "io.yumemi.tart.compose"
compileSdk = libs.versions.android.compileSdk.get().toInt()
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
}
}

mavenPublishing {
publishToMavenCentral(SonatypeHost.CENTRAL_PORTAL)

if (System.getenv("ORG_GRADLE_PROJECT_mavenCentralUsername") != null) {
signAllPublications()
}

coordinates(group.toString(), "tart-compose", version.toString())

pom {
name = "Tart"
description = "A Kotlin Multiplatform Flux framework."
inceptionYear = "2024"
url = "https://github.com/yumemi-inc/Tart/"
licenses {
license {
name = "MIT"
url = "https://opensource.org/licenses/MIT"
distribution = "https://opensource.org/licenses/MIT"
}
}
developers {
developer {
id = "yumemi-inc"
name = "YUMEMI Inc."
url = "https://github.com/yumemi-inc/"
}
}
scm {
url = "https://github.com/yumemi-inc/Tart/"
connection = "scm:git:git://github.com/yumemi-inc/Tart.git"
developerConnection = "scm:git:git://github.com/yumemi-inc/Tart.git"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package io.yumemi.tart.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import io.yumemi.tart.core.Action
import io.yumemi.tart.core.Event
import io.yumemi.tart.core.State
import io.yumemi.tart.core.Store
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.filter

@Suppress("unused")
class ComposeStore<S : State, A : Action, E : Event> private constructor(
val state: S,
val dispatch: (action: A) -> Unit,
val eventFlow: Flow<E>,
) {
@Composable
inline fun <reified S2 : S> render(block: ComposeStore<S2, A, E>.() -> Unit) {
if (state is S2) {
block(
mock(
state = state,
dispatch = dispatch,
eventFlow = eventFlow,
),
)
}
}

@Composable
inline fun <reified E2 : E> handle(crossinline block: ComposeStore<S, A, E>.(event: E2) -> Unit) {
LaunchedEffect(Unit) {
eventFlow.filter { it is E2 }.collect {
block(this@ComposeStore, it as E2)
}
}
}

companion object {
@Composable
fun <S : State, A : Action, E : Event> create(store: Store<S, A, E>): ComposeStore<S, A, E> {
val state by store.state.collectAsState()
return ComposeStore(
state = state,
dispatch = store::dispatch,
eventFlow = store.event,
)
}

@Composable
fun <S : State, A : Action, E : Event> mock(state: S, dispatch: (action: A) -> Unit = {}, eventFlow: Flow<E> = emptyFlow()): ComposeStore<S, A, E> {
return ComposeStore(
state = state,
dispatch = dispatch,
eventFlow = eventFlow,
)
}
}
}
21 changes: 11 additions & 10 deletions library/build.gradle.kts → tart-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ plugins {
alias(libs.plugins.vanniktech.mavenPublish)
}

group = "io.yumemi.something"
version = "0.0.1"
group = "io.yumemi.tart"
version = "1.0.0-beta01"

kotlin {
androidTarget {
Expand All @@ -27,6 +27,7 @@ kotlin {
val commonMain by getting {
dependencies {
// put your multiplatform dependencies here
implementation(libs.coroutines.core)
}
}
val commonTest by getting {
Expand All @@ -38,7 +39,7 @@ kotlin {
}

android {
namespace = "io.yumemi.something.library"
namespace = "io.yumemi.tart.core"
compileSdk = libs.versions.android.compileSdk.get().toInt()
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
Expand All @@ -52,13 +53,13 @@ mavenPublishing {
signAllPublications()
}

coordinates(group.toString(), "library", version.toString())
coordinates(group.toString(), "tart-core", version.toString())

pom {
name = "My library"
description = "A library."
name = "Tart"
description = "A Kotlin Multiplatform Flux framework."
inceptionYear = "2024"
url = "https://github.com/yumemi-inc/something/"
url = "https://github.com/yumemi-inc/Tart/"
licenses {
license {
name = "MIT"
Expand All @@ -74,9 +75,9 @@ mavenPublishing {
}
}
scm {
url = "https://github.com/yumemi-inc/something/"
connection = "scm:git:git://github.com/yumemi-inc/something.git"
developerConnection = "scm:git:git://github.com/yumemi-inc/something.git"
url = "https://github.com/yumemi-inc/Tart/"
connection = "scm:git:git://github.com/yumemi-inc/Tart.git"
developerConnection = "scm:git:git://github.com/yumemi-inc/Tart.git"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.yumemi.tart.core

interface State
interface Action
interface Event
19 changes: 19 additions & 0 deletions tart-core/src/commonMain/kotlin/io/yumemi/tart/core/Middleware.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.yumemi.tart.core

import kotlinx.coroutines.CoroutineScope

interface Middleware<S : State, A : Action, E : Event> {
suspend fun onInit(store: Store<S, A, E>, coroutineScope: CoroutineScope) {}
suspend fun beforeActionDispatch(state: S, action: A) {}
suspend fun afterActionDispatch(state: S, action: A, nextState: S) {}
suspend fun beforeEventEmit(state: S, event: E) {}
suspend fun afterEventEmit(state: S, event: E) {}
suspend fun beforeStateEnter(state: S) {}
suspend fun afterStateEnter(state: S, nextState: S) {}
suspend fun beforeStateExit(state: S) {}
suspend fun afterStateExit(state: S) {}
suspend fun beforeStateChange(state: S, nextState: S) {}
suspend fun afterStateChange(state: S, prevState: S) {}
suspend fun beforeError(state: S, error: Throwable) {}
suspend fun afterError(state: S, nextState: S, error: Throwable) {}
}
56 changes: 56 additions & 0 deletions tart-core/src/commonMain/kotlin/io/yumemi/tart/core/Store.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.yumemi.tart.core

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.emptyFlow

interface Store<S : State, A : Action, E : Event> {

val state: StateFlow<S>

val event: Flow<E>

val currentState: S

fun dispatch(action: A)

fun collectState(state: (state: S) -> Unit)

fun collectEvent(event: (event: E) -> Unit)

fun dispose()

@Suppress("unused")
abstract class Base<S : State, A : Action, E : Event>(
initialState: S,
processInitialStateEnter: Boolean = true,
latestState: suspend (state: S) -> Unit = {},
onError: (error: Throwable) -> Unit = { throw it },
coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Default + SupervisorJob()),
) : TartStore<S, A, E>(
initialState = initialState,
processInitialStateEnter = processInitialStateEnter,
latestState = latestState,
onError = onError,
coroutineScope = coroutineScope,
)

companion object {
@Suppress("unused")
fun <S : State, A : Action, E : Event> mock(state: S): Store<S, A, E> {
return object : Store<S, A, E> {
override val state: StateFlow<S> = MutableStateFlow(state)
override val event: Flow<E> = emptyFlow()
override val currentState: S = state
override fun dispose() {}
override fun collectEvent(event: (event: E) -> Unit) {}
override fun collectState(state: (state: S) -> Unit) {}
override fun dispatch(action: A) {}
}
}
}
}
Loading

0 comments on commit e522d8b

Please sign in to comment.