Giter Club home page Giter Club logo

decompose's Introduction



License Twitter URL


Decompose is a Kotlin Multiplatform library for breaking down your code into tree-structured lifecycle-aware business logic components (aka BLoC), with routing functionality and pluggable UI (Jetpack/Multiplatform Compose, Android Views, SwiftUI, Kotlin/React, etc.).

Please see the project website for documentation and APIs.

Should you have any questions or ideas - there is Discussions section. Also welcome to the Kotlin Slack channel - #decompose!

⚡⚡⚡ Where are all the stars, issues, discussions, pull requests, etc?

Having spent 5 years working on a variety of projects for Badoo/Bumble, I’m now off to another adventure. As part of that transition I was asked to transfer this repository to Badoo GitHub account.

Now I continue my work on this project as a copy.

There should be no breaking changes related to this transfer. Most of the external links should not be broken. The repository link is also the same: arkivanov/Decompose. Please file an issue in this repository, if you think something is broken or does not work properly.

Here is what is mostly affected by the transfer:

  • All the stars were transferred
  • All the issues and discussions were transferred as well. I will do all my best to fill the gap here.
  • All pull requests with all the comment history are also gone.

I will continue doing all my best for this project and for the community! Business as usual!

Additional resources:

Why Decompose?

  • Decompose breaks the code down into small and independent components and organizes them into trees. Each parent component is only aware of its immediate children.
  • 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, Kotlin/React, etc.)
    • Business logic code is testable with pure multiplatform unit tests
  • Navigation state is fully exposed - plug any UI you want, animate as you like using your favourite UI framework's API or use predefined API.
  • Navigation is a pure function from the old state to a new one - navigate without limits.
  • 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
  • Components in the back stack are not destroyed, they continue working in background without UI
  • State preservation (automatically on Android, manually on all other targets via kotlinx-serialization)
  • Instances retaining (aka ViewModels) over configuration changes (mostly useful in Android)

Setup

Please check the Installation section of the documentation.

Supported platforms

In general, Decompose supports the following targets: android, jvm, ios, watchos, tvos, macos, wasmJs, js. However, some modules do not support all targets or the support depends on the Decompose version. Please see the Installation docs for details.

Overview

Here are some key concepts of the library, more details can be found in the documentation.

  • Component - every component represents a piece of logic with its own lifecycle, the UI is optional and is plugged externally
  • ComponentContext - every component has its own [ComponentContext], which makes components lifecycle-aware and allows state preservation, instances retaining (aka AndroidX ViewModel) and back button handling
  • Child Stack - enables navigation between child components, nested navigation is also supported
  • Child Slot - allows only one child component at a time, or none
  • Child Pages - a list of child components with one selected component (e.g. pager-like navigation)
  • Generic Navigation - provides a way to create your own custom navigation model, when none of the predefined models fit your needs
  • Lifecycle - provides a way to listen for lifecycle events in components
  • StateKeeper - makes it possible to preserve state or data in a component when it gets destroyed
  • InstanceKeeper - retains instances in your components (similar to AndroidX ViewModel)
  • BackPressedHandler - provides a way to handle and intercept back button presses

Component hierarchy

Pluggable UI hierarchy

Typical component structure

Quick start

Please refer to the Quick start section of the docs.

Samples

Check out the Samples section of the docs for a full description of each sample.

Template

Check out the template repository which may be used to kick-start a project for you.

Articles

Author

Twitter: @arkann1985

If you like this project you can always Buy Me A Coffee ;-)

decompose's People

Contributors

alexzhirkevich avatar anton-avm avatar arkivanov avatar azlekov avatar c2h6o avatar chen-xi-g avatar darvld avatar datl4g avatar drinkthestars avatar eliavyair1 avatar girijakar avatar hamen avatar ivkosh avatar jimkarsh avatar malliaridis avatar maxtox3 avatar moffpage avatar mohamedrejeb avatar morfly avatar nikola-milovic avatar plusmobileapps avatar shabinder avatar steelahhh avatar theapache64 avatar tiebe avatar tommyten avatar ttypic avatar zikstar avatar zveljkovic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

decompose's Issues

Create new Value from multiple Values

It would be great to have a function to create a new Value from several Values, kind of like Compose's derivedStateOf(). I know that there is map, this however takes in only one Value, or am I overlooking something?

Use case could be for example:
You have a parent Component with several ChildComponents. When at least one of the ChildComponents is loading something, set a Value loading of the parent component to true, to show a Loading Indicator.

Problem with configurations containing 3rd-party non-parcelable classes.

