-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add android app example with kotlin multiplatform (#196)
- Loading branch information
1 parent
caef472
commit e0f8fda
Showing
51 changed files
with
1,639 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
end-to-end-applications/kotlin/kmp-android-todo-app/.gitignore
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
*.iml | ||
.kotlin | ||
.gradle | ||
**/build/ | ||
xcuserdata | ||
!src/**/build/ | ||
local.properties | ||
.idea | ||
.DS_Store | ||
captures | ||
.externalNativeBuild | ||
.cxx | ||
*.xcodeproj/* | ||
!*.xcodeproj/project.pbxproj | ||
!*.xcodeproj/xcshareddata/ | ||
!*.xcodeproj/project.xcworkspace/ | ||
!*.xcworkspace/contents.xcworkspacedata | ||
**/xcshareddata/WorkspaceSettings.xcsettings | ||
restate-data |
15 changes: 15 additions & 0 deletions
15
end-to-end-applications/kotlin/kmp-android-todo-app/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Kotlin Multiplatform example Android app + Restate backend | ||
|
||
Kotlin multiplatform example for a Todo app using Restate as backend: | ||
|
||
![](screenshot.png) | ||
|
||
This project contains: | ||
|
||
* The [shared](./shared) code | ||
* The [Todos Virtual Object](./server/src/main/kotlin/dev/restate/examples/noteapp/Application.kt), to store the todos, built using the Kotlin Restate SDK | ||
* The [Android app](./composeApp) | ||
|
||
For more details on how to use it and run the Android app, check: https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html | ||
|
||
To run the Restate server, just follow the same instructions as https://docs.restate.dev/get_started/quickstart?sdk=kotlin |
11 changes: 11 additions & 0 deletions
11
end-to-end-applications/kotlin/kmp-android-todo-app/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
plugins { | ||
// this is necessary to avoid the plugins to be loaded multiple times | ||
// in each subproject's classloader | ||
alias(libs.plugins.androidApplication) apply false | ||
alias(libs.plugins.androidLibrary) apply false | ||
alias(libs.plugins.jetbrainsCompose) apply false | ||
alias(libs.plugins.compose.compiler) apply false | ||
alias(libs.plugins.kotlinJvm) apply false | ||
alias(libs.plugins.kotlinMultiplatform) apply false | ||
alias(libs.plugins.kotlinxSerialization) apply false | ||
} |
82 changes: 82 additions & 0 deletions
82
end-to-end-applications/kotlin/kmp-android-todo-app/composeApp/build.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import org.jetbrains.compose.desktop.application.dsl.TargetFormat | ||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi | ||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget | ||
|
||
plugins { | ||
alias(libs.plugins.kotlinMultiplatform) | ||
alias(libs.plugins.androidApplication) | ||
alias(libs.plugins.jetbrainsCompose) | ||
alias(libs.plugins.compose.compiler) | ||
} | ||
|
||
kotlin { | ||
androidTarget { | ||
@OptIn(ExperimentalKotlinGradlePluginApi::class) | ||
compilerOptions { | ||
jvmTarget.set(JvmTarget.JVM_11) | ||
} | ||
} | ||
|
||
sourceSets { | ||
androidMain.dependencies { | ||
implementation(compose.preview) | ||
implementation(libs.androidx.activity.compose) | ||
implementation(libs.ktor.client.okhttp) | ||
implementation(libs.kotlinx.coroutines.android) | ||
} | ||
commonMain.dependencies { | ||
implementation(compose.runtime) | ||
implementation(compose.foundation) | ||
implementation(compose.material) | ||
implementation(compose.ui) | ||
implementation(compose.material3) | ||
implementation(compose.components.resources) | ||
implementation(compose.components.uiToolingPreview) | ||
implementation(libs.androidx.lifecycle.viewmodel) | ||
implementation(libs.androidx.lifecycle.runtime.compose) | ||
implementation(projects.shared) | ||
implementation(libs.ktor.client.core) | ||
implementation(libs.ktor.serialization.json) | ||
implementation(libs.ktor.client.content.negotiation) | ||
implementation(libs.kotlinx.coroutines.core) | ||
} | ||
} | ||
} | ||
|
||
android { | ||
namespace = "dev.restate.examples.noteapp" | ||
compileSdk = libs.versions.android.compileSdk.get().toInt() | ||
|
||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") | ||
sourceSets["main"].res.srcDirs("src/androidMain/res") | ||
sourceSets["main"].resources.srcDirs("src/commonMain/resources") | ||
|
||
defaultConfig { | ||
applicationId = "dev.restate.examples.noteapp" | ||
minSdk = libs.versions.android.minSdk.get().toInt() | ||
targetSdk = libs.versions.android.targetSdk.get().toInt() | ||
versionCode = 1 | ||
versionName = "1.0" | ||
} | ||
packaging { | ||
resources { | ||
excludes += "/META-INF/{AL2.0,LGPL2.1}" | ||
} | ||
} | ||
buildTypes { | ||
getByName("release") { | ||
isMinifyEnabled = false | ||
} | ||
} | ||
compileOptions { | ||
sourceCompatibility = JavaVersion.VERSION_11 | ||
targetCompatibility = JavaVersion.VERSION_11 | ||
} | ||
buildFeatures { | ||
compose = true | ||
} | ||
dependencies { | ||
debugImplementation(compose.uiTooling) | ||
} | ||
} | ||
|
27 changes: 27 additions & 0 deletions
27
...d-applications/kotlin/kmp-android-todo-app/composeApp/src/androidMain/AndroidManifest.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
<uses-permission android:name="android.permission.INTERNET" /> | ||
|
||
<application | ||
android:allowBackup="true" | ||
android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:supportsRtl="true" | ||
android:theme="@android:style/Theme.Material.Light.NoActionBar" | ||
android:usesCleartextTraffic="true"> | ||
<activity | ||
android:exported="true" | ||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode" | ||
android:name=".MainActivity"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
|
||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
|
||
</application> | ||
|
||
</manifest> |
39 changes: 39 additions & 0 deletions
39
...d-todo-app/composeApp/src/androidMain/kotlin/dev/restate/examples/noteapp/MainActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package dev.restate.examples.noteapp | ||
|
||
import android.os.Bundle | ||
import androidx.activity.ComponentActivity | ||
import androidx.activity.compose.setContent | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import dev.restate.examples.noteapp.composables.TodoItemsContainer | ||
import dev.restate.examples.noteapp.composables.TodoInputBar | ||
import dev.restate.examples.noteapp.ui.constants.OverlappingHeight | ||
import io.ktor.http.Url | ||
import kotlinx.coroutines.Dispatchers | ||
|
||
// Thanks to https://medium.com/deuk/intermediate-android-compose-todo-app-ui-1d808ef7882d for the Compose UI related code. | ||
|
||
class MainActivity : ComponentActivity() { | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
val mainViewModel = MainViewModel(TodosClient(Url("http://localhost:8080")), dispatcher = Dispatchers.IO) | ||
setContent { | ||
Box( | ||
modifier = Modifier.fillMaxSize() | ||
) { | ||
TodoItemsContainer( | ||
todoItemsFlow = mainViewModel.todos, | ||
onItemClick = mainViewModel::toggleTodo, | ||
onItemDelete = mainViewModel::removeTodo, | ||
overlappingElementsHeight = OverlappingHeight | ||
) | ||
TodoInputBar( | ||
modifier = Modifier.align(Alignment.BottomStart), | ||
onAddButtonClick = mainViewModel::addTodo | ||
) | ||
} | ||
} | ||
} | ||
} |
56 changes: 56 additions & 0 deletions
56
...-todo-app/composeApp/src/androidMain/kotlin/dev/restate/examples/noteapp/MainViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package dev.restate.examples.noteapp | ||
|
||
import androidx.lifecycle.ViewModel | ||
import androidx.lifecycle.viewModelScope | ||
import kotlinx.coroutines.CoroutineDispatcher | ||
import kotlinx.coroutines.async | ||
import kotlinx.coroutines.channels.Channel | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.map | ||
import kotlinx.coroutines.flow.receiveAsFlow | ||
import kotlinx.coroutines.launch | ||
|
||
class MainViewModel( | ||
private val client: TodosClient, | ||
private val dispatcher: CoroutineDispatcher | ||
) : ViewModel() { | ||
|
||
private val updateSignal = Channel<Unit>() | ||
|
||
val todos: Flow<List<TodoItem>> = updateSignal.receiveAsFlow().map { | ||
getTodos().await() | ||
} | ||
|
||
init { | ||
// Trigger first reload | ||
viewModelScope.launch(dispatcher) { | ||
triggerTodosReload() | ||
} | ||
} | ||
|
||
fun addTodo(todo: String) = | ||
viewModelScope.launch(dispatcher) { | ||
client.add(TodoItem(content = todo)) | ||
triggerTodosReload() | ||
} | ||
|
||
fun toggleTodo(todoItem: TodoItem) = | ||
viewModelScope.launch(dispatcher) { | ||
client.markCompleted(todoItem.id) | ||
triggerTodosReload() | ||
} | ||
|
||
fun removeTodo(todoItem: TodoItem) = | ||
viewModelScope.launch(dispatcher) { | ||
client.remove(todoItem.id) | ||
triggerTodosReload() | ||
} | ||
|
||
private fun getTodos() = | ||
viewModelScope.async(dispatcher) { this@MainViewModel.client.readAll() } | ||
|
||
private suspend fun triggerTodosReload() { | ||
updateSignal.send(Unit) | ||
} | ||
|
||
} |
Oops, something went wrong.