Skip to content

Commit

Permalink
Merge branch 'v2.2' into v2.2-compose-experimental
Browse files Browse the repository at this point in the history
  • Loading branch information
arkivanov committed Oct 31, 2023
2 parents dc4f361 + ab9d773 commit f277563
Show file tree
Hide file tree
Showing 22 changed files with 715 additions and 450 deletions.
2 changes: 2 additions & 0 deletions decompose/api/android/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,8 @@ public final class com/arkivanov/decompose/router/stack/StackNavigatorExtKt {
public static final fun popWhile (Lcom/arkivanov/decompose/router/stack/StackNavigator;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public static final fun push (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
public static synthetic fun push$default (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
public static final fun pushNew (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun pushNew$default (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun replaceAll (Lcom/arkivanov/decompose/router/stack/StackNavigator;[Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
public static synthetic fun replaceAll$default (Lcom/arkivanov/decompose/router/stack/StackNavigator;[Ljava/lang/Object;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
public static final fun replaceCurrent (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
Expand Down
2 changes: 2 additions & 0 deletions decompose/api/jvm/decompose.api
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ public final class com/arkivanov/decompose/router/stack/StackNavigatorExtKt {
public static final fun popWhile (Lcom/arkivanov/decompose/router/stack/StackNavigator;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)V
public static final fun push (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
public static synthetic fun push$default (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
public static final fun pushNew (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun pushNew$default (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public static final fun replaceAll (Lcom/arkivanov/decompose/router/stack/StackNavigator;[Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
public static synthetic fun replaceAll$default (Lcom/arkivanov/decompose/router/stack/StackNavigator;[Ljava/lang/Object;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)V
public static final fun replaceCurrent (Lcom/arkivanov/decompose/router/stack/StackNavigator;Ljava/lang/Object;Lkotlin/jvm/functions/Function0;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.arkivanov.decompose.router.stack

import com.arkivanov.decompose.ExperimentalDecomposeApi

/**
* A convenience method for [StackNavigator.navigate].
*/
Expand All @@ -10,12 +12,38 @@ fun <C : Any> StackNavigator<C>.navigate(transformer: (stack: List<C>) -> List<C
/**
* Pushes the provided [configuration] at the top of the stack.
*
* Decompose will throw an exception if the provided [configuration] is already present in the stack.
*
* @param onComplete called when the navigation is finished (either synchronously or asynchronously).
*/
fun <C : Any> StackNavigator<C>.push(configuration: C, onComplete: () -> Unit = {}) {
navigate(transformer = { it + configuration }, onComplete = { _, _ -> onComplete() })
}

/**
* Pushes the provided [configuration] at the top of the stack. Does nothing if the provided
* [configuration] is already on top of the stack.
*
* Decompose will throw an exception if the provided [configuration] is already present in the
* back stack (not at the top of the stack).
*
* This can be useful when pushing a component on button click, to avoid pushing the same component
* if the user clicks the same button quickly multiple times.
*
* @param onComplete called when the navigation is finished (either synchronously or asynchronously).
* The `isSuccess` argument is `true` if the component was pushed, `false` otherwise.
*/
@ExperimentalDecomposeApi
fun <C : Any> StackNavigator<C>.pushNew(
configuration: C,
onComplete: (isSuccess: Boolean) -> Unit = {},
) {
navigate(
transformer = { stack -> if (stack.last() == configuration) stack else stack + configuration },
onComplete = { newStack, oldStack -> onComplete(newStack.size > oldStack.size) },
)
}

/**
* Pops the latest configuration at the top of the stack.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.arkivanov.decompose.router.stack

import kotlin.test.Test
import kotlin.test.assertEquals

@Suppress("TestFunctionName")
class RouterPushNewTest {

@Test
fun GIVEN_configuration_not_present_WHEN_pushNew_THEN_pushed() {
val navigator = TestStackNavigator(listOf(1, 2))

navigator.pushNew(3)

assertEquals(listOf(1, 2, 3), navigator.configurations)
}

@Test
fun GIVEN_configuration_present_on_top_WHEN_pushNew_THEN_not_pushed() {
val navigator = TestStackNavigator(listOf(1, 2))

navigator.pushNew(2)

assertEquals(listOf(1, 2), navigator.configurations)
}

@Test
fun GIVEN_configuration_not_present_WHEN_pushNew_THEN_onComplete_success() {
val navigator = TestStackNavigator(listOf(1, 2))
var result: Boolean? = null

navigator.pushNew(3) { result = it }

assertEquals(true, result)
}

@Test
fun GIVEN_configuration_present_on_top_WHEN_pushNew_THEN_onComplete_not_success() {
val navigator = TestStackNavigator(listOf(1, 2))
var result: Boolean? = null

navigator.pushNew(2) { result = it }

assertEquals(false, result)
}
}
5 changes: 3 additions & 2 deletions deps.versions.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
[versions]

decompose = "2.2.0-compose-experimental-alpha02"
decompose = "2.2.0-compose-experimental-alpha03"
kotlin = "1.9.10"
essenty = "1.3.0-alpha01"
essenty = "1.3.0-alpha02"
parcelizeDarwin = "0.2.2"
reaktive = "1.2.3"
junit = "4.13.2"
Expand All @@ -26,6 +26,7 @@ androidxTestCore = "1.5.0"
[libraries]

kotlin-kotlinGradlePlug = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" }

essenty-lifecycle = { group = "com.arkivanov.essenty", name = "lifecycle", version.ref = "essenty" }
essenty-stateKeeper = { group = "com.arkivanov.essenty", name = "state-keeper", version.ref = "essenty" }
Expand Down
23 changes: 23 additions & 0 deletions docs/community.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
This page contains links to various useful projects related to Decompose and maintained by the community.

### Decompose-Router

A Compose-multiplatform navigation library that leverage Decompose to create an API inspired by [Conductor](https://github.com/bluelinelabs/Conductor).

!!! tip

Decompose-Router is a lightweight library based on Decompose, it can be especially useful if you find Decompose cumbersome or difficult to learn.

Link: [github.com/xxfast/Decompose-Router](https://github.com/xxfast/Decompose-Router)

Author: [@xxfast](https://github.com/xxfast)

### MVIKotlin Decompose Template (IDEA Plugin)

Decompose and MVIKotlin plugin template, which will help you to create new components.

Link: [plugins.jetbrains.com/plugin/22852-mvikotlin-decompose-template](https://plugins.jetbrains.com/plugin/22852-mvikotlin-decompose-template)

Source code: [github.com/makeevrserg/MVIKotlin-Decompose-Plugin](https://github.com/makeevrserg/MVIKotlin-Decompose-Plugin)

Author: [@makeevrserg](https://github.com/makeevrserg)
41 changes: 41 additions & 0 deletions docs/extensions/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,47 @@ fun DetailsContent(component: DetailsComponent) {
}
```

## Child Slot navigation with Compose

Child Slot navigation model can be used for different purposes. It can be used to just show/hide a certain part of UI, or to present a dialog, or a sheet (like Material Bottom Sheet). Although Decompose doesn't provide any special Compose API for Child Slot, it's pretty easy to do it manually.

```kotlin title="AlertDialog example"
interface RootComponent {
val dialog: Value<ChildSlot<*, DialogComponent>>
}

@Composable
fun RootContent(component: RootComponent) {
val dialogSlot by component.dialog.subscribeAsState()
dialogSlot.child?.instance?.also {
DialogContent(component = it)
}
}

interface DialogComponent {
fun onDismissClicked()
}

@Composable
fun DialogContent(component: DialogComponent) {
AlertDialog(
onDismissRequest = component::onDismissClicked,
title = { Text(text = "Title") },
text = { Text(text = "Message") },
confirmButton = {
TextButton(onClick = component::onDismissClicked) {
Text("Dismiss")
}
},
modifier = Modifier.width(300.dp),
)
}
```

!!! note

Child Slot might not be suitable for a Navigation Drawer. This is because the Navigation Drawer can be opened by a drag gesture at any time. The corresponding component should be [always created](https://arkivanov.github.io/Decompose/component/child-components/#adding-a-child-component-manually) so that it's always ready to be rendered.

## Pager-like navigation

!!!warning
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Decompose is a Kotlin Multiplatform library for breaking down your code into lif
- Decompose draws clear boundaries between UI and non-UI code, which gives the following benefits:
- Better separation of concerns
- Pluggable platform-specific UI (Compose, SwiftUI, React, etc.)
- Business logic code is testable with pure multiplatform unit tets
- Business logic code is testable with pure multiplatform unit tests
- Proper dependency injection (DI) and inversion of control (IoC) via constructor, including but not limited to type-safe arguments.
- Shared navigation logic
- Lifecycle-aware components
Expand Down
6 changes: 6 additions & 0 deletions docs/samples.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ Simple todo application with a list and detail page that shares UI between Andro

![](https://github.com/IlyaGulya/TodoAppDecomposeMviKotlin/blob/master/screenshots/todo.png?raw=true)

## Decompose-Dagger Sample

A sample Android project demonstrating the use of Decompose library together with Dagger DI framework.

[decompose-dagger-sample](https://github.com/arkivanov/decompose-dagger-sample)

## Sample Greetings App

![](media/SampleGreetingsDemo.gif)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/an
public static synthetic fun fade$default (Landroidx/compose/animation/core/FiniteAnimationSpec;FILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/PredictiveBackAnimationKt {
public static final fun predictiveBackAnimation (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
public static synthetic fun predictiveBackAnimation$default (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/ScaleKt {
public static final fun scale (Landroidx/compose/animation/core/FiniteAnimationSpec;FF)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
public static synthetic fun scale$default (Landroidx/compose/animation/core/FiniteAnimationSpec;FFILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
Expand Down Expand Up @@ -111,3 +106,20 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/an
public static synthetic fun stackAnimator$default (Landroidx/compose/animation/core/FiniteAnimationSpec;Lkotlin/jvm/functions/Function5;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
}

public abstract interface class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable {
public abstract fun animate (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun finish (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getEnterModifier ()Landroidx/compose/ui/Modifier;
public abstract fun getExitModifier ()Landroidx/compose/ui/Modifier;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatableKt {
public static final fun predictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable;
public static synthetic fun predictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimationKt {
public static final fun predictiveBackAnimation (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
public static synthetic fun predictiveBackAnimation$default (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
}

Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,6 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/an
public static synthetic fun fade$default (Landroidx/compose/animation/core/FiniteAnimationSpec;FILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/PredictiveBackAnimationKt {
public static final fun predictiveBackAnimation (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
public static synthetic fun predictiveBackAnimation$default (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/ScaleKt {
public static final fun scale (Landroidx/compose/animation/core/FiniteAnimationSpec;FF)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
public static synthetic fun scale$default (Landroidx/compose/animation/core/FiniteAnimationSpec;FFILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
Expand Down Expand Up @@ -123,3 +118,20 @@ public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/an
public static synthetic fun stackAnimator$default (Landroidx/compose/animation/core/FiniteAnimationSpec;Lkotlin/jvm/functions/Function5;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimator;
}

public abstract interface class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable {
public abstract fun animate (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun finish (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public abstract fun getEnterModifier ()Landroidx/compose/ui/Modifier;
public abstract fun getExitModifier ()Landroidx/compose/ui/Modifier;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatableKt {
public static final fun predictiveBackAnimatable (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable;
public static synthetic fun predictiveBackAnimatable$default (Lcom/arkivanov/essenty/backhandler/BackEvent;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimatable;
}

public final class com/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/predictiveback/PredictiveBackAnimationKt {
public static final fun predictiveBackAnimation (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
public static synthetic fun predictiveBackAnimation$default (Lcom/arkivanov/essenty/backhandler/BackHandler;Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lcom/arkivanov/decompose/extensions/compose/jetbrains/stack/animation/StackAnimation;
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.arkivanov.decompose.Child
import com.arkivanov.decompose.ExperimentalDecomposeApi
Expand Down Expand Up @@ -83,7 +84,10 @@ fun <C : Any, T : Any> Pages(
}

DisposableEffect(state.currentPage) {
onPageSelected(state.currentPage)
if (state.currentPage == state.targetPage) {
onPageSelected(state.currentPage)
}

onDispose {}
}

Expand All @@ -92,7 +96,9 @@ fun <C : Any, T : Any> Pages(
state,
{ key(childPages.items[it]) },
) { pageIndex ->
childPages.items[pageIndex].instance?.also { page ->
val item = childPages.items[pageIndex]
val page = remember(item.configuration) { item.instance }
if (page != null) {
pageContent(pageIndex, page)
}
}
Expand Down
Loading

0 comments on commit f277563

Please sign in to comment.