Is it possible to use arrow.core.Either (or other classes from 3rd-party multiplatform libraries which isn't inherit Parcelable / Serializable) as part of configuration class?

Context: I want to store (inside some of configurations) something like Either<TemporaryView, String>, where the .right() is for an id of DbView (I don't want to store it inside configuration) and .left() is for a temporary view (which can be saved).

Right now my configuration looks like this:

// main module
sealed class Screen : Parcelable {
    @Parcelize
    data class Notes(val filter: NotesFilterInfo) : Screen()
    ...
}

// shared module without access to parcelable
data class NotesFilterInfo(
    @Serializable(with = EitherSerializer::class)
    tempOrId: Either<NotesFilter, String>
) : java.io.Serializable

@Serializable
data class NotesFilter(val id: String, val tags: List<String>) : java.io.Serializable

And it fails when activity paused:

 java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = NotesFilterInfo)
        at android.os.Parcel.writeSerializable(Parcel.java:1833)
        at NotesFilterInfo.writeToParcel(Unknown Source:16)
        at android.os.Parcel.writeParcelable(Parcel.java:1801)
        at android.os.Parcel.writeValue(Parcel.java:1707)
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:928)
        at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1584)
        at android.os.Bundle.writeToParcel(Bundle.java:1253)
        at android.os.Parcel.writeBundle(Parcel.java:997)
        at com.arkivanov.essenty.parcelable.AndroidParcelableContainer.writeToParcel(AndroidParcelableContainer.kt:32)
        ...
     Caused by: java.io.NotSerializableException: arrow.core.Either$Right
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1240)
        at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1604)
        at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1565)
        at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1488)
E/AndroidRuntime:     at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1234)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:354)
        at android.os.Parcel.writeSerializable(Parcel.java:1828)
        	... 51 more

Don't sure how to solve this problem, so I have some sub-questions:

  1. Is it actully enough to implement Serializable to have Parcelable? (NotesFilterInfo is contained inside shared module without access to Parcelable)
  2. Is it possible to define custom router with serializable configuration? (my configurations isn't big and Parcelable implementation probably hasn't perfomance gain comparing to Serializable implementation)

Child is not created on forward press. Composable does not render.

This is the flow when website is launched.

  1. Starts on Homepage.
  2. Click on Button to show next screen. (router.push(Config.Splash) )
  3. user press back button (returns to homepage)
  4. user pressed forward button
  5. Blank white screen is seen. How to create child when forward is pressed?
private val router: Router<Config, Any> =
        router(
            initialStack = { getInitialStack(deepLink) },
            handleBackButton = true,
            childFactory = ::createChild
        )

private fun createChild(config: Config, componentContext: ComponentContext): Any =
        when (config) {
            is Config.Splash -> Nav.Child.Splash()
            is Config.HomePage -> Nav.Child.HomePage()
            else -> {}
        }

ios Counter Example fails to build

When trying to build the ios counter example, i am getting an error:

ContentView.swift:14:81: error: cannot convert value of type '() -> CounterRootComponent' to expected argument type '(ComponentContext) -> CounterRootComponent'
    private var componentHolder = ComponentHolder(factory: CounterRootComponent.init)

Screenshot 2022-04-11 at 09 32 22

I think i remember seeing something similar before and was to do with not including the decompose lib within the generate framework - maybe a red herring though

After making this repo a fork, search in the repository doesn't work

As mentioned in the readme, code search doesn't work in this fork because it is not indexed by GitHub.

There are two ways of fixing this:

  • Make this repository more stars than the upstream
  • Try to unfork the repository, probably by asking GitHub support

The community can definitely help with the first point. And I will try the second option once this repository diverge significantly enough.

Thanks for your understanding and all your support!

Stabilise Compose Animations API

Docs: link. Collecting feedback and use cases here.

Points to improve:

  • Get rid of Direction.IDLE using movableContentOf (blocked by Compose 1.2.0 release)
  • Make click interception configurable? Or replace with another solution? See b/214231672
  • Nullable StackAnimator in StackAnimation selector
  • Shared element transitions (perhaps LookaheadLayout + movableContentOf should work out of the box when they land in Compose)
  • Add otherChild argument to stackAnimation selector
  • Add minAlpha argument to fade animation

Stabilise Web Routing API

Docs: link. Collection feedback and use cases here.

Points to improve:

  • Consider moving WebHistoryController from commonMain to jsMain
  • Consider nested WebHistoryController

[Security] Workflow build.yml is using vulnerable action actions/checkout

The workflow build.yml is referencing action actions/checkout using references v1. However this reference is missing the commit a6747255bd19d7a757dbdda8c654a9f84db19839 which may contain fix to the some vulnerability.
The vulnerability fix that is missing by actions version could be related to:
(1) CVE fix
(2) upgrade of vulnerable dependency
(3) fix to secret leak and others.
Please consider to update the reference to the action.

Child gets recomposed more than once at startup in Compose Desktop

I have 2 problems at the moment.

  1. When you launch the app on Compose Desktop the initial configuration destination gets called more than once which causes the Children block to be called more than once causing multiple recompositions which can lead to a crash.

You can see here on the first screenshot that at the launch there are multiple calls to same thing (related to the Home Screen):
Screenshot 2022-03-23 090508

But after you navigate to something like a Settings Screen. You only see one call for each. Even when you pop back to the Home screen the home screen composable will be called only once this time:
Screenshot 2022-03-23 090709

