Skip to content
Open
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
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.gradle
.settings
.project
.classpath
.vscode
.idea
.kotlin
build
*.iml
Pods
xcuserdata
local.properties
local.gradle
38 changes: 38 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Do’s and Don’ts

* **Search tickets before you file a new one.** Add to tickets if you have new information about the issue.
* **Keep tickets short but sweet.** Make sure you include all the context needed to solve the issue. Don't overdo it. Great tickets allow us to focus on solving problems instead of discussing them.
* **Take care of your ticket.** When you spend time to report a ticket with care we'll enjoy fixing it for you.
* **Use [GitHub-flavored Markdown](https://help.github.com/articles/markdown-basics/).** Especially put code blocks and console outputs in backticks (```` ``` ````). That increases the readability. Bonus points for applying the appropriate syntax highlighting.

## Bug Reports

In short, since you are most likely a developer, provide a ticket that you _yourself_ would _like_ to receive.

First check if you are using the latest library version and Kotlin version before filing a ticket.

Please include steps to reproduce and _all_ other relevant information, including any other relevant dependency and version information.

## Feature Requests

Please try to be precise about the proposed outcome of the feature and how it
would related to existing features.


## Pull Requests

We **love** pull requests!

All contributions _will_ be licensed under the Apache 2 license.

Code/comments should adhere to the following rules:

* Names should be descriptive and concise.
* Use four spaces and no tabs.
* Remember that source code usually gets written once and read often: ensure
the reader doesn't have to make guesses. Make sure that the purpose and inner
logic are either obvious to a reasonably skilled professional, or add a
comment that explains it.
* Please add a detailed description.

If you consistently contribute improvements and/or bug fixes, we're happy to make you a maintainer.
6 changes: 3 additions & 3 deletions LICENSE → LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,15 @@
APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright {yyyy} {name of copyright owner}

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -198,4 +198,4 @@
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Mobile Kotlin RemoteState

A Kotlin Multiplatform library for managing remote state in your Android, iOS, and Web applications.

## Overview

Moko RemoteState provides a simple and efficient way to handle remote data states with Kotlin's coroutines and Flow. It's designed for multiplatform projects, allowing you to share state management logic across iOS, Android, and Web platforms.

## Features

- **Multiplatform support**: Works on Android, iOS, and Web
- **Coroutines & Flow**: Built on Kotlin coroutines and Flow for reactive programming
- **Simple API**: Easy to use with intuitive state representation
- **Type-safe**: Compile-time safe state transitions
- **Zero dependencies**: Pure Kotlin implementation

## Getting Started

### Gradle Setup

Add the dependency to your common source set:

```kotlin
implementation("dev.icerock.moko:remotestate:[latestVersion]")
```

### Usage

```kotlin
import dev.icerock.moko.remotestate.RemoteState

// Define your state
val state = MutableStateFlow<RemoteState<Data, Error>>(Loading)

// Update state
state.value = Success(Data("Hello, World!"))

// Map success
val mappedState = state.mapSuccess { it.uppercase() }

// Check state
if (state.isSuccess()) {
println(state.data)
}
```

## API Reference

### RemoteState

A sealed class representing the state of remote data.

- `Loading` - Represents an ongoing operation
- `Success<T>` - Contains successfully loaded data
- `Error<E>` - Contains an error occurred during operation

### Functions

- `mapSuccess` - Transform data in Success state
- `mapError` - Transform error in Error state
- `isLoading` - Check if state is loading
- `isSuccess` - Check if state is successful
- `tryUpdateSuccess` - Atomically update data in Success state

## Contributing
All development (both new features and bug fixes) is performed in the `develop` branch. This way `master` always contains the sources of the most recently released version. Please send PRs with bug fixes to the `develop` branch. Documentation fixes in the markdown files are an exception to this rule. They are updated directly in `master`.

The `develop` branch is pushed to `master` on release.

For more details on contributing please see the [contributing guide](CONTRIBUTING.md).

## License

Apache 2.0 License - see [LICENSE](LICENSE) file for details.
14 changes: 14 additions & 0 deletions build-logic/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
plugins {
`kotlin-dsl`
}

repositories {
mavenCentral()
google()

gradlePluginPortal()
}

dependencies {
api(libs.nexusPublishing)
}
18 changes: 18 additions & 0 deletions build-logic/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

rootProject.name = "build-logic"

dependencyResolutionManagement {
repositories {
mavenCentral()
google()
}

versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

import java.net.URI

plugins {
id("io.github.gradle-nexus.publish-plugin")
}

nexusPublishing {
repositories {
// TODO()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need now?

sonatype {
nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/"))
snapshotRepositoryUrl.set(URI.create("https://central.sonatype.com/repository/maven-snapshots/"))
username.set(System.getenv("OSSRH_USER"))
password.set(System.getenv("OSSRH_KEY"))
}
}
}
57 changes: 57 additions & 0 deletions build-logic/src/main/kotlin/publication-convention.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

import java.util.Base64

plugins {
id("org.gradle.maven-publish")
}

publishing {
publications.withType<MavenPublication> {
// Provide artifacts information requited by Maven Central
pom {
name.set("MOKO state")
description.set("Resources access for Kotlin Multiplatform development (mobile first)")
url.set("https://github.com/icerockdev/moko-state")
licenses {
license {
name.set("Apache-2.0")
distribution.set("repo")
url.set("https://github.com/icerockdev/moko-state/blob/master/LICENSE.md")
}
}

developers {
// TODO()
}

scm {
connection.set("scm:git:ssh://github.com/icerockdev/moko-state.git")
developerConnection.set("scm:git:ssh://github.com/icerockdev/moko-state.git")
url.set("https://github.com/icerockdev/moko-state")
}
}
}
}

val signingKeyId: String? = System.getenv("SIGNING_KEY_ID")
if (signingKeyId != null) {
apply(plugin = "signing")

configure<SigningExtension> {
val signingPassword: String? = System.getenv("SIGNING_PASSWORD")
val signingKey: String? = System.getenv("SIGNING_KEY")?.let { base64Key ->
String(Base64.getDecoder().decode(base64Key))
}

useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
sign(publishing.publications)
}

val signingTasks = tasks.withType<Sign>()
tasks.withType<AbstractPublishToMaven>().configureEach {
dependsOn(signingTasks)
}
}
38 changes: 38 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2026 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

buildscript {
repositories {
mavenCentral()
google()
gradlePluginPortal()
}

dependencies {
classpath(libs.kotlinGradlePlugin)
classpath(libs.androidGradlePlugin)
classpath(libs.mokoGradlePlugin)
classpath(libs.mobileMultiplatformGradlePlugin)
classpath(":build-logic")
}
}

val mokoVersion = libs.versions.mokoStateVersion.get()

allprojects {
plugins.withId("org.gradle.maven-publish") {
group = "dev.icerock.moko"
version = mokoVersion
}
}

// required for nexus plugin
group = "dev.icerock.moko"
version = mokoVersion

apply(plugin = "nexus-publication-convention")

tasks.register("clean", Delete::class).configure {
delete(rootProject.buildDir)
}
9 changes: 9 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
org.gradle.jvmargs=-Xmx4096m
org.gradle.configureondemand=false
org.gradle.parallel=true

kotlin.code.style=official

moko.android.targetSdk=35
moko.android.compileSdk=35
moko.android.minSdk=16
14 changes: 14 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[versions]
kotlinVersion = "2.1.10"
coroutinesVersion = "1.10.2"
mokoStateVersion = "0.1.0"

[libraries]
coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutinesVersion" }
coroutinesTest = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutinesVersion" }

kotlinGradlePlugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinVersion" }
androidGradlePlugin = { module = "com.android.tools.build:gradle", version = "8.0.2" }
mokoGradlePlugin = { module = "dev.icerock.moko:moko-gradle-plugin", version = "0.3.0" }
mobileMultiplatformGradlePlugin = { module = "dev.icerock:mobile-multiplatform", version = "0.14.4" }
nexusPublishing = { module = "io.github.gradle-nexus:publish-plugin", version = "2.0.0" }
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
5 changes: 5 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading