ci: desktop snapshots render animations at their end (#7916)

* ci: desktop snapshots render animations at their end

* ci: re-record the desktop snapshots of the loading link preview
This commit is contained in:
Evgeny @ SimpleX Chat authored and GitHub committed 2026-10-29 09:55:40 +00:00
1 parent 501eec671d
commit bcb1afba40
4 files changed
+8 -2

No files matched your search

@@ -3,6 +3,7 @@ package chat.simplex.app
import androidx.compose.runtime.Composable
import androidx.compose.ui.ImageComposeScene
import androidx.compose.ui.Modifier
import androidx.compose.ui.MotionDurationScale
import androidx.compose.ui.layout.FirstBaseline
import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.layout.layout
@@ -12,6 +13,7 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.use
import kotlinx.coroutines.Dispatchers
import org.jetbrains.skia.Image
import kotlin.math.roundToInt
@@ -27,8 +29,12 @@ fun Modifier.fixed(width: Int, height: Int, baseline: Int?): Modifier = layout {
layout(width, height, if (baseline == null) emptyMap() else mapOf(FirstBaseline to baseline, LastBaseline to baseline)) { placeable.place(0, 0) }
}
private object InstantMotion : MotionDurationScale {
override val scaleFactor = 0f
}
fun renderScene(direction: LayoutDirection = LayoutDirection.Ltr, width: Int = 400, height: Int = 400, frames: Int = 1, content: @Composable () -> Unit): Image =
ImageComposeScene(width = width, height = height, density = Density(1f), layoutDirection = direction, content = content).use { scene ->
ImageComposeScene(width = width, height = height, density = Density(1f), layoutDirection = direction, coroutineContext = Dispatchers.Unconfined + InstantMotion, content = content).use { scene ->
(0 until frames).map { scene.render(it * 1_000_000_000L) }.last()
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 679 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

After

Width:  |  Height:  |  Size: 617 B

+1 -1
View File
@@ -31,7 +31,7 @@ Queueing for a runner adds from under a minute to 20 minutes. Results are artifa
## Snapshots
`:common:desktopTest` runs `SnapshotTest` (`apps/multiplatform/common/src/desktopTest/kotlin/chat/simplex/app/SnapshotTest.kt`). It renders each preview listed in `previewScenes` with Compose's `ImageComposeScene`, 402 dp wide at density 1, one pixel per dp, as tall as the preview's content up to 874 dp, so a preview that fills any height is 874 pixels tall. It renders the light and dark themes without a wallpaper, over the theme's background, and keeps the fourth frame, 3 s of frame time after the first. As the app does for its screens, the test provides an `AppBarHandler` (`LocalAppBarHandler`) and the window state (`simplexWindowState`, sized as the scene). Each preview is rendered at the default font size; the chat item previews (package `views.chat.item`) also at 1.4 and 1.5, the two largest values of the desktop app's font size setting.
`:common:desktopTest` runs `SnapshotTest` (`apps/multiplatform/common/src/desktopTest/kotlin/chat/simplex/app/SnapshotTest.kt`). It renders each preview listed in `previewScenes` with Compose's `ImageComposeScene`, 402 dp wide at density 1, one pixel per dp, as tall as the preview's content up to 874 dp, so a preview that fills any height is 874 pixels tall. It renders the light and dark themes without a wallpaper, over the theme's background, and keeps the fourth frame, 3 s of frame time after the first. The scene's coroutine context sets the animation duration scale (`MotionDurationScale`) to 0, so each animation ends at its first frame and a spinner is drawn the same in every run. As the app does for its screens, the test provides an `AppBarHandler` (`LocalAppBarHandler`) and the window state (`simplexWindowState`, sized as the scene). Each preview is rendered at the default font size; the chat item previews (package `views.chat.item`) also at 1.4 and 1.5, the two largest values of the desktop app's font size setting.
`everyPreviewIsRendered` reads the Kotlin sources of `commonMain` and `desktopMain` without comments, and fails when a `@Preview` function is missing from both `previewScenes` and `previewsCallingCore`, or when either names a function absent from the sources; a scene is named `<file>.<function>`. `previewsCallingCore` lists the previews whose layouts validate names or descriptions with the core library (`chatValidName`, `chatJsonLength`), which the test JVM does not load, so they are not rendered. The previews of `androidMain` and of the Android app module are left out too, since they use Android APIs.