I am using Decompose version: 0.5.2. Github link to the navigation and ui part of the app in question is this: https://github.com/Thinkrchive/Thinkrchive-Multiplatform/tree/main/desktopApp/src/jvmMain/kotlin/work/racka/thinkrchive/v2/desktop/ui

The navigation folder contains RootComponent and it's implementations.
The screen folder contains each screen composable with it component Interface and Implementation.

I followed the official guide for using compose-extensions.

  1. Navigating to my About screen fails.
    When I click the About button the event is not propagated from the comoposable to the component creation inside my NavHostComponent

What's weird is that every other call like for settingsScreen or donateScreen work as expected just the aboutScreen call that has issues.

Also using crossfade() or crossfadeScale() crashes the app or refuses any navigation calls.

Try to improve the "Check failed" error message

When there are multiple components registering in the StateKeeper under the same key, or multiple Routers in a component with the same key - there is a runtime error thrown saying java.lang.IllegalStateException: Check failed.. The error message is meaningless, let's try to improve the experience.

Describe delivering a result from one component to another in the docs

This question is being asked quite often - how to start component B from A, and then deliver a result from B to A. This should be described in the docs.

Long story short:

// RootComponent.kt

SecondComponent(
    onFinished = { result ->
        router.pop {
            (router.activeChild.instance as? First)?.onResult(result)
        }
    }
)

Add onComplete callback to Router.popWhile

We can pass data from one child to another e.g. when pushing / replacing / bringingToFront we can provide necessary data from configuration class or tell a child to execute a function, but to be consistent with pop(...) function, an onComplete: (isSuccess: Boolean) -> Unit callback may be added.
Passing data from a child to its indirect parent is a popular use case, there're many applications where we might need to skip some (or even all) configurations e.g. until the root element is shown.

Error when moving Compose Desktop app between screens

