<@U019WDTQTS6> This is a weak area at the moment, ...
# compose-desktop
d
@xxfast This is a weak area at the moment, the limitations had me frustrated for some time. Here's what you need to do: • First, make sure you are only defining
@Preview
s from your top-level Application modules, for either Android or Desktop. You can try to do it from library projects or submodules, and some stuff might work if you import extra dependencies; but it's unsupported and gets ugly (ref: this thread). • Secondly; import the
compose.preview
and
compose.uitooling
dependencies for Android and Desktop as you would expect to; but for the Android top-level project you must apply a Gradle Dependency Substitution to 'deeply' replace all the JetBrains preview dependencies with the Google ones, for it to work with Android Studio properly. By 'deeply', I mean the replacement will affect all transitive dependencies as well. Just directly depending on the Google one won't work; you'll get duplicate class errors. I will fetch you a code snippet for the dependency substitution...
👍 2
1
x
do you mean
compose.preview
?
👌 1
d
Where:
Versions.Compose.JetBrainsMultiplatform
= e.g.
1.0.0-alpha4-build331
Versions.Compose.GoogleAndroid
=
1.0.1
☝️ Put that block in the top-level of your Android App module's
build.gradle.kts
to workaround the 'broken' JetBrains Artifact and resolve the Google one instead.
x
I see - thanks @darkmoon_uk 🙌 will give that a go
d
The limitation that you can only put
@Preview
in the top-level module is painful in the common-case that you want to build a component library in it's own module... you would want the `@Preview`s to live alongside the components, but this is not directly possible right now 👎 As a compromise; I still define
@Composable
functions intended as previews in the component library module, just without their
@Preview
annotation, then expose them with the
@Preview
from the top level module e.g: Component Library Module (the preview implementation)
Copy code
@Composable
fun MyButton_Preview() {
    MyButton(...)
}
Top-level Application Module (just proxy the preview, adding annotation)
Copy code
@Preview
@Composable
fun MyButton() = MyButton_Preview()
You can change the naming to suit but this gives one idea how to work around the limit.
x
yeah - i have a
:login
feature module that targets ios, jvm, android, js while
:login:ui
is a sub-module that only targets jvm and android. I wish i can just define my composable previews in the
commonMain
of
:login:ui
and keep the components and their previews together
d
You can play around with split panes in the IDE to make the code and preview visible at the same time... the Code / Split / Design won't be useful now because of the need to keep the Preview in a different module.
I really hope JetBrains and Google can improve Compose/MP in this area soon. This is fundamental workflow stuff and impacts usability a lot.
How did you go @xxfast? I've edited some of the guidance above to be a little clearer, in case it helps.
x
didn’t seem to work on my first try - i placed these in a feature submodule
:login:ui
Copy code
kotlin {
  android {
    compilations.all {
      kotlinOptions {
        jvmTarget = "1.8"
      }
    }

    // Part of workaround to transitively enforce Google Preview/Tooling while JetBrains' is broken
    configurations.all {
      resolutionStrategy {
        dependencySubstitution {
          substitute(module("org.jetbrains.compose.ui:ui-tooling-preview:${Jetbrains.Versions.composeMultiplatform}"))
            .using(module("androidx.compose.ui:ui-tooling:${AndroidX.Versions.compose}"))
          substitute(module("org.jetbrains.compose.ui:ui-tooling-preview:${Jetbrains.Versions.composeMultiplatform}"))
            .using(module("androidx.compose.ui:ui-tooling-preview:${AndroidX.Versions.compose}"))
        }
      }
    }
  }
  ..
}
where
Copy code
object AndroidX {
  object Versions {
    ...
    const val compose = "1.0.0"
  }
}

object Jetbrains {
  object Versions {
    const val composeMultiplatform = "1.0.0-alpha3"
    const val kotlin = "1.5.21"
    ..
  }
}
i should note that compose Multiplatform plugin i’ve installed is
1.0.0-alpha4-build331
- perhaps the plugin version should also match version of the dependency
👌 1
d
As mentioned, the dependency substitution should go in your Application (Top-Level) module, not in a sub-module.
You also cannot use the
@Preview
annotation from your feature submodule.
x
ah i see
nice - got the preview window to show up 🙌
d
👌 It's there, but that grey-boxed
ComposeViewAdapter
message is actually the error state expected when the dependency substitution isn't applied.
Assuming your top-level Android Application project is a standard Android Application Module, then place the given substitution block of code, at the top-level of its
build.gradle.kts
... not inside
kotlin {...}
or
android {...}
etc.
x
ah my bad - let me give that a try
woohoo 🦜
thanks for helping out @darkmoon_uk 🙌
hopefully JB/Google will work on getting the tooling support over to
commonMain
source sets where these composable are defined
Is there a ticket/issue raised regarding this on compose-jb?
☝️ 1
c
@Igor Demin is this something every project should be doing? Re: deep dependency substitution
i
@Igor Demin is this something every project should be doing? Re: deep dependency substitution
Only as a workaround. Either Android Studio doesn't work with the artifacts published by maven coordinates other than
androidx.compose.ui:ui-tooling-preview
Or our
org.jetbrains.compose.ui:ui-tooling-preview-android
is broken. We currently investigate a possibility of not publishing our own android artifacts and reusing the already published
androidx.compose
artifacts. After that this issue will no longer be relevant.
Is there a ticket/issue raised regarding this on compose-jb?
I haven't found any
👍 2
d