diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100644
index 0000000..ca137f4
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Rebuilds the packaged skills (skills/) from their sources (skills-src/) and stages
+# the result, so any changes are included in the commit being made.
+set -e
+
+repo_root="$(git rev-parse --show-toplevel)"
+cd "$repo_root"
+
+if [ ! -f "skills-src/build_skills.sh" ]; then
+ echo "Warning: skills-src/build_skills.sh not found, skipping skills rebuild."
+ exit 0
+fi
+
+echo "Rebuilding skills/ from skills-src/..."
+bash skills-src/build_skills.sh
+
+echo "Adding changes..."
+git add skills
+
+exit 0
diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml
index 7c2b62f..c073595 100644
--- a/.github/workflows/check.yml
+++ b/.github/workflows/check.yml
@@ -33,7 +33,7 @@ jobs:
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Check with gradle
- run: ./gradlew runUnitTests :examples:lce:assembleDebug :examples:welcome:welcome:assembleDebug :examples:multi:navbar:assembleDebug :examples:multi:parallel:assembleDebug :examples:lifecycle:assembleDebug :examples:di:app:assembleDebug :examples:book:app:assembleDebug :examples:book:book:demo:assembleDebug checkLegacyAbi --no-daemon --no-configuration-cache
+ run: ./gradlew runUnitTests :examples:lce:assembleDebug :examples:welcome:app:assembleDebug :examples:multi:navbar:assembleDebug :examples:multi:parallel:assembleDebug :examples:lifecycle:assembleDebug :examples:di:app:assembleDebug :examples:book:app:assembleDebug :examples:book:book:demo:assembleDebug :examples:book:app:assembleDebug :examples:skills:auth:demo:assembleHappyPathDebug :examples:skills:auth:demo:assembleConnectionErrorsDebug :examples:skills:app:assembleDebug checkLegacyAbi --no-daemon --no-configuration-cache
- name: Upload problems report
uses: actions/upload-artifact@v4
if: failure()
diff --git a/.gitignore b/.gitignore
index cdbd6ea..ac927bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,8 @@
/.idea
.DS_Store
/build
+/Claude outputs
+/artifacts
/.kotlin
build
/captures
diff --git a/.run/Check All.run.xml b/.run/Check All.run.xml
new file mode 100644
index 0000000..a9c45b1
--- /dev/null
+++ b/.run/Check All.run.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+
+ false
+ false
+
+ false
+ false
+ false
+ false
+
+
+
\ No newline at end of file
diff --git a/.run/Journeys.run.xml b/.run/Journeys.run.xml
new file mode 100644
index 0000000..03a2f26
--- /dev/null
+++ b/.run/Journeys.run.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+
+ true
+
+
+ true
+ true
+
+ false
+ true
+ false
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..05adb52
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,63 @@
+# AGENTS.md
+
+## Project Overview
+**CommonStateMachine** is a lightweight, non-opinionated Kotlin Multiplatform (KMP) library that implements a finite-state machine pattern for MVI (Model-View-Intent) architectures.
+
+### Key Architecture Concepts
+- **`CommonStateMachine`**: Acts as a bridge between the active logical state and the UI. `FlowStateMachine` exports state updates as a Kotlin `StateFlow`.
+- **`CommonMachineState`**: Encapsulates state-bound business logic, processes user gestures (`G`), emits UI states (`U`), and handles transitions to other states. Supports state-scoped coroutines via `CoroutineState`.
+- **StateMachine Class diagram**: Take a look at the framework [class diagram](doc/StateMachine.puml).
+- **State Separation & DI Abstractions**:
+ - **Use-cases**: Business logic isolated from view logic.
+ - **View-state Renderer**: Decouples UI rendering logic from logical state transitions.
+ - **Context & State Factories**: Common `Context` delegates dependencies to states; dedicated factories (`StateFactory`) create states using inter-state dynamic data.
+- **Multi-Module Support (`ProxyMachineState`)**:
+ - Wraps nested feature flows within a parent state machine.
+ - Bridges heterogeneous gesture and UI state systems through mapping adapters (`mapGesture`, `mapUiState`).
+ - Standardized via `commonflow` modules (`commonflow-data`, `commonflow-compose`, `commonflow-viewmodel`).
+ - Take a look at the [proxy lifecycle diagram](doc/ProxyLifecycle.puml).
+- **Parallel Machine Composition (`MultiMachineState`)**:
+ - Runs multiple state machines concurrently or selectively in parallel using `ProxyMachineContainer`.
+ - Manages active/dormant machine lifecycles via `MachineLifecycle`.
+
+---
+
+## Build and Verification
+If you need to test if everything in the project compiles and unit tests pass:
+
+1. Take the GitHub action: `.github/workflows/check.yml`.
+2. Find and execute the Gradle command from the step: `Check with gradle`.
+
+---
+
+## Examples
+Example projects demonstrating various architectures, state machine features, and usage patterns are located in the `examples` folder:
+- **`examples/lce`**: Basic Load-Content-Error pattern.
+- **`examples/welcome`**: Multi-module on-boarding flow.
+- **`examples/multi`**: Parallel state machines (`parallel`), bottom navbar navigation (`navbar`), and mixed gesture/UI state composition (`mixed`).
+- **`examples/lifecycle`**: View lifecycle tracking and operation pausing on lifecycle changes.
+- **`examples/di`**: Dynamic child flow binding with Hilt.
+- **`examples/skills`**: Multi-module example demonstrating custom skills implementation.
+
+---
+
+## Skills
+There are two folders managing skills:
+- **`skills-src`**: Source files used to develop and maintain skills. **Always edit skill files in `skills-src`**, never directly in `skills/`.
+ - **Shared resources**: Reusable files and templates are stored in `.shared/` subfolders.
+ - **Asset symlinks**: Code examples in `assets/` subfolders are symlinked from `examples/skills/` so they remain compilable and testable.
+- **`skills`**: Contains complete, self-contained generated skills for distribution (e.g. `npx skills`). Do not edit files here directly—they are automatically generated from `skills-src/` via [the build script](skills-src/build_skills.sh) (executed automatically by [.githooks/pre-commit](.githooks/pre-commit) upon commit).
+
+---
+
+## Coding conventions
+- Use KDoc for documenting classes, interfaces, and public functions.
+- Follow standard Kotlin coding conventions and style guidelines.
+- Add copyright headers at the top of Kotlin source files.
+- When checking for boolean `false`, use the `.not()` extension function instead of `!` for clarity (e.g., `if (condition.not()) { ... }`).
+- Use Yoda style for equality comparisons (e.g., `if ("a" == b) { ... }`).
+
+## Disk operations
+- When moving or renaming files, use `git mv` instead of deleting the old file and creating a new file at the new path, so file history and changes remain tracked.
+- When deleting files, use `git rm` so the removal is properly tracked by Git.
+
diff --git a/README.md b/README.md
index f030a5e..1ce3dfd 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,76 @@
# CommonStateMachine [](https://github.com/motorro/CommonStateMachine/actions/workflows/check.yml) [](https://repo1.maven.org/maven2/com/motorro/commonstatemachine/commonstatemachine/)
-Please checkout the Medium article on pattern/library usage.
+Please check out the Medium article on pattern/library usage.
- [Part I - basics](https://proandroiddev.com/mvi-architecture-with-a-state-machine-basics-721c5ebed893)
- [Part II - tools](https://proandroiddev.com/mvi-architecture-with-a-state-machine-tools-721c5ebed893-47f46413415d)
- [Part III - multi-module and multi-platform](https://proandroiddev.com/mvi-architecture-with-a-state-machine-modules-3e242666c7c)
+## TL;DR (for AI agents and quick answers)
+
+**What this is**: a lightweight Kotlin Multiplatform state-machine library for building MVI-pattern apps
+(Android, Compose Multiplatform, and beyond) around an explicit finite-state machine instead of reducer
+if/else logic or a navigation graph. Core idea - **Navigation Inversion**: the state machine decides what
+screen to show next, not a nav graph; several logical states can map to the same screen, and a transition can
+carry live data (even a running coroutine) forward without serializing it into navigation arguments.
+
+**Reach for it when you need to**:
+- Replace sprawling reducer logic for a multi-step flow (onboarding, checkout, auth) with explicit states and
+ transitions that unit-test in isolation.
+- Embed a self-contained feature module (built by another team, or living in its own Gradle module) inside a
+ host app's flow by running it as a nested state machine within one host state - a `ProxyMachineState`
+ (see [Adopting foreign state-flow](#adopting-foreign-state-flow)) - or, just as easily, run the very same
+ module standalone behind a traditional per-screen ViewModel and navigation setup via `CommonFlowViewModel`.
+ Check the [Common Child Flow](#common-child-flow-api) section below for the full pattern (`ProxyMachineState`, `CommonFlowHost`,
+ `CommonFlowDataApi`, `CommonFlowUiApi`, `CommonFlowViewModel`, `CommonFlowComposition`).
+- Run independent state machines together on one screen (`MultiMachineState`) - in parallel, or one-active-at-a-time.
+ Check [Running state-machines in parallel](#running-state-machines-in-parallel-composition) section below for the full pattern.
+- Scaffold, extend, demo, or write AI-driven UI tests for a Common Child Flow feature module with a coding
+ agent - see [AI Skills](#ai-skills) below.
+
+**Key vocabulary** (the exact terms used throughout this repo and its AI skills):
+
+| Term | What it is |
+|-------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `CommonMachineState` | One logical state: processes gesture `G`, emits UI state `U`. |
+| `CommonStateMachine` | Holds the current state, dispatches gestures to it, exposes the UI-state stream. |
+| `ProxyMachineState` | A state that runs a nested state-machine inside it, translating gestures/UI-states between parent and child systems - the mechanism behind both parallel composition and Common Child Flow. |
+| `MultiMachineState` / `ProxyMachineContainer` | Runs several state machines side by side under one parent state. |
+| `Common Child Flow` | A pattern to create a feature module with a child state-machine, hosted via a `ProxyMachineState` so host and feature never share concrete types. Great for DI, build flavors, A-B testing, etc. |
+| `CommonFlowHost` | Interface the parent (proxy) provides to the child flow, so the child can interract with the host and signal its flow completion. |
+| `CommonFlowDataApi` | Interface the child flow exposes to initiate itself and adapt its gestures/UI-states to the hosting flow. |
+| `CommonFlowUiApi` | Interface with a single `Screen` method to inject the child flow's UI into the host's composition. |
+| `CommonFlowViewModel` / `CommonFlowComposition` | Bridges a Common Child Flow module into traditional per-screen architecture - a ready-made ViewModel + Compose scaffold that works with Activities, Fragments or Compose navigation |
+
+**Gradle coordinates** (replace `x.x.x` with the latest release):
+```groovy
+implementation "com.motorro.commonstatemachine:commonstatemachine:x.x.x" // core
+implementation "com.motorro.commonstatemachine:coroutines:x.x.x" // coroutine extensions (optional)
+implementation "com.motorro.commonstatemachine:lifecycle:x.x.x" // view-lifecycle-aware proxies (optional)
+implementation "com.motorro.commonstatemachine:commonflow-data:x.x.x" // Common Child Flow: Child state-flow layer
+implementation "com.motorro.commonstatemachine:commonflow-compose:x.x.x" // Common Child Flow: Child Compose UI layer
+implementation "com.motorro.commonstatemachine:commonflow-viewmodel:x.x.x" // Common Child Flow: ViewModel bridge
+```
+
+The full guide below covers the basic Load-Content-Error example, state factories and dependency provision,
+multi-module adoption, and parallel composition in depth - this TL;DR is a map to it, not a replacement.
+
+## AI Skills
+
+The project ships a set of AI skills that teach coding agents (such as Claude) how to work with
+`CommonStateMachine` - for example, scaffolding a new feature-flow module that follows the
+[Common Child Flow](#common-child-flow-api) architecture described below. See
+[skills/README.md](skills/README.md) for the full list of available skills.
+
+Skills can be installed straight from this repository with the [`skills` CLI](https://github.com/vercel-labs/skills):
+
+```bash
+# List the skills available in this repository
+npx skills add motorro/commonstatemachine --list
+
+# Install specific skills
+npx skills add motorro/commonstatemachine --skill commonstatemachine-commonchildflow-boilerplate
+```
+
## Contents
@@ -47,7 +113,7 @@ Please checkout the Medium article on pattern/library usage.
* [ProxyMachineContainer](#proxymachinecontainer)
* [Mapping UI states](#mapping-ui-states)
* [Dispatching gestures](#dispatching-gestures)
- * [MachineLifecle bonus](#machinelifecle-bonus)
+ * [MachineLifecle bonus](#machinelifecyle-bonus)
- [Conclusion](#conclusion)
@@ -76,7 +142,7 @@ app growth:
- Too much overkill for simple functions like LCE (Load/Content/Error) display
- Too much reducer logic based on if/else of the current data state which plays badly in complex
- multi-step scenarios.
+ multistep scenarios.
- Quite a learning curve to grasp the technology
The simple pattern presented by this project aims to overcome the above drawbacks and to give you
@@ -90,9 +156,14 @@ Key features:
- Should work well in kotlin-multiplatform projects
- Easy to integrate with multi-module architecture
- Designed for [Jetpack Compose](https://developer.android.com/jetpack/compose) but it is not a restriction
+- **Navigation inversion** - the user doesn't navigate between screens, the logic decides what to show next; several
+ logical states can map to the very same screen while the machine moves silently between them, and a transition can
+ carry live data (even a running coroutine) forward without packing it into serializable arguments the way a
+ screen-based navigation graph would
+ ([read more](https://proandroiddev.com/mvi-architecture-with-a-state-machine-basics-721c5ebed893))
- May (if you like to) work as a navigation library
- Explicit `Back` gesture management with the total control of yours
-- Get rid of `SingleLiveEvent` for navigation, dialogs and even side-effects like toasts if you
+- Get rid of `SingleLiveEvent` for navigation, dialogs and even side effects like toasts if you
like to by completely describing the current UI state.
## v3.X Breaking change
@@ -103,7 +174,7 @@ the `ProxyMachineState` now require to pass initial UI state in constructors.
## v4.X Breaking change
-The view lifecycle [MachineLifecycle](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/lifecycle/MachineLifecycle.kt))
+The view lifecycle [MachineLifecycle](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/lifecycle/MachineLifecycle.kt)
implementation is moved to the separate multiplatform library:
```groovy
@@ -115,7 +186,7 @@ dependencies {
## Dependencies
-The project has a very simple core to implement yourself but you could also grab the latest core
+The project has a very simple core to implement yourself, but you could also grab the latest core
version like that:
```groovy
@@ -143,7 +214,7 @@ val commonMain by getting {
## Examples
- [LCE](examples/lce) - basic example of Load-Content-Error application
-- [Welcome](examples/welcome/welcome) - multi-module example of user on-boarding flow
+- [Welcome](examples/welcome/app) - multi-module example of user on-boarding flow
- [Parallel](examples/multi/parallel) - two machines running in parallel in one proxy state
- [Navbar](examples/multi/navbar) - several machines running in proxy state, one of them active at a time
- [Mixed](examples/multi/mixed) - two machines of different gesture/UI system mixed in one state
@@ -161,10 +232,10 @@ Let's break down business requirements...
We have four application _logical_ states which correspond to _screen_ states for this application:
-- Item list - the list of items to load is displayed. User clicks an item to load it's contents.
+- Item list - the list of items to load is displayed. User clicks an item to load its contents.
- Loading item - the network operation is running. User waits for operation to complete.
- Item content - the loaded item content is displayed. User may return back to item list.
-- Item load error - the load operation has failed and we have a choice to retry load or to quit the
+- Item load error - the load operation has failed, and we have a choice to retry load or to quit the
application.
### States and transitions
@@ -186,17 +257,17 @@ Let's take a look at which `Gestures` each logical state processes and how they
logical states:
-| Logical state | Ui-State | Gesture/Event | Next state | Output |
-| -------------------- | --------- | ------------- | ---------- | -------------------------------- |
-| ItemList | ItemList | Back | Terminated | Finishes activity |
-| | | ItemClicked | Loading | Loads requested item |
-| Loading | Loading | Back | Item list | Cancels load and returns to list |
-| | | onContent | Content | Displays loaded item |
-| | | onError | Error | Displays load error |
-| Content | Item | Back | Item list | Returns to the item list |
-| Error | Error | Back | Item list | Returns to the item list |
-| | | Retry | Loading | Retries load operation |
-| | | Exit | Terminated | Finishes activity |
+| Logical state | Ui-State | Gesture/Event | Next state | Output |
+|---------------|----------|---------------|------------|----------------------------------|
+| ItemList | ItemList | Back | Terminated | Finishes activity |
+| | | ItemClicked | Loading | Loads requested item |
+| Loading | Loading | Back | Item list | Cancels load and returns to list |
+| | | onContent | Content | Displays loaded item |
+| | | onError | Error | Displays load error |
+| Content | Item | Back | Item list | Returns to the item list |
+| Error | Error | Back | Item list | Returns to the item list |
+| | | Retry | Loading | Retries load operation |
+| | | Exit | Terminated | Finishes activity |
Each logical state should be able to:
@@ -211,7 +282,7 @@ state when logic falls behind what's relevant for this state.
### State machine
-First of all we need some kind of a bridge between the current logical state and the outside world.
+First of all we need some kind of bridge between the current logical state and the outside world.
The [state machine](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/CommonStateMachine.kt)
should be able to:
@@ -219,14 +290,14 @@ should be able to:
- Transition between states
- Delegate gesture processing to the current state
- Propagate UI-state changes to the outside world
-- Clean-up all resources on shutdown
+- Cleanup all resources on shutdown

Methods:
- `process(gesture: G)` - Called by view upon user action. Delegated to current state.
-- `clear()` - Called by view/framework to cleanup resources. Like in `onCleared` of `ViewModel`.
+- `clear()` - Called by view/framework to clean up resources. Like in `onCleared` of `ViewModel`.
- `setMachineState(machineState: CommonMachineState)`- Called by active state to transition
to the new one.
- `setUiState(uiState: U)` - Called by active state to update view.
@@ -281,9 +352,9 @@ and two lifecycle methods:
by replacing by the new state or when state-machine is about to be destroyed.
The state lives between `doStart` and `doClear` calls. You could safely call interaction methods
-and expect gesture processing calls within that period. Make sure to cleanup all your pending
+and expect gesture processing calls within that period. Make sure to clean up all your pending
operations in `doClear` handler. For example, the [CoroutineState](coroutines/src/commonMain/kotlin/com/motorro/commonstatemachine/coroutines/CoroutineState.kt)
-provides you the `stateScope` coroutine scope that is being cancelled in `doClear`:
+provides you the `stateScope` coroutine scope that is being canceled in `doClear`:
```kotlin
abstract class CoroutineState: CommonMachineState() {
@@ -303,7 +374,7 @@ concerns. Will talk about it later.
#### Item list state
-[ItemListState](examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ItemListState.kt) is a
+[ItemListState](examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListState.kt) is a
starting state for our application. It displays the list of items to load. The list is hardcoded for
this example so we just emit a complete view-state when started:
@@ -319,7 +390,7 @@ override fun doStart() {
```
Handle relevant gestures by transitioning the state-machine to the newly created states.
-The `LoadingState` constructor accepts an id of item to load as an inter-state common data.
+The `LoadingState` constructor accepts an id of item to load as an interstate common data.
```kotlin
override fun doProcess(gesture: LceGesture) = when(gesture) {
@@ -339,7 +410,7 @@ private fun onBack() {
#### Item loading state
-[LoadingState](examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LoadingState.kt) emulates
+[LoadingState](examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadingState.kt) emulates
an asynchronous operation:
```kotlin
@@ -360,7 +431,7 @@ private fun load() {
```
Depending on the item we pass the state transitions to either a `ContentState` or an `ErrorState`
-passing either the mock content or the error occurred as an inter-state data:
+passing either the mock content or the error occurred as an interstate data:
```kotlin
private fun toContent() {
@@ -374,7 +445,7 @@ private fun toError() {
#### Item contents state
-[ContentState](examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ContentState.kt) is very
+[ContentState](examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ContentState.kt) is very
simple. It just sets the UI state to display data passed to the constructor and handles a `Back`
gesture to return to the item list:
@@ -394,10 +465,10 @@ private fun onBack() {
```
#### Error state
-The [ErrorState](examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ErrorState.kt) gives a
-user the ability to retry item load or to exit the app. Also it handles `Back` gesture to return to
+The [ErrorState](examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ErrorState.kt) gives a
+user the ability to retry item load or to exit the app. Also, it handles `Back` gesture to return to
the item list. Handling all user interactions through your state machine gives you a precise control
-on what happens next. The item ID passed in the constructor as an inter-state data makes it possible
+on what happens next. The item ID passed in the constructor as an interstate data makes it possible
to preserve user's selection and to restart loading from scratch.
```kotlin
@@ -436,7 +507,7 @@ class ErrorState(private val failed: ItemId, private val error: Throwable) : Lce
#### Wiring with the application
Now that we have all states in place let's connect them together with a state machine. We need some
-place to retain a machine through the application flow so let's wrap it to the [Jetpack ViewModel](examples/lce/src/main/java/com/motorro/statemachine/lce/model/LceViewModel.kt)
+place to retain a machine through the application flow so let's wrap it to the [Jetpack ViewModel](examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/LceViewModel.kt)
which is common now:
```kotlin
@@ -479,7 +550,7 @@ All we need to do here is:
- to figure out the initial state that machine will start from
- to wire ui-state and gesture processing with the outside world
-And here is an abstract of the [view](examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LceScreen.kt)
+And here is an abstract of the [view](examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LceScreen.kt)
that interacts with the model:
```kotlin
@@ -513,17 +584,17 @@ fun LceScreen(onExit: @Composable () -> Unit) {
}
```
-Compose library plays greatly here but you could easily adapt a fragment transaction or a
+Compose library plays greatly here, but you could easily adapt a fragment transaction or a
recycler view architecture as well.
### Result
As you can see the state-machine pattern may be a good choice in implementing your MVI architecture.
It produces a clean and easy to grasp step-by-step logic with well-separated concerns and easy and
-[thorough](examples/lce/src/test/java/com/motorro/statemachine/lce/model/state) testing. The pattern also
+[thorough](examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state) testing. The pattern also
attempts to be as non-opinionated as possible. Each state is a black-box with a defined contract and
developers may choose the most suitable tools to implement each one without affecting the other. The
-example above is a very basic one. However you could do things a bit more clean by using some of the
+example above is a very basic one. However, you could do things a bit more clean by using some of the
additional abstractions (see below).
## Tools and Handy abstractions to mix-in
@@ -541,9 +612,9 @@ So let's introduce some abstractions that will lift the burden off the state's s
By use-case I assume any business logic external to your view logic implemented in a state. Be it
some network operation or some other "use-case" - provide it to your state and use them as you like.
-There is nothing new here - I'm sure you already use the approach in your flavour of
+There is nothing new here - I'm sure you already use the approach in your flavor of
Clean Architecture or similar. Example of using an external use-case could be found in
-[examples/welcome/welcome example](examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/CredentialsCheckState.kt):
+[examples/welcome/app example](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckState.kt):
```kotlin
class CredentialsCheckState(private val checkCredentials: CheckCredentials) {
@@ -570,11 +641,11 @@ creates it's scope with `Dispatchers.Main.immediate`.
Preparing the complex view-state from your state data might be a non-trivial task in applications
with complex interface. Moving a coupling to the view-state and data structures from your state logic
might be a good idea. Testing the exact view-state creation would be much easier if you make it
-as more or less a clean function. Also your logic states may share the same rendering logic so
+as more or less a clean function. Also, your logic states may share the same rendering logic so
externalizing it would play greatly in terms of code reuse. For example the same view-state
-rendering is used by [PasswordEntryState](examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/PasswordEntryState.kt)
-and [ErrorState](examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/ErrorState.kt) of
-examples/welcome/welcome example. You could inject your renderer in a state factory or get it from common context
+rendering is used by [PasswordEntryState](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryState.kt)
+and [ErrorState](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorState.kt) of
+examples/welcome/app example. You could inject your renderer in a state factory or get it from common context
(see below).
### State factories and dependency provision
@@ -585,7 +656,7 @@ is not a good idea in terms of coupling and dependency provision.
The machine state, when created, may require three main classes of dependencies:
- State-specific dependencies like use-cases state operates.
-- Inter-state data e.g. data loaded in a previous state, common data state, etc.
+- Interstate data e.g. data loaded in a previous state, common data state, etc.
- Common dependencies for all states in machine: renderers, resource providers, factories
You are free to choose the way to provide dependencies however let's take a look at the approach
@@ -605,8 +676,8 @@ class CredentialsCheckState(private val checkCredentials: CheckCredentials) {
/**
* Dedicated state factory
*/
- @LoginScope
- class Factory @Inject constructor(private val checkCredentials: CheckCredentials) {
+ @Factory
+ class StateFactory(private val checkCredentials: CheckCredentials) {
operator fun invoke(): LoginState = CredentialsCheckState(
checkCredentials
)
@@ -616,7 +687,7 @@ class CredentialsCheckState(private val checkCredentials: CheckCredentials) {
#### Inter-state data
-By inter-state data I assume any dynamic data that is passed between states. It may be a product of
+By interstate data I assume any dynamic data that is passed between states. It may be a product of
some calculation, user-generated data, etc. The most obvious way is providing it through the state
constructor:
@@ -647,7 +718,7 @@ class CredentialsCheckState(
Common dependencies may include renderers, state factories, common external interfaces and anything
else that is required by all states that make up the state-machine. For convenience and to save the
number of constructor params I suggest to bind them to some common interface and provide it as a
-whole. Let's name it a common [Context](examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginContext.kt):
+whole. Let's name it a common [Context](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginContext.kt):
```kotlin
interface LoginContext {
@@ -669,7 +740,7 @@ interface LoginContext {
```
Then you could provide it to your state through the constructor parameters. To make things even
-easier let's make some [base state](examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginState.kt)
+easier let's make some [base state](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginState.kt)
for the state-machine assembly and use a delegation to provide each context dependency:
```kotlin
@@ -678,13 +749,13 @@ abstract class LoginState(
): CoroutineState(), LoginContext by context {
override fun doProcess(gesture: LoginGesture) {
- Timber.w("Unsupported gesture: %s", gesture)
+ Napier.w("Unsupported gesture: ${gesture}")
}
}
```
-Thus every sub-class of the `LoginState` has any context dependency at hand by getting it from the
-corresponding property as if the were provided explicitly:
+Thus, every subclass of the `LoginState` has any context dependency at hand by getting it from the
+corresponding property as if they were provided explicitly:
```kotlin
class CredentialsCheckState(
@@ -701,8 +772,8 @@ class CredentialsCheckState(
/**
* Factory updated to pass common context
*/
- @LoginScope
- class Factory @Inject constructor(private val checkCredentials: CheckCredentials) {
+ @Factory
+ class StateFactory(private val checkCredentials: CheckCredentials) {
operator fun invoke(
context: LoginContext,
data: LoginDataState
@@ -720,7 +791,7 @@ class CredentialsCheckState(
As I've already mentioned, creating new states explicitly to pass them to the state-machine later
(like in the basic example) is not a good idea in terms of coupling and dependency provision.
-Let's move it away from our machine states by introducing a common [factory interface](examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginStateFactory.kt)
+Let's move it away from our machine states by introducing a common [factory interface](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactory.kt)
that will take the responsibility to provide dependencies and abstract our state creation logic:
```kotlin
@@ -744,24 +815,24 @@ interface LoginStateFactory {
}
```
-Each factory method here will accept **only** the inter-state data providing both context and
+Each factory method here will accept **only** the interstate data providing both context and
state-specific dependencies implicitly. This will decouple state logic from the concrete
-implementations and increase our [testability](examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/BaseStateTest.kt)
+implementations and increase our [testability](examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/BaseStateTest.kt)
greatly.
The exact factory implementation that binds together all data and dependencies will look like that:
```kotlin
-@LoginScope
-class LoginStateFactoryImpl @Inject constructor(
- host: WelcomeFeatureHost, // External interface
+@Factory(binds = [LoginFlowStarter::class])
+class LoginStateFactoryImpl(
+ @InjectedParam host: WelcomeFeatureHost, // External interface
renderer: LoginRenderer, // Renderer
- private val createCredentialsCheck: CredentialsCheckState.Factory // Concrete state factory
+ private val createCredentialsCheck: CredentialsCheckState.StateFactory // Concrete state factory
) : LoginStateFactory {
// Dependencies common for each state provided through the context
private val context: LoginContext = object : LoginContext {
- override val factory: LoginStateFactory = this@Impl
+ override val factory: LoginStateFactory = this@LoginStateFactoryImpl
override val host: WelcomeFeatureHost = host
override val renderer: LoginRenderer = renderer
}
@@ -828,22 +899,21 @@ class CredentialsCheckStateTest {
We can also provide the state factory to the `ViewModel` and use it to initialize our state-machine:
```kotlin
-@HiltViewModel
-class LoginViewModel @Inject constructor(private val factory: LoginStateFactory) : ViewModel() {
+@KoinViewModel
+class WelcomeViewModel(private val factory: WelcomeStateFactory) : ViewModel() {
/**
* Creates initializing state
*/
private fun initializeStateMachine(): CommonMachineState {
// Obtain data required to start from a saved-state handle or injection
- val commonData: LoginDataState = LoginDataState()
- return factory.passwordEntry(commonData)
+ return factory.preload()
}
/**
* State machine
*/
- private val stateMachine = FlowStateMachine(::initializeStateMachine)
+ private val stateMachine = FlowStateMachine(WelcomeUiState.Loading, ::initializeStateMachine)
}
```
@@ -893,7 +963,7 @@ class WithIdleViewModel : ViewModel() {
## Multi-module applications
-Let's take a more complicated example with a multi-screen flow like the [customer on-boarding](examples/welcome/welcome).
+Let's take a more complicated example with a multiscreen flow like the [customer on-boarding](examples/welcome/app).

The user is required to accept terms and conditions and to enter his email. Then the logic checks if
he is already registered or a new customer and runs the appropriate flow to login or to register
@@ -903,24 +973,22 @@ the work between teams. The state diagram would be the following:
The project uses the following modules:
-* **examples/welcome/welcome** - common flow: preloading, email entry, customer check, complete
-* **commoncore** - common abstractions to build application: dispatchers, resources, etc.
-* **commonapi** - common multi-platform module to connect the main app with modules
-* **login** - login flow
-* **commonregister** - multi-platform registration logic
-* **register** - android view module for registration (separate because I've failed to implemented
- it in android source of `commonregister` due to some multiplatform misconfiguration)
+* **examples/welcome/app** - common flow: preloading, email entry, customer check, complete
+* **examples/commoncore** - common abstractions to build application: dispatchers, resources, etc.
+* **examples/welcome/commonapi** - common multi-platform module to connect the main app with modules
+* **examples/welcome/login** - login flow
+* **examples/welcome/register** - multi-platform registration flow logic and UI
### Common API
-As you could see in the diagram above each `login` and `commonregister` start after the email is
+As you could see in the diagram above each `login` and `register` start after the email is
checked and the answer to user's registration status is obtained. The module flow starts from
password entry screen though a bit different. Each module flow returns to the main flow either:
- when flow completes succefully - transfers to `Complete`
- when user hits `Back` - transfers back to email entry
-Let's define the main flow interaction [API](examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/WelcomeFeatureHost.kt)
+Let's define the main flow interaction [API](examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/WelcomeFeatureHost.kt)
then:
```kotlin
interface WelcomeFeatureHost {
@@ -952,13 +1020,13 @@ interface LoginContext {
### Module flow
-Each module has it's own sealed system of gesture/view-states:
+Each module has its own sealed system of gesture/view-states:
-| Module name | Gestures | UI-states |
-| -------------- | --------------- | ----------------- |
-| welcome | WelcomeGesture | WelcomeUiState |
-| login | LoginGesture | LoginUiState |
-| commonregister | RegisterGesture | RegisterUiState |
+| Module name | Gestures | UI-states |
+|----------------|-----------------|-----------------|
+| welcome | WelcomeGesture | WelcomeUiState |
+| login | LoginGesture | LoginUiState |
+| register | RegisterGesture | RegisterUiState |
Each module is completely independent in terms of gestures and UI states, and we also have a
proprietary set of 'handy abstractions' for each module: renderers, factories, use-cases, etc.
@@ -982,10 +1050,10 @@ To adopt feature-module gestures there are at least two solutions:
view-states. Though simple, the solution is not ideal as we lose the type-safe `when` exhaustive
checks when we dispatch gestures in our states. So let's drop it...
2. Make a wrapping adapter that wraps the foreign gesture/view-state and unwrap it later when
- passing them to concrete implementation. Thus we don't loose compiler support and type-safety.
+ passing them to concrete implementation. Thus, we don't lose compiler support and type-safety.
Let's follow this route
-Gesture [adapter](examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeGesture.kt):
+Gesture [adapter](examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeGesture.kt):
```kotlin
sealed class WelcomeGesture {
// Native gestures...
@@ -1004,7 +1072,7 @@ sealed class WelcomeGesture {
}
```
-UI-state [adapter](examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeUiState.kt):
+UI-state [adapter](examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeUiState.kt):
```kotlin
sealed class WelcomeUiState {
/**
@@ -1025,7 +1093,7 @@ sealed class WelcomeUiState {
Now let's build feature and host composables to take advantage of our adapters.
-Feature [master-view](examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/LoginScreen.kt):
+Feature [master-view](examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/LoginScreen.kt):
```kotlin
@Composable
fun LoginScreen(state: LoginUiState, onGesture: (LoginGesture) -> Unit) {
@@ -1038,13 +1106,14 @@ fun RegistrationScreen(state: RegisterUiState, onGesture: (RegisterGesture) -> U
}
```
-Application [master-view](examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/WelcomeScreen.kt):
+Application [master-view](examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/WelcomeScreen.kt):
```kotlin
+@Composable
fun WelcomeScreen(onTerminate: @Composable () -> Unit) {
- val model = hiltViewModel()
+ val model = koinViewModel()
val state = model.state.collectAsState(WelcomeUiState.Loading)
- BackHandler(onBack = { model.process(Back) })
+ BackHandler(onBack = { model.process(WelcomeGesture.Back) })
when (val uiState = state.value) {
@@ -1053,13 +1122,13 @@ fun WelcomeScreen(onTerminate: @Composable () -> Unit) {
// Render login screens
is WelcomeUiState.Login -> LoginScreen(
state = uiState.value,
- onGesture = { model.process(Login(it)) }
+ onGesture = { model.process(WelcomeGesture.Login(it)) }
)
// Render registration screens
is WelcomeUiState.Register -> RegistrationScreen(
state = uiState.value,
- onGesture = { model.process(Register(it))}
+ onGesture = { model.process(WelcomeGesture.Register(it))}
)
}
}
@@ -1101,7 +1170,7 @@ by running a _child_ state-machine inside the host state!
Whenever a `ProxyMachineState` is started it launches it's internal instance of a state-machine
bound to the feature gesture and view system. It also bridges two incompatible gesture/view systems
by wrapping/unwrapping and adopting one system to another. Let's see the example of a login flow
-[proxy](examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/LoginFlowState.kt)
+[proxy](examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/LoginFlowState.kt)
to make things clear:
```kotlin
@@ -1119,8 +1188,7 @@ private typealias LoginProxy = ProxyMachineState<
class LoginFlowState(
private val context: WelcomeContext,
private val data: WelcomeDataState,
- private val loginComponentBuilder: LoginComponentBuilder
-) : LoginProxy(Loading), WelcomeFeatureHost {
+) : LoginProxy(LoginUiState.Loading), WelcomeFeatureHost, KoinComponent {
/**
* Should have valid email at this point
@@ -1133,9 +1201,7 @@ class LoginFlowState(
* Creates initial child state
*/
override fun init(): CommonMachineState {
- val component = loginComponentBuilder.host(this).build()
- val starter = EntryPoints.get(component, LoginEntryPoint::class.java).flowStarter()
-
+ val starter = get { parametersOf(this as WelcomeFeatureHost) }
return starter.start(email)
}
@@ -1174,7 +1240,7 @@ class LoginFlowState(
To create a proxy you need to implement three core methods:
-- `init()` - creates a starting state for a proxy state-machine. We fetch a [FlowStarter](examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/FlowStarter.kt)
+- `init()` - creates a starting state for a proxy state-machine. We fetch a [FlowStarter](examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/FlowStarter.kt)
interface (which is just a feature state factory segregation) to create a starting state.
- `mapGesture(parent: PG)` - maps a gesture from the parent system to the child system. You may
unwrap the gesture we have implemented in the previous state, adopt one system to another as with
@@ -1190,7 +1256,7 @@ this interface by switching host machine to email or complete states in correspo
#### Common child flow API
-For your convenience there are couple of ready-made interfaces to adopt child flow.
+For your convenience there are a couple of ready-made interfaces to adopt child flow.
The interfaces are located in a separate libraries:
```groovy
@@ -1217,7 +1283,7 @@ Check the [example](examples/di) that shows the use of this flow:
- The app has two states: `Content` and `Auth`.
- `Content` requires authenticated user.
-- We have a basic [authentication flow](examples/di/api) flow defined.
+- We have a basic [authentication flow](examples/di/api) defined.
- We have two implementation modules [Login](examples/di/login) and [Social](examples/di/social) that authenticate users
using different authentication "providers".
- The [app](examples/di/app) module has two build variants to support each.
@@ -1242,21 +1308,21 @@ Take a look at the [books](examples/books) project to see how it works.
## Running state-machines in parallel (composition)
-In case you want several state-machines to run in parallel producing a single combined UI state or you
+In case you want several state-machines to run in parallel producing a single combined UI state, or you
want to persist several machines on a single screen (like a page with a bottom navigation) there is an
option to do it with the [MultiMachineState](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/MultiMachineState.kt)
and [ProxyMachineContainer](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/ProxyMachineContainer.kt)
### MultiMachineState
-This state is a proxy that holds several machines at once. It is in charge for combining the UI state
+This state is a proxy that holds several machines at once. It is in charge of combining the UI state
whenever the running machine updates and for dispatching gestures from a single parent gesture to
proxied machines inside the composition. To distinguish machines and to ensure type-safety each machine in
composition is identified with the [MachineKey](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/MachineKey.kt)
The state has three things to override:
- [container](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/MultiMachineState.kt#L28):
- manages machines lifecycle. More on this follows.
+ manages machines lifecycle. More on these follows.
- [mapUiState](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/MultiMachineState.kt#L97):
called each time your proxied machine updates UI state or explicitly when calling [updateUi](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/MultiMachineState.kt#L69).
Here you take a decision on changes and build a common resulting UI state. See the dedicated section below.
@@ -1267,7 +1333,7 @@ Now let's see how the things work a bit closer.
### ProxyMachineContainer
-Container is in charge for creating and managing the lifecycle of the state machines. So far the
+Container is in charge of creating and managing the lifecycle of the state machines. So far the
interface has two companion functions:
- [allTogether](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/multi/ProxyMachineContainer.kt#L44):
@@ -1315,7 +1381,7 @@ interface MachineInit {
The `init` function is called each time the container needs to create a new machine. The [MachineLifecycle](commonstatemachine/src/commonMain/kotlin/com/motorro/commonstatemachine/lifecycle/MachineLifecycle.kt)
interface passed to initialization may be used by your states to determine if the machine is suspended
or active. If you use coroutines you could use [asFlow](coroutines/src/commonMain/kotlin/com/motorro/commonstatemachine/coroutines/lifecycle/lifecycleStateFlow.kt)
-function to convert it to `Flow`. See [example](examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/state/TimerState.kt) on how to start/stop
+function to convert it to `Flow`. See [example](examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/state/TimerState.kt) on how to start/stop
your pending operations that are not needed when your machine is inactive: gps tracking, server messaging, etc.
For example:
@@ -1354,8 +1420,8 @@ private open class TestState : MultiMachineState
Check example states for each case:
-- [Parallel](examples/multi/parallel/src/main/java/com/motorro/statemachine/parallel/model/state/ParallelState.kt) - two machines running in parallel in one proxy state
-- [Navbar](examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/state/NavbarState.kt) - several machines running in proxy state, one of them active at a time
+- [Parallel](examples/multi/parallel/src/main/kotlin/com/motorro/commonstatemachine/examples/parallel/model/state/ParallelState.kt) - two machines running in parallel in one proxy state
+- [Navbar](examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/state/NavbarState.kt) - several machines running in proxy state, one of them active at a time
### Mapping UI states
@@ -1389,8 +1455,8 @@ private open class TestState : MultiMachineState() {
Check example states for use cases:
-- [Parallel](examples/multi/parallel/src/main/java/com/motorro/statemachine/parallel/model/state/ParallelState.kt) - two machines running in parallel in one proxy state
-- [Navbar](examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/state/NavbarState.kt) - several machines running in proxy state, one of them active at a time
+- [Parallel](examples/multi/parallel/src/main/kotlin/com/motorro/commonstatemachine/examples/parallel/model/state/ParallelState.kt) - two machines running in parallel in one proxy state
+- [Navbar](examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/state/NavbarState.kt) - several machines running in proxy state, one of them active at a time
### Dispatching gestures
@@ -1428,27 +1494,27 @@ private open class TestState : MultiMachineState() {
Check example states and test class for use cases:
-- [Parallel](examples/multi/parallel/src/main/java/com/motorro/statemachine/parallel/model/state/ParallelState.kt) - two machines running in parallel in one proxy state
-- [Navbar](examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/state/NavbarState.kt) - several machines running in proxy state, one of them active at a time
+- [Parallel](examples/multi/parallel/src/main/kotlin/com/motorro/commonstatemachine/examples/parallel/model/state/ParallelState.kt) - two machines running in parallel in one proxy state
+- [Navbar](examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/state/NavbarState.kt) - several machines running in proxy state, one of them active at a time
- [MultiMachineStateTest](commonstatemachine/src/commonTest/kotlin/com/motorro/commonstatemachine/multi/MultiMachineStateTest.kt) - unit test
### MachineLifecyle bonus
-The interface used to pass the machine activity to proxied state machine could also be used as an
-view lifecycle monitor for your app. Pass [UiMachineLifecycle](commonstatemachine/src/androidMain/kotlin/com/motorro/commonstatemachine/lifecycle/UiMachineLifecycle.kt)
-to your model initialization to by able to suspend your machines when app is not in use.
+The interface used to pass the machine activity to proxied state machine could also be used as a
+view lifecycle monitor for your app. Pass [UiMachineLifecycle](lifecycle/src/commonMain/kotlin/com/motorro/commonstatemachine/lifecycle/UiMachineLifecycle.kt)
+to your model initialization to be able to suspend your machines when app is not in use.
Similar to [state collection methods](https://medium.com/androiddevelopers/a-safer-way-to-collect-flows-from-android-uis-23080b1f8bda) optimized with lificycle.
Check the [example](examples/lifecycle) to get the details.
## Conclusion
I hope someone finds the article (and the library if you like to take it as-is) helpful in building
-complex multi-screen applications with multi-module ability. This approach aims to give you as much
-freedom as possible to implement your flows. Of cause it is not a silver bullet but the flexibility
+complex multiscreen applications with multi-module ability. This approach aims to give you as much
+freedom as possible to implement your flows. Of course, it is not a silver bullet but the flexibility
in structuring your app it promotes plays well in most scenarios. You could combine all your
application steps in a single state flow or build separate models and inject them to the parts of
your navigation library graph. And you could also use any architecture inside your states - simple
coroutines to fetch the data, complex RxJava flows or even another MVI library in more complex cases.
The library was created with multi-platform approach in mind as it contains no concrete platform
-dependencies and coroutines extentions are optional. So you may create your view logic once and
+dependencies and coroutines extensions are optional. So you may create your view logic once and
adopt it's output to your platform view components.
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
new file mode 100644
index 0000000..442e236
--- /dev/null
+++ b/build-logic/convention/build.gradle.kts
@@ -0,0 +1,74 @@
+plugins {
+ `kotlin-dsl`
+}
+
+group = "com.motorro.gradle.convention"
+
+dependencies {
+ compileOnly(libs.android.gradle.plugin)
+ compileOnly(libs.kotlin.gradle.plugin)
+ compileOnly(libs.compose.gradle.plugin)
+ compileOnly(libs.compose.multiplatform.gradle.plugin)
+}
+
+tasks {
+ validatePlugins {
+ enableStricterValidation = true
+ failOnWarning = true
+ }
+}
+
+tasks.withType().configureEach {
+ compilerOptions {
+ freeCompilerArgs.addAll(listOf(
+ "-opt-in=kotlin.RequiresOptIn",
+ "-Xinline-classes",
+ "-Xcontext-parameters"
+ ))
+ }
+}
+
+gradlePlugin {
+ plugins {
+ register("baseLibrary"){
+ id = "motorro.baseLibrary"
+ implementationClass = "BaseLibraryPlugin"
+ }
+ register("jvmLibrary"){
+ id = "motorro.jvmLibrary"
+ implementationClass = "JvmLibraryPlugin"
+ }
+ register("androidLibrary"){
+ id = "motorro.androidLibrary"
+ implementationClass = "AndroidLibraryPlugin"
+ }
+ register("androidComposeLibrary"){
+ id = "motorro.androidComposeLibrary"
+ implementationClass = "AndroidComposeLibraryPlugin"
+ }
+ register("androidApplication"){
+ id = "motorro.androidApplication"
+ implementationClass = "AndroidApplicationPlugin"
+ }
+ register("androidTest"){
+ id = "motorro.androidTest"
+ implementationClass = "AndroidTestPlugin"
+ }
+ register("androidDynamicFreature"){
+ id = "motorro.androidDynamicFeature"
+ implementationClass = "AndroidDynamicFeaturePlugin"
+ }
+ register("kotlinMultiplatform"){
+ id = "motorro.kmp"
+ implementationClass = "KmpPlugin"
+ }
+ register("composeMultiplatform"){
+ id = "motorro.cmp"
+ implementationClass = "CmpPlugin"
+ }
+ register("publishing"){
+ id = "motorro.publishing"
+ implementationClass = "PublishingPlugin"
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/androidcore/consumer-rules.pro b/build-logic/convention/consumer-rules.pro
similarity index 100%
rename from examples/androidcore/consumer-rules.pro
rename to build-logic/convention/consumer-rules.pro
diff --git a/build-logic/convention/proguard-rules.pro b/build-logic/convention/proguard-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationPlugin.kt
new file mode 100644
index 0000000..ef40f78
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidApplicationPlugin.kt
@@ -0,0 +1,95 @@
+import com.android.build.api.dsl.ApplicationExtension
+import com.motorro.gradle.convention.addDependency
+import com.motorro.gradle.convention.configureCommonAndroid
+import com.motorro.gradle.convention.implementation
+import com.motorro.gradle.convention.libs
+import com.motorro.gradle.convention.testImplementation
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.extra
+
+class AndroidApplicationPlugin : Plugin {
+ override fun apply(targetProject: Project) = with(targetProject) {
+ val vName = rootProject.extra.get("versionName") as String
+ val vCode = rootProject.extra.get("versionCode") as Int
+
+ println("== Application: **$name**, version: $vName($vCode) ==")
+
+ // Core plugins
+ pluginManager.apply(libs.findPlugin("android_app").get().get().pluginId)
+ pluginManager.apply(libs.findPlugin("compose").get().get().pluginId)
+
+ extensions.configure {
+
+ configureCommonAndroid(this)
+
+ defaultConfig {
+ minSdk = libs.findVersion("androidMinSdkVersion").get().requiredVersion.toInt()
+ targetSdk = libs.findVersion("androidTargetSdkVersion").get().requiredVersion.toInt()
+ versionName = vName
+ versionCode = vCode
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = true
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = Jvm.JAVA_VERSION
+ targetCompatibility = Jvm.JAVA_VERSION
+
+ isCoreLibraryDesugaringEnabled = true
+ }
+
+ testOptions {
+ unitTests {
+ isIncludeAndroidResources = true
+ all {
+ it.systemProperties["robolectric.pixelCopyRenderMode"] = "hardware"
+ }
+ }
+ }
+ }
+
+ dependencies {
+ addDependency("coreLibraryDesugaring", "desugaring")
+
+ implementation("androidx_core")
+ implementation("androidx_activity")
+ implementation("androidx_lifecycle_runtime")
+ implementation("androidx_lifecycle_viewmodel")
+
+ implementation("kotlin_coroutines_core")
+ implementation("kotlin_coroutines_android")
+
+ add("implementation", platform(libs.findLibrary("compose_bom").get()))
+ implementation("compose_ui")
+ implementation("compose_tooling_preview")
+ implementation("compose_material")
+ implementation("compose_activity")
+ implementation("compose_viewmodel")
+ implementation("compose_foundation")
+ implementation("compose_foundation_layouts")
+
+ implementation("napier")
+
+ addDependency("debugImplementation", "compose_tooling")
+ addDependency("debugImplementation", "test_compose_manifest")
+
+ testImplementation("compose_test_junit")
+ }
+ }
+}
+
diff --git a/build-logic/convention/src/main/kotlin/AndroidComposeLibraryPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidComposeLibraryPlugin.kt
new file mode 100644
index 0000000..db0f439
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidComposeLibraryPlugin.kt
@@ -0,0 +1,40 @@
+import com.android.build.api.dsl.LibraryExtension
+import com.motorro.gradle.convention.addDependency
+import com.motorro.gradle.convention.implementation
+import com.motorro.gradle.convention.libs
+import com.motorro.gradle.convention.testImplementation
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+
+class AndroidComposeLibraryPlugin : Plugin {
+
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // Core plugin
+ pluginManager.apply("motorro.androidLibrary")
+ pluginManager.apply(libs.findPlugin("compose").get().get().pluginId)
+
+ extensions.configure {
+ buildFeatures {
+ compose = true
+ }
+ }
+
+ dependencies {
+ add("implementation", platform(libs.findLibrary("compose_bom").get()))
+
+ implementation("compose_runtime")
+ implementation("compose_ui")
+ implementation("compose_tooling_preview")
+ implementation("compose_foundation")
+ implementation("compose_foundation_layouts")
+ implementation("compose_material")
+
+ addDependency("debugImplementation", "compose_tooling")
+ addDependency("debugImplementation", "test_compose_manifest")
+
+ testImplementation("compose_test_junit")
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/AndroidDynamicFeaturePlugin.kt b/build-logic/convention/src/main/kotlin/AndroidDynamicFeaturePlugin.kt
new file mode 100644
index 0000000..482a193
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidDynamicFeaturePlugin.kt
@@ -0,0 +1,43 @@
+import com.android.build.api.dsl.DynamicFeatureExtension
+import com.motorro.gradle.convention.configureCommonAndroid
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidDynamicFeaturePlugin : Plugin {
+
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // Core plugins
+ pluginManager.apply(libs.findPlugin("android_dynamic_feature").get().get().pluginId)
+
+ extensions.configure {
+
+ configureCommonAndroid(this)
+
+ defaultConfig {
+ minSdk = libs.findVersion("androidMinSdkVersion").get().requiredVersion.toInt()
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = Jvm.JAVA_VERSION
+ targetCompatibility = Jvm.JAVA_VERSION
+
+ isCoreLibraryDesugaringEnabled = true
+ }
+
+ testOptions {
+ unitTests {
+ isIncludeAndroidResources = true
+ }
+ }
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryPlugin.kt
new file mode 100644
index 0000000..85ef16e
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidLibraryPlugin.kt
@@ -0,0 +1,58 @@
+import com.android.build.api.dsl.LibraryExtension
+import com.motorro.gradle.convention.configureCommonAndroid
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidLibraryPlugin : Plugin {
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // First base library.
+ targetProject.pluginManager.apply("motorro.baseLibrary")
+
+ // Core plugins
+ pluginManager.apply(libs.findPlugin("android_lib").get().get().pluginId)
+
+ extensions.configure {
+
+ configureCommonAndroid(this)
+
+ androidResources.enable = true
+
+ defaultConfig {
+ minSdk = libs.findVersion("androidMinSdkVersion").get().requiredVersion.toInt()
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = Jvm.JAVA_VERSION
+ targetCompatibility = Jvm.JAVA_VERSION
+
+ isCoreLibraryDesugaringEnabled = true
+ }
+
+ testOptions {
+ unitTests {
+ isIncludeAndroidResources = true
+ all {
+ it.systemProperties["robolectric.pixelCopyRenderMode"] = "hardware"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/AndroidTestPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidTestPlugin.kt
new file mode 100644
index 0000000..f6c282a
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/AndroidTestPlugin.kt
@@ -0,0 +1,35 @@
+import com.android.build.api.dsl.TestExtension
+import com.motorro.gradle.convention.configureKotlin
+import com.motorro.gradle.convention.defaultNamespace
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+
+class AndroidTestPlugin : Plugin {
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // Core plugins
+ pluginManager.apply(libs.findPlugin("android_test").get().get().pluginId)
+
+ extensions.configure {
+ // Take from module name
+ namespace = defaultNamespace()
+
+ compileSdk = libs.findVersion("androidCompileSdkVersion").get().requiredVersion.toInt()
+
+ configureKotlin()
+
+ defaultConfig {
+ minSdk = libs.findVersion("androidMinTestSdk").get().requiredVersion.toInt()
+ targetSdk = libs.findVersion("androidTargetSdkVersion").get().requiredVersion.toInt()
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ testInstrumentationRunnerArguments["androidx.benchmark.suppressErrors"] = "EMULATOR"
+ }
+
+ compileOptions {
+ sourceCompatibility = Jvm.JAVA_VERSION
+ targetCompatibility = Jvm.JAVA_VERSION
+ }
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/BaseLibraryPlugin.kt b/build-logic/convention/src/main/kotlin/BaseLibraryPlugin.kt
new file mode 100644
index 0000000..e3fcabb
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/BaseLibraryPlugin.kt
@@ -0,0 +1,21 @@
+import com.motorro.gradle.convention.libDesc
+import com.motorro.gradle.convention.libId
+import com.motorro.gradle.convention.libName
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+/**
+ * Base library plugin
+ */
+class BaseLibraryPlugin : Plugin {
+ override fun apply(targetProject: Project) = with(targetProject) {
+ group = rootProject.group
+ version = rootProject.version
+
+ println("== Library: **$name**, version: $version ==")
+ println("===> Lib id: $libId")
+ println("===> Lib name: $libName")
+ println("===> Lib desc: ${libDesc ?: "--"}")
+ }
+}
+
diff --git a/build-logic/convention/src/main/kotlin/CmpPlugin.kt b/build-logic/convention/src/main/kotlin/CmpPlugin.kt
new file mode 100644
index 0000000..1101eed
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/CmpPlugin.kt
@@ -0,0 +1,57 @@
+import com.motorro.gradle.convention.defaultNamespace
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.dependencies
+import org.jetbrains.compose.ComposeExtension
+import org.jetbrains.compose.resources.ResourcesExtension
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+
+class CmpPlugin : Plugin {
+
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // First base KMP convention.
+ pluginManager.apply("motorro.kmp")
+
+ // Then Compose side.
+ pluginManager.apply(libs.findPlugin("compose").get().get().pluginId)
+ pluginManager.apply(libs.findPlugin("compose_multiplatform").get().get().pluginId)
+ pluginManager.apply(libs.findPlugin("compose_hot_reload").get().get().pluginId)
+
+ extensions.configure {
+
+ sourceSets.apply {
+ commonMain.dependencies {
+ implementation(libs.findLibrary("compose_multiplatform_runtime").get())
+ implementation(libs.findLibrary("compose_multiplatform_ui").get())
+ implementation(libs.findLibrary("compose_multiplatform_foundation").get())
+ implementation(libs.findLibrary("compose_multiplatform_material3").get())
+
+ // KMP resources (Res.drawable.*)
+ implementation(libs.findLibrary("compose_multiplatform_resources").get())
+
+ // Enable KMP @Preview for @Compose functions.
+ implementation(libs.findLibrary("compose_multiplatform_preview").get())
+ }
+
+ // Preview / tooling for only Android.
+ androidMain.dependencies {
+ implementation(libs.findLibrary("compose_tooling").get())
+ }
+ }
+ }
+
+ dependencies {
+ add("androidRuntimeClasspath", libs.findLibrary("compose_multiplatform_tooling").get())
+ }
+
+ extensions.configure {
+ configure {
+ publicResClass = false
+ packageOfResClass = defaultNamespace()
+ generateResClass = always
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/Jvm.kt b/build-logic/convention/src/main/kotlin/Jvm.kt
new file mode 100644
index 0000000..787c0bf
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/Jvm.kt
@@ -0,0 +1,8 @@
+import org.gradle.api.JavaVersion
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+internal object Jvm {
+ const val JDK_VERSION = 21
+ val JVM_TARGET = JvmTarget.JVM_21
+ val JAVA_VERSION = JavaVersion.VERSION_21
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/JvmPlugin.kt b/build-logic/convention/src/main/kotlin/JvmPlugin.kt
new file mode 100644
index 0000000..1c5ff83
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/JvmPlugin.kt
@@ -0,0 +1,17 @@
+import com.motorro.gradle.convention.configureKotlinJvm
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.internal.Actions.with
+
+class JvmPlugin : Plugin {
+ override fun apply(targetProject: Project) {
+ // First base library.
+ targetProject.pluginManager.apply("motorro.baseLibrary")
+
+ with(targetProject) {
+ pluginManager.apply(libs.findPlugin("kotlin_jvm").get().get().pluginId)
+ configureKotlinJvm()
+ }
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/KmpPlugin.kt b/build-logic/convention/src/main/kotlin/KmpPlugin.kt
new file mode 100644
index 0000000..7bfbe43
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/KmpPlugin.kt
@@ -0,0 +1,98 @@
+import com.motorro.gradle.convention.androidLibrary
+import com.motorro.gradle.convention.defaultNamespace
+import com.motorro.gradle.convention.frameworkBaseName
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+
+class KmpPlugin : Plugin {
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // First base library.
+ targetProject.pluginManager.apply("motorro.baseLibrary")
+
+ // Core KMP plugins
+ pluginManager.apply(libs.findPlugin("kotlin_multiplatform").get().get().pluginId)
+ pluginManager.apply(libs.findPlugin("android_kotlin_multiplatform_library").get().get().pluginId)
+
+ extensions.configure {
+ jvmToolchain(Jvm.JDK_VERSION)
+
+ compilerOptions {
+ jvm {
+ compilerOptions.jvmTarget.set(Jvm.JVM_TARGET)
+ }
+ compilerOptions.optIn.addAll(Kotlin.optIn)
+ compilerOptions.freeCompilerArgs.addAll(Kotlin.compilerArgs)
+ }
+
+ androidLibrary {
+ namespace = defaultNamespace()
+ compileSdk = libs.findVersion("androidCompileSdkVersion").get().requiredVersion.toInt()
+ minSdk = libs.findVersion("androidMinSdkVersion").get().requiredVersion.toInt()
+ androidResources.enable = true
+ compilerOptions.jvmTarget.set(Jvm.JVM_TARGET)
+
+ withHostTest {
+ isIncludeAndroidResources = true
+ }
+
+ @Suppress("UnstableApiUsage")
+ optimization {
+ consumerKeepRules.apply {
+ publish = true
+ file("consumer-rules.pro")
+ }
+ }
+ }
+
+ // iOS targets
+ listOf(
+ iosArm64(),
+ iosSimulatorArm64()
+ ).forEach {
+ it.binaries.framework {
+ baseName = project.frameworkBaseName()
+ isStatic = true
+ }
+ }
+
+ js {
+ outputModuleName.set(project.frameworkBaseName())
+ browser()
+ binaries.executable()
+ binaries.library()
+ generateTypeScriptDefinitions()
+ compilerOptions {
+ target.set("es2015")
+ }
+ }
+
+ @OptIn(ExperimentalWasmDsl::class)
+ wasmJs {
+ browser()
+ binaries.executable()
+ binaries.library()
+ useCommonJs()
+ }
+
+ sourceSets.apply {
+ commonMain {
+ dependencies {
+ implementation(libs.findLibrary("kotlin_annotations").get())
+ }
+ }
+ jvmMain.dependencies {
+
+ }
+ commonTest {
+ dependencies {
+ implementation(libs.findLibrary("test_kotlin").get())
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/Kotlin.kt b/build-logic/convention/src/main/kotlin/Kotlin.kt
new file mode 100644
index 0000000..9f65d28
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/Kotlin.kt
@@ -0,0 +1,13 @@
+/**
+ * Kotlin options
+ */
+object Kotlin {
+ val optIn = listOf(
+ "kotlin.RequiresOptIn",
+ "kotlinx.coroutines.ExperimentalCoroutinesApi",
+ "kotlin.time.ExperimentalTime"
+ )
+ val compilerArgs = listOf(
+ "-Xexpect-actual-classes"
+ )
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/PublishingPlugin.kt b/build-logic/convention/src/main/kotlin/PublishingPlugin.kt
new file mode 100644
index 0000000..9c244b9
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/PublishingPlugin.kt
@@ -0,0 +1,100 @@
+import com.motorro.gradle.convention.getProjectProperty
+import com.motorro.gradle.convention.libDesc
+import com.motorro.gradle.convention.libId
+import com.motorro.gradle.convention.libName
+import com.motorro.gradle.convention.libs
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.publish.PublishingExtension
+import org.gradle.api.publish.maven.MavenPublication
+import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven
+import org.gradle.api.tasks.bundling.Jar
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.extra
+import org.gradle.kotlin.dsl.getByType
+import org.gradle.kotlin.dsl.register
+import org.gradle.kotlin.dsl.withType
+import org.gradle.plugins.signing.Sign
+import org.gradle.plugins.signing.SigningExtension
+
+val Project.developerId: String?
+ get() = (findProperty("developerId") as? String) ?: if (rootProject.extra.has("developerId")) rootProject.extra.get("developerId") as String else null
+
+val Project.developerName: String?
+ get() = (findProperty("developerName") as? String) ?: if (rootProject.extra.has("developerName")) rootProject.extra.get("developerName") as String else null
+
+val Project.developerEmail: String?
+ get() = (findProperty("developerEmail") as? String) ?: if (rootProject.extra.has("developerEmail")) rootProject.extra.get("developerEmail") as String else null
+
+val Project.projectScm: String?
+ get() = (findProperty("projectScm") as? String) ?: if (rootProject.extra.has("projectScm")) rootProject.extra.get("projectScm") as String else null
+
+val Project.projectUrl: String?
+ get() = (findProperty("projectUrl") as? String) ?: if (rootProject.extra.has("projectUrl")) rootProject.extra.get("projectUrl") as String else null
+
+val Project.signingKey: String?
+ get() = getProjectProperty("signingKey", "SIGNING_KEY")
+
+val Project.signingPassword: String?
+ get() = getProjectProperty("signingPassword", "SIGNING_PASSWORD")
+
+class PublishingPlugin : Plugin {
+ override fun apply(targetProject: Project) = with(targetProject) {
+ // Apply plugins
+ pluginManager.apply(libs.findPlugin("kotlin_dokka").get().get().pluginId)
+ pluginManager.apply("maven-publish")
+ pluginManager.apply("signing")
+
+ val javadocJar = tasks.register("javadocJar") {
+ val dokkaGenerate = tasks.named("dokkaGenerate")
+ dependsOn(dokkaGenerate)
+ group = "documentation"
+ archiveClassifier.set("javadoc")
+ from(dokkaGenerate)
+ }
+
+ extensions.configure {
+ publications.withType {
+ artifact(javadocJar)
+ pom {
+ name.set(provider {
+ libName ?: libId ?: name.toString()
+ })
+ description.set(provider {
+ libDesc ?: libName ?: ""
+ })
+ url.set(projectUrl)
+ licenses {
+ license {
+ name.set("Apache-2.0")
+ url.set("https://apache.org/licenses/LICENSE-2.0")
+ }
+ }
+ developers {
+ developer {
+ id.set(developerId)
+ name.set(developerName)
+ email.set(developerEmail)
+ }
+ }
+ scm {
+ connection.set(projectScm)
+ developerConnection.set(projectScm)
+ url.set(projectUrl)
+ }
+ }
+ }
+ }
+
+ extensions.configure {
+ useInMemoryPgpKeys(signingKey, signingPassword)
+ val publishing = extensions.getByType()
+ sign(publishing.publications)
+ }
+
+ val signingTasks = tasks.withType()
+ tasks.withType().configureEach {
+ dependsOn(signingTasks)
+ }
+ }
+}
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureCommonAndroid.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureCommonAndroid.kt
new file mode 100644
index 0000000..091b272
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureCommonAndroid.kt
@@ -0,0 +1,25 @@
+package com.motorro.gradle.convention
+
+import com.android.build.api.dsl.CommonExtension
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.dependencies
+
+internal fun Project.configureCommonAndroid(ext: CommonExtension) = ext.apply {
+
+ // Take from module name
+ namespace = defaultNamespace()
+
+ compileSdk = libs.findVersion("androidCompileSdkVersion").get().requiredVersion.toInt()
+
+ configureKotlin()
+
+ dependencies {
+ addDependency("coreLibraryDesugaring", "desugaring")
+ implementation("kotlin_coroutines_core")
+
+ testImplementation("test_kotlin")
+ testImplementation("test_kotlin_coroutines")
+ testImplementation("test_junit")
+ testImplementation("test_mockk")
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureKotlin.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureKotlin.kt
new file mode 100644
index 0000000..77faa32
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureKotlin.kt
@@ -0,0 +1,33 @@
+package com.motorro.gradle.convention
+
+import Jvm
+import Kotlin
+import org.gradle.api.Project
+import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.withType
+import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+internal fun Project.configureKotlin() {
+ tasks.withType().configureEach {
+ compilerOptions {
+ jvmTarget.set(Jvm.JVM_TARGET)
+ compilerOptions.optIn.addAll(Kotlin.optIn)
+ compilerOptions.freeCompilerArgs.addAll(Kotlin.compilerArgs)
+ }
+ }
+}
+
+internal fun Project.configureKotlinJvm() {
+ extensions.configure {
+ sourceCompatibility = Jvm.JAVA_VERSION
+ targetCompatibility = Jvm.JAVA_VERSION
+ }
+
+ extensions.configure {
+ jvmToolchain(Jvm.JDK_VERSION)
+ }
+
+ configureKotlin()
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureMultiplatformAndroidLibrary.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureMultiplatformAndroidLibrary.kt
new file mode 100644
index 0000000..aa5a488
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/configureMultiplatformAndroidLibrary.kt
@@ -0,0 +1,9 @@
+package com.motorro.gradle.convention
+
+import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
+import org.gradle.kotlin.dsl.configure
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+
+internal fun KotlinMultiplatformExtension.androidLibrary(block: KotlinMultiplatformAndroidLibraryTarget.() -> Unit) {
+ configure(block)
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/dependencies.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/dependencies.kt
new file mode 100644
index 0000000..a3b8a45
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/dependencies.kt
@@ -0,0 +1,37 @@
+package com.motorro.gradle.convention
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalog
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.DependencyHandlerScope
+import org.gradle.kotlin.dsl.getByType
+
+val Project.libs get(): VersionCatalog = extensions.getByType().named("libs")
+
+context(project: Project)
+fun DependencyHandlerScope.addDependency(configurationName: String, dependencyName: String) {
+ project.libs.findLibrary(dependencyName).ifPresent {
+ add(configurationName, it)
+ }
+}
+
+context(project: Project)
+fun DependencyHandlerScope.api(dependencyName: String) {
+ project.libs.findLibrary(dependencyName).ifPresent {
+ add("api", it)
+ }
+}
+
+context(project: Project)
+fun DependencyHandlerScope.implementation(dependencyName: String) {
+ project.libs.findLibrary(dependencyName).ifPresent {
+ add("implementation", it)
+ }
+}
+
+context(project: Project)
+fun DependencyHandlerScope.testImplementation(dependencyName: String) {
+ project.libs.findLibrary(dependencyName).ifPresent {
+ add("testImplementation", it)
+ }
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/library.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/library.kt
new file mode 100644
index 0000000..da2cc80
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/library.kt
@@ -0,0 +1,18 @@
+package com.motorro.gradle.convention
+
+import org.gradle.api.Project
+
+/**
+ * Library ID
+ */
+val Project.libId: String get() = findProperty("libId") as? String ?: frameworkBaseName()
+
+/**
+ * Library Name
+ */
+val Project.libName: String get() = findProperty("libName") as? String ?: libId
+
+/**
+ * Library Description
+ */
+val Project.libDesc: String? get() = findProperty("libDesc") as? String
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/naming.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/naming.kt
new file mode 100644
index 0000000..0f3acca
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/naming.kt
@@ -0,0 +1,23 @@
+package com.motorro.gradle.convention
+
+import org.gradle.api.Project
+
+internal fun Project.defaultNamespace(): String {
+ val prefix = "com.motorro.commonstatemachine"
+ val suffix = path
+ .trim(':')
+ .split(':')
+ .joinToString(".") { it.lowercase().replace("-", "_") }
+ .ifBlank { name.lowercase().replace("-", "_") }
+
+ return "$prefix.$suffix"
+}
+
+internal fun Project.frameworkBaseName(): String {
+ val readable = path.trim(':')
+ .split(':')
+ .joinToString("_") { it.replace("-", "_") }
+ .ifBlank { name }
+
+ return readable
+}
\ No newline at end of file
diff --git a/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/properties.kt b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/properties.kt
new file mode 100644
index 0000000..af24aca
--- /dev/null
+++ b/build-logic/convention/src/main/kotlin/com/motorro/gradle/convention/properties.kt
@@ -0,0 +1,57 @@
+package com.motorro.gradle.convention
+
+import org.gradle.api.Project
+import org.gradle.api.provider.Property
+import org.gradle.kotlin.dsl.extra
+import org.gradle.kotlin.dsl.getByType
+import java.io.File
+import java.util.Properties
+import kotlin.reflect.KClass
+
+/**
+ * Gets extension property
+ */
+context(project: Project)
+inline fun KClass.extensionProperty(block: E.() -> Property): T {
+ return project.extensions.getByType().block().get()
+}
+
+/**
+ * Takes extra property
+ */
+inline fun Project.extraProperty(name: String): T? = if (extra.has("versionCode")) extra.get("versionCode") as T else null
+
+/**
+ * Extra or root project extra property
+ */
+inline fun Project.findExtraProperty(name: String): T? = extraProperty(name) ?: rootProject.extraProperty(name)
+
+private fun Project.loadLocalProperties(): Properties {
+ val props = Properties()
+ val localPropsFile = File(rootProject.rootDir, "local.properties")
+ if (localPropsFile.exists()) {
+ localPropsFile.inputStream().use { props.load(it) }
+ val signingConfigPath = props.getProperty("SIGNING_CONFIG")
+ if (!signingConfigPath.isNullOrBlank()) {
+ val signingConfigFile = File(signingConfigPath)
+ if (signingConfigFile.exists()) {
+ signingConfigFile.inputStream().use { props.load(it) }
+ }
+ }
+ }
+ return props
+}
+
+fun Project.getProjectProperty(propertyName: String, envName: String): String? {
+ val fromProperty = findProperty(propertyName) as? String
+ if (!fromProperty.isNullOrBlank()) return fromProperty
+
+ val localProps = loadLocalProperties()
+ val fromLocalProps = localProps.getProperty(propertyName)
+ if (!fromLocalProps.isNullOrBlank()) return fromLocalProps
+
+ val fromEnv = System.getenv(envName)
+ if (!fromEnv.isNullOrBlank()) return fromEnv
+
+ return null
+}
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
new file mode 100644
index 0000000..b11df90
--- /dev/null
+++ b/build-logic/settings.gradle.kts
@@ -0,0 +1,23 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+ versionCatalogs {
+ create("libs") {
+ from(files("../gradle/libs.versions.toml"))
+ }
+ }
+}
+
+rootProject.name = "build-logic"
+include(":convention")
diff --git a/build.gradle.kts b/build.gradle.kts
index 8928362..aa80982 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -13,9 +13,9 @@
@file:Suppress("unused")
-import groovy.lang.Closure
+import com.motorro.gradle.convention.buildVersionCode
+import com.motorro.gradle.convention.buildVersionName
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
alias(libs.plugins.android.app) apply false
@@ -26,20 +26,14 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.google.ksp) apply false
alias(libs.plugins.compose) apply false
+ alias(libs.plugins.compose.multiplatform) apply false
alias(libs.plugins.kotlin.dokka) apply false
alias(libs.plugins.hilt) apply false
+ alias(libs.plugins.koin) apply false
alias(libs.plugins.nexus.publish)
alias(libs.plugins.git)
}
-apply {
- from("$rootDir/gradle/versioning.gradle")
- from("$rootDir/gradle/maven-publish-config.gradle")
-}
-
-private val buildVersionName: Closure by ext
-private val buildVersionCode: Closure by ext
-
version = buildVersionName()
group = "com.motorro.commonstatemachine"
description = "Multiplatform state machine for mobile applications"
@@ -49,27 +43,6 @@ allprojects {
val versionName by extra(buildVersionName())
val versionCode by extra(buildVersionCode())
- val androidBuildToolsVersion by extra("35.0.0")
- val androidMinSdkVersion by extra(24)
- val androidTargetSdkVersion by extra(37)
- val androidCompileSdkVersion by extra(37)
-
- val developerId by extra("motorro")
- val developerName by extra("Nikolai Kotchetkov")
- val developerEmail by extra("motorro@gmail.com")
-
- val projectScm by extra("https://github.com/motorro/CommonStateMachine.git")
- val projectUrl by extra("https://github.com/motorro/CommonStateMachine")
-
- tasks.withType().configureEach {
- compilerOptions {
- freeCompilerArgs.addAll(listOf(
- "-opt-in=kotlin.RequiresOptIn",
- "-Xexpect-actual-classes"
- ))
- }
- }
-
tasks.withType().configureEach {
forkEvery = 100
testLogging {
@@ -116,9 +89,9 @@ tasks.register("runLceExampleUnitTests") {
}
tasks.register("runWelcomeExampleUnitTests") {
- dependsOn(":examples:welcome:commonregister:allTests")
+ dependsOn(":examples:welcome:register:allTests")
dependsOn(":examples:welcome:login:testDebugUnitTest")
- dependsOn(":examples:welcome:welcome:testDebugUnitTest")
+ dependsOn(":examples:welcome:app:testDebugUnitTest")
description = "Run unit tests for welcome app."
}
@@ -129,7 +102,7 @@ tasks.register("runTimerExampleUnitTests") {
tasks.register("runDiExampleUnitTests") {
dependsOn(":examples:di:login:testDebugUnitTest")
- dependsOn(":examples:di:social:testDebugUnitTest")
+ dependsOn(":examples:di:app:testLoginDebugUnitTest")
description = "Run unit tests for di app."
}
@@ -139,6 +112,12 @@ tasks.register("runBooksExampleUnitTests") {
description = "Run unit tests for books app."
}
+tasks.register("runSkillsExampleUnitTests") {
+ dependsOn(":examples:skills:app:testDebugUnitTest")
+ dependsOn(":examples:skills:auth:implementation:allTests")
+ description = "Run unit tests for skills."
+}
+
tasks.register("displayVersion") {
description = "Display application version name"
doLast {
@@ -156,7 +135,8 @@ tasks.register("runUnitTests") {
"runWelcomeExampleUnitTests",
"runTimerExampleUnitTests",
"runDiExampleUnitTests",
- "runBooksExampleUnitTests"
+ "runBooksExampleUnitTests",
+ "runSkillsExampleUnitTests"
)
group = "verification"
description = "Run unit tests for all modules."
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
new file mode 100644
index 0000000..a1e8f84
--- /dev/null
+++ b/buildSrc/build.gradle.kts
@@ -0,0 +1,9 @@
+plugins {
+ `kotlin-dsl`
+}
+
+repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+}
diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts
new file mode 100644
index 0000000..6060510
--- /dev/null
+++ b/buildSrc/settings.gradle.kts
@@ -0,0 +1,14 @@
+dependencyResolutionManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+ versionCatalogs {
+ create("libs") {
+ from(files("../gradle/libs.versions.toml"))
+ }
+ }
+}
+
+rootProject.name = "buildSrc"
diff --git a/buildSrc/src/main/kotlin/com/motorro/gradle/convention/Versioning.kt b/buildSrc/src/main/kotlin/com/motorro/gradle/convention/Versioning.kt
new file mode 100644
index 0000000..07d8f65
--- /dev/null
+++ b/buildSrc/src/main/kotlin/com/motorro/gradle/convention/Versioning.kt
@@ -0,0 +1,134 @@
+package com.motorro.gradle.convention
+
+import org.gradle.api.GradleException
+import org.gradle.api.Project
+
+val platformVersionCodeAdditives: Map = mapOf(
+ "armeabi" to 1,
+ "armeabi-v7a" to 2,
+ "arm64-v8a" to 3,
+ "x86" to 4,
+ "x86_64" to 5,
+ "mips" to 6,
+ "mips64" to 7
+)
+
+private fun getGitDescribe(project: Project): String? {
+ val grgit = project.findProperty("grgit") ?: project.rootProject.findProperty("grgit")
+ if (grgit != null) {
+ try {
+ val describeMethod = grgit.javaClass.getMethod("describe", Map::class.java)
+ val result = describeMethod.invoke(grgit, mapOf("match" to listOf("v[0-9]*"))) as? String
+ if (!result.isNullOrBlank()) return result
+ } catch (e: Exception) {
+ project.logger.info("Failed to invoke grgit.describe: {}", e.message)
+ }
+ }
+ return try {
+ val process = ProcessBuilder("git", "describe", "--match", "v[0-9]*")
+ .directory(project.rootDir)
+ .redirectError(ProcessBuilder.Redirect.DISCARD)
+ .start()
+ val output = process.inputStream.bufferedReader().readText().trim()
+ if (process.waitFor() == 0 && output.isNotEmpty()) output else null
+ } catch (e: Exception) {
+ null
+ }
+}
+
+private fun getGitBranchName(project: Project): String? {
+ val grgit = project.findProperty("grgit") ?: project.rootProject.findProperty("grgit")
+ if (grgit != null) {
+ try {
+ val branchProp = grgit.javaClass.getMethod("getBranch").invoke(grgit)
+ val currentMethod = branchProp?.javaClass?.getMethod("current")
+ val currentBranch = currentMethod?.invoke(branchProp)
+ val nameMethod = currentBranch?.javaClass?.getMethod("getName")
+ val name = nameMethod?.invoke(currentBranch) as? String
+ if (!name.isNullOrBlank()) return name
+ } catch (e: Exception) {
+ project.logger.info("Failed to invoke grgit.branch: {}", e.message)
+ }
+ }
+ return try {
+ val process = ProcessBuilder("git", "rev-parse", "--abbrev-ref", "HEAD")
+ .directory(project.rootDir)
+ .redirectError(ProcessBuilder.Redirect.DISCARD)
+ .start()
+ val output = process.inputStream.bufferedReader().readText().trim()
+ if (process.waitFor() == 0 && output.isNotEmpty() && output != "HEAD") output else null
+ } catch (e: Exception) {
+ null
+ }
+}
+
+/**
+ * Builds app version using latest repository tag
+ * Tag should be a semantic version of major/minor at least
+ * Function takes number of commits since last tag and uses it to calculate patch number
+ * - If patch is omitted in tag - uses number of commits
+ * - If patch version set in tag - pluses number of commits to patch number
+ * @return Semantic version string
+ */
+fun Project.buildVersionName(): String {
+ val versionRegexp = Regex("""^v?(\d+)\.(\d+)\.?(\d*)-?(\d*)""")
+
+ val fromEnv = (findProperty("versionName") as? String) ?: System.getenv("VERSION_NAME")
+ if (!fromEnv.isNullOrBlank() && versionRegexp.containsMatchIn(fromEnv)) {
+ logger.info("Version from ENV: {}", fromEnv)
+ return fromEnv
+ }
+
+ val described = getGitDescribe(this)
+ val matchResult = if (described != null) versionRegexp.find(described) else null
+
+ val (major, minor, patch, changes) = if (matchResult == null) {
+ logger.info("Git description does not have any version info. Make sure you have a semver tag (v1.2) or (v1.2.3) in a repository.")
+ logger.info("Using `v0.0.1` for this build")
+ listOf(0, 0, 1, 0)
+ } else {
+ val groups = matchResult.groupValues
+ val maj = groups[1].toIntOrNull() ?: 0
+ val min = groups[2].toIntOrNull() ?: 0
+ val pat = groups[3].takeIf { it.isNotEmpty() }?.toIntOrNull() ?: 0
+ val cha = groups[4].takeIf { it.isNotEmpty() }?.toIntOrNull() ?: 0
+ listOf(maj, min, pat, cha)
+ }
+
+ val fromGit = "$major.$minor.${patch + changes}"
+ logger.info("Version evaluated using Git: {}", fromGit)
+ return fromGit
+}
+
+/**
+ * Builds version code using [buildVersionName]
+ * @return Integer version code
+ */
+fun Project.buildVersionCode(versionName: String = buildVersionName()): Int {
+ /*
+ Max version code (INT32) is 214 74 836 47
+ Spaces denote positions of:
+ - major
+ - minor
+ - build
+ - build variant
+ */
+ val parts = versionName.split('.').mapNotNull { it.toIntOrNull() }
+ val major = parts.getOrElse(0) { 0 }
+ val minor = parts.getOrElse(1) { 0 }
+ val patch = parts.getOrElse(2) { 0 }
+
+ if (major > 214) {
+ throw GradleException("Major version exhausted: version greater than 214 not supported")
+ }
+ if (minor > 99) {
+ throw GradleException("Minor version exhausted: version greater than 99 not supported")
+ }
+ if (patch > 999) {
+ throw GradleException("Patch version exhausted: version greater than 999 not supported")
+ }
+
+ val version = major * 10000000 + minor * 100000 + patch * 100
+ logger.info("Version code evaluated using Git: {}", version)
+ return version
+}
diff --git a/commonflow/compose/api/android/commonflow-compose.api b/commonflow/compose/api/android/commonflow-compose.api
new file mode 100644
index 0000000..590424d
--- /dev/null
+++ b/commonflow/compose/api/android/commonflow-compose.api
@@ -0,0 +1,8 @@
+public abstract interface class com/motorro/commonstatemachine/flow/compose/CommonFlowUiApi {
+ public abstract fun Screen (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+}
+
+public final class com/motorro/commonstatemachine/flow/compose/CommonFlowUiApi$ComposeDefaultImpls {
+ public static final fun Screen$default (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;Landroidx/compose/ui/Modifier;Lcom/motorro/commonstatemachine/flow/compose/CommonFlowUiApi;Landroidx/compose/runtime/Composer;II)V
+}
+
diff --git a/commonflow/compose/api/commonflow-compose.klib.api b/commonflow/compose/api/commonflow-compose.klib.api
index 1791cb6..65c9247 100644
--- a/commonflow/compose/api/commonflow-compose.klib.api
+++ b/commonflow/compose/api/commonflow-compose.klib.api
@@ -13,3 +13,15 @@ abstract interface <#A: kotlin/Any, #B: kotlin/Any> com.motorro.commonstatemachi
final fun Screen$default(#B, kotlin/Function1<#A, kotlin/Unit>, androidx.compose.ui/Modifier?, com.motorro.commonstatemachine.flow.compose/CommonFlowUiApi<#A, #B>, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.motorro.commonstatemachine.flow.compose/CommonFlowUiApi.ComposeDefaultImpls.Screen$default|Screen$default#static(2:1;kotlin.Function1<2:0,kotlin.Unit>;androidx.compose.ui.Modifier?;com.motorro.commonstatemachine.flow.compose.CommonFlowUiApi<2:0,2:1>;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
}
}
+
+final val com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_array$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_array$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_array$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_drawable$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_drawable$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_drawable$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_font$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_font$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_font$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_plurals$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_plurals$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_plurals$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_string$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_string$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_string$stableprop[0]
+
+final fun com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_array$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_array$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_array$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_drawable$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_drawable$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_drawable$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_font$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_font$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_font$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_plurals$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_plurals$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_plurals$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_string$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_compose/com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_string$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_compose_Res_string$stableprop_getter(){}[0]
diff --git a/commonflow/compose/build.gradle.kts b/commonflow/compose/build.gradle.kts
index 8f67655..034fada 100644
--- a/commonflow/compose/build.gradle.kts
+++ b/commonflow/compose/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
+
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,153 +13,23 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-@file:OptIn(ExperimentalWasmDsl::class, ExperimentalAbiValidation::class)
-
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
-
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
- alias(libs.plugins.compose)
- alias(libs.plugins.composeMultiplatform)
- alias(libs.plugins.kotlin.dokka)
- id("maven-publish")
- id("signing")
+ alias(libs.plugins.motorro.cmp)
+ alias(libs.plugins.motorro.publishing)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = rootProject.group
-version = rootProject.version
-
-println("== Project version: $versionName ==")
-
kotlin {
+ @OptIn(ExperimentalAbiValidation::class)
abiValidation {
}
- jvmToolchain(21)
-
- jvm()
- android {
- namespace = "com.motorro.commonstatemachine.commonflow.compose"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- withHostTest {
- isIncludeAndroidResources = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- wasmJs {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- listOf(
- iosArm64(),
- iosSimulatorArm64()
- ).forEach {
- it.binaries.framework {
- baseName = "commonflow-compose"
- isStatic = true
- }
- }
-
sourceSets {
commonMain.dependencies {
api(project(":commonstatemachine"))
api(project(":commonflow:commonflow-data"))
- api(libs.composeMultiplatform.runtime)
- api(libs.composeMultiplatform.foundation)
- }
- }
-}
-val javadocJar by tasks.registering(Jar::class) {
- dependsOn(tasks.dokkaGenerate)
- group = "documentation"
- archiveClassifier.set("javadoc")
- from(tasks.dokkaGenerate)
-}
-
-val libId = "commonflow-compose"
-val libName = "commonflow-compose"
-val libDesc = "Common compose flow for modularized state machines"
-val projectUrl: String by project.extra
-val projectScm: String by project.extra
-val ossrhUsername: String? by rootProject.extra
-val ossrhPassword: String? by rootProject.extra
-val developerId: String by project.extra
-val developerName: String by project.extra
-val developerEmail: String by project.extra
-val signingKey: String? by rootProject.extra
-val signingPassword: String? by rootProject.extra
-
-publishing {
- publications.withType {
- artifact(javadocJar)
- pom {
- name.set(libName)
- description.set(libDesc)
- url.set(projectUrl)
- licenses {
- license {
- name.set("Apache-2.0")
- url.set("https://apache.org/licenses/LICENSE-2.0")
- }
- }
- developers {
- developer {
- id.set(developerId)
- name.set(developerName)
- email.set(developerEmail)
- }
- }
- scm {
- connection.set(projectScm)
- developerConnection.set(projectScm)
- url.set(projectUrl)
- }
+ api(libs.compose.multiplatform.runtime)
+ api(libs.compose.multiplatform.foundation)
}
}
}
-
-signing {
- useInMemoryPgpKeys(signingKey, signingPassword)
- sign(publishing.publications)
-}
-
-val signingTasks = tasks.withType()
-tasks.withType().configureEach {
- dependsOn(signingTasks)
-}
\ No newline at end of file
diff --git a/commonflow/compose/consumer-rules.pro b/commonflow/compose/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/commonflow/compose/gradle.properties b/commonflow/compose/gradle.properties
new file mode 100644
index 0000000..f3d63af
--- /dev/null
+++ b/commonflow/compose/gradle.properties
@@ -0,0 +1,16 @@
+#
+# Copyright 2022 Nikolai Kotchetkov.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# 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.
+#
+#Project
+libId="commonflow-compose"
+libName="commonflow-compose"
+libDesc="Common compose flow for modularised state machines"
diff --git a/commonflow/data/api/android/commonflow-data.api b/commonflow/data/api/android/commonflow-data.api
new file mode 100644
index 0000000..5ff04bb
--- /dev/null
+++ b/commonflow/data/api/android/commonflow-data.api
@@ -0,0 +1,14 @@
+public abstract interface class com/motorro/commonstatemachine/flow/data/CommonFlowDataApi {
+ public fun getBackGesture ()Ljava/lang/Object;
+ public abstract fun getDefaultUiState ()Ljava/lang/Object;
+ public abstract fun init (Lcom/motorro/commonstatemachine/flow/data/CommonFlowHost;Ljava/lang/Object;)Lcom/motorro/commonstatemachine/CommonMachineState;
+}
+
+public final class com/motorro/commonstatemachine/flow/data/CommonFlowDataApi$DefaultImpls {
+ public static fun getBackGesture (Lcom/motorro/commonstatemachine/flow/data/CommonFlowDataApi;)Ljava/lang/Object;
+}
+
+public abstract interface class com/motorro/commonstatemachine/flow/data/CommonFlowHost {
+ public abstract fun onComplete (Ljava/lang/Object;)V
+}
+
diff --git a/commonflow/data/build.gradle.kts b/commonflow/data/build.gradle.kts
index cdf3d9c..bb764cd 100644
--- a/commonflow/data/build.gradle.kts
+++ b/commonflow/data/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
+
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,149 +13,20 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-@file:OptIn(ExperimentalWasmDsl::class, ExperimentalAbiValidation::class)
-
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
-
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
- alias(libs.plugins.kotlin.dokka)
- id("maven-publish")
- id("signing")
+ alias(libs.plugins.motorro.kmp)
+ alias(libs.plugins.motorro.publishing)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = rootProject.group
-version = rootProject.version
-
-println("== Project version: $versionName ==")
-
kotlin {
+ @OptIn(ExperimentalAbiValidation::class)
abiValidation {
}
- jvmToolchain(21)
-
- jvm()
-
- android {
- namespace = "com.motorro.commonstatemachine.commonflow.data"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- withHostTest {
- isIncludeAndroidResources = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- wasmJs {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- listOf(
- iosArm64(),
- iosSimulatorArm64()
- ).forEach {
- it.binaries.framework {
- baseName = "commonflow-data"
- isStatic = true
- }
- }
-
sourceSets {
commonMain.dependencies {
api(project(":commonstatemachine"))
}
}
}
-val javadocJar by tasks.registering(Jar::class) {
- dependsOn(tasks.dokkaGenerate)
- group = "documentation"
- archiveClassifier.set("javadoc")
- from(tasks.dokkaGenerate)
-}
-
-val libId = "commonflow-data"
-val libName = "commonflow-data"
-val libDesc = "Common data flow for modularized state machines"
-val projectUrl: String by project.extra
-val projectScm: String by project.extra
-val ossrhUsername: String? by rootProject.extra
-val ossrhPassword: String? by rootProject.extra
-val developerId: String by project.extra
-val developerName: String by project.extra
-val developerEmail: String by project.extra
-val signingKey: String? by rootProject.extra
-val signingPassword: String? by rootProject.extra
-
-publishing {
- publications.withType {
- artifact(javadocJar)
- pom {
- name.set(libName)
- description.set(libDesc)
- url.set(projectUrl)
- licenses {
- license {
- name.set("Apache-2.0")
- url.set("https://apache.org/licenses/LICENSE-2.0")
- }
- }
- developers {
- developer {
- id.set(developerId)
- name.set(developerName)
- email.set(developerEmail)
- }
- }
- scm {
- connection.set(projectScm)
- developerConnection.set(projectScm)
- url.set(projectUrl)
- }
- }
- }
-}
-
-signing {
- useInMemoryPgpKeys(signingKey, signingPassword)
- sign(publishing.publications)
-}
-
-val signingTasks = tasks.withType()
-tasks.withType().configureEach {
- dependsOn(signingTasks)
-}
\ No newline at end of file
diff --git a/commonflow/data/consumer-rules.pro b/commonflow/data/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/commonflow/data/gradle.properties b/commonflow/data/gradle.properties
new file mode 100644
index 0000000..a0125c2
--- /dev/null
+++ b/commonflow/data/gradle.properties
@@ -0,0 +1,16 @@
+#
+# Copyright 2022 Nikolai Kotchetkov.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# 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.
+#
+#Project
+libId="commonflow-data"
+libName="commonflow-data"
+libDesc="Common data flow for modularised state machines"
diff --git a/commonflow/viewmodel/api/android/commonflow-viewmodel.api b/commonflow/viewmodel/api/android/commonflow-viewmodel.api
new file mode 100644
index 0000000..b3a0bda
--- /dev/null
+++ b/commonflow/viewmodel/api/android/commonflow-viewmodel.api
@@ -0,0 +1,82 @@
+public final class com/motorro/commonstatemachine/flow/viewmodel/CommonFlowCompositionKt {
+ public static final fun CommonFlowComposition (Lcom/motorro/commonstatemachine/flow/viewmodel/CommonFlowViewModel;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function4;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;II)V
+}
+
+public class com/motorro/commonstatemachine/flow/viewmodel/CommonFlowViewModel : androidx/lifecycle/ViewModel {
+ public static final field $stable I
+ public static final field CLOSABLE_KEY Ljava/lang/String;
+ public static final field Companion Lcom/motorro/commonstatemachine/flow/viewmodel/CommonFlowViewModel$Companion;
+ public fun (Lcom/motorro/commonstatemachine/flow/data/CommonFlowDataApi;Ljava/lang/Object;[Ljava/lang/AutoCloseable;)V
+ public final fun getUiState ()Lkotlinx/coroutines/flow/StateFlow;
+ public final fun process (Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture;)V
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/CommonFlowViewModel$Companion {
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/ComposableSingletons$CommonFlowCompositionKt {
+ public static final field INSTANCE Lcom/motorro/commonstatemachine/flow/viewmodel/ComposableSingletons$CommonFlowCompositionKt;
+ public fun ()V
+ public final fun getLambda$1100526547$com_motorro_commonstatemachine_commonflow_viewmodel ()Lkotlin/jvm/functions/Function4;
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/ViewModelComposition_androidKt {
+ public static final fun DefaultNavigationBackHandler (ZLkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)V
+}
+
+public abstract class com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture {
+ public static final field $stable I
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture$Back : com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture {
+ public static final field $stable I
+ public static final field INSTANCE Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture$Back;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture$Child : com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture {
+ public static final field $stable I
+ public fun (Ljava/lang/Object;)V
+ public final fun component1 ()Ljava/lang/Object;
+ public final fun copy (Ljava/lang/Object;)Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture$Child;
+ public static synthetic fun copy$default (Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture$Child;Ljava/lang/Object;ILjava/lang/Object;)Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowGesture$Child;
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getChild ()Ljava/lang/Object;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public abstract class com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState {
+ public static final field $stable I
+ public abstract fun getBackHandlerEnabled ()Z
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Child : com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState {
+ public static final field $stable I
+ public fun (Ljava/lang/Object;Z)V
+ public final fun component1 ()Ljava/lang/Object;
+ public final fun component2 ()Z
+ public final fun copy (Ljava/lang/Object;Z)Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Child;
+ public static synthetic fun copy$default (Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Child;Ljava/lang/Object;ZILjava/lang/Object;)Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Child;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getBackHandlerEnabled ()Z
+ public final fun getChild ()Ljava/lang/Object;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
+public final class com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Terminated : com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState {
+ public static final field $stable I
+ public fun (Ljava/lang/Object;)V
+ public final fun component1 ()Ljava/lang/Object;
+ public final fun copy (Ljava/lang/Object;)Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Terminated;
+ public static synthetic fun copy$default (Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Terminated;Ljava/lang/Object;ILjava/lang/Object;)Lcom/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState$Terminated;
+ public fun equals (Ljava/lang/Object;)Z
+ public fun getBackHandlerEnabled ()Z
+ public final fun getResult ()Ljava/lang/Object;
+ public fun hashCode ()I
+ public fun toString ()Ljava/lang/String;
+}
+
diff --git a/commonflow/viewmodel/api/commonflow-viewmodel.klib.api b/commonflow/viewmodel/api/commonflow-viewmodel.klib.api
index 73d8160..ffc430b 100644
--- a/commonflow/viewmodel/api/commonflow-viewmodel.klib.api
+++ b/commonflow/viewmodel/api/commonflow-viewmodel.klib.api
@@ -41,15 +41,15 @@ sealed class <#A: out kotlin/Any, #B: out kotlin/Any?> com.motorro.commonstatema
}
final class <#A1: out kotlin/Any?> Terminated : com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState { // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated|null[0]
- constructor (#A1?) // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.|(1:0?){}[0]
+ constructor (#A1) // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.|(1:0){}[0]
final val backHandlerEnabled // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.backHandlerEnabled|{}backHandlerEnabled[0]
final fun (): kotlin/Boolean // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.backHandlerEnabled.|(){}[0]
final val result // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.result|{}result[0]
- final fun (): #A1? // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.result.|(){}[0]
+ final fun (): #A1 // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.result.|(){}[0]
- final fun component1(): #A1? // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.component1|component1(){}[0]
- final fun copy(#A1? = ...): com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated<#A1> // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.copy|copy(1:0?){}[0]
+ final fun component1(): #A1 // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.component1|component1(){}[0]
+ final fun copy(#A1 = ...): com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated<#A1> // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.copy|copy(1:0){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // com.motorro.commonstatemachine.flow.viewmodel.data/BaseFlowUiState.Terminated.toString|toString(){}[0]
@@ -77,6 +77,11 @@ sealed class <#A: out kotlin/Any> com.motorro.commonstatemachine.flow.viewmodel.
}
}
+final val com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_array$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_array$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_array$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_drawable$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_drawable$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_drawable$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_font$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_font$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_font$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_plurals$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_plurals$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_plurals$stableprop[0]
+final val com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_string$stableprop // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_string$stableprop|#static{}com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_string$stableprop[0]
final val com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture$stableprop // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture$stableprop|#static{}com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture$stableprop[0]
final val com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Back$stableprop // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Back$stableprop|#static{}com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Back$stableprop[0]
final val com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Child$stableprop // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Child$stableprop|#static{}com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Child$stableprop[0]
@@ -85,7 +90,12 @@ final val com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commons
final val com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowUiState_Terminated$stableprop // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowUiState_Terminated$stableprop|#static{}com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowUiState_Terminated$stableprop[0]
final val com.motorro.commonstatemachine.flow.viewmodel/com_motorro_commonstatemachine_flow_viewmodel_CommonFlowViewModel$stableprop // com.motorro.commonstatemachine.flow.viewmodel/com_motorro_commonstatemachine_flow_viewmodel_CommonFlowViewModel$stableprop|#static{}com_motorro_commonstatemachine_flow_viewmodel_CommonFlowViewModel$stableprop[0]
-final fun <#A: kotlin/Any, #B: kotlin/Any, #C: kotlin/Any?> com.motorro.commonstatemachine.flow.viewmodel/CommonFlowComposition(com.motorro.commonstatemachine.flow.viewmodel/CommonFlowViewModel<#A, #B, *, #C>, kotlin/Function4, androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>?, kotlin/Function4<#B, kotlin/Function1<#A, kotlin/Unit>, androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>, kotlin/Function1<#C?, kotlin/Unit>, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.motorro.commonstatemachine.flow.viewmodel/CommonFlowComposition|CommonFlowComposition(com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel<0:0,0:1,*,0:2>;kotlin.Function4,androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>?;kotlin.Function4<0:1,kotlin.Function1<0:0,kotlin.Unit>,androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>;kotlin.Function1<0:2?,kotlin.Unit>;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){0§;1§;2§}[0]
+final fun <#A: kotlin/Any, #B: kotlin/Any, #C: kotlin/Any?> com.motorro.commonstatemachine.flow.viewmodel/CommonFlowComposition(com.motorro.commonstatemachine.flow.viewmodel/CommonFlowViewModel<#A, #B, *, #C>, kotlin/Function4, androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>?, kotlin/Function4<#B, kotlin/Function1<#A, kotlin/Unit>, androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>, kotlin/Function1<#C, kotlin/Unit>, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.motorro.commonstatemachine.flow.viewmodel/CommonFlowComposition|CommonFlowComposition(com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel<0:0,0:1,*,0:2>;kotlin.Function4,androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>?;kotlin.Function4<0:1,kotlin.Function1<0:0,kotlin.Unit>,androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>;kotlin.Function1<0:2,kotlin.Unit>;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){0§;1§;2§}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_array$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_array$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_array$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_drawable$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_drawable$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_drawable$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_font$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_font$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_font$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_plurals$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_plurals$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_plurals$stableprop_getter(){}[0]
+final fun com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_string$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.commonflow.commonflow_viewmodel/com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_string$stableprop_getter|com_motorro_commonstatemachine_commonflow_commonflow_viewmodel_Res_string$stableprop_getter(){}[0]
final fun com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture$stableprop_getter|com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture$stableprop_getter(){}[0]
final fun com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Back$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Back$stableprop_getter|com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Back$stableprop_getter(){}[0]
final fun com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Child$stableprop_getter(): kotlin/Int // com.motorro.commonstatemachine.flow.viewmodel.data/com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Child$stableprop_getter|com_motorro_commonstatemachine_flow_viewmodel_data_BaseFlowGesture_Child$stableprop_getter(){}[0]
diff --git a/commonflow/viewmodel/build.gradle.kts b/commonflow/viewmodel/build.gradle.kts
index 08d7dc3..7e434ff 100644
--- a/commonflow/viewmodel/build.gradle.kts
+++ b/commonflow/viewmodel/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
+
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,96 +13,24 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-@file:OptIn(ExperimentalWasmDsl::class, ExperimentalAbiValidation::class)
-
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
-
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
- alias(libs.plugins.compose)
- alias(libs.plugins.composeMultiplatform)
- alias(libs.plugins.kotlin.dokka)
- id("maven-publish")
- id("signing")
+ alias(libs.plugins.motorro.cmp)
+ alias(libs.plugins.motorro.publishing)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = rootProject.group
-version = rootProject.version
-
-println("== Project version: $versionName ==")
-
kotlin {
+ @OptIn(ExperimentalAbiValidation::class)
abiValidation {
}
- jvmToolchain(21)
-
- jvm()
- android {
- namespace = "com.motorro.commonstatemachine.commonflow.viewmodel"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- withHostTest {
- isIncludeAndroidResources = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- wasmJs {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- listOf(
- iosArm64(),
- iosSimulatorArm64()
- ).forEach {
- it.binaries.framework {
- baseName = "commonflow-viewmodel"
- isStatic = true
- }
- }
-
sourceSets {
commonMain.dependencies {
api(project(":commonstatemachine"))
api(project(":coroutines"))
api(project(":commonflow:commonflow-compose"))
- api(libs.composeMultiplatform.viewmodel)
- implementation(libs.composeMultiplatform.lifecycle)
+ api(libs.compose.multiplatform.viewmodel)
+ implementation(libs.compose.multiplatform.lifecycle)
}
commonTest.dependencies {
implementation(libs.test.kotlin)
@@ -114,61 +44,3 @@ kotlin {
}
}
}
-val javadocJar by tasks.registering(Jar::class) {
- dependsOn(tasks.dokkaGenerate)
- group = "documentation"
- archiveClassifier.set("javadoc")
- from(tasks.dokkaGenerate)
-}
-
-val libId = "commonflow-viewmodel"
-val libName = "commonflow-viewmodel"
-val libDesc = "Common view components to wrap standard flow"
-val projectUrl: String by project.extra
-val projectScm: String by project.extra
-val ossrhUsername: String? by rootProject.extra
-val ossrhPassword: String? by rootProject.extra
-val developerId: String by project.extra
-val developerName: String by project.extra
-val developerEmail: String by project.extra
-val signingKey: String? by rootProject.extra
-val signingPassword: String? by rootProject.extra
-
-publishing {
- publications.withType {
- artifact(javadocJar)
- pom {
- name.set(libName)
- description.set(libDesc)
- url.set(projectUrl)
- licenses {
- license {
- name.set("Apache-2.0")
- url.set("https://apache.org/licenses/LICENSE-2.0")
- }
- }
- developers {
- developer {
- id.set(developerId)
- name.set(developerName)
- email.set(developerEmail)
- }
- }
- scm {
- connection.set(projectScm)
- developerConnection.set(projectScm)
- url.set(projectUrl)
- }
- }
- }
-}
-
-signing {
- useInMemoryPgpKeys(signingKey, signingPassword)
- sign(publishing.publications)
-}
-
-val signingTasks = tasks.withType()
-tasks.withType().configureEach {
- dependsOn(signingTasks)
-}
\ No newline at end of file
diff --git a/commonflow/viewmodel/consumer-rules.pro b/commonflow/viewmodel/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/commonflow/viewmodel/gradle.properties b/commonflow/viewmodel/gradle.properties
new file mode 100644
index 0000000..3ed4780
--- /dev/null
+++ b/commonflow/viewmodel/gradle.properties
@@ -0,0 +1,16 @@
+#
+# Copyright 2022 Nikolai Kotchetkov.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# 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.
+#
+#Project
+libId="commonflow-viewmodel"
+libName="commonflow-viewmodel"
+libDesc="Common view components to wrap standard flow"
diff --git a/commonflow/viewmodel/src/androidMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/ViewModelComposition_android.kt b/commonflow/viewmodel/src/androidMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/ViewModelComposition_android.kt
index 7de8d39..0b39a94 100644
--- a/commonflow/viewmodel/src/androidMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/ViewModelComposition_android.kt
+++ b/commonflow/viewmodel/src/androidMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/ViewModelComposition_android.kt
@@ -27,6 +27,14 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider.Factory
import androidx.lifecycle.viewmodel.CreationExtras
+/**
+ * Default navigation back handler using [BackHandler].
+ */
+@Composable
+fun DefaultNavigationBackHandler(enabled: Boolean, onBack: () -> Unit) {
+ BackHandler(enabled = enabled) { onBack() }
+}
+
/**
* Builds state machine composition
* Ensure that [AppCompatActivity] has correct view model factory
@@ -40,9 +48,7 @@ inline fun > Com
noinline extrasProducer: (() -> CreationExtras)? = null,
noinline factoryProducer: (() -> Factory)? = null,
noinline setResult: (R?) -> Unit = { },
- noinline navigationBackHandler: @Composable (Boolean, () -> Unit) -> Unit = { enabled, onBack ->
- BackHandler(enabled = enabled) { onBack() }
- },
+ noinline navigationBackHandler: @Composable (Boolean, () -> Unit) -> Unit = ::DefaultNavigationBackHandler,
noinline content: @Composable (U, (G) -> Unit) -> Unit
) {
setContent {
@@ -77,9 +83,7 @@ inline fun > Fra
noinline onFinish: (R?) -> Unit,
noinline extrasProducer: (() -> CreationExtras)? = null,
noinline factoryProducer: (() -> Factory)? = null,
- noinline navigationBackHandler: @Composable (Boolean, () -> Unit) -> Unit = { enabled, onBack ->
- BackHandler(enabled = enabled) { onBack() }
- },
+ noinline navigationBackHandler: @Composable (Boolean, () -> Unit) -> Unit = ::DefaultNavigationBackHandler,
noinline content: @Composable (U, (G) -> Unit) -> Unit
): View = ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
diff --git a/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/CommonFlowComposition.kt b/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/CommonFlowComposition.kt
index 0a6604f..a9d0bb1 100644
--- a/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/CommonFlowComposition.kt
+++ b/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/CommonFlowComposition.kt
@@ -26,7 +26,7 @@ fun < G: Any, U: Any, R> CommonFlowComposition(
viewModel: CommonFlowViewModel,
navigationBackHandler: @Composable (enabled: Boolean, onBack: () -> Unit) -> Unit = { _, _ -> },
content: @Composable (U, (G) -> Unit) -> Unit,
- finish: (R?) -> Unit
+ finish: (R) -> Unit
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val process = remember<(G) -> Unit> {
diff --git a/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState.kt b/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState.kt
index eda52c1..6095bdb 100644
--- a/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState.kt
+++ b/commonflow/viewmodel/src/commonMain/kotlin/com/motorro/commonstatemachine/flow/viewmodel/data/BaseFlowUiState.kt
@@ -14,7 +14,7 @@ sealed class BaseFlowUiState {
/**
* Flow terminated
*/
- data class Terminated(val result: R?) : BaseFlowUiState() {
+ data class Terminated(val result: R) : BaseFlowUiState() {
override val backHandlerEnabled: Boolean = false
}
}
diff --git a/commonstatemachine/api/android/commonstatemachine.api b/commonstatemachine/api/android/commonstatemachine.api
new file mode 100644
index 0000000..b8f8180
--- /dev/null
+++ b/commonstatemachine/api/android/commonstatemachine.api
@@ -0,0 +1,187 @@
+public class com/motorro/commonstatemachine/CommonMachineState {
+ public fun ()V
+ public final fun clear ()V
+ protected fun doClear ()V
+ protected fun doProcess (Ljava/lang/Object;)V
+ protected fun doStart ()V
+ public final fun process (Ljava/lang/Object;)V
+ protected final fun setMachineState (Lcom/motorro/commonstatemachine/CommonMachineState;)V
+ protected final fun setUiState (Ljava/lang/Object;)V
+ public final fun start (Lcom/motorro/commonstatemachine/MachineOutput;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/CommonStateMachine : com/motorro/commonstatemachine/MachineInput, com/motorro/commonstatemachine/MachineOutput, com/motorro/commonstatemachine/MachineStatus {
+ public abstract fun start ()V
+}
+
+public abstract class com/motorro/commonstatemachine/CommonStateMachine$Base : com/motorro/commonstatemachine/CommonStateMachine {
+ protected field activeState Lcom/motorro/commonstatemachine/CommonMachineState;
+ public fun (Lkotlin/jvm/functions/Function0;)V
+ public final fun clear ()V
+ protected final fun getActiveState ()Lcom/motorro/commonstatemachine/CommonMachineState;
+ public final fun isStarted ()Z
+ public final fun process (Ljava/lang/Object;)V
+ protected final fun setActiveState (Lcom/motorro/commonstatemachine/CommonMachineState;)V
+ public final fun setMachineState (Lcom/motorro/commonstatemachine/CommonMachineState;)V
+ public fun start ()V
+}
+
+public abstract interface class com/motorro/commonstatemachine/MachineInput {
+ public abstract fun clear ()V
+ public abstract fun process (Ljava/lang/Object;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/MachineOutput {
+ public abstract fun setMachineState (Lcom/motorro/commonstatemachine/CommonMachineState;)V
+ public abstract fun setUiState (Ljava/lang/Object;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/MachineStatus {
+ public abstract fun getUiState ()Ljava/lang/Object;
+ public abstract fun isStarted ()Z
+}
+
+public abstract class com/motorro/commonstatemachine/ProxyMachineState : com/motorro/commonstatemachine/CommonMachineState {
+ public fun (Ljava/lang/Object;)V
+ protected fun doClear ()V
+ protected fun doProcess (Ljava/lang/Object;)V
+ protected fun doStart ()V
+ protected final fun getChildMachineState ()Lcom/motorro/commonstatemachine/MachineStatus;
+ protected abstract fun init ()Lcom/motorro/commonstatemachine/CommonMachineState;
+ protected abstract fun mapGesture (Ljava/lang/Object;)Ljava/lang/Object;
+ protected abstract fun mapUiState (Ljava/lang/Object;)Ljava/lang/Object;
+}
+
+public final class com/motorro/commonstatemachine/lifecycle/ActivatedMachineLifecycle : com/motorro/commonstatemachine/lifecycle/MachineLifecycle, com/motorro/commonstatemachine/multi/Activated {
+ public fun (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;)V
+ public fun activate ()V
+ public fun addObserver (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer;)V
+ public fun deactivate ()V
+ public fun getState ()Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+ public fun hasObservers ()Z
+ public fun isActive ()Z
+ public fun removeObserver (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer;)V
+}
+
+public final class com/motorro/commonstatemachine/lifecycle/BaseMachineLifecycle : com/motorro/commonstatemachine/lifecycle/MachineLifecycle {
+ public fun (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;)V
+ public fun addObserver (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer;)V
+ public fun getState ()Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+ public fun hasObservers ()Z
+ public fun removeObserver (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer;)V
+ public final fun setState (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/lifecycle/MachineLifecycle {
+ public abstract fun addObserver (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer;)V
+ public abstract fun getState ()Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+ public abstract fun hasObservers ()Z
+ public abstract fun removeObserver (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/lifecycle/MachineLifecycle$Observer {
+ public abstract fun onStateChange (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;)V
+}
+
+public final class com/motorro/commonstatemachine/lifecycle/MachineLifecycle$State : java/lang/Enum {
+ public static final field ACTIVE Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+ public static final field PAUSED Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+ public static fun getEntries ()Lkotlin/enums/EnumEntries;
+ public static fun valueOf (Ljava/lang/String;)Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+ public static fun values ()[Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle$State;
+}
+
+public final class com/motorro/commonstatemachine/lifecycle/MachineLifecycleKt {
+ public static final fun combinePaused (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle;Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle;)Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle;
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/Activated {
+ public abstract fun activate ()V
+ public abstract fun deactivate ()V
+ public abstract fun isActive ()Z
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/ActiveMachineContainer : com/motorro/commonstatemachine/multi/ProxyMachineContainer {
+ public abstract fun dispose (Ljava/util/Set;)V
+ public fun dispose ([Lcom/motorro/commonstatemachine/multi/MachineKey;)V
+ public abstract fun disposeInactive ()V
+ public abstract fun getActive ()Ljava/util/Set;
+ public abstract fun setActive (Ljava/util/Set;)V
+ public fun setActive ([Lcom/motorro/commonstatemachine/multi/MachineKey;)V
+}
+
+public final class com/motorro/commonstatemachine/multi/ActiveMachineContainer$DefaultImpls {
+ public static fun dispose (Lcom/motorro/commonstatemachine/multi/ActiveMachineContainer;[Lcom/motorro/commonstatemachine/multi/MachineKey;)V
+ public static fun setActive (Lcom/motorro/commonstatemachine/multi/ActiveMachineContainer;[Lcom/motorro/commonstatemachine/multi/MachineKey;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/GestureProcessor {
+ public abstract fun process (Lcom/motorro/commonstatemachine/multi/MachineKey;Ljava/lang/Object;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/MachineAccess {
+ public abstract fun getKeys ()Ljava/util/Set;
+ public abstract fun getState (Lcom/motorro/commonstatemachine/multi/MachineKey;)Ljava/lang/Object;
+ public abstract fun process (Lcom/motorro/commonstatemachine/multi/MachineKey;Ljava/lang/Object;)V
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/MachineInit {
+ public abstract fun getInit ()Lkotlin/jvm/functions/Function1;
+ public abstract fun getInitialUiState ()Ljava/lang/Object;
+ public abstract fun getKey ()Lcom/motorro/commonstatemachine/multi/MachineKey;
+}
+
+public abstract class com/motorro/commonstatemachine/multi/MachineKey {
+ public fun ()V
+ public fun (Ljava/lang/String;)V
+ public synthetic fun (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
+ public fun equals (Ljava/lang/Object;)Z
+ public final fun getTag ()Ljava/lang/String;
+ public fun hashCode ()I
+}
+
+public abstract class com/motorro/commonstatemachine/multi/MultiMachineState : com/motorro/commonstatemachine/CommonMachineState {
+ public fun ()V
+ protected fun doClear ()V
+ protected fun doProcess (Ljava/lang/Object;)V
+ protected fun doStart ()V
+ protected abstract fun getContainer ()Lcom/motorro/commonstatemachine/multi/ProxyMachineContainer;
+ protected abstract fun mapGesture (Ljava/lang/Object;Lcom/motorro/commonstatemachine/multi/GestureProcessor;)V
+ protected abstract fun mapUiState (Lcom/motorro/commonstatemachine/multi/UiStateProvider;Lcom/motorro/commonstatemachine/multi/MachineKey;)Ljava/lang/Object;
+ protected final fun updateUi ()V
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/ProxyMachineContainer {
+ public static final field Companion Lcom/motorro/commonstatemachine/multi/ProxyMachineContainer$Companion;
+ public abstract fun clear ()V
+ public abstract fun getMachineAccess ()Lcom/motorro/commonstatemachine/multi/MachineAccess;
+ public abstract fun start (Lkotlin/jvm/functions/Function2;)V
+}
+
+public abstract class com/motorro/commonstatemachine/multi/ProxyMachineContainer$Base : com/motorro/commonstatemachine/multi/ProxyMachineContainer {
+ public fun (Ljava/util/Collection;)V
+ public fun clear ()V
+ public abstract fun create (Lcom/motorro/commonstatemachine/multi/MachineInit;Lkotlin/jvm/functions/Function2;)Lcom/motorro/commonstatemachine/CommonStateMachine;
+ public fun doStart ()V
+ public fun getMachineAccess ()Lcom/motorro/commonstatemachine/multi/MachineAccess;
+ protected final fun getMachines ()Ljava/util/Map;
+ protected final fun setMachines (Ljava/util/Map;)V
+ public fun start (Lkotlin/jvm/functions/Function2;)V
+}
+
+public final class com/motorro/commonstatemachine/multi/ProxyMachineContainer$Companion {
+ public final fun allTogether (Ljava/util/Collection;)Lcom/motorro/commonstatemachine/multi/ProxyMachineContainer;
+ public final fun some (Ljava/util/Collection;Ljava/util/Set;)Lcom/motorro/commonstatemachine/multi/ActiveMachineContainer;
+ public static synthetic fun some$default (Lcom/motorro/commonstatemachine/multi/ProxyMachineContainer$Companion;Ljava/util/Collection;Ljava/util/Set;ILjava/lang/Object;)Lcom/motorro/commonstatemachine/multi/ActiveMachineContainer;
+}
+
+public abstract interface class com/motorro/commonstatemachine/multi/UiStateProvider {
+ public abstract fun get (Lcom/motorro/commonstatemachine/multi/MachineKey;)Ljava/lang/Object;
+ public abstract fun getMachineKeys ()Ljava/util/Set;
+ public fun getValue (Lcom/motorro/commonstatemachine/multi/MachineKey;)Ljava/lang/Object;
+}
+
+public final class com/motorro/commonstatemachine/multi/UiStateProvider$DefaultImpls {
+ public static fun getValue (Lcom/motorro/commonstatemachine/multi/UiStateProvider;Lcom/motorro/commonstatemachine/multi/MachineKey;)Ljava/lang/Object;
+}
+
diff --git a/commonstatemachine/api/commonstatemachine.klib.api b/commonstatemachine/api/commonstatemachine.klib.api
index 93154c0..9cdf9d4 100644
--- a/commonstatemachine/api/commonstatemachine.klib.api
+++ b/commonstatemachine/api/commonstatemachine.klib.api
@@ -1,5 +1,5 @@
// Klib ABI Dump
-// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, wasmJs]
+// Targets: [iosArm64, iosSimulatorArm64, js, wasmJs]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
diff --git a/commonstatemachine/build.gradle.kts b/commonstatemachine/build.gradle.kts
index 9d20183..288f9cd 100644
--- a/commonstatemachine/build.gradle.kts
+++ b/commonstatemachine/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
+
/*
* Copyright 2022 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,152 +13,14 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-@file:OptIn(ExperimentalWasmDsl::class, ExperimentalAbiValidation::class)
-
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
-
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
- alias(libs.plugins.kotlin.dokka)
- id("maven-publish")
- id("signing")
+ alias(libs.plugins.motorro.kmp)
+ alias(libs.plugins.motorro.publishing)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = rootProject.group
-version = rootProject.version
-
-println("== Project version: $versionName ==")
-
kotlin {
+ @OptIn(ExperimentalAbiValidation::class)
abiValidation {
}
-
- jvmToolchain(21)
-
- jvm()
- android {
- namespace = "com.motorro.commonstatemachine.commonstatemachine"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- withHostTest {
- isIncludeAndroidResources = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- wasmJs {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- listOf(
- iosX64(),
- iosArm64(),
- iosSimulatorArm64()
- ).forEach {
- it.binaries.framework {
- baseName = "commonstatemachine"
- isStatic = true
- }
- }
-
- sourceSets {
- commonMain.dependencies {
- api(project(":tmap"))
- }
- commonTest.dependencies {
- implementation(libs.test.kotlin)
- }
- }
-}
-val javadocJar by tasks.registering(Jar::class) {
- dependsOn(tasks.dokkaGenerate)
- group = "documentation"
- archiveClassifier.set("javadoc")
- from(tasks.dokkaGenerate)
}
-
-val libId = "commonstatemachine"
-val libName = "commonstatemachine"
-val libDesc = "Multiplatform state machine for mobile applications"
-val projectUrl: String by project.extra
-val projectScm: String by project.extra
-val ossrhUsername: String? by rootProject.extra
-val ossrhPassword: String? by rootProject.extra
-val developerId: String by project.extra
-val developerName: String by project.extra
-val developerEmail: String by project.extra
-val signingKey: String? by rootProject.extra
-val signingPassword: String? by rootProject.extra
-
-publishing {
- publications.withType {
- artifact(javadocJar)
- pom {
- name.set(libName)
- description.set(libDesc)
- url.set(projectUrl)
- licenses {
- license {
- name.set("Apache-2.0")
- url.set("https://apache.org/licenses/LICENSE-2.0")
- }
- }
- developers {
- developer {
- id.set(developerId)
- name.set(developerName)
- email.set(developerEmail)
- }
- }
- scm {
- connection.set(projectScm)
- developerConnection.set(projectScm)
- url.set(projectUrl)
- }
- }
- }
-}
-
-signing {
- useInMemoryPgpKeys(signingKey, signingPassword)
- sign(publishing.publications)
-}
-
-val signingTasks = tasks.withType()
-tasks.withType().configureEach {
- dependsOn(signingTasks)
-}
\ No newline at end of file
diff --git a/commonstatemachine/consumer-rules.pro b/commonstatemachine/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/commonstatemachine/gradle.properties b/commonstatemachine/gradle.properties
new file mode 100644
index 0000000..35cfa73
--- /dev/null
+++ b/commonstatemachine/gradle.properties
@@ -0,0 +1,14 @@
+#
+# Copyright 2022 Nikolai Kotchetkov.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# 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.
+#
+#Project
+libDesc=Multiplatform state machine for mobile applications
diff --git a/coroutines/api/android/coroutines.api b/coroutines/api/android/coroutines.api
new file mode 100644
index 0000000..b4fcaa2
--- /dev/null
+++ b/coroutines/api/android/coroutines.api
@@ -0,0 +1,24 @@
+public abstract class com/motorro/commonstatemachine/coroutines/CoroutineState : com/motorro/commonstatemachine/CommonMachineState {
+ public fun ()V
+ protected fun doClear ()V
+ protected final fun getStateScope ()Lkotlinx/coroutines/CoroutineScope;
+}
+
+public class com/motorro/commonstatemachine/coroutines/FlowStateMachine : com/motorro/commonstatemachine/CommonStateMachine$Base {
+ public fun (Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
+ public fun getUiState ()Ljava/lang/Object;
+ public final fun getUiState ()Lkotlinx/coroutines/flow/StateFlow;
+ public final fun getUiStateSubscriptionCount ()Lkotlinx/coroutines/flow/StateFlow;
+ public final fun setUiState (Ljava/lang/Object;)V
+}
+
+public final class com/motorro/commonstatemachine/coroutines/FlowStateMachineKt {
+ public static final fun mapUiSubscriptions (Lcom/motorro/commonstatemachine/coroutines/FlowStateMachine;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;)V
+ public static synthetic fun mapUiSubscriptions$default (Lcom/motorro/commonstatemachine/coroutines/FlowStateMachine;Lkotlinx/coroutines/CoroutineScope;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
+}
+
+public final class com/motorro/commonstatemachine/coroutines/lifecycle/LifecycleStateFlowKt {
+ public static final fun asCallback (Lkotlinx/coroutines/flow/StateFlow;Lkotlinx/coroutines/CoroutineScope;)Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle;
+ public static final fun asFlow (Lcom/motorro/commonstatemachine/lifecycle/MachineLifecycle;Lkotlinx/coroutines/CoroutineScope;)Lkotlinx/coroutines/flow/StateFlow;
+}
+
diff --git a/coroutines/api/coroutines.klib.api b/coroutines/api/coroutines.klib.api
index e0d5fba..8b6f52a 100644
--- a/coroutines/api/coroutines.klib.api
+++ b/coroutines/api/coroutines.klib.api
@@ -1,5 +1,5 @@
// Klib ABI Dump
-// Targets: [iosArm64, iosSimulatorArm64, iosX64, js, wasmJs]
+// Targets: [iosArm64, iosSimulatorArm64, js, wasmJs]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
diff --git a/coroutines/build.gradle.kts b/coroutines/build.gradle.kts
index f35174c..6cc2568 100644
--- a/coroutines/build.gradle.kts
+++ b/coroutines/build.gradle.kts
@@ -1,3 +1,5 @@
+import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
+
/*
* Copyright 2022 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -11,155 +13,25 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-@file:OptIn(ExperimentalAbiValidation::class)
-
-import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation
-
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
- alias(libs.plugins.kotlin.dokka)
- id("maven-publish")
- id("signing")
+ alias(libs.plugins.motorro.kmp)
+ alias(libs.plugins.motorro.publishing)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = rootProject.group
-version = rootProject.version
-
-println("== Project version: $versionName ==")
-
kotlin {
+ @OptIn(ExperimentalAbiValidation::class)
abiValidation {
}
- jvmToolchain(21)
-
- jvm()
- android {
- namespace = "com.motorro.commonstatemachine.coroutines"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- withHostTest {
- isIncludeAndroidResources = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- @OptIn(ExperimentalWasmDsl::class)
- wasmJs {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- listOf(
- iosX64(),
- iosArm64(),
- iosSimulatorArm64()
- ).forEach {
- it.binaries.framework {
- baseName = "coroutines"
- isStatic = true
- }
- }
-
sourceSets {
commonMain.dependencies {
api(project(":commonstatemachine"))
api(libs.kotlin.coroutines.core)
}
commonTest.dependencies {
- implementation(libs.test.kotlin)
implementation(libs.test.kotlin.coroutines)
}
}
}
-val javadocJar by tasks.registering(Jar::class) {
- dependsOn(tasks.dokkaGenerate)
- group = "documentation"
- archiveClassifier.set("javadoc")
- from(tasks.dokkaGenerate)
-}
-
-val libId = "coroutines"
-val libName = "coroutines"
-val libDesc = "Coroutines extension for CommonStateMachine"
-val projectUrl: String by project.extra
-val projectScm: String by project.extra
-val ossrhUsername: String? by rootProject.extra
-val ossrhPassword: String? by rootProject.extra
-val developerId: String by project.extra
-val developerName: String by project.extra
-val developerEmail: String by project.extra
-val signingKey: String? by rootProject.extra
-val signingPassword: String? by rootProject.extra
-
-publishing {
- publications.withType {
- artifact(javadocJar)
- pom {
- name.set(libName)
- description.set(libDesc)
- url.set(projectUrl)
- licenses {
- license {
- name.set("Apache-2.0")
- url.set("https://apache.org/licenses/LICENSE-2.0")
- }
- }
- developers {
- developer {
- id.set(developerId)
- name.set(developerName)
- email.set(developerEmail)
- }
- }
- scm {
- connection.set(projectScm)
- developerConnection.set(projectScm)
- url.set(projectUrl)
- }
- }
- }
-}
-
-signing {
- useInMemoryPgpKeys(signingKey, signingPassword)
- sign(publishing.publications)
-}
-
-val signingTasks = tasks.withType()
-tasks.withType().configureEach {
- dependsOn(signingTasks)
-}
\ No newline at end of file
diff --git a/coroutines/consumer-rules.pro b/coroutines/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/coroutines/gradle.properties b/coroutines/gradle.properties
new file mode 100644
index 0000000..7241a4d
--- /dev/null
+++ b/coroutines/gradle.properties
@@ -0,0 +1,14 @@
+#
+# Copyright 2022 Nikolai Kotchetkov.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing, software
+# 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.
+#
+#Project
+libDesc=Coroutines extension for CommonStateMachine
diff --git a/examples/androidcore/build.gradle.kts b/examples/androidcore/build.gradle.kts
deleted file mode 100644
index a89e506..0000000
--- a/examples/androidcore/build.gradle.kts
+++ /dev/null
@@ -1,79 +0,0 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.compose)
-}
-
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- isCoreLibraryDesugaringEnabled = true
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.androidcore"
-}
-
-dependencies {
- api(libs.timber)
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.material.icons)
- implementation(libs.compose.activity)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.androidx.core)
- testImplementation(libs.test.kotlin.coroutines)
-}
diff --git a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Theme.kt b/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Theme.kt
deleted file mode 100644
index 373f154..0000000
--- a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Theme.kt
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2023 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.androidcore.ui.theme
-
-import android.os.Build
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.dynamicDarkColorScheme
-import androidx.compose.material3.dynamicLightColorScheme
-import androidx.compose.material3.lightColorScheme
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.platform.LocalContext
-
-private val DarkColorScheme = darkColorScheme(
- primary = Purple80,
- secondary = PurpleGrey80,
- tertiary = Pink80
-)
-
-private val LightColorScheme = lightColorScheme(
- primary = Purple40,
- secondary = PurpleGrey40,
- tertiary = Pink40
-
- /* Other default colors to override
- background = Color(0xFFFFFBFE),
- surface = Color(0xFFFFFBFE),
- onPrimary = Color.White,
- onSecondary = Color.White,
- onTertiary = Color.White,
- onBackground = Color(0xFF1C1B1F),
- onSurface = Color(0xFF1C1B1F),
- */
-)
-
-@Composable
-fun CommonStateMachineTheme(
- darkTheme: Boolean = isSystemInDarkTheme(),
- // Dynamic color is available on Android 12+
- dynamicColor: Boolean = true,
- content: @Composable () -> Unit
-) {
- val colorScheme = when {
- dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
- val context = LocalContext.current
- if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
- }
-
- darkTheme -> DarkColorScheme
- else -> LightColorScheme
- }
-
- MaterialTheme(
- colorScheme = colorScheme,
- typography = Typography,
- content = content
- )
-}
\ No newline at end of file
diff --git a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Type.kt b/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Type.kt
deleted file mode 100644
index 6451de1..0000000
--- a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Type.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.motorro.statemachine.androidcore.ui.theme
-
-import androidx.compose.material3.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-
-// Set of Material typography styles to start with
-val Typography = Typography(
- bodyLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.5.sp
- )
- /* Other default text styles to override
- titleLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 22.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp
- ),
- labelSmall = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Medium,
- fontSize = 11.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
- )
- */
-)
\ No newline at end of file
diff --git a/examples/books/app/build.gradle.kts b/examples/books/app/build.gradle.kts
index 27a53ff..5aa005e 100644
--- a/examples/books/app/build.gradle.kts
+++ b/examples/books/app/build.gradle.kts
@@ -11,80 +11,12 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
plugins {
- id("com.android.application")
- id("org.jetbrains.kotlin.plugin.compose")
+ alias(libs.plugins.motorro.android.app)
alias(libs.plugins.google.ksp)
alias(libs.plugins.hilt)
}
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.books.app"
-
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
- versionCode = versionCode
- versionName = versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
- namespace = "com.motorro.statemachine.books.app"
-}
-
dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":commonflow:commonflow-data"))
@@ -92,37 +24,15 @@ dependencies {
implementation(project(":commonflow:commonflow-viewmodel"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:books:domain"))
implementation(project(":examples:books:book"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
implementation(libs.kotlin.immutable)
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
implementation(libs.compose.material.icons)
implementation(libs.hilt.android)
implementation(libs.hilt.compose)
ksp(libs.hilt.compiler)
ksp(libs.hilt.compiler.androidx)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.kotlin.coroutines)
}
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/App.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/App.kt
similarity index 82%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/App.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/App.kt
index b00c8e2..f96bccd 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/App.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/App.kt
@@ -11,11 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app
+package com.motorro.commonstatemachine.examples.books.app
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
-import timber.log.Timber
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+
@HiltAndroidApp
class App : Application() {
@@ -25,6 +27,6 @@ class App : Application() {
}
private fun setupLogger() {
- Timber.plant(Timber.DebugTree())
+ Napier.base(DebugAntilog())
}
}
\ No newline at end of file
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/MainActivity.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/MainActivity.kt
similarity index 77%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/MainActivity.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/MainActivity.kt
index ad1bf33..ed4e8be 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/MainActivity.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/MainActivity.kt
@@ -11,23 +11,23 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app
+package com.motorro.commonstatemachine.examples.books.app
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.enableEdgeToEdge
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.app.ui.MainScreen
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
import com.motorro.commonstatemachine.flow.viewmodel.setStateMachineContent
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.books.app.ui.MainScreen
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
- enableEdgeToEdge()
super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
setStateMachineContent { state, onGesture ->
CommonStateMachineTheme {
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/MainViewModel.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/MainViewModel.kt
similarity index 77%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/MainViewModel.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/MainViewModel.kt
index ed17c66..5672200 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/MainViewModel.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/MainViewModel.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app
+package com.motorro.commonstatemachine.examples.books.app
+import com.motorro.commonstatemachine.examples.books.app.api.MainApi
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel
-import com.motorro.statemachine.books.app.api.MainApi
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainApi.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainApi.kt
similarity index 85%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainApi.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainApi.kt
index 5a58725..d573545 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainApi.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainApi.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.api
+package com.motorro.commonstatemachine.examples.books.app.api
import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.books.app.data.MainDataState
+import com.motorro.commonstatemachine.examples.books.app.state.MainFactory
import com.motorro.commonstatemachine.flow.data.CommonFlowDataApi
import com.motorro.commonstatemachine.flow.data.CommonFlowHost
-import com.motorro.statemachine.books.app.data.MainDataState
-import com.motorro.statemachine.books.app.state.MainFactory
import javax.inject.Inject
/**
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainFlowHost.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainFlowHost.kt
similarity index 92%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainFlowHost.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainFlowHost.kt
index 32b28fa..a51da36 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainFlowHost.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainFlowHost.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.api
+package com.motorro.commonstatemachine.examples.books.app.api
import com.motorro.commonstatemachine.flow.data.CommonFlowHost
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainGesture.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainGesture.kt
similarity index 87%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainGesture.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainGesture.kt
index b2d7fe0..7d2a184 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainGesture.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainGesture.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.api
+package com.motorro.commonstatemachine.examples.books.app.api
-import com.motorro.statemachine.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
/**
* Main flow gesture
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainUiState.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainUiState.kt
similarity index 84%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainUiState.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainUiState.kt
index 6e245e2..de2d97c 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/api/MainUiState.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/api/MainUiState.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.api
+package com.motorro.commonstatemachine.examples.books.app.api
import androidx.compose.runtime.Immutable
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
import kotlinx.collections.immutable.ImmutableList
/**
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/data/MainDataState.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/data/MainDataState.kt
similarity index 84%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/data/MainDataState.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/data/MainDataState.kt
index cc6f6f7..2c8aef3 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/data/MainDataState.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/data/MainDataState.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.data
+package com.motorro.commonstatemachine.examples.books.app.data
-import com.motorro.statemachine.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
import kotlinx.collections.immutable.ImmutableList
/**
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/di/ApplicationModule.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/di/ApplicationModule.kt
similarity index 90%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/di/ApplicationModule.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/di/ApplicationModule.kt
index 15f36d9..c897abb 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/di/ApplicationModule.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/di/ApplicationModule.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.di
+package com.motorro.commonstatemachine.examples.books.app.di
-import com.motorro.statemachine.books.app.repository.BookRepositoryImpl
-import com.motorro.statemachine.books.domain.entity.Book
-import com.motorro.statemachine.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.books.app.repository.BookRepositoryImpl
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/repository/BookRepositoryImpl.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/repository/BookRepositoryImpl.kt
similarity index 84%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/repository/BookRepositoryImpl.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/repository/BookRepositoryImpl.kt
index 436860b..64d10fb 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/repository/BookRepositoryImpl.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/repository/BookRepositoryImpl.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.repository
+package com.motorro.commonstatemachine.examples.books.app.repository
-import com.motorro.statemachine.books.domain.entity.Book
-import com.motorro.statemachine.books.domain.entity.ListBook
-import com.motorro.statemachine.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.delay
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/BaseMainState.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/BaseMainState.kt
similarity index 76%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/BaseMainState.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/BaseMainState.kt
index a7e4831..c9a5fbd 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/BaseMainState.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/BaseMainState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
+package com.motorro.commonstatemachine.examples.books.app.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
internal abstract class BaseMainState(context: MainContext) : CoroutineState(), MainContext by context {
override fun doProcess(gesture: MainGesture) {
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/ItemListState.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemListState.kt
similarity index 80%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/ItemListState.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemListState.kt
index 46903c6..6d333b3 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/ItemListState.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemListState.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
+package com.motorro.commonstatemachine.examples.books.app.state
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.books.app.data.MainDataState
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.domain.entity.ListBook
-import com.motorro.statemachine.books.domain.repository.BookRepository
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.app.data.MainDataState
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/ItemProxy.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemProxy.kt
similarity index 70%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/ItemProxy.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemProxy.kt
index 59e0311..01cc0af 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/ItemProxy.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemProxy.kt
@@ -11,18 +11,18 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
+package com.motorro.commonstatemachine.examples.books.app.state
import com.motorro.commonstatemachine.ProxyMachineState
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.books.app.data.MainDataState
-import com.motorro.statemachine.books.book.api.BookApi
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.api.ItemFlowHost
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.app.data.MainDataState
+import com.motorro.commonstatemachine.examples.books.book.api.BookApi
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.api.ItemFlowHost
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
import javax.inject.Inject
internal class ItemProxy(
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/MainContext.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/MainContext.kt
similarity index 91%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/MainContext.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/MainContext.kt
index 76543a8..96161a9 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/MainContext.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/MainContext.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
+package com.motorro.commonstatemachine.examples.books.app.state
/**
* Main flow context
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/MainFactory.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/MainFactory.kt
similarity index 82%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/MainFactory.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/MainFactory.kt
index 34d8d2e..75d4523 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/state/MainFactory.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/state/MainFactory.kt
@@ -11,14 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
+package com.motorro.commonstatemachine.examples.books.app.state
import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.books.app.api.MainFlowHost
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.books.app.data.MainDataState
-import com.motorro.statemachine.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.app.api.MainFlowHost
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.app.data.MainDataState
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/ui/BookListView.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/ui/BookListView.kt
similarity index 91%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/ui/BookListView.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/ui/BookListView.kt
index c332b4f..57762b2 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/ui/BookListView.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/ui/BookListView.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.ui
+package com.motorro.commonstatemachine.examples.books.app.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
@@ -27,8 +27,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
diff --git a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/ui/MainScreen.kt b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/ui/MainScreen.kt
similarity index 87%
rename from examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/ui/MainScreen.kt
rename to examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/ui/MainScreen.kt
index 1fc3d31..d8bfc40 100644
--- a/examples/books/app/src/main/kotlin/com/motorro/statemachine/books/app/ui/MainScreen.kt
+++ b/examples/books/app/src/main/kotlin/com/motorro/commonstatemachine/examples/books/app/ui/MainScreen.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.ui
+package com.motorro.commonstatemachine.examples.books.app.ui
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentTransitionScope
@@ -30,13 +30,13 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.books.app.R
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainGesture.Book
-import com.motorro.statemachine.books.app.api.MainGesture.BookSelected
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.books.book.ui.BookScreen
+import com.motorro.commonstatemachine.examples.books.app.R
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture.Book
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture.BookSelected
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.book.ui.BookScreen
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
import kotlin.reflect.KClass
@Composable
diff --git a/examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/mock.kt b/examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/mock.kt
similarity index 86%
rename from examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/mock.kt
rename to examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/mock.kt
index dd62339..7d36ddd 100644
--- a/examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/mock.kt
+++ b/examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/mock.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app
+package com.motorro.commonstatemachine.examples.books.app
-import com.motorro.statemachine.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
import kotlinx.collections.immutable.persistentListOf
val BOOK_1 = ListBook(
diff --git a/examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/BaseStateTest.kt b/examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/state/BaseStateTest.kt
similarity index 90%
rename from examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/BaseStateTest.kt
rename to examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/state/BaseStateTest.kt
index 87bbd1d..8fb1d8b 100644
--- a/examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/BaseStateTest.kt
+++ b/examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/state/BaseStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
+package com.motorro.commonstatemachine.examples.books.app.state
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/ItemListStateTest.kt b/examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemListStateTest.kt
similarity index 85%
rename from examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/ItemListStateTest.kt
rename to examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemListStateTest.kt
index b4ccfa8..3e503bf 100644
--- a/examples/books/app/src/test/kotlin/com/motorro/statemachine/books/app/state/ItemListStateTest.kt
+++ b/examples/books/app/src/test/kotlin/com/motorro/commonstatemachine/examples/books/app/state/ItemListStateTest.kt
@@ -11,16 +11,16 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.app.state
-
-import com.motorro.statemachine.books.app.BOOK_1
-import com.motorro.statemachine.books.app.BOOK_2
-import com.motorro.statemachine.books.app.api.MainGesture
-import com.motorro.statemachine.books.app.api.MainUiState
-import com.motorro.statemachine.books.app.data.MainDataState
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.domain.entity.ListBook
-import com.motorro.statemachine.books.domain.repository.BookRepository
+package com.motorro.commonstatemachine.examples.books.app.state
+
+import com.motorro.commonstatemachine.examples.books.app.BOOK_1
+import com.motorro.commonstatemachine.examples.books.app.BOOK_2
+import com.motorro.commonstatemachine.examples.books.app.api.MainGesture
+import com.motorro.commonstatemachine.examples.books.app.api.MainUiState
+import com.motorro.commonstatemachine.examples.books.app.data.MainDataState
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
import io.mockk.Ordering
import io.mockk.coVerify
import io.mockk.every
diff --git a/examples/books/book/build.gradle.kts b/examples/books/book/build.gradle.kts
index 2916083..acb05a2 100644
--- a/examples/books/book/build.gradle.kts
+++ b/examples/books/book/build.gradle.kts
@@ -1,5 +1,3 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,77 +12,24 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.compose)
+ alias(libs.plugins.motorro.android.lib.compose)
alias(libs.plugins.google.ksp)
alias(libs.plugins.hilt)
}
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- isCoreLibraryDesugaringEnabled = true
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.books.book"
-}
-
dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":coroutines"))
implementation(project(":commonflow:commonflow-data"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:books:domain"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
-
- implementation(platform(libs.compose.bom))
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
implementation(libs.compose.material.icons)
implementation(libs.hilt.android)
implementation(libs.hilt.compose)
ksp(libs.hilt.compiler)
ksp(libs.hilt.compiler.androidx)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.kotlin.coroutines)
}
diff --git a/examples/books/book/demo/build.gradle.kts b/examples/books/book/demo/build.gradle.kts
index e28d565..e441b8f 100644
--- a/examples/books/book/demo/build.gradle.kts
+++ b/examples/books/book/demo/build.gradle.kts
@@ -11,80 +11,12 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
plugins {
- id("com.android.application")
- id("org.jetbrains.kotlin.plugin.compose")
+ alias(libs.plugins.motorro.android.app)
alias(libs.plugins.google.ksp)
alias(libs.plugins.hilt)
}
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.books.book.demo"
-
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
- versionCode = versionCode
- versionName = versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
- namespace = "com.motorro.statemachine.books.book.demo"
-}
-
dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":commonflow:commonflow-data"))
@@ -92,34 +24,13 @@ dependencies {
implementation(project(":commonflow:commonflow-viewmodel"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:books:domain"))
implementation(project(":examples:books:book"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
- implementation(libs.kotlin.immutable)
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
implementation(libs.compose.material.icons)
implementation(libs.hilt.android)
implementation(libs.hilt.compose)
ksp(libs.hilt.compiler)
ksp(libs.hilt.compiler.androidx)
-
- debugImplementation(libs.compose.tooling)
}
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/App.kt b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/App.kt
similarity index 82%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/App.kt
rename to examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/App.kt
index ccc579b..8c5347f 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/App.kt
+++ b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/App.kt
@@ -11,11 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app
+package com.motorro.commonstatemachine.examples.books.book.demo
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
-import timber.log.Timber
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+
@HiltAndroidApp
class App : Application() {
@@ -25,6 +27,6 @@ class App : Application() {
}
private fun setupLogger() {
- Timber.plant(Timber.DebugTree())
+ Napier.base(DebugAntilog())
}
}
\ No newline at end of file
diff --git a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/MainActivity.kt b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/MainActivity.kt
similarity index 77%
rename from examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/MainActivity.kt
rename to examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/MainActivity.kt
index 47aa33c..10792c9 100644
--- a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/MainActivity.kt
+++ b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/MainActivity.kt
@@ -11,17 +11,17 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.demo
+package com.motorro.commonstatemachine.examples.books.book.demo
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.enableEdgeToEdge
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.ui.BookScreen
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
import com.motorro.commonstatemachine.flow.viewmodel.setStateMachineContent
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.ui.BookScreen
import dagger.hilt.android.AndroidEntryPoint
import dagger.hilt.android.lifecycle.withCreationCallback
diff --git a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/MainViewModel.kt b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/MainViewModel.kt
similarity index 77%
rename from examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/MainViewModel.kt
rename to examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/MainViewModel.kt
index 143073a..e8f22f4 100644
--- a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/MainViewModel.kt
+++ b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/MainViewModel.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.demo
+package com.motorro.commonstatemachine.examples.books.book.demo
+import com.motorro.commonstatemachine.examples.books.book.api.BookApi
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel
-import com.motorro.statemachine.books.book.api.BookApi
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
diff --git a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/data.kt b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/data.kt
similarity index 87%
rename from examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/data.kt
rename to examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/data.kt
index bd22232..ebc80d2 100644
--- a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/data.kt
+++ b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/data.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.demo
+package com.motorro.commonstatemachine.examples.books.book.demo
-import com.motorro.statemachine.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
import kotlinx.collections.immutable.persistentListOf
internal val BOOK = Book(
diff --git a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/di/ApplicationModule.kt b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/di/ApplicationModule.kt
similarity index 79%
rename from examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/di/ApplicationModule.kt
rename to examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/di/ApplicationModule.kt
index 56d4fee..65e5870 100644
--- a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/di/ApplicationModule.kt
+++ b/examples/books/book/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/demo/di/ApplicationModule.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.demo.di
+package com.motorro.commonstatemachine.examples.books.book.demo.di
-import com.motorro.statemachine.books.book.demo.BOOK
-import com.motorro.statemachine.books.domain.entity.Book
-import com.motorro.statemachine.books.domain.entity.ListBook
-import com.motorro.statemachine.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.books.book.demo.BOOK
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookApi.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookApi.kt
similarity index 90%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookApi.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookApi.kt
index fe12321..f0c5006 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookApi.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookApi.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.api
+package com.motorro.commonstatemachine.examples.books.book.api
import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.books.book.state.BookFactory
import com.motorro.commonstatemachine.flow.data.CommonFlowDataApi
import com.motorro.commonstatemachine.flow.data.CommonFlowHost
-import com.motorro.statemachine.books.book.state.BookFactory
import javax.inject.Inject
/**
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookFlowHost.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookFlowHost.kt
similarity index 92%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookFlowHost.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookFlowHost.kt
index 877d02d..fcb71d6 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookFlowHost.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookFlowHost.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.api
+package com.motorro.commonstatemachine.examples.books.book.api
import com.motorro.commonstatemachine.flow.data.CommonFlowHost
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookGesture.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookGesture.kt
similarity index 93%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookGesture.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookGesture.kt
index 39b6daa..e78cce6 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookGesture.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookGesture.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.api
+package com.motorro.commonstatemachine.examples.books.book.api
/**
* Item item flow gesture
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookInput.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookInput.kt
similarity index 91%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookInput.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookInput.kt
index 04c4953..606c343 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookInput.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookInput.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.api
+package com.motorro.commonstatemachine.examples.books.book.api
/**
* Flow input
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookUiState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookUiState.kt
similarity index 88%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookUiState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookUiState.kt
index 89bb7e1..b72f8c5 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/api/BookUiState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/api/BookUiState.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.api
+package com.motorro.commonstatemachine.examples.books.book.api
-import com.motorro.statemachine.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
/**
* Item sub-flow UI state
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/data/BookDataState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/data/BookDataState.kt
similarity index 77%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/data/BookDataState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/data/BookDataState.kt
index 075b7bc..8256338 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/data/BookDataState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/data/BookDataState.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.data
+package com.motorro.commonstatemachine.examples.books.book.data
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
/**
* Item sub-flow internal data
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BaseBookState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BaseBookState.kt
similarity index 76%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BaseBookState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BaseBookState.kt
index 90277d3..f6ce151 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BaseBookState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BaseBookState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
internal abstract class BaseBookState(context: BookContext) : CoroutineState(), BookContext by context {
override fun doProcess(gesture: BookGesture) {
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BookContext.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BookContext.kt
similarity index 91%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BookContext.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BookContext.kt
index 6e8ce27..286734b 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BookContext.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BookContext.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
/**
* Item sub-flow common components
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BookFactory.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BookFactory.kt
similarity index 86%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BookFactory.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BookFactory.kt
index 9abdb71..0c3b2a9 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/BookFactory.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BookFactory.kt
@@ -11,14 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.api.ItemFlowHost
-import com.motorro.statemachine.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.api.ItemFlowHost
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/ContentState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ContentState.kt
similarity index 79%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/ContentState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ContentState.kt
index d8812ae..84b7228 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/ContentState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ContentState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
internal class ContentState(
context: BookContext,
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/DeleteConfirmationState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeleteConfirmationState.kt
similarity index 79%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/DeleteConfirmationState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeleteConfirmationState.kt
index c03bf53..5ecec28 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/DeleteConfirmationState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeleteConfirmationState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
internal class DeleteConfirmationState(
context: BookContext,
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/DeletingState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeletingState.kt
similarity index 82%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/DeletingState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeletingState.kt
index c162702..d2db124 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/DeletingState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeletingState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.books.domain.repository.BookRepository
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
import kotlinx.coroutines.launch
import javax.inject.Inject
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/ErrorState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ErrorState.kt
similarity index 77%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/ErrorState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ErrorState.kt
index 942f150..87178a9 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/ErrorState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ErrorState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
internal class ErrorState(
context: BookContext,
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/LoadingState.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/LoadingState.kt
similarity index 81%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/LoadingState.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/LoadingState.kt
index c8c8c48..b42d66c 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/state/LoadingState.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/state/LoadingState.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.books.domain.repository.BookRepository
-import com.motorro.statemachine.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import javax.inject.Inject
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/ui/BookContentScreen.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/ui/BookContentScreen.kt
similarity index 93%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/ui/BookContentScreen.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/ui/BookContentScreen.kt
index c93ae76..860fa6d 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/ui/BookContentScreen.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/ui/BookContentScreen.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.ui
+package com.motorro.commonstatemachine.examples.books.book.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
@@ -38,10 +38,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.books.book.R
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.book.R
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
import kotlinx.collections.immutable.persistentListOf
@Composable
diff --git a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/ui/BookScreen.kt b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/ui/BookScreen.kt
similarity index 88%
rename from examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/ui/BookScreen.kt
rename to examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/ui/BookScreen.kt
index da169e2..ce61ad0 100644
--- a/examples/books/book/src/main/kotlin/com/motorro/statemachine/books/book/ui/BookScreen.kt
+++ b/examples/books/book/src/main/kotlin/com/motorro/commonstatemachine/examples/books/book/ui/BookScreen.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.ui
+package com.motorro.commonstatemachine.examples.books.book.ui
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
@@ -25,11 +25,11 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
-import com.motorro.statemachine.androidcore.compose.Error
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.books.book.R
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.R
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.Error
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
@Composable
fun BookScreen(state: BookUiState, onGesture: (BookGesture) -> Unit) {
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/mock.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/mock.kt
similarity index 87%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/mock.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/mock.kt
index 974ceae..0291623 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/mock.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/mock.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book
+package com.motorro.commonstatemachine.examples.books.book
-import com.motorro.statemachine.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
import kotlinx.collections.immutable.persistentListOf
internal const val BOOK_ID = 10
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/BaseStateTest.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BaseStateTest.kt
similarity index 90%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/BaseStateTest.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BaseStateTest.kt
index 1533a52..82866db 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/BaseStateTest.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/BaseStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/ContentStateTest.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ContentStateTest.kt
similarity index 78%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/ContentStateTest.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ContentStateTest.kt
index cc42f52..0e6eb19 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/ContentStateTest.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ContentStateTest.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.BOOK_ID
-import com.motorro.statemachine.books.book.BOOK_TITLE
-import com.motorro.statemachine.books.book.Book
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.book.BOOK_ID
+import com.motorro.commonstatemachine.examples.books.book.BOOK_TITLE
+import com.motorro.commonstatemachine.examples.books.book.Book
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
import io.mockk.every
import io.mockk.verify
import org.junit.Test
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/DeleteConfirmationStateTest.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeleteConfirmationStateTest.kt
similarity index 80%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/DeleteConfirmationStateTest.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeleteConfirmationStateTest.kt
index 10538fd..01a4be0 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/DeleteConfirmationStateTest.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeleteConfirmationStateTest.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
-
-import com.motorro.statemachine.books.book.BOOK_ID
-import com.motorro.statemachine.books.book.BOOK_TITLE
-import com.motorro.statemachine.books.book.Book
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
+package com.motorro.commonstatemachine.examples.books.book.state
+
+import com.motorro.commonstatemachine.examples.books.book.BOOK_ID
+import com.motorro.commonstatemachine.examples.books.book.BOOK_TITLE
+import com.motorro.commonstatemachine.examples.books.book.Book
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
import io.mockk.every
import io.mockk.verify
import org.junit.Test
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/DeletingStateTest.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeletingStateTest.kt
similarity index 78%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/DeletingStateTest.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeletingStateTest.kt
index cf550d9..dc80333 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/DeletingStateTest.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/DeletingStateTest.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.BOOK_ID
-import com.motorro.statemachine.books.book.BOOK_TITLE
-import com.motorro.statemachine.books.book.Book
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.books.book.BOOK_ID
+import com.motorro.commonstatemachine.examples.books.book.BOOK_TITLE
+import com.motorro.commonstatemachine.examples.books.book.Book
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/ErrorStateTest.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ErrorStateTest.kt
similarity index 78%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/ErrorStateTest.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ErrorStateTest.kt
index f016776..ee11c15 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/ErrorStateTest.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/ErrorStateTest.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.BOOK_ID
-import com.motorro.statemachine.books.book.BOOK_TITLE
-import com.motorro.statemachine.books.book.Book
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.book.BOOK_ID
+import com.motorro.commonstatemachine.examples.books.book.BOOK_TITLE
+import com.motorro.commonstatemachine.examples.books.book.Book
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
import io.mockk.every
import io.mockk.verify
import org.junit.Test
diff --git a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/LoadingStateTest.kt b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/LoadingStateTest.kt
similarity index 76%
rename from examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/LoadingStateTest.kt
rename to examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/LoadingStateTest.kt
index 7db5a48..8ba687a 100644
--- a/examples/books/book/src/test/kotlin/com/motorro/statemachine/books/book/state/LoadingStateTest.kt
+++ b/examples/books/book/src/test/kotlin/com/motorro/commonstatemachine/examples/books/book/state/LoadingStateTest.kt
@@ -11,22 +11,22 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.state
+package com.motorro.commonstatemachine.examples.books.book.state
-import com.motorro.statemachine.books.book.BOOK_ID
-import com.motorro.statemachine.books.book.BOOK_TITLE
-import com.motorro.statemachine.books.book.Book
-import com.motorro.statemachine.books.book.api.BookGesture
-import com.motorro.statemachine.books.book.api.BookInput
-import com.motorro.statemachine.books.book.api.BookUiState
-import com.motorro.statemachine.books.book.data.BookDataState
-import com.motorro.statemachine.books.domain.repository.BookRepository
+import com.motorro.commonstatemachine.examples.books.book.BOOK_ID
+import com.motorro.commonstatemachine.examples.books.book.BOOK_TITLE
+import com.motorro.commonstatemachine.examples.books.book.Book
+import com.motorro.commonstatemachine.examples.books.book.api.BookGesture
+import com.motorro.commonstatemachine.examples.books.book.api.BookInput
+import com.motorro.commonstatemachine.examples.books.book.api.BookUiState
+import com.motorro.commonstatemachine.examples.books.book.data.BookDataState
+import com.motorro.commonstatemachine.examples.books.domain.repository.BookRepository
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
+import kotlinx.coroutines.suspendCancellableCoroutine
import org.junit.Test
-import kotlin.coroutines.suspendCoroutine
import kotlin.test.assertEquals
internal class LoadingStateTest : BaseStateTest() {
@@ -75,7 +75,7 @@ internal class LoadingStateTest : BaseStateTest() {
@Test
fun terminatesOnBack() = test {
coEvery { repository.getBook(any()) } coAnswers {
- suspendCoroutine {
+ suspendCancellableCoroutine {
// No-op
}
}
diff --git a/examples/books/domain/build.gradle.kts b/examples/books/domain/build.gradle.kts
index 5d5ce7d..a93cc3b 100644
--- a/examples/books/domain/build.gradle.kts
+++ b/examples/books/domain/build.gradle.kts
@@ -1,60 +1,8 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-/*
- * Copyright 2026 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
plugins {
- alias(libs.plugins.android.lib)
-}
-
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- isCoreLibraryDesugaringEnabled = true
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- namespace = "com.motorro.statemachine.books.domain"
+ alias(libs.plugins.motorro.android.lib)
}
dependencies {
- coreLibraryDesugaring(libs.desugaring)
-
api(libs.kotlin.immutable)
- api(libs.kotlin.coroutines.core)
}
diff --git a/examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/entity/Book.kt b/examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/entity/Book.kt
similarity index 91%
rename from examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/entity/Book.kt
rename to examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/entity/Book.kt
index 5a4da8b..ae2ce2a 100644
--- a/examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/entity/Book.kt
+++ b/examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/entity/Book.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.domain.entity
+package com.motorro.commonstatemachine.examples.books.domain.entity
import kotlinx.collections.immutable.ImmutableList
diff --git a/examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/entity/ListBook.kt b/examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/entity/ListBook.kt
similarity index 91%
rename from examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/entity/ListBook.kt
rename to examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/entity/ListBook.kt
index 8b83a30..2917953 100644
--- a/examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/entity/ListBook.kt
+++ b/examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/entity/ListBook.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.domain.entity
+package com.motorro.commonstatemachine.examples.books.domain.entity
import kotlinx.collections.immutable.ImmutableList
diff --git a/examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/repository/BookRepository.kt b/examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/repository/BookRepository.kt
similarity index 79%
rename from examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/repository/BookRepository.kt
rename to examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/repository/BookRepository.kt
index 05c6d6a..6d266a4 100644
--- a/examples/books/domain/src/main/kotlin/com/motorro/statemachine/books/domain/repository/BookRepository.kt
+++ b/examples/books/domain/src/main/kotlin/com/motorro/commonstatemachine/examples/books/domain/repository/BookRepository.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.domain.repository
+package com.motorro.commonstatemachine.examples.books.domain.repository
-import com.motorro.statemachine.books.domain.entity.Book
-import com.motorro.statemachine.books.domain.entity.ListBook
+import com.motorro.commonstatemachine.examples.books.domain.entity.Book
+import com.motorro.commonstatemachine.examples.books.domain.entity.ListBook
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.flow.Flow
diff --git a/examples/commoncore/build.gradle.kts b/examples/commoncore/build.gradle.kts
index 5379a8c..8caf29d 100644
--- a/examples/commoncore/build.gradle.kts
+++ b/examples/commoncore/build.gradle.kts
@@ -10,62 +10,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
+ alias(libs.plugins.motorro.cmp)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = "com.motorro"
-version = versionName
-
kotlin {
- jvmToolchain(21)
-
- compilerOptions {
- freeCompilerArgs.addAll(listOf(
- "-Xexpect-actual-classes"
- ))
- }
-
- android {
- namespace = "com.motorro.statemachine.commoncore"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
sourceSets {
commonMain.dependencies {
- implementation(libs.kotlin.coroutines.core)
- }
- commonTest.dependencies {
- implementation(libs.test.kotlin)
- implementation(libs.test.kotlin.coroutines)
- }
- androidMain.dependencies {
- implementation(libs.timber)
+ api(libs.kotlin.coroutines.core)
+ api(libs.compose.multiplatform.icons)
+ implementation(libs.napier)
}
}
}
\ No newline at end of file
diff --git a/examples/commoncore/consumer-rules.pro b/examples/commoncore/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/commoncore/src/androidMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt b/examples/commoncore/src/androidMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt
deleted file mode 100644
index eb94b30..0000000
--- a/examples/commoncore/src/androidMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.commoncore.log
-
-import timber.log.Timber
-
-actual object Logger {
- actual fun d(message: String?, vararg args: Any?) {
- Timber.d(message, *args)
- }
-
- actual fun i(message: String?, vararg args: Any?) {
- Timber.i(message, *args)
- }
-
- actual fun w(message: String?, vararg args: Any?) {
- Timber.w(message, *args)
- }
-
- actual fun w(t: Throwable?, message: String?, vararg args: Any?) {
- Timber.w(t, message, *args)
- }
-
- actual fun w(t: Throwable?) {
- Timber.w(t)
- }
-
- actual fun e(message: String?, vararg args: Any?) {
- Timber.e(message, *args)
- }
-
- actual fun e(t: Throwable?, message: String?, vararg args: Any?) {
- Timber.e(t, message, *args)
- }
-
- actual fun e(t: Throwable?) {
- Timber.e(t)
- }
-}
\ No newline at end of file
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/coroutines/DispatcherProvider.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/coroutines/DispatcherProvider.kt
similarity index 94%
rename from examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/coroutines/DispatcherProvider.kt
rename to examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/coroutines/DispatcherProvider.kt
index eaf0173..6ada95e 100644
--- a/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/coroutines/DispatcherProvider.kt
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/coroutines/DispatcherProvider.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.commoncore.coroutines
+package com.motorro.commonstatemachine.examples.commoncore.coroutines
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/log/Logger.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/log/Logger.kt
new file mode 100644
index 0000000..2a02778
--- /dev/null
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/log/Logger.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.commoncore.log
+
+import io.github.aakira.napier.LogLevel
+import io.github.aakira.napier.Napier
+
+object Logger {
+
+ private fun napier(logLevel: LogLevel, throwable: Throwable?, message: String?, args: Array?) {
+ val toLog = buildString {
+ message?.let { append(it) }
+ throwable?.let {
+ if (isNotEmpty()) {
+ append(" ")
+ }
+ append(it)
+ }
+ args?.takeIf { it.isNotEmpty() }?.let {
+ if (isNotEmpty()) {
+ append(" ")
+ }
+ append(it.joinToString(prefix = "(", postfix = ")"))
+ }
+ }
+ Napier.log(logLevel, throwable =throwable, message = toLog)
+ }
+
+ fun d(message: String?, vararg args: Any?) = napier(LogLevel.DEBUG, null, message, args)
+
+ fun i(message: String?, vararg args: Any?) = napier(LogLevel.INFO, null, message, args)
+
+ fun w(message: String?, vararg args: Any?) = napier(LogLevel.WARNING, null, message, args)
+
+ fun w(t: Throwable?, message: String?, vararg args: Any?) = napier(LogLevel.WARNING, t, message, args)
+
+ fun w(t: Throwable?) = napier(LogLevel.WARNING, t, null, null)
+
+ fun e(message: String?, vararg args: Any?) = napier(LogLevel.ERROR, null, message, args)
+
+ fun e(t: Throwable?, message: String?, vararg args: Any?) = napier(LogLevel.ERROR, t, message, args)
+
+ fun e(t: Throwable?) = napier(LogLevel.ERROR, null, null, null)
+}
\ No newline at end of file
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/resources/ResourceWrapper.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/resources/ResourceWrapper.kt
similarity index 91%
rename from examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/resources/ResourceWrapper.kt
rename to examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/resources/ResourceWrapper.kt
index 517a489..7da1f4c 100644
--- a/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/resources/ResourceWrapper.kt
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/resources/ResourceWrapper.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.commoncore.resources
+package com.motorro.commonstatemachine.examples.commoncore.resources
/**
* Wraps resource context
diff --git a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/compose/Error.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/Error.kt
similarity index 93%
rename from examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/compose/Error.kt
rename to examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/Error.kt
index 6bed1a0..993acd8 100644
--- a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/compose/Error.kt
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/Error.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.androidcore.compose
+package com.motorro.commonstatemachine.examples.commoncore.ui
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -32,8 +32,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import java.io.IOException
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
@Composable
fun Error(error: Throwable, onDismiss: () -> Unit, modifier: Modifier = Modifier) {
@@ -77,7 +76,7 @@ fun Error(error: Throwable, onDismiss: () -> Unit, modifier: Modifier = Modifier
fun ErrorPreview() {
CommonStateMachineTheme {
Error(
- error = IOException("Network error"),
+ error = RuntimeException("Network error"),
onDismiss = {}
)
}
diff --git a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/compose/Loading.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/Loading.kt
similarity index 95%
rename from examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/compose/Loading.kt
rename to examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/Loading.kt
index 387f18b..6d5eec7 100644
--- a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/compose/Loading.kt
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/Loading.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.androidcore.compose
+package com.motorro.commonstatemachine.examples.commoncore.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
diff --git a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Color.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Color.kt
similarity index 78%
rename from examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Color.kt
rename to examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Color.kt
index 6e5361e..75302e7 100644
--- a/examples/androidcore/src/main/java/com/motorro/statemachine/androidcore/ui/theme/Color.kt
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Color.kt
@@ -1,4 +1,4 @@
-package com.motorro.statemachine.androidcore.ui.theme
+package com.motorro.commonstatemachine.examples.commoncore.ui.theme
import androidx.compose.ui.graphics.Color
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Dimensions.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Dimensions.kt
new file mode 100644
index 0000000..88b55c1
--- /dev/null
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Dimensions.kt
@@ -0,0 +1,34 @@
+package com.motorro.commonstatemachine.examples.commoncore.ui.theme
+
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Common dimensions for the application
+ */
+data object Dimensions {
+ /**
+ * Extra small padding: 4dp
+ */
+ val extraSmall: Dp = 4.dp
+
+ /**
+ * Small padding: 8dp
+ */
+ val small: Dp = 8.dp
+
+ /**
+ * Medium padding: 16dp
+ */
+ val medium: Dp = 16.dp
+
+ /**
+ * Large padding: 24dp
+ */
+ val large: Dp = 24.dp
+
+ /**
+ * Extra large padding: 32dp
+ */
+ val extraLarge: Dp = 32.dp
+}
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Theme.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Theme.kt
new file mode 100644
index 0000000..ed0d476
--- /dev/null
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Theme.kt
@@ -0,0 +1,37 @@
+package com.motorro.commonstatemachine.examples.commoncore.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+)
+
+@Composable
+fun CommonStateMachineTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography(),
+ content = content
+ )
+}
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Type.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Type.kt
new file mode 100644
index 0000000..92f8a81
--- /dev/null
+++ b/examples/commoncore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/commoncore/ui/theme/Type.kt
@@ -0,0 +1,18 @@
+package com.motorro.commonstatemachine.examples.commoncore.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+)
\ No newline at end of file
diff --git a/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt b/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt
deleted file mode 100644
index ba4383e..0000000
--- a/examples/commoncore/src/commonMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.commoncore.log
-
-expect object Logger {
- fun d(message: String?, vararg args: Any?)
-
- fun i(message: String?, vararg args: Any?)
-
- fun w(message: String?, vararg args: Any?)
-
- fun w(t: Throwable?, message: String?, vararg args: Any?)
-
- fun w(t: Throwable?)
-
- fun e(message: String?, vararg args: Any?)
-
- fun e(t: Throwable?, message: String?, vararg args: Any?)
-
- fun e(t: Throwable?)
-}
\ No newline at end of file
diff --git a/examples/commoncore/src/jsMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt b/examples/commoncore/src/jsMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt
deleted file mode 100644
index 91b2413..0000000
--- a/examples/commoncore/src/jsMain/kotlin/com/motorro/statemachine/commoncore/log/Logger.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.commoncore.log
-
-actual object Logger {
- actual fun d(message: String?, vararg args: Any?) {
- console.log(message, *args)
- }
-
- actual fun i(message: String?, vararg args: Any?) {
- console.info(message, *args)
- }
-
- actual fun w(message: String?, vararg args: Any?) {
- console.warn(message, *args)
- }
-
- actual fun w(t: Throwable?, message: String?, vararg args: Any?) {
- console.warn(message, t, *args)
- }
-
- actual fun w(t: Throwable?) {
- console.warn(t)
- }
-
- actual fun e(message: String?, vararg args: Any?) {
- console.error(message, *args)
- }
-
- actual fun e(t: Throwable?, message: String?, vararg args: Any?) {
- console.error(message, t, *args)
- }
-
- actual fun e(t: Throwable?) {
- console.error(t)
- }
-}
\ No newline at end of file
diff --git a/examples/di/api/build.gradle.kts b/examples/di/api/build.gradle.kts
index 27d9ecc..cf32b4f 100644
--- a/examples/di/api/build.gradle.kts
+++ b/examples/di/api/build.gradle.kts
@@ -1,5 +1,3 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,58 +12,11 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.compose)
-}
-
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- isCoreLibraryDesugaringEnabled = true
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.di.api"
+ alias(libs.plugins.motorro.android.lib.compose)
}
dependencies {
api(project(":commonstatemachine"))
api(project(":commonflow:commonflow-data"))
api(project(":commonflow:commonflow-compose"))
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
}
diff --git a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/AuthApi.kt b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/AuthApi.kt
similarity index 91%
rename from examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/AuthApi.kt
rename to examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/AuthApi.kt
index 0517567..3aee0c6 100644
--- a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/AuthApi.kt
+++ b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/AuthApi.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.api
+package com.motorro.commonstatemachine.examples.di.api
import androidx.compose.runtime.staticCompositionLocalOf
+import com.motorro.commonstatemachine.examples.di.api.data.Session
import com.motorro.commonstatemachine.flow.compose.CommonFlowUiApi
import com.motorro.commonstatemachine.flow.data.CommonFlowDataApi
-import com.motorro.statemachine.di.api.data.Session
/**
* Auth gesture marker
diff --git a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/AuthFlowHost.kt b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/AuthFlowHost.kt
similarity index 85%
rename from examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/AuthFlowHost.kt
rename to examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/AuthFlowHost.kt
index cdb1b0c..fee1f50 100644
--- a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/AuthFlowHost.kt
+++ b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/AuthFlowHost.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.api
+package com.motorro.commonstatemachine.examples.di.api
+import com.motorro.commonstatemachine.examples.di.api.data.Session
import com.motorro.commonstatemachine.flow.data.CommonFlowHost
-import com.motorro.statemachine.di.api.data.Session
/**
* Handles authentication
diff --git a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/SessionManager.kt b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/SessionManager.kt
similarity index 87%
rename from examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/SessionManager.kt
rename to examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/SessionManager.kt
index 4e74da4..eaebbac 100644
--- a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/SessionManager.kt
+++ b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/SessionManager.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.api
+package com.motorro.commonstatemachine.examples.di.api
-import com.motorro.statemachine.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.api.data.Session
import kotlinx.coroutines.flow.StateFlow
/**
diff --git a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/data/Session.kt b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/data/Session.kt
similarity index 93%
rename from examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/data/Session.kt
rename to examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/data/Session.kt
index ae26484..53536b8 100644
--- a/examples/di/api/src/main/kotlin/com/motorro/statemachine/di/api/data/Session.kt
+++ b/examples/di/api/src/main/kotlin/com/motorro/commonstatemachine/examples/di/api/data/Session.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.api.data
+package com.motorro.commonstatemachine.examples.di.api.data
/**
* Session state
diff --git a/examples/di/app/build.gradle.kts b/examples/di/app/build.gradle.kts
index ebf3168..f36523e 100644
--- a/examples/di/app/build.gradle.kts
+++ b/examples/di/app/build.gradle.kts
@@ -11,79 +11,13 @@
* limitations under the License.
*/
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
plugins {
- id("com.android.application")
- id("org.jetbrains.kotlin.plugin.compose")
+ alias(libs.plugins.motorro.android.app)
alias(libs.plugins.google.ksp)
alias(libs.plugins.hilt)
}
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-
android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.di"
-
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
- versionCode = versionCode
- versionName = versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
- namespace = "com.motorro.statemachine.di.app"
-
flavorDimensions += "auth"
productFlavors {
create("login") {
@@ -101,40 +35,15 @@ dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":coroutines"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:di:api"))
"loginImplementation"(project(":examples:di:login"))
"socialImplementation"(project(":examples:di:social"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.timber)
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
-
implementation(libs.hilt.android)
implementation(libs.hilt.compose)
ksp(libs.hilt.compiler)
ksp(libs.hilt.compiler.androidx)
debugImplementation(libs.compose.material.icons)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.kotlin.coroutines)
}
diff --git a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/App.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/App.kt
similarity index 82%
rename from examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/App.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/App.kt
index 5567f41..b894336 100644
--- a/examples/books/book/demo/src/main/kotlin/com/motorro/statemachine/books/book/demo/App.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/App.kt
@@ -11,11 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.books.book.demo
+package com.motorro.commonstatemachine.examples.di.app
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
-import timber.log.Timber
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+
@HiltAndroidApp
class App : Application() {
@@ -25,6 +27,6 @@ class App : Application() {
}
private fun setupLogger() {
- Timber.plant(Timber.DebugTree())
+ Napier.base(DebugAntilog())
}
}
\ No newline at end of file
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/MainActivity.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/MainActivity.kt
similarity index 85%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/MainActivity.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/MainActivity.kt
index ab05030..0392ee2 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/MainActivity.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/MainActivity.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app
+package com.motorro.commonstatemachine.examples.di.app
import android.os.Bundle
import androidx.activity.ComponentActivity
@@ -21,10 +21,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.di.api.AuthUiApi
-import com.motorro.statemachine.di.api.LocalAuth
-import com.motorro.statemachine.di.app.ui.MainScreen
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import com.motorro.commonstatemachine.examples.di.api.AuthUiApi
+import com.motorro.commonstatemachine.examples.di.api.LocalAuth
+import com.motorro.commonstatemachine.examples.di.app.ui.MainScreen
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/MainViewModel.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/MainViewModel.kt
similarity index 81%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/MainViewModel.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/MainViewModel.kt
index 174bad7..fd12757 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/MainViewModel.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/MainViewModel.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app
+package com.motorro.commonstatemachine.examples.di.app
import androidx.lifecycle.ViewModel
import com.motorro.commonstatemachine.coroutines.FlowStateMachine
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
-import com.motorro.statemachine.di.app.state.MainFactory
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.di.app.state.MainFactory
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/data/MainGesture.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/data/MainGesture.kt
similarity index 86%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/data/MainGesture.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/data/MainGesture.kt
index 9b297cc..def0cf5 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/data/MainGesture.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/data/MainGesture.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.data
+package com.motorro.commonstatemachine.examples.di.app.data
-import com.motorro.statemachine.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
/**
* Main flow gesture
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/data/MainUiState.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/data/MainUiState.kt
similarity index 81%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/data/MainUiState.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/data/MainUiState.kt
index 763cf86..290e671 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/data/MainUiState.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/data/MainUiState.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.data
+package com.motorro.commonstatemachine.examples.di.app.data
-import com.motorro.statemachine.di.api.AuthUiState
-import com.motorro.statemachine.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.data.Session
internal sealed class MainUiState {
data object Loading : MainUiState()
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/di/ApplicationModule.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/di/ApplicationModule.kt
similarity index 81%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/di/ApplicationModule.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/di/ApplicationModule.kt
index 91baaf3..5a61709 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/di/ApplicationModule.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/di/ApplicationModule.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.di
+package com.motorro.commonstatemachine.examples.di.app.di
-import com.motorro.statemachine.di.api.SessionManager
-import com.motorro.statemachine.di.app.session.SessionManagerImpl
+import com.motorro.commonstatemachine.examples.di.api.SessionManager
+import com.motorro.commonstatemachine.examples.di.app.session.SessionManagerImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/di/MainModule.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/di/MainModule.kt
similarity index 87%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/di/MainModule.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/di/MainModule.kt
index 09c2e3b..5161f41 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/di/MainModule.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/di/MainModule.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.di
+package com.motorro.commonstatemachine.examples.di.app.di
-import com.motorro.statemachine.di.app.state.MainFactory
+import com.motorro.commonstatemachine.examples.di.app.state.MainFactory
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/session/SessionManagerImpl.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/session/SessionManagerImpl.kt
similarity index 84%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/session/SessionManagerImpl.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/session/SessionManagerImpl.kt
index 114a267..68647f3 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/session/SessionManagerImpl.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/session/SessionManagerImpl.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.session
+package com.motorro.commonstatemachine.examples.di.app.session
-import com.motorro.statemachine.di.api.SessionManager
-import com.motorro.statemachine.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.api.SessionManager
+import com.motorro.commonstatemachine.examples.di.api.data.Session
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/AuthProxy.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/AuthProxy.kt
similarity index 77%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/AuthProxy.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/AuthProxy.kt
index ebb65ad..6730bb7 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/AuthProxy.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/AuthProxy.kt
@@ -11,16 +11,16 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
import com.motorro.commonstatemachine.ProxyMachineState
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.AuthDataApi
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiState
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
import javax.inject.Inject
internal class AuthProxy(
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/BaseMainState.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/BaseMainState.kt
similarity index 76%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/BaseMainState.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/BaseMainState.kt
index b8e9329..ae28d2a 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/BaseMainState.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/BaseMainState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
internal abstract class BaseMainState(context: MainContext) : CoroutineState(), MainContext by context {
override fun doProcess(gesture: MainGesture) {
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/Content.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/Content.kt
similarity index 83%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/Content.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/Content.kt
index 8a090bc..4abbeae 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/Content.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/Content.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.SessionManager
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.SessionManager
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import javax.inject.Inject
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/MainContext.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/MainContext.kt
similarity index 91%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/MainContext.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/MainContext.kt
index 34d5742..b213c06 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/MainContext.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/MainContext.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
/**
* Main flow context
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/MainFactory.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/MainFactory.kt
similarity index 88%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/MainFactory.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/MainFactory.kt
index a752123..70f0deb 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/MainFactory.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/MainFactory.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
import javax.inject.Inject
import javax.inject.Provider
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/UpdatingSession.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/UpdatingSession.kt
similarity index 79%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/UpdatingSession.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/UpdatingSession.kt
index bce2095..a8ca521 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/state/UpdatingSession.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/state/UpdatingSession.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.SessionManager
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.SessionManager
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
import kotlinx.coroutines.launch
import javax.inject.Inject
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/ui/MainScreen.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/ui/MainScreen.kt
similarity index 88%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/ui/MainScreen.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/ui/MainScreen.kt
index 6cf88a7..cc429ce 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/ui/MainScreen.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/ui/MainScreen.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.ui
+package com.motorro.commonstatemachine.examples.di.app.ui
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.fillMaxSize
@@ -30,11 +30,11 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.di.api.LocalAuth
-import com.motorro.statemachine.di.app.R
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import com.motorro.commonstatemachine.examples.di.api.LocalAuth
+import com.motorro.commonstatemachine.examples.di.app.R
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
@Composable
@OptIn(ExperimentalMaterial3Api::class)
diff --git a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/ui/MainScreenView.kt b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/ui/MainScreenView.kt
similarity index 90%
rename from examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/ui/MainScreenView.kt
rename to examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/ui/MainScreenView.kt
index 5dc5ae5..04673a3 100644
--- a/examples/di/app/src/main/kotlin/com/motorro/statemachine/di/app/ui/MainScreenView.kt
+++ b/examples/di/app/src/main/kotlin/com/motorro/commonstatemachine/examples/di/app/ui/MainScreenView.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.ui
+package com.motorro.commonstatemachine.examples.di.app.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -30,10 +30,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.app.R
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.app.R
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
@Composable
internal fun MainScreenView(state: MainUiState.Content, onGesture: (MainGesture) -> Unit, modifier: Modifier = Modifier) {
diff --git a/examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/mock.kt b/examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/mock.kt
similarity index 85%
rename from examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/mock.kt
rename to examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/mock.kt
index 8c145d0..9e082e5 100644
--- a/examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/mock.kt
+++ b/examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/mock.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app
+package com.motorro.commonstatemachine.examples.di.app
-import com.motorro.statemachine.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.api.data.Session
internal val ACTIVE_SESSION = Session.Active(
accessToken = "access",
diff --git a/examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/state/BaseStateTest.kt b/examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/state/BaseStateTest.kt
similarity index 89%
rename from examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/state/BaseStateTest.kt
rename to examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/state/BaseStateTest.kt
index d8804ad..ee58480 100644
--- a/examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/state/BaseStateTest.kt
+++ b/examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/state/BaseStateTest.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
diff --git a/examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/state/ContentTest.kt b/examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/state/ContentTest.kt
similarity index 87%
rename from examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/state/ContentTest.kt
rename to examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/state/ContentTest.kt
index 7b4a617..5899e95 100644
--- a/examples/di/app/src/test/kotlin/com/motorro/statemachine/di/app/state/ContentTest.kt
+++ b/examples/di/app/src/test/kotlin/com/motorro/commonstatemachine/examples/di/app/state/ContentTest.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.app.state
+package com.motorro.commonstatemachine.examples.di.app.state
-import com.motorro.statemachine.di.api.SessionManager
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.app.ACTIVE_SESSION
-import com.motorro.statemachine.di.app.data.MainGesture
-import com.motorro.statemachine.di.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.di.api.SessionManager
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.app.ACTIVE_SESSION
+import com.motorro.commonstatemachine.examples.di.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.di.app.data.MainUiState
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
diff --git a/examples/di/login/build.gradle.kts b/examples/di/login/build.gradle.kts
index 4b7ed4b..dab2d46 100644
--- a/examples/di/login/build.gradle.kts
+++ b/examples/di/login/build.gradle.kts
@@ -1,5 +1,3 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,72 +12,18 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.compose)
+ alias(libs.plugins.motorro.android.lib.compose)
alias(libs.plugins.google.ksp)
alias(libs.plugins.hilt)
}
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- isCoreLibraryDesugaringEnabled = true
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.di.login"
-}
-
dependencies {
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:di:api"))
implementation(project(":coroutines"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
-
- implementation(platform(libs.compose.bom))
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
-
implementation(libs.hilt.android)
implementation(libs.hilt.compose)
ksp(libs.hilt.compiler)
ksp(libs.hilt.compiler.androidx)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.kotlin.coroutines)
}
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/LoginConstants.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/LoginConstants.kt
similarity index 93%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/LoginConstants.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/LoginConstants.kt
index 3fbdfe0..83e9814 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/LoginConstants.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/LoginConstants.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login
+package com.motorro.commonstatemachine.examples.di.login
/**
* Mock data
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/LoginDataApi.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/LoginDataApi.kt
similarity index 68%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/LoginDataApi.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/LoginDataApi.kt
index dc7809f..3585e48 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/LoginDataApi.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/LoginDataApi.kt
@@ -11,20 +11,20 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login
+package com.motorro.commonstatemachine.examples.di.login
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.motorro.statemachine.di.api.AuthDataApi
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiApi
-import com.motorro.statemachine.di.api.AuthUiState
-import com.motorro.statemachine.di.login.data.LoginDataState
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
-import com.motorro.statemachine.di.login.state.LoginFactory
-import com.motorro.statemachine.di.login.ui.LoginScreen
+import com.motorro.commonstatemachine.examples.di.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiApi
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.di.login.state.LoginFactory
+import com.motorro.commonstatemachine.examples.di.login.ui.LoginScreen
import jakarta.inject.Inject
/**
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginDataState.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginDataState.kt
similarity index 91%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginDataState.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginDataState.kt
index 1943f8e..d6f5010 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginDataState.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginDataState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.data
+package com.motorro.commonstatemachine.examples.di.login.data
/**
* Data state
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginGesture.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginGesture.kt
similarity index 87%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginGesture.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginGesture.kt
index 24d3a2a..51efa22 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginGesture.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginGesture.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.data
+package com.motorro.commonstatemachine.examples.di.login.data
-import com.motorro.statemachine.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
internal sealed class LoginGesture : AuthGesture {
data object Back : LoginGesture()
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginUiState.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginUiState.kt
similarity index 86%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginUiState.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginUiState.kt
index 7857d44..50a0427 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/data/LoginUiState.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/data/LoginUiState.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.data
+package com.motorro.commonstatemachine.examples.di.login.data
-import com.motorro.statemachine.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
internal sealed class LoginUiState: AuthUiState {
data object Loading : LoginUiState()
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/di/LoginFlowModule.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/di/LoginFlowModule.kt
similarity index 77%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/di/LoginFlowModule.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/di/LoginFlowModule.kt
index 18395f2..8153be7 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/di/LoginFlowModule.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/di/LoginFlowModule.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.di
+package com.motorro.commonstatemachine.examples.di.login.di
-import com.motorro.statemachine.di.api.AuthDataApi
-import com.motorro.statemachine.di.api.AuthUiApi
-import com.motorro.statemachine.di.login.LoginDataApi
-import com.motorro.statemachine.di.login.LoginUiApi
+import com.motorro.commonstatemachine.examples.di.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.di.api.AuthUiApi
+import com.motorro.commonstatemachine.examples.di.login.LoginDataApi
+import com.motorro.commonstatemachine.examples.di.login.LoginUiApi
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/BaseLoginState.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/BaseLoginState.kt
similarity index 76%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/BaseLoginState.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/BaseLoginState.kt
index 9736270..2ad8f77 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/BaseLoginState.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/BaseLoginState.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiState
-import com.motorro.statemachine.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
internal abstract class BaseLoginState(context: LoginContext) : CoroutineState(), LoginContext by context {
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/Error.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/Error.kt
similarity index 76%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/Error.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/Error.kt
index f5ae0a2..64e600f 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/Error.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/Error.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.login.data.LoginDataState
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
/**
* Displays error
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/FormState.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/FormState.kt
similarity index 84%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/FormState.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/FormState.kt
index 9ca534e..7bef7bd 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/FormState.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/FormState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.login.data.LoginDataState
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
import kotlin.properties.Delegates
internal class FormState(context: LoginContext, data: LoginDataState) : BaseLoginState(context) {
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoggingIn.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoggingIn.kt
similarity index 79%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoggingIn.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoggingIn.kt
index 5025f2c..a8a2c0c 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoggingIn.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoggingIn.kt
@@ -11,14 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.login.LoginConstants
-import com.motorro.statemachine.di.login.data.LoginDataState
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.login.LoginConstants
+import com.motorro.commonstatemachine.examples.di.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.time.Duration.Companion.seconds
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoginContext.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoginContext.kt
similarity index 84%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoginContext.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoginContext.kt
index 253887e..0d342d8 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoginContext.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoginContext.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
-import com.motorro.statemachine.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
/**
* Common inter-state context
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoginFactory.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoginFactory.kt
similarity index 85%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoginFactory.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoginFactory.kt
index 46bc515..a0df7c0 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/state/LoginFactory.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/state/LoginFactory.kt
@@ -11,14 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiState
-import com.motorro.statemachine.di.api.data.Session
-import com.motorro.statemachine.di.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.login.data.LoginDataState
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/ui/LoginFormView.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/ui/LoginFormView.kt
similarity index 89%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/ui/LoginFormView.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/ui/LoginFormView.kt
index 37c9634..077d28e 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/ui/LoginFormView.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/ui/LoginFormView.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.ui
+package com.motorro.commonstatemachine.examples.di.login.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
@@ -26,9 +26,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
@Composable
internal fun LoginFormView(state: LoginUiState.Form, onGesture: (LoginGesture) -> Unit, modifier: Modifier = Modifier) {
diff --git a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/ui/LoginScreen.kt b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/ui/LoginScreen.kt
similarity index 76%
rename from examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/ui/LoginScreen.kt
rename to examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/ui/LoginScreen.kt
index 95734ac..56ea3e5 100644
--- a/examples/di/login/src/main/kotlin/com/motorro/statemachine/di/login/ui/LoginScreen.kt
+++ b/examples/di/login/src/main/kotlin/com/motorro/commonstatemachine/examples/di/login/ui/LoginScreen.kt
@@ -11,14 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.ui
+package com.motorro.commonstatemachine.examples.di.login.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.motorro.statemachine.androidcore.compose.Error
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.Error
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
@Composable
internal fun LoginScreen(state: LoginUiState, onGesture: (LoginGesture) -> Unit, modifier: Modifier = Modifier) {
diff --git a/examples/di/login/src/test/kotlin/com/motorro/statemachine/di/login/state/BaseStateTest.kt b/examples/di/login/src/test/kotlin/com/motorro/commonstatemachine/examples/di/login/state/BaseStateTest.kt
similarity index 90%
rename from examples/di/login/src/test/kotlin/com/motorro/statemachine/di/login/state/BaseStateTest.kt
rename to examples/di/login/src/test/kotlin/com/motorro/commonstatemachine/examples/di/login/state/BaseStateTest.kt
index a5cc5e7..36caa32 100644
--- a/examples/di/login/src/test/kotlin/com/motorro/statemachine/di/login/state/BaseStateTest.kt
+++ b/examples/di/login/src/test/kotlin/com/motorro/commonstatemachine/examples/di/login/state/BaseStateTest.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
diff --git a/examples/di/login/src/test/kotlin/com/motorro/statemachine/di/login/state/FormStateTest.kt b/examples/di/login/src/test/kotlin/com/motorro/commonstatemachine/examples/di/login/state/FormStateTest.kt
similarity index 93%
rename from examples/di/login/src/test/kotlin/com/motorro/statemachine/di/login/state/FormStateTest.kt
rename to examples/di/login/src/test/kotlin/com/motorro/commonstatemachine/examples/di/login/state/FormStateTest.kt
index 8f4cbc7..65dc624 100644
--- a/examples/di/login/src/test/kotlin/com/motorro/statemachine/di/login/state/FormStateTest.kt
+++ b/examples/di/login/src/test/kotlin/com/motorro/commonstatemachine/examples/di/login/state/FormStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.di.login.state
+package com.motorro.commonstatemachine.examples.di.login.state
-import com.motorro.statemachine.di.login.data.LoginDataState
-import com.motorro.statemachine.di.login.data.LoginGesture
-import com.motorro.statemachine.di.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.di.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.di.login.data.LoginUiState
import io.mockk.Ordering
import io.mockk.coVerify
import io.mockk.every
diff --git a/examples/di/social/build.gradle.kts b/examples/di/social/build.gradle.kts
index efd51ee..66a87ef 100644
--- a/examples/di/social/build.gradle.kts
+++ b/examples/di/social/build.gradle.kts
@@ -1,5 +1,3 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,73 +12,20 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.compose)
+ alias(libs.plugins.motorro.android.lib.compose)
alias(libs.plugins.google.ksp)
alias(libs.plugins.hilt)
}
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- isCoreLibraryDesugaringEnabled = true
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.di.social"
-}
-
dependencies {
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:di:api"))
implementation(project(":coroutines"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
-
- implementation(platform(libs.compose.bom))
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
implementation(libs.compose.material.icons)
implementation(libs.hilt.android)
implementation(libs.hilt.compose)
ksp(libs.hilt.compiler)
ksp(libs.hilt.compiler.androidx)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.kotlin.coroutines)
}
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/SocialConstants.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/SocialConstants.kt
similarity index 91%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/SocialConstants.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/SocialConstants.kt
index 8c4ad86..6706a69 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/SocialConstants.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/SocialConstants.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social
/**
* Mock data
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/SocialDataApi.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/SocialDataApi.kt
similarity index 68%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/SocialDataApi.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/SocialDataApi.kt
index 5f4b003..bf88504 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/SocialDataApi.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/SocialDataApi.kt
@@ -11,20 +11,20 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.motorro.statemachine.di.api.AuthDataApi
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiApi
-import com.motorro.statemachine.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiApi
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
import jakarta.inject.Inject
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialGesture
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialUiState
-import main.kotlin.com.motorro.statemachine.di.social.state.SocialFactory
-import main.kotlin.com.motorro.statemachine.di.social.ui.SocialScreen
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialGesture
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialUiState
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.state.SocialFactory
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.ui.SocialScreen
/**
* Auth data API implementation for Social flow
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/data/SocialGesture.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/data/SocialGesture.kt
similarity index 83%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/data/SocialGesture.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/data/SocialGesture.kt
index 89bfcb0..a29aa93 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/data/SocialGesture.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/data/SocialGesture.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.data
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.data
-import com.motorro.statemachine.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
internal sealed class SocialGesture : AuthGesture {
data object Back : SocialGesture()
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/data/SocialUiState.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/data/SocialUiState.kt
similarity index 83%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/data/SocialUiState.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/data/SocialUiState.kt
index cdc63d7..403e6e5 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/data/SocialUiState.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/data/SocialUiState.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.data
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.data
-import com.motorro.statemachine.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
internal sealed class SocialUiState: AuthUiState {
data object Loading : SocialUiState()
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/di/SocialFlowModule.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/di/SocialFlowModule.kt
similarity index 75%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/di/SocialFlowModule.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/di/SocialFlowModule.kt
index 8c8c582..3d960d7 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/di/SocialFlowModule.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/di/SocialFlowModule.kt
@@ -11,17 +11,17 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.di
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.di
-import com.motorro.statemachine.di.api.AuthDataApi
-import com.motorro.statemachine.di.api.AuthUiApi
+import com.motorro.commonstatemachine.examples.di.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.di.api.AuthUiApi
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dagger.hilt.android.components.ViewModelComponent
-import main.kotlin.com.motorro.statemachine.di.social.SocialDataApi
-import main.kotlin.com.motorro.statemachine.di.social.SocialUiApi
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.SocialDataApi
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.SocialUiApi
@Module
@InstallIn(ViewModelComponent::class)
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/BaseSocialState.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/BaseSocialState.kt
similarity index 75%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/BaseSocialState.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/BaseSocialState.kt
index 4db3fb2..0ac6dbb 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/BaseSocialState.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/BaseSocialState.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.state
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiState
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialGesture
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialGesture
internal abstract class BaseSocialState(context: SocialContext) : CoroutineState(), SocialContext by context {
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/FormState.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/FormState.kt
similarity index 78%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/FormState.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/FormState.kt
index 3427c6f..c987639 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/FormState.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/FormState.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.state
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.state
-import com.motorro.statemachine.commoncore.log.Logger
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialGesture
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialGesture
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialUiState
internal class FormState(context: SocialContext) : BaseSocialState(context) {
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/LoggingIn.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/LoggingIn.kt
similarity index 76%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/LoggingIn.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/LoggingIn.kt
index c30c1f7..fdbfe6b 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/LoggingIn.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/LoggingIn.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.state
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.di.api.data.Session
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.di.api.data.Session
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import main.kotlin.com.motorro.statemachine.di.social.SocialConstants
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialGesture
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialUiState
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.SocialConstants
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialGesture
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialUiState
import kotlin.time.Duration.Companion.seconds
/**
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/SocialContext.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/SocialContext.kt
similarity index 83%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/SocialContext.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/SocialContext.kt
index 56b89c6..47e3129 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/SocialContext.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/SocialContext.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.state
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.state
-import com.motorro.statemachine.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
/**
* Common inter-state context
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/SocialFactory.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/SocialFactory.kt
similarity index 85%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/SocialFactory.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/SocialFactory.kt
index 2492310..0a173ca 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/state/SocialFactory.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/state/SocialFactory.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.state
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.state
import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.di.api.AuthFlowHost
-import com.motorro.statemachine.di.api.AuthGesture
-import com.motorro.statemachine.di.api.AuthUiState
-import com.motorro.statemachine.di.api.data.Session
+import com.motorro.commonstatemachine.examples.di.api.AuthFlowHost
+import com.motorro.commonstatemachine.examples.di.api.AuthGesture
+import com.motorro.commonstatemachine.examples.di.api.AuthUiState
+import com.motorro.commonstatemachine.examples.di.api.data.Session
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/ui/SocialFormView.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/ui/SocialFormView.kt
similarity index 87%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/ui/SocialFormView.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/ui/SocialFormView.kt
index 8fe1585..37db52f 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/ui/SocialFormView.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/ui/SocialFormView.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.ui
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.ui
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
@@ -31,9 +31,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialGesture
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialGesture
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialUiState
@Composable
internal fun SocialFormView(state: SocialUiState.Form, onGesture: (SocialGesture) -> Unit, modifier: Modifier = Modifier) {
diff --git a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/ui/SocialScreen.kt b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/ui/SocialScreen.kt
similarity index 75%
rename from examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/ui/SocialScreen.kt
rename to examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/ui/SocialScreen.kt
index 1841ca3..1067ce1 100644
--- a/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/statemachine/di/social/ui/SocialScreen.kt
+++ b/examples/di/social/src/main/kotlin/main/kotlin/com/motorro/commonstatemachine/examples/di/social/ui/SocialScreen.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package main.kotlin.com.motorro.statemachine.di.social.ui
+package main.kotlin.com.motorro.commonstatemachine.examples.di.social.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
-import com.motorro.statemachine.androidcore.compose.Loading
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialGesture
-import main.kotlin.com.motorro.statemachine.di.social.data.SocialUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialGesture
+import main.kotlin.com.motorro.commonstatemachine.examples.di.social.data.SocialUiState
@Composable
internal fun SocialScreen(state: SocialUiState, onGesture: (SocialGesture) -> Unit, modifier: Modifier = Modifier) {
diff --git a/examples/lce/build.gradle.kts b/examples/lce/build.gradle.kts
index c0b1e92..2847d26 100644
--- a/examples/lce/build.gradle.kts
+++ b/examples/lce/build.gradle.kts
@@ -1,7 +1,3 @@
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2022 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,90 +12,12 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- id("com.android.application")
- id("org.jetbrains.kotlin.plugin.compose")
-}
-
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-
-android {
- compileSdk = androidCompileSdkVersion // Assuming androidCompileSdkVersion is defined elsewhere (e.g., gradle.properties or root build.gradle)
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.lce"
- minSdk = androidMinSdkVersion // Assuming androidMinSdkVersion is defined elsewhere
- targetSdk = androidTargetSdkVersion // Assuming androidTargetSdkVersion is defined elsewhere
- versionCode = versionCode // Assuming versionCode is defined elsewhere
- versionName = versionName // Assuming versionName is defined elsewhere
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
- namespace = "com.motorro.statemachine.lce"
+ alias(libs.plugins.motorro.android.app)
}
dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":coroutines"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.timber)
-
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
- debugImplementation(libs.compose.material)
- debugImplementation(libs.compose.material.icons)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.androidx.arch)
- testImplementation(libs.test.kotlin.coroutines)
+ implementation(libs.compose.material.icons)
}
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/MainActivity.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/MainActivity.kt
similarity index 74%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/MainActivity.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/MainActivity.kt
index bd3676e..275ba9b 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/MainActivity.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/MainActivity.kt
@@ -11,21 +11,25 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce
+package com.motorro.commonstatemachine.examples.lce
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.LaunchedEffect
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.lce.ui.LceScreen
-import timber.log.Timber
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import com.motorro.commonstatemachine.examples.lce.ui.LceScreen
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
- Timber.plant(Timber.DebugTree())
+ Napier.base(DebugAntilog())
setContent {
CommonStateMachineTheme {
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/ItemId.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/ItemId.kt
similarity index 92%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/data/ItemId.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/ItemId.kt
index 317cd31..8b87720 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/ItemId.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/ItemId.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.data
+package com.motorro.commonstatemachine.examples.lce.data
enum class ItemId {
LOADS_CONTENT,
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/ItemModel.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/ItemModel.kt
similarity index 79%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/data/ItemModel.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/ItemModel.kt
index 74faf6c..2e9481d 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/ItemModel.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/ItemModel.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.data
+package com.motorro.commonstatemachine.examples.lce.data
/**
* Item UI model
*/
-data class ItemModel(val id: ItemId, val name: String)
\ No newline at end of file
+data class ItemModel(val id: com.motorro.commonstatemachine.examples.lce.data.ItemId, val name: String)
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/LceGesture.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/LceGesture.kt
similarity index 85%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/data/LceGesture.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/LceGesture.kt
index 8664176..23dfcd6 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/LceGesture.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/LceGesture.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.data
+package com.motorro.commonstatemachine.examples.lce.data
/**
* Gestures for application flow
@@ -21,7 +21,7 @@ sealed class LceGesture {
* Item to load clicked
* @property id Item ID to load
*/
- data class ItemClicked(val id: ItemId) : LceGesture()
+ data class ItemClicked(val id: com.motorro.commonstatemachine.examples.lce.data.ItemId) : LceGesture()
/**
* Retry operation clicked
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/LceUiState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/LceUiState.kt
similarity index 86%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/data/LceUiState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/LceUiState.kt
index 07e2cc0..fabaf52 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/data/LceUiState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/data/LceUiState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.data
+package com.motorro.commonstatemachine.examples.lce.data
import androidx.compose.runtime.Immutable
@@ -23,7 +23,7 @@ sealed class LceUiState {
* Item list view
*/
@Immutable
- data class ItemList(val items: List) : LceUiState()
+ data class ItemList(val items: List) : LceUiState()
/**
* Loading spinner
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/LceViewModel.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/LceViewModel.kt
similarity index 80%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/LceViewModel.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/LceViewModel.kt
index 60ba0e7..573a695 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/LceViewModel.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/LceViewModel.kt
@@ -11,17 +11,18 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model
+package com.motorro.commonstatemachine.examples.lce.model
import androidx.lifecycle.ViewModel
import com.motorro.commonstatemachine.CommonMachineState
import com.motorro.commonstatemachine.coroutines.FlowStateMachine
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
-import com.motorro.statemachine.lce.model.state.ItemListState
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.model.state.ItemListState
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import timber.log.Timber
+
/**
* Wraps state-machine with view-model
@@ -31,7 +32,8 @@ class LceViewModel : ViewModel() {
/**
* Creates initial state for state-machine
*/
- private fun initStateMachine(): CommonMachineState = ItemListState()
+ private fun initStateMachine(): CommonMachineState =
+ ItemListState()
/**
* State-machine instance
@@ -48,7 +50,7 @@ class LceViewModel : ViewModel() {
* @param gesture UI gesture to proceed
*/
fun process(gesture: LceGesture) {
- Timber.d("Gesture: %s", gesture)
+ Napier.d("Gesture: ${gesture}")
stateMachine.process(gesture)
}
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ContentState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ContentState.kt
similarity index 78%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ContentState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ContentState.kt
index 92f9e4a..7a119f9 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ContentState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ContentState.kt
@@ -11,11 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
+
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
-import timber.log.Timber
/**
* Displays item details
@@ -27,7 +28,7 @@ class ContentState(private val contents: String) : LceLogicalState() {
* A part of [start] template to initialize state
*/
override fun doStart() {
- Timber.d("Displaying content...")
+ Napier.d("Displaying content...")
setUiState(LceUiState.Item(contents))
}
@@ -40,7 +41,7 @@ class ContentState(private val contents: String) : LceLogicalState() {
}
private fun onBack() {
- Timber.d("Back: returning to item list view...")
+ Napier.d("Back: returning to item list view...")
setMachineState(ItemListState())
}
}
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ErrorState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ErrorState.kt
similarity index 76%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ErrorState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ErrorState.kt
index d2173d1..4fe064b 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ErrorState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ErrorState.kt
@@ -11,12 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
+
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
-import timber.log.Timber
/**
* Item load error state
@@ -30,7 +31,7 @@ class ErrorState(private val failed: ItemId, private val error: Throwable) : Lce
* A part of [start] template to initialize state
*/
override fun doStart() {
- Timber.d("Displaying error...")
+ Napier.d("Displaying error...")
setUiState(LceUiState.Error(error))
}
@@ -45,17 +46,17 @@ class ErrorState(private val failed: ItemId, private val error: Throwable) : Lce
}
private fun onRetry() {
- Timber.d("Retry: retrying load...")
+ Napier.d("Retry: retrying load...")
setMachineState(LoadingState(failed))
}
private fun onBack() {
- Timber.d("Back: returning to item list view...")
+ Napier.d("Back: returning to item list view...")
setMachineState(ItemListState())
}
private fun onExit() {
- Timber.d("Exit: Terminating flow...")
+ Napier.d("Exit: Terminating flow...")
setMachineState(TerminatedState())
}
}
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ItemListState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListState.kt
similarity index 74%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ItemListState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListState.kt
index e4063ac..b4f3125 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/ItemListState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListState.kt
@@ -11,13 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
+
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.ItemModel
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.ItemModel
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
-import timber.log.Timber
/**
* Item list
@@ -34,7 +35,7 @@ class ItemListState : LceLogicalState() {
* A part of [start] template to initialize state
*/
override fun doStart() {
- Timber.d("Displaying item list")
+ Napier.d("Displaying item list")
setUiState(LceUiState.ItemList(items.map { ItemModel(it.first, it.second) }))
}
@@ -48,12 +49,12 @@ class ItemListState : LceLogicalState() {
}
private fun onItemClicked(id: ItemId) {
- Timber.d("Item clicked: transferring to loading...")
+ Napier.d("Item clicked: transferring to loading...")
setMachineState(LoadingState(id))
}
private fun onBack() {
- Timber.d("Back: Terminating flow...")
+ Napier.d("Back: Terminating flow...")
setMachineState(TerminatedState())
}
}
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LceLogicalState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LceLogicalState.kt
similarity index 75%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LceLogicalState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LceLogicalState.kt
index 710d22d..f2a886a 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LceLogicalState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LceLogicalState.kt
@@ -11,12 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
-import timber.log.Timber
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import io.github.aakira.napier.Napier
+
/**
* Basic flow state
@@ -26,6 +27,6 @@ abstract class LceLogicalState : CommonMachineState() {
* A part of [process] template to process UI gesture
*/
override fun doProcess(gesture: LceGesture) {
- Timber.d("Unhandled gesture: %s", gesture)
+ Napier.d("Unhandled gesture: ${gesture}")
}
}
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LoadingState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadingState.kt
similarity index 78%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LoadingState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadingState.kt
index 1202ff5..62f8e1b 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/LoadingState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadingState.kt
@@ -11,19 +11,19 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
import androidx.annotation.VisibleForTesting
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import timber.log.Timber
import java.io.IOException
/**
@@ -41,14 +41,14 @@ class LoadingState(
* A part of [start] template to initialize state
*/
override fun doStart() {
- Timber.d("Displaying spinner...")
+ Napier.d("Displaying spinner...")
setUiState(LceUiState.Loading)
load()
}
private fun load() {
stateScope.launch(defaultDispatcher) {
- Timber.d("Loading data...")
+ Napier.d("Loading data...")
delay(1000L)
withContext(Dispatchers.Main) {
when (id) {
@@ -60,12 +60,12 @@ class LoadingState(
}
private fun toContent() {
- Timber.d("Data loaded: transferring to content...")
+ Napier.d("Data loaded: transferring to content...")
setMachineState(ContentState("Some item data..."))
}
private fun toError() {
- Timber.d("Data load error: transferring to error...")
+ Napier.d("Data load error: transferring to error...")
setMachineState(ErrorState(id, IOException("Failed to load item")))
}
@@ -74,11 +74,11 @@ class LoadingState(
*/
override fun doProcess(gesture: LceGesture) = when(gesture) {
LceGesture.Back -> onBack()
- else -> Timber.d("Unhandled gesture: %s", gesture)
+ else -> Napier.d("Unhandled gesture: ${gesture}")
}
private fun onBack() {
- Timber.d("Back: returning to item view")
+ Napier.d("Back: returning to item view")
setMachineState(ItemListState())
}
}
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/TerminatedState.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/TerminatedState.kt
similarity index 80%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/TerminatedState.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/TerminatedState.kt
index 6f98d6e..44805f4 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/model/state/TerminatedState.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/TerminatedState.kt
@@ -11,10 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
+
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.lce.data.LceUiState
-import timber.log.Timber
/**
* Terminates activity
@@ -24,7 +25,7 @@ class TerminatedState : LceLogicalState() {
* A part of [start] template to initialize state
*/
override fun doStart() {
- Timber.d("Terminated")
+ Napier.d("Terminated")
setUiState(LceUiState.Terminated)
}
}
\ No newline at end of file
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/ItemContents.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/ItemContents.kt
similarity index 89%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/ui/ItemContents.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/ItemContents.kt
index 8e2a1f0..391c586 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/ItemContents.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/ItemContents.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.ui
+package com.motorro.commonstatemachine.examples.lce.ui
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
@@ -19,7 +19,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
@Composable
fun ItemDetails(state: LceUiState.Item) {
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/ItemList.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/ItemList.kt
similarity index 87%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/ui/ItemList.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/ItemList.kt
index 473756b..8fed86f 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/ItemList.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/ItemList.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.ui
+package com.motorro.commonstatemachine.examples.lce.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -26,9 +26,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.lce.R
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.R
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
@Composable
fun ItemList(state: LceUiState.ItemList, onItemClicked: (ItemId) -> Unit) {
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LceScreen.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LceScreen.kt
similarity index 83%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LceScreen.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LceScreen.kt
index a60d99c..77bc5d1 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LceScreen.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LceScreen.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.ui
+package com.motorro.commonstatemachine.examples.lce.ui
import android.annotation.SuppressLint
import androidx.activity.compose.BackHandler
@@ -32,14 +32,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.lce.R
-import com.motorro.statemachine.lce.data.LceGesture.Back
-import com.motorro.statemachine.lce.data.LceGesture.Exit
-import com.motorro.statemachine.lce.data.LceGesture.ItemClicked
-import com.motorro.statemachine.lce.data.LceGesture.Retry
-import com.motorro.statemachine.lce.data.LceUiState
-import com.motorro.statemachine.lce.model.LceViewModel
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import com.motorro.commonstatemachine.examples.lce.R
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture.Back
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture.Exit
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture.ItemClicked
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture.Retry
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.model.LceViewModel
@Composable
@OptIn(ExperimentalMaterial3Api::class)
diff --git a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LoadError.kt b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LoadError.kt
similarity index 90%
rename from examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LoadError.kt
rename to examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LoadError.kt
index f31bcc1..4a0dcfe 100644
--- a/examples/lce/src/main/java/com/motorro/statemachine/lce/ui/LoadError.kt
+++ b/examples/lce/src/main/kotlin/com/motorro/commonstatemachine/examples/lce/ui/LoadError.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.ui
+package com.motorro.commonstatemachine.examples.lce.ui
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.AlertDialog
@@ -21,8 +21,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
-import com.motorro.statemachine.lce.R
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.R
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
@Composable
fun LoadError(state: LceUiState.Error, onRetry: () -> Unit, onBack: () -> Unit, onExit: () -> Unit) {
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/ExampleUnitTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/ExampleUnitTest.kt
similarity index 94%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/ExampleUnitTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/ExampleUnitTest.kt
index e653870..32019c4 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/ExampleUnitTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/ExampleUnitTest.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce
+package com.motorro.commonstatemachine.examples.lce
import org.junit.Assert.assertEquals
import org.junit.Test
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/BaseStateTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/BaseStateTest.kt
similarity index 81%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/BaseStateTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/BaseStateTest.kt
index 11d191d..aca32f2 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/BaseStateTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/BaseStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
import io.mockk.mockk
open class BaseStateTest {
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemDetailsStateTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemDetailsStateTest.kt
similarity index 86%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemDetailsStateTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemDetailsStateTest.kt
index 30a0ccc..02ea4db 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemDetailsStateTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemDetailsStateTest.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
import io.mockk.verify
import org.junit.Test
import kotlin.test.assertIs
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemListStateTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListStateTest.kt
similarity index 84%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemListStateTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListStateTest.kt
index 0fc31ad..6bf1664 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemListStateTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemListStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
import io.mockk.verify
import org.junit.Test
import kotlin.test.assertIs
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemLoadingStateTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemLoadingStateTest.kt
similarity index 83%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemLoadingStateTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemLoadingStateTest.kt
index d04829e..6472ae0 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/ItemLoadingStateTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/ItemLoadingStateTest.kt
@@ -13,15 +13,19 @@
@file:OptIn(ExperimentalCoroutinesApi::class)
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
import io.mockk.verify
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.*
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.advanceUntilIdle
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before
import org.junit.Test
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/LoadErrorStateTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadErrorStateTest.kt
similarity index 87%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/LoadErrorStateTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadErrorStateTest.kt
index db69418..dac172c 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/LoadErrorStateTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/LoadErrorStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
-import com.motorro.statemachine.lce.data.ItemId
-import com.motorro.statemachine.lce.data.LceGesture
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.ItemId
+import com.motorro.commonstatemachine.examples.lce.data.LceGesture
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
import io.mockk.verify
import org.junit.Test
import java.io.IOException
diff --git a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/TerminatedStateTest.kt b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/TerminatedStateTest.kt
similarity index 87%
rename from examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/TerminatedStateTest.kt
rename to examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/TerminatedStateTest.kt
index 85ef3cf..0df0ad8 100644
--- a/examples/lce/src/test/java/com/motorro/statemachine/lce/model/state/TerminatedStateTest.kt
+++ b/examples/lce/src/test/kotlin/com/motorro/commonstatemachine/examples/lce/model/state/TerminatedStateTest.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lce.model.state
+package com.motorro.commonstatemachine.examples.lce.model.state
-import com.motorro.statemachine.lce.data.LceUiState
+import com.motorro.commonstatemachine.examples.lce.data.LceUiState
import io.mockk.verify
import org.junit.Test
diff --git a/examples/lifecycle/build.gradle.kts b/examples/lifecycle/build.gradle.kts
index 38a0b36..312fd51 100644
--- a/examples/lifecycle/build.gradle.kts
+++ b/examples/lifecycle/build.gradle.kts
@@ -1,8 +1,3 @@
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-
/*
* Copyright 2026 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,60 +12,7 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.app)
- alias(libs.plugins.compose)
-}
-
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- namespace = "com.motorro.statemachine.lifecycle"
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.lifecycle"
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
- versionCode = versionCode
- versionName = versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
+ alias(libs.plugins.motorro.android.app)
}
dependencies {
@@ -78,32 +20,7 @@ dependencies {
implementation(project(":coroutines"))
implementation(project(":lifecycle"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:timer"))
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- val composeBom = platform(libs.compose.bom)
- implementation(composeBom)
- androidTestImplementation(composeBom)
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
testImplementation(libs.test.androidx.arch)
- testImplementation(libs.test.kotlin.coroutines)
}
\ No newline at end of file
diff --git a/examples/lifecycle/src/main/AndroidManifest.xml b/examples/lifecycle/src/main/AndroidManifest.xml
index 5e83929..96b177b 100644
--- a/examples/lifecycle/src/main/AndroidManifest.xml
+++ b/examples/lifecycle/src/main/AndroidManifest.xml
@@ -20,10 +20,10 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:name="com.motorro.statemachine.lifecycle.App"
+ android:name="com.motorro.commonstatemachine.examples.lifecycle.App"
android:theme="@style/Theme.CommonStateMachine">
diff --git a/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/App.kt b/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/App.kt
deleted file mode 100644
index 5624198..0000000
--- a/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/App.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.lifecycle
-
-import android.app.Application
-import timber.log.Timber
-
-class App : Application() {
- override fun onCreate() {
- super.onCreate()
- setupLogger()
- }
-
- private fun setupLogger() {
- Timber.plant(Timber.DebugTree())
- }
-}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/App.kt b/examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/App.kt
similarity index 81%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/App.kt
rename to examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/App.kt
index 889e383..74c38ff 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/App.kt
+++ b/examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/App.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine
+package com.motorro.commonstatemachine.examples.lifecycle
import android.app.Application
-import dagger.hilt.android.HiltAndroidApp
-import timber.log.Timber
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+
-@HiltAndroidApp
class App : Application() {
override fun onCreate() {
super.onCreate()
@@ -25,6 +25,6 @@ class App : Application() {
}
private fun setupLogger() {
- Timber.plant(Timber.DebugTree())
+ Napier.base(DebugAntilog())
}
}
\ No newline at end of file
diff --git a/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/MainActivity.kt b/examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/MainActivity.kt
similarity index 87%
rename from examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/MainActivity.kt
rename to examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/MainActivity.kt
index d8f6c51..c4934b6 100644
--- a/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/MainActivity.kt
+++ b/examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/MainActivity.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.lifecycle
+package com.motorro.commonstatemachine.examples.lifecycle
import android.os.Bundle
import androidx.activity.ComponentActivity
@@ -24,9 +24,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.viewmodel.compose.viewModel
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.lifecycle.model.MainViewModel
-import com.motorro.statemachine.timer.ui.TimerScreen
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import com.motorro.commonstatemachine.examples.lifecycle.model.MainViewModel
+import com.motorro.commonstatemachine.examples.timer.ui.TimerScreen
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
diff --git a/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/model/MainViewModel.kt b/examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/model/MainViewModel.kt
similarity index 81%
rename from examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/model/MainViewModel.kt
rename to examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/model/MainViewModel.kt
index 3003d34..70c0bd9 100644
--- a/examples/lifecycle/src/main/java/com/motorro/statemachine/lifecycle/model/MainViewModel.kt
+++ b/examples/lifecycle/src/main/kotlin/com/motorro/commonstatemachine/examples/lifecycle/model/MainViewModel.kt
@@ -1,13 +1,13 @@
-package com.motorro.statemachine.lifecycle.model
+package com.motorro.commonstatemachine.examples.lifecycle.model
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModel
import com.motorro.commonstatemachine.coroutines.FlowStateMachine
+import com.motorro.commonstatemachine.examples.timer.data.TimerGesture
+import com.motorro.commonstatemachine.examples.timer.data.TimerUiState
+import com.motorro.commonstatemachine.examples.timer.state.TimerState
import com.motorro.commonstatemachine.lifecycle.UiMachineLifecycle
import com.motorro.commonstatemachine.lifecycle.UiMachineLifecycle.Companion.bindLifecycle
-import com.motorro.statemachine.timer.data.TimerGesture
-import com.motorro.statemachine.timer.data.TimerUiState
-import com.motorro.statemachine.timer.state.TimerState
import kotlinx.coroutines.flow.StateFlow
import kotlin.time.Duration
diff --git a/examples/multi/mixed/build.gradle.kts b/examples/multi/mixed/build.gradle.kts
index 712270d..e3295b6 100644
--- a/examples/multi/mixed/build.gradle.kts
+++ b/examples/multi/mixed/build.gradle.kts
@@ -1,8 +1,3 @@
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-
/*
* Copyright 2023 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,92 +12,12 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.app)
- alias(libs.plugins.compose)
-}
-
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- namespace = "com.motorro.statemachine.multi.mixed"
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.multi.mixed"
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
- versionCode = versionCode
- versionName = versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
+ alias(libs.plugins.motorro.android.app)
}
dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":coroutines"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:timer"))
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- val composeBom = platform(libs.compose.bom)
- implementation(composeBom)
- androidTestImplementation(composeBom)
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.androidx.arch)
- testImplementation(libs.test.kotlin.coroutines)
}
\ No newline at end of file
diff --git a/examples/multi/mixed/src/main/AndroidManifest.xml b/examples/multi/mixed/src/main/AndroidManifest.xml
index dff16cc..9986708 100644
--- a/examples/multi/mixed/src/main/AndroidManifest.xml
+++ b/examples/multi/mixed/src/main/AndroidManifest.xml
@@ -21,10 +21,10 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:name="com.motorro.statemachine.mixed.App"
+ android:name="com.motorro.commonstatemachine.examples.mixed.App"
android:theme="@style/Theme.CommonStateMachine">
diff --git a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/App.kt b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/App.kt
similarity index 81%
rename from examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/App.kt
rename to examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/App.kt
index d0a9593..b3646ea 100644
--- a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/App.kt
+++ b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/App.kt
@@ -11,10 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.navbar
+package com.motorro.commonstatemachine.examples.navbar
import android.app.Application
-import timber.log.Timber
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+
class App : Application() {
override fun onCreate() {
@@ -23,6 +25,6 @@ class App : Application() {
}
private fun setupLogger() {
- Timber.plant(Timber.DebugTree())
+ Napier.base(DebugAntilog())
}
}
\ No newline at end of file
diff --git a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/MainActivity.kt b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/MainActivity.kt
similarity index 93%
rename from examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/MainActivity.kt
rename to examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/MainActivity.kt
index 8adcbed..160de42 100644
--- a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/MainActivity.kt
+++ b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/MainActivity.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.navbar
+package com.motorro.commonstatemachine.examples.navbar
import android.content.ComponentCallbacks2
import android.os.Bundle
@@ -45,10 +45,10 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.navbar.model.MainViewModel
-import com.motorro.statemachine.navbar.model.data.NavbarGesture
-import com.motorro.statemachine.timer.ui.TimerScreen
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import com.motorro.commonstatemachine.examples.navbar.model.MainViewModel
+import com.motorro.commonstatemachine.examples.navbar.model.data.NavbarGesture
+import com.motorro.commonstatemachine.examples.timer.ui.TimerScreen
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity(), ComponentCallbacks2 {
diff --git a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/MainViewModel.kt b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/MainViewModel.kt
similarity index 78%
rename from examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/MainViewModel.kt
rename to examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/MainViewModel.kt
index 03754c4..a021ad6 100644
--- a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/MainViewModel.kt
+++ b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/MainViewModel.kt
@@ -11,13 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.navbar.model
+package com.motorro.commonstatemachine.examples.navbar.model
import androidx.lifecycle.ViewModel
import com.motorro.commonstatemachine.coroutines.FlowStateMachine
-import com.motorro.statemachine.navbar.model.data.NavbarGesture
-import com.motorro.statemachine.navbar.model.data.NavbarUiState
-import com.motorro.statemachine.navbar.model.state.NavbarState
+import com.motorro.commonstatemachine.examples.navbar.model.data.NavbarGesture
+import com.motorro.commonstatemachine.examples.navbar.model.data.NavbarUiState
+import com.motorro.commonstatemachine.examples.navbar.model.state.NavbarState
import kotlinx.coroutines.flow.StateFlow
class MainViewModel : ViewModel() {
diff --git a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/data/NavbarGesture.kt b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/data/NavbarGesture.kt
similarity index 82%
rename from examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/data/NavbarGesture.kt
rename to examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/data/NavbarGesture.kt
index b501208..23f2776 100644
--- a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/data/NavbarGesture.kt
+++ b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/data/NavbarGesture.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.navbar.model.data
+package com.motorro.commonstatemachine.examples.navbar.model.data
-import com.motorro.statemachine.timer.data.TimerGesture
-import com.motorro.statemachine.timer.data.TimerKey
+import com.motorro.commonstatemachine.examples.timer.data.TimerGesture
+import com.motorro.commonstatemachine.examples.timer.data.TimerKey
/**
* Application gestures
diff --git a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/data/NavbarUiState.kt b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/data/NavbarUiState.kt
similarity index 80%
rename from examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/data/NavbarUiState.kt
rename to examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/data/NavbarUiState.kt
index dcc91ce..09c4f21 100644
--- a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/data/NavbarUiState.kt
+++ b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/data/NavbarUiState.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.navbar.model.data
+package com.motorro.commonstatemachine.examples.navbar.model.data
import androidx.compose.runtime.Immutable
+import com.motorro.commonstatemachine.examples.timer.data.TimerKey
+import com.motorro.commonstatemachine.examples.timer.data.TimerUiState
import com.motorro.commonstatemachine.multi.MachineKey
-import com.motorro.statemachine.timer.data.TimerKey
-import com.motorro.statemachine.timer.data.TimerUiState
/**
* Common state for all active machines
diff --git a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/state/NavbarState.kt b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/state/NavbarState.kt
similarity index 86%
rename from examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/state/NavbarState.kt
rename to examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/state/NavbarState.kt
index 3e27426..38c631e 100644
--- a/examples/multi/navbar/src/main/java/com/motorro/statemachine/navbar/model/state/NavbarState.kt
+++ b/examples/multi/navbar/src/main/kotlin/com/motorro/commonstatemachine/examples/navbar/model/state/NavbarState.kt
@@ -11,9 +11,16 @@
* limitations under the License.
*/
-package com.motorro.statemachine.navbar.model.state
+package com.motorro.commonstatemachine.examples.navbar.model.state
import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.navbar.model.data.NavbarGesture
+import com.motorro.commonstatemachine.examples.navbar.model.data.NavbarUiState
+import com.motorro.commonstatemachine.examples.timer.data.TimerGesture
+import com.motorro.commonstatemachine.examples.timer.data.TimerKey
+import com.motorro.commonstatemachine.examples.timer.data.TimerUiState
+import com.motorro.commonstatemachine.examples.timer.state.TimerState
import com.motorro.commonstatemachine.lifecycle.MachineLifecycle
import com.motorro.commonstatemachine.multi.ActiveMachineContainer
import com.motorro.commonstatemachine.multi.GestureProcessor
@@ -22,13 +29,6 @@ import com.motorro.commonstatemachine.multi.MachineKey
import com.motorro.commonstatemachine.multi.MultiMachineState
import com.motorro.commonstatemachine.multi.ProxyMachineContainer
import com.motorro.commonstatemachine.multi.UiStateProvider
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.navbar.model.data.NavbarGesture
-import com.motorro.statemachine.navbar.model.data.NavbarUiState
-import com.motorro.statemachine.timer.data.TimerGesture
-import com.motorro.statemachine.timer.data.TimerKey
-import com.motorro.statemachine.timer.data.TimerUiState
-import com.motorro.statemachine.timer.state.TimerState
import kotlin.time.Duration
/**
diff --git a/examples/multi/parallel/build.gradle.kts b/examples/multi/parallel/build.gradle.kts
index 9754e7d..e3295b6 100644
--- a/examples/multi/parallel/build.gradle.kts
+++ b/examples/multi/parallel/build.gradle.kts
@@ -1,8 +1,3 @@
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-
/*
* Copyright 2023 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,92 +12,12 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.app)
- alias(libs.plugins.compose)
-}
-
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- namespace = "com.motorro.statemachine.multi.parallel"
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- applicationId = "com.motorro.statemachine.multi.parallel"
- minSdk = androidMinSdkVersion
- targetSdk = androidTargetSdkVersion
- versionCode = versionCode
- versionName = versionName
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(
- getDefaultProguardFile("proguard-android-optimize.txt"),
- "proguard-rules.pro"
- )
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
+ alias(libs.plugins.motorro.android.app)
}
dependencies {
implementation(project(":commonstatemachine"))
implementation(project(":coroutines"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
implementation(project(":examples:timer"))
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.androidx.core)
- implementation(libs.androidx.lifecycle.runtime)
- implementation(libs.androidx.lifecycle.livedata)
- implementation(libs.androidx.lifecycle.viewmodel)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- val composeBom = platform(libs.compose.bom)
- implementation(composeBom)
- androidTestImplementation(composeBom)
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.androidx.arch)
- testImplementation(libs.test.kotlin.coroutines)
}
\ No newline at end of file
diff --git a/examples/multi/parallel/src/main/AndroidManifest.xml b/examples/multi/parallel/src/main/AndroidManifest.xml
index a87bdae..d3ff5fc 100644
--- a/examples/multi/parallel/src/main/AndroidManifest.xml
+++ b/examples/multi/parallel/src/main/AndroidManifest.xml
@@ -21,10 +21,10 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:name="com.motorro.statemachine.parallel.App"
+ android:name="com.motorro.commonstatemachine.examples.parallel.App"
android:theme="@style/Theme.CommonStateMachine">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/App.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/App.kt
new file mode 100644
index 0000000..2aea628
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/App.kt
@@ -0,0 +1,30 @@
+package com.motorro.commonstatemachine.examples.skills.app
+
+import android.app.Application
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.AuthModule
+import com.motorro.commonstatemachine.skills.usecase.UsecaseModule
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.annotation.KoinApplication
+import org.koin.plugin.module.dsl.startKoin
+
+@KoinApplication(modules = [
+ UsecaseModule::class,
+ AuthModule::class,
+ MainModule::class
+])
+class App : Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ Napier.base(DebugAntilog())
+
+ startKoin {
+ allowOverride(false)
+ androidLogger()
+ androidContext(this@App)
+ }
+ }
+}
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainActivity.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainActivity.kt
new file mode 100644
index 0000000..d8d6ccf
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainActivity.kt
@@ -0,0 +1,23 @@
+package com.motorro.commonstatemachine.examples.skills.app
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.SkillsTheme
+import com.motorro.commonstatemachine.examples.skills.app.ui.MainScreen
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+ SkillsTheme {
+ MainScreen {
+ finish()
+ }
+ }
+ }
+ }
+}
+
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainModule.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainModule.kt
new file mode 100644
index 0000000..9f15aa7
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainModule.kt
@@ -0,0 +1,8 @@
+package com.motorro.commonstatemachine.examples.skills.app
+
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+
+@Module
+@ComponentScan("com.motorro.commonstatemachine.examples.skills.app")
+internal class MainModule
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainViewModel.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainViewModel.kt
new file mode 100644
index 0000000..000ebb7
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/MainViewModel.kt
@@ -0,0 +1,32 @@
+package com.motorro.commonstatemachine.examples.skills.app
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.skills.app.state.MainStateFactory
+import com.motorro.commonstatemachine.flow.data.CommonFlowDataApi
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.KoinViewModel
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.parameter.parametersOf
+
+@KoinViewModel
+internal class MainViewModel(api: MainApi) : CommonFlowViewModel(
+ api = api,
+ init = Unit
+)
+
+@Factory
+internal class MainApi : CommonFlowDataApi, KoinComponent {
+ override fun init(flowHost: CommonFlowHost, input: Unit): CommonMachineState {
+ val factory = this@MainApi.get {
+ parametersOf(flowHost)
+ }
+ return factory.auth()
+ }
+ override fun getDefaultUiState(): MainUiState = MainUiState.Splash
+ override fun getBackGesture(): MainGesture = MainGesture.Back
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/data/MainGesture.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/data/MainGesture.kt
new file mode 100644
index 0000000..8126794
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/data/MainGesture.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.data
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+
+/**
+ * Main flow gesture
+ */
+internal sealed class MainGesture {
+
+ object Back : MainGesture()
+
+ data class Auth(val child: AuthGesture) : MainGesture()
+}
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/data/MainUiState.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/data/MainUiState.kt
new file mode 100644
index 0000000..c25ca24
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/data/MainUiState.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.data
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+
+
+internal sealed class MainUiState {
+ /**
+ * Preloading
+ */
+ data object Splash : MainUiState()
+
+ /**
+ * Authentication
+ */
+ data class Auth(val child: AuthUiState) : MainUiState()
+
+ /**
+ * Content placeholder
+ */
+ data object Friends : MainUiState()
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/AuthProxyState.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/AuthProxyState.kt
new file mode 100644
index 0000000..9f1bcd1
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/AuthProxyState.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.ProxyMachineState
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+
+internal class AuthProxyState(
+ private val context: MainContext,
+ private val requireAuthentication: Boolean,
+ private val api: AuthDataApi
+) : ProxyMachineState(api.getDefaultUiState()) {
+
+ private val flowHost = CommonFlowHost { result ->
+ if (result.authenticated) {
+ Napier.d { "Authenticated. Checking..." }
+ setMachineState(context.factory.init())
+ } else {
+ Napier.d { "Authentication cancelled. Terminating..." }
+ setMachineState(context.factory.terminated())
+ }
+ }
+
+ override fun init() = api.init(flowHost, AuthInput(requireAuthentication.not()))
+
+ override fun mapGesture(parent: MainGesture): AuthGesture? = when (parent) {
+ is MainGesture.Auth -> parent.child
+ MainGesture.Back -> api.getBackGesture()
+ }
+
+ override fun mapUiState(child: AuthUiState): MainUiState = MainUiState.Auth(child)
+
+ @Factory
+ class StateFactory(private val api: AuthDataApi) {
+ fun create(context: MainContext) = AuthProxyState(
+ context = context,
+ requireAuthentication = true,
+ api = api
+ )
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/CheckingAuthentication.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/CheckingAuthentication.kt
new file mode 100644
index 0000000..713e591
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/CheckingAuthentication.kt
@@ -0,0 +1,52 @@
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.skills.domain.session.SessionManager
+import com.motorro.commonstatemachine.skills.domain.session.data.Session
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.launch
+import org.koin.core.annotation.Factory
+
+internal class CheckingAuthentication(
+ context: MainContext,
+ private val sessionManager: SessionManager
+) : BaseMainState(context) {
+ override fun doStart() {
+ setUiState(renderer.renderSplash())
+ checkAuthentication()
+ }
+
+ private fun checkAuthentication() = stateScope.launch {
+ Napier.d { "Checking current session..." }
+ when(sessionManager.session.catch { emit(Session.None) }.first()) {
+ is Session.Active -> {
+ Napier.d { "Authenticated. Transferring to content..." }
+ setMachineState(factory.content())
+ }
+ Session.None -> {
+ Napier.d { "No active user. Requiring authentication..." }
+ setMachineState(factory.auth())
+ }
+ }
+ }
+
+ override fun doProcess(gesture: MainGesture) {
+ when(gesture) {
+ is MainGesture.Back -> {
+ Napier.d { "Back requested. Terminating..." }
+ setMachineState(factory.terminated())
+ }
+ else -> super.doProcess(gesture)
+ }
+ }
+
+ @Factory
+ class StateFactory(private val sessionManager: SessionManager) {
+ fun create(context: MainContext) = CheckingAuthentication(
+ context = context,
+ sessionManager = sessionManager
+ )
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/ContentState.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/ContentState.kt
new file mode 100644
index 0000000..6d22d89
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/ContentState.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+
+/**
+ * Content stub
+ */
+internal class ContentState(context: MainContext) : BaseMainState(context) {
+ override fun doStart() {
+ setUiState(renderer.renderContent())
+ }
+
+ override fun doProcess(gesture: MainGesture) {
+ when (gesture) {
+ MainGesture.Back -> {
+ Napier.d("Back. Terminating...")
+ setMachineState(factory.terminated())
+ }
+ else -> super.doProcess(gesture)
+ }
+ }
+
+ @Factory
+ class StateFactory() {
+ fun create(context: MainContext) = ContentState(
+ context
+ )
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainContext.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainContext.kt
new file mode 100644
index 0000000..d92d16a
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainContext.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.examples.skills.app.ui.MainUiRenderer
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+
+/**
+ * Main flow context
+ */
+internal interface MainContext {
+ /**
+ * Main flow host
+ */
+ val flowHost: CommonFlowHost
+
+ /**
+ * State factory
+ */
+ val factory: MainStateFactory
+
+ /**
+ * UI renderer
+ */
+ val renderer: MainUiRenderer
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainState.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainState.kt
new file mode 100644
index 0000000..140d336
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainState.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.coroutines.CoroutineState
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import io.github.aakira.napier.Napier
+
+internal typealias MainState = CommonMachineState
+
+internal abstract class BaseMainState(context: MainContext) : CoroutineState(), MainContext by context {
+ override fun doProcess(gesture: MainGesture) {
+ Napier.w("Unhandled gesture: $gesture")
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainStateFactory.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainStateFactory.kt
new file mode 100644
index 0000000..5b5d987
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/MainStateFactory.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.examples.skills.app.ui.MainUiRenderer
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.InjectedParam
+
+/**
+ * Main state factory
+ */
+internal interface MainStateFactory {
+ fun init(): MainState
+ fun auth(): MainState
+ fun content(): MainState
+ fun terminated(): MainState
+
+ @Factory
+ class Impl(
+ @InjectedParam flowHost: CommonFlowHost,
+ renderer: MainUiRenderer,
+ private val checkingAuthenticationFactory: CheckingAuthentication.StateFactory,
+ private val contentFactory: ContentState.StateFactory,
+ private val authFactory: AuthProxyState.StateFactory
+ ) : MainStateFactory {
+
+ private val context = object : MainContext {
+ override val flowHost: CommonFlowHost = flowHost
+ override val factory: MainStateFactory get() = this@Impl
+ override val renderer: MainUiRenderer = renderer
+ }
+
+ override fun init() = checkingAuthenticationFactory.create(context)
+
+ override fun auth() = authFactory.create(context)
+
+ override fun content() = contentFactory.create(context)
+
+ override fun terminated() = object : MainState() {
+ override fun doStart() {
+ context.flowHost.onComplete(Unit)
+ }
+ }
+ }
+}
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/ui/MainScreen.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/ui/MainScreen.kt
new file mode 100644
index 0000000..566c749
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/ui/MainScreen.kt
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.app.ui
+
+import androidx.activity.compose.BackHandler
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextAlign
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.design.SkillsAppBar
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.design.SkillsLoading
+import com.motorro.commonstatemachine.examples.skills.app.MainViewModel
+import com.motorro.commonstatemachine.examples.skills.app.R
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiApi
+import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowComposition
+import io.github.aakira.napier.Napier
+import org.koin.compose.koinInject
+import org.koin.compose.viewmodel.koinViewModel
+
+@Composable
+internal fun MainScreen(onTerminated: () -> Unit) {
+ val viewModel: MainViewModel = koinViewModel()
+
+ CommonFlowComposition(
+ viewModel = viewModel,
+ navigationBackHandler = { enabled, onBack ->
+ BackHandler(enabled, onBack)
+ },
+ finish = {
+ Napier.i { "Finished with: $it" }
+ onTerminated()
+ },
+ content = { state, onGesture ->
+ when(state) {
+ is MainUiState.Splash -> SplashScreen()
+ is MainUiState.Auth -> {
+ val onAuthGesture = remember {
+ { child: AuthGesture -> onGesture(MainGesture.Auth(child)) }
+ }
+ AuthScreen(state = state, onGesture = onAuthGesture)
+ }
+ MainUiState.Friends -> ContentScreen()
+ }
+ }
+ )
+}
+
+@Composable
+private fun AuthScreen(
+ state: MainUiState.Auth,
+ onGesture: (AuthGesture) -> Unit
+) {
+ val uiApi: AuthUiApi = koinInject()
+ Scaffold(
+ topBar = {
+ SkillsAppBar(
+ title = stringResource(R.string.app_name),
+ topLevel = true
+ )
+ },
+ content = { paddingValues ->
+ uiApi.Screen(
+ state = state.child,
+ onGesture = onGesture,
+ modifier = Modifier.padding(paddingValues)
+ )
+ }
+ )
+}
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+private fun SplashScreen() {
+ Scaffold(
+ topBar = {
+ SkillsAppBar(
+ title = stringResource(R.string.app_name),
+ topLevel = true
+ )
+ },
+ content = { paddingValues ->
+ SkillsLoading(Modifier.padding(paddingValues))
+ }
+ )
+}
+
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+private fun ContentScreen() {
+ Scaffold(
+ topBar = {
+ SkillsAppBar(
+ title = stringResource(R.string.app_name),
+ topLevel = true
+ )
+ },
+ content = { paddingValues ->
+ Box(modifier = Modifier.padding(paddingValues).fillMaxSize(), contentAlignment = Alignment.Center) {
+ Text(
+ modifier = Modifier.fillMaxWidth(),
+ textAlign = TextAlign.Center,
+ text = "Friends placeholder"
+ )
+ }
+ }
+ )
+}
diff --git a/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/ui/MainUiRenderer.kt b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/ui/MainUiRenderer.kt
new file mode 100644
index 0000000..97c4bf4
--- /dev/null
+++ b/examples/skills/app/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/app/ui/MainUiRenderer.kt
@@ -0,0 +1,23 @@
+package com.motorro.commonstatemachine.examples.skills.app.ui
+
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+import org.koin.core.annotation.Factory
+
+/**
+ * Main UI renderer
+ */
+internal interface MainUiRenderer {
+ fun renderSplash(): MainUiState
+ fun renderAuth(child: AuthUiState): MainUiState
+ fun renderContent(): MainUiState
+
+ @Factory
+ class Impl : MainUiRenderer {
+ override fun renderSplash() = MainUiState.Splash
+
+ override fun renderAuth(child: AuthUiState) = MainUiState.Auth(child)
+
+ override fun renderContent(): MainUiState = MainUiState.Friends
+ }
+}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/skills/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/drawable-v24/ic_launcher_foreground.xml
rename to examples/skills/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
diff --git a/examples/welcome/welcome/src/main/res/drawable/ic_launcher_background.xml b/examples/skills/app/src/main/res/drawable/ic_launcher_background.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/drawable/ic_launcher_background.xml
rename to examples/skills/app/src/main/res/drawable/ic_launcher_background.xml
diff --git a/examples/welcome/welcome/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/skills/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to examples/skills/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/examples/welcome/welcome/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/skills/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to examples/skills/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
diff --git a/examples/welcome/welcome/src/main/res/mipmap-hdpi/ic_launcher.webp b/examples/skills/app/src/main/res/mipmap-hdpi/ic_launcher.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-hdpi/ic_launcher.webp
rename to examples/skills/app/src/main/res/mipmap-hdpi/ic_launcher.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/examples/skills/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-hdpi/ic_launcher_round.webp
rename to examples/skills/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-mdpi/ic_launcher.webp b/examples/skills/app/src/main/res/mipmap-mdpi/ic_launcher.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-mdpi/ic_launcher.webp
rename to examples/skills/app/src/main/res/mipmap-mdpi/ic_launcher.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/examples/skills/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-mdpi/ic_launcher_round.webp
rename to examples/skills/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-xhdpi/ic_launcher.webp b/examples/skills/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-xhdpi/ic_launcher.webp
rename to examples/skills/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/examples/skills/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
rename to examples/skills/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/examples/skills/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-xxhdpi/ic_launcher.webp
rename to examples/skills/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/examples/skills/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
rename to examples/skills/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/examples/skills/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
rename to examples/skills/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
diff --git a/examples/welcome/welcome/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/examples/skills/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
similarity index 100%
rename from examples/welcome/welcome/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
rename to examples/skills/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
diff --git a/examples/skills/app/src/main/res/values/strings.xml b/examples/skills/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..d945175
--- /dev/null
+++ b/examples/skills/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Skills app
+
\ No newline at end of file
diff --git a/examples/skills/app/src/main/res/xml/backup_rules.xml b/examples/skills/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/examples/skills/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/app/src/main/res/xml/data_extraction_rules.xml b/examples/skills/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/examples/skills/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/app/src/main/res/xml/network_security_config.xml b/examples/skills/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..c64cff3
--- /dev/null
+++ b/examples/skills/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+ 10.0.2.2
+
+
diff --git a/examples/skills/app/src/test/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/BaseStateTest.kt b/examples/skills/app/src/test/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/BaseStateTest.kt
new file mode 100644
index 0000000..7f686a3
--- /dev/null
+++ b/examples/skills/app/src/test/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/BaseStateTest.kt
@@ -0,0 +1,61 @@
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.CommonStateMachine
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import com.motorro.commonstatemachine.examples.skills.app.ui.MainUiRenderer
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import io.mockk.mockk
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+
+@OptIn(ExperimentalCoroutinesApi::class)
+internal abstract class BaseStateTest {
+ protected lateinit var stateMachine: CommonStateMachine
+ protected lateinit var stateFactory: MainStateFactory
+ protected lateinit var renderer: MainUiRenderer
+ protected lateinit var context: MainContext
+ protected lateinit var flowHost: CommonFlowHost
+ protected lateinit var nextState: MainState
+ protected lateinit var dispatcher: TestDispatcher
+
+ @Before
+ fun init() {
+ dispatcher = UnconfinedTestDispatcher()
+ Dispatchers.setMain(dispatcher)
+
+ stateMachine = mockk(relaxed = true)
+ stateFactory = mockk()
+ flowHost = mockk(relaxed = true)
+ renderer = mockk()
+ nextState = MainState()
+
+ context = object : MainContext {
+ override val factory: MainStateFactory = this@BaseStateTest.stateFactory
+ override val flowHost: CommonFlowHost = this@BaseStateTest.flowHost
+ override val renderer: MainUiRenderer = this@BaseStateTest.renderer
+ }
+
+ doInit()
+ }
+
+ @After
+ fun deinit() {
+ Dispatchers.resetMain()
+ }
+
+ protected fun test(block: TestScope.() -> Unit) = runTest(
+ dispatcher,
+ testBody = block
+ )
+
+ protected open fun doInit() = Unit
+}
\ No newline at end of file
diff --git a/examples/skills/app/src/test/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/CheckingAuthenticationTest.kt b/examples/skills/app/src/test/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/CheckingAuthenticationTest.kt
new file mode 100644
index 0000000..8aae00c
--- /dev/null
+++ b/examples/skills/app/src/test/kotlin/com/motorro/commonstatemachine/examples/skills/app/state/CheckingAuthenticationTest.kt
@@ -0,0 +1,104 @@
+package com.motorro.commonstatemachine.examples.skills.app.state
+
+import com.motorro.commonstatemachine.examples.skills.app.data.MainGesture
+import com.motorro.commonstatemachine.examples.skills.app.data.MainUiState
+import com.motorro.commonstatemachine.skills.domain.session.SessionManager
+import com.motorro.commonstatemachine.skills.domain.session.data.Session
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.suspendCancellableCoroutine
+import org.junit.Test
+
+internal class CheckingAuthenticationTest : BaseStateTest() {
+ private lateinit var sessionManager: SessionManager
+ private lateinit var state: CheckingAuthentication
+
+ private fun createState(sessionFlow: Flow) {
+ sessionManager = mockk {
+ every { session } returns sessionFlow
+ }
+ state = CheckingAuthentication(context, sessionManager)
+ }
+
+ @Test
+ fun displaysSplashOnStart() = test {
+ createState(flowOf(Session.None))
+ every { renderer.renderSplash() } returns MainUiState.Splash
+ every { stateFactory.auth() } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ renderer.renderSplash()
+ stateMachine.setUiState(MainUiState.Splash)
+ }
+ }
+
+ @Test
+ fun transfersToContentWhenAuthenticated() = test {
+ createState(flowOf(Session.Active(Username("user"))))
+ every { renderer.renderSplash() } returns MainUiState.Splash
+ every { stateFactory.content() } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.content()
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun transfersToAuthWhenNotAuthenticated() = test {
+ createState(flowOf(Session.None))
+ every { renderer.renderSplash() } returns MainUiState.Splash
+ every { stateFactory.auth() } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.auth()
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun transfersToAuthOnSessionError() = test {
+ createState(flow { throw RuntimeException("Error") })
+ every { renderer.renderSplash() } returns MainUiState.Splash
+ every { stateFactory.auth() } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.auth()
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun terminatesOnBack() = test {
+ createState(
+ flow {
+ suspendCancellableCoroutine {
+ // No-op
+ }
+ }
+ )
+ every { renderer.renderSplash() } returns MainUiState.Splash
+ every { stateFactory.terminated() } returns nextState
+
+ state.start(stateMachine)
+ state.process(MainGesture.Back)
+
+ verify {
+ stateFactory.terminated()
+ stateMachine.setMachineState(nextState)
+ }
+ }
+}
diff --git a/examples/skills/appcore/build.gradle.kts b/examples/skills/appcore/build.gradle.kts
new file mode 100644
index 0000000..f509912
--- /dev/null
+++ b/examples/skills/appcore/build.gradle.kts
@@ -0,0 +1,28 @@
+/*
+* Copyright 2023 Nikolai Kotchetkov.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* 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.
+*/
+
+plugins {
+ alias(libs.plugins.motorro.cmp)
+}
+
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ api(libs.compose.multiplatform.icons)
+ implementation(libs.compose.multiplatform.navigationevent)
+ implementation(libs.compose.multiplatform.preview)
+ }
+ }
+}
+
+
diff --git a/examples/skills/appcore/consumer-rules.pro b/examples/skills/appcore/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/skills/appcore/src/commonMain/composeResources/values/strings.xml b/examples/skills/appcore/src/commonMain/composeResources/values/strings.xml
new file mode 100644
index 0000000..182a3b9
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/composeResources/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Back
+
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/design/SkillsAppBar.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/design/SkillsAppBar.kt
new file mode 100644
index 0000000..e2223e4
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/design/SkillsAppBar.kt
@@ -0,0 +1,99 @@
+package com.motorro.commonstatemachine.examples.auth.appcore.ui.design
+
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.rounded.AddCircle
+import androidx.compose.material.icons.rounded.Call
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import androidx.navigationevent.NavigationEventInfo
+import androidx.navigationevent.compose.NavigationBackHandler
+import androidx.navigationevent.compose.rememberNavigationEventState
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.preview.SkillsPreviewComposition
+import com.motorro.commonstatemachine.examples.skills.appcore.Res
+import com.motorro.commonstatemachine.examples.skills.appcore.btn_back
+import org.jetbrains.compose.resources.stringResource
+
+/**
+ * Common top bar sample
+ */
+@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+fun SkillsAppBar(
+ title: String,
+ modifier: Modifier = Modifier,
+ topLevel: Boolean = true,
+ actions: @Composable RowScope.() -> Unit = { },
+ onBack: () -> Unit = { }
+) {
+ NavigationBackHandler(
+ state = rememberNavigationEventState(
+ currentInfo = NavigationEventInfo.None
+ ),
+ isBackEnabled = topLevel.not(),
+ onBackCompleted = onBack
+ )
+
+ TopAppBar(
+ title = { Text(title) },
+ modifier = modifier,
+ navigationIcon = {
+ if (topLevel.not()) {
+ IconButton(onClick = onBack) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Filled.ArrowBack,
+ contentDescription = stringResource(Res.string.btn_back)
+ )
+ }
+ }
+ },
+ actions = actions
+ )
+}
+
+
+private data class AppBarData(val title: String, val topLevel: Boolean = false, val actions: List = emptyList())
+
+private class AppBarDataProvider : PreviewParameterProvider {
+ override val values: Sequence = sequenceOf(
+ AppBarData("Top Level", topLevel = true),
+ AppBarData("Top Level Actions", topLevel = true, listOf(
+ Icons.Rounded.AddCircle,
+ Icons.Rounded.Call
+ )),
+ AppBarData("Inner", topLevel = false),
+ AppBarData("Inner Actions", topLevel = false, listOf(
+ Icons.Rounded.AddCircle,
+ Icons.Rounded.Call
+ ))
+ )
+}
+
+@Preview
+@Composable
+private fun SkillsScreenPreview(@PreviewParameter(AppBarDataProvider::class) data: AppBarData?) {
+ if (null == data) return
+ SkillsPreviewComposition {
+ SkillsAppBar(
+ title = data.title,
+ topLevel = data.topLevel,
+ actions = {
+ data.actions.forEach {
+ IconButton(onClick = {}) {
+ Icon(it, null)
+ }
+ }
+ }
+ )
+ }
+}
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/design/SkillsLoading.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/design/SkillsLoading.kt
new file mode 100644
index 0000000..fe1010f
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/design/SkillsLoading.kt
@@ -0,0 +1,15 @@
+package com.motorro.commonstatemachine.examples.auth.appcore.ui.design
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+
+@Composable
+fun SkillsLoading(modifier: Modifier = Modifier) {
+ Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
+ CircularProgressIndicator()
+ }
+}
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/preview/SkillsPreviewComposition.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/preview/SkillsPreviewComposition.kt
new file mode 100644
index 0000000..9f2a203
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/preview/SkillsPreviewComposition.kt
@@ -0,0 +1,28 @@
+package com.motorro.commonstatemachine.examples.auth.appcore.ui.preview
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.remember
+import androidx.navigationevent.NavigationEventDispatcher
+import androidx.navigationevent.NavigationEventDispatcherOwner
+import androidx.navigationevent.compose.LocalNavigationEventDispatcherOwner
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.SkillsTheme
+
+/**
+ * App preview with all the required locals and theming
+ */
+@Composable
+fun SkillsPreviewComposition(content: @Composable () -> Unit) {
+
+ val navEventDispatcherOwner = remember {
+ object : NavigationEventDispatcherOwner {
+ override val navigationEventDispatcher: NavigationEventDispatcher = NavigationEventDispatcher()
+ }
+ }
+
+ SkillsTheme {
+ CompositionLocalProvider(LocalNavigationEventDispatcherOwner provides navEventDispatcherOwner) {
+ content()
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Color.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Color.kt
new file mode 100644
index 0000000..421d7fc
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.motorro.commonstatemachine.examples.auth.appcore.ui.theme
+
+import androidx.compose.ui.graphics.Color
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+val Purple40 = Color(0xFF6650a4)
+val PurpleGrey40 = Color(0xFF625b71)
+val Pink40 = Color(0xFF7D5260)
\ No newline at end of file
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Dimensions.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Dimensions.kt
new file mode 100644
index 0000000..6e8ceaf
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Dimensions.kt
@@ -0,0 +1,34 @@
+package com.motorro.commonstatemachine.examples.auth.appcore.ui.theme
+
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+
+/**
+ * Common dimensions for the application
+ */
+data object Dimensions {
+ /**
+ * Extra small padding: 4dp
+ */
+ val extraSmall: Dp = 4.dp
+
+ /**
+ * Small padding: 8dp
+ */
+ val small: Dp = 8.dp
+
+ /**
+ * Medium padding: 16dp
+ */
+ val medium: Dp = 16.dp
+
+ /**
+ * Large padding: 24dp
+ */
+ val large: Dp = 24.dp
+
+ /**
+ * Extra large padding: 32dp
+ */
+ val extraLarge: Dp = 32.dp
+}
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/SkillsTheme.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/SkillsTheme.kt
new file mode 100644
index 0000000..3631d0e
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/SkillsTheme.kt
@@ -0,0 +1,37 @@
+package com.motorro.commonstatemachine.examples.auth.appcore.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Typography
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+
+private val DarkColorScheme = darkColorScheme(
+ primary = Purple80,
+ secondary = PurpleGrey80,
+ tertiary = Pink80
+)
+
+private val LightColorScheme = lightColorScheme(
+ primary = Purple40,
+ secondary = PurpleGrey40,
+ tertiary = Pink40
+)
+
+@Composable
+fun SkillsTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable () -> Unit
+) {
+ val colorScheme = when {
+ darkTheme -> DarkColorScheme
+ else -> LightColorScheme
+ }
+
+ MaterialTheme(
+ colorScheme = colorScheme,
+ typography = Typography(),
+ content = content
+ )
+}
diff --git a/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Type.kt b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Type.kt
new file mode 100644
index 0000000..2ac1237
--- /dev/null
+++ b/examples/skills/appcore/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/auth/appcore/ui/theme/Type.kt
@@ -0,0 +1,18 @@
+package com.motorro.commonstatemachine.examples.common.ui.theme
+
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ bodyLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+)
\ No newline at end of file
diff --git a/examples/skills/auth/api/build.gradle.kts b/examples/skills/auth/api/build.gradle.kts
new file mode 100644
index 0000000..be1f8cc
--- /dev/null
+++ b/examples/skills/auth/api/build.gradle.kts
@@ -0,0 +1,29 @@
+/*
+* Copyright 2023 Nikolai Kotchetkov.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* 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.
+*/
+
+plugins {
+ alias(libs.plugins.motorro.cmp)
+}
+
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ implementation(project(":commonstatemachine"))
+ implementation(project(":coroutines"))
+ implementation(project(":commonflow:commonflow-data"))
+ implementation(project(":commonflow:commonflow-compose"))
+ implementation(libs.kotlin.coroutines.core)
+ }
+ }
+}
+
diff --git a/examples/skills/auth/api/consumer-rules.pro b/examples/skills/auth/api/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthDataApi.kt b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthDataApi.kt
new file mode 100644
index 0000000..e03a962
--- /dev/null
+++ b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthDataApi.kt
@@ -0,0 +1,8 @@
+package com.motorro.commonstatemachine.examples.skills.auth.api
+import com.motorro.commonstatemachine.flow.data.CommonFlowDataApi
+
+/**
+ * Data API used to run a child-flow in a proxy machine
+ * Available to a feature consumer
+ */
+interface AuthDataApi : CommonFlowDataApi
\ No newline at end of file
diff --git a/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthGesture.kt b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthGesture.kt
new file mode 100644
index 0000000..b93d81e
--- /dev/null
+++ b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthGesture.kt
@@ -0,0 +1,7 @@
+package com.motorro.commonstatemachine.examples.skills.auth.api
+
+/**
+ * A base type for authentication user gestures
+ * Available to a feature consumer
+ */
+interface AuthGesture
\ No newline at end of file
diff --git a/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthInput.kt b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthInput.kt
new file mode 100644
index 0000000..90aba9d
--- /dev/null
+++ b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthInput.kt
@@ -0,0 +1,7 @@
+package com.motorro.commonstatemachine.examples.skills.auth.api
+
+/**
+ * Initializing data for the feature flow
+ * @property skippable If true, allows user to skip authentication
+ */
+data class AuthInput(val skippable: Boolean)
\ No newline at end of file
diff --git a/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthResult.kt b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthResult.kt
new file mode 100644
index 0000000..e57a379
--- /dev/null
+++ b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthResult.kt
@@ -0,0 +1,7 @@
+package com.motorro.commonstatemachine.examples.skills.auth.api
+
+/**
+ * Feature flow result
+ * @param authenticated Example of a property returned to a parent flow
+ */
+data class AuthResult(val authenticated: Boolean)
\ No newline at end of file
diff --git a/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthUiApi.kt b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthUiApi.kt
new file mode 100644
index 0000000..1663448
--- /dev/null
+++ b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthUiApi.kt
@@ -0,0 +1,8 @@
+package com.motorro.commonstatemachine.examples.skills.auth.api
+import com.motorro.commonstatemachine.flow.compose.CommonFlowUiApi
+
+/**
+ * UI API used display a child flow inside a parent composition
+ * Available to a feature consumer
+ */
+interface AuthUiApi: CommonFlowUiApi
\ No newline at end of file
diff --git a/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthUiState.kt b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthUiState.kt
new file mode 100644
index 0000000..b16324d
--- /dev/null
+++ b/examples/skills/auth/api/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/api/AuthUiState.kt
@@ -0,0 +1,7 @@
+package com.motorro.commonstatemachine.examples.skills.auth.api
+
+/**
+ * A base type for authentication UI state
+ * Available to a feature consumer
+ */
+interface AuthUiState
\ No newline at end of file
diff --git a/examples/welcome/welcome/.gitignore b/examples/skills/auth/demo/.gitignore
similarity index 100%
rename from examples/welcome/welcome/.gitignore
rename to examples/skills/auth/demo/.gitignore
diff --git a/examples/skills/auth/demo/build.gradle.kts b/examples/skills/auth/demo/build.gradle.kts
new file mode 100644
index 0000000..f500670
--- /dev/null
+++ b/examples/skills/auth/demo/build.gradle.kts
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+plugins {
+ alias(libs.plugins.motorro.android.app)
+ alias(libs.plugins.koin)
+}
+
+android {
+ defaultConfig {
+ minSdk = 34
+ }
+
+ flavorDimensions += "demo"
+ productFlavors {
+ create("happyPath") {
+ dimension = "demo"
+ applicationIdSuffix = ".happypath"
+ isDefault = true
+ }
+ create("connectionErrors") {
+ dimension = "demo"
+ applicationIdSuffix = ".connectionerrors"
+ }
+ }
+
+ sourceSets {
+ getByName("happyPath") {
+ java.directories.add("src/happyPath/kotlin")
+ res.directories.add("src/happyPath/res")
+ }
+ getByName("connectionErrors") {
+ java.directories.add("src/connectionErrors/kotlin")
+ res.directories.add("src/connectionErrors/res")
+ }
+ }
+}
+
+dependencies {
+ implementation(project(":examples:skills:appcore"))
+ implementation(project(":examples:skills:domain"))
+ implementation(project(":examples:skills:auth:api"))
+ implementation(project(":examples:skills:auth:implementation"))
+ implementation(project(":commonstatemachine"))
+ implementation(project(":coroutines"))
+ implementation(project(":commonflow:commonflow-data"))
+ implementation(project(":commonflow:commonflow-compose"))
+ implementation(project(":commonflow:commonflow-viewmodel"))
+
+ implementation(libs.napier)
+
+ implementation(platform(libs.koin.bom))
+ implementation(libs.koin.core)
+ implementation(libs.koin.annotations)
+ implementation(libs.koin.core.viewmodel)
+ implementation(libs.koin.android)
+ implementation(libs.koin.compose)
+ implementation(libs.koin.compose.viewmodel)
+}
diff --git a/examples/welcome/welcome/proguard-rules.pro b/examples/skills/auth/demo/proguard-rules.pro
similarity index 100%
rename from examples/welcome/welcome/proguard-rules.pro
rename to examples/skills/auth/demo/proguard-rules.pro
diff --git a/examples/skills/auth/demo/src/connectionErrors/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/AppModule.kt b/examples/skills/auth/demo/src/connectionErrors/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/AppModule.kt
new file mode 100644
index 0000000..c98df26
--- /dev/null
+++ b/examples/skills/auth/demo/src/connectionErrors/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/AppModule.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.auth.demo
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.AuthModule
+import com.motorro.commonstatemachine.skills.domain.authenticate.AuthenticateWithPassword
+import com.motorro.commonstatemachine.skills.domain.authenticate.GetPasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.exception.IOException
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.delay
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+import org.koin.core.annotation.Single
+import kotlin.time.Duration.Companion.seconds
+
+/**
+ * Demo fixtures for Connection Errors flavor
+ */
+@Module(includes = [AuthModule::class])
+@ComponentScan
+class AppModule {
+
+ @Single
+ fun getPasswordRequirements(): GetPasswordRequirements {
+ var attempt = 1
+ val tag = GetPasswordRequirements::class.simpleName!!
+ return object : GetPasswordRequirements {
+ override suspend fun invoke(): PasswordRequirements {
+ delay(2.seconds)
+ when (attempt) {
+ 1 -> {
+ Napier.d(tag = tag) { "Emulating non-fatal connection error" }
+ attempt = 2
+ throw IOException("Network error")
+ }
+ else -> {
+ Napier.d(tag = tag) { "Emulating success on retry" }
+ attempt = 1
+ return PasswordRequirements(
+ regex = "^.{8,}$".toRegex(),
+ description = "Minimum eight characters"
+ )
+ }
+ }
+ }
+ }
+ }
+
+ @Single
+ fun authenticateWithPassword(): AuthenticateWithPassword {
+ var attempt = 1
+ val tag = AuthenticateWithPassword::class.simpleName!!
+ return object : AuthenticateWithPassword {
+ override suspend fun invoke(username: Username, password: String) {
+ delay(2.seconds)
+ when (attempt) {
+ 1 -> {
+ Napier.d(tag = tag) { "Emulating connection error" }
+ attempt = 2
+ throw IOException("Network error")
+ }
+ else -> {
+ Napier.d(tag = tag) { "Emulating success on retry" }
+ attempt = 1
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/skills/auth/demo/src/connectionErrors/res/values/strings.xml b/examples/skills/auth/demo/src/connectionErrors/res/values/strings.xml
new file mode 100644
index 0000000..fe206a4
--- /dev/null
+++ b/examples/skills/auth/demo/src/connectionErrors/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Auth Demo (Connection Errors)
+
diff --git a/examples/skills/auth/demo/src/happyPath/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/AppModule.kt b/examples/skills/auth/demo/src/happyPath/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/AppModule.kt
new file mode 100644
index 0000000..33043c3
--- /dev/null
+++ b/examples/skills/auth/demo/src/happyPath/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/AppModule.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.auth.demo
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.AuthModule
+import com.motorro.commonstatemachine.skills.domain.authenticate.AuthenticateWithPassword
+import com.motorro.commonstatemachine.skills.domain.authenticate.GetPasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.delay
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+import org.koin.core.annotation.Single
+import kotlin.time.Duration.Companion.seconds
+
+/**
+ * Demo fixtures for Happy Path flavor
+ */
+@Module(includes = [AuthModule::class])
+@ComponentScan
+class AppModule {
+
+ @Single
+ fun getPasswordRequirements(): GetPasswordRequirements {
+ val tag = GetPasswordRequirements::class.simpleName!!
+ return object : GetPasswordRequirements {
+ override suspend fun invoke(): PasswordRequirements {
+ delay(2.seconds)
+ Napier.d(tag = tag) { "Emulating success" }
+ return PasswordRequirements(
+ regex = "^.{8,}$".toRegex(),
+ description = "Minimum eight characters"
+ )
+ }
+ }
+ }
+
+ @Single
+ fun authenticateWithPassword(): AuthenticateWithPassword {
+ val tag = AuthenticateWithPassword::class.simpleName!!
+ return object : AuthenticateWithPassword {
+ override suspend fun invoke(username: Username, password: String) {
+ delay(2.seconds)
+ Napier.d(tag = tag) { "Emulating success" }
+ }
+ }
+ }
+}
diff --git a/examples/skills/auth/demo/src/happyPath/res/values/strings.xml b/examples/skills/auth/demo/src/happyPath/res/values/strings.xml
new file mode 100644
index 0000000..a822831
--- /dev/null
+++ b/examples/skills/auth/demo/src/happyPath/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ Auth Demo (Happy Path)
+
diff --git a/examples/skills/auth/demo/src/main/AndroidManifest.xml b/examples/skills/auth/demo/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e347350
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/App.kt b/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/App.kt
new file mode 100644
index 0000000..584c1be
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/App.kt
@@ -0,0 +1,25 @@
+package com.motorro.commonstatemachine.examples.skills.auth.demo
+
+import android.app.Application
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.annotation.KoinApplication
+import org.koin.plugin.module.dsl.startKoin
+
+@KoinApplication(modules = [AppModule::class])
+class App : Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ Napier.base(DebugAntilog())
+
+ startKoin {
+ allowOverride(false)
+ androidLogger()
+ androidContext(this@App)
+ }
+ }
+}
+
diff --git a/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/MainActivity.kt b/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/MainActivity.kt
new file mode 100644
index 0000000..86d2f19
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/MainActivity.kt
@@ -0,0 +1,115 @@
+package com.motorro.commonstatemachine.examples.skills.auth.demo
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.BackHandler
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.design.SkillsAppBar
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.Dimensions
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.SkillsTheme
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiApi
+import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowComposition
+import io.github.aakira.napier.Napier
+import org.koin.compose.koinInject
+import org.koin.compose.viewmodel.koinViewModel
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+
+ val (result, setResult) = remember {
+ mutableStateOf(null)
+ }
+
+ SkillsTheme {
+ Scaffold(
+ topBar = {
+ SkillsAppBar(
+ title = stringResource(R.string.app_name),
+ modifier = Modifier.fillMaxWidth(),
+ topLevel = true
+ )
+ }
+ ) { paddingValues ->
+ if (null == result) {
+ MainScreen(
+ modifier = Modifier.padding(paddingValues),
+ onComplete = setResult
+ )
+ } else {
+ ResultScreen(result) {
+ finish()
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Feature composition
+ */
+@Composable
+private fun MainScreen(modifier: Modifier = Modifier, onComplete: (AuthResult) -> Unit) {
+ val viewModel: MainViewModel = koinViewModel()
+ val uiApi: AuthUiApi = koinInject()
+
+ CommonFlowComposition(
+ viewModel = viewModel,
+ navigationBackHandler = { enabled, onBack ->
+ BackHandler(enabled, onBack)
+ },
+ content = { state, onGesture ->
+ uiApi.Screen(
+ state = state,
+ onGesture = onGesture,
+ modifier = modifier
+ )
+ },
+ finish = {
+ Napier.i { "Finished with: $it" }
+ onComplete(it)
+ }
+ )
+}
+
+/**
+ * Describes the flow result
+ */
+@Composable
+private fun ResultScreen(result: AuthResult, onComplete: () -> Unit) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.spacedBy(Dimensions.medium, Alignment.CenterVertically),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ style = MaterialTheme.typography.bodyLarge,
+ text = stringResource(R.string.result_authenticated, result.authenticated)
+ )
+ Button(onClick = onComplete) {
+ Text(text = stringResource(R.string.btn_exit))
+ }
+ }
+}
+
diff --git a/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/MainViewModel.kt b/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/MainViewModel.kt
new file mode 100644
index 0000000..88d2fcd
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/demo/MainViewModel.kt
@@ -0,0 +1,15 @@
+package com.motorro.commonstatemachine.examples.skills.auth.demo
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel
+import org.koin.core.annotation.KoinViewModel
+
+@KoinViewModel
+class MainViewModel (api: AuthDataApi) : CommonFlowViewModel(
+ api = api,
+ init = AuthInput(skippable = true)
+)
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/skills/auth/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..40ce517
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/res/drawable/ic_launcher_background.xml b/examples/skills/auth/demo/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..997ef0b
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/commoncore/src/androidMain/AndroidManifest.xml b/examples/skills/auth/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 73%
rename from examples/commoncore/src/androidMain/AndroidManifest.xml
rename to examples/skills/auth/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index a4b25cb..0147ca8 100644
--- a/examples/commoncore/src/androidMain/AndroidManifest.xml
+++ b/examples/skills/auth/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -12,4 +12,7 @@
~ limitations under the License.
-->
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/examples/androidcore/src/main/AndroidManifest.xml b/examples/skills/auth/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 73%
rename from examples/androidcore/src/main/AndroidManifest.xml
rename to examples/skills/auth/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index cfc666d..0147ca8 100644
--- a/examples/androidcore/src/main/AndroidManifest.xml
+++ b/examples/skills/auth/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -12,6 +12,7 @@
~ limitations under the License.
-->
-
-
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/res/values/strings.xml b/examples/skills/auth/demo/src/main/res/values/strings.xml
new file mode 100644
index 0000000..4d15595
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+ Auth Demo
+ Authenticated: %b
+ Exit
+
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/res/xml/backup_rules.xml b/examples/skills/auth/demo/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/res/xml/data_extraction_rules.xml b/examples/skills/auth/demo/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/demo/src/main/res/xml/network_security_config.xml b/examples/skills/auth/demo/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..c64cff3
--- /dev/null
+++ b/examples/skills/auth/demo/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+ 10.0.2.2
+
+
diff --git a/examples/skills/auth/implementation/build.gradle.kts b/examples/skills/auth/implementation/build.gradle.kts
new file mode 100644
index 0000000..ec5590b
--- /dev/null
+++ b/examples/skills/auth/implementation/build.gradle.kts
@@ -0,0 +1,42 @@
+/*
+* Copyright 2023 Nikolai Kotchetkov.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* 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.
+*/
+
+plugins {
+ alias(libs.plugins.motorro.cmp)
+ alias(libs.plugins.mockery)
+ alias(libs.plugins.koin)
+}
+
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ implementation(project(":commonstatemachine"))
+ implementation(project(":coroutines"))
+ implementation(project(":commonflow:commonflow-data"))
+ implementation(project(":commonflow:commonflow-compose"))
+ implementation(project(":examples:skills:domain"))
+ implementation(project(":examples:skills:appcore"))
+ implementation(project(":examples:skills:auth:api"))
+ implementation(libs.kotlin.coroutines.core)
+ implementation(project.dependencies.platform(libs.koin.bom))
+ implementation(libs.koin.core)
+ implementation(libs.koin.annotations)
+ implementation(libs.napier)
+ }
+ commonTest.dependencies {
+ implementation(libs.test.kotlin.coroutines)
+ }
+ }
+}
+
+
diff --git a/examples/skills/auth/implementation/consumer-rules.pro b/examples/skills/auth/implementation/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/skills/auth/implementation/src/commonMain/composeResources/values/strings.xml b/examples/skills/auth/implementation/src/commonMain/composeResources/values/strings.xml
new file mode 100644
index 0000000..e0fe510
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/composeResources/values/strings.xml
@@ -0,0 +1,9 @@
+
+ Authentication
+ Username
+ Password
+ Login
+ Skip
+ Retry
+ Close
+
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthDataApiImpl.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthDataApiImpl.kt
new file mode 100644
index 0000000..aa90a5e
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthDataApiImpl.kt
@@ -0,0 +1,35 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.state.AuthStateFactory
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import org.koin.core.annotation.Factory
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.parameter.parametersOf
+
+/**
+ * Data API implementation
+ */
+@Factory
+internal class AuthDataApiImpl : AuthDataApi, KoinComponent {
+
+ @Suppress("UNCHECKED_CAST")
+ override fun init(flowHost: CommonFlowHost, input: AuthInput): CommonMachineState {
+ val factory = this@AuthDataApiImpl.get {
+ parametersOf(flowHost)
+ }
+ return factory.preloading(input) as CommonMachineState
+ }
+
+ override fun getDefaultUiState(): AuthUiState = AuthUiStateImpl.Loading
+
+ override fun getBackGesture(): AuthGesture = AuthGestureImpl.Back
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthModule.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthModule.kt
new file mode 100644
index 0000000..b646f31
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthModule.kt
@@ -0,0 +1,8 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation
+
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+
+@Module
+@ComponentScan
+class AuthModule
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthUiApiImpl.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthUiApiImpl.kt
new file mode 100644
index 0000000..a0ccad4
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/AuthUiApiImpl.kt
@@ -0,0 +1,27 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation
+
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiApi
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.ui.AuthScreen
+import org.koin.core.annotation.Factory
+
+/**
+ * UI API implementation
+ */
+@Factory
+internal class AuthUiApiImpl : AuthUiApi {
+ @Composable
+ override fun Screen(
+ state: AuthUiState,
+ onGesture: (AuthGesture) -> Unit,
+ modifier: Modifier
+ ) = AuthScreen(
+ state = state as AuthUiStateImpl,
+ modifier = modifier,
+ onGesture = onGesture
+ )
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthGestureImpl.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthGestureImpl.kt
new file mode 100644
index 0000000..ba1df8e
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthGestureImpl.kt
@@ -0,0 +1,38 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+
+/**
+ * All gestures available in this feature
+ */
+internal sealed class AuthGestureImpl : AuthGesture {
+ /**
+ * Backwards navigation element clicked
+ */
+ data object Back : AuthGestureImpl()
+
+ /**
+ * Default call-to-action clicked
+ */
+ data object Action : AuthGestureImpl()
+
+ /**
+ * Gestures for the login form
+ */
+ sealed class Form : AuthGestureImpl() {
+ /**
+ * Username input changed
+ */
+ data class UsernameChanged(val value: String) : Form()
+
+ /**
+ * Password input changed
+ */
+ data class PasswordChanged(val value: String) : Form()
+
+ /**
+ * Skips the authentication
+ */
+ data object Skip : Form()
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthStateData.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthStateData.kt
new file mode 100644
index 0000000..d8cf559
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthStateData.kt
@@ -0,0 +1,23 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+
+/**
+ * Interstate data to pass between the machine states
+ * @property input Flow input from the flow initialization
+ * @property passwordRequirements Password requirements (preloaded later)
+ * @property username User input for the username is stored here
+ * @property password User input for the password is stored here
+ */
+internal data class AuthStateData(
+ val input: AuthInput,
+ val passwordRequirements: PasswordRequirements,
+ val username: String = "",
+ val password: String = ""
+)
+
+/**
+ * Some utility function to check the form state
+ */
+internal fun AuthStateData.isValidToAuthenticate() = username.isNotBlank() && passwordRequirements.regex.matches(password)
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthUiStateImpl.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthUiStateImpl.kt
new file mode 100644
index 0000000..5476939
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthUiStateImpl.kt
@@ -0,0 +1,36 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+
+/**
+ * All gestures available in this feature
+ */
+internal sealed class AuthUiStateImpl : AuthUiState {
+ /**
+ * Loading data
+ */
+ data object Loading : AuthUiStateImpl()
+
+ /**
+ * Login form
+ * @property username Username
+ * @property password Password
+ * @property passwordRequirements Password requirements description
+ * @property loginEnabled If true, the form is complete and the user can log in
+ * @property canSkip If true, the user can skip the authentication
+ */
+ data class Form(
+ val username: String,
+ val password: String,
+ val passwordRequirements: String,
+ val loginEnabled: Boolean,
+ val canSkip: Boolean
+ ) : AuthUiStateImpl()
+
+ /**
+ * Displays error
+ * @property message Error message to display
+ * @property canRetry If true, the error is recoverable and can be retried
+ */
+ data class Error(val message: String, val canRetry: Boolean) : AuthUiStateImpl()
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthContext.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthContext.kt
new file mode 100644
index 0000000..21bc639
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthContext.kt
@@ -0,0 +1,25 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.ui.AuthUiRenderer
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+
+/**
+ * Common tools used by states
+ */
+internal interface AuthContext {
+ /**
+ * State-factory
+ */
+ val factory: AuthStateFactory
+
+ /**
+ * Flow-host
+ */
+ val flowHost: CommonFlowHost
+
+ /**
+ * UI-renderer
+ */
+ val renderer: AuthUiRenderer
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthState.kt
new file mode 100644
index 0000000..bcf46b6
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthState.kt
@@ -0,0 +1,10 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+
+/**
+ * Convenient type-alias - bounds gesture and ui state system
+ */
+internal typealias AuthState = CommonMachineState
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthStateFactory.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthStateFactory.kt
new file mode 100644
index 0000000..5013652
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthStateFactory.kt
@@ -0,0 +1,54 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+
+/**
+ * State-factory interface
+ * Abstracts the machine state from the state creation
+ */
+internal interface AuthStateFactory {
+ /**
+ * Creates a flow preloading state.
+ * The interstate data will be created by the state.
+ * @param input Initialization params
+ */
+ fun preloading(input: AuthInput): AuthState
+
+ /**
+ * Creates a preload error state.
+ * Again, there's no interstate data here as the preloading failed.
+ * @param input Initialization params
+ * @param error Error that occurred during the initialization
+ */
+ fun preloadError(input: AuthInput, error: AppException): AuthState
+
+ /**
+ * Creates authentication form state.
+ * Now we have the interstate data, pass it as a parameter.
+ * @param data Interstate data
+ */
+ fun form(data: AuthStateData): AuthState
+
+ /**
+ * Creates the authentication state.
+ * @param data Interstate data
+ */
+ fun authenticating(data: AuthStateData): AuthState
+
+ /**
+ * Creates an authentication error state.
+ * @param data Interstate data
+ * @param error Error that occurred during the initialization
+ */
+ fun authenticationError(data: AuthStateData, error: AppException): AuthState
+
+ /**
+ * Creates the termination state that finishes the flow.
+ * All interstate data is lost as not needed anymore.
+ * @param result Flow result
+ */
+ fun terminated(result: AuthResult): AuthState
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthStateFactoryImpl.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthStateFactoryImpl.kt
new file mode 100644
index 0000000..35be8ff
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthStateFactoryImpl.kt
@@ -0,0 +1,84 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.ui.AuthUiRenderer
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.InjectedParam
+
+/**
+ * Main state-factory implementation
+ */
+@Factory
+internal class AuthStateFactoryImpl(
+ private val preloadingStateFactory: PreloadingState.StateFactory,
+ private val authenticatingStateFactory: AuthenticatingState.StateFactory,
+ @InjectedParam flowHost: CommonFlowHost,
+ renderer: AuthUiRenderer
+) : AuthStateFactory {
+
+ /**
+ * Context implementation
+ */
+ private val context = object : AuthContext {
+ override val factory: AuthStateFactory = this@AuthStateFactoryImpl
+ override val flowHost: CommonFlowHost = flowHost
+ override val renderer: AuthUiRenderer = renderer
+ }
+
+ /**
+ * Creates preloading state with help of a preloading state factory
+ */
+ override fun preloading(input: AuthInput) = preloadingStateFactory.create(
+ context,
+ input
+ )
+
+ /**
+ * Creates preload error state directly
+ */
+ override fun preloadError(input: AuthInput, error: AppException) = PreloadingErrorState(
+ context,
+ input,
+ error
+ )
+
+ /**
+ * Creates authentication form state
+ */
+ override fun form(data: AuthStateData) = FormState(
+ context,
+ data
+ )
+
+ /**
+ * Creates authenticating state
+ */
+ override fun authenticating(data: AuthStateData): AuthState = authenticatingStateFactory.create(
+ context,
+ data
+ )
+
+ /**
+ * Creates authentication error state
+ */
+ override fun authenticationError(data: AuthStateData, error: AppException) = AuthenticationErrorState(
+ context,
+ data,
+ error
+ )
+
+ /**
+ * Ad-hoc terminated state implementation
+ */
+ override fun terminated(result: AuthResult) = object : AuthState() {
+ override fun doStart() {
+ Napier.d { "Terminating flow..." }
+ context.flowHost.onComplete(result)
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticatingState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticatingState.kt
new file mode 100644
index 0000000..f337087
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticatingState.kt
@@ -0,0 +1,81 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.skills.domain.authenticate.AuthenticateWithPassword
+import com.motorro.commonstatemachine.skills.domain.exception.toAppException
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.ensureActive
+import kotlinx.coroutines.launch
+import org.koin.core.annotation.Factory
+
+/**
+ * Authenticates the user
+ * @param context Auth context
+ * @param data Interstate data
+ * @param authenticate Authenticate usecase
+ */
+internal class AuthenticatingState(
+ context: AuthContext,
+ private val data: AuthStateData,
+ private val authenticate: AuthenticateWithPassword
+) : BaseAuthState(context) {
+
+ /**
+ * State start-up
+ */
+ override fun doStart() {
+ setUiState {
+ renderLoading()
+ }
+ doAuthenticate()
+ }
+
+ /**
+ * Gesture processing
+ */
+ override fun doProcess(gesture: AuthGestureImpl) {
+ when(gesture) {
+ is AuthGestureImpl.Back -> setMachineState {
+ Napier.d { "Back gesture. Returning to form..." }
+ form(data)
+ }
+ else -> super.doProcess(gesture)
+ }
+ }
+
+ /**
+ * Authentication function
+ */
+ private fun doAuthenticate() = stateScope.launch {
+ try {
+ authenticate(Username(data.username), data.password)
+ // Advance to the next state
+ setMachineState {
+ terminated(AuthResult(authenticated = true))
+ }
+ } catch (e: Throwable) {
+ ensureActive()
+ Napier.w(e) { "Error during authentication" }
+ // Advance to the error state
+ setMachineState {
+ authenticationError(data, e.toAppException())
+ }
+ }
+ }
+
+ /**
+ * State factory
+ * State dependencies are injected here
+ */
+ @Factory
+ class StateFactory(private val authenticate: AuthenticateWithPassword) {
+ fun create(context: AuthContext, data: AuthStateData): AuthState = AuthenticatingState(
+ context = context,
+ data = data,
+ authenticate = authenticate
+ )
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticationErrorState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticationErrorState.kt
new file mode 100644
index 0000000..772a972
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticationErrorState.kt
@@ -0,0 +1,53 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+import com.motorro.commonstatemachine.skills.domain.exception.IOException
+import io.github.aakira.napier.Napier
+
+/**
+ * Handles authentication error
+ * If the error is recoverable (IOException), allows to transfer back to authenticating to retry.
+ * Otherwise returns to form.
+ * @param context Auth context
+ * @param data Interstate data
+ * @param error Error to handle
+ */
+internal class AuthenticationErrorState(
+ context: AuthContext,
+ private val data: AuthStateData,
+ private val error: AppException
+) : BaseAuthState(context) {
+ override fun doStart() {
+ setUiState {
+ renderFullScreenError(error, canRetry())
+ }
+ }
+
+ private fun canRetry(): Boolean = when(error) {
+ is IOException -> true
+ else -> false
+ }
+
+ override fun doProcess(gesture: AuthGestureImpl) {
+ when(gesture) {
+ is AuthGestureImpl.Back -> setMachineState {
+ Napier.d { "Back gesture. Returning to form..." }
+ form(data)
+ }
+ is AuthGestureImpl.Action -> if (canRetry()) {
+ Napier.d { "Action gesture. Retrying authentication..." }
+ setMachineState {
+ authenticating(data)
+ }
+ } else {
+ Napier.d { "Action gesture. Returning to form..." }
+ setMachineState {
+ form(data)
+ }
+ }
+ else -> super.doProcess(gesture)
+ }
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/BaseAuthState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/BaseAuthState.kt
new file mode 100644
index 0000000..267cf74
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/BaseAuthState.kt
@@ -0,0 +1,34 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.coroutines.CoroutineState
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.ui.AuthUiRenderer
+import io.github.aakira.napier.Napier
+
+/**
+ * Base class for the most logic states
+ */
+internal abstract class BaseAuthState(context: AuthContext) : CoroutineState(), AuthContext by context {
+
+ /**
+ * Common gesture processing (logs a warning for an unexpected gesture)
+ */
+ override fun doProcess(gesture: AuthGestureImpl) {
+ Napier.w { "Unsupported gesture: $gesture" }
+ }
+
+ /**
+ * Convenience function to switch a machine state
+ */
+ protected inline fun setMachineState(block: AuthStateFactory.() -> AuthState) {
+ setMachineState(block(factory))
+ }
+
+ /**
+ * Convenience function to render UI state
+ */
+ protected inline fun setUiState(block: AuthUiRenderer.() -> AuthUiStateImpl) {
+ setUiState(renderer.block())
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/FormState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/FormState.kt
new file mode 100644
index 0000000..c52effb
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/FormState.kt
@@ -0,0 +1,75 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.isValidToAuthenticate
+import io.github.aakira.napier.Napier
+import org.jetbrains.annotations.VisibleForTesting
+
+/**
+ * Authentication form state - an interactive state that:
+ * - handles user input
+ * - updates the UI state
+ * - validates the input
+ * - updates the interstate data
+ * @param context Auth context
+ * @param data Interstate data. Visible for testing.
+ */
+internal class FormState(
+ context: AuthContext,
+ @get:VisibleForTesting var data: AuthStateData,
+) : BaseAuthState(context) {
+
+ /**
+ * State start-up
+ */
+ override fun doStart() {
+ setUiState {
+ renderForm(data, data.isValidToAuthenticate())
+ }
+ }
+
+ /**
+ * Updates the interstate data and renders the form
+ */
+ private inline fun updateData(block: AuthStateData.() -> AuthStateData) {
+ val oldData = data
+ val newData = data.block()
+ if (oldData != newData) {
+ data = newData
+ setUiState {
+ renderForm(newData, newData.isValidToAuthenticate())
+ }
+ }
+ }
+
+ /**
+ * Processes the gesture
+ */
+ override fun doProcess(gesture: AuthGestureImpl) {
+ when(gesture) {
+ is AuthGestureImpl.Back -> setMachineState {
+ terminated(AuthResult(false))
+ }
+ is AuthGestureImpl.Action -> if (data.isValidToAuthenticate()) {
+ Napier.d { "Action gesture. Authenticating..." }
+ setMachineState {
+ authenticating(data)
+ }
+ }
+ is AuthGestureImpl.Form.UsernameChanged -> updateData {
+ copy(username = gesture.value)
+ }
+ is AuthGestureImpl.Form.PasswordChanged -> updateData {
+ copy(password = gesture.value)
+ }
+ is AuthGestureImpl.Form.Skip -> if (data.input.skippable) {
+ Napier.d { "Skipping authentication..." }
+ setMachineState {
+ terminated(AuthResult(false))
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingErrorState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingErrorState.kt
new file mode 100644
index 0000000..61db5fc
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingErrorState.kt
@@ -0,0 +1,52 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+import com.motorro.commonstatemachine.skills.domain.exception.IOException
+import io.github.aakira.napier.Napier
+
+/**
+ * Handles preloading error
+ * If the error is recoverable, allows to transfer back to loading to retry, otherwise terminates the flow.
+ * @param context Auth context
+ * @param error Error to handle
+ */
+internal class PreloadingErrorState(
+ context: AuthContext,
+ private val input: AuthInput,
+ private val error: AppException
+) : BaseAuthState(context) {
+ override fun doStart() {
+ setUiState {
+ renderFullScreenError(error, canRetry())
+ }
+ }
+
+ private fun canRetry(): Boolean = when(error) {
+ is IOException -> true
+ else -> false
+ }
+
+ override fun doProcess(gesture: AuthGestureImpl) {
+ when(gesture) {
+ is AuthGestureImpl.Back -> setMachineState {
+ Napier.d { "Back gesture. Terminating flow..." }
+ terminated(AuthResult(false))
+ }
+ is AuthGestureImpl.Action -> if (canRetry()) {
+ Napier.d { "Action gesture. Retrying initialization..." }
+ setMachineState {
+ preloading(input)
+ }
+ } else {
+ Napier.d { "Action gesture. Terminating flow..." }
+ setMachineState {
+ terminated(AuthResult(false))
+ }
+ }
+ else -> super.doProcess(gesture)
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingState.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingState.kt
new file mode 100644
index 0000000..63dd138
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingState.kt
@@ -0,0 +1,78 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.skills.domain.authenticate.GetPasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.exception.toAppException
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.ensureActive
+import kotlinx.coroutines.launch
+import org.koin.core.annotation.Factory
+
+/**
+ * Example of a state that preloads some data with the usecase
+ * and creates the valid [data-state](data-and-ui-implementation.md#step-3-interstate-data).
+ */
+internal class PreloadingState(
+ context: AuthContext,
+ private val input: AuthInput,
+ private val getPasswordRequirements: GetPasswordRequirements
+) : BaseAuthState(context) {
+
+ /**
+ * State start-up
+ */
+ override fun doStart() {
+ setUiState {
+ renderLoading()
+ }
+ preload()
+ }
+
+ /**
+ * Dummy gesture processing
+ */
+ override fun doProcess(gesture: AuthGestureImpl) {
+ when(gesture) {
+ is AuthGestureImpl.Back -> setMachineState {
+ terminated(AuthResult(false))
+ }
+ else -> super.doProcess(gesture)
+ }
+ }
+
+ /**
+ * Dummy preloading function
+ */
+ private fun preload() = stateScope.launch {
+ try {
+ val passwordRequirements = getPasswordRequirements()
+ // Advance to the next state
+ setMachineState {
+ form(AuthStateData(input, passwordRequirements))
+ }
+ } catch (e: Throwable) {
+ ensureActive()
+ Napier.w(e) { "Error during initialization" }
+ // Advance to the error state
+ setMachineState {
+ preloadError(input, e.toAppException())
+ }
+ }
+ }
+
+ /**
+ * State factory
+ * State dependencies are injected here
+ */
+ @Factory
+ class StateFactory(private val getPasswordRequirements: GetPasswordRequirements) {
+ fun create(context: AuthContext, input: AuthInput): AuthState = PreloadingState(
+ context = context,
+ input = input,
+ getPasswordRequirements = getPasswordRequirements
+ )
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthErrorScreen.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthErrorScreen.kt
new file mode 100644
index 0000000..fd8c8a1
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthErrorScreen.kt
@@ -0,0 +1,79 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.preview.SkillsPreviewComposition
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.Dimensions
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.Res
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.btn_close
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.btn_retry
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import org.jetbrains.compose.resources.stringResource
+
+@Composable
+internal fun AuthErrorScreen(
+ state: AuthUiStateImpl.Error,
+ modifier: Modifier = Modifier,
+ onGesture: (AuthGestureImpl) -> Unit
+) {
+ Column(
+ modifier = modifier.fillMaxSize().padding(Dimensions.medium),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ Text(
+ text = state.message,
+ color = MaterialTheme.colorScheme.error,
+ style = MaterialTheme.typography.bodyLarge
+ )
+ Spacer(Modifier.height(Dimensions.medium))
+ Button(onClick = { onGesture(AuthGestureImpl.Action) }) {
+ Text(
+ if (state.canRetry) {
+ stringResource(Res.string.btn_retry)
+ } else {
+ stringResource(Res.string.btn_close)
+ }
+ )
+ }
+ }
+}
+
+private class AuthErrorDataProvider : PreviewParameterProvider {
+ override val values: Sequence = sequenceOf(
+ AuthUiStateImpl.Error(
+ message = "A recoverable error occurred",
+ canRetry = true
+ ),
+ AuthUiStateImpl.Error(
+ message = "A non-recoverable error occurred",
+ canRetry = false
+ )
+ )
+}
+
+@Preview
+@Composable
+private fun AuthErrorPreview(@PreviewParameter(AuthErrorDataProvider::class) state: AuthUiStateImpl.Error?) {
+ if (null == state) return
+ SkillsPreviewComposition {
+ AuthErrorScreen(
+ state = state,
+ modifier = Modifier.fillMaxSize()
+ ) {}
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthFormScreen.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthFormScreen.kt
new file mode 100644
index 0000000..0172cfc
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthFormScreen.kt
@@ -0,0 +1,142 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.text.KeyboardActions
+import androidx.compose.foundation.text.KeyboardOptions
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.OutlinedButton
+import androidx.compose.material3.Text
+import androidx.compose.material3.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.focus.FocusDirection
+import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.text.input.ImeAction
+import androidx.compose.ui.text.input.PasswordVisualTransformation
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.preview.SkillsPreviewComposition
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.Dimensions
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.Res
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.btn_login
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.btn_skip
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.input_password
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.input_username
+import org.jetbrains.compose.resources.stringResource
+
+@Composable
+internal fun AuthFormScreen(
+ state: AuthUiStateImpl.Form,
+ modifier: Modifier = Modifier,
+ onGesture: (AuthGestureImpl) -> Unit,
+) {
+ val focusManager = LocalFocusManager.current
+
+ Column(
+ modifier = modifier.fillMaxSize().padding(Dimensions.medium),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.Center
+ ) {
+ TextField(
+ value = state.username,
+ onValueChange = { onGesture(AuthGestureImpl.Form.UsernameChanged(it)) },
+ label = { Text(stringResource(Res.string.input_username)) },
+ modifier = Modifier.fillMaxWidth(),
+ singleLine = true,
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
+ keyboardActions = KeyboardActions(
+ onNext = { focusManager.moveFocus(FocusDirection.Down) }
+ )
+ )
+ Spacer(Modifier.height(Dimensions.medium))
+ TextField(
+ value = state.password,
+ onValueChange = { onGesture(AuthGestureImpl.Form.PasswordChanged(it)) },
+ label = { Text(stringResource(Res.string.input_password)) },
+ modifier = Modifier.fillMaxWidth(),
+ visualTransformation = PasswordVisualTransformation(),
+ singleLine = true,
+ keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
+ keyboardActions = KeyboardActions(
+ onDone = {
+ focusManager.clearFocus()
+ if (state.loginEnabled) {
+ onGesture(AuthGestureImpl.Action)
+ }
+ }
+ )
+ )
+ Text(
+ text = state.passwordRequirements,
+ modifier = Modifier.fillMaxWidth().padding(top = Dimensions.small),
+ style = MaterialTheme.typography.bodySmall,
+ color = MaterialTheme.colorScheme.onSurfaceVariant
+ )
+ Spacer(Modifier.height(Dimensions.medium))
+ Button(
+ onClick = { onGesture(AuthGestureImpl.Action) },
+ enabled = state.loginEnabled,
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(stringResource(Res.string.btn_login))
+ }
+ if (state.canSkip) {
+ Spacer(Modifier.height(Dimensions.medium))
+ OutlinedButton(
+ onClick = { onGesture(AuthGestureImpl.Form.Skip) },
+ modifier = Modifier.fillMaxWidth()
+ ) {
+ Text(stringResource(Res.string.btn_skip))
+ }
+ }
+ }
+}
+
+private class AuthFormDataProvider : PreviewParameterProvider {
+ override val values: Sequence = sequenceOf(
+ AuthUiStateImpl.Form(
+ username = "",
+ password = "",
+ passwordRequirements = "At least 8 characters",
+ loginEnabled = false,
+ canSkip = true
+ ),
+ AuthUiStateImpl.Form(
+ username = "user",
+ password = "password",
+ passwordRequirements = "At least 8 characters",
+ loginEnabled = true,
+ canSkip = true
+ ),
+ AuthUiStateImpl.Form(
+ username = "user",
+ password = "password",
+ passwordRequirements = "At least 8 characters",
+ loginEnabled = true,
+ canSkip = false
+ )
+ )
+}
+
+@Preview
+@Composable
+private fun AuthFormPreview(@PreviewParameter(AuthFormDataProvider::class) state: AuthUiStateImpl.Form?) {
+ if (null == state) return
+ SkillsPreviewComposition {
+ AuthFormScreen(
+ state = state,
+ modifier = Modifier.fillMaxSize()
+ ) {}
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthLoadingScreen.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthLoadingScreen.kt
new file mode 100644
index 0000000..90875c9
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthLoadingScreen.kt
@@ -0,0 +1,21 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.design.SkillsLoading
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.preview.SkillsPreviewComposition
+
+@Composable
+internal fun AuthLoadingScreen(modifier: Modifier = Modifier) {
+ SkillsLoading(modifier)
+}
+
+@Preview
+@Composable
+private fun AuthLoadingPreview() {
+ SkillsPreviewComposition {
+ AuthLoadingScreen(Modifier.fillMaxSize())
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthScreen.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthScreen.kt
new file mode 100644
index 0000000..f2fbfd9
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthScreen.kt
@@ -0,0 +1,68 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.tooling.preview.PreviewParameter
+import androidx.compose.ui.tooling.preview.PreviewParameterProvider
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.preview.SkillsPreviewComposition
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+
+/**
+ * Authentication screen
+ * @param state UI state
+ * @param onGesture Gesture handler
+ */
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+internal fun AuthScreen(
+ state: AuthUiStateImpl,
+ modifier: Modifier = Modifier,
+ onGesture: (AuthGestureImpl) -> Unit,
+) {
+ val modifier = modifier.fillMaxSize()
+ when(state) {
+ AuthUiStateImpl.Loading -> AuthLoadingScreen(modifier)
+ is AuthUiStateImpl.Error -> AuthErrorScreen(
+ state = state,
+ modifier = modifier,
+ onGesture = onGesture
+ )
+ is AuthUiStateImpl.Form -> AuthFormScreen(
+ state = state,
+ modifier = modifier,
+ onGesture = onGesture
+ )
+ }
+}
+
+private class AuthScreenDataProvider : PreviewParameterProvider {
+ override val values: Sequence = sequenceOf(
+ AuthUiStateImpl.Loading,
+ AuthUiStateImpl.Form(
+ username = "user",
+ password = "password",
+ passwordRequirements = "At least 8 characters",
+ loginEnabled = true,
+ canSkip = true
+ ),
+ AuthUiStateImpl.Error(
+ message = "A recoverable error occurred",
+ canRetry = true
+ )
+ )
+}
+
+@Preview
+@Composable
+private fun SkillsScreenPreview(@PreviewParameter(AuthScreenDataProvider::class) state: AuthUiStateImpl?) {
+ if (null == state) return
+ SkillsPreviewComposition {
+ AuthScreen(
+ state = state
+ ) {}
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRenderer.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRenderer.kt
new file mode 100644
index 0000000..f117aba
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRenderer.kt
@@ -0,0 +1,33 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+
+/**
+ * Transforms the data state to the UI state
+ */
+internal interface AuthUiRenderer {
+ /**
+ * Renders loading.
+ * The result would be an object so we don't need interstate data here.
+ */
+ fun renderLoading(): AuthUiStateImpl
+
+ /**
+ * Renders login form.
+ * The data could be fully taken from the data state.
+ * @param data Data-state to transform
+ * @param isValid If the form is valid or not
+ */
+ fun renderForm(data: AuthStateData, isValid: Boolean): AuthUiStateImpl
+
+ /**
+ * Renders error that takes the full screen
+ * - doesn't require any data-state
+ * - requires an error and takes a message from it
+ * @param error Error to present to the user
+ * @param canRetry Error could be retried
+ */
+ fun renderFullScreenError(error: AppException, canRetry: Boolean): AuthUiStateImpl
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRendererImpl.kt b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRendererImpl.kt
new file mode 100644
index 0000000..8f4e0b7
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRendererImpl.kt
@@ -0,0 +1,28 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthStateData
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+import org.koin.core.annotation.Factory
+
+/**
+ * UI renderer implementation
+ */
+@Factory
+internal class AuthUiRendererImpl : AuthUiRenderer {
+
+ override fun renderLoading(): AuthUiStateImpl = AuthUiStateImpl.Loading
+
+ override fun renderForm(data: AuthStateData, isValid: Boolean) = AuthUiStateImpl.Form(
+ username = data.username,
+ password = data.password,
+ passwordRequirements = data.passwordRequirements.description,
+ loginEnabled = isValid,
+ canSkip = data.input.skippable
+ )
+
+ override fun renderFullScreenError(error: AppException, canRetry: Boolean) = AuthUiStateImpl.Error(
+ message = error.message,
+ canRetry = canRetry
+ )
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthStateDataTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthStateDataTest.kt
new file mode 100644
index 0000000..a27db2f
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/AuthStateDataTest.kt
@@ -0,0 +1,51 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+import kotlin.test.Test
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+internal class AuthStateDataTest {
+ @Test
+ fun returnsTrueIfValid() {
+ val data = AuthStateData(
+ input = INPUT,
+ passwordRequirements = PASSWORD_REQUIREMENTS,
+ username = "user",
+ password = "password",
+ )
+ assertTrue(data.isValidToAuthenticate())
+ }
+
+ @Test
+ fun returnsFalseIfUsernameEmpty() {
+ val data = AuthStateData(
+ input = INPUT,
+ passwordRequirements = PASSWORD_REQUIREMENTS,
+ username = "",
+ password = "password",
+ )
+ assertFalse(data.isValidToAuthenticate())
+ }
+
+ @Test
+ fun returnsFalseIfUsernameBlank() {
+ val data = AuthStateData(
+ input = INPUT,
+ passwordRequirements = PASSWORD_REQUIREMENTS,
+ username = " ",
+ password = "password",
+ )
+ assertFalse(data.isValidToAuthenticate())
+ }
+
+ @Test
+ fun returnsFalseIfPasswordInvalid() {
+ val data = AuthStateData(
+ input = INPUT,
+ passwordRequirements = PASSWORD_REQUIREMENTS,
+ username = "user",
+ password = "short", // PASSWORD_REQUIREMENTS regex is ^.{8,}$
+ )
+ assertFalse(data.isValidToAuthenticate())
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/authGesturesFixtures.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/authGesturesFixtures.kt
new file mode 100644
index 0000000..45c6ec5
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/authGesturesFixtures.kt
@@ -0,0 +1,11 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+/**
+ * Username input changed
+ */
+internal val USERNAME_CHANGED = AuthGestureImpl.Form.UsernameChanged("user")
+
+/**
+ * Password input changed
+ */
+internal val PASSWORD_CHANGED = AuthGestureImpl.Form.PasswordChanged("password")
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/dataStatesFixtures.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/dataStatesFixtures.kt
new file mode 100644
index 0000000..7b04bbf
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/dataStatesFixtures.kt
@@ -0,0 +1,45 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.exception.IOException
+import com.motorro.commonstatemachine.skills.domain.exception.UnknownException
+
+/**
+ * Input fixture
+ */
+internal val INPUT = AuthInput(true)
+
+/**
+ * Result fixture
+ */
+internal val RESULT = AuthResult(authenticated = true)
+
+internal val PASSWORD_REQUIREMENTS = PasswordRequirements(
+ regex = "^.{8,}$".toRegex(),
+ description = "Minimum eight characters"
+)
+
+/**
+ * Initial state
+ */
+internal val EMPTY_STATE = AuthStateData(INPUT, PASSWORD_REQUIREMENTS)
+
+/**
+ * Valid form state
+ */
+internal val VALID_FORM_STATE = EMPTY_STATE.copy(
+ username = "user",
+ password = "password"
+)
+
+/**
+ * Fatal error fixture
+ */
+internal val FATAL_ERROR = UnknownException("Something went wrong")
+
+/**
+ * Non-fatal error fixture
+ */
+internal val NON_FATAL_ERROR = IOException("Internet is down")
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/uiStatesFixtures.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/uiStatesFixtures.kt
new file mode 100644
index 0000000..14b7733
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/data/uiStatesFixtures.kt
@@ -0,0 +1,6 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.data
+
+/**
+ * Some UI-state to return from [com.motorro.commonstatemachine.examples.skills.auth.implementation.ui.AuthUiRenderer] mock
+ */
+internal val UI_STATE = AuthUiStateImpl.Loading
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticatingStateTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticatingStateTest.kt
new file mode 100644
index 0000000..5d5f135
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticatingStateTest.kt
@@ -0,0 +1,82 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.UI_STATE
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.VALID_FORM_STATE
+import com.motorro.commonstatemachine.skills.domain.authenticate.AuthenticateWithPassword
+import dev.mokkery.MockMode
+import dev.mokkery.answering.calls
+import dev.mokkery.answering.returns
+import dev.mokkery.answering.throws
+import dev.mokkery.every
+import dev.mokkery.everySuspend
+import dev.mokkery.matcher.any
+import dev.mokkery.mock
+import dev.mokkery.verify
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.test.Test
+
+internal class AuthenticatingStateTest : BaseStateTest() {
+ private lateinit var authenticateMock: AuthenticateWithPassword
+ private lateinit var state: AuthenticatingState
+
+ override fun doInit() {
+ authenticateMock = mock(MockMode.strict)
+ state = AuthenticatingState(context, VALID_FORM_STATE, authenticateMock)
+ every { renderer.renderLoading() } returns UI_STATE
+ }
+
+ @Test
+ fun rendersLoadingOnStart() = test {
+ everySuspend { authenticateMock(any(), any()) } calls { suspendCancellableCoroutine { } }
+
+ state.start(stateMachine)
+
+ verify {
+ renderer.renderLoading()
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun terminatesWhenAuthenticated() = test {
+ everySuspend { authenticateMock(any(), any()) } returns Unit
+ every { stateFactory.terminated(any()) } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.terminated(AuthResult(authenticated = true))
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun transfersToErrorWhenFailed() = test {
+ everySuspend { authenticateMock(any(), any()) } throws FATAL_ERROR
+ every { stateFactory.authenticationError(any(), any()) } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.authenticationError(VALID_FORM_STATE, any())
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun returnsToFormOnBackWhileAuthenticating() = test {
+ everySuspend { authenticateMock(any(), any()) } calls { suspendCancellableCoroutine { } }
+ every { stateFactory.form(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Back)
+
+ verify {
+ stateFactory.form(VALID_FORM_STATE)
+ stateMachine.setMachineState(nextState)
+ }
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticationErrorStateTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticationErrorStateTest.kt
new file mode 100644
index 0000000..163d205
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/AuthenticationErrorStateTest.kt
@@ -0,0 +1,87 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.NON_FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.UI_STATE
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.VALID_FORM_STATE
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+import dev.mokkery.answering.returns
+import dev.mokkery.every
+import dev.mokkery.matcher.any
+import dev.mokkery.verify
+import kotlin.test.Test
+
+internal class AuthenticationErrorStateTest : BaseStateTest() {
+ override fun doInit() {
+ every { renderer.renderFullScreenError(any(), any()) } returns UI_STATE
+ }
+
+ private fun createState(error: AppException) = AuthenticationErrorState(
+ context,
+ VALID_FORM_STATE,
+ error
+ )
+
+ @Test
+ fun rendersFatalErrorOnStart() = test {
+ val state = createState(FATAL_ERROR)
+ state.start(stateMachine)
+ verify {
+ renderer.renderFullScreenError(FATAL_ERROR, canRetry = false)
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun rendersNonFatalErrorOnStart() = test {
+ val state = createState(NON_FATAL_ERROR)
+ state.start(stateMachine)
+ verify {
+ renderer.renderFullScreenError(NON_FATAL_ERROR, canRetry = true)
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun returnsToFormOnBack() = test {
+ val state = createState(NON_FATAL_ERROR)
+ every { stateFactory.form(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Back)
+
+ verify {
+ stateFactory.form(VALID_FORM_STATE)
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun retriesOnActionIfRetryable() = test {
+ val state = createState(NON_FATAL_ERROR)
+ every { stateFactory.authenticating(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Action)
+
+ verify {
+ stateFactory.authenticating(VALID_FORM_STATE)
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun returnsToFormOnActionIfNotRetryable() = test {
+ val state = createState(FATAL_ERROR)
+ every { stateFactory.form(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Action)
+
+ verify {
+ stateFactory.form(VALID_FORM_STATE)
+ stateMachine.setMachineState(nextState)
+ }
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/BaseStateTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/BaseStateTest.kt
new file mode 100644
index 0000000..1d4ca54
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/BaseStateTest.kt
@@ -0,0 +1,63 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.CommonStateMachine
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.ui.AuthUiRenderer
+import com.motorro.commonstatemachine.flow.data.CommonFlowHost
+import dev.mokkery.MockMode
+import dev.mokkery.mock
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
+
+@OptIn(ExperimentalCoroutinesApi::class)
+internal abstract class BaseStateTest {
+ protected lateinit var stateMachine: CommonStateMachine
+ protected lateinit var stateFactory: AuthStateFactory
+ protected lateinit var renderer: AuthUiRenderer
+ protected lateinit var context: AuthContext
+ protected lateinit var flowHost: CommonFlowHost
+ protected lateinit var nextState: AuthState
+ protected lateinit var dispatcher: TestDispatcher
+
+ @BeforeTest
+ fun init() {
+ dispatcher = UnconfinedTestDispatcher()
+ Dispatchers.setMain(dispatcher)
+
+ stateMachine = mock(mode = MockMode.autoUnit)
+ stateFactory = mock()
+ flowHost = mock(mode = MockMode.autoUnit)
+ renderer = mock(mode = MockMode.strict)
+ nextState = AuthState()
+
+ context = object : AuthContext {
+ override val factory: AuthStateFactory = this@BaseStateTest.stateFactory
+ override val flowHost: CommonFlowHost = this@BaseStateTest.flowHost
+ override val renderer: AuthUiRenderer = this@BaseStateTest.renderer
+ }
+
+ doInit()
+ }
+
+ @AfterTest
+ fun deinit() {
+ Dispatchers.resetMain()
+ }
+
+ protected fun test(block: TestScope.() -> Unit) = runTest(
+ dispatcher,
+ testBody = block
+ )
+
+ protected open fun doInit() = Unit
+}
\ No newline at end of file
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/FormStateTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/FormStateTest.kt
new file mode 100644
index 0000000..80c6e7a
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/FormStateTest.kt
@@ -0,0 +1,125 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.EMPTY_STATE
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.PASSWORD_CHANGED
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.UI_STATE
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.USERNAME_CHANGED
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.VALID_FORM_STATE
+import dev.mokkery.answering.returns
+import dev.mokkery.every
+import dev.mokkery.matcher.any
+import dev.mokkery.verify
+import dev.mokkery.verify.VerifyMode
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal class FormStateTest : BaseStateTest() {
+ private lateinit var state: FormState
+
+ override fun doInit() {
+ state = FormState(context, EMPTY_STATE)
+ every { renderer.renderForm(any(), any()) } returns UI_STATE
+ }
+
+ @Test
+ fun rendersFormOnStart() = test {
+ state.start(stateMachine)
+ verify {
+ renderer.renderForm(EMPTY_STATE, isValid = false)
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun processesUsernameChanged() = test {
+ state.start(stateMachine)
+ state.process(USERNAME_CHANGED)
+
+ val expectedData = EMPTY_STATE.copy(username = USERNAME_CHANGED.value)
+ verify(mode = VerifyMode.order) {
+ renderer.renderForm(EMPTY_STATE, isValid = false)
+ renderer.renderForm(expectedData, isValid = false)
+ }
+ assertEquals(USERNAME_CHANGED.value, state.data.username)
+ }
+
+ @Test
+ fun processesPasswordChanged() = test {
+ state.start(stateMachine)
+ state.process(PASSWORD_CHANGED)
+
+ val expectedData = EMPTY_STATE.copy(password = PASSWORD_CHANGED.value)
+ verify(mode = VerifyMode.order) {
+ renderer.renderForm(EMPTY_STATE, isValid = false)
+ renderer.renderForm(expectedData, isValid = false)
+ }
+ assertEquals(PASSWORD_CHANGED.value, state.data.password)
+ }
+
+ @Test
+ fun processesAction() = test {
+ every { stateFactory.authenticating(any()) } returns nextState
+ state.data = VALID_FORM_STATE
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Action)
+
+ verify {
+ renderer.renderForm(VALID_FORM_STATE, isValid = true)
+ stateFactory.authenticating(VALID_FORM_STATE)
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun doesNotProcessActionIfInvalid() = test {
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Action)
+
+ verify(VerifyMode.exactly(0)) {
+ stateFactory.authenticating(any())
+ stateMachine.setMachineState(any())
+ }
+ }
+
+ @Test
+ fun processesBack() = test {
+ every { stateFactory.terminated(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Back)
+
+ verify {
+ stateFactory.terminated(AuthResult(authenticated = false))
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun processesSkip() = test {
+ every { stateFactory.terminated(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Form.Skip)
+
+ verify {
+ stateFactory.terminated(AuthResult(authenticated = false))
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun doesNotProcessSkipIfNotSkippable() = test {
+ state.data = EMPTY_STATE.copy(input = EMPTY_STATE.input.copy(skippable = false))
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Form.Skip)
+
+ verify(VerifyMode.exactly(0)) {
+ stateFactory.terminated(any())
+ stateMachine.setMachineState(any())
+ }
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingErrorStateTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingErrorStateTest.kt
new file mode 100644
index 0000000..cc51dc9
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingErrorStateTest.kt
@@ -0,0 +1,91 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.INPUT
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.NON_FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.UI_STATE
+import com.motorro.commonstatemachine.skills.domain.exception.AppException
+import dev.mokkery.answering.returns
+import dev.mokkery.every
+import dev.mokkery.matcher.any
+import dev.mokkery.verify
+import kotlin.test.Test
+
+internal class PreloadingErrorStateTest : BaseStateTest() {
+ override fun doInit() {
+ every { renderer.renderFullScreenError(any(), any()) } returns UI_STATE
+ }
+
+ private fun createState(error: AppException) = PreloadingErrorState(
+ context,
+ INPUT,
+ error
+ )
+
+ @Test
+ fun rendersFatalErrorOnStart() = test {
+ val state = createState(FATAL_ERROR)
+ state.start(stateMachine)
+ verify {
+ renderer.renderFullScreenError(FATAL_ERROR, canRetry = false)
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun rendersNonFatalErrorOnStart() = test {
+ val state = createState(NON_FATAL_ERROR)
+ state.start(stateMachine)
+ verify {
+ renderer.renderFullScreenError(NON_FATAL_ERROR, canRetry = true)
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun terminatesOnBack() = test {
+ val state = createState(NON_FATAL_ERROR)
+
+ every { stateFactory.terminated(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Back)
+
+ verify {
+ stateFactory.terminated(AuthResult(authenticated = false))
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun terminatesOnActionIfCannotRetry() = test {
+ val state = createState(FATAL_ERROR)
+
+ every { stateFactory.terminated(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Action)
+
+ verify {
+ stateFactory.terminated(AuthResult(authenticated = false))
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun reloadsOnActionIfCanRetry() = test {
+ val state = createState(NON_FATAL_ERROR)
+
+ every { stateFactory.preloading(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Action)
+
+ verify {
+ stateFactory.preloading(INPUT)
+ stateMachine.setMachineState(nextState)
+ }
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingStateTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingStateTest.kt
new file mode 100644
index 0000000..3017c63
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/state/PreloadingStateTest.kt
@@ -0,0 +1,82 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.state
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthGestureImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.INPUT
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.PASSWORD_REQUIREMENTS
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.UI_STATE
+import com.motorro.commonstatemachine.skills.domain.authenticate.GetPasswordRequirements
+import dev.mokkery.answering.calls
+import dev.mokkery.answering.returns
+import dev.mokkery.answering.throws
+import dev.mokkery.every
+import dev.mokkery.everySuspend
+import dev.mokkery.matcher.any
+import dev.mokkery.mock
+import dev.mokkery.verify
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.test.Test
+
+internal class PreloadingStateTest : BaseStateTest() {
+ private lateinit var requirementsMock: GetPasswordRequirements
+ private lateinit var state: PreloadingState
+
+ override fun doInit() {
+ requirementsMock = mock()
+ state = PreloadingState(context, INPUT, requirementsMock)
+ every { renderer.renderLoading() } returns UI_STATE
+ }
+
+ @Test
+ fun rendersLoadingOnStart() = test {
+ everySuspend { requirementsMock() } calls { suspendCancellableCoroutine { } }
+
+ state.start(stateMachine)
+
+ verify {
+ renderer.renderLoading()
+ stateMachine.setUiState(UI_STATE)
+ }
+ }
+
+ @Test
+ fun transfersToFormWhenLoaded() = test {
+ everySuspend { requirementsMock() } returns PASSWORD_REQUIREMENTS
+ every { stateFactory.form(any()) } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.form(any())
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun transfersToErrorWhenFailed() = test {
+ everySuspend { requirementsMock() } throws FATAL_ERROR
+ every { stateFactory.preloadError(any(), any()) } returns nextState
+
+ state.start(stateMachine)
+
+ verify {
+ stateFactory.preloadError(INPUT, any())
+ stateMachine.setMachineState(nextState)
+ }
+ }
+
+ @Test
+ fun terminatesOnBackWhileLoading() = test {
+ everySuspend { requirementsMock() } calls { suspendCancellableCoroutine { } }
+ every { stateFactory.terminated(any()) } returns nextState
+
+ state.start(stateMachine)
+ state.process(AuthGestureImpl.Back)
+
+ verify {
+ stateFactory.terminated(AuthResult(authenticated = false))
+ stateMachine.setMachineState(nextState)
+ }
+ }
+}
diff --git a/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRendererImplTest.kt b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRendererImplTest.kt
new file mode 100644
index 0000000..7e59579
--- /dev/null
+++ b/examples/skills/auth/implementation/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/skills/auth/implementation/ui/AuthUiRendererImplTest.kt
@@ -0,0 +1,63 @@
+package com.motorro.commonstatemachine.examples.skills.auth.implementation.ui
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.AuthUiStateImpl
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.EMPTY_STATE
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.FATAL_ERROR
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.data.VALID_FORM_STATE
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+internal class AuthUiRendererImplTest {
+ private val renderer = AuthUiRendererImpl()
+
+ @Test
+ fun rendersLoading() {
+ assertEquals(AuthUiStateImpl.Loading, renderer.renderLoading())
+ }
+
+ @Test
+ fun rendersForm() {
+ val uiState = renderer.renderForm(VALID_FORM_STATE, isValid = true)
+ val expected = AuthUiStateImpl.Form(
+ username = VALID_FORM_STATE.username,
+ password = VALID_FORM_STATE.password,
+ passwordRequirements = VALID_FORM_STATE.passwordRequirements.description,
+ loginEnabled = true,
+ canSkip = true
+ )
+ assertEquals(expected, uiState)
+ }
+
+ @Test
+ fun rendersFormInvalid() {
+ val uiState = renderer.renderForm(EMPTY_STATE, isValid = false)
+ val expected = AuthUiStateImpl.Form(
+ username = EMPTY_STATE.username,
+ password = EMPTY_STATE.password,
+ passwordRequirements = EMPTY_STATE.passwordRequirements.description,
+ loginEnabled = false,
+ canSkip = true
+ )
+ assertEquals(expected, uiState)
+ }
+
+ @Test
+ fun rendersFullScreenError() {
+ val uiState = renderer.renderFullScreenError(FATAL_ERROR, canRetry = false)
+ val expected = AuthUiStateImpl.Error(
+ message = FATAL_ERROR.message,
+ canRetry = false
+ )
+ assertEquals(expected, uiState)
+ }
+
+ @Test
+ fun rendersFullScreenErrorWithRetry() {
+ val uiState = renderer.renderFullScreenError(FATAL_ERROR, canRetry = true)
+ val expected = AuthUiStateImpl.Error(
+ message = FATAL_ERROR.message,
+ canRetry = true
+ )
+ assertEquals(expected, uiState)
+ }
+}
diff --git a/examples/skills/auth/journey/.gitignore b/examples/skills/auth/journey/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/examples/skills/auth/journey/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/examples/skills/auth/journey/build.gradle.kts b/examples/skills/auth/journey/build.gradle.kts
new file mode 100644
index 0000000..2d0f253
--- /dev/null
+++ b/examples/skills/auth/journey/build.gradle.kts
@@ -0,0 +1,67 @@
+@file:Suppress("UnstableApiUsage")
+
+/*
+* Copyright 2026 Nikolai Kotchetkov.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* 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.
+*/
+
+plugins {
+ alias(libs.plugins.motorro.android.app)
+ alias(libs.plugins.koin)
+}
+
+android {
+ defaultConfig {
+ minSdk = 34
+ }
+
+ testOptions {
+ suites {
+ create("journeys") {
+ targets {
+ create("default") {
+
+ }
+ }
+ useJunitEngine {
+ inputs += listOf(com.android.build.api.dsl.AgpTestSuiteInputParameters.TESTED_APKS)
+ includeEngines += listOf("journeys-test-engine")
+ enginesDependencies(libs.junit.platform.launcher)
+ enginesDependencies(libs.junit.platform.engine)
+ enginesDependencies(libs.journeys.junit.engine)
+ }
+ targetVariants += listOf("debug")
+ }
+ }
+ }
+}
+
+dependencies {
+ implementation(project(":examples:skills:appcore"))
+ implementation(project(":examples:skills:domain"))
+ implementation(project(":examples:skills:auth:api"))
+ implementation(project(":examples:skills:auth:implementation"))
+ implementation(project(":commonstatemachine"))
+ implementation(project(":coroutines"))
+ implementation(project(":commonflow:commonflow-data"))
+ implementation(project(":commonflow:commonflow-compose"))
+ implementation(project(":commonflow:commonflow-viewmodel"))
+
+ implementation(libs.napier)
+
+ implementation(platform(libs.koin.bom))
+ implementation(libs.koin.core)
+ implementation(libs.koin.annotations)
+ implementation(libs.koin.core.viewmodel)
+ implementation(libs.koin.android)
+ implementation(libs.koin.compose)
+ implementation(libs.koin.compose.viewmodel)
+}
diff --git a/examples/skills/auth/journey/proguard-rules.pro b/examples/skills/auth/journey/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/examples/skills/auth/journey/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/journeys/auth.journey.xml b/examples/skills/auth/journey/src/journeys/auth.journey.xml
new file mode 100644
index 0000000..b9083f0
--- /dev/null
+++ b/examples/skills/auth/journey/src/journeys/auth.journey.xml
@@ -0,0 +1,10 @@
+
+
+ Test authentication happy path with valid credentials
+
+ Wait for the authentication form to open.
+ Type "user" into the username field and "password" into the password field.
+ Tap the Login button to submit the form.
+ Verify that authentication succeeds and the screen displays "authenticated: true".
+
+
diff --git a/examples/skills/auth/journey/src/journeys/authentication_failure.journey.xml b/examples/skills/auth/journey/src/journeys/authentication_failure.journey.xml
new file mode 100644
index 0000000..9c3c511
--- /dev/null
+++ b/examples/skills/auth/journey/src/journeys/authentication_failure.journey.xml
@@ -0,0 +1,12 @@
+
+
+ Test that submitting a wrong password for a known username shows an authentication error, and that closing it returns to the form
+
+ Wait for the authentication form to open.
+ Type "user" into the username field and "wrongpass" into the password field. Submit the form with the Login button.
+ Verify that an error screen appears showing the message "Invalid username or password".
+ Verify that the screen shows a Close button, not a Retry button.
+ Tap the Close button.
+ Verify that the authentication form opens.
+
+
diff --git a/examples/skills/auth/journey/src/journeys/invalid_password.journey.xml b/examples/skills/auth/journey/src/journeys/invalid_password.journey.xml
new file mode 100644
index 0000000..772be8e
--- /dev/null
+++ b/examples/skills/auth/journey/src/journeys/invalid_password.journey.xml
@@ -0,0 +1,11 @@
+
+
+ Test that login button remains disabled when password does not meet requirements
+
+ Wait for the authentication form to open.
+ Type "user" into the username field.
+ Read and verify the password requirements displayed on the screen.
+ Type some invalid password into the password field.
+ Verify that the Login submit button is disabled.
+
+
diff --git a/examples/skills/auth/journey/src/main/AndroidManifest.xml b/examples/skills/auth/journey/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e347350
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/App.kt b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/App.kt
new file mode 100644
index 0000000..de82446
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/App.kt
@@ -0,0 +1,25 @@
+package com.motorro.commonstatemachine.examples.skills.auth.journey
+
+import android.app.Application
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.annotation.KoinApplication
+import org.koin.plugin.module.dsl.startKoin
+
+@KoinApplication(modules = [AppModule::class])
+class App : Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ Napier.base(DebugAntilog())
+
+ startKoin {
+ allowOverride(false)
+ androidLogger()
+ androidContext(this@App)
+ }
+ }
+}
+
diff --git a/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/AppModule.kt b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/AppModule.kt
new file mode 100644
index 0000000..8833678
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/AppModule.kt
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.skills.auth.journey
+
+import com.motorro.commonstatemachine.examples.skills.auth.implementation.AuthModule
+import com.motorro.commonstatemachine.skills.domain.authenticate.AuthenticateWithPassword
+import com.motorro.commonstatemachine.skills.domain.authenticate.GetPasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.exception.AuthenticationException
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.delay
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+import org.koin.core.annotation.Single
+import kotlin.time.Duration.Companion.seconds
+
+const val USERNAME = "user"
+const val PASSWORD = "password"
+
+/**
+ * Demo fixtures for Happy Path flavor
+ */
+@Module(includes = [AuthModule::class])
+@ComponentScan
+class AppModule {
+
+ @Single
+ fun getPasswordRequirements(): GetPasswordRequirements {
+ val tag = GetPasswordRequirements::class.simpleName!!
+ return object : GetPasswordRequirements {
+ override suspend fun invoke(): PasswordRequirements {
+ delay(2.seconds)
+ Napier.d(tag = tag) { "Emulating success" }
+ return PasswordRequirements(
+ regex = "^.{8,}$".toRegex(),
+ description = "Minimum eight characters"
+ )
+ }
+ }
+ }
+
+ @Single
+ fun authenticateWithPassword(): AuthenticateWithPassword {
+ val tag = AuthenticateWithPassword::class.simpleName!!
+ return object : AuthenticateWithPassword {
+ override suspend fun invoke(username: Username, password: String) {
+ delay(2.seconds)
+ if (USERNAME != username.value || PASSWORD != password) {
+ Napier.d(tag = tag) { "Emulating failure" }
+ throw AuthenticationException("Invalid username or password")
+ }
+ Napier.d(tag = tag) { "Emulating success" }
+ }
+ }
+ }
+}
diff --git a/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/MainActivity.kt b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/MainActivity.kt
new file mode 100644
index 0000000..fbdc9c0
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/MainActivity.kt
@@ -0,0 +1,114 @@
+package com.motorro.commonstatemachine.examples.skills.auth.journey
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.BackHandler
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.design.SkillsAppBar
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.Dimensions
+import com.motorro.commonstatemachine.examples.auth.appcore.ui.theme.SkillsTheme
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiApi
+import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowComposition
+import io.github.aakira.napier.Napier
+import org.koin.compose.koinInject
+import org.koin.compose.viewmodel.koinViewModel
+
+class MainActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ enableEdgeToEdge()
+ setContent {
+
+ val (result, setResult) = remember {
+ mutableStateOf(null)
+ }
+
+ SkillsTheme {
+ Scaffold(
+ topBar = {
+ SkillsAppBar(
+ title = stringResource(R.string.app_name),
+ modifier = Modifier.fillMaxWidth(),
+ topLevel = true
+ )
+ }
+ ) { paddingValues ->
+ if (null == result) {
+ MainScreen(
+ modifier = Modifier.padding(paddingValues),
+ onComplete = setResult
+ )
+ } else {
+ ResultScreen(result) {
+ finish()
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Feature composition
+ */
+@Composable
+private fun MainScreen(modifier: Modifier = Modifier, onComplete: (AuthResult) -> Unit) {
+ val viewModel: MainViewModel = koinViewModel()
+ val uiApi: AuthUiApi = koinInject()
+
+ CommonFlowComposition(
+ viewModel = viewModel,
+ navigationBackHandler = { enabled, onBack ->
+ BackHandler(enabled, onBack)
+ },
+ content = { state, onGesture ->
+ uiApi.Screen(
+ state = state,
+ onGesture = onGesture,
+ modifier = modifier
+ )
+ },
+ finish = {
+ Napier.i { "Finished with: $it" }
+ onComplete(it)
+ }
+ )
+}
+
+/**
+ * Describes the flow result
+ */
+@Composable
+private fun ResultScreen(result: AuthResult, onComplete: () -> Unit) {
+ Column(
+ modifier = Modifier.fillMaxSize(),
+ verticalArrangement = Arrangement.spacedBy(Dimensions.medium, Alignment.CenterVertically),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Text(
+ style = MaterialTheme.typography.bodyLarge,
+ text = stringResource(R.string.result_authenticated, result.authenticated)
+ )
+ Button(onClick = onComplete) {
+ Text(text = stringResource(R.string.btn_exit))
+ }
+ }
+}
diff --git a/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/MainViewModel.kt b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/MainViewModel.kt
new file mode 100644
index 0000000..d3df77a
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/kotlin/com/motorro/commonstatemachine/examples/skills/auth/journey/MainViewModel.kt
@@ -0,0 +1,15 @@
+package com.motorro.commonstatemachine.examples.skills.auth.journey
+
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthDataApi
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthGesture
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthInput
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthResult
+import com.motorro.commonstatemachine.examples.skills.auth.api.AuthUiState
+import com.motorro.commonstatemachine.flow.viewmodel.CommonFlowViewModel
+import org.koin.core.annotation.KoinViewModel
+
+@KoinViewModel
+class MainViewModel (api: AuthDataApi) : CommonFlowViewModel(
+ api = api,
+ init = AuthInput(skippable = true)
+)
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/skills/auth/journey/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..40ce517
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/res/drawable/ic_launcher_background.xml b/examples/skills/auth/journey/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..997ef0b
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/welcome/commonregister/src/androidMain/res/values/strings.xml b/examples/skills/auth/journey/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 73%
rename from examples/welcome/commonregister/src/androidMain/res/values/strings.xml
rename to examples/skills/auth/journey/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index 289a66a..0147ca8 100644
--- a/examples/welcome/commonregister/src/androidMain/res/values/strings.xml
+++ b/examples/skills/auth/journey/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -12,7 +12,7 @@
~ limitations under the License.
-->
-
- Password should be at least 6 chars long
- Passwords mismatch
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/AndroidManifest.xml b/examples/skills/auth/journey/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 73%
rename from examples/welcome/login/src/main/AndroidManifest.xml
rename to examples/skills/auth/journey/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index cfc666d..0147ca8 100644
--- a/examples/welcome/login/src/main/AndroidManifest.xml
+++ b/examples/skills/auth/journey/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -12,6 +12,7 @@
~ limitations under the License.
-->
-
-
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/res/values/strings.xml b/examples/skills/auth/journey/src/main/res/values/strings.xml
new file mode 100644
index 0000000..4d15595
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/res/values/strings.xml
@@ -0,0 +1,5 @@
+
+ Auth Demo
+ Authenticated: %b
+ Exit
+
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/res/xml/backup_rules.xml b/examples/skills/auth/journey/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..fa0f996
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/res/xml/data_extraction_rules.xml b/examples/skills/auth/journey/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/skills/auth/journey/src/main/res/xml/network_security_config.xml b/examples/skills/auth/journey/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..c64cff3
--- /dev/null
+++ b/examples/skills/auth/journey/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+ 10.0.2.2
+
+
diff --git a/examples/skills/domain/build.gradle.kts b/examples/skills/domain/build.gradle.kts
new file mode 100644
index 0000000..d1b4748
--- /dev/null
+++ b/examples/skills/domain/build.gradle.kts
@@ -0,0 +1,25 @@
+/*
+* Copyright 2023 Nikolai Kotchetkov.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* 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.
+*/
+
+plugins {
+ alias(libs.plugins.motorro.kmp)
+}
+
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ api(libs.kotlin.coroutines.core)
+ }
+ }
+}
+
diff --git a/examples/skills/domain/consumer-rules.pro b/examples/skills/domain/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/AuthenticateWithPassword.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/AuthenticateWithPassword.kt
new file mode 100644
index 0000000..1a58d49
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/AuthenticateWithPassword.kt
@@ -0,0 +1,15 @@
+package com.motorro.commonstatemachine.skills.domain.authenticate
+
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+
+/**
+ * Authenticates with a password
+ */
+interface AuthenticateWithPassword {
+ /**
+ * Authenticates with [username] and [password]
+ * @param username Username
+ * @param password Password
+ */
+ suspend operator fun invoke(username: Username, password: String)
+}
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/GetPasswordRequirements.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/GetPasswordRequirements.kt
new file mode 100644
index 0000000..cfc66ff
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/GetPasswordRequirements.kt
@@ -0,0 +1,13 @@
+package com.motorro.commonstatemachine.skills.domain.authenticate
+
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+
+/**
+ * Loads password requirements
+ */
+interface GetPasswordRequirements {
+ /**
+ * Loads password requirements
+ */
+ suspend operator fun invoke(): PasswordRequirements
+}
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/data/PasswordRequirements.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/data/PasswordRequirements.kt
new file mode 100644
index 0000000..01bb73a
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/authenticate/data/PasswordRequirements.kt
@@ -0,0 +1,11 @@
+package com.motorro.commonstatemachine.skills.domain.authenticate.data
+
+/**
+ * Password requirements
+ * @property regex Regular expression to match the password
+ * @property description Description of the password requirements
+ */
+data class PasswordRequirements(
+ val regex: Regex,
+ val description: String
+)
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/AppException.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/AppException.kt
new file mode 100644
index 0000000..4812838
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/AppException.kt
@@ -0,0 +1,35 @@
+package com.motorro.commonstatemachine.skills.domain.exception
+
+/**
+ * Base domain exception
+ * @property message Error message
+ * @property cause Error cause if any
+ */
+abstract class AppException(final override val message: String, final override val cause: Throwable? = null) : RuntimeException() {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (other == null || this::class != other::class) return false
+
+ other as AppException
+
+ if (message != other.message) return false
+ if (cause != other.cause) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = message.hashCode()
+ result = 31 * result + (cause?.hashCode() ?: 0)
+ return result
+ }
+}
+
+/**
+ * Converts exception to domain
+ */
+fun Throwable.toAppException(): AppException = when(this) {
+ is AppException -> this
+ else -> UnknownException(message ?: "UNKNOWN exception", this)
+}
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/AuthenticationException.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/AuthenticationException.kt
new file mode 100644
index 0000000..6bd8c7f
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/AuthenticationException.kt
@@ -0,0 +1,6 @@
+package com.motorro.commonstatemachine.skills.domain.exception
+
+/**
+ * Authentication exception
+ */
+class AuthenticationException(message: String, cause: Throwable? = null) : AppException(message, cause)
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/IOException.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/IOException.kt
new file mode 100644
index 0000000..ab5320d
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/IOException.kt
@@ -0,0 +1,6 @@
+package com.motorro.commonstatemachine.skills.domain.exception
+
+/**
+ * IO exception
+ */
+class IOException(message: String, cause: Throwable? = null) : AppException(message, cause)
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/UnknownException.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/UnknownException.kt
new file mode 100644
index 0000000..2259626
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/exception/UnknownException.kt
@@ -0,0 +1,6 @@
+package com.motorro.commonstatemachine.skills.domain.exception
+
+/**
+ * Unknown exception
+ */
+class UnknownException(message: String, cause: Throwable? = null) : AppException(message, cause)
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/GetFriendList.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/GetFriendList.kt
new file mode 100644
index 0000000..1a19efd
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/GetFriendList.kt
@@ -0,0 +1,11 @@
+package com.motorro.commonstatemachine.skills.domain.friends
+
+import com.motorro.commonstatemachine.skills.domain.friends.data.Friend
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Retrieves a friend list
+ */
+interface GetFriendList {
+ operator fun invoke(): Flow>
+}
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/data/Friend.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/data/Friend.kt
new file mode 100644
index 0000000..dae8b90
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/data/Friend.kt
@@ -0,0 +1,3 @@
+package com.motorro.commonstatemachine.skills.domain.friends.data
+
+data class Friend(val id: Int, val data: FriendData)
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/data/FriendData.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/data/FriendData.kt
new file mode 100644
index 0000000..da8cb5d
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/friends/data/FriendData.kt
@@ -0,0 +1,9 @@
+package com.motorro.commonstatemachine.skills.domain.friends.data
+
+/**
+ * Friend properties
+ */
+data class FriendData(
+ val name: String,
+ val age: Int
+)
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/SessionManager.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/SessionManager.kt
new file mode 100644
index 0000000..76f8b7b
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/SessionManager.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.skills.domain.session
+
+import com.motorro.commonstatemachine.skills.domain.session.data.Session
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Session manager
+ */
+interface SessionManager {
+ /**
+ * Session state
+ */
+ val session: Flow
+
+ /**
+ * Updates session state
+ * @param session New session state
+ */
+ suspend fun update(session: Session)
+}
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/data/Session.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/data/Session.kt
new file mode 100644
index 0000000..29f49fd
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/data/Session.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.skills.domain.session.data
+
+/**
+ * Session state
+ */
+sealed class Session {
+ /**
+ * No session
+ */
+ data object None : Session()
+
+ /**
+ * Session is active
+ */
+ data class Active(val username: Username) : Session()
+}
\ No newline at end of file
diff --git a/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/data/Username.kt b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/data/Username.kt
new file mode 100644
index 0000000..bcd923c
--- /dev/null
+++ b/examples/skills/domain/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/domain/session/data/Username.kt
@@ -0,0 +1,6 @@
+package com.motorro.commonstatemachine.skills.domain.session.data
+
+import kotlin.jvm.JvmInline
+
+@JvmInline
+value class Username(val value: String)
\ No newline at end of file
diff --git a/examples/skills/usecase/build.gradle.kts b/examples/skills/usecase/build.gradle.kts
new file mode 100644
index 0000000..5eaed0a
--- /dev/null
+++ b/examples/skills/usecase/build.gradle.kts
@@ -0,0 +1,31 @@
+@file:Suppress("unused")
+
+/*
+* Copyright 2023 Nikolai Kotchetkov.
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+* http://www.apache.org/licenses/LICENSE-2.0
+* Unless required by applicable law or agreed to in writing, software
+* 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.
+*/
+
+plugins {
+ alias(libs.plugins.motorro.cmp)
+ alias(libs.plugins.koin)
+}
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ implementation(project(":examples:skills:domain"))
+ implementation(project.dependencies.platform(libs.koin.bom))
+ implementation(libs.koin.core)
+ implementation(libs.koin.annotations)
+ implementation(libs.napier)
+ }
+ }
+}
+
diff --git a/examples/skills/usecase/consumer-rules.pro b/examples/skills/usecase/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/Fixtures.kt b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/Fixtures.kt
new file mode 100644
index 0000000..2ed4ece
--- /dev/null
+++ b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/Fixtures.kt
@@ -0,0 +1,32 @@
+package com.motorro.commonstatemachine.skills.usecase
+
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.friends.data.Friend
+import com.motorro.commonstatemachine.skills.domain.friends.data.FriendData
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import kotlin.time.Duration.Companion.seconds
+
+internal object Fixtures {
+
+ val NETWORK_DELAY = 2.seconds
+
+ object Authentication {
+ val REQUIREMENTS = PasswordRequirements(
+ regex = "^.{8,}$".toRegex(),
+ description = "Minimum eight characters"
+ )
+
+ val USERNAME = Username("user")
+
+ const val PASSWORD = "password"
+ }
+
+ val FRIENDS = listOf(
+ Friend(1, FriendData("Alice", 28)),
+ Friend(2, FriendData("Bob", 32)),
+ Friend(3, FriendData("Charlie", 25)),
+ Friend(4, FriendData("Diana", 30)),
+ Friend(5, FriendData("Evan", 22))
+ )
+}
+
diff --git a/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/UsecaseModule.kt b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/UsecaseModule.kt
new file mode 100644
index 0000000..df461a0
--- /dev/null
+++ b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/UsecaseModule.kt
@@ -0,0 +1,8 @@
+package com.motorro.commonstatemachine.skills.usecase
+
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+
+@Module
+@ComponentScan
+class UsecaseModule
\ No newline at end of file
diff --git a/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/authenticate/AuthenticateWithPasswordImpl.kt b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/authenticate/AuthenticateWithPasswordImpl.kt
new file mode 100644
index 0000000..b91f9a1
--- /dev/null
+++ b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/authenticate/AuthenticateWithPasswordImpl.kt
@@ -0,0 +1,26 @@
+package com.motorro.commonstatemachine.skills.usecase.authenticate
+
+import com.motorro.commonstatemachine.skills.domain.authenticate.AuthenticateWithPassword
+import com.motorro.commonstatemachine.skills.domain.exception.AuthenticationException
+import com.motorro.commonstatemachine.skills.domain.session.SessionManager
+import com.motorro.commonstatemachine.skills.domain.session.data.Session
+import com.motorro.commonstatemachine.skills.domain.session.data.Username
+import com.motorro.commonstatemachine.skills.usecase.Fixtures.Authentication
+import com.motorro.commonstatemachine.skills.usecase.Fixtures.NETWORK_DELAY
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.delay
+import org.koin.core.annotation.Factory
+
+@Factory
+internal class AuthenticateWithPasswordImpl(private val sessionManager: SessionManager) : AuthenticateWithPassword {
+ override suspend fun invoke(username: Username, password: String) {
+ Napier.i { "Authenticating: ${username.value}..." }
+ delay(NETWORK_DELAY)
+ if (Authentication.USERNAME == username && Authentication.PASSWORD == password) {
+ sessionManager.update(Session.Active(username))
+ } else {
+ Napier.w { "Authentication failed" }
+ throw AuthenticationException("Invalid login or password")
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/authenticate/GetPasswordRequirementsImpl.kt b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/authenticate/GetPasswordRequirementsImpl.kt
new file mode 100644
index 0000000..7b82ff6
--- /dev/null
+++ b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/authenticate/GetPasswordRequirementsImpl.kt
@@ -0,0 +1,16 @@
+package com.motorro.commonstatemachine.skills.usecase.authenticate
+
+import com.motorro.commonstatemachine.skills.domain.authenticate.GetPasswordRequirements
+import com.motorro.commonstatemachine.skills.domain.authenticate.data.PasswordRequirements
+import com.motorro.commonstatemachine.skills.usecase.Fixtures
+import com.motorro.commonstatemachine.skills.usecase.Fixtures.NETWORK_DELAY
+import kotlinx.coroutines.delay
+import org.koin.core.annotation.Factory
+
+@Factory
+internal class GetPasswordRequirementsImpl : GetPasswordRequirements {
+ override suspend fun invoke(): PasswordRequirements {
+ delay(NETWORK_DELAY)
+ return Fixtures.Authentication.REQUIREMENTS
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/friends/GetFriendListImpl.kt b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/friends/GetFriendListImpl.kt
new file mode 100644
index 0000000..d9ed656
--- /dev/null
+++ b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/friends/GetFriendListImpl.kt
@@ -0,0 +1,20 @@
+package com.motorro.commonstatemachine.skills.usecase.friends
+
+import com.motorro.commonstatemachine.skills.domain.friends.GetFriendList
+import com.motorro.commonstatemachine.skills.domain.friends.data.Friend
+import com.motorro.commonstatemachine.skills.usecase.Fixtures
+import com.motorro.commonstatemachine.skills.usecase.Fixtures.NETWORK_DELAY
+import io.github.aakira.napier.Napier
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import org.koin.core.annotation.Factory
+
+@Factory
+internal class GetFriendListImpl : GetFriendList {
+ override fun invoke(): Flow> = flow {
+ Napier.i { "Loading friend list..." }
+ delay(NETWORK_DELAY)
+ emit(Fixtures.FRIENDS)
+ }
+}
\ No newline at end of file
diff --git a/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/session/SessionManagerImpl.kt b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/session/SessionManagerImpl.kt
new file mode 100644
index 0000000..b066ab6
--- /dev/null
+++ b/examples/skills/usecase/src/commonMain/kotlin/com/motorro/commonstatemachine/skills/usecase/session/SessionManagerImpl.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2026 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.skills.usecase.session
+
+import com.motorro.commonstatemachine.skills.domain.session.SessionManager
+import com.motorro.commonstatemachine.skills.domain.session.data.Session
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.koin.core.annotation.Single
+
+@Single
+internal class SessionManagerImpl() : SessionManager {
+ override val session: Flow field = MutableStateFlow(Session.None)
+
+ override suspend fun update(session: Session) {
+ this.session.emit(session)
+ }
+}
\ No newline at end of file
diff --git a/examples/timer/build.gradle.kts b/examples/timer/build.gradle.kts
index e4f7989..922a670 100644
--- a/examples/timer/build.gradle.kts
+++ b/examples/timer/build.gradle.kts
@@ -12,39 +12,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
- alias(libs.plugins.compose)
+ alias(libs.plugins.motorro.cmp)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = "com.motorro"
-version = versionName
-
kotlin {
- jvmToolchain(21)
-
- android {
- namespace = "com.motorro.statemachine.timer"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- withHostTest {
- isIncludeAndroidResources = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
sourceSets {
commonMain.dependencies {
implementation(project(":commonstatemachine"))
@@ -54,21 +27,8 @@ kotlin {
implementation(libs.kotlin.datetime)
}
commonTest.dependencies {
- implementation(libs.test.kotlin)
implementation(libs.test.kotlin.coroutines)
}
- androidMain.dependencies {
- implementation(libs.timber)
- implementation(libs.kotlin.coroutines.android)
-
- implementation(project.dependencies.platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.viewmodel)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts)
- }
}
}
diff --git a/examples/timer/consumer-rules.pro b/examples/timer/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerGesture.kt b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerGesture.kt
similarity index 92%
rename from examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerGesture.kt
rename to examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerGesture.kt
index 7c0bd68..47adf0f 100644
--- a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerGesture.kt
+++ b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerGesture.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.data
+package com.motorro.commonstatemachine.examples.timer.data
/**
* Timer gesture
diff --git a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerKey.kt b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerKey.kt
similarity index 93%
rename from examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerKey.kt
rename to examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerKey.kt
index 2ccbd91..9adbe00 100644
--- a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerKey.kt
+++ b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerKey.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.data
+package com.motorro.commonstatemachine.examples.timer.data
import com.motorro.commonstatemachine.multi.MachineKey
diff --git a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerUiState.kt b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerUiState.kt
similarity index 94%
rename from examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerUiState.kt
rename to examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerUiState.kt
index a1ff1d4..1bc6bd4 100644
--- a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/data/TimerUiState.kt
+++ b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/data/TimerUiState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.data
+package com.motorro.commonstatemachine.examples.timer.data
import kotlin.time.Duration
diff --git a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/state/TimerState.kt b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/state/TimerState.kt
similarity index 93%
rename from examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/state/TimerState.kt
rename to examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/state/TimerState.kt
index 5e7cd4b..672b2a3 100644
--- a/examples/timer/src/commonMain/kotlin/com/motorro/statemachine/timer/state/TimerState.kt
+++ b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/state/TimerState.kt
@@ -11,14 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.state
+package com.motorro.commonstatemachine.examples.timer.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
import com.motorro.commonstatemachine.coroutines.lifecycle.asFlow
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.timer.data.TimerGesture
+import com.motorro.commonstatemachine.examples.timer.data.TimerUiState
import com.motorro.commonstatemachine.lifecycle.MachineLifecycle
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.timer.data.TimerGesture
-import com.motorro.statemachine.timer.data.TimerUiState
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.delay
diff --git a/examples/timer/src/androidMain/kotlin/com/motorro/statemachine/timer/ui/TimerScreen.kt b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/ui/TimerScreen.kt
similarity index 91%
rename from examples/timer/src/androidMain/kotlin/com/motorro/statemachine/timer/ui/TimerScreen.kt
rename to examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/ui/TimerScreen.kt
index 5416064..fd5e943 100644
--- a/examples/timer/src/androidMain/kotlin/com/motorro/statemachine/timer/ui/TimerScreen.kt
+++ b/examples/timer/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/timer/ui/TimerScreen.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.ui
+package com.motorro.commonstatemachine.examples.timer.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -23,8 +23,8 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import com.motorro.statemachine.timer.data.TimerGesture
-import com.motorro.statemachine.timer.data.TimerUiState
+import com.motorro.commonstatemachine.examples.timer.data.TimerGesture
+import com.motorro.commonstatemachine.examples.timer.data.TimerUiState
import kotlin.time.Duration
@Composable
diff --git a/examples/timer/src/commonTest/kotlin/com/motorro/statemachine/timer/state/RunningTest.kt b/examples/timer/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/timer/state/RunningTest.kt
similarity index 94%
rename from examples/timer/src/commonTest/kotlin/com/motorro/statemachine/timer/state/RunningTest.kt
rename to examples/timer/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/timer/state/RunningTest.kt
index 90fdc1a..a269250 100644
--- a/examples/timer/src/commonTest/kotlin/com/motorro/statemachine/timer/state/RunningTest.kt
+++ b/examples/timer/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/timer/state/RunningTest.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.state
+package com.motorro.commonstatemachine.examples.timer.state
+import com.motorro.commonstatemachine.examples.timer.data.TimerGesture
+import com.motorro.commonstatemachine.examples.timer.data.TimerUiState
import com.motorro.commonstatemachine.lifecycle.ActivatedMachineLifecycle
import com.motorro.commonstatemachine.lifecycle.MachineLifecycle
-import com.motorro.statemachine.timer.data.TimerGesture
-import com.motorro.statemachine.timer.data.TimerUiState
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
diff --git a/examples/timer/src/commonTest/kotlin/com/motorro/statemachine/timer/state/mocks.kt b/examples/timer/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/timer/state/mocks.kt
similarity index 96%
rename from examples/timer/src/commonTest/kotlin/com/motorro/statemachine/timer/state/mocks.kt
rename to examples/timer/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/timer/state/mocks.kt
index 9a68d43..fe6876c 100644
--- a/examples/timer/src/commonTest/kotlin/com/motorro/statemachine/timer/state/mocks.kt
+++ b/examples/timer/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/timer/state/mocks.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.timer.state
+package com.motorro.commonstatemachine.examples.timer.state
import com.motorro.commonstatemachine.CommonMachineState
import com.motorro.commonstatemachine.CommonStateMachine
diff --git a/examples/welcome/app/.gitignore b/examples/welcome/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/examples/welcome/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/examples/welcome/app/build.gradle.kts b/examples/welcome/app/build.gradle.kts
new file mode 100644
index 0000000..601e2d5
--- /dev/null
+++ b/examples/welcome/app/build.gradle.kts
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+plugins {
+ alias(libs.plugins.motorro.android.app)
+ alias(libs.plugins.koin)
+}
+
+dependencies {
+ implementation(project(":commonstatemachine"))
+ implementation(project(":coroutines"))
+ implementation(project(":examples:welcome:commonapi"))
+ implementation(project(":examples:commoncore"))
+ implementation(project(":examples:welcome:login"))
+ implementation(project(":examples:welcome:register"))
+
+ implementation(platform(libs.koin.bom))
+ implementation(libs.koin.android)
+ implementation(libs.koin.compose)
+ implementation(libs.koin.compose.viewmodel)
+ implementation(libs.koin.annotations)
+
+ testImplementation(libs.test.androidx.arch)
+}
diff --git a/examples/welcome/app/proguard-rules.pro b/examples/welcome/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/examples/welcome/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/AndroidManifest.xml b/examples/welcome/app/src/main/AndroidManifest.xml
similarity index 94%
rename from examples/welcome/welcome/src/main/AndroidManifest.xml
rename to examples/welcome/app/src/main/AndroidManifest.xml
index 3ddcc43..8ae827e 100644
--- a/examples/welcome/welcome/src/main/AndroidManifest.xml
+++ b/examples/welcome/app/src/main/AndroidManifest.xml
@@ -27,7 +27,7 @@
android:theme="@style/Theme.StateMachine"
tools:targetApi="31">
diff --git a/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/App.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/App.kt
new file mode 100644
index 0000000..cd8ba1f
--- /dev/null
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/App.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.welcome.app
+
+import android.app.Application
+import com.motorro.commonstatemachine.examples.welcome.login.LoginModule
+import com.motorro.commonstatemachine.examples.welcome.register.RegisterModule
+import io.github.aakira.napier.DebugAntilog
+import io.github.aakira.napier.Napier
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.annotation.KoinApplication
+import org.koin.plugin.module.dsl.startKoin
+
+@KoinApplication(modules = [
+ RegisterModule::class,
+ LoginModule::class,
+ WelcomeModule::class,
+])
+class App : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ setupLogger()
+ startKoin {
+ allowOverride(false)
+ androidLogger()
+ androidContext(this@App)
+ }
+ Napier.d { "Started" }
+ }
+
+ private fun setupLogger() {
+ Napier.base(DebugAntilog())
+ }
+}
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/MainActivity.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/MainActivity.kt
similarity index 80%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/MainActivity.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/MainActivity.kt
index ad608a6..8399b1b 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/MainActivity.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/MainActivity.kt
@@ -11,26 +11,26 @@
* limitations under the License.
*/
-package com.motorro.statemachine
+package com.motorro.commonstatemachine.examples.welcome.app
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
-import androidx.core.view.WindowCompat
-import com.motorro.statemachine.androidcore.ui.theme.CommonStateMachineTheme
-import com.motorro.statemachine.welcome.view.WelcomeScreen
-import dagger.hilt.android.AndroidEntryPoint
-import timber.log.Timber
+import com.motorro.commonstatemachine.examples.commoncore.ui.theme.CommonStateMachineTheme
+import com.motorro.commonstatemachine.examples.welcome.app.view.WelcomeScreen
+import io.github.aakira.napier.Napier
+
-@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- WindowCompat.setDecorFitsSystemWindows(window, false)
+ enableEdgeToEdge()
+
setContent {
CommonStateMachineTheme {
Surface(
@@ -50,7 +50,7 @@ class MainActivity : ComponentActivity() {
}
override fun finish() {
- Timber.d("Activity finished")
+ Napier.d("Activity finished")
super.finish()
}
}
diff --git a/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/WelcomeModule.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/WelcomeModule.kt
new file mode 100644
index 0000000..64bd249
--- /dev/null
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/WelcomeModule.kt
@@ -0,0 +1,27 @@
+package com.motorro.commonstatemachine.examples.welcome.app
+
+import android.content.Context
+import com.motorro.commonstatemachine.examples.commoncore.coroutines.DispatcherProvider
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.Module
+
+@Module
+@ComponentScan
+class WelcomeModule {
+
+ @Factory
+ fun resourceWrapper(context: Context): ResourceWrapper = object : ResourceWrapper {
+ override fun getString(resId: Int, vararg args: Any): String = context.getString(resId, *args)
+ }
+
+ @Factory
+ fun dispatchers(): DispatcherProvider = object : DispatcherProvider {
+ override val default: CoroutineDispatcher = Dispatchers.Default
+ override val main: CoroutineDispatcher = Dispatchers.Main
+ override val io: CoroutineDispatcher = Dispatchers.IO
+ }
+}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeDataState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeDataState.kt
similarity index 91%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeDataState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeDataState.kt
index 4866fb9..c3747e6 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeDataState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeDataState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.data
+package com.motorro.commonstatemachine.examples.welcome.app.data
/**
* Welcome data state
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeGesture.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeGesture.kt
similarity index 85%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeGesture.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeGesture.kt
index f08ba30..6b49154 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeGesture.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeGesture.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.data
+package com.motorro.commonstatemachine.examples.welcome.app.data
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
/**
* Welcome flow UI gestures
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeUiState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeUiState.kt
similarity index 89%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeUiState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeUiState.kt
index 6569e8e..b4682ca 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/data/WelcomeUiState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/data/WelcomeUiState.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.data
+package com.motorro.commonstatemachine.examples.welcome.app.data
-import com.motorro.statemachine.login.data.LoginUiState
-import com.motorro.statemachine.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
/**
* Welcome flow UI state
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/WelcomeRenderer.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/WelcomeRenderer.kt
similarity index 77%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/WelcomeRenderer.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/WelcomeRenderer.kt
index fb098b1..259086c 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/WelcomeRenderer.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/WelcomeRenderer.kt
@@ -11,19 +11,18 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model
+package com.motorro.commonstatemachine.examples.welcome.app.model
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import dagger.hilt.android.scopes.ViewModelScoped
-import javax.inject.Inject
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import org.koin.core.annotation.Factory
/**
* Welcome ui-state renderer
*/
-@ViewModelScoped
-class WelcomeRenderer @Inject constructor(resourceWrapper: ResourceWrapper): ResourceWrapper by resourceWrapper {
+@Factory
+class WelcomeRenderer(resourceWrapper: ResourceWrapper): ResourceWrapper by resourceWrapper {
/**
* Renders preloading
*/
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/WelcomeViewModel.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/WelcomeViewModel.kt
similarity index 52%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/WelcomeViewModel.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/WelcomeViewModel.kt
index 8824fd6..d6744da 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/WelcomeViewModel.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/WelcomeViewModel.kt
@@ -11,58 +11,36 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model
+package com.motorro.commonstatemachine.examples.welcome.app.model
import androidx.lifecycle.ViewModel
import com.motorro.commonstatemachine.CommonMachineState
import com.motorro.commonstatemachine.coroutines.FlowStateMachine
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import com.motorro.statemachine.welcome.model.state.WelcomeStateFactory
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.ExperimentalCoroutinesApi
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.model.state.WelcomeStateFactory
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.flow.Flow
-import timber.log.Timber
-import javax.inject.Inject
+import org.koin.core.annotation.KoinViewModel
+
+@KoinViewModel
+class WelcomeViewModel(private val factory: WelcomeStateFactory) : ViewModel() {
-@HiltViewModel
-@OptIn(ExperimentalCoroutinesApi::class)
-class WelcomeViewModel @Inject constructor(private val factory: WelcomeStateFactory) : ViewModel() {
- /**
- * State machine
- */
private val stateMachine = FlowStateMachine(WelcomeUiState.Loading, ::initializeStateMachine)
- /**
- * Creates initializing state
- */
private fun initializeStateMachine(): CommonMachineState {
- Timber.d("Initializing state machine...")
+ Napier.d("Initializing state machine...")
return factory.preload()
}
- /**
- * UI State
- */
val state: Flow = stateMachine.uiState
- /**
- * Updates state with UI gesture
- * @param gesture UI gesture to proceed
- */
fun process(gesture: WelcomeGesture) {
- Timber.d("Gesture: %s", gesture)
+ Napier.d("Gesture: $gesture")
stateMachine.process(gesture)
}
- /**
- * This method will be called when this ViewModel is no longer used and will be destroyed.
- *
- *
- * It is useful when ViewModel observes some data and you need to clear this subscription to
- * prevent a leak of this ViewModel.
- */
override fun onCleared() {
stateMachine.clear()
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/CompleteState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/CompleteState.kt
similarity index 83%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/CompleteState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/CompleteState.kt
index a06b0d6..9faf5fe 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/CompleteState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/CompleteState.kt
@@ -11,10 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import timber.log.Timber
class CompleteState(
context: WelcomeContext,
@@ -36,7 +37,7 @@ class CompleteState(
}
private fun onBack() {
- Timber.d("Back. Terminating...")
+ Napier.d("Back. Terminating...")
setMachineState(factory.terminate())
}
}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/EmailCheckState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailCheckState.kt
similarity index 74%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/EmailCheckState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailCheckState.kt
index 1b5903c..c35d52e 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/EmailCheckState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailCheckState.kt
@@ -11,15 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.usecase.CheckEmail
-import dagger.hilt.android.scopes.ViewModelScoped
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.usecase.CheckEmail
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.launch
-import timber.log.Timber
-import javax.inject.Inject
+import org.koin.core.annotation.Factory
/**
* Switches login/registration flow based on hardcoded addresses
@@ -42,14 +41,14 @@ class EmailCheckState(
*/
override fun doStart() {
setUiState(renderer.renderChecking(data))
- Timber.d("Checking if user exists...")
+ Napier.d("Checking if user exists...")
stateScope.launch {
val exists = checkEmail(email)
if (exists) {
- Timber.d("Existing user. Transferring to login flow...")
+ Napier.d("Existing user. Transferring to login flow...")
setMachineState(factory.loginFlow(data))
} else {
- Timber.d("New user. Transferring to registration flow...")
+ Napier.d("New user. Transferring to registration flow...")
setMachineState(factory.registrationFlow(data))
}
}
@@ -67,12 +66,12 @@ class EmailCheckState(
* Exits app
*/
private fun onBack() {
- Timber.d("Going back to email entry...")
+ Napier.d("Going back to email entry...")
setMachineState(factory.emailEntry(data))
}
- @ViewModelScoped
- class Factory @Inject constructor(private val checkEmail: CheckEmail) {
+ @Factory
+ class StateFactory(private val checkEmail: CheckEmail) {
operator fun invoke(
context: WelcomeContext,
data: WelcomeDataState
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/EmailEntryState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailEntryState.kt
similarity index 87%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/EmailEntryState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailEntryState.kt
index 8b5619c..7387f2e 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/EmailEntryState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailEntryState.kt
@@ -11,12 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import androidx.annotation.VisibleForTesting
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import timber.log.Timber
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import io.github.aakira.napier.Napier
+
/**
* Email entry state
@@ -61,13 +62,13 @@ class EmailEntryState(
private fun onAction() {
if (data.isValid()) {
- Timber.d("Moving to checking email...")
+ Napier.d("Moving to checking email...")
setMachineState(factory.checkEmail(data))
}
}
private fun onBack() {
- Timber.d("Terminating...")
+ Napier.d("Terminating...")
setMachineState(factory.terminate())
}
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/LoginFlowState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/LoginFlowState.kt
similarity index 64%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/LoginFlowState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/LoginFlowState.kt
index e620a57..9877039 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/LoginFlowState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/LoginFlowState.kt
@@ -11,22 +11,22 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import com.motorro.commonstatemachine.CommonMachineState
import com.motorro.commonstatemachine.ProxyMachineState
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
-import com.motorro.statemachine.login.di.LoginComponentBuilder
-import com.motorro.statemachine.login.di.LoginEntryPoint
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import dagger.hilt.EntryPoints
-import dagger.hilt.android.scopes.ViewModelScoped
-import timber.log.Timber
-import javax.inject.Inject
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.login.LoginFlowStarter
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.parameter.parametersOf
/**
* Proxy for login flow
@@ -35,7 +35,7 @@ import javax.inject.Inject
class LoginFlowState(
private val context: WelcomeContext,
private val data: WelcomeDataState,
- private val loginComponentBuilder: LoginComponentBuilder
+ private val startLogin: (WelcomeFeatureHost, String) -> CommonMachineState
) : LoginProxy(LoginUiState.Loading), WelcomeFeatureHost {
/**
@@ -48,12 +48,7 @@ class LoginFlowState(
/**
* Creates initial child state
*/
- override fun init(): CommonMachineState {
- val component = loginComponentBuilder.host(this).build()
- val starter = EntryPoints.get(component, LoginEntryPoint::class.java).flowStarter()
-
- return starter.start(email)
- }
+ override fun init(): CommonMachineState = startLogin(this, email)
/**
* Maps child UI state to parent if relevant
@@ -76,7 +71,7 @@ class LoginFlowState(
* Returns user to email entry screen
*/
override fun backToEmailEntry() {
- Timber.d("Transferring to e-mail entry...")
+ Napier.d("Transferring to e-mail entry...")
setMachineState(context.factory.emailEntry(data))
}
@@ -84,19 +79,19 @@ class LoginFlowState(
* Authentication complete
*/
override fun complete() {
- Timber.d("Transferring to complete screen...")
+ Napier.d("Transferring to complete screen...")
setMachineState(context.factory.complete(email))
}
- @ViewModelScoped
- class Factory @Inject constructor(private val loginComponentBuilder: LoginComponentBuilder) {
+ @Factory
+ class StateFactory : KoinComponent {
operator fun invoke(
context: WelcomeContext,
data: WelcomeDataState
): CommonMachineState = LoginFlowState(
- context,
- data,
- loginComponentBuilder
+ context = context,
+ data = data,
+ startLogin = { host, email -> get { parametersOf(host) }.start(email) }
)
}
}
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/PreloadingState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/PreloadingState.kt
similarity index 77%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/PreloadingState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/PreloadingState.kt
index 8d97cca..d9ff9c4 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/PreloadingState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/PreloadingState.kt
@@ -11,14 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.usecase.Preload
-import dagger.hilt.android.scopes.ViewModelScoped
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.usecase.Preload
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.launch
-import timber.log.Timber
-import javax.inject.Inject
+import org.koin.core.annotation.Factory
/**
* Preloads 'data' to use in [TermsAndConditionsState]
@@ -33,7 +32,7 @@ class PreloadingState(context: WelcomeContext, private val preload: Preload) : W
setUiState(renderer.renderPreloading())
stateScope.launch {
val greeting = preload()
- Timber.d("Transferring to welcome screen...")
+ Napier.d("Transferring to welcome screen...")
setMachineState(factory.welcome(greeting))
}
}
@@ -50,12 +49,12 @@ class PreloadingState(context: WelcomeContext, private val preload: Preload) : W
* Exits app
*/
private fun onBack() {
- Timber.d("Terminating...")
+ Napier.d("Terminating...")
setMachineState(factory.terminate())
}
- @ViewModelScoped
- class Factory @Inject constructor(private val preload: Preload) {
+ @Factory
+ class StateFactory(private val preload: Preload) {
operator fun invoke(context: WelcomeContext) = PreloadingState(context, preload)
}
}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/RegistrationFlowState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/RegistrationFlowState.kt
similarity index 63%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/RegistrationFlowState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/RegistrationFlowState.kt
index 8a2821f..e46a637 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/RegistrationFlowState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/RegistrationFlowState.kt
@@ -11,31 +11,31 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import com.motorro.commonstatemachine.CommonMachineState
import com.motorro.commonstatemachine.ProxyMachineState
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
-import com.motorro.statemachine.register.di.RegisterComponentBuilder
-import com.motorro.statemachine.register.di.RegisterEntryPoint
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import dagger.hilt.EntryPoints
-import dagger.hilt.android.scopes.ViewModelScoped
-import timber.log.Timber
-import javax.inject.Inject
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.register.RegisterFlowStarter
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.get
+import org.koin.core.parameter.parametersOf
/**
* Proxy for registration flow
- * Adapts login flow sub-graph to registration flow
+ * Adapts registration flow sub-graph to welcome flow
*/
class RegistrationFlowState(
private val context: WelcomeContext,
private val data: WelcomeDataState,
- private val registerComponentBuilder: RegisterComponentBuilder
+ private val startRegister: (WelcomeFeatureHost, String) -> CommonMachineState
) : RegistrationProxy(RegisterUiState.Loading), WelcomeFeatureHost {
/**
@@ -48,12 +48,7 @@ class RegistrationFlowState(
/**
* Creates initial child state
*/
- override fun init(): CommonMachineState {
- val component = registerComponentBuilder.host(this).build()
- val starter = EntryPoints.get(component, RegisterEntryPoint::class.java).flowStarter()
-
- return starter.start(email)
- }
+ override fun init(): CommonMachineState = startRegister(this, email)
/**
* Maps child UI state to parent if relevant
@@ -76,7 +71,7 @@ class RegistrationFlowState(
* Returns user to email entry screen
*/
override fun backToEmailEntry() {
- Timber.d("Transferring to e-mail entry...")
+ Napier.d("Transferring to e-mail entry...")
setMachineState(context.factory.emailEntry(data))
}
@@ -84,19 +79,19 @@ class RegistrationFlowState(
* Authentication complete
*/
override fun complete() {
- Timber.d("Transferring to complete screen...")
+ Napier.d("Transferring to complete screen...")
setMachineState(context.factory.complete(email))
}
- @ViewModelScoped
- class Factory @Inject constructor(private val registerComponentBuilder: RegisterComponentBuilder) {
+ @Factory
+ class StateFactory : KoinComponent {
operator fun invoke(
context: WelcomeContext,
data: WelcomeDataState
): CommonMachineState = RegistrationFlowState(
- context,
- data,
- registerComponentBuilder
+ context = context,
+ data = data,
+ startRegister = { host, email -> get { parametersOf(host) }.start(email) }
)
}
}
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/TerminatedState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TerminatedState.kt
similarity index 79%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/TerminatedState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TerminatedState.kt
index 670b020..d079882 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/TerminatedState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TerminatedState.kt
@@ -11,10 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import timber.log.Timber
/**
* Terminates wizard
@@ -24,7 +25,7 @@ class TerminatedState(context: WelcomeContext) : WelcomeState(context) {
* A part of [start] template to initialize state
*/
override fun doStart() {
- Timber.d("Terminated")
+ Napier.d("Terminated")
setUiState(WelcomeUiState.Terminated)
}
}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/TermsAndConditionsState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TermsAndConditionsState.kt
similarity index 86%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/TermsAndConditionsState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TermsAndConditionsState.kt
index ea80ec5..a2ade44 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/TermsAndConditionsState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TermsAndConditionsState.kt
@@ -11,10 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import timber.log.Timber
/**
* Terms and conditions screen
@@ -55,13 +56,13 @@ class TermsAndConditionsState(
private fun onAction() {
if (termsAccepted) {
- Timber.d("Action. Going to email entry...")
+ Napier.d("Action. Going to email entry...")
setMachineState(factory.emailEntry())
}
}
private fun onBack() {
- Timber.d("Back. Terminating...")
+ Napier.d("Back. Terminating...")
setMachineState(factory.terminate())
}
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/WelcomeContext.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeContext.kt
similarity index 86%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/WelcomeContext.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeContext.kt
index ee66128..38fa596 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/WelcomeContext.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeContext.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import androidx.lifecycle.SavedStateHandle
-import com.motorro.statemachine.welcome.model.WelcomeRenderer
+import com.motorro.commonstatemachine.examples.welcome.app.model.WelcomeRenderer
/**
* Common state passed from state to state
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/WelcomeState.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeState.kt
similarity index 64%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/WelcomeState.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeState.kt
index e24b95c..31005f8 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/model/state/WelcomeState.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeState.kt
@@ -11,23 +11,22 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import timber.log.Timber
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import io.github.aakira.napier.Napier
+
/**
* Base class for welcome flow state
*/
-abstract class WelcomeState(
- context: WelcomeContext
-): CoroutineState(), WelcomeContext by context {
+abstract class WelcomeState(context: WelcomeContext): CoroutineState(), WelcomeContext by context {
/**
* A part of [process] template to process UI gesture
*/
override fun doProcess(gesture: WelcomeGesture) {
- Timber.w("Unsupported gesture: %s", gesture)
+ Napier.w("Unsupported gesture: ${gesture}")
}
}
\ No newline at end of file
diff --git a/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeStateFactory.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeStateFactory.kt
new file mode 100644
index 0000000..3797f64
--- /dev/null
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeStateFactory.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2022 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+
+/**
+ * Welcome state factory
+ */
+interface WelcomeStateFactory {
+ /**
+ * Preloads 'data' for registration
+ */
+ fun preload(): CommonMachineState
+
+ /**
+ * Creates welcome screen state
+ * @param welcomeGreeting Message to display on welcome screen
+ */
+ fun welcome(welcomeGreeting: String): CommonMachineState
+
+ /**
+ * Creates email-entry state
+ * @param data Data state
+ */
+ fun emailEntry(data: WelcomeDataState? = null): CommonMachineState
+
+ /**
+ * Checks if email is registered
+ * @param data Data state
+ */
+ fun checkEmail(data: WelcomeDataState): CommonMachineState
+
+ /**
+ * Enter existing user password
+ * @param data Data state
+ */
+ fun loginFlow(data: WelcomeDataState): CommonMachineState
+
+ /**
+ * Enter registration user password
+ * @param data Data state
+ */
+ fun registrationFlow(data: WelcomeDataState): CommonMachineState
+
+ /**
+ * Registration complete state
+ * @param email Registered user's email
+ */
+ fun complete(email: String) : CommonMachineState
+
+ /**
+ * Terminates registration flow
+ */
+ fun terminate() : CommonMachineState
+
+}
+
diff --git a/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeStateFactoryImpl.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeStateFactoryImpl.kt
new file mode 100644
index 0000000..d83be1d
--- /dev/null
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/WelcomeStateFactoryImpl.kt
@@ -0,0 +1,101 @@
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
+
+import androidx.lifecycle.SavedStateHandle
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.model.WelcomeRenderer
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+
+/**
+ * [WelcomeStateFactory] implementation
+ */
+@Factory
+class WelcomeStateFactoryImpl(
+ savedStateHandle: SavedStateHandle,
+ renderer: WelcomeRenderer,
+ private val createPreloading: PreloadingState.StateFactory,
+ private val createLogin: LoginFlowState.StateFactory,
+ private val createRegister: RegistrationFlowState.StateFactory,
+ private val createEmailCheck: EmailCheckState.StateFactory
+) : WelcomeStateFactory {
+
+ private val context: WelcomeContext = object : WelcomeContext {
+ override val factory = this@WelcomeStateFactoryImpl
+ override val savedStateHandle = savedStateHandle
+ override val renderer: WelcomeRenderer = renderer
+ }
+
+ /**
+ * Preloads 'data' for registration
+ */
+ override fun preload(): CommonMachineState {
+ Napier.d("Creating 'Preloading'...")
+ return createPreloading(context)
+ }
+
+ /**
+ * Creates welcome screen state
+ * @param welcomeGreeting Message to display on welcome screen
+ */
+ override fun welcome(welcomeGreeting: String): CommonMachineState {
+ Napier.d("Creating 'Welcome'...")
+ return TermsAndConditionsState(context, welcomeGreeting)
+ }
+
+ /**
+ * Creates email-entry state
+ * @param data Data state
+ */
+ override fun emailEntry(data: WelcomeDataState?): CommonMachineState {
+ Napier.d("Creating 'Email entry'...")
+ return EmailEntryState(context, data)
+ }
+
+ /**
+ * Checks if email is registered
+ * @param data Data state
+ */
+ override fun checkEmail(data: WelcomeDataState): CommonMachineState {
+ Napier.d("Creating 'Check e-mail'...")
+ return createEmailCheck(context, data)
+ }
+
+ /**
+ * Enter existing user password
+ * @param data Data state
+ */
+ override fun loginFlow(data: WelcomeDataState): CommonMachineState {
+ Napier.d("Creating 'Login flow'...")
+ return createLogin(context, data)
+ }
+
+ /**
+ * Enter registration user password
+ * @param data Data state
+ */
+ override fun registrationFlow(data: WelcomeDataState): CommonMachineState {
+ Napier.d("Creating 'Registration flow'...")
+ return createRegister(context, data)
+ }
+
+ /**
+ * Registration complete state
+ * @param email Registered user's email
+ */
+ override fun complete(email: String): CommonMachineState {
+ Napier.d("Creating 'Complete'...")
+ return CompleteState(context, email)
+ }
+
+ /**
+ * Terminates registration flow
+ */
+ override fun terminate(): CommonMachineState {
+ Napier.d("Creating 'Terminated'...")
+ return TerminatedState(context)
+ }
+
+}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/usecase/CheckEmail.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/usecase/CheckEmail.kt
similarity index 73%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/usecase/CheckEmail.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/usecase/CheckEmail.kt
index b1b94cb..8378f59 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/usecase/CheckEmail.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/usecase/CheckEmail.kt
@@ -11,22 +11,21 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.usecase
+package com.motorro.commonstatemachine.examples.welcome.app.usecase
-import com.motorro.statemachine.commonapi.NETWORK_DELAY
-import com.motorro.statemachine.commonapi.welcome.data.BAD
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.commoncore.coroutines.DispatcherProvider
-import dagger.hilt.android.scopes.ViewModelScoped
+import com.motorro.commonstatemachine.examples.commoncore.coroutines.DispatcherProvider
+import com.motorro.commonstatemachine.examples.welcome.commonapi.NETWORK_DELAY
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.BAD
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
-import javax.inject.Inject
+import org.koin.core.annotation.Factory
/**
* Checks if user is registered
*/
-@ViewModelScoped
-class CheckEmail @Inject constructor(private val dispatchers: DispatcherProvider) {
+@Factory
+class CheckEmail(private val dispatchers: DispatcherProvider) {
/**
* Checks if user is registered
* @param email User to check
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/usecase/Preload.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/usecase/Preload.kt
similarity index 69%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/usecase/Preload.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/usecase/Preload.kt
index 8130081..63fb23f 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/usecase/Preload.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/usecase/Preload.kt
@@ -11,23 +11,22 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.usecase
+package com.motorro.commonstatemachine.examples.welcome.app.usecase
-import com.motorro.statemachine.R
-import com.motorro.statemachine.commonapi.NETWORK_DELAY
-import com.motorro.statemachine.commoncore.coroutines.DispatcherProvider
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import dagger.hilt.android.scopes.ViewModelScoped
+import com.motorro.commonstatemachine.examples.commoncore.coroutines.DispatcherProvider
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.app.R
+import com.motorro.commonstatemachine.examples.welcome.commonapi.NETWORK_DELAY
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
-import timber.log.Timber
-import javax.inject.Inject
+import org.koin.core.annotation.Factory
/**
* Emulates data preload
*/
-@ViewModelScoped
-class Preload @Inject constructor(
+@Factory
+class Preload(
resourceWrapper: ResourceWrapper,
private val dispatchers: DispatcherProvider,
): ResourceWrapper by resourceWrapper {
@@ -41,7 +40,7 @@ class Preload @Inject constructor(
private suspend fun loadGreeting(): String {
delay(NETWORK_DELAY)
- Timber.d("Loading complete")
+ Napier.d("Loading complete")
return getString(R.string.welcome_terms)
}
}
\ No newline at end of file
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/Complete.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/Complete.kt
similarity index 92%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/Complete.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/Complete.kt
index 0e0668e..3a620fe 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/Complete.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/Complete.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.view
+package com.motorro.commonstatemachine.examples.welcome.app.view
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -32,8 +32,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.R
-import com.motorro.statemachine.welcome.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.R
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
@Composable
fun Complete(state: WelcomeUiState.Complete, onAction: () -> Unit) {
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/EmailEntry.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/EmailEntry.kt
similarity index 94%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/EmailEntry.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/EmailEntry.kt
index 6726075..786c2f5 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/EmailEntry.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/EmailEntry.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.view
+package com.motorro.commonstatemachine.examples.welcome.app.view
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -35,8 +35,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.R
-import com.motorro.statemachine.welcome.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.R
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
@Composable
fun EmailEntry(state: WelcomeUiState.EmailEntry, onEmailChanged: (String) -> Unit, onNext: () -> Unit) {
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/Welcome.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/Welcome.kt
similarity index 94%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/Welcome.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/Welcome.kt
index de58729..1845453 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/Welcome.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/Welcome.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.view
+package com.motorro.commonstatemachine.examples.welcome.app.view
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -34,8 +34,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.R
-import com.motorro.statemachine.welcome.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.R
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
@Composable
fun Welcome(state: WelcomeUiState.Welcome, onTermsToggled: () -> Unit, onNext: () -> Unit) {
diff --git a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/WelcomeScreen.kt b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/WelcomeScreen.kt
similarity index 61%
rename from examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/WelcomeScreen.kt
rename to examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/WelcomeScreen.kt
index e3c4e6c..8c73983 100644
--- a/examples/welcome/welcome/src/main/java/com/motorro/statemachine/welcome/view/WelcomeScreen.kt
+++ b/examples/welcome/app/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/app/view/WelcomeScreen.kt
@@ -11,30 +11,28 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.view
+package com.motorro.commonstatemachine.examples.welcome.app.view
import androidx.activity.compose.BackHandler
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
-import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.login.view.LoginScreen
-import com.motorro.statemachine.register.view.RegistrationScreen
-import com.motorro.statemachine.welcome.data.WelcomeGesture.Action
-import com.motorro.statemachine.welcome.data.WelcomeGesture.Back
-import com.motorro.statemachine.welcome.data.WelcomeGesture.EmailChanged
-import com.motorro.statemachine.welcome.data.WelcomeGesture.Login
-import com.motorro.statemachine.welcome.data.WelcomeGesture.Register
-import com.motorro.statemachine.welcome.data.WelcomeGesture.TermsAndConditionsToggled
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import com.motorro.statemachine.welcome.model.WelcomeViewModel
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture.Action
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture.EmailChanged
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture.TermsAndConditionsToggled
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.model.WelcomeViewModel
+import com.motorro.commonstatemachine.examples.welcome.login.view.LoginScreen
+import com.motorro.commonstatemachine.examples.welcome.register.view.RegistrationScreen
+import org.koin.compose.viewmodel.koinViewModel
@Composable
fun WelcomeScreen(onTerminate: @Composable () -> Unit) {
- val model = hiltViewModel()
+ val model = koinViewModel()
val state = model.state.collectAsState(WelcomeUiState.Loading)
- BackHandler(onBack = { model.process(Back) })
+ BackHandler(onBack = { model.process(WelcomeGesture.Back) })
when (val uiState = state.value) {
WelcomeUiState.Loading -> Loading()
@@ -50,11 +48,11 @@ fun WelcomeScreen(onTerminate: @Composable () -> Unit) {
)
is WelcomeUiState.Login -> LoginScreen(
state = uiState.value,
- onGesture = { model.process(Login(it)) }
+ onGesture = { model.process(WelcomeGesture.Login(it)) }
)
is WelcomeUiState.Register -> RegistrationScreen(
state = uiState.value,
- onGesture = { model.process(Register(it))}
+ onGesture = { model.process(WelcomeGesture.Register(it))}
)
is WelcomeUiState.Complete -> Complete(
state = uiState,
diff --git a/examples/welcome/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/examples/welcome/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..40ce517
--- /dev/null
+++ b/examples/welcome/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/welcome/app/src/main/res/drawable/ic_launcher_background.xml b/examples/welcome/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..997ef0b
--- /dev/null
+++ b/examples/welcome/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/welcome/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/welcome/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..0147ca8
--- /dev/null
+++ b/examples/welcome/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/welcome/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/welcome/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..0147ca8
--- /dev/null
+++ b/examples/welcome/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/welcome/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/examples/welcome/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/examples/welcome/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/examples/welcome/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/examples/welcome/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/examples/welcome/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/examples/welcome/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/examples/welcome/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/examples/welcome/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/examples/welcome/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/examples/welcome/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/examples/welcome/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/examples/welcome/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/examples/welcome/welcome/src/main/res/values/colors.xml b/examples/welcome/app/src/main/res/values/colors.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/values/colors.xml
rename to examples/welcome/app/src/main/res/values/colors.xml
diff --git a/examples/welcome/welcome/src/main/res/values/strings.xml b/examples/welcome/app/src/main/res/values/strings.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/values/strings.xml
rename to examples/welcome/app/src/main/res/values/strings.xml
diff --git a/examples/welcome/welcome/src/main/res/values/themes.xml b/examples/welcome/app/src/main/res/values/themes.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/values/themes.xml
rename to examples/welcome/app/src/main/res/values/themes.xml
diff --git a/examples/welcome/welcome/src/main/res/xml/backup_rules.xml b/examples/welcome/app/src/main/res/xml/backup_rules.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/xml/backup_rules.xml
rename to examples/welcome/app/src/main/res/xml/backup_rules.xml
diff --git a/examples/welcome/welcome/src/main/res/xml/data_extraction_rules.xml b/examples/welcome/app/src/main/res/xml/data_extraction_rules.xml
similarity index 100%
rename from examples/welcome/welcome/src/main/res/xml/data_extraction_rules.xml
rename to examples/welcome/app/src/main/res/xml/data_extraction_rules.xml
diff --git a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/BaseStateTest.kt b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/BaseStateTest.kt
similarity index 86%
rename from examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/BaseStateTest.kt
rename to examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/BaseStateTest.kt
index 8095d69..cde1bee 100644
--- a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/BaseStateTest.kt
+++ b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/BaseStateTest.kt
@@ -11,15 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import androidx.annotation.CallSuper
import androidx.lifecycle.SavedStateHandle
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.data.WelcomeUiState
-import com.motorro.statemachine.welcome.model.WelcomeRenderer
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeUiState
+import com.motorro.commonstatemachine.examples.welcome.app.model.WelcomeRenderer
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
diff --git a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/CompleteStateTest.kt b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/CompleteStateTest.kt
similarity index 88%
rename from examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/CompleteStateTest.kt
rename to examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/CompleteStateTest.kt
index 03e17b8..f03e175 100644
--- a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/CompleteStateTest.kt
+++ b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/CompleteStateTest.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.welcome.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
diff --git a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/EmailCheckStateTest.kt b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailCheckStateTest.kt
similarity index 84%
rename from examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/EmailCheckStateTest.kt
rename to examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailCheckStateTest.kt
index 1fa13a5..778283a 100644
--- a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/EmailCheckStateTest.kt
+++ b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailCheckStateTest.kt
@@ -13,13 +13,17 @@
@file:OptIn(ExperimentalCoroutinesApi::class)
-package com.motorro.statemachine.welcome.model.state
-
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.usecase.CheckEmail
-import io.mockk.*
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.usecase.CheckEmail
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
diff --git a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/EmailEntryStateTest.kt b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailEntryStateTest.kt
similarity index 94%
rename from examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/EmailEntryStateTest.kt
rename to examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailEntryStateTest.kt
index 0663d74..89a2a40 100644
--- a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/EmailEntryStateTest.kt
+++ b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/EmailEntryStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
import androidx.lifecycle.SavedStateHandle
-import com.motorro.statemachine.welcome.data.WelcomeDataState
-import com.motorro.statemachine.welcome.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeDataState
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
diff --git a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/PreloadingStateTest.kt b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/PreloadingStateTest.kt
similarity index 86%
rename from examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/PreloadingStateTest.kt
rename to examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/PreloadingStateTest.kt
index f538092..911a3f7 100644
--- a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/PreloadingStateTest.kt
+++ b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/PreloadingStateTest.kt
@@ -13,11 +13,15 @@
@file:OptIn(ExperimentalCoroutinesApi::class)
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
-import com.motorro.statemachine.welcome.data.WelcomeGesture
-import com.motorro.statemachine.welcome.usecase.Preload
-import io.mockk.*
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.usecase.Preload
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.mockk
+import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
diff --git a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/TermsAndConditionsStateTest.kt b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TermsAndConditionsStateTest.kt
similarity index 95%
rename from examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/TermsAndConditionsStateTest.kt
rename to examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TermsAndConditionsStateTest.kt
index fad9a48..a991f64 100644
--- a/examples/welcome/welcome/src/test/java/com/motorro/statemachine/welcome/model/state/TermsAndConditionsStateTest.kt
+++ b/examples/welcome/app/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/app/model/state/TermsAndConditionsStateTest.kt
@@ -11,9 +11,9 @@
* limitations under the License.
*/
-package com.motorro.statemachine.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.app.model.state
-import com.motorro.statemachine.welcome.data.WelcomeGesture
+import com.motorro.commonstatemachine.examples.welcome.app.data.WelcomeGesture
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
diff --git a/examples/welcome/commonapi/build.gradle.kts b/examples/welcome/commonapi/build.gradle.kts
index 2c38ecb..caee088 100644
--- a/examples/welcome/commonapi/build.gradle.kts
+++ b/examples/welcome/commonapi/build.gradle.kts
@@ -10,51 +10,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
+ alias(libs.plugins.motorro.cmp)
}
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = "com.motorro"
-version = versionName
-
kotlin {
- android {
- namespace = "com.motorro.statemachine.commonapi"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
sourceSets {
commonMain.dependencies {
implementation(project(":commonstatemachine"))
implementation(libs.kotlin.coroutines.core)
}
commonTest.dependencies {
- implementation(libs.test.kotlin)
implementation(libs.test.kotlin.coroutines)
}
}
diff --git a/examples/welcome/commonapi/consumer-rules.pro b/examples/welcome/commonapi/consumer-rules.pro
new file mode 100644
index 0000000..e69de29
diff --git a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/constants.kt b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/constants.kt
similarity index 80%
rename from examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/constants.kt
rename to examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/constants.kt
index 9d2011f..1cc3ac0 100644
--- a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/constants.kt
+++ b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/constants.kt
@@ -11,9 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.commonapi
+package com.motorro.commonstatemachine.examples.welcome.commonapi
+
+import kotlin.time.Duration.Companion.milliseconds
/**
* Network emulation delay
*/
-const val NETWORK_DELAY = 2000L
\ No newline at end of file
+val NETWORK_DELAY = 2000.milliseconds
\ No newline at end of file
diff --git a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/data/users.kt b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/data/users.kt
similarity index 90%
rename from examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/data/users.kt
rename to examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/data/users.kt
index 6c10b5a..cd4184c 100644
--- a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/data/users.kt
+++ b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/data/users.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.commonapi.welcome.data
+package com.motorro.commonstatemachine.examples.welcome.commonapi.data
/**
* Mock users
diff --git a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/FlowStarter.kt b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/FlowStarter.kt
similarity index 91%
rename from examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/FlowStarter.kt
rename to examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/FlowStarter.kt
index f8e21bc..a8cfe8b 100644
--- a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/FlowStarter.kt
+++ b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/FlowStarter.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.commonapi.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.commonapi.model.state
import com.motorro.commonstatemachine.CommonMachineState
diff --git a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/WelcomeFeatureHost.kt b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/WelcomeFeatureHost.kt
similarity index 91%
rename from examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/WelcomeFeatureHost.kt
rename to examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/WelcomeFeatureHost.kt
index d44e7c9..8233f4e 100644
--- a/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/statemachine/commonapi/welcome/model/state/WelcomeFeatureHost.kt
+++ b/examples/welcome/commonapi/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/commonapi/model/state/WelcomeFeatureHost.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.commonapi.welcome.model.state
+package com.motorro.commonstatemachine.examples.welcome.commonapi.model.state
/**
diff --git a/examples/welcome/commonregister/build.gradle.kts b/examples/welcome/commonregister/build.gradle.kts
deleted file mode 100644
index b4f07b4..0000000
--- a/examples/welcome/commonregister/build.gradle.kts
+++ /dev/null
@@ -1,73 +0,0 @@
-@file:Suppress("unused")
-
-/*
-* Copyright 2022 Nikolai Kotchetkov.
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-* http://www.apache.org/licenses/LICENSE-2.0
-* Unless required by applicable law or agreed to in writing, software
-* 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.
-*/
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
-plugins {
- alias(libs.plugins.kotlin.multiplatform)
- alias(libs.plugins.android.kotlin.multiplatform.library)
-}
-
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-group = "com.motorro"
-version = versionName
-
-kotlin {
- android {
- namespace = "com.motorro.statemachine.commonregister"
- compileSdk = androidCompileSdkVersion
- minSdk = androidMinSdkVersion
-
- androidResources {
- enable = true
- }
-
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
-
- js {
- binaries.library()
- useCommonJs()
- browser {
- testTask(Action {
- useMocha {
- timeout = "10s"
- }
- })
- }
- }
-
- sourceSets {
- commonMain.dependencies {
- implementation(project(":commonstatemachine"))
- implementation(project(":coroutines"))
- implementation(project(":examples:commoncore"))
- implementation(project(":examples:welcome:commonapi"))
- implementation(libs.kotlin.coroutines.core)
- }
- commonTest.dependencies {
- implementation(libs.test.kotlin)
- implementation(libs.test.kotlin.coroutines)
- }
- androidMain.dependencies {
- implementation(libs.timber)
- }
- }
-}
diff --git a/examples/welcome/commonregister/src/androidMain/kotlin/com/motorro/statemachine/register/model/getPasswordError.kt b/examples/welcome/commonregister/src/androidMain/kotlin/com/motorro/statemachine/register/model/getPasswordError.kt
deleted file mode 100644
index 9171b21..0000000
--- a/examples/welcome/commonregister/src/androidMain/kotlin/com/motorro/statemachine/register/model/getPasswordError.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.register.model
-
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.commonregister.R
-import com.motorro.statemachine.register.data.PasswordValidationError
-import com.motorro.statemachine.register.data.PasswordValidationError.PASSWORD_LENGTH
-import com.motorro.statemachine.register.data.PasswordValidationError.PASSWORD_MISMATCH
-
-/**
- * Returns password error text
- */
-actual fun ResourceWrapper.getPasswordError(error: PasswordValidationError): String = when(error) {
- PASSWORD_LENGTH -> getString(R.string.register_error_password_length)
- PASSWORD_MISMATCH -> getString(R.string.register_error_password_mismatch)
-}
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterStateFactory.kt b/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterStateFactory.kt
deleted file mode 100644
index 278e94f..0000000
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterStateFactory.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.register.model.state
-
-import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.commonapi.welcome.model.state.FlowStarter
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
-import com.motorro.statemachine.register.model.RegistrationRenderer
-
-/**
- * Login flow state factory
- */
-interface RegisterStateFactory : FlowStarter {
- /**
- * Creates a starting state
- * @param email Email to proceed with
- */
- override fun start(email: String): CommonMachineState = passwordEntry(RegisterDataState(email))
-
- /**
- * Password entry screen
- * @param data Registration data state
- */
- fun passwordEntry(data: RegisterDataState): RegisterState
-
- /**
- * Registers user
- * @param data Data state
- */
- fun registering(data: RegisterDataState): RegisterState
-
- /**
- * [RegisterStateFactory] implementation
- */
- class Impl(
- host: WelcomeFeatureHost,
- renderer: RegistrationRenderer,
- private val createRegistration: RegistrationState.Factory
- ) : RegisterStateFactory {
-
- private val context: RegisterContext = object : RegisterContext {
- override val factory: RegisterStateFactory = this@Impl
- override val host: WelcomeFeatureHost = host
- override val renderer: RegistrationRenderer = renderer
- }
-
- /**
- * Password entry screen
- * @param data Registration data state
- */
- override fun passwordEntry(data: RegisterDataState): RegisterState {
- Logger.d("Creating 'Password entry'...")
- return PasswordEntryState(context, data)
- }
-
- /**
- * Registers user
- * @param data Data state
- */
- override fun registering(data: RegisterDataState): RegisterState {
- Logger.d("Creating 'Credentials check'...")
- return createRegistration(context, data)
- }
- }
-}
\ No newline at end of file
diff --git a/examples/welcome/commonregister/src/jsMain/kotlin/com/motorro/statemachine/register/model/getPasswordError.kt b/examples/welcome/commonregister/src/jsMain/kotlin/com/motorro/statemachine/register/model/getPasswordError.kt
deleted file mode 100644
index fee5b2f..0000000
--- a/examples/welcome/commonregister/src/jsMain/kotlin/com/motorro/statemachine/register/model/getPasswordError.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.register.model
-
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.register.data.PasswordValidationError
-import com.motorro.statemachine.register.data.PasswordValidationError.PASSWORD_LENGTH
-import com.motorro.statemachine.register.data.PasswordValidationError.PASSWORD_MISMATCH
-
-/**
- * Returns password error text
- */
-actual fun ResourceWrapper.getPasswordError(error: PasswordValidationError): String = when(error) {
- PASSWORD_LENGTH -> "Password should be at least 6 chars long"
- PASSWORD_MISMATCH -> "Passwords mismatch"
-}
diff --git a/examples/welcome/login/build.gradle.kts b/examples/welcome/login/build.gradle.kts
index 0d6699b..eb9886b 100644
--- a/examples/welcome/login/build.gradle.kts
+++ b/examples/welcome/login/build.gradle.kts
@@ -1,7 +1,3 @@
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2022 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,50 +12,8 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.google.ksp)
- alias(libs.plugins.hilt)
- alias(libs.plugins.compose)
-}
-
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidTargetSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-android {
- // Assuming androidCompileSdkVersion, androidMinSdkVersion, and androidTargetSdkVersion
- // are defined in your project's gradle.properties or root build.gradle.kts
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- }
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
- }
- }
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.login"
+ alias(libs.plugins.motorro.android.lib.compose)
+ alias(libs.plugins.koin)
}
dependencies {
@@ -67,28 +21,9 @@ dependencies {
implementation(project(":coroutines"))
implementation(project(":examples:welcome:commonapi"))
implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts) // Corrected from "foundation.layout" to "foundation.layouts" as per your original file
-
- implementation(libs.hilt.android)
- implementation(libs.hilt.compose) // Assuming this is 'libs.hilt.navigation.compose' or similar based on common usage with Hilt and Compose
- ksp(libs.hilt.compiler)
- ksp(libs.hilt.compiler.androidx) // Assuming this is 'libs.hilt.android.compiler' or similar
-
- debugImplementation(libs.compose.tooling)
+ implementation(libs.napier)
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.androidx.arch)
- testImplementation(libs.test.kotlin.coroutines)
+ implementation(platform(libs.koin.bom))
+ implementation(libs.koin.android)
+ implementation(libs.koin.annotations)
}
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginComponent.kt b/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginComponent.kt
deleted file mode 100644
index b225aa7..0000000
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginComponent.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.login.di
-
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import dagger.BindsInstance
-import dagger.hilt.DefineComponent
-import dagger.hilt.components.SingletonComponent
-
-@LoginScope
-@DefineComponent(parent = SingletonComponent::class)
-interface LoginComponent
-
-@DefineComponent.Builder
-interface LoginComponentBuilder {
- /**
- * Defines feature host graph
- */
- fun host(@BindsInstance value: WelcomeFeatureHost): LoginComponentBuilder
-
- /**
- * Builds component
- */
- fun build(): LoginComponent
-}
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginEntryPoint.kt b/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginEntryPoint.kt
deleted file mode 100644
index b974fc2..0000000
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginEntryPoint.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.login.di
-
-import com.motorro.statemachine.commonapi.welcome.model.state.FlowStarter
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
-import dagger.hilt.EntryPoint
-import dagger.hilt.InstallIn
-
-/**
- * Login feature entry point
- */
-@EntryPoint
-@InstallIn(LoginComponent::class)
-interface LoginEntryPoint {
- /**
- * Flow starter
- */
- fun flowStarter(): FlowStarter
-}
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginModule.kt b/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginModule.kt
deleted file mode 100644
index 7102833..0000000
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginModule.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.login.di
-
-import com.motorro.statemachine.commonapi.welcome.model.state.FlowStarter
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
-import com.motorro.statemachine.login.model.state.LoginStateFactory
-import dagger.Binds
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-
-@Module
-@InstallIn(LoginComponent::class)
-internal class LoginModule {
- @Provides
- @LoginScope
- fun flowStarter(factory: LoginStateFactory): FlowStarter = factory
-}
-
-@Module
-@InstallIn(LoginComponent::class)
-internal interface LoginBindingModule {
- @Binds
- @LoginScope
- fun factory(impl: LoginStateFactory.Impl): LoginStateFactory
-}
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginStateFactory.kt b/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginStateFactory.kt
deleted file mode 100644
index c53ebd6..0000000
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginStateFactory.kt
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2022 Nikolai Kotchetkov.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * 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.
- */
-
-package com.motorro.statemachine.login.model.state
-
-import com.motorro.commonstatemachine.CommonMachineState
-import com.motorro.statemachine.commonapi.welcome.model.state.FlowStarter
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
-import com.motorro.statemachine.login.di.LoginScope
-import com.motorro.statemachine.login.model.LoginRenderer
-import timber.log.Timber
-import javax.inject.Inject
-
-/**
- * Login flow state factory
- */
-internal interface LoginStateFactory : FlowStarter {
- /**
- * Creates a starting state
- * @param email Common data state
- */
- override fun start(email: String): CommonMachineState = passwordEntry(LoginDataState(email))
-
- /**
- * Enter existing user password
- * @param data Login data state
- */
- fun passwordEntry(data: LoginDataState): LoginState
-
- /**
- * Checks email/password
- * @param data Data state
- */
- fun checking(data: LoginDataState): LoginState
-
- /**
- * Password error screen
- */
- fun error(data: LoginDataState, error: Throwable): LoginState
-
- /**
- * [LoginStateFactory] implementation
- */
- @LoginScope
- class Impl @Inject constructor(
- host: WelcomeFeatureHost,
- renderer: LoginRenderer,
- private val createCredentialsCheck: CredentialsCheckState.Factory
- ) : LoginStateFactory {
-
- private val context: LoginContext = object : LoginContext {
- override val factory: LoginStateFactory = this@Impl
- override val host: WelcomeFeatureHost = host
- override val renderer: LoginRenderer = renderer
- }
-
- /**
- * Enter existing user password
- * @param data Common data state
- */
- override fun passwordEntry(data: LoginDataState): LoginState {
- Timber.d("Creating 'Password entry'...")
- return PasswordEntryState(context, data)
- }
-
- /**
- * Checks email/password
- * @param data Data state
- */
- override fun checking(data: LoginDataState): LoginState {
- Timber.d("Creating 'Credentials check'...")
- return createCredentialsCheck(context, data)
- }
-
- /**
- * Password error screen
- */
- override fun error(data: LoginDataState, error: Throwable): LoginState {
- Timber.d("Creating 'Error'...")
- return ErrorState(context, data, error)
- }
- }
-}
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/LoginFlowStarter.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/LoginFlowStarter.kt
new file mode 100644
index 0000000..04ece08
--- /dev/null
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/LoginFlowStarter.kt
@@ -0,0 +1,10 @@
+package com.motorro.commonstatemachine.examples.welcome.login
+
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.FlowStarter
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+
+/**
+ * Starts login flow
+ */
+interface LoginFlowStarter : FlowStarter
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginScope.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/LoginModule.kt
similarity index 74%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginScope.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/LoginModule.kt
index 2d48a78..20fbdb5 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/di/LoginScope.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/LoginModule.kt
@@ -11,14 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.di
+package com.motorro.commonstatemachine.examples.welcome.login
-import javax.inject.Scope
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
-/**
- * Login feature scope
- */
-@Scope
-@MustBeDocumented
-@Retention(value = AnnotationRetention.RUNTIME)
-annotation class LoginScope
\ No newline at end of file
+@Module
+@ComponentScan
+class LoginModule
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginDataState.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginDataState.kt
similarity index 91%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginDataState.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginDataState.kt
index 0912e12..8b8bbad 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginDataState.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginDataState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.data
+package com.motorro.commonstatemachine.examples.welcome.login.data
/**
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginGesture.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginGesture.kt
similarity index 93%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginGesture.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginGesture.kt
index 58ed854..5ab9b6d 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginGesture.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginGesture.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.data
+package com.motorro.commonstatemachine.examples.welcome.login.data
/**
* Login flow UI gestures
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginUiState.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginUiState.kt
similarity index 95%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginUiState.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginUiState.kt
index a8fd402..039b836 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/data/LoginUiState.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/data/LoginUiState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.data
+package com.motorro.commonstatemachine.examples.welcome.login.data
/**
* Login flow UI state
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/LoginRenderer.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/LoginRenderer.kt
similarity index 67%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/LoginRenderer.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/LoginRenderer.kt
index 0c2b61f..7fd5c98 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/LoginRenderer.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/LoginRenderer.kt
@@ -11,24 +11,23 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model
+package com.motorro.commonstatemachine.examples.welcome.login.model
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.login.R
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginUiState
-import com.motorro.statemachine.login.di.LoginScope
-import javax.inject.Inject
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.login.R
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+import org.koin.core.annotation.Factory
/**
* Renders Login flow view states
*/
-@LoginScope
-internal class LoginRenderer @Inject constructor(resourceWrapper: ResourceWrapper): ResourceWrapper by resourceWrapper {
+@Factory
+internal class LoginRenderer(resourceWrapper: ResourceWrapper): ResourceWrapper by resourceWrapper {
/**
* Renders password form
*/
- fun renderPassword(data: LoginDataState, isValid: Boolean): LoginUiState.PasswordEntry =
+ fun renderPassword(data: com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState, isValid: Boolean): LoginUiState.PasswordEntry =
LoginUiState.PasswordEntry(
data.email,
data.password.orEmpty(),
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/CredentialsCheckState.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckState.kt
similarity index 74%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/CredentialsCheckState.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckState.kt
index f2eb1b1..ddd7347 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/CredentialsCheckState.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckState.kt
@@ -11,15 +11,14 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.di.LoginScope
-import com.motorro.statemachine.login.usecase.CheckCredentials
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.usecase.CheckCredentials
+import io.github.aakira.napier.Napier
import kotlinx.coroutines.launch
-import timber.log.Timber
-import javax.inject.Inject
+import org.koin.core.annotation.Factory
/**
* Emulates login operation
@@ -42,14 +41,14 @@ internal class CredentialsCheckState(
*/
override fun doStart() {
setUiState(renderer.renderLoading(data))
- Timber.d("Checking for user credentials...")
+ Napier.d("Checking for user credentials...")
stateScope.launch {
val valid = checkCredentials(data.email, password)
if (valid) {
- Timber.d("Correct credentials. Transferring to complete screen...")
+ Napier.d("Correct credentials. Transferring to complete screen...")
host.complete()
} else {
- Timber.w("Login error. Transferring to error screen...")
+ Napier.w("Login error. Transferring to error screen...")
setMachineState(factory.error(data, IllegalArgumentException("Wrong username or password")))
}
}
@@ -64,12 +63,12 @@ internal class CredentialsCheckState(
}
private fun onBack() {
- Timber.d("Returning to password entry")
+ Napier.d("Returning to password entry")
setMachineState(factory.passwordEntry(data))
}
- @LoginScope
- class Factory @Inject constructor(private val checkCredentials: CheckCredentials) {
+ @Factory
+ class StateFactory(private val checkCredentials: CheckCredentials) {
operator fun invoke(
context: LoginContext,
data: LoginDataState
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/ErrorState.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorState.kt
similarity index 79%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/ErrorState.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorState.kt
index 47e0061..bd3bd64 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/ErrorState.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorState.kt
@@ -11,11 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
-import timber.log.Timber
/**
* Login error
@@ -35,7 +36,7 @@ internal class ErrorState(
}
private fun onDismiss() {
- Timber.d("Returning to password entry")
+ Napier.d("Returning to password entry")
setMachineState(factory.passwordEntry(data))
}
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginContext.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginContext.kt
similarity index 77%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginContext.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginContext.kt
index 4a3fc61..765a09a 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginContext.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginContext.kt
@@ -11,10 +11,10 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.login.model.LoginRenderer
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.login.model.LoginRenderer
/**
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginState.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginState.kt
similarity index 64%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginState.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginState.kt
index 11f7bab..501d60a 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/LoginState.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginState.kt
@@ -11,23 +11,22 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
-import timber.log.Timber
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+import io.github.aakira.napier.Napier
+
/**
* Base class for login flow state
*/
-internal abstract class LoginState(
- context: LoginContext
-): CoroutineState(), LoginContext by context {
+internal abstract class LoginState(context: LoginContext): CoroutineState(), LoginContext by context {
/**
* A part of [process] template to process UI gesture
*/
override fun doProcess(gesture: LoginGesture) {
- Timber.w("Unsupported gesture: %s", gesture)
+ Napier.w("Unsupported gesture: ${gesture}")
}
}
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactory.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactory.kt
new file mode 100644
index 0000000..a7caec2
--- /dev/null
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactory.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2022 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.welcome.login.LoginFlowStarter
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+
+/**
+ * Login flow state factory
+ */
+internal interface LoginStateFactory : LoginFlowStarter {
+ /**
+ * Creates a starting state
+ * @param email Common data state
+ */
+ override fun start(email: String): CommonMachineState = passwordEntry(LoginDataState(email))
+
+ /**
+ * Enter existing user password
+ * @param data Login data state
+ */
+ fun passwordEntry(data: LoginDataState): LoginState
+
+ /**
+ * Checks email/password
+ * @param data Data state
+ */
+ abstract fun checking(data: LoginDataState): LoginState
+
+ /**
+ * Password error screen
+ */
+ abstract fun error(data: LoginDataState, error: Throwable): LoginState
+
+}
+
diff --git a/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactoryImpl.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactoryImpl.kt
new file mode 100644
index 0000000..00607e4
--- /dev/null
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/LoginStateFactoryImpl.kt
@@ -0,0 +1,52 @@
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.login.LoginFlowStarter
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.model.LoginRenderer
+import io.github.aakira.napier.Napier
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.InjectedParam
+
+/**
+ * [LoginStateFactory] implementation
+ */
+@Factory(binds = [LoginFlowStarter::class])
+internal class LoginStateFactoryImpl(
+ @InjectedParam host: WelcomeFeatureHost,
+ renderer: LoginRenderer,
+ private val createCredentialsCheck: CredentialsCheckState.StateFactory
+) : LoginStateFactory {
+
+ private val context: LoginContext = object : LoginContext {
+ override val factory: LoginStateFactory = this@LoginStateFactoryImpl
+ override val host: WelcomeFeatureHost = host
+ override val renderer: LoginRenderer = renderer
+ }
+
+ /**
+ * Enter existing user password
+ * @param data Common data state
+ */
+ override fun passwordEntry(data: LoginDataState): LoginState {
+ Napier.d("Creating 'Password entry'...")
+ return PasswordEntryState(context, data)
+ }
+
+ /**
+ * Checks email/password
+ * @param data Data state
+ */
+ override fun checking(data: LoginDataState): LoginState {
+ Napier.d("Creating 'Credentials check'...")
+ return createCredentialsCheck(context, data)
+ }
+
+ /**
+ * Password error screen
+ */
+ override fun error(data: LoginDataState, error: Throwable): LoginState {
+ Napier.d("Creating 'Error'...")
+ return ErrorState(context, data, error)
+ }
+}
\ No newline at end of file
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/PasswordEntryState.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryState.kt
similarity index 81%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/PasswordEntryState.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryState.kt
index 93cd0a8..4b6a331 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/model/state/PasswordEntryState.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryState.kt
@@ -11,11 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import io.github.aakira.napier.Napier
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
-import timber.log.Timber
/**
* Password entry screen
@@ -43,13 +44,13 @@ internal class PasswordEntryState(
private fun onAction() {
if (isPasswordValid()) {
- Timber.d("Valid password. Transferring to credentials check")
+ Napier.d("Valid password. Transferring to credentials check")
setMachineState(factory.checking(data))
}
}
private fun onBack() {
- Timber.d("Returning to e-mail entry...")
+ Napier.d("Returning to e-mail entry...")
host.backToEmailEntry()
}
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/usecase/CheckCredentials.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/usecase/CheckCredentials.kt
similarity index 73%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/usecase/CheckCredentials.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/usecase/CheckCredentials.kt
index 69a0106..fa82f66 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/usecase/CheckCredentials.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/usecase/CheckCredentials.kt
@@ -11,22 +11,21 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.usecase
+package com.motorro.commonstatemachine.examples.welcome.login.usecase
-import com.motorro.statemachine.commonapi.NETWORK_DELAY
-import com.motorro.statemachine.commonapi.welcome.data.BAD
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.commoncore.coroutines.DispatcherProvider
-import com.motorro.statemachine.login.di.LoginScope
+import com.motorro.commonstatemachine.examples.commoncore.coroutines.DispatcherProvider
+import com.motorro.commonstatemachine.examples.welcome.commonapi.NETWORK_DELAY
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.BAD
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
-import javax.inject.Inject
+import org.koin.core.annotation.Factory
/**
* Emulates user's credentials check
*/
-@LoginScope
-internal class CheckCredentials @Inject constructor(private val dispatchers: DispatcherProvider) {
+@Factory
+internal class CheckCredentials(private val dispatchers: DispatcherProvider) {
/**
* Tries to log-in user
* @param email User to check
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/LoginScreen.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/LoginScreen.kt
similarity index 81%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/LoginScreen.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/LoginScreen.kt
index f6079d8..83ba492 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/LoginScreen.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/LoginScreen.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.view
+package com.motorro.commonstatemachine.examples.welcome.login.view
import androidx.compose.runtime.Composable
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
/**
* Login screen flow
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/PasswordEntry.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/PasswordEntry.kt
similarity index 95%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/PasswordEntry.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/PasswordEntry.kt
index cf8d1bc..17f13a5 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/PasswordEntry.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/PasswordEntry.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.view
+package com.motorro.commonstatemachine.examples.welcome.login.view
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -38,8 +38,8 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.login.R
-import com.motorro.statemachine.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.welcome.login.R
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
@Composable
internal fun PasswordEntry(
diff --git a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/PasswordError.kt b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/PasswordError.kt
similarity index 91%
rename from examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/PasswordError.kt
rename to examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/PasswordError.kt
index 300e170..1251fd8 100644
--- a/examples/welcome/login/src/main/java/com/motorro/statemachine/login/view/PasswordError.kt
+++ b/examples/welcome/login/src/main/kotlin/com/motorro/commonstatemachine/examples/welcome/login/view/PasswordError.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.view
+package com.motorro.commonstatemachine.examples.welcome.login.view
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.AlertDialog
@@ -22,8 +22,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
-import com.motorro.statemachine.login.R
-import com.motorro.statemachine.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.welcome.login.R
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
@Composable
internal fun PasswordError(state: LoginUiState.LoginError, onDismiss: () -> Unit) {
diff --git a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/BaseStateTest.kt b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/BaseStateTest.kt
similarity index 81%
rename from examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/BaseStateTest.kt
rename to examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/BaseStateTest.kt
index 7da04a8..bcd0871 100644
--- a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/BaseStateTest.kt
+++ b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/BaseStateTest.kt
@@ -11,16 +11,16 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
import androidx.annotation.CallSuper
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.data.LoginUiState
-import com.motorro.statemachine.login.model.LoginRenderer
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginUiState
+import com.motorro.commonstatemachine.examples.welcome.login.model.LoginRenderer
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
diff --git a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/CredentialsCheckStateTest.kt b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckStateTest.kt
similarity index 84%
rename from examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/CredentialsCheckStateTest.kt
rename to examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckStateTest.kt
index cd97c62..31bae83 100644
--- a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/CredentialsCheckStateTest.kt
+++ b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/CredentialsCheckStateTest.kt
@@ -13,13 +13,19 @@
@file:OptIn(ExperimentalCoroutinesApi::class)
-package com.motorro.statemachine.login.model.state
-
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
-import com.motorro.statemachine.login.usecase.CheckCredentials
-import io.mockk.*
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.login.usecase.CheckCredentials
+import io.mockk.Runs
+import io.mockk.coEvery
+import io.mockk.coVerify
+import io.mockk.every
+import io.mockk.just
+import io.mockk.mockk
+import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
diff --git a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/ErrorStateTest.kt b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorStateTest.kt
similarity index 85%
rename from examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/ErrorStateTest.kt
rename to examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorStateTest.kt
index 36adb2e..c9884af 100644
--- a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/ErrorStateTest.kt
+++ b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/ErrorStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
-import com.motorro.statemachine.commonapi.welcome.data.BAD
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.BAD
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
diff --git a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/PasswordEntryStateTest.kt b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryStateTest.kt
similarity index 91%
rename from examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/PasswordEntryStateTest.kt
rename to examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryStateTest.kt
index b55e06d..c7a09f0 100644
--- a/examples/welcome/login/src/test/java/com/motorro/statemachine/login/model/state/PasswordEntryStateTest.kt
+++ b/examples/welcome/login/src/test/kotlin/com/motorro/commonstatemachine/examples/welcome/login/model/state/PasswordEntryStateTest.kt
@@ -11,11 +11,11 @@
* limitations under the License.
*/
-package com.motorro.statemachine.login.model.state
+package com.motorro.commonstatemachine.examples.welcome.login.model.state
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.login.data.LoginDataState
-import com.motorro.statemachine.login.data.LoginGesture
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginDataState
+import com.motorro.commonstatemachine.examples.welcome.login.data.LoginGesture
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
diff --git a/examples/welcome/register/build.gradle.kts b/examples/welcome/register/build.gradle.kts
index 5170669..8513ab3 100644
--- a/examples/welcome/register/build.gradle.kts
+++ b/examples/welcome/register/build.gradle.kts
@@ -1,7 +1,3 @@
-@file:Suppress("unused")
-
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-
/*
* Copyright 2022 Nikolai Kotchetkov.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,80 +12,25 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
*/
plugins {
- alias(libs.plugins.android.lib)
- alias(libs.plugins.google.ksp)
- alias(libs.plugins.hilt)
- alias(libs.plugins.compose)
+ alias(libs.plugins.motorro.cmp)
+ alias(libs.plugins.koin)
}
-
-val versionCode: String by project.extra
-val versionName: String by project.extra
-val androidMinSdkVersion: Int by project.extra
-val androidCompileSdkVersion: Int by project.extra
-
-
-android {
- // Ensure androidCompileSdkVersion, androidMinSdkVersion, and androidTargetSdkVersion
- // are defined in your project's gradle.properties or root build.gradle.kts
- compileSdk = androidCompileSdkVersion
-
- defaultConfig {
- minSdk = androidMinSdkVersion
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles("consumer-rules.pro")
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+kotlin {
+ sourceSets {
+ commonMain.dependencies {
+ implementation(project(":commonstatemachine"))
+ implementation(project(":coroutines"))
+ implementation(project(":examples:commoncore"))
+ implementation(project(":examples:welcome:commonapi"))
+ implementation(libs.kotlin.coroutines.core)
+ implementation(libs.napier)
+ implementation(project.dependencies.platform(libs.koin.bom))
+ implementation(libs.koin.core)
+ implementation(libs.koin.annotations)
}
- }
- compileOptions {
- isCoreLibraryDesugaringEnabled = true
- sourceCompatibility = JavaVersion.VERSION_21
- targetCompatibility = JavaVersion.VERSION_21
- }
- kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_21)
+ commonTest.dependencies {
+ implementation(libs.test.kotlin.coroutines)
}
}
- buildFeatures {
- compose = true
- }
- namespace = "com.motorro.statemachine.register"
-}
-
-dependencies {
- implementation(project(":commonstatemachine"))
- implementation(project(":examples:welcome:commonapi"))
- implementation(project(":examples:commoncore"))
- implementation(project(":examples:androidcore"))
- api(project(":examples:welcome:commonregister"))
-
- coreLibraryDesugaring(libs.desugaring)
-
- implementation(libs.kotlin.coroutines.core)
- implementation(libs.kotlin.coroutines.android)
-
- implementation(platform(libs.compose.bom))
-
- implementation(libs.bundles.compose.core)
- implementation(libs.compose.activity)
- implementation(libs.compose.foundation)
- implementation(libs.compose.foundation.layouts) // In Groovy, this was 'foundation.layouts'. Ensure this maps correctly in your TOML.
-
- implementation(libs.hilt.android)
- implementation(libs.hilt.compose) // This was 'libs.hilt.compose'. Verify it maps to 'androidx.hilt:hilt-navigation-compose' or your intended Hilt Compose library.
- ksp(libs.hilt.compiler)
- ksp(libs.hilt.compiler.androidx) // This was 'libs.hilt.compiler.androidx'. Verify it maps to 'com.google.dagger:hilt-android-compiler' or the intended artifact.
-
- debugImplementation(libs.compose.tooling)
-
- testImplementation(libs.bundles.test.core)
- testImplementation(libs.test.androidx.arch)
- testImplementation(libs.test.kotlin.coroutines)
}
diff --git a/examples/welcome/register/src/commonMain/composeResources/values/strings.xml b/examples/welcome/register/src/commonMain/composeResources/values/strings.xml
new file mode 100644
index 0000000..ab51dbb
--- /dev/null
+++ b/examples/welcome/register/src/commonMain/composeResources/values/strings.xml
@@ -0,0 +1,10 @@
+
+ Enter password for:
+ Any password at least 6 chars long will do
+ Password
+ Repeat password
+ Previous
+ Next
+ Password should be at least 6 chars long
+ Passwords mismatch
+
diff --git a/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/RegisterFlowStarter.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/RegisterFlowStarter.kt
new file mode 100644
index 0000000..7c3db63
--- /dev/null
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/RegisterFlowStarter.kt
@@ -0,0 +1,10 @@
+package com.motorro.commonstatemachine.examples.welcome.register
+
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.FlowStarter
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
+
+/**
+ * Starts login flow
+ */
+interface RegisterFlowStarter : FlowStarter
\ No newline at end of file
diff --git a/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/RegisterModule.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/RegisterModule.kt
new file mode 100644
index 0000000..7d801b9
--- /dev/null
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/RegisterModule.kt
@@ -0,0 +1,8 @@
+package com.motorro.commonstatemachine.examples.welcome.register
+
+import org.koin.core.annotation.ComponentScan
+import org.koin.core.annotation.Module
+
+@Module
+@ComponentScan
+class RegisterModule
\ No newline at end of file
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/PasswordValidationError.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/PasswordValidationError.kt
similarity index 90%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/PasswordValidationError.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/PasswordValidationError.kt
index 5383146..0fc58ca 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/PasswordValidationError.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/PasswordValidationError.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.data
+package com.motorro.commonstatemachine.examples.welcome.register.data
enum class PasswordValidationError {
PASSWORD_LENGTH,
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterDataState.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterDataState.kt
similarity index 91%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterDataState.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterDataState.kt
index e28f5b5..5d30425 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterDataState.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterDataState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.data
+package com.motorro.commonstatemachine.examples.welcome.register.data
/**
* Login flow inter-state data
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterGesture.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterGesture.kt
similarity index 94%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterGesture.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterGesture.kt
index 3e24a6d..a872667 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterGesture.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterGesture.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.data
+package com.motorro.commonstatemachine.examples.welcome.register.data
/**
* Login flow UI gestures
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterUiState.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterUiState.kt
similarity index 94%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterUiState.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterUiState.kt
index 6d2c39c..3ed2603 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/data/RegisterUiState.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/data/RegisterUiState.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.data
+package com.motorro.commonstatemachine.examples.welcome.register.data
/**
* Login flow UI state
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/RegistrationRenderer.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/RegistrationRenderer.kt
similarity index 65%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/RegistrationRenderer.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/RegistrationRenderer.kt
index 7be4540..5c188ff 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/RegistrationRenderer.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/RegistrationRenderer.kt
@@ -11,18 +11,21 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.model
+package com.motorro.commonstatemachine.examples.welcome.register.model
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.register.data.PasswordValidationError
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError.PASSWORD_LENGTH
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError.PASSWORD_MISMATCH
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
+import org.koin.core.annotation.Factory
/**
* Renders data state
* Externalizes resource usage
*/
-interface RegistrationRenderer {
+internal interface RegistrationRenderer {
/**
* Renders password entry
*/
@@ -37,6 +40,7 @@ interface RegistrationRenderer {
*/
fun renderRegistration(data: RegisterDataState): RegisterUiState
+ @Factory
class Impl(resourceWrapper: ResourceWrapper): RegistrationRenderer, ResourceWrapper by resourceWrapper {
/**
* Renders password entry
@@ -62,4 +66,7 @@ interface RegistrationRenderer {
/**
* Returns password error text
*/
-expect fun ResourceWrapper.getPasswordError(error: PasswordValidationError): String
+fun ResourceWrapper.getPasswordError(error: PasswordValidationError): String = when(error) {
+ PASSWORD_LENGTH -> "Password should be at least 6 chars long"
+ PASSWORD_MISMATCH -> "Passwords mismatch"
+}
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/PasswordEntryState.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/PasswordEntryState.kt
similarity index 81%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/PasswordEntryState.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/PasswordEntryState.kt
index 92ea7b7..6890a38 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/PasswordEntryState.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/PasswordEntryState.kt
@@ -11,19 +11,19 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.model.state
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.register.data.PasswordValidationError
-import com.motorro.statemachine.register.data.PasswordValidationError.PASSWORD_LENGTH
-import com.motorro.statemachine.register.data.PasswordValidationError.PASSWORD_MISMATCH
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError.PASSWORD_LENGTH
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError.PASSWORD_MISMATCH
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
/**
* Password entry screen
*/
-class PasswordEntryState(
+internal class PasswordEntryState(
context: RegisterContext,
private var data: RegisterDataState
) : RegisterState(context) {
@@ -101,4 +101,3 @@ class PasswordEntryState(
else -> null
}
}
-
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterContext.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterContext.kt
similarity index 73%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterContext.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterContext.kt
index f839264..dec5c69 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterContext.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterContext.kt
@@ -11,16 +11,15 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.model.state
-
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.register.model.RegistrationRenderer
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.register.model.RegistrationRenderer
/**
* Context for login flow
*/
-interface RegisterContext {
+internal interface RegisterContext {
/**
* State factory
*/
@@ -35,4 +34,4 @@ interface RegisterContext {
* Renderer
*/
val renderer: RegistrationRenderer
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterState.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterState.kt
similarity index 65%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterState.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterState.kt
index 96de414..40b3dc9 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegisterState.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterState.kt
@@ -11,23 +11,21 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.model.state
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
import com.motorro.commonstatemachine.coroutines.CoroutineState
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
/**
* Base class for registration flow state
*/
-abstract class RegisterState(
- context: RegisterContext
-): CoroutineState(), RegisterContext by context {
+internal abstract class RegisterState(context: RegisterContext): CoroutineState(), RegisterContext by context {
/**
* A part of [process] template to process UI gesture
*/
override fun doProcess(gesture: RegisterGesture) {
Logger.w("Unsupported gesture: %s", gesture)
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterStateFactory.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterStateFactory.kt
new file mode 100644
index 0000000..58ceae3
--- /dev/null
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterStateFactory.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2022 Nikolai Kotchetkov.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * 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.
+ */
+
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
+
+import com.motorro.commonstatemachine.CommonMachineState
+import com.motorro.commonstatemachine.examples.welcome.register.RegisterFlowStarter
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
+
+/**
+ * Login flow state factory
+ */
+internal interface RegisterStateFactory : RegisterFlowStarter {
+ /**
+ * Creates a starting state
+ * @param email Email to proceed with
+ */
+ override fun start(email: String): CommonMachineState = passwordEntry(
+ RegisterDataState(email)
+ )
+
+ /**
+ * Password entry screen
+ * @param data Registration data state
+ */
+ fun passwordEntry(data: RegisterDataState): RegisterState
+
+ /**
+ * Registers user
+ * @param data Data state
+ */
+ fun registering(data: RegisterDataState): RegisterState
+
+}
+
diff --git a/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterStateFactoryImpl.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterStateFactoryImpl.kt
new file mode 100644
index 0000000..c06e4c4
--- /dev/null
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegisterStateFactoryImpl.kt
@@ -0,0 +1,44 @@
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
+
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.register.RegisterFlowStarter
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.model.RegistrationRenderer
+import org.koin.core.annotation.Factory
+import org.koin.core.annotation.InjectedParam
+
+/**
+ * [RegisterStateFactory] implementation
+ */
+@Factory(binds = [RegisterFlowStarter::class])
+internal class RegisterStateFactoryImpl(
+ @InjectedParam host: WelcomeFeatureHost,
+ renderer: RegistrationRenderer,
+ private val createRegistration: RegistrationState.StateFactory
+) : RegisterStateFactory {
+
+ private val context: RegisterContext = object : RegisterContext {
+ override val factory: RegisterStateFactory = this@RegisterStateFactoryImpl
+ override val host: WelcomeFeatureHost = host
+ override val renderer: RegistrationRenderer = renderer
+ }
+
+ /**
+ * Password entry screen
+ * @param data Registration data state
+ */
+ override fun passwordEntry(data: RegisterDataState): RegisterState {
+ Logger.d("Creating 'Password entry'...")
+ return PasswordEntryState(context, data)
+ }
+
+ /**
+ * Registers user
+ * @param data Data state
+ */
+ override fun registering(data: RegisterDataState): RegisterState {
+ Logger.d("Creating 'Credentials check'...")
+ return createRegistration(context, data)
+ }
+}
\ No newline at end of file
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegistrationState.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegistrationState.kt
similarity index 78%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegistrationState.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegistrationState.kt
index a58624d..d7bf40b 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/model/state/RegistrationState.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/model/state/RegistrationState.kt
@@ -11,18 +11,19 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.model.state
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
-import com.motorro.statemachine.commoncore.log.Logger
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.usecase.Registration
+import com.motorro.commonstatemachine.examples.commoncore.log.Logger
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.usecase.Registration
import kotlinx.coroutines.launch
+import org.koin.core.annotation.Factory
/**
* Emulates login operation
*/
-class RegistrationState(
+internal class RegistrationState(
context: RegisterContext,
private val data: RegisterDataState,
private val register: Registration
@@ -64,7 +65,8 @@ class RegistrationState(
/**
* [RegisterState] factory
*/
- class Factory(private val register: Registration) {
+ @Factory
+ class StateFactory(private val register: Registration) {
operator fun invoke(
context: RegisterContext,
data: RegisterDataState
@@ -74,4 +76,4 @@ class RegistrationState(
register
)
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/usecase/Registration.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/usecase/Registration.kt
similarity index 80%
rename from examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/usecase/Registration.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/usecase/Registration.kt
index 4432e46..758971f 100644
--- a/examples/welcome/commonregister/src/commonMain/kotlin/com/motorro/statemachine/register/usecase/Registration.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/usecase/Registration.kt
@@ -11,17 +11,18 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.usecase
+package com.motorro.commonstatemachine.examples.welcome.register.usecase
-import com.motorro.statemachine.commonapi.NETWORK_DELAY
-import com.motorro.statemachine.commoncore.coroutines.DispatcherProvider
+import com.motorro.commonstatemachine.examples.commoncore.coroutines.DispatcherProvider
+import com.motorro.commonstatemachine.examples.welcome.commonapi.NETWORK_DELAY
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
+import org.koin.core.annotation.Factory
/**
* Emulates user registration
*/
-interface Registration {
+internal interface Registration {
/**
* Registers user
* @param email Email to register
@@ -29,6 +30,7 @@ interface Registration {
*/
suspend operator fun invoke(email: String, password: String): Boolean
+ @Factory
class Impl(private val dispatchers: DispatcherProvider): Registration {
/**
* Registers user
diff --git a/examples/welcome/register/src/main/java/com/motorro/statemachine/register/view/PasswordEntry.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/view/PasswordEntry.kt
similarity index 76%
rename from examples/welcome/register/src/main/java/com/motorro/statemachine/register/view/PasswordEntry.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/view/PasswordEntry.kt
index 5eb06aa..81cba86 100644
--- a/examples/welcome/register/src/main/java/com/motorro/statemachine/register/view/PasswordEntry.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/view/PasswordEntry.kt
@@ -11,7 +11,7 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.view
+package com.motorro.commonstatemachine.examples.welcome.register.view
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -34,12 +34,18 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import com.motorro.statemachine.register.R
-import com.motorro.statemachine.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.welcome.register.Res
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.welcome.register.register_password_entry_desc
+import com.motorro.commonstatemachine.examples.welcome.register.register_password_entry_label
+import com.motorro.commonstatemachine.examples.welcome.register.register_password_entry_next
+import com.motorro.commonstatemachine.examples.welcome.register.register_password_entry_prev
+import com.motorro.commonstatemachine.examples.welcome.register.register_password_entry_title
+import com.motorro.commonstatemachine.examples.welcome.register.register_repeat_password_entry_label
+import org.jetbrains.compose.resources.stringResource
@Composable
fun PasswordEntry(
@@ -63,7 +69,7 @@ fun PasswordEntry(
) {
Column(modifier = Modifier.fillMaxWidth()) {
Text(
- text = stringResource(id = R.string.register_password_entry_title),
+ text = stringResource(Res.string.register_password_entry_title),
style = MaterialTheme.typography.headlineMedium
)
@@ -76,7 +82,7 @@ fun PasswordEntry(
Spacer(modifier = Modifier.height(12.dp))
Text(
- text = stringResource(id = R.string.register_password_entry_desc),
+ text = stringResource(Res.string.register_password_entry_desc),
style = MaterialTheme.typography.bodyMedium
)
@@ -86,7 +92,7 @@ fun PasswordEntry(
value = state.password,
onValueChange = onPasswordChanged,
modifier = Modifier.fillMaxWidth(),
- label = { Text(stringResource(id = R.string.register_password_entry_label)) },
+ label = { Text(stringResource(Res.string.register_password_entry_label)) },
visualTransformation = PasswordVisualTransformation()
)
@@ -96,7 +102,7 @@ fun PasswordEntry(
value = state.repeatPassword,
onValueChange = onRepeatPasswordChanged,
modifier = Modifier.fillMaxWidth(),
- label = { Text(stringResource(id = R.string.register_repeat_password_entry_label)) },
+ label = { Text(stringResource(Res.string.register_repeat_password_entry_label)) },
visualTransformation = PasswordVisualTransformation()
)
@@ -116,13 +122,13 @@ fun PasswordEntry(
verticalAlignment = Alignment.CenterVertically
) {
Button(onClick = onPrevious) {
- Text(text = stringResource(id = R.string.register_password_entry_prev))
+ Text(text = stringResource(Res.string.register_password_entry_prev))
}
Spacer(modifier = Modifier.width(12.dp))
Button(onClick = onNext) {
- Text(text = stringResource(id = R.string.register_password_entry_next))
+ Text(text = stringResource(Res.string.register_password_entry_next))
}
}
}
@@ -143,4 +149,4 @@ fun EmailEntryPreview() {
onPrevious = {},
onNext = {}
)
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/register/src/main/java/com/motorro/statemachine/register/view/RegistrationScreen.kt b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/view/RegistrationScreen.kt
similarity index 79%
rename from examples/welcome/register/src/main/java/com/motorro/statemachine/register/view/RegistrationScreen.kt
rename to examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/view/RegistrationScreen.kt
index 5ccc356..0863f92 100644
--- a/examples/welcome/register/src/main/java/com/motorro/statemachine/register/view/RegistrationScreen.kt
+++ b/examples/welcome/register/src/commonMain/kotlin/com/motorro/commonstatemachine/examples/welcome/register/view/RegistrationScreen.kt
@@ -11,12 +11,12 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.view
+package com.motorro.commonstatemachine.examples.welcome.register.view
import androidx.compose.runtime.Composable
-import com.motorro.statemachine.androidcore.compose.Loading
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.commoncore.ui.Loading
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
/**
* Registration screen flow
@@ -33,4 +33,4 @@ fun RegistrationScreen(state: RegisterUiState, onGesture: (RegisterGesture) -> U
onNext = { onGesture(RegisterGesture.Action) }
)
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/mocks.kt b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/mocks.kt
similarity index 70%
rename from examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/mocks.kt
rename to examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/mocks.kt
index 0eeeb1e..da77bc1 100644
--- a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/mocks.kt
+++ b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/mocks.kt
@@ -11,26 +11,26 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register
+package com.motorro.commonstatemachine.examples.welcome.register
import com.motorro.commonstatemachine.CommonMachineState
import com.motorro.commonstatemachine.CommonStateMachine
-import com.motorro.statemachine.commonapi.welcome.model.state.WelcomeFeatureHost
-import com.motorro.statemachine.commoncore.resources.ResourceWrapper
-import com.motorro.statemachine.register.data.PasswordValidationError
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
-import com.motorro.statemachine.register.model.RegistrationRenderer
-import com.motorro.statemachine.register.model.state.RegisterContext
-import com.motorro.statemachine.register.model.state.RegisterState
-import com.motorro.statemachine.register.model.state.RegisterStateFactory
-import com.motorro.statemachine.register.usecase.Registration
+import com.motorro.commonstatemachine.examples.commoncore.resources.ResourceWrapper
+import com.motorro.commonstatemachine.examples.welcome.commonapi.model.state.WelcomeFeatureHost
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.welcome.register.model.RegistrationRenderer
+import com.motorro.commonstatemachine.examples.welcome.register.model.state.RegisterContext
+import com.motorro.commonstatemachine.examples.welcome.register.model.state.RegisterState
+import com.motorro.commonstatemachine.examples.welcome.register.model.state.RegisterStateFactory
+import com.motorro.commonstatemachine.examples.welcome.register.usecase.Registration
const val R_STRING = "string"
val R_CONTENT = RegisterUiState.Loading
-class StateMock(context: RegisterContext) : RegisterState(context) {
+internal class StateMock(context: RegisterContext) : RegisterState(context) {
var started = false
val processed = mutableListOf()
var cleared = false
@@ -48,7 +48,7 @@ class StateMock(context: RegisterContext) : RegisterState(context) {
}
}
-class MachineMock : CommonStateMachine {
+internal class MachineMock : CommonStateMachine {
val machineStates = mutableListOf>()
val processed = mutableListOf()
val uiStates = mutableListOf()
@@ -80,13 +80,13 @@ class MachineMock : CommonStateMachine {
}
}
-class MockContext : RegisterContext {
+internal class MockContext : RegisterContext {
override val factory: MockFactory = MockFactory(this)
override val host: MockHost = MockHost()
override val renderer: MockRenderer = MockRenderer()
}
-class MockHost : WelcomeFeatureHost {
+internal class MockHost : WelcomeFeatureHost {
var backToEmails = 0
var completes = 0
@@ -99,7 +99,7 @@ class MockHost : WelcomeFeatureHost {
}
}
-class MockFactory(private val context: RegisterContext) : RegisterStateFactory {
+internal class MockFactory(private val context: RegisterContext) : RegisterStateFactory {
val passwordEntries = mutableListOf()
val registers = mutableListOf()
@@ -114,7 +114,7 @@ class MockFactory(private val context: RegisterContext) : RegisterStateFactory {
}
}
-class MockRenderer : RegistrationRenderer {
+internal class MockRenderer : RegistrationRenderer {
val passwordEntries = mutableListOf>()
val registrations = mutableListOf()
@@ -133,7 +133,7 @@ class MockRenderer : RegistrationRenderer {
}
}
-class MockResourceWrapper : ResourceWrapper {
+internal class MockResourceWrapper : ResourceWrapper {
val getStrings = mutableListOf>>()
override fun getString(resId: Int, vararg args: Any): String {
@@ -142,11 +142,11 @@ class MockResourceWrapper : ResourceWrapper {
}
}
-class MockRegistration : Registration {
+internal class MockRegistration : Registration {
val invocations = mutableListOf>()
override suspend fun invoke(email: String, password: String): Boolean {
invocations.add(email to password)
return true
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/BaseStateTest.kt b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/BaseStateTest.kt
similarity index 74%
rename from examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/BaseStateTest.kt
rename to examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/BaseStateTest.kt
index ac1d8ed..27b5a31 100644
--- a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/BaseStateTest.kt
+++ b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/BaseStateTest.kt
@@ -11,9 +11,13 @@
* limitations under the License.
*/
-package com.motorro.statemachine.register.model.state
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
-import com.motorro.statemachine.register.*
+import com.motorro.commonstatemachine.examples.welcome.register.MachineMock
+import com.motorro.commonstatemachine.examples.welcome.register.MockContext
+import com.motorro.commonstatemachine.examples.welcome.register.MockFactory
+import com.motorro.commonstatemachine.examples.welcome.register.MockHost
+import com.motorro.commonstatemachine.examples.welcome.register.MockResourceWrapper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -22,7 +26,7 @@ import kotlinx.coroutines.test.setMain
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
-open class BaseStateTest {
+internal open class BaseStateTest {
protected val stateMachine: MachineMock = MachineMock()
protected val context: MockContext = MockContext()
protected val factory: MockFactory = context.factory
@@ -40,4 +44,4 @@ open class BaseStateTest {
open fun after() {
Dispatchers.resetMain()
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/PasswordEntryStateTest.kt b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/PasswordEntryStateTest.kt
similarity index 89%
rename from examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/PasswordEntryStateTest.kt
rename to examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/PasswordEntryStateTest.kt
index b45089d..1ac9213 100644
--- a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/PasswordEntryStateTest.kt
+++ b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/PasswordEntryStateTest.kt
@@ -13,24 +13,25 @@
@file:Suppress("RemoveExplicitTypeArguments")
-package com.motorro.statemachine.register.model.state
-
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.register.R_CONTENT
-import com.motorro.statemachine.register.data.PasswordValidationError
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
+
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
+import com.motorro.commonstatemachine.examples.welcome.register.R_CONTENT
+import com.motorro.commonstatemachine.examples.welcome.register.data.PasswordValidationError
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
import kotlin.test.Test
import kotlin.test.assertEquals
-class PasswordEntryStateTest : BaseStateTest() {
+internal class PasswordEntryStateTest : BaseStateTest() {
private val password = "password"
private val data = RegisterDataState(GOOD)
private lateinit var state: PasswordEntryState
- private fun createState(data: RegisterDataState = this.data) = PasswordEntryState(context, data)
+ private fun createState(data: RegisterDataState = this.data) =
+ PasswordEntryState(context, data)
@Test
fun displaysValidStateOnEmptyPasswordBeforeAction() {
@@ -197,4 +198,3 @@ class PasswordEntryStateTest : BaseStateTest() {
)
}
}
-
diff --git a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/RegisterStateTest.kt b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/RegisterStateTest.kt
similarity index 76%
rename from examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/RegisterStateTest.kt
rename to examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/RegisterStateTest.kt
index 024e486..5cc478a 100644
--- a/examples/welcome/commonregister/src/commonTest/kotlin/com/motorro/statemachine/register/model/state/RegisterStateTest.kt
+++ b/examples/welcome/register/src/commonTest/kotlin/com/motorro/commonstatemachine/examples/welocme/register/model/state/RegisterStateTest.kt
@@ -13,29 +13,31 @@
@file:Suppress("RemoveExplicitTypeArguments")
-package com.motorro.statemachine.register.model.state
+package com.motorro.commonstatemachine.examples.welcome.register.model.state
-import com.motorro.statemachine.commonapi.welcome.data.GOOD
-import com.motorro.statemachine.register.MockRegistration
-import com.motorro.statemachine.register.R_CONTENT
-import com.motorro.statemachine.register.data.RegisterDataState
-import com.motorro.statemachine.register.data.RegisterGesture
-import com.motorro.statemachine.register.data.RegisterUiState
+import com.motorro.commonstatemachine.examples.welcome.commonapi.data.GOOD
+import com.motorro.commonstatemachine.examples.welcome.register.MockRegistration
+import com.motorro.commonstatemachine.examples.welcome.register.R_CONTENT
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterDataState
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterGesture
+import com.motorro.commonstatemachine.examples.welcome.register.data.RegisterUiState
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import kotlin.test.AfterTest
+import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals
@OptIn(ExperimentalCoroutinesApi::class)
-abstract class RegisterStateTest: BaseStateTest() {
+internal abstract class RegisterStateTest: BaseStateTest() {
private val password = "password"
private val data = RegisterDataState(GOOD, password)
private val registration = MockRegistration()
private lateinit var state: RegistrationState
+ @BeforeTest
override fun before() {
super.before()
state = RegistrationState(context, data, registration)
@@ -87,4 +89,4 @@ abstract class RegisterStateTest: BaseStateTest() {
host.backToEmails
)
}
-}
\ No newline at end of file
+}
diff --git a/examples/welcome/register/src/main/AndroidManifest.xml b/examples/welcome/register/src/main/AndroidManifest.xml
deleted file mode 100644
index cfc666d..0000000
--- a/examples/welcome/register/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-