I get this crash when moving my Desktop app between my 1080p screen and my apple m1 laptop screen:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Check failed.
	at com.arkivanov.essenty.statekeeper.DefaultStateKeeperDispatcher.register(DefaultStateKeeperDispatcher.kt:42)
	at com.arkivanov.decompose.router.StackSaverImpl.register(StackSaverImpl.kt:19)
	at com.arkivanov.decompose.router.StackHolderImpl.<init>(StackHolderImpl.kt:30)
	at com.arkivanov.decompose.router.RouterFactoryExtKt.router(RouterFactoryExt.kt:33)
	at com.devit.checkin.device.RootDeviceComponentImpl.<init>(RootDeviceComponent.kt:78)
	at com.devit.checkin.device.RootDeviceComponentKt.RootDeviceComponent(RootDeviceComponent.kt:37)
	at com.devit.checkin.RootComponentImpl$resolveChild$2.invoke(RootComponent.kt:94)
	at com.devit.checkin.RootComponentImpl$resolveChild$2.invoke(RootComponent.kt:93)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at com.devit.checkin.ComposableSingletons$RootComposableKt$lambda-1$1.invoke(RootComposable.kt:18)
	at com.devit.checkin.ComposableSingletons$RootComposableKt$lambda-1$1.invoke(RootComposable.kt:17)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at com.arkivanov.decompose.extensions.compose.jetbrains.ChildrenKt$Children$1$1.invoke(Children.kt:28)
	at com.arkivanov.decompose.extensions.compose.jetbrains.ChildrenKt$Children$1$1.invoke(Children.kt:27)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
	at androidx.compose.runtime.saveable.SaveableStateHolderImpl.SaveableStateProvider(SaveableStateHolder.kt:84)
	at com.arkivanov.decompose.extensions.compose.jetbrains.ChildrenKt$Children$1.invoke(Children.kt:27)
	at com.arkivanov.decompose.extensions.compose.jetbrains.ChildrenKt$Children$1.invoke(Children.kt:26)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at com.arkivanov.decompose.extensions.compose.jetbrains.animation.page.PageAnimationKt$PageAnimationFrame$1$1$1.invoke(PageAnimation.kt:143)
	at com.arkivanov.decompose.extensions.compose.jetbrains.animation.page.PageAnimationKt$PageAnimationFrame$1$1$1.invoke(PageAnimation.kt:141)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at com.arkivanov.decompose.extensions.compose.jetbrains.animation.child.ComposableSingletons$SlideKt$lambda-1$1.invoke(Slide.kt:18)
	at com.arkivanov.decompose.extensions.compose.jetbrains.animation.child.ComposableSingletons$SlideKt$lambda-1$1.invoke(Slide.kt:17)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:252)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at com.arkivanov.decompose.extensions.compose.jetbrains.animation.page.PageAnimationKt$PageAnimationFrame$1.invoke(PageAnimation.kt:141)
	at com.arkivanov.decompose.extensions.compose.jetbrains.animation.page.PageAnimationKt$PageAnimationFrame$1.invoke(PageAnimation.kt:132)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1.invoke(BoxWithConstraints.kt:66)
	at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1$measurables$1.invoke(BoxWithConstraints.kt:66)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2$1$1.invoke(SubcomposeLayout.kt:251)
	at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2$1$1.invoke(SubcomposeLayout.kt:251)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.runtime.ActualJvm_jvmKt.invokeComposable(ActualJvm.jvm.kt:72)
	at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2582)
	at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2571)
	at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:247)
	at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source)
	at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2571)
	at androidx.compose.runtime.ComposerImpl.composeContent$runtime(Composer.kt:2522)
	at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:478)
	at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:748)
	at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime(Composer.kt:2987)
	at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:433)
	at androidx.compose.ui.layout.SubcomposeLayoutState.subcomposeInto(SubcomposeLayout.kt:269)
	at androidx.compose.ui.layout.SubcomposeLayoutState.access$subcomposeInto(SubcomposeLayout.kt:154)
	at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2.invoke(SubcomposeLayout.kt:244)
	at androidx.compose.ui.layout.SubcomposeLayoutState$subcompose$2.invoke(SubcomposeLayout.kt:241)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.withNoObservations(SnapshotStateObserver.kt:142)
	at androidx.compose.ui.node.OwnerSnapshotObserver.withNoSnapshotReadObservation$ui(OwnerSnapshotObserver.kt:55)
	at androidx.compose.ui.node.LayoutNode.withNoSnapshotReadObservation$ui(LayoutNode.kt:1140)
	at androidx.compose.ui.layout.SubcomposeLayoutState.subcompose(SubcomposeLayout.kt:241)
	at androidx.compose.ui.layout.SubcomposeLayoutState.subcompose(SubcomposeLayout.kt:235)
	at androidx.compose.ui.layout.SubcomposeLayoutState.subcompose$ui(SubcomposeLayout.kt:224)
	at androidx.compose.ui.layout.SubcomposeLayoutState$Scope.subcompose(SubcomposeLayout.kt:490)
	at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1.invoke-0kLqBqw(BoxWithConstraints.kt:66)
	at androidx.compose.foundation.layout.BoxWithConstraintsKt$BoxWithConstraints$1$1.invoke(BoxWithConstraints.kt:64)
	at androidx.compose.ui.layout.SubcomposeLayoutState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:355)
	at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:55)
	at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$2.invoke(OuterMeasurablePlaceable.kt:99)
	at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$2.invoke(OuterMeasurablePlaceable.kt:98)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:126)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:88)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:76)
	at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:98)
	at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75)
	at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1260)
	at androidx.compose.foundation.layout.BoxKt$boxMeasurePolicy$1.measure-3p2s80s(Box.kt:115)
	at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:55)
	at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$2.invoke(OuterMeasurablePlaceable.kt:99)
	at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$2.invoke(OuterMeasurablePlaceable.kt:98)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:126)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:88)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:76)
	at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:98)
	at androidx.compose.ui.node.OuterMeasurablePlaceable.measure-BRTryo0(OuterMeasurablePlaceable.kt:75)
	at androidx.compose.ui.node.LayoutNode.measure-BRTryo0(LayoutNode.kt:1260)
	at androidx.compose.ui.layout.RootMeasurePolicy.measure-3p2s80s(RootMeasurePolicy.kt:38)
	at androidx.compose.ui.node.InnerPlaceable.measure-BRTryo0(InnerPlaceable.kt:55)
	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:118)
	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:118)
	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:118)
	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:118)
	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:118)
	at androidx.compose.ui.node.DelegatingLayoutNodeWrapper.measure-BRTryo0(DelegatingLayoutNodeWrapper.kt:118)
	at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$2.invoke(OuterMeasurablePlaceable.kt:99)
	at androidx.compose.ui.node.OuterMeasurablePlaceable$remeasure$2.invoke(OuterMeasurablePlaceable.kt:98)
	at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:1798)
	at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:121)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui(OwnerSnapshotObserver.kt:88)
	at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui(OwnerSnapshotObserver.kt:76)
	at androidx.compose.ui.node.OuterMeasurablePlaceable.remeasure-BRTryo0(OuterMeasurablePlaceable.kt:98)
	at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui(LayoutNode.kt:1269)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure(MeasureAndLayoutDelegate.kt:168)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:228)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.access$remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:38)
	at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:201)
	at androidx.compose.ui.platform.SkiaBasedOwner.measureAndLayout(SkiaBasedOwner.skiko.kt:266)
	at androidx.compose.ui.node.Owner$DefaultImpls.measureAndLayout$default(Owner.kt:182)
	at androidx.compose.ui.platform.SkiaBasedOwner.render(SkiaBasedOwner.skiko.kt:234)
	at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:354)
	at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:224)
	at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:222)
	at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:89)
	at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:70)
	at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:222)
	at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.jvm.kt:433)
	at org.jetbrains.skiko.redrawer.MetalRedrawer.update(MetalRedrawer.kt:65)
	at org.jetbrains.skiko.redrawer.MetalRedrawer.redrawImmediately(MetalRedrawer.kt:59)
	at org.jetbrains.skiko.SkiaLayer.paint(SkiaLayer.jvm.kt:324)
	at androidx.compose.ui.awt.ComposeLayer$ComponentImpl.paint(ComposeLayer.desktop.kt:144)
	at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
	at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
	at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
	at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1128)
	at java.desktop/javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
	at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:952)
	at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5318)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(RepaintManager.java:1657)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1632)
	at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1570)
	at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1337)
	at java.desktop/javax.swing.JComponent.paint(JComponent.java:1105)
	at java.desktop/java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
	at java.desktop/sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:75)
	at java.desktop/sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:112)
	at java.desktop/java.awt.Container.paint(Container.java:2005)
	at java.desktop/java.awt.Window.paint(Window.java:3959)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:890)
	at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:862)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:862)
	at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:835)
	at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:784)
	at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1898)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Compose Runtime internal error. Unexpected or incorrect use of the Compose internal runtime API (Expected applyChanges() to have been called). Please report to Google or use https://goo.gle/compose-feedback
	at androidx.compose.runtime.ComposerKt.composeRuntimeError(Composer.kt:3456)
	at androidx.compose.runtime.ComposerImpl.recompose$runtime(Composer.kt:3504)
	at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:620)
	at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:786)
	at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:105)
	at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:456)
	at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:425)
	at androidx.compose.runtime.BroadcastFrameClock$FrameAwaiter.resume(BroadcastFrameClock.kt:42)
	at androidx.compose.runtime.BroadcastFrameClock.sendFrame(BroadcastFrameClock.kt:71)
	at androidx.compose.ui.ComposeScene.render(ComposeScene.skiko.kt:351)
	at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:224)
	at androidx.compose.ui.awt.ComposeLayer$1$onRender$1.invoke(ComposeLayer.desktop.kt:222)
	at androidx.compose.ui.awt.ComposeLayer.catchExceptions(ComposeLayer.desktop.kt:89)
	at androidx.compose.ui.awt.ComposeLayer.access$catchExceptions(ComposeLayer.desktop.kt:70)
	at androidx.compose.ui.awt.ComposeLayer$1.onRender(ComposeLayer.desktop.kt:222)
	at org.jetbrains.skiko.SkiaLayer.update$skiko(SkiaLayer.jvm.kt:433)
	at org.jetbrains.skiko.redrawer.MetalRedrawer.update(MetalRedrawer.kt:65)
	at org.jetbrains.skiko.redrawer.MetalRedrawer.access$update(MetalRedrawer.kt:14)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invokeSuspend(MetalRedrawer.kt:39)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.redrawer.MetalRedrawer$frameDispatcher$1.invoke(MetalRedrawer.kt)
	at org.jetbrains.skiko.FrameDispatcher$job$1.invokeSuspend(FrameDispatcher.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117)
	at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:191)
	at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:236)
	at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:234)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:318)
	at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:234)
	at java.desktop/java.awt.Dialog.show(Dialog.java:1080)
	at java.desktop/javax.swing.JOptionPane.showOptionDialog(JOptionPane.java:880)
	at java.desktop/javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:676)
	at java.desktop/javax.swing.JOptionPane.showMessageDialog(JOptionPane.java:647)
	at androidx.compose.ui.window.DefaultWindowExceptionHandlerFactory$exceptionHandler$1$onException$1.run(WindowExceptionHandlerFactory.desktop.kt:18)
	at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:318)
	at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:771)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:722)
	at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:716)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
	at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
	at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:741)
	at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
	at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
	at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
	at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)

