Skip to content

Commit

Permalink
add: docs generation by dokka
Browse files Browse the repository at this point in the history
  • Loading branch information
anwarpro committed Oct 6, 2024
1 parent 10706ba commit 6d2d09e
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 56 deletions.
91 changes: 76 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,82 @@
This is a Kotlin Multiplatform project targeting Android, iOS, Web, Desktop.
# MVVMate

* `/composeApp` is for code that will be shared across your Compose Multiplatform applications.
It contains several subfolders:
- `commonMain` is for code that’s common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
`iosMain` would be the right folder for such calls.
MVVMate is a minimal state management library for Compose Multiplatform, based on the MVVM architecture.

* `/iosApp` contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform,
you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
[![Maven Central](https://img.shields.io/maven-central/v/com.helloanwar.mvvmate.core)](https://search.maven.org/artifact/com.helloanwar/mvvmate.core)
[![Documentation](https://img.shields.io/badge/docs-API-blue)](https://anwarpro.github.io/mvvmate)

## Overview

Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html),
[Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/#compose-multiplatform),
[Kotlin/Wasm](https://kotl.in/wasm/)
This library provides base classes and interfaces for managing UI state, handling user actions, and emitting side effects in a Compose Multiplatform project.

We would appreciate your feedback on Compose/Web and Kotlin/Wasm in the public Slack channel [#compose-web](https://slack-chats.kotlinlang.org/c/compose-web).
If you face any issues, please report them on [GitHub](https://github.com/JetBrains/compose-multiplatform/issues).
### Key Components

You can open the web application by running the `:composeApp:wasmJsBrowserDevelopmentRun` Gradle task.
- **BaseViewModel**: A base ViewModel class that manages state and handles user actions.
- **BaseViewModelWithEffect**: Extends `BaseViewModel` to also manage UI side effects.
- **UiState**: A marker interface for defining UI states.
- **UiAction**: A marker interface for user actions.
- **UiEffect**: A marker interface for UI side effects.

## Installation

To use MVVMate in your project, add the following to your `build.gradle.kts`:

### For Kotlin Multiplatform Projects:

```kotlin
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.helloanwar.mvvmate.core:1.0.0")
}
}
}
}
```

### For Android Projects:

```kotlin
dependencies {
implementation("com.helloanwar.mvvmate.core:1.0.0")
}
```

## Usage

Here's a simple example of how you can use `MVVMate` in your Compose Multiplatform project:

```kotlin
// Define your UI State
data class MyUiState(val message: String = "") : UiState

// Define your User Actions
sealed class MyUiAction : UiAction {
object ShowMessage : MyUiAction()
}

// Define your ViewModel
class MyViewModel : BaseViewModel<MyUiState, MyUiAction>(MyUiState()) {
override suspend fun onAction(action: MyUiAction) {
when (action) {
MyUiAction.ShowMessage -> updateState { copy(message = "Hello, World!") }
}
}
}

// Use the ViewModel in your Composable function
@Composable
fun MyScreen(viewModel: MyViewModel) {
val state by viewModel.state.collectAsState()

Text(text = state.message)
Button(onClick = { viewModel.handleAction(MyUiAction.ShowMessage) }) {
Text("Show Message")
}
}
```

## API Documentation

For more detailed information, you can check the [API documentation](https://anwarpro.github.io/mvvmate) generated by Dokka.
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ plugins {
alias(libs.plugins.jetbrainsCompose) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.kotlinMultiplatform) apply false
alias(libs.plugins.jreleaser) apply false
// alias(libs.plugins.jreleaser) apply false
alias(libs.plugins.dokka) apply false
}
26 changes: 26 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
import java.net.URL

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.jetbrainsCompose)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.dokka)
id("maven-publish")
id("com.vanniktech.maven.publish") version "0.29.0"
}
Expand Down Expand Up @@ -160,4 +162,28 @@ mavenPublishing {

// Enable GPG signing for all publications
signAllPublications()
}

tasks.dokkaHtml {
outputDirectory.set(buildDir.resolve("dokka"))
dokkaSourceSets {
configureEach {
// Links to external documentation (e.g., coroutines, Android APIs, etc.)
externalDocumentationLink {
url.set(URL("https://kotlinlang.org/api/latest/jvm/stdlib/"))
}
}
}
}

tasks.dokkaHtml.configure {
dokkaSourceSets {
named("commonMain") {
sourceLink {
localDirectory.set(file("src/commonMain/kotlin"))
remoteUrl.set(URL("https://github.com/anwarpro/mvvmate/blob/main/src/commonMain/kotlin"))
remoteLineSuffix.set("#L")
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,50 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.Dispatchers

/**
* Base class for ViewModels that manages UI state and handles user actions.
*
* This class holds the common logic for state management using [StateFlow] and
* provides a mechanism to handle actions asynchronously using Kotlin coroutines.
*
* @param S The type of UI state that this ViewModel manages. It should implement [UiState].
* @param A The type of user actions (intents) that this ViewModel responds to. It should implement [UiAction].
* @property initialState The initial state of the ViewModel when it is created.
*/
abstract class BaseViewModel<S : UiState, A : UiAction>(
initialState: S
) : ViewModel() {

/**
* StateFlow that represents the current UI state.
*/
private val _state = MutableStateFlow(initialState)
val state: StateFlow<S> get() = _state

// Expose a method to update the state
/**
* Method to update the current state of the UI.
*
* @param reducer A lambda that defines how to modify the state.
*/
protected fun updateState(reducer: S.() -> S) {
_state.update { it.reducer() }
}

// Handle intents or actions
/**
* Handles a user action and updates the state accordingly using the provided [onAction] method.
*
* @param action The user action to handle.
*/
fun handleAction(action: A) {
CoroutineScope(Dispatchers.Main).launch {
onAction(action)
}
}

// Abstract method to handle actions
/**
* Abstract method to be implemented by subclasses to handle the specific action logic.
*
* @param action The user action to be handled.
*/
abstract suspend fun onAction(action: A)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,33 @@ package com.helloanwar.mvvmate.core
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow

/**
* Base class for ViewModels that manages UI state, handles user actions, and emits side effects.
*
* This class extends [BaseViewModel] by adding support for emitting side effects
* via a [SharedFlow]. Side effects are typically used for actions that should not
* directly mutate the UI state but trigger external events, such as navigation or showing a dialog.
*
* @param S The type of UI state that this ViewModel manages. It should implement [UiState].
* @param A The type of user actions (intents) that this ViewModel responds to. It should implement [UiAction].
* @param E The type of side effects that this ViewModel emits.
* @property initialState The initial state of the ViewModel when it is created.
*/
abstract class BaseViewModelWithEffect<S : UiState, A : UiAction, E>(
initialState: S
) : BaseViewModel<S, A>(initialState) {

/**
* A [SharedFlow] for emitting one-time side effects such as navigation or showing dialogs.
*/
private val _sideEffects = MutableSharedFlow<E>()
val sideEffects: SharedFlow<E> get() = _sideEffects

/**
* Emit a side effect to be handled by the UI.
*
* @param effect The side effect to emit.
*/
protected suspend fun emitSideEffect(effect: E) {
_sideEffects.emit(effect)
}
Expand Down
17 changes: 17 additions & 0 deletions core/src/commonMain/kotlin/com/helloanwar/mvvmate/core/Platform.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
package com.helloanwar.mvvmate.core

/**
* Platform interface representing platform-specific implementations.
*
* This interface is expected to be implemented by each target in a Kotlin Multiplatform project (e.g., Android, iOS).
* It is typically used to get platform-specific information like the name of the platform.
*/
interface Platform {
/**
* The name of the platform (e.g., "Android", "iOS").
*/
val name: String
}


/**
* Function to get the platform-specific implementation of [Platform].
*
* This function is expected to be implemented separately in each platform's source set.
*
* @return A [Platform] instance that represents the current platform.
*/
expect fun getPlatform(): Platform
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
package com.helloanwar.mvvmate.core

/**
* Marker interface representing an action or intent from the user.
*
* This interface is used in the MVVM pattern to define user actions that are handled by the ViewModel.
* Examples of actions might include button clicks, text input changes, etc.
*/
interface UiAction
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
package com.helloanwar.mvvmate.core

/**
* Marker interface representing a UI side effect.
*
* Side effects are typically actions that do not directly modify the UI state but are meant to trigger external events,
* such as showing a toast, navigating to another screen, or showing a dialog.
*/
interface UiEffect
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
package com.helloanwar.mvvmate.core

/**
* Marker interface representing the state of the UI.
*
* This interface is implemented by classes that define the data necessary to render the UI.
* In the MVVM pattern, the state represents the current state of the ViewModel and is observed by the UI.
*/
interface UiState
4 changes: 3 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ junit = "4.13.2"
kotlin = "2.0.20"
kotlinx-coroutines = "1.8.1"
jreleaser = "1.7.0"
dokka = "1.9.0"

[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
Expand All @@ -40,4 +41,5 @@ androidLibrary = { id = "com.android.library", version.ref = "agp" }
jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
jreleaser = { id = "org.jreleaser", version.ref = "jreleaser" }
jreleaser = { id = "org.jreleaser", version.ref = "jreleaser" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }

0 comments on commit 6d2d09e

Please sign in to comment.