Sergej Shafarenka
07/23/2024, 3:19 PMcommonMain/kotlin
in a Compose Multiplatform project? Neither IntelliJ nor AS seems to open a preview for them. Fleet requires desktop
target and is extremely slow and limited in configuration options, so it's kind of painful and cannot compete with native AS dev experience. How do you do that?Wout Werkman
07/23/2024, 3:40 PMSergej Shafarenka
07/23/2024, 3:51 PMCould you share for which reason you need a Desktop target when you try to preview in Fleet? Previews in Fleet without Desktop target are supposed to work as long as you don't call expects (we will have stubbed them) and all your dependencies support JVM.Initially I only had Android and iOS targets in
build.gradle.kts
file and Compose (Android) + Swift UI. The app could be built and worked for both platforms. Then I moved Compose UI to commomMain/kotlin
and tried to preview some composable views. Preview pane failed with an error saying something like "some actual implementations are missing". It turned out that because of some reasons, preview pane expected "missing" actuals for desktop
platform. After I added jvm()
to build.gradle.kts
and provided dummy actual
implementations for it, preview started working. Fleet 1.37.84, Kotlin 2.0.0, AGP: 8.3.2, Compose plugin: 1.7.0-alpha01Sergej Shafarenka
07/23/2024, 4:11 PMWhen it comes to performance, thanks for sharing your concern, please vote to keep track of our progress here.
Also, we have Android preview support coming up under a feature flag, in some near future could opt in for more AS like preview performance.Thanks for sharing the info, Wout! Voted for both issues and eager to have my hands on the update. For now, I'm juggling between Fleet and AS and copying views from one to another to be able to code views faster with a property preview.
Wout Werkman
07/23/2024, 4:20 PMSergej Shafarenka
07/23/2024, 4:53 PMjvm()
platform, it builds and runs on Android. When opening a preview, "Compose preview" pane looks as in the screenshot.
Compose Preview log:
> Configure project :
>>>>>> Version: 5.743-jetpack-compose <<<<<<
Configuration '__COMPOSE_PREVIEW__RuntimeClasspath' was resolved during configuration time.
This is a build performance and scalability issue.
See <https://github.com/gradle/gradle/issues/2298>
Run with --info for a stacktrace.
Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.
You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.
For more on this, please refer to <https://docs.gradle.org/8.8/userguide/command_line_interface.html#sec:command_line_warnings> in the Gradle documentation.
BUILD SUCCESSFUL in 802ms
11 actionable tasks: 1 executed, 10 up-to-date
PREVIEW_HOST:SENT COMMAND 'ATTACH 2
PREVIEW_HOST:GOT COMMAND 'PREVIEW_CLASSPATH
PREVIEW_HOST:GOT [9961
PREVIEW_HOST:GOT COMMAND 'FRAME_REQUEST de.halfbit.gamineforagents.widgets.EmptyListWidgetKt.PreviewEmptyListWidget 21 478 986 4611686018427387904
PREVIEW_HOST:RENDERING 'de.halfbit.gamineforagents.widgets.EmptyListWidgetKt.PreviewEmptyListWidget' 956x1972@2.
PreviewLogger: Failed to invoke Composable Method 'de.halfbit.gamineforagents.widgets.EmptyListWidgetKt.PreviewEmptyListWidget'
nul
PREVIEW_HOST:SENT COMMAND 'ERROR
PREVIEW_HOST:SENT DATA [6067
Sergej Shafarenka
07/23/2024, 4:55 PMSergej Shafarenka
07/23/2024, 4:58 PM@Composable expect fun StatusBarTheme(darkTheme: Boolean)
expect fun createHttpClient(baseUrl: String): HttpClient
(ktor)
expect fun generateUuidV4(): Uuid
(Uuid - type in the project)
expect fun regexDotMatchAll(regex: String): Regex
(kotlin.text)
@Composable
expect fun ScannerWidget(
modifier: Modifier = Modifier,
surfaceColor: Color,
onTextScanned: (String) -> Unit,
)
Wout Werkman
07/23/2024, 5:04 PMzt
07/23/2024, 6:35 PMSergej Shafarenka
07/23/2024, 7:38 PMStatusBarTheme
is used in every preview and causes the issue. I commented the function out and not calling it. Now I'm getting another error (see the screenshot and attached file). I also added a simple snipped as below and it causes the same exception. Mayme it can say something to you.
@Preview
@Composable
fun PreviewText() {
Text("Hello there!")
}
‼️ UPDATE: After calling ./gradlew clean
and reopening the project in Fleet, it started to show previews. Please ignore the error.Sergej Shafarenka
07/23/2024, 7:42 PMSergej Shafarenka
07/23/2024, 7:53 PMcontent: @Composable () -> Unit
as the last parameter. Then the stub for this function could simply call the content().
2. A composable function has no content
parameter - such function can be just skipped.
3. For any other composable function (with many content
- like parameters) , the stubs will throw.
For 1. and 2. the Preview Pane can show a warning saying that some functions are not implemented and will do nothing. Then devs will be informed and know why something maybe is not working.
This behavoir of stubs could be an option, in addition to always throwing stubs. Just an idea.Sergej Shafarenka
07/23/2024, 9:12 PMexpect
functions in code.Wout Werkman
07/24/2024, 9:35 AMIs there a way of knowing if a composable runs inside a tool or as a real app? I thought I could use such a check to avoid callingYou could catch the exception that is thrown in the generate actual stub 😅 It throwsfunctions in code.expect
kotlin.NotImplementedError("__COMPOSE__PREVIEW__This_preview_uses_expects__COMPOSE__PREVIEW__")
You didn't ask for a pretty solution right? ;)Wout Werkman
07/24/2024, 9:43 AMUnit
or null
for nullables, empty string, list, 0
etc. But any such stubs might really confuse users. For all we know a user thinks that their code is wrong because the preview shows something weird, and after hours of debugging they realize that it's because I stubbed some default value.
But actually, for `@Composable`s, this is a really interesting idea! We could make it a lot more clear to users. We could show purple-black 404 texture with a some text informing about the situation for example... I'll make sure it get's discussed! (Just calling content()
seems a bit dangerous again, since we might get to the same situation I explained before :/ )Sergej Shafarenka
07/24/2024, 2:13 PMYou didn't ask for a pretty solution right? 😉That would work in my case. Having a separate function would be nice to have in the future 🙂
Sergej Shafarenka
07/24/2024, 2:15 PMSergej Shafarenka
07/24/2024, 2:16 PM