Compose for iOS, macOS and Web

Latest builds of JetBrains Compose support native iOS and macOS targets. Let's try to add it to extensions-compose-jetbrains module. Since it's far from stable, a separate branch seems reasonable.

Status update: experimental -native-compose versions of Decompose with Compose for Darwin (Apple/iOS) are published from the compose-experimental branch, and have <version>-compose-experimental version suffix.

Usage of drawin compose

Hi, can you help me?

I tried to run ./gradlew iosDeployIPhone12Debug

but it threw the following error

Field 'dataPathSize' is required for type with serial name 'org.jetbrains.compose.experimental.uikit.internal.DeviceData', but it was missing

Coroutines Interop

I was wondering why you use your own State implementation instead of using MutableStateFlow. Is there any benefit in using your State implementation, as it looks like it's just an observer pattern? As I really like to use flows, I was also asking myself if there is something similar to the Android viewModelScope, a componentScope maybe, that is cancelled when the component is killed.

v1.0.0 roadmap

Required tasks:

  • Stabilize Compose Animations API (see #110)
  • Improve the "Check failed" error message (see #77)
  • Comply with the new predictive back gesture in Android 13 (see #156)
  • Move Router to stack sub-package and rename it to StackRouter (see #134)
  • Remove all deprecated code
  • Add extensions for Value (see #200)
  • Change naming in samples from Some + SomeComponent to SomeComponent + DefaultSomeComponent
  • Update all Android dependencies (#303)

Desired tasks:

  • Stabilize Web Routing API (see #111)
  • Stabilize extensions-android module
  • Support Compose for iOS and macOS (see #74)
  • Allow safe Router access from childFactory function
  • Remove extensions-compose-jetpack module (see #11)
  • Add child overlay navigation

multiple calls to defaultComponentContext() lead to a crash -> IllegalArgumentException

Calling defaultComponentContext() more than once from the same Activity or from two fragments tied to the same Activity will crash with an IllegalArgumentException:

java.lang.IllegalArgumentException: SavedStateProvider with the given key is already registered
AndroidRuntime:        at androidx.savedstate.SavedStateRegistry.registerSavedStateProvider(SavedStateRegistry.java:111)

The culprit is the registerSavedStateProvider call:

savedStateRegistry.registerSavedStateProvider(KEY_STATE) {
    Bundle().apply {
        if (isSavingAllowed()) {
            putParcelable(KEY_STATE, dispatcher.save())
        }
   }
}

This should be caught and ignored (the SavedStateRegistry.SavedStateProvider is already registered).
The use case for this is e.g. when using two components in an Activity or using the same component in two fragments (e.g. master/detail view).

[Security] Workflow publish.yml is using vulnerable action actions/checkout

The workflow publish.yml is referencing action actions/checkout using references v1. However this reference is missing the commit a6747255bd19d7a757dbdda8c654a9f84db19839 which may contain fix to the some vulnerability.
The vulnerability fix that is missing by actions version could be related to:
(1) CVE fix
(2) upgrade of vulnerable dependency
(3) fix to secret leak and others.
Please consider to update the reference to the action.

How to specify the order of back press handlers?

I want to specify the order of handlers like follows:

  1. close drawer (if open)
  2. close search (if expanded)
  3. handle backpress by component (if can)
  4. router.pop
  5. handle double-press (first press for toast "press twice to exit", second quick press for exit)

I can implement all these handlers, but I don't understand, how to tangle them together in correct order.

Is there some API to do it? As I see, the order isn't specified, moreover, router calls pop after other handlers.

Sub question: is it possible to access router.backstackSize from outside? Probably it can help me.

Web Browser routing support

Copying from #271

Raising an issue as per the conversation over at MVIKotlin Slack channel

As discussed, what do others think about having the support for routing in web browsers (eg having paths in the URL, yourwebsite/users/profile and etc...).

There are two main options for the URL paths:

  1. Hashed paths
    eg. example.com/#users/profile

Consider one page website, or website built fully on AJAX, without any page reloads.

#hash helps such applications to push state of the application to the client, this helps the application itself to be aware of the state and the client (and browser) to be aware of the state. This will also help the user to bookmark the application in its' current state and use back and forward buttons (browser history).

Which basically is Client Side way of telling where we are, it's easy to implement but a bit uncommon and not what the people are used to. As it doesn't require page refreshes

  1. Normal paths
    eg. example.com/users/profile

More common, the paths we are accustomed to seeing. A bit more difficult to implement.

Issues that are currently present while developing for web that can be solved with this:

  1. Refreshing the page returns you to the root and not just the "page" you were on
  2. Nicer looking URL's, since currently all pages live in the /
  3. Support for History (going backward and forwards in the browser). Most notably on Desktop, you are sometimes stuck between Parent and a Child on Desktop as there is no back option unless you manually add a button.

Implementation

As for the concrete implementation, I am not sure. But here are some of my notes

  1. Changing the path should change the configuration, alongside pushing a new configuration should update the path. So the entity responsible for the path should be aware of the possible configurations
  2. How would it integrate with the current way navigation is handled (talking about the implementation), of pushing configuration onto a router that is being observed in your UI solution (Compose, React...). As the navigation is currently platform-independent.
  3. Can it be made in a way that doesn't affect the existing code for other platforms? Maybe even keep the existing code for the web alongside some additional setup at the beginning to map all of the routes.
  4. Parameters, dynamic URLs. Currently, with configurations, you can pass pretty much anything to the children, but for the URL's this wouldn't be the case. So if we push a complex configuration via the existing code that may not be possible to map to a path with parameters. This would mean that a possible limitation could be to not allow manually altering the path from point 1. Considering that this works in other solutions like NextJs and React with Navigation libraries, this shouldn't be an issue.

Please correct me if I am wrong on anything, and do add some more input.

This is primarily based on similar solutions existing for Compose on Web

Handle navigation with Jetpack Compose Modal Bottom Sheets correctly

I'm receiving a crash when trying to display a modal bottom sheet after it was dismissed (in other words - after first time) when having bottom sheet state (maybe static as well) management delegated to a Component (in Decompose terms). Maybe that's related to Jetpack Compose itself, not really sure.
Crash statement: java.lang.IllegalArgumentException: The target value must have an associated anchor.

By the way, there's no hide/dismiss animation and some sort of half-transparent overlay is also visible. Currently, Jetpack Compose notifies component's router to replace the configuration (bottom sheet parent) in confirmStateChange, so that we could replace with configuration that represents bottom sheet in this case. We do however observe the router state in LaunchedEffect then show and hide the bottom sheet looking at the type of current child. Maybe the observations need to be implemented in some different way, so that it works, no idea.

Sample project: https://github.com/moffpage/DecomposeBottomSheetCrash

Kotlin version: 1.6.20
Jetpack Compose version: 1.2.0-alpha08

I think I can sort of "fix" this by creating the component which is displayed via bottom sheet just in time, not lazily, having it as a permanent child via childContext(key = "..."), that was the thing I wanted to avoid but if there isn't any fix that comes to mind, I might do so for now, just so everything works.

Move Router to `stack` sub-package and rename it to StackRouter

Router organizes children as a stack - there is always one resumed child on top of the stack, children in the back stack are either stopped or destroyed. In the future, there could be other kinds of routers, e.g. a router that organizes children as a list (all children are active, no back stack).

To allow the room for additional routers, it is necessary to move Router and all its surroundings to stack sub-package. And also rename it to StackRouter - to make it clear that it acts as a stack. It also makes sense to rename RouterState to ChildStack.

This change should be done via deprecation cycle.

Reasons to bound Value for non-null values only?

I want to ask for a reason to define Value as Value<T : Any>, not just Value<T>.

Is it intended? In my project i need to use Value for nullable types as well, and I don't see any practical reasons to define Value as Value<T : Any>.

Currently I forced to use it with custom wrapper (like Optional in java), but actually i don't need it if it will be just Value<T>.

Swiftui push pop navigation example

The decompose examples are great but they don't demonstrate a typical navigation stack of pushing and popping.

The counter and master detail examples show a 'replace' navigation but doesn't show a push transition - this is probably the most common navigation pattern used within ios/swiftui

Maybe you could take inspiration of this:
https://quickbirdstudios.com/blog/coordinator-pattern-in-swiftui/

Also would be cool to see an example using deeplink navigation, where a user can click an item in the list and this fires off a deeplink to push a view in the navigation.

Incomplete documentation on Compose-JB usage

When using Decompose with Compose-JB for desktop, it is necessary to use the LifecycleController composable, otherwise the LifecycleRegistry will not work properly. However, this is not mentioned in the documentation at all (even if the samples do include it in the code). I believe this fact should be clarified in the documentation.
(If none of this is actually necessary and I'm simply missing something obvious, please let me know.)

Gradle fails in Idea Community desktop compose template

Tried on macbook m1
Idea Community version
jdk: azul-16.0.2

Create a default desktop compose template project

Steps:

  • Add
implementation("com.arkivanov.decompose:decompose:0.6.0")
implementation("com.arkivanov.decompose:extensions-compose-jetbrains:0.6.0")

to gradle dependencies

  • try to run gradle run task

Result:
Gradle failed to run

Caused by: org.gradle.process.internal.ExecException: Process 'command '...Library/Java/JavaVirtualMachines/azul-16.0.2/Contents/Home/bin/java'' finished with non-zero exit value 1
	at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:414)
	at org.gradle.process.internal.DefaultJavaExecAction.execute(DefaultJavaExecAction.java:52)
	at org.gradle.api.tasks.JavaExec.exec(JavaExec.java:156)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:104)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
	at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$2.run(ExecuteActionsTaskExecuter.java:506)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:56)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$run$1(DefaultBuildOperationExecutor.java:74)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.runWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:45)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:74)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:491)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:474)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.access$300(ExecuteActionsTaskExecuter.java:106)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.executeWithPreviousOutputFiles(ExecuteActionsTaskExecuter.java:271)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution.execute(ExecuteActionsTaskExecuter.java:249)
	at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:83)
	at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:37)
	at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
	at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:47)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:47)
	at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:37)
	at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
	at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:50)
	at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
	at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
	at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
	at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
	at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
	at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
	at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:54)
	at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:35)
	at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:60)
	at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:27)
	at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:174)
	at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:74)
	at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:45)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:40)
	at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:29)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
	at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:99)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$0(SkipUpToDateStep.java:92)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:52)
	at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:36)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:85)
	at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:42)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:91)
	at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:49)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:106)
	at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:51)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:72)
	at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:46)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.lambda$execute$2(SkipEmptyWorkStep.java:86)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:86)
	at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:32)
	at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:43)
	at org.gradle.internal.execution.steps.LoadExecutionStateStep.execute(LoadExecutionStateStep.java:31)
	at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter$TaskExecution$2.withWorkspace(ExecuteActionsTaskExecuter.java:284)
	at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
	at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
	at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
	at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
	at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
	at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
	at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:185)
	at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:174)
	at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:109)
	at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
	at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
	at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
	at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:56)
	at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:200)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:195)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:75)
	at org.gradle.internal.operations.DefaultBuildOperationRunner$3.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:153)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:68)
	at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:62)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$call$2(DefaultBuildOperationExecutor.java:79)
	at org.gradle.internal.operations.UnmanagedBuildOperationWrapper.callWithUnmanagedSupport(UnmanagedBuildOperationWrapper.java:54)
	at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:79)
	at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
	at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:74)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:408)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:395)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:388)
	at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:374)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.lambda$run$0(DefaultPlanExecutor.java:127)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:191)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.executeNextNode(DefaultPlanExecutor.java:182)
	at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:124)
	at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
	at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
	at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)

Update Kotlin to 1.6.x

Things to consider:

  • Version 1.6.0 has some bugs (e.g. KT-49798), perhaps better to skip this version.
  • There is no stable version of Jetpack and JetBrains Compose version compatible with Kotlin 1.6.10 as of now.
  • Mind #3

Can't start app only with Navigation <= No interface method startRestartGroup on ChildrenKt.Children(Children.kt:22)

I followed this tutorial.
Of course, I checked this on medium.com

I almost only copied codes from the tutorial and changed the package name.

When starting desktop on InteliiJ IDEA:

Exception in thread "main" java.lang.NoSuchMethodError: androidx.compose.runtime.Composer.startRestartGroup(ILjava/lang/String;)Landroidx/compose/runtime/Composer;
	at com.arkivanov.decompose.extensions.compose.jetbrains.ChildrenKt.Children(Children.kt:22)
	at net.liplum.common.ScreenKt.Root(Screen.kt:90)
	at net.liplum.common.ComposableSingletons$AppKt$lambda-1$1.invoke(App.kt:10)
	at net.liplum.common.ComposableSingletons$AppKt$lambda-1$1.invoke(App.kt:9)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
	at androidx.compose.material.MaterialTheme_desktopKt.PlatformMaterialTheme(MaterialTheme.desktop.kt:26)
	at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:82)
	at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:81)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
	at androidx.compose.material.TextKt.ProvideTextStyle(Text.kt:265)
	at androidx.compose.material.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:81)
	at androidx.compose.material.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:80)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
	at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
	at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
	at androidx.compose.material.MaterialThemeKt.MaterialTheme(MaterialTheme.kt:72)
	at net.liplum.common.AppKt.App(App.kt:9)
	at net.liplum.desktop.ComposableSingletons$MainKt$lambda-1$1.invoke(Main.kt:8)
	at net.liplum.desktop.ComposableSingletons$MainKt$lambda-1$1.invoke(Main.kt:7)

When starting android on Android Studio.

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.myapplication, PID: 24932
    java.lang.NoSuchMethodError: No interface method startRestartGroup(ILjava/lang/String;)Landroidx/compose/runtime/Composer; in class Landroidx/compose/runtime/Composer; or its super classes (declaration of 'androidx.compose.runtime.Composer' appears in /data/app/~~cveqtxczmcjgqqWLQeHzrA==/com.myapplication-ztE8pb2vmNxy0BTJ1BWwxg==/base.apk)
        at com.arkivanov.decompose.extensions.compose.jetbrains.ChildrenKt.Children(Children.kt:22)
        at net.liplum.common.ScreenKt.Root(Screen.kt:90)
        at net.liplum.common.ComposableSingletons$AppKt$lambda-1$1.invoke(App.kt:10)
        at net.liplum.common.ComposableSingletons$AppKt$lambda-1$1.invoke(App.kt:9)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.material.MaterialTheme_androidKt.PlatformMaterialTheme(MaterialTheme.android.kt:23)
        at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:82)
        at androidx.compose.material.MaterialThemeKt$MaterialTheme$1$1.invoke(MaterialTheme.kt:81)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.material.TextKt.ProvideTextStyle(Text.kt:265)
        at androidx.compose.material.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:81)
        at androidx.compose.material.MaterialThemeKt$MaterialTheme$1.invoke(MaterialTheme.kt:80)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
        at androidx.compose.material.MaterialThemeKt.MaterialTheme(MaterialTheme.kt:72)
        at net.liplum.common.AppKt.App(App.kt:9)
        at net.liplum.android.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:13)
        at net.liplum.android.ComposableSingletons$MainActivityKt$lambda-1$1.invoke(MainActivity.kt:12)

[3.0.0] Remove extensions-compose-jetpack module

Since one of the recent releases of JetBrains (MPP) Compose, a library that depends on JetBrains Compose can be used in an Android project that depends on Jetpack Compose. This makes the extensions-compose-jetpack module useless, the extensions-compose-jetbrains module can be used instead. Further, extensions-compose-jetbrains module can be renamed to just extensions-compose.

This task should be done only after JetBrains Compose versions are aligned with Jetpack Compose. Currently stable versions of JetBrains Compose are based on Jetpack Compose 1.1.0 alpha/beta versions.

Navigation does not work on chrome ios

Only occurs on chrome for mobile ios devices. After debugging, it appears the issue is that routerState.activeChild.instance does not update after child is created.

//This code does not get executed.

Crossfade(
            target = routerState.activeChild.instance, 
            attrs = {
                style {
                    width(100.percent)
                    height(100.percent)
                    position(Position.Relative)
                    left(0.px)
                    top(0.px)
                }
            }
        ) { child ->
            when (child) {
                is Nav.Child.Splash -> Splash(component)
                is Nav.Child.Inbox -> ChatUI(component)
                is Nav.Child.Home -> Home(component)
                is Nav.Child.HomePage -> HomePage(component)
        }
    }
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.