Compare commits

...
19 Commits
Author SHA1 Message Date
Bitsy 1b2e83a155 ci(publish): delete-then-retry so a mid-publish network blip can't poison a release
GitHub Packages forbids overwriting files that already exist in a
version, and maven-publish uploads each publication's files sequentially
from the first one. When the v0.1.13 macOS run lost DNS mid-publish, the
retries hit 409 Conflict on the first already-uploaded file of each
publication and aborted before re-attempting the missing tail — the
version could never complete (a 409 is only benign when the publication
had already fully landed, which the 409 alone can't tell you).

Between attempts each host now deletes ITS OWN package versions for the
current release via the API (GITHUB_TOKEN, packages:write) and starts
the upload from a clean slate. Hosts own disjoint package names (roots /
-macosarm64 / -jvm / bridge on macOS, -mingwx64 on Windows, -linuxx64 /
-linuxarm64 on Linux) so parallel jobs can't clobber each other; a 403
on delete degrades to the old blind retry. Last-version deletes (a
package new in this release) fall back to deleting the whole package.
2026-07-13 23:36:12 +02:00
Bitsy 8a6cb868d9 fix(sdl): defer decoded-image texture creation to the first main-thread draw
Sdl3EncodedImageDecoder ran SDL_CreateTextureFromSurface on the
resources pipeline's Dispatchers.Default workers — SDL renderer calls
are not thread-safe, so every painterResource decode on the SDL
renderer was a sporadic-crash risk (same family as #1, SDL flavour).

decode() now does the pure IMG_Load_IO surface decode only (renderer-
free, worker-safe) and hands the surface to SdlImageBitmap, which
creates the texture lazily on first access — createCanvas / the draw
paths, main thread only. Blend modes preserved: straight-alpha BLEND
for decoded surfaces, premultiplied for the vector render-target path.

Verified on Windows: demo --screen=Images renders PNG/JPG/SVG/Android-
vector through the new worker-decode → lazy-texture path.
2026-07-13 22:31:04 +02:00
Bitsy 4a7080b313 fix(window): periodic GC nudge so Cleaner-managed native memory is released
Renderer resources (Skia surfaces / images / typefaces, SDL textures)
free their NATIVE memory through Cleaners that only run when the
Kotlin/Native GC collects — and a Compose app's Kotlin heap is small
enough that the allocation-driven scheduler can starve them for minutes
while the native heap balloons (50MB → 190MB navigating the demo, never
reclaimed). Not a retention leak: layers are plain value objects, the
text/image caches are capped, and the draw paths already close() their
Skia objects eagerly.

The main loop now calls GC.collect() every 10s, only after rendering
activity, scheduled between frames — ~ms pause at these heap sizes,
keeps RSS tracking real usage on both renderers.

Fixes #2
2026-07-13 22:26:35 +02:00
Bitsy 1afb13aae0 fix(skia): register an encoded-image decoder so painterResource works on Skia builds
:components-resources' skikoRenderer variant reuses the SDL actuals,
which decode through :ui's encodedImageDecoder hook — but only the SDL
backend ever registered it. On every macOS/Linux Skia build the first
painterResource() (the demo's Images screen) hit a null decoder and
crashed with 'Image decode failed'. Deterministic, not a race.

Add SkiaEncodedImageDecoder (Image.makeFromEncoded + SVGDOM fallback via
rasterizeSvg, hoisted to file scope from SkiaImageCache) drawn into a
SkiaImageBitmap, registered at SkiaRenderBackend construction — decode
runs on the resources pipeline's Dispatchers.Default workers, which the
CPU-raster path tolerates. Mark the hook @Volatile (main-thread write,
worker-thread reads) and de-SDL the error message.

Fixes #1
2026-07-13 22:26:25 +02:00
Bitsy 3d519bcfcd docs: ui-tooling-preview, apidemo JVM parity target, bridge plugin
README: module tree entries for :ui-tooling-preview and the bridge
plugin, apidemo jvm run command + native-only mTLS note, and a new
"Using it from your own build" section for the bridge.

CLAUDE.md: same module-tree additions, apidemo multiplatform layout
(compat/Compat.kt seams), :apidemo:run parity command, bridge coverage
wording, and a new pitfall: substituted Maven modules hide their
transitives from KGP's granular-metadata visibility check — declare
every artifact commonMain touches directly + a bridge rule each.
2026-07-13 22:06:45 +02:00
Bitsy 72287fc995 feat(bridge): consumer-side Gradle plugin — official CMP coords on every platform
Dependency-substitution rules can't ship inside Maven artifacts, so the
FULL-COMMONIZATION BRIDGE is published as a Gradle plugin instead:
:compose-desktop-native-bridge (id com.bitsycore.compose-desktop-native
.bridge). Consumers apply it once in settings (gradle.lifecycle
.beforeProject, Gradle 8.8+) or per module, declare the OFFICIAL
org.jetbrains.compose coordinates in commonMain, and every native
desktop configuration substitutes the published com.bitsycore.compose
.sdl klibs — android/jvm/iOS/wasm keep resolving the official artifacts.

The substituted version defaults to the plugin's own (stamped into a
resource at build time; plugin and klibs ship from the same tag) and can
be overridden with the composeDesktopNative.version property. The
runtime is deliberately absent from the table — official klibs serve
every target. Published by the macOS publish job (host-independent jar
+ plugin marker).

Verified end-to-end offline: klibs + plugin published to mavenLocal, a
scratch third-party build applying only the plugin compiled a Compose
composable for mingwX64 against official coords — dependencyInsight
shows org.jetbrains.compose.ui:ui -> com.bitsycore.compose.sdl:ui
(selected by rule).
2026-07-13 22:06:45 +02:00
Bitsy 0b4a170910 feat(apidemo): port to JVM — shared commonMain UI + per-stack seams
Same commonization as :demo: the whole UI/logic (App, Sidebar,
ViewerPanel, panels, Model, Http, Persist, SyntaxHighlight, ...) moves
to commonMain compiling against the official Maven compose coords
(native configs substitute the port modules via the root bridge); a
jvm() target runs it on upstream Compose Desktop.

Seams (compat/Compat.kt expects; native actuals are pure delegation to
com.compose.sdl, jvm actuals use AWT + upstream desktop APIs):
file dialogs, appDataDir, revealInFileManager, clipboard text entry,
in-memory response images (Skia decode / loadSvgPainter on jvm),
wrappedRowCount (upstream TextMeasurer at density 1), editorTabWidth,
createApiHttpClient (Curl native / CIO jvm), InstallWindowHooks
(close-intercept + app-wide shortcuts -> Window onCloseRequest/
onPreviewKeyEvent), systemFileSystem (okio SYSTEM isn't in common
metadata), expect/actual mono font. Scrollbar/SplitPane/LayoutExt are
copies of the port's pure-Compose project code (ScrollState adapter
dropped — reads foundation internals; only a LazyColumn is scrollbared).

mTLS (CurlMtls + per-OS ClientCert*) stays native: ChainCert/TlsChain +
expects move to TlsCommon.kt, jvm actuals report the feature as
native-only. kotlinx-coroutines-swing provides Dispatchers.Main on
desktop jvm (App launches on it); jvmProcessResources stages
NotoSansMono + the used Material Symbols fonts.

Verified: common metadata + mingwX64 + jvm compile, native exe links
and boots, jvm app runs (fonts staged, clean exit through the
persist-then-close hook).
2026-07-13 21:40:24 +02:00
Bitsy 72e6f145b3 feat(ui-tooling-preview): common @Preview via vendored module + bridge
The canonical common @Preview is androidx.compose.ui.tooling.preview
.Preview from org.jetbrains.compose.ui:ui-tooling-preview (the umbrella
components-ui-tooling-preview annotation is deprecated). The Maven
artifact ships no mingwX64/linux klibs, so vendor the upstream module
verbatim as :ui-tooling-preview (compose-fork manifest at
COMPOSE_CORE_REF, commonMain + nonJvm actual) and substitute the Maven
coord for it on native configurations via the root bridge.

:demo declares the coord in commonMain; previews render through the jvm
parity target (IntelliJ/AS with the CMP plugin). Example on ColorsScreen.
2026-07-13 21:40:07 +02:00
Bitsy 367ed94c01 refactor(screens): streamline import statements across multiple screen files 2026-07-13 20:46:09 +02:00
Bitsy fa9bd93ada fix(demo): commonize dependencies so commonMain metadata + IDE analysis resolve
demo's commonMain had NO Compose dependencies — shared screens only
compiled because each target folds them in with jvmMain/nativeMain deps,
leaving compileCommonMainKotlinMetadata (and the IDE's common analysis)
broken between the JetBrains artifacts and the local fork.

Apply the :material-symbols pattern: commonMain declares the official
Maven coords for everything the shared screens touch (runtime, ui,
ui-graphics/-text/-unit/-geometry/-util, foundation(+layout),
animation(+core), material3, nav3-runtime, nav3-ui,
lifecycle-viewmodel-navigation3); metadata + jvm resolve them from
Maven, and the root FULL-COMMONIZATION BRIDGE substitutes each for its
port module on native configurations (new rules: ui-text/ui-graphics ->
:ui, ui-unit/-geometry/-util, foundation-layout, animation(+core),
navigation3-ui). Each artifact is declared DIRECTLY because transitives
of a substituted module are invisible to KGP's granular-metadata
visibility check.

nativeMain keeps only :window (the rest now flows from commonMain);
jvmMain keeps only its version bumps (nav3-runtime 1.2.0-alpha05) and
compose.desktop.currentOs.

Verified: :demo compileCommonMainKotlinMetadata + mingwX64 + jvm compile,
mingwX64 link, and a --screenshot runtime smoke test all pass.
2026-07-13 20:43:14 +02:00
Bitsy d1551bc9c1 fix(publish): resolve ui-graphics/ui-unit in material-symbols common metadata
The macOS publish job (the only one running the KotlinMultiplatform
metadata publication) failed in :material-symbols:
compileCommonMainKotlinMetadata — Color/isSpecified/Dp/dp unresolved.
They live in ui-graphics/ui-unit, TRANSITIVES of the Maven ui artifact:
the native substitution (ui -> project(":ui")) hides those transitives
from KGP's granular-metadata visibility check, dropping their metadata
klibs from the commonMain classpath.

Declare both explicitly in commonMain and teach the bridge their
project equivalents (ui-graphics is merged into :ui; ui-unit has its
own module).
2026-07-13 20:34:31 +02:00
DWA e9527ee8c2 refactor(publish): update caching and build logic for native dependencies based on platform 2026-07-13 17:47:41 +02:00
DWA 6040816cf7 refactor(scrollbar): improve drag handling and scrolling logic for smoother interactions 2026-07-13 17:31:07 +02:00
Bitsy 6f3bc915b2 docs: update build instructions and system dependencies for SDL3 integration 2026-07-12 23:46:54 +02:00
Bitsy 1ba84a3a2c feat(material-symbols): common API with per-stack renderers (native IconFont / JVM Skiko)
MaterialSymbols<Style> moves to commonMain so shared app code can use it on
both stacks; an internal expect/actual picks the renderer:
- native: unchanged — :foundation IconFontIcon (IconFont handles SDL3/Skia)
- jvm (NEW): Skiko direct — Typeface.makeClone per axes combination +
  TextLine on the native canvas. Not the upstream Font(variationSettings)
  route: published desktop artifacts never apply the settings at typeface
  load, and even at the pinned dev ref FontCache drops them from its cache
  key, collapsing every axes combination onto the first one loaded. Fill is
  quantised to 1/100 steps so animated FILL keeps the clone cache bounded.

Wiring:
- commonMain declares the official Maven compose coords; a repo-wide
  FULL-COMMONIZATION BRIDGE (root build) substitutes ui/foundation/material3
  for the project modules on native configurations (runtime never swapped)
- jvm stack pinned to 1.12.0-beta01+dev4324 = the vendored COMPOSE_CORE_REF
  (material3 rides its own train: 1.12.0-alpha03+dev4324); forced on jvm
  configs since gradle orders +dev below the plain version
- demo stages used icon fonts onto the jvm classpath (jvmProcessResources);
  publish workflow adds the jvm publication (macOS host)

Demo:
- DemoIcon is now common — same Material Symbols glyphs on both stacks,
  material-icons-extended jvm shim deleted
- IconsScreen (material3) keeps Icon(painter) + IconButton; the symbols
  engine gets its own Others > MaterialSymbols screen: axis sweeps, style
  families, and an animated-FILL selected-state transition
2026-07-12 23:24:53 +02:00
Bitsy e807ecf973 feat(demo): implement clipboard functionality for demo jvm 2026-07-12 22:08:13 +02:00
Bitsy dc35f5bd37 build: update build scripts to use Python for SDL builds 2026-07-12 21:16:36 +02:00
Bitsy 4888fdcda0 build: update build scripts to use Python for SDL builds 2026-07-12 21:10:44 +02:00
Bitsy 85e0179590 ci(publish): use python zipfile so macOS extracts keep the exec bit
`jar --create` strips file modes to 0644 in the archive, so any .kexe
inside extracted by macOS Archive Utility (or `ditto` / `unzip -oa`)
comes out non-executable and fails to launch. Switch the packaging
step to python's `zipfile` module — it's on every runner and preserves
the source file's exec bit + marks entries as Unix-origin, so
extractors read the right permissions.

Verified locally with ditto (Archive Utility's engine): jar-produced
zips extract source `hello.txt` at 0755 down to 0644; python-produced
zips preserve 0755 through the round-trip.

Only touches the CI workflow — next release picks up the fix, no
retag for v0.1.11 (which is publishing now with jar).
2026-07-12 18:38:05 +02:00
147 changed files with 10965 additions and 3564 deletions
+88 -22
View File
@@ -31,9 +31,16 @@ jobs:
host: macos
target: MacosArm64
exe_ext: kexe
# jvm publication: only :material-symbols declares a jvm() target
# (its common API renders via upstream Compose on JVM) — publish
# its host-independent jar from the same host as the metadata.
# :compose-desktop-native-bridge (the consumer-side bridge Gradle plugin +
# its plugin marker) is host-independent too — same job.
tasks: >-
publishKotlinMultiplatformPublicationToGitHubPackagesRepository
publishMacosArm64PublicationToGitHubPackagesRepository
publishJvmPublicationToGitHubPackagesRepository
:compose-desktop-native-bridge:publishAllPublicationsToGitHubPackagesRepository
- runner: ubuntu-22.04
host: linux
target: LinuxX64
@@ -95,23 +102,33 @@ jobs:
# intrinsic K/N's LLD can't resolve is aliased to msvcrt's _setjmpex at
# link time via --defsym in sdl3.def.
# Build static SDL3 / SDL3_ttf / SDL3_image / FreeType from
# scripts/build-sdl/build-sdl.properties. Cached against the manifest +
# scripts so version bumps invalidate cleanly.
# `cache_version` is a manual bump for when the toolchain (runner OS,
# compiler flavour, K/N sysroot expectations) changes without any
# scripts/build-sdl/ file changing. Increment to force a rebuild.
# Build the static native deps from scripts/build-sdl/build-sdl.properties.
# Only Windows ships the SDL3 renderer (no Skiko on mingw), so only it needs
# SDL3_ttf / SDL3_image / FreeType (SDL3_ttf text, SDL3_image decode, FreeType
# icon-axis rasterisation). macOS / Linux publish the Skia renderer — Skiko
# handles text / images / icons — so they only need base SDL3 for the main
# loop (windowing / input / audio / filesystem). Matches the cinterop guard
# in compose/ui/ui/build.gradle.kts, which skips those three cinterops on the
# Skia targets. Cached against the manifest + scripts so version bumps
# invalidate cleanly; bump the `v3` key when the toolchain (runner OS,
# compiler flavour, K/N sysroot) changes without a scripts/build-sdl/ edit.
- name: Cache libs/
id: cache-libs
uses: actions/cache@v4
with:
path: libs
key: sdl-libs-v2-${{ matrix.host }}-${{ hashFiles('scripts/build-sdl/**') }}
key: sdl-libs-v3-${{ matrix.host }}-${{ hashFiles('scripts/build-sdl/**') }}
- name: Build static SDL / TTF / image / FreeType
# Windows: full SDL3 renderer stack. macOS / Linux (Skia): base SDL3 only.
- name: Build static native deps
if: steps.cache-libs.outputs.cache-hit != 'true'
shell: bash
run: bash scripts/build-sdl/build-all.sh
run: |
if [ "${{ matrix.host }}" = "windows" ]; then
python3 scripts/build-sdl/build-all.py
else
python3 scripts/build-sdl/build-all.py sdl3
fi
# src/vendor/ trees are gitignored — a fresh checkout has zero vendored
# androidx.compose.* files. Sync copies them in from the upstream refs
@@ -121,16 +138,65 @@ jobs:
shell: bash
run: bash scripts/compose-fork/sync.sh
# GitHub Packages sometimes returns 409 Conflict on a fresh upload when
# the same coordinate was recently deleted (soft-delete propagation).
# `--continue` lets Gradle finish the rest of the publish tasks past a
# single 409, and the outer retry re-runs the whole thing (Gradle skips
# already-uploaded artifacts). Two attempts is enough for the transient
# cases we've hit; the third pass falls through as a hard failure.
# GitHub Packages FORBIDS overwriting a file that already exists in a
# version, and maven-publish uploads each publication's files
# SEQUENTIALLY from the first one. So when an upload dies mid-publication
# (the v0.1.13 macOS run lost DNS mid-publish), a blind retry hits 409
# Conflict on the first already-uploaded file and aborts BEFORE reaching
# the missing tail files — the version is poisoned and can never
# complete. A 409 is therefore only benign when the publication had
# already completed; you can't tell from the 409 alone. The fix: between
# attempts, DELETE this host's package versions for the current release
# and re-upload from a clean slate. Each host owns DISJOINT package
# names (roots / -macosarm64 / -jvm / bridge on macOS, -mingwx64 on
# Windows, -linuxx64/-linuxarm64 on Linux), so parallel jobs never touch
# each other's uploads. Uses the run's GITHUB_TOKEN (packages: write);
# a 403 on delete just degrades to the old blind-retry behaviour.
- name: Publish to GitHub Packages
shell: bash
run: |
set -e
VER="${PUBLISH_VERSION#v}"
OWNER="${GITHUB_REPOSITORY%%/*}"
# Keep in sync with the module list in settings.gradle.kts.
MODULES="ui ui-util ui-geometry ui-unit ui-backhandler ui-tooling-preview animation animation-core animation-graphics foundation foundation-layout material3 material-ripple window material-symbols navigation3-ui components-resources"
case "${{ matrix.host }}" in
macos) SUFFIXES="_ROOT_ -macosarm64" ;;
linux) SUFFIXES="-linuxx64 -linuxarm64" ;;
windows) SUFFIXES="-mingwx64" ;;
esac
host_packages() {
for m in $MODULES; do
for s in $SUFFIXES; do
if [ "$s" = "_ROOT_" ]; then echo "com.bitsycore.compose.sdl.$m"; else echo "com.bitsycore.compose.sdl.$m$s"; fi
done
done
if [ "${{ matrix.host }}" = "macos" ]; then
echo "com.bitsycore.compose.sdl.material-symbols-jvm"
echo "com.bitsycore.compose.sdl.compose-desktop-native-bridge"
echo "com.bitsycore.compose-desktop-native.bridge.com.bitsycore.compose-desktop-native.bridge.gradle.plugin"
fi
}
cleanup_host_versions() {
echo "Deleting this host's partially-published $VER package versions"
host_packages | while read -r pkg; do
vid=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/users/$OWNER/packages/maven/$pkg/versions?per_page=100" \
| jq -r --arg v "$VER" '[.[]? | select(.name==$v) | .id] | first // empty')
[ -z "$vid" ] && continue
code=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/users/$OWNER/packages/maven/$pkg/versions/$vid")
if [ "$code" != "204" ]; then
# Deleting the LAST version of a package is refused (400) —
# a package new in this release: drop the whole package.
code=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: Bearer $GITHUB_TOKEN" \
"https://api.github.com/users/$OWNER/packages/maven/$pkg")
fi
echo " $pkg@$VER -> HTTP $code"
done
}
for attempt in 1 2 3; do
echo "::group::Publish attempt $attempt"
if ./gradlew ${{ matrix.tasks }} --continue --no-daemon --stacktrace; then
@@ -138,7 +204,11 @@ jobs:
exit 0
fi
echo "::endgroup::"
[ $attempt -lt 3 ] && { echo "::warning::Publish attempt $attempt failed — sleeping 60s and retrying"; sleep 60; }
if [ $attempt -lt 3 ]; then
echo "::warning::Publish attempt $attempt failed — cleaning this host's $VER packages and retrying"
cleanup_host_versions || true
sleep 30
fi
done
echo "::error::Publish failed after 3 attempts"
exit 1
@@ -167,15 +237,11 @@ jobs:
target_dir=$(echo "${{ matrix.target }}" | awk '{print tolower(substr($0,1,1)) substr($0,2)}')
version="${GITHUB_REF_NAME#v}"
mkdir -p dist
# Windows Git Bash has no `zip`; every runner has JDK 21 → use `jar cf`
# which writes a valid ZIP file. `-C dir file` = enter dir then add
# `file` at the archive root, so the archive stays flat like `zip -j`.
for app in demo apidemo; do
src="$app/build/bin/$target_dir/releaseExecutable"
zip_path="$(pwd)/dist/$app-$version-$target_dir.zip"
jar --create --no-manifest --file "$zip_path" \
-C "$src" "$app.${{ matrix.exe_ext }}" \
-C "$src" "data.kres"
python3 -c 'import sys,os,zipfile; z=zipfile.ZipFile(sys.argv[1],"w",zipfile.ZIP_DEFLATED,compresslevel=9); [z.write(f,os.path.basename(f)) for f in sys.argv[2:]]; z.close()' \
"$zip_path" "$src/$app.${{ matrix.exe_ext }}" "$src/data.kres"
done
ls -la dist/
+67 -22
View File
@@ -42,7 +42,12 @@ compose/
│ ├── ui-util/ → :ui-util — androidx.compose.ui.util.* (+ Experimental/InternalComposeUiApi)
│ ├── ui-geometry/ → :ui-geometry — androidx.compose.ui.geometry.*
│ ├── ui-unit/ → :ui-unit — androidx.compose.ui.unit.*
│ └── ui-backhandler/ → :ui-backhandler — androidx.compose.ui.backhandler.*
│ ├── ui-backhandler/ → :ui-backhandler — androidx.compose.ui.backhandler.*
│ └── ui-tooling-preview/ → :ui-tooling-preview — androidx.compose.ui.tooling.preview.*
│ (the common @Preview + PreviewParameterProvider,
│ vendored verbatim; the Maven artifact ships no
│ mingwX64/linux klibs). IDE-only metadata — previews
│ render through the apps' jvm parity targets.
├── animation/
│ ├── animation-core/ → :animation-core — androidx.compose.animation.core.*
│ ├── animation/ → :animation — androidx.compose.animation.* (non-core)
@@ -60,8 +65,21 @@ compose/
utils/
└── material-symbols/ → :material-symbols — codepoints + all three style objects
(Outlined / Rounded / Sharp). Apps get one dep;
the consumer Zip task bundles only the fonts used.
(Outlined / Rounded / Sharp). COMMON API (usable from
shared app code) + per-stack actuals: native renders
via :foundation IconFontIcon (IconFont handles the
SDL3/Skia split), jvm() via Skiko directly
(Typeface.makeClone per axes — upstream's FontCache
drops variationSettings from its key). Its commonMain
declares official Maven compose coords — the root
build's FULL-COMMONIZATION BRIDGE substitutes the
whole ui / foundation / animation / material3 /
nav3-ui family to project modules on native configs
(:demo and :apidemo commonMains rely on the same
bridge; :compose-desktop-native-bridge ships it to
consumers). Apps get one dep; the consumer Zip task
bundles only the fonts used (native) and
jvmProcessResources stages the same fonts (jvm).
components/
└── resources/library/ → :components-resources — the OFFICIAL Compose resources
@@ -93,12 +111,28 @@ demo/ → :demo — flagship showcase app (30+ screens) + th
MULTIPLATFORM: also has a jvm() target running the SAME shared
screens on stock JVM Compose Desktop (`./gradlew :demo:run`,
MainJvmKt) — the parity reference; differences vs native = port bugs
apidemo/ → :apidemo — Postman-style REST API manager
scripts/ → vendor-sync + python helper scripts (compose-fidelity/coverage,
material-symbols generate/subset) + compose-fork/;
scripts/build-sdl/ = Windows static-lib build scripts (bash)
apidemo/ → :apidemo — Postman-style REST API manager. MULTIPLATFORM like :demo
(`./gradlew :apidemo:run`): the whole UI lives in commonMain
against the official Maven coords; SDL-backed APIs go through
expect/actual seams (compat/Compat.kt — native actuals delegate
to com.compose.sdl, jvm actuals use AWT + upstream desktop).
mTLS / TLS-chain inspection stays native-only (bundled libcurl).
gradle-plugin/
└── compose-desktop-native-bridge/ → :compose-desktop-native-bridge — the CONSUMER-side bridge as a
published Gradle plugin (id com.bitsycore.compose-desktop-native
.bridge, applies to Settings or Project): substitution rules
can't ship inside Maven artifacts, so third-party apps apply the
plugin, declare OFFICIAL CMP coords in commonMain, and native
configurations swap in the published com.bitsycore.compose.sdl
klibs. Substituted version defaults to the plugin's own
(override: composeDesktopNative.version property). Published by
the macOS publish job.
scripts/ → vendor-sync + python helper scripts (compose-coverage = API
coverage/fidelity vs upstream, material-symbols generate/subset)
+ compose-fork/;
scripts/build-sdl/ = static-lib build script (python)
libs/ → gitignored per-host static SDL3 / SDL3_ttf / SDL3_image / FreeType
output of scripts/build-sdl/build-*.sh on Windows
output of scripts/build-sdl/build-all.py on Windows
```
Module PATHS stay short (`:ui`, `:foundation`, `:window`, …) —
@@ -307,26 +341,28 @@ gradlew.bat :apidemo:runDebugExecutableMingwX64
./gradlew :demo:runDebugExecutableMacosArm64 -Prenderer=sdl3
# Stock JVM Compose Desktop (any host) — the parity reference: the SAME shared
# demo screens on upstream Compose; differences vs the native build = port bugs.
# screens on upstream Compose; differences vs the native build = port bugs.
./gradlew :demo:run
./gradlew :apidemo:run
```
### System dependencies
**macOS (default Skia build):** `brew install sdl3`. Only need `sdl3_ttf`
if you set `-Prenderer=sdl3`. Skiko klibs come from Maven.
SDL3 + SDL3_ttf + SDL3_image + FreeType (+ image codecs) are **built from
source as static libraries on every OS** and linked straight into the
executable — no brew/apt SDL packages, no runtime .dll/.so/.dylib;
a distributable is `<app>` + `data.kres`. One script does it all:
`python scripts/build-sdl/build-all.py` (plain Python 3, no Git Bash needed)
builds into the gitignored, in-repo `libs/` folder. Versions/URLs pinned in
`scripts/build-sdl/build-sdl.properties`. Steps run in order freetype → sdl3
→ sdl3-image → sdl3-ttf; pass step names to rebuild a subset
(`python scripts/build-sdl/build-all.py sdl3-ttf`).
**Linux (default Skia build):** `sudo apt install libsdl3-dev`. Same caveat
for SDL3_ttf.
**Windows (mingwX64 — always uses SDL3 + SDL3_ttf + SDL3_image + FreeType):**
these four libraries + image codecs are **linked statically into the
executable** — no runtime DLLs, distributable is just `<app>.exe` +
`data.kres`. They're not downloaded — `scripts/build-sdl/build-all.sh` (from Git
Bash) builds them from source as static libs into a gitignored, in-repo `libs/`
folder. Needs: git, cmake, mingw-w64 gcc/g++ on PATH, plus curl + python for
ninja fetch. `scripts/build-sdl/build-all.sh` = `build-freetype.sh` → `build-sdl3.sh` →
`build-sdl3-image.sh` → `build-sdl3-ttf.sh`.
Needs everywhere: git, cmake, python 3 (ninja fetched automatically). Per
host: macOS = Xcode CLT (Skia default; Skiko klibs from Maven); Linux =
gcc/g++ + the X11/Wayland/audio dev headers SDL3's configure detects (apt
list in .github/workflows/publish.yml); Windows = mingw-w64 g++ on PATH
(C compiles with K/N's bundled mingw).
## Runtime bundling — data.kres
@@ -469,6 +505,15 @@ that should surface in tooling.
toggling the renderer property may not invalidate it. Delete
`.gradle/configuration-cache/` between switches if you see weird
"couldn't find sdl3_ttf" errors.
- **Substituted Maven modules hide their transitives from common metadata** —
when the bridge swaps an official coord for a project module on native
configs, KGP's granular-metadata visibility check drops that Maven module's
TRANSITIVES from the commonMain classpath (symptom: `Unresolved reference
'Color'` / `Cannot access class ...` in `compileCommonMainKotlinMetadata`,
while per-target compilation is fine). Declare EVERY artifact the common
code touches DIRECTLY (ui-graphics, ui-text, ui-unit, …) and give each its
own bridge rule. Note only the macOS publish job compiles common metadata —
test with `gradlew :<module>:compileCommonMainKotlinMetadata` before tagging.
- **`Path()` in commonMain returns different actuals per renderer** —
the Skia renderer produces a `SkiaBackedPath` (wraps
`org.jetbrains.skia.Path`), the SDL renderer produces a project
+79 -10
View File
@@ -32,7 +32,9 @@ compose/
│ ├── ui-util/ → :ui-util
│ ├── ui-geometry/ → :ui-geometry
│ ├── ui-unit/ → :ui-unit
│ └── ui-backhandler/ → :ui-backhandler
│ ├── ui-backhandler/ → :ui-backhandler
│ └── ui-tooling-preview/ → :ui-tooling-preview (common @Preview + PreviewParameterProvider —
│ IDE-only metadata; previews render via the apps' jvm targets)
├── animation/
│ ├── animation-core/ → :animation-core
│ ├── animation/ → :animation
@@ -47,7 +49,11 @@ compose/
per-window Lifecycle/ViewModelStore/SavedState owners)
utils/
└── material-symbols/ → :material-symbols (codepoints + Outlined/Rounded/Sharp icon fonts)
└── material-symbols/ → :material-symbols (Material Symbols: 4200+ codepoints + Outlined/Rounded/
Sharp composables with the variable-font axes as
parameters (FILL/wght/GRAD/opsz). Common API — native
draws via the port's icon-font engine, the jvm target
via Skiko, so shared app code uses it on both stacks)
components/
└── resources/library/ → :components-resources (vendored official compose resources runtime —
@@ -58,9 +64,13 @@ navigation3/
└── navigation3-ui/ → :navigation3-ui (vendored NavDisplay + scene machinery — the one
Navigation 3 layer without a K/N desktop artifact)
gradle-plugin/
└── compose-desktop-native-bridge/ → :compose-desktop-native-bridge (the consumer-side bridge, published
as a Gradle plugin — see "Using it from your own build")
demo/ → :demo (showcase + CLI probe suite; multiplatform — the same screens
also build for stock JVM Compose Desktop as a parity reference)
apidemo/ → :apidemo (Postman-style REST client)
apidemo/ → :apidemo (Postman-style REST client; multiplatform — same UI on JVM too)
```
## demo — widget & feature showcase
@@ -102,8 +112,13 @@ file-based sessions.
./gradlew :apidemo:runDebugExecutableMacosArm64
./gradlew :apidemo:runDebugExecutableLinuxX64
gradlew.bat :apidemo:runDebugExecutableMingwX64
./gradlew :apidemo:run # stock JVM Compose Desktop (parity reference)
```
Like the demo, the whole UI lives in `commonMain` and also runs on upstream
Compose Desktop (JVM); only the mTLS / TLS-chain features are native-only —
they drive the bundled libcurl directly.
Add `-Prenderer=sdl3` on macOS/Linux to drop Skiko and use the pure-SDL3
renderer everywhere.
@@ -131,15 +146,60 @@ implementation(project(":material3")) // Material 3 widgets
implementation(project(":material-symbols")) // icon-font composables (optional)
```
## Using it from your own build — the bridge plugin
The klibs publish to GitHub Packages under `com.bitsycore.compose.sdl:*`, and
a companion Gradle plugin ships the "redirect trick" this repo uses
internally: apply **`com.bitsycore.compose-desktop-native.bridge`** once in
`settings.gradle.kts` and declare the **official Compose Multiplatform
coordinates** in `commonMain` — the plugin substitutes the port's klibs on
every native desktop configuration (mingwX64 / linuxX64 / linuxArm64 /
macosArm64), while android / jvm / iOS / wasm keep resolving the official
artifacts. One dependency list, all CMP platforms + the port's new ones.
```kotlin
// settings.gradle.kts
plugins { id("com.bitsycore.compose-desktop-native.bridge") version "<release>" }
// build.gradle.kts — official coords, everywhere
commonMain.dependencies {
implementation("org.jetbrains.compose.runtime:runtime:<runtime-version>")
implementation("org.jetbrains.compose.ui:ui:<cmp-version>")
implementation("org.jetbrains.compose.foundation:foundation:<cmp-version>")
implementation("org.jetbrains.compose.material3:material3:<cmp-m3-version>")
}
```
Setup details (repositories, credentials, version pinning):
[gradle-plugin/compose-desktop-native-bridge/README.md](gradle-plugin/compose-desktop-native-bridge/README.md).
## Building
- **macOS:** `brew install sdl3` (Skia is the default; Skiko klibs come from
Maven).
- **Linux:** `sudo apt install libsdl3-dev`.
- **Windows:** SDL3, SDL3_ttf, SDL3_image and FreeType are built from source
as **static** libraries by `scripts/build-sdl/build-all.sh` into the gitignored
in-repo `libs/`, then linked into the executable — the Windows
distributable is just `<app>.exe` + `data.kres`, no runtime DLLs.
All four native dependencies — **SDL3**, **SDL3_ttf** (the in-house
variable-font-axes fork), **SDL3_image** (+ vendored PNG/WEBP codecs) and
**FreeType** — are built from source as **static** libraries by one script,
on every OS, and linked straight into the executable. No `brew install`, no
`apt install libsdl3-dev`, no runtime `.dll` / `.so` / `.dylib` next to the
binary — a distributable is just `<app>` + `data.kres`.
```bash
python3 scripts/build-sdl/build-all.py # freetype → sdl3 → sdl3-image → sdl3-ttf
python3 scripts/build-sdl/build-all.py sdl3-ttf # rebuild a subset
```
Library versions / URLs are pinned in `scripts/build-sdl/build-sdl.properties`;
output lands in the gitignored in-repo `libs/`. Required on every host: `git`,
`cmake`, Python 3 (`ninja` is fetched automatically when absent). Per host:
- **macOS** — Xcode command line tools. Skia is the default renderer; Skiko
klibs come from Maven.
- **Linux** — gcc/g++ plus the X11 / Wayland / audio dev headers SDL3's
configure detects (the exact apt list is in
`.github/workflows/publish.yml`).
- **Windows** — a mingw-w64 g++ on PATH (the C side compiles with
Kotlin/Native's bundled mingw).
Then build any app target — see the demo / apidemo commands above.
## Vendoring
@@ -158,6 +218,15 @@ Upstream ref pinned in `scripts/compose-fork/compose.properties`; manifests can
pin additional upstream repos inline (`SET_REPO=<url>@<ref>` — the resources
runtime vendors from the compose-multiplatform umbrella repo this way).
How much of upstream's public API the port actually covers is measured, not
guessed — `scripts/compose-coverage.py` diffs this repo's klib ABI dumps
against upstream's, per vendored module:
```bash
./gradlew apiDump && python3 scripts/compose-coverage.py # per-module coverage tables
python3 scripts/compose-coverage.py --missing ui-text # list the exact uncovered decls
```
See [CLAUDE.md](CLAUDE.md) for the full architecture, source-set hierarchy,
vendoring rules, density flow (physical-pixel Option B), and per-area file
map.
+101 -13
View File
@@ -16,12 +16,38 @@ plugins {
// Skip mingwX64 on non-Windows hosts; see root build.gradle.kts.
val vHostSupportsMingw: Boolean by rootProject.extra
// JVM parity target's Compose version — the dev build matching the pinned
// COMPOSE_CORE_REF (see scripts/compose-fork/compose.properties); mirrors
// :demo's forcing (Gradle orders "+dev" BELOW the plain version, so the
// plugin's beta01 would win conflict resolution without it).
val vComposeJvmVersion = "1.12.0-beta01+dev4324"
val vComposeM3JvmVersion = "1.12.0-alpha03+dev4324"
val vComposeJvmForced = mapOf(
"org.jetbrains.compose.runtime" to vComposeJvmVersion,
"org.jetbrains.compose.ui" to vComposeJvmVersion,
"org.jetbrains.compose.foundation" to vComposeJvmVersion,
"org.jetbrains.compose.animation" to vComposeJvmVersion,
"org.jetbrains.compose.material" to vComposeJvmVersion,
"org.jetbrains.compose.material3" to vComposeM3JvmVersion,
)
configurations.configureEach {
if (name.startsWith("jvm")) {
resolutionStrategy.eachDependency {
vComposeJvmForced[requested.group]?.let { useVersion(it) }
}
}
}
kotlin {
jvm()
linuxArm64()
linuxX64()
macosArm64()
if (vHostSupportsMingw) mingwX64()
applyDefaultHierarchyTemplate()
targets.withType<KotlinNativeTarget>().all {
val isMingw = name == "mingwX64"
val isLinux = name.startsWith("linux")
@@ -68,9 +94,31 @@ kotlin {
sourceSets {
commonMain {
dependencies {
implementation(project(":window"))
implementation(project(":material3"))
// Common API on both stacks — usable from shared code.
implementation(project(":material-symbols"))
// Official Maven coords for everything the shared UI touches,
// so commonMain metadata (and the IDE's common analysis)
// resolve. Metadata + jvm resolve them from Maven; the NATIVE
// configurations substitute each for its port module (root
// build's FULL-COMMONIZATION BRIDGE). Every artifact must be
// declared DIRECTLY: transitives of a substituted module are
// invisible to the granular-metadata visibility check. The
// runtime is the official klib everywhere, never substituted
// (jvm configs force the +dev build above).
implementation("org.jetbrains.compose.runtime:runtime:1.11.1")
implementation("org.jetbrains.compose.ui:ui:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-graphics:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-text:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-unit:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-geometry:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-util:$vComposeJvmVersion")
implementation("org.jetbrains.compose.foundation:foundation:$vComposeJvmVersion")
implementation("org.jetbrains.compose.foundation:foundation-layout:$vComposeJvmVersion")
implementation("org.jetbrains.compose.animation:animation:$vComposeJvmVersion")
implementation("org.jetbrains.compose.animation:animation-core:$vComposeJvmVersion")
implementation("org.jetbrains.compose.material3:material3:$vComposeM3JvmVersion")
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
@@ -80,17 +128,32 @@ kotlin {
implementation(libs.kotlinx.datetime)
}
}
// Single HTTP engine on every desktop target: Ktor's Curl engine. It
// bundles a static libcurl per target (Schannel on Windows, OpenSSL on
// macOS/Linux) embedded in its cinterop klib — no runtime DLL, one copy.
// We use Curl everywhere (not WinHttp/Darwin) so that an upcoming
// client-certificate (mTLS) path — which calls the same bundled libcurl
// directly, since Ktor's engines expose no client-cert API — shares the
// exact same TLS stack as ordinary requests.
if (vHostSupportsMingw) getByName("mingwX64Main").dependencies { implementation(libs.ktor.client.curl) }
getByName("macosArm64Main").dependencies { implementation(libs.ktor.client.curl) }
getByName("linuxX64Main").dependencies { implementation(libs.ktor.client.curl) }
getByName("linuxArm64Main").dependencies { implementation(libs.ktor.client.curl) }
nativeMain {
dependencies {
// The SDL window shell + main loop (native-only).
implementation(project(":window"))
// Single HTTP engine on every native target: Ktor's Curl
// engine. It bundles a static libcurl per target (Schannel on
// Windows, OpenSSL on macOS/Linux) embedded in its cinterop
// klib — no runtime DLL, one copy. Curl everywhere (not
// WinHttp/Darwin) so the client-certificate (mTLS) path —
// which calls the same bundled libcurl directly, since Ktor's
// engines expose no client-cert API — shares the exact same
// TLS stack as ordinary requests.
implementation(libs.ktor.client.curl)
}
}
jvmMain {
dependencies {
// Upstream Compose Desktop — the parity stack.
implementation(compose.desktop.currentOs)
// Coroutine-based engine on JVM; native targets keep Curl.
implementation(libs.ktor.client.cio)
// Dispatchers.Main provider on desktop JVM (must match
// kotlinx-coroutines-core's version — the catalog pins both).
implementation(libs.kotlinx.coroutines.swing)
}
}
}
compilerOptions {
@@ -99,6 +162,12 @@ kotlin {
}
}
compose.desktop {
application {
mainClass = "apidemo.MainJvmKt"
}
}
// SDL3 / SDL3_ttf / SDL3_image / FreeType are linked statically into the
// executable (see the mingw linkerOpts above), so there are no runtime DLLs to
// bundle — the distributable is just <app>.exe + data.kres.
@@ -277,3 +346,22 @@ for (variant in variants) {
}
}
}
// ==================
// MARK: Stage fonts onto the JVM classpath
// ==================
// The JVM analog of the data.kres font/ entries: :material-symbols' JVM actual
// loads each style's font from the classpath at font/<Style>.ttf, and the
// jvm Fonts actual loads the mono body font at font/NotoSansMono.ttf.
tasks.named<ProcessResources>("jvmProcessResources") {
from(notoMonoFile) { into("font") }
dependsOn(":ui:downloadNotoFonts")
val vSymbolsProject = rootProject.project(":material-symbols")
for (vStyle in vUsedStyles) {
@Suppress("UNCHECKED_CAST")
val vFontFile = vSymbolsProject.extra["iconFontFile$vStyle"] as org.gradle.api.provider.Provider<org.gradle.api.file.RegularFile>
val vDownloadTask = vSymbolsProject.extra["iconFontDownloadTask$vStyle"] as TaskProvider<*>
from(vFontFile) { into("font") }
dependsOn(vDownloadTask)
}
}
File diff suppressed because it is too large Load Diff
+20
View File
@@ -0,0 +1,20 @@
package apidemo
import androidx.compose.ui.text.font.FontFamily
// ==================
// MARK: Monospace body font (seam)
// ==================
// Family name the body editor passes for monospace text. Resolves to the
// bundled Noto Sans Mono once registered; null means the font isn't shipped
// (data.kres on native, classpath font/ on jvm), in which case the body falls
// back to the default proportional font.
const val kMonoFamily = "noto-mono"
/* The raw family name string — used by wrappedRowCount, which measures via the
platform text pipeline (accepts a name string). Null when not bundled. */
expect val monoFontFamilyName: String?
/* The material3 Text / BasicTextField-shaped FontFamily for the mono family.
Null when not bundled. */
expect val monoFontFamily: FontFamily?
@@ -1,7 +1,6 @@
package apidemo
import io.ktor.client.*
import io.ktor.client.engine.curl.Curl
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
@@ -23,7 +22,7 @@ import kotlin.time.TimeSource
run() is a suspend fun — call it off the UI dispatcher. */
class HttpRunner {
private val fClient = HttpClient(Curl)
private val fClient = createApiHttpClient()
init {
// Clear any temporary client certs a prior crash left in the Windows
@@ -140,7 +139,7 @@ private fun isGzip(inEncoding: String?, inBytes: ByteArray): Boolean =
/* Read a file's raw bytes (used for a FILE request body). */
internal fun readFileBytes(inPath: String): ByteArray =
FileSystem.SYSTEM.read(inPath.trim().toPath()) { readByteArray() }
systemFileSystem.read(inPath.trim().toPath()) { readByteArray() }
/* Inflate a gzip stream to its original bytes via okio's GzipSource. */
private fun gunzip(inBytes: ByteArray): ByteArray {
@@ -19,7 +19,7 @@ private val fJson = Json {
/* Write the pack as pretty JSON to inPath. Returns null on success, else the
error message. */
fun exportPack(inPack: Pack, inPath: String): String? = try {
FileSystem.SYSTEM.write(inPath.trim().toPath()) {
systemFileSystem.write(inPath.trim().toPath()) {
writeUtf8(fJson.encodeToString(inPack))
}
null
@@ -29,7 +29,7 @@ fun exportPack(inPack: Pack, inPath: String): String? = try {
/* Read a pack back from inPath. */
fun importPack(inPath: String): Result<Pack> = try {
val vText = FileSystem.SYSTEM.read(inPath.trim().toPath()) { readUtf8() }
val vText = systemFileSystem.read(inPath.trim().toPath()) { readUtf8() }
Result.success(fJson.decodeFromString<Pack>(vText))
} catch (e: Throwable) {
Result.failure(e)
@@ -37,7 +37,7 @@ fun importPack(inPath: String): Result<Pack> = try {
/* Write a whole self-contained session to inPath. Returns null on success. */
fun exportSession(inSession: Session, inPath: String): String? = try {
FileSystem.SYSTEM.write(inPath.trim().toPath()) {
systemFileSystem.write(inPath.trim().toPath()) {
writeUtf8(fJson.encodeToString(inSession))
}
null
@@ -47,7 +47,7 @@ fun exportSession(inSession: Session, inPath: String): String? = try {
/* Read a session back from inPath. */
fun importSession(inPath: String): Result<Session> = try {
val vText = FileSystem.SYSTEM.read(inPath.trim().toPath()) { readUtf8() }
val vText = systemFileSystem.read(inPath.trim().toPath()) { readUtf8() }
Result.success(fJson.decodeFromString<Session>(vText))
} catch (e: Throwable) {
Result.failure(e)
@@ -59,7 +59,7 @@ fun renameFile(inPath: String, inNewName: String): Result<String> = try {
val vSrc = inPath.trim().toPath()
val vLeaf = inNewName.trim().let { if (it.contains('.')) it else "$it.json" }
val vDst = vSrc.parent?.div(vLeaf) ?: vLeaf.toPath()
FileSystem.SYSTEM.atomicMove(vSrc, vDst)
systemFileSystem.atomicMove(vSrc, vDst)
Result.success(vDst.toString())
} catch (e: Throwable) {
Result.failure(e)
@@ -68,7 +68,7 @@ fun renameFile(inPath: String, inNewName: String): Result<String> = try {
/* Write arbitrary text (a response body / headers dump) to inPath. Returns null
on success, else the error message. */
fun writeTextFile(inPath: String, inText: String): String? = try {
FileSystem.SYSTEM.write(inPath.trim().toPath()) { writeUtf8(inText) }
systemFileSystem.write(inPath.trim().toPath()) { writeUtf8(inText) }
null
} catch (e: Throwable) {
e.message ?: e.toString()
@@ -76,7 +76,7 @@ fun writeTextFile(inPath: String, inText: String): String? = try {
/* Write raw bytes (a binary response body, e.g. an image) to inPath. */
fun writeBytesFile(inPath: String, inBytes: ByteArray): String? = try {
FileSystem.SYSTEM.write(inPath.trim().toPath()) { write(inBytes) }
systemFileSystem.write(inPath.trim().toPath()) { write(inBytes) }
null
} catch (e: Throwable) {
e.message ?: e.toString()
@@ -1,7 +1,5 @@
package apidemo
import com.compose.sdl.appDataDir
import com.compose.sdl.revealInFileManager
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import okio.FileSystem
@@ -86,7 +84,7 @@ private fun stateFilePath(): String? {
fun loadAppState(): AppState {
val vPath = stateFilePath() ?: return AppState()
return try {
val vText = FileSystem.SYSTEM.read(vPath.toPath()) { readUtf8() }
val vText = systemFileSystem.read(vPath.toPath()) { readUtf8() }
fStateJson.decodeFromString<AppState>(vText)
} catch (e: Throwable) {
AppState()
@@ -98,7 +96,7 @@ fun loadAppState(): AppState {
fun saveAppState(inState: AppState) {
val vPath = stateFilePath() ?: return
try {
FileSystem.SYSTEM.write(vPath.toPath()) { writeUtf8(fStateJson.encodeToString(inState)) }
systemFileSystem.write(vPath.toPath()) { writeUtf8(fStateJson.encodeToString(inState)) }
} catch (e: Throwable) {
// ignore — nothing the user can act on, and packs can still be exported
}
@@ -17,10 +17,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.compose.sdl.TextLayoutConfig
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
import com.compose.sdl.showOpenFileDialog
// ==================
// MARK: Panel 3 — request builder (Query / Headers / Body)
@@ -219,7 +217,7 @@ internal fun TabSizeSelector() {
var vOpen by remember { mutableStateOf(false) }
val vHoverSrc = remember { MutableInteractionSource() }
val vHover by vHoverSrc.collectIsHoveredAsState()
val vSize = TextLayoutConfig.tabWidth
val vSize = editorTabWidth
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(TooltipAnchorPosition.Above),
tooltip = { PlainTooltip { Text("Editor tab size") } },
@@ -243,7 +241,7 @@ internal fun TabSizeSelector() {
for (vN in listOf(2, 4, 8)) {
DropdownMenuItem(text = {
Text("$vN spaces", color = if (vN == vSize) c.accent else c.text)
}, onClick = { TextLayoutConfig.tabWidth = vN; vOpen = false })
}, onClick = { editorTabWidth = vN; vOpen = false })
}
}
}
@@ -25,7 +25,6 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
import com.compose.sdl.layout.x
// ==================
// MARK: Request tab strip (open requests; drag a tab to reorder)
@@ -31,11 +31,8 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex
import com.compose.sdl.fileManagerName
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
import com.compose.sdl.layout.y
import com.compose.sdl.revealInFileManager
// ==================
// MARK: Pack colour (palette dot + picker)
@@ -23,8 +23,6 @@ import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.Popup
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
import com.compose.sdl.layout.x
import com.compose.sdl.layout.y
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -141,7 +139,7 @@ internal fun CopyButton(inText: String, inLabel: String? = null) {
.background(if (vHover) c.accent.copy(alpha = 0.18f) else Color.Transparent, RoundedCornerShape(7.dp))
.hoverable(vHoverSrc)
.clickable {
vScope.launch { vClipboard.setClipEntry(ClipEntry.withPlainText(inText)) }
vScope.launch { vClipboard.setClipEntry(clipEntryOfText(inText)) }
vCopied = true
}
.padding(horizontal = if (inLabel != null) 10.dp else 5.dp, vertical = 5.dp),
@@ -0,0 +1,29 @@
package apidemo
// ==================
// MARK: TLS chain / client-certificate seam
// ==================
// The real implementations drive the bundled libcurl directly (CurlMtls.kt,
// nativeMain) — Ktor's engines expose no client-cert / CERTINFO API. The jvm
// parity app has no bundled libcurl, so its actuals report the feature as
// native-only instead.
/* One certificate in the chain: its CURLINFO_CERTINFO-style fields (Subject /
Issuer / the PEM under "Cert" / dates …) and whether the server actually
presented it. Derived certs — an issuer resolved from the OS store, or a
name-only placeholder — have fromServer = false and are drawn dotted. */
class ChainCert(val fields: List<Pair<String, String>>, val fromServer: Boolean)
/* The server's TLS certificate chain. error is set instead when it couldn't be
fetched; fields vary by TLS backend. */
class TlsChain(val certs: List<ChainCert>, val error: String?)
/* Fetch the TLS certificate chain the request's server presents. */
expect fun inspectTlsChain(inReq: ApiRequest): TlsChain
/* Send the request with its client certificate attached (mTLS). */
expect fun curlSendWithClientCert(inReq: ApiRequest): ApiResponse
/* Remove temp client certs a previous crashed run left behind. Call once at
startup; no-op where the OS store isn't used. */
expect fun sweepTempClientCerts()
@@ -39,14 +39,6 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
import com.compose.sdl.removeMemoryResource
import com.compose.sdl.res.ResourceKind
import com.compose.sdl.res.painterResource
import com.compose.sdl.scrollbar.ScrollbarStyle
import com.compose.sdl.scrollbar.VerticalScrollbar
import com.compose.sdl.scrollbar.rememberScrollbarAdapter
import com.compose.sdl.showSaveFileDialog
import com.compose.sdl.text.currentTextMeasurer
import kotlinx.coroutines.launch
// ==================
@@ -169,8 +161,8 @@ internal fun ViewerPanel(inRs: ReqState, inResolved: ApiRequest) {
inBody = if (vRespImage) null else vBody,
inIsImage = vRespImage && !vLoading,
inImagePainter = if (vRespImage && !vLoading) {
val vKind = if (vResp?.contentType?.contains("svg", ignoreCase = true) == true) ResourceKind.Svg else ResourceKind.Raster
painterResource(inRs.imageKey!!, vKind)
val vSvg = vResp?.contentType?.contains("svg", ignoreCase = true) == true
memoryImagePainter(inRs.imageKey!!, vSvg)
} else null,
inHeadersCollapsed = vHeadersCollapsed,
inOnToggleCollapse = { vHeadersCollapsed = !vHeadersCollapsed },
@@ -247,7 +239,7 @@ internal fun ViewerPanel(inRs: ReqState, inResolved: ApiRequest) {
inResponseBody = vRespBody,
inOnMessage = { vMsg = it },
inOnClear = {
inRs.imageKey?.let { removeMemoryResource(it) }
inRs.imageKey?.let { removeMemoryImage(it) }
inRs.imageKey = null
inRs.response = null
inRs.sentReq = null
@@ -508,7 +500,7 @@ internal fun HttpFlowView(
val vS = vSel
if (vS != null && !vS.isEmpty) {
val vText = vBody.substring(vS.start, vS.end)
vScope.launch { vClipboard.setClipEntry(ClipEntry.withPlainText(vText)) }
vScope.launch { vClipboard.setClipEntry(clipEntryOfText(vText)) }
true
} else false
}
@@ -974,18 +966,18 @@ internal fun BodyView(
// also use it for the first frame, before the body reports its width).
val vNumColor = c.dim.copy(alpha = 0.45f)
val vNumbers = remember(inText, vBodyWidthPx, inSoftWrap, vFontPx) {
val vM = if (inSoftWrap && vBodyWidthPx > 0) currentTextMeasurer else null
val vWrapRows = inSoftWrap && vBodyWidthPx > 0
buildString {
for ((vIdx, vSrc) in vLines.withIndex()) {
if (vIdx > 0) append('\n')
append(vIdx + 1)
if (vM != null) {
if (vWrapRows) {
// Pass the density-scaled font size so this wrap matches the body's
// actual glyph pixel widths — passing 12 (sp) here counted each
// char as half its rendered size, so long lines that visually
// wrapped into 3 rows in the body were estimated as 1 or 2 rows
// here and the gutter numbers drifted upward.
val vRows = vM.wrap(vSrc, vFontPx, vBodyWidthPx, monoFontFamilyName).lines.size.coerceAtLeast(1)
val vRows = wrappedRowCount(vSrc, vFontPx, vBodyWidthPx, monoFontFamilyName).coerceAtLeast(1)
repeat(vRows - 1) { append('\n') }
}
}
@@ -1309,18 +1301,18 @@ internal fun ViewerOverflowMenu(
}
DropdownMenu(expanded = vOpen, onDismissRequest = { vOpen = false }) {
DropdownMenuItem(text = { Text("Copy all") }, onClick = {
vScope.launch { vClipboard.setClipEntry(ClipEntry.withPlainText(copyAll())) }
vScope.launch { vClipboard.setClipEntry(clipEntryOfText(copyAll())) }
inOnMessage("Copied all.")
vOpen = false
})
DropdownMenuItem(text = { Text("Copy headers") }, onClick = {
vScope.launch { vClipboard.setClipEntry(ClipEntry.withPlainText(vHeadersText)) }
vScope.launch { vClipboard.setClipEntry(clipEntryOfText(vHeadersText)) }
inOnMessage("Copied headers.")
vOpen = false
})
if (vCanCopyBody) {
DropdownMenuItem(text = { Text("Copy body") }, onClick = {
vScope.launch { vClipboard.setClipEntry(ClipEntry.withPlainText(vBodyText)) }
vScope.launch { vClipboard.setClipEntry(clipEntryOfText(vBodyText)) }
inOnMessage("Copied body.")
vOpen = false
})
@@ -0,0 +1,77 @@
package apidemo
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.platform.ClipEntry
import io.ktor.client.HttpClient
import okio.FileSystem
// ==================
// MARK: Platform seams (native = com.compose.sdl / SDL3, jvm = AWT + upstream desktop)
// ==================
// The port modules are native-only, so shared code can't call com.compose.sdl
// directly — every SDL-backed API the app uses goes through these expects.
// Signatures mirror the native originals so the native actuals are pure
// delegation (same pattern as :demo's demo.shim package).
/* Per-user app-data dir (created on demand, ends with a separator) or null. */
expect fun appDataDir(inOrg: String, inApp: String): String?
/* Open the OS file manager showing the given path. Fire-and-forget. */
expect fun revealInFileManager(inPath: String, inOnResult: ((Boolean) -> Unit)? = null)
/* "Explorer" / "Finder" / "Files" — for menu labels. */
expect fun fileManagerName(): String
/* Async save-file dialog; the callback gets the chosen absolute path or null. */
expect fun showSaveFileDialog(inDefaultName: String? = null, inOnResult: (String?) -> Unit)
/* Async open-file dialog; the callback gets the chosen absolute path or null. */
expect fun showOpenFileDialog(inOnResult: (String?) -> Unit)
/* A plain-text clipboard entry (ClipEntry construction differs per stack). */
expect fun clipEntryOfText(inText: String): ClipEntry
// ============
// In-memory response images
/* Register/replace decoded-image source bytes under a key (resp-image://N). */
expect fun registerMemoryImage(inKey: String, inBytes: ByteArray)
/* Drop a registered image's bytes. */
expect fun removeMemoryImage(inKey: String)
/* Painter for a registered image key (raster or SVG). */
@Composable
expect fun memoryImagePainter(inKey: String, inSvg: Boolean): Painter
// ============
// Text layout
/* Rows the given line occupies when soft-wrapped to inMaxWidthPx at
inFontPx (already density-scaled). Used by the body gutter so its line
numbers stay aligned with the wrapped body text. */
expect fun wrappedRowCount(inText: String, inFontPx: Int, inMaxWidthPx: Int, inFamilyName: String?): Int
/* Editor tab width in spaces — how wide a typed '\t' renders. On the native
stack this drives the project text pipeline (TextLayoutConfig); the jvm
parity app only stores the preference. */
expect var editorTabWidth: Int
// ============
// Infrastructure
/* okio's FileSystem.SYSTEM is declared per-platform, not in its common
metadata — surface it through a seam. */
internal expect val systemFileSystem: FileSystem
/* The app's Ktor client: Curl on native (bundled libcurl — same TLS stack as
the mTLS path), CIO on the jvm parity target. */
expect fun createApiHttpClient(): HttpClient
/* Window-shell integration: an intercepting close handler (return true to
allow the close) and an app-wide key-shortcut handler; both cleared when
the composition leaves. */
@Composable
expect fun InstallWindowHooks(inOnCloseRequest: () -> Boolean, inOnKeyShortcut: (KeyEvent) -> Boolean)
@@ -0,0 +1,16 @@
package apidemo
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.positionInWindow
// COPY of the port's com.compose.sdl.layout LayoutCoordinates sugar so the
// same helpers resolve on the jvm parity target (the port modules are
// native-only). Guards `isAttached`: a menu/tooltip anchor can be read while
// its node is mid-recycle, and positionInWindow() throws on a detached
// coordinator.
/* Logical-point X of this layout in the window. */
val LayoutCoordinates.x: Int get() = if (isAttached) positionInWindow().x.toInt() else 0
/* Logical-point Y of this layout in the window. */
val LayoutCoordinates.y: Int get() = if (isAttached) positionInWindow().y.toInt() else 0
@@ -0,0 +1,333 @@
// COPY of the port's Scrollbar (package com.compose.sdl.scrollbar) so the SAME
// implementation runs on the jvm parity target — the port modules are
// native-only, so apidemo's commonMain cannot reference them directly.
// Keep in sync with the original when it changes.
package apidemo
import androidx.compose.foundation.ScrollState
import androidx.compose.foundation.background
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.hoverable
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import kotlin.math.abs
import kotlin.math.roundToInt
// ==================
// MARK: Scrollbar (Compose Desktop-style)
// ==================
/* A faithful subset of Compose Desktop's scrollbar (androidx.compose.foundation).
You overlay a VerticalScrollbar / HorizontalScrollbar on a scrollable and feed
it a ScrollbarAdapter built from the same ScrollState. This project's Box has
no BoxScope (so no Modifier.align) — pin the bar with the Box's
contentAlignment; the fillMaxSize content fills the rest:
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.CenterEnd) {
val state = rememberScrollState()
Column(Modifier.fillMaxSize().verticalScroll(state)) { ... }
VerticalScrollbar(
adapter = rememberScrollbarAdapter(state),
modifier = Modifier.fillMaxHeight(),
)
}
Always visible (no auto-hide); the thumb tweens unhoverColor -> hoverColor on
hover over hoverDurationMillis, matching upstream. Drag the thumb to scroll;
click the track to page. */
@Immutable
class ScrollbarStyle(
val minimalHeight: Dp,
val thickness: Dp,
val shape: Shape,
val hoverDurationMillis: Int,
val unhoverColor: Color,
val hoverColor: Color,
)
/* Upstream default: an 8dp black thumb that's faint until hovered. Dark UIs
provide a white-tinted style via LocalScrollbarStyle or the `style` param. */
fun defaultScrollbarStyle(): ScrollbarStyle = ScrollbarStyle(
minimalHeight = 16.dp,
thickness = 8.dp,
shape = RoundedCornerShape(4.dp),
hoverDurationMillis = 300,
unhoverColor = Color.Black.copy(alpha = 0.12f),
hoverColor = Color.Black.copy(alpha = 0.50f),
)
val LocalScrollbarStyle = compositionLocalOf { defaultScrollbarStyle() }
// ==================
// MARK: ScrollbarAdapter
// ==================
/* Bridges a scrollable's state to the scrollbar in pixels. scrollOffset /
contentSize / viewportSize are along the scroll axis; the thumb is sized by
viewportSize / contentSize and positioned by scrollOffset / (content - viewport). */
interface ScrollbarAdapter {
val scrollOffset: Double
val contentSize: Double
val viewportSize: Double
suspend fun scrollTo(scrollOffset: Double)
}
// (The port also ships a ScrollState-based adapter; it reads foundation
// internals (ScrollState.contentSize/viewportSize) that a copy outside
// :foundation cannot access. apidemo only scrollbars a LazyColumn.)
/* Adapter for a virtualized LazyColumn / LazyRow. A lazy list only knows the
size of its VISIBLE items, so exact pixel geometry of off-screen content is
unknowable — we estimate it from the average visible item size × total item
count (the same approach as Compose Desktop). Accurate enough for a thumb
whose length/position track the scroll position; the estimate self-corrects
as items of different sizes scroll through the viewport. */
@Composable
fun rememberScrollbarAdapter(scrollState: LazyListState): ScrollbarAdapter =
remember(scrollState) { LazyListScrollbarAdapter(scrollState) }
private class LazyListScrollbarAdapter(private val state: LazyListState) : ScrollbarAdapter {
// Mean main-axis size of the currently-visible items, in px (>= 1 to avoid /0).
private fun averageItemSize(): Double {
val vVisible = state.layoutInfo.visibleItemsInfo
if (vVisible.isEmpty()) return 0.0
val vSpan = (vVisible.last().offset + vVisible.last().size) - vVisible.first().offset
return (vSpan.toDouble() / vVisible.size).coerceAtLeast(1.0)
}
override val scrollOffset: Double
get() = averageItemSize() * state.firstVisibleItemIndex + state.firstVisibleItemScrollOffset
override val contentSize: Double
get() = averageItemSize() * state.layoutInfo.totalItemsCount
override val viewportSize: Double
get() = (state.layoutInfo.viewportEndOffset - state.layoutInfo.viewportStartOffset).toDouble()
override suspend fun scrollTo(scrollOffset: Double) {
val vDistance = scrollOffset - this.scrollOffset
// Within a viewport, scroll by EXACT pixels so a drag stays smooth. A lazy
// list's pixel geometry is only ESTIMATED (average visible item size), and
// that estimate drifts as differently-sized items scroll through the
// viewport — so index-snapping every frame makes the thumb jump. scrollBy
// sidesteps the estimate entirely. This is what Compose Desktop's own
// LazyListScrollbarAdapter does, and for the same reason.
if (abs(vDistance) <= viewportSize) {
state.scrollBy(vDistance.toFloat())
return
}
// Far jump (track-click paging past a viewport): no exact geometry to lean
// on, so estimate an index/offset from the average and snap to it.
val vAvg = averageItemSize()
if (vAvg <= 0.0) return
val vTarget = scrollOffset.coerceAtLeast(0.0)
val vTotal = state.layoutInfo.totalItemsCount
val vIndex = (vTarget / vAvg).toInt().coerceIn(0, (vTotal - 1).coerceAtLeast(0))
val vItemOffset = (vTarget - vIndex * vAvg).toInt().coerceAtLeast(0)
state.scrollToItem(vIndex, vItemOffset)
}
}
// ==================
// MARK: VerticalScrollbar / HorizontalScrollbar
// ==================
@Composable
fun VerticalScrollbar(
adapter: ScrollbarAdapter,
modifier: Modifier = Modifier,
reverseLayout: Boolean = false,
style: ScrollbarStyle = LocalScrollbarStyle.current,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) = Scrollbar(adapter, modifier, reverseLayout, style, interactionSource, isVertical = true)
@Composable
fun HorizontalScrollbar(
adapter: ScrollbarAdapter,
modifier: Modifier = Modifier,
reverseLayout: Boolean = false,
style: ScrollbarStyle = LocalScrollbarStyle.current,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) = Scrollbar(adapter, modifier, reverseLayout, style, interactionSource, isVertical = false)
/* Shared impl. The root Box is the track (fixed thickness on the cross axis,
filling the main axis from the caller's modifier); a child Box is the thumb,
positioned with an offset. Drag + track-click are handled on the track in
track-relative coordinates (a stable origin), so the grab point stays under
the pointer with no feedback from the thumb moving. interactionSource is
accepted for API parity; hover here is driven by Modifier.hoverable. */
@Composable
private fun Scrollbar(
adapter: ScrollbarAdapter,
modifier: Modifier,
reverseLayout: Boolean,
style: ScrollbarStyle,
@Suppress("UNUSED_PARAMETER") interactionSource: MutableInteractionSource,
isVertical: Boolean,
) {
val vScope = rememberCoroutineScope()
var vTrackPx by remember { mutableStateOf(0) }
val vHoverSource = remember { MutableInteractionSource() }
val vHovered by vHoverSource.collectIsHoveredAsState()
var vDraggingThumb by remember { mutableStateOf(false) }
// onSizeChanged reports PHYSICAL pixels (Option-B density flow), so every
// int/px carried through here — vTrackPx, vThumbLen, vThumbPos — is in
// physical pixels. Passing them into `.dp` doubles again through
// density.toPx() on Retina, which visibly bloated the thumb (filled the
// whole track) and made drag/track-click positions land 2Ă— too far down.
// Route pixel-sized modifiers through the current density so `.dp` and the
// pixel value stay in the same coord space.
val vDensity = LocalDensity.current
val vContent = adapter.contentSize
val vViewport = adapter.viewportSize
val vOffset = adapter.scrollOffset
val vMaxScroll = vContent - vViewport
val vScrollable = vMaxScroll > 0.5 && vViewport > 0.0
val vColor by animateColorAsState(
targetValue = if (vHovered || vDraggingThumb) style.hoverColor else style.unhoverColor,
animationSpec = tween(style.hoverDurationMillis),
)
val vRoot = (if (isVertical) modifier.width(style.thickness) else modifier.height(style.thickness))
.onSizeChanged { vTrackPx = if (isVertical) it.height else it.width }
.hoverable(vHoverSource)
Box(modifier = vRoot) {
if (!vScrollable || vTrackPx <= 0) return@Box
// ============
// Thumb metrics (px)
val vMinLen = style.minimalHeight.value.toInt()
val vThumbLen = (vTrackPx * (vViewport / vContent)).roundToInt()
.coerceIn(vMinLen.coerceAtMost(vTrackPx), vTrackPx)
val vTravel = vTrackPx - vThumbLen
val vRawPos = if (vTravel <= 0) 0 else (vTravel * (vOffset / vMaxScroll)).roundToInt()
val vThumbPos = (if (reverseLayout) vTravel - vRawPos else vRawPos).coerceIn(0, vTravel)
val vThumbLenDp = with(vDensity) { vThumbLen.toDp() }
val vThumbMod = (
if (isVertical) Modifier.offset { IntOffset(0, vThumbPos) }.width(style.thickness).height(vThumbLenDp)
else Modifier.offset { IntOffset(vThumbPos, 0) }.height(style.thickness).width(vThumbLenDp)
)
.clip(style.shape)
.background(vColor)
Box(modifier = vThumbMod)
// ============
// Drag the thumb / page on track click — handled on the track so the
// coordinates have a stable (non-moving) origin. The press is CONSUMED:
// a scrollbar owns the pointer input it handles, so content sharing this
// region (the scrollable beneath, or a parent that also reads pointer
// input) never reacts to the same press. Geometry is read LIVE from the
// adapter at press time — not from the captured render metrics above,
// which go stale between pointerInput relaunches — so a grab after a
// wheel-scroll still hit-tests against the thumb's current position.
Box(
modifier = Modifier
.matchTrackSize(isVertical, with(vDensity) { vTrackPx.toDp() }, style.thickness)
.pointerInput(isVertical, adapter, vTrackPx, reverseLayout) {
awaitEachGesture {
val vDown = awaitFirstDown(requireUnconsumed = false)
vDown.consume()
// Live geometry — stable for the drag's duration (content /
// viewport / track sizes don't change mid-drag).
val vContentPx = adapter.contentSize
val vViewportPx = adapter.viewportSize
val vMaxScrollPx = vContentPx - vViewportPx
if (vMaxScrollPx <= 0.0 || vTrackPx <= 0) return@awaitEachGesture
val vMinLen = style.minimalHeight.value.toInt()
val vLen = (vTrackPx * (vViewportPx / vContentPx)).roundToInt()
.coerceIn(vMinLen.coerceAtMost(vTrackPx), vTrackPx)
val vTravelPx = vTrackPx - vLen
val vRaw = if (vTravelPx <= 0) 0
else (vTravelPx * (adapter.scrollOffset / vMaxScrollPx)).roundToInt()
val vPos = (if (reverseLayout) vTravelPx - vRaw else vRaw).coerceIn(0, vTravelPx)
// Map a track-relative thumb-top to a scroll offset. The
// target uses the LIVE max scroll (read fresh each move),
// not the press-time value — the adapter compares it against
// its live scrollOffset, and mixing a stale scale with a live
// one makes the delta run away (grab at the bottom, drag up,
// and the list overshoots to the middle).
fun scrollToTrackPos(inThumbTop: Int) {
if (vTravelPx <= 0) return
val vLiveMax = adapter.contentSize - adapter.viewportSize
if (vLiveMax <= 0.0) return
val vClamped = inThumbTop.coerceIn(0, vTravelPx)
val vFrac = (if (reverseLayout) vTravelPx - vClamped else vClamped).toDouble() / vTravelPx
vScope.launch { adapter.scrollTo(vFrac * vLiveMax) }
}
val vPress = (if (isVertical) vDown.position.y else vDown.position.x).toInt()
val vGrab: Int
if (vPress in vPos..(vPos + vLen)) {
vDraggingThumb = true
vGrab = vPress - vPos
} else {
// Page toward the click by one viewport.
vDraggingThumb = false
vGrab = 0
val vDir = if (vPress < vPos) -1.0 else 1.0
vScope.launch { adapter.scrollTo(adapter.scrollOffset + vDir * vViewportPx) }
}
// Follow the pressed pointer to release, consuming every
// change so the interaction can't leak. Only a thumb grab
// drags-to-scroll; a track press just consumes.
do {
val vEvent = awaitPointerEvent()
val vChange = vEvent.changes.firstOrNull { it.id == vDown.id } ?: break
if (vDraggingThumb) {
val vCur = (if (isVertical) vChange.position.y else vChange.position.x).toInt()
scrollToTrackPos(vCur - vGrab)
}
vChange.consume()
} while (vEvent.changes.any { it.id == vDown.id && it.pressed })
vDraggingThumb = false
}
}
)
}
}
/* Sizes the invisible drag-capture overlay to the full track. `inTrackDp`
comes from the caller pre-converted via LocalDensity (Option-B: layout
coords are physical px, so px-to-dp goes through the current density). */
private fun Modifier.matchTrackSize(inVertical: Boolean, inTrackDp: Dp, inThickness: Dp): Modifier =
if (inVertical) this.width(inThickness).height(inTrackDp)
else this.height(inThickness).width(inTrackDp)
@@ -0,0 +1,172 @@
// COPY of the port's SplitPane (package com.compose.sdl.widgets) so the SAME
// implementation runs on the jvm parity target — the port modules are
// native-only, so apidemo's commonMain cannot reference them directly.
// Keep in sync with the original when it changes.
package apidemo
import androidx.compose.foundation.background
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
// ==================
// MARK: SplitPane
// ==================
/** Two-pane resizable split. `initialFirstSize` seeds the first pane's width
* (horizontal split) or height (vertical split); after first layout it tracks
* the user's drag. `minFirstSize` / `minSecondSize` clamp so neither pane can
* shrink past its minimum.
*
* Internal sizing is in **pixels** to match this port's pixel-space layout
* tree (Option-B density flow). `Modifier.width((px / density).dp)` converts
* back at the modifier boundary. */
@Composable
fun HorizontalSplitPane(
modifier: Modifier = Modifier,
initialFirstSize: Dp = 200.dp,
minFirstSize: Dp = 50.dp,
minSecondSize: Dp = 50.dp,
dividerColor: Color = Color(0x33FFFFFFL),
dividerHoverColor: Color = Color(0x66FFFFFFL),
first: @Composable () -> Unit,
second: @Composable () -> Unit,
) {
val vDensity = LocalDensity.current
val vDividerPx = with(vDensity) { SplitPaneDefaults.DividerThickness.toPx().toInt() }
val vMinFirstPx = with(vDensity) { minFirstSize.toPx().toInt() }
val vMinSecondPx = with(vDensity) { minSecondSize.toPx().toInt() }
val vInitialFirstPx = with(vDensity) { initialFirstSize.toPx().toInt() }
var vTotalWidthPx by remember { mutableStateOf(0) }
var vFirstWidthPx by remember { mutableStateOf(vInitialFirstPx) }
val vDividerSource = remember { MutableInteractionSource() }
val vDividerHover by vDividerSource.collectIsHoveredAsState()
var vDragging by remember { mutableStateOf(false) }
Row(
modifier = modifier
.fillMaxSize()
.onSizeChanged { vTotalWidthPx = it.width },
) {
val vClampedFirstPx = if (vTotalWidthPx > 0)
vFirstWidthPx.coerceIn(vMinFirstPx, (vTotalWidthPx - vDividerPx - vMinSecondPx).coerceAtLeast(vMinFirstPx))
else vFirstWidthPx
val vSecondWidthPx = (vTotalWidthPx - vClampedFirstPx - vDividerPx).coerceAtLeast(0)
Box(modifier = Modifier.width(with(vDensity) { vClampedFirstPx.toDp() }).fillMaxHeight()) { first() }
// Solid divider that fills its own slot — what you see is exactly what
// you can grab. Hover or an in-progress drag just changes the colour (no
// size change → no layout shift, and no flicker when the pointer briefly
// leaves the slot mid-drag).
val vActive = vDividerHover || vDragging
Box(
modifier = Modifier
.width(SplitPaneDefaults.DividerThickness)
.fillMaxHeight()
.background(if (vActive) dividerHoverColor else dividerColor)
.hoverable(vDividerSource)
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { vDragging = true },
onDragEnd = { vDragging = false },
onDragCancel = { vDragging = false },
onDrag = { _, delta ->
val vMax = (vTotalWidthPx - vDividerPx - vMinSecondPx).coerceAtLeast(vMinFirstPx)
vFirstWidthPx = (vFirstWidthPx + delta.x.toInt()).coerceIn(vMinFirstPx, vMax)
},
)
},
)
Box(modifier = Modifier.width(with(vDensity) { vSecondWidthPx.toDp() }).fillMaxHeight()) { second() }
}
}
@Composable
fun VerticalSplitPane(
modifier: Modifier = Modifier,
initialFirstSize: Dp = 150.dp,
minFirstSize: Dp = 50.dp,
minSecondSize: Dp = 50.dp,
dividerColor: Color = Color(0x33FFFFFFL),
dividerHoverColor: Color = Color(0x66FFFFFFL),
first: @Composable () -> Unit,
second: @Composable () -> Unit,
) {
val vDensity = LocalDensity.current
val vDividerPx = with(vDensity) { SplitPaneDefaults.DividerThickness.toPx().toInt() }
val vMinFirstPx = with(vDensity) { minFirstSize.toPx().toInt() }
val vMinSecondPx = with(vDensity) { minSecondSize.toPx().toInt() }
val vInitialFirstPx = with(vDensity) { initialFirstSize.toPx().toInt() }
var vTotalHeightPx by remember { mutableStateOf(0) }
var vFirstHeightPx by remember { mutableStateOf(vInitialFirstPx) }
val vDividerSource = remember { MutableInteractionSource() }
val vDividerHover by vDividerSource.collectIsHoveredAsState()
var vDragging by remember { mutableStateOf(false) }
var vPressStartFirstPx by remember { mutableStateOf(0) }
Column(
modifier = modifier
.fillMaxSize()
.onSizeChanged { vTotalHeightPx = it.height },
) {
val vClampedFirstPx = if (vTotalHeightPx > 0)
vFirstHeightPx.coerceIn(vMinFirstPx, (vTotalHeightPx - vDividerPx - vMinSecondPx).coerceAtLeast(vMinFirstPx))
else vFirstHeightPx
val vSecondHeightPx = (vTotalHeightPx - vClampedFirstPx - vDividerPx).coerceAtLeast(0)
Box(modifier = Modifier.height(with(vDensity) { vClampedFirstPx.toDp() }).fillMaxWidth()) { first() }
// Solid divider that fills its slot; hover/drag only changes the colour
// (no size change → no layout shift, no flicker mid-drag).
val vActive = vDividerHover || vDragging
Box(
modifier = Modifier
.height(SplitPaneDefaults.DividerThickness)
.fillMaxWidth()
.background(if (vActive) dividerHoverColor else dividerColor)
.hoverable(vDividerSource)
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { vDragging = true },
onDragEnd = { vDragging = false },
onDragCancel = { vDragging = false },
onDrag = { _, delta ->
val vMax = (vTotalHeightPx - vDividerPx - vMinSecondPx).coerceAtLeast(vMinFirstPx)
vFirstHeightPx = (vFirstHeightPx + delta.y.toInt()).coerceIn(vMinFirstPx, vMax)
},
)
},
)
Box(modifier = Modifier.height(with(vDensity) { vSecondHeightPx.toDp() }).fillMaxWidth()) { second() }
}
}
object SplitPaneDefaults {
val DividerThickness: Dp = 4.dp // divider width = hit/drag area (solid; what you see is what you grab)
}
+162
View File
@@ -0,0 +1,162 @@
@file:OptIn(androidx.compose.ui.ExperimentalComposeUiApi::class)
package apidemo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.loadSvgPainter
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextMeasurer
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.createFontFamilyResolver
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.sp
import java.awt.Desktop
import java.awt.EventQueue
import java.awt.FileDialog
import java.awt.Frame
import java.awt.datatransfer.StringSelection
import java.io.File
import org.jetbrains.skia.Image
// ==================
// MARK: JVM actuals — AWT + upstream Compose Desktop
// ==================
private val kIsWindows = System.getProperty("os.name").startsWith("Windows")
private val kIsMac = System.getProperty("os.name").startsWith("Mac")
internal actual val systemFileSystem: okio.FileSystem = okio.FileSystem.SYSTEM
actual fun createApiHttpClient(): io.ktor.client.HttpClient =
io.ktor.client.HttpClient(io.ktor.client.engine.cio.CIO)
// ============
// Window hooks — the shared App installs them; MainJvm wires them into the
// upstream Window() (onCloseRequest / onPreviewKeyEvent).
internal var jvmOnCloseRequest: (() -> Boolean)? = null
internal var jvmOnKeyShortcut: ((KeyEvent) -> Boolean)? = null
@Composable
actual fun InstallWindowHooks(inOnCloseRequest: () -> Boolean, inOnKeyShortcut: (KeyEvent) -> Boolean) {
androidx.compose.runtime.DisposableEffect(inOnCloseRequest, inOnKeyShortcut) {
jvmOnCloseRequest = inOnCloseRequest
jvmOnKeyShortcut = inOnKeyShortcut
onDispose { jvmOnCloseRequest = null; jvmOnKeyShortcut = null }
}
}
/* Mirrors SDL_GetPrefPath's layout: <os user-data dir>/<org>/<app>/ with a
trailing separator, created on demand. */
actual fun appDataDir(inOrg: String, inApp: String): String? {
val vHome = System.getProperty("user.home") ?: return null
val vBase = when {
kIsWindows -> System.getenv("APPDATA") ?: "$vHome/AppData/Roaming"
kIsMac -> "$vHome/Library/Application Support"
else -> System.getenv("XDG_DATA_HOME") ?: "$vHome/.local/share"
}
val vDir = File(File(vBase, inOrg), inApp)
if (!vDir.exists() && !vDir.mkdirs()) return null
return vDir.absolutePath + File.separator
}
/* Opens the path's containing folder (AWT has no cross-platform "select in
file manager"); fire-and-forget off the EDT. */
actual fun revealInFileManager(inPath: String, inOnResult: ((Boolean) -> Unit)?) {
Thread {
val vOk = runCatching {
val vFile = File(inPath)
Desktop.getDesktop().open(if (vFile.isDirectory) vFile else vFile.parentFile ?: vFile)
}.isSuccess
inOnResult?.invoke(vOk)
}.apply { isDaemon = true }.start()
}
actual fun fileManagerName(): String = when {
kIsWindows -> "Explorer"
kIsMac -> "Finder"
else -> "Files"
}
/* AWT FileDialog runs its own nested event loop, so invoking from the EDT
(where Compose Desktop also runs) keeps the UI serviced while modal. */
actual fun showSaveFileDialog(inDefaultName: String?, inOnResult: (String?) -> Unit) {
EventQueue.invokeLater {
val vDlg = FileDialog(null as Frame?, "Save", FileDialog.SAVE)
inDefaultName?.let { vDlg.file = it }
vDlg.isVisible = true
inOnResult(vDlg.file?.let { vDlg.directory + it })
}
}
actual fun showOpenFileDialog(inOnResult: (String?) -> Unit) {
EventQueue.invokeLater {
val vDlg = FileDialog(null as Frame?, "Open", FileDialog.LOAD)
vDlg.isVisible = true
inOnResult(vDlg.file?.let { vDlg.directory + it })
}
}
/* Upstream desktop's ClipEntry wraps an AWT Transferable. */
actual fun clipEntryOfText(inText: String): ClipEntry = ClipEntry(StringSelection(inText))
// ============
// In-memory response images
private val kMemoryImages = HashMap<String, ByteArray>()
actual fun registerMemoryImage(inKey: String, inBytes: ByteArray) { kMemoryImages[inKey] = inBytes }
actual fun removeMemoryImage(inKey: String) { kMemoryImages.remove(inKey) }
@Composable
actual fun memoryImagePainter(inKey: String, inSvg: Boolean): Painter {
val vDensity = LocalDensity.current
return remember(inKey, inSvg) {
val vBytes = kMemoryImages[inKey]
runCatching {
if (vBytes == null) error("no bytes for $inKey")
if (inSvg) loadSvgPainter(vBytes.inputStream(), vDensity)
else BitmapPainter(Image.makeFromEncoded(vBytes).toComposeImageBitmap())
}.getOrElse { BitmapPainter(ImageBitmap(1, 1)) }
}
}
// ============
// Text layout
/* Upstream TextMeasurer at density 1 so the px-valued font size maps 1:1
(the caller passes an already density-scaled size). */
private val kRowMeasurer: TextMeasurer by lazy {
TextMeasurer(createFontFamilyResolver(), Density(1f), LayoutDirection.Ltr)
}
actual fun wrappedRowCount(inText: String, inFontPx: Int, inMaxWidthPx: Int, inFamilyName: String?): Int =
runCatching {
kRowMeasurer.measure(
AnnotatedString(inText),
TextStyle(fontSize = inFontPx.sp, fontFamily = monoFontFamily ?: FontFamily.Monospace),
constraints = Constraints(maxWidth = inMaxWidthPx),
).lineCount
}.getOrDefault(1)
/* The jvm parity app only stores the preference — upstream's text pipeline has
no global tab-width knob. Backed by state so menu checkmarks recompose. */
private var fTabWidth by mutableStateOf(4)
actual var editorTabWidth: Int
get() = fTabWidth
set(value) { fTabWidth = value }
+23
View File
@@ -0,0 +1,23 @@
package apidemo
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.platform.Font
// ==================
// MARK: Monospace body font — JVM actuals (classpath font/ staged by
// jvmProcessResources)
// ==================
actual val monoFontFamily: FontFamily? by lazy {
val vBytes = object {}.javaClass.getResourceAsStream("/font/NotoSansMono.ttf")?.use { it.readBytes() }
if (vBytes == null) {
println("apidemo: NotoSansMono.ttf not on the classpath — body uses the default font")
null
} else {
FontFamily(Font(identity = kMonoFamily, data = vBytes))
}
}
actual val monoFontFamilyName: String? by lazy {
if (monoFontFamily != null) kMonoFamily else null
}
+22
View File
@@ -0,0 +1,22 @@
package apidemo
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import androidx.compose.ui.window.rememberWindowState
// The JVM comparison app's entry point. Runs the SAME shared App() as the
// native :apidemo, but on Compose Desktop (JVM) against upstream
// org.jetbrains.compose. Client-certificate (mTLS) features are native-only
// (they drive the bundled libcurl); the jvm actuals report that instead.
fun main() = application {
Window(
// The shared App installs a persist-then-close hook (InstallWindowHooks).
onCloseRequest = { if (jvmOnCloseRequest?.invoke() != false) exitApplication() },
onPreviewKeyEvent = { jvmOnKeyShortcut?.invoke(it) ?: false },
title = "API Manager — JVM (upstream Compose)",
state = rememberWindowState(width = 1240.dp, height = 820.dp),
) {
App()
}
}
+26
View File
@@ -0,0 +1,26 @@
package apidemo
// ==================
// MARK: TLS chain / client-certificate — JVM actuals (native-only feature)
// ==================
// The native builds drive the bundled libcurl (CURLOPT_SSLCERT / CERTINFO);
// there is no libcurl on the jvm parity stack, so both entry points report
// the limitation instead of half-implementing it over JSSE.
private const val kNativeOnly =
"Client-certificate (mTLS) features need the native build — they drive the bundled libcurl directly."
actual fun inspectTlsChain(inReq: ApiRequest): TlsChain = TlsChain(emptyList(), kNativeOnly)
actual fun curlSendWithClientCert(inReq: ApiRequest): ApiResponse = ApiResponse(
ok = false,
status = 0,
statusText = "",
timeMs = 0,
sizeBytes = 0,
headers = emptyList(),
body = "",
error = kNativeOnly,
)
actual fun sweepTempClientCerts() {}
@@ -0,0 +1,63 @@
package apidemo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.ClipEntry
import com.compose.sdl.LocalComposeNativeWindow
import com.compose.sdl.TextLayoutConfig
import com.compose.sdl.registerMemoryResource
import com.compose.sdl.removeMemoryResource
import com.compose.sdl.res.ResourceKind
import com.compose.sdl.text.currentTextMeasurer
// ==================
// MARK: Native actuals — pure delegation to the port's SDL-backed APIs
// ==================
actual fun appDataDir(inOrg: String, inApp: String): String? =
com.compose.sdl.appDataDir(inOrg, inApp)
actual fun revealInFileManager(inPath: String, inOnResult: ((Boolean) -> Unit)?) =
com.compose.sdl.revealInFileManager(inPath, inOnResult)
actual fun fileManagerName(): String = com.compose.sdl.fileManagerName()
actual fun showSaveFileDialog(inDefaultName: String?, inOnResult: (String?) -> Unit) =
com.compose.sdl.showSaveFileDialog(inDefaultName, inOnResult)
actual fun showOpenFileDialog(inOnResult: (String?) -> Unit) =
com.compose.sdl.showOpenFileDialog(inOnResult)
actual fun clipEntryOfText(inText: String): ClipEntry = ClipEntry.withPlainText(inText)
actual fun registerMemoryImage(inKey: String, inBytes: ByteArray) = registerMemoryResource(inKey, inBytes)
actual fun removeMemoryImage(inKey: String) = removeMemoryResource(inKey)
@Composable
actual fun memoryImagePainter(inKey: String, inSvg: Boolean): Painter =
com.compose.sdl.res.painterResource(inKey, if (inSvg) ResourceKind.Svg else ResourceKind.Raster)
actual fun wrappedRowCount(inText: String, inFontPx: Int, inMaxWidthPx: Int, inFamilyName: String?): Int =
currentTextMeasurer.wrap(inText, inFontPx, inMaxWidthPx, inFamilyName).lines.size
actual var editorTabWidth: Int
get() = TextLayoutConfig.tabWidth
set(value) { TextLayoutConfig.tabWidth = value }
internal actual val systemFileSystem: okio.FileSystem = okio.FileSystem.SYSTEM
actual fun createApiHttpClient(): io.ktor.client.HttpClient =
io.ktor.client.HttpClient(io.ktor.client.engine.curl.Curl)
@Composable
actual fun InstallWindowHooks(inOnCloseRequest: () -> Boolean, inOnKeyShortcut: (KeyEvent) -> Boolean) {
val vWindow = LocalComposeNativeWindow.current
DisposableEffect(inOnCloseRequest, inOnKeyShortcut) {
vWindow.setOnCloseRequest(inOnCloseRequest)
vWindow.setOnKeyShortcut(inOnKeyShortcut)
onDispose { vWindow.setOnCloseRequest(null); vWindow.setOnKeyShortcut(null) }
}
}
+6 -17
View File
@@ -39,21 +39,10 @@ class PreparedCert(
Throws with a user-facing message if the cert/key can't be loaded. */
expect fun prepareClientCert(inReq: ApiRequest): PreparedCert
/* Remove any temporary client certs (and their key containers) a previous run
left behind in the Windows store after a crash — identified by our prefix, so
the user's own certificates are never touched. No-op off Windows. Call once
at startup. */
expect fun sweepTempClientCerts()
/* One certificate in the chain: its CURLINFO_CERTINFO-style fields (Subject /
Issuer / the PEM under "Cert" / dates …) and whether the server actually
presented it. Derived certs — an issuer resolved from the OS store, or a
name-only placeholder — have fromServer = false and are drawn dotted. */
class ChainCert(val fields: List<Pair<String, String>>, val fromServer: Boolean)
/* The server's TLS certificate chain. error is set instead when it couldn't be
fetched; fields vary by TLS backend. */
class TlsChain(val certs: List<ChainCert>, val error: String?)
// ChainCert / TlsChain and the sweepTempClientCerts / inspectTlsChain /
// curlSendWithClientCert expects live in commonMain (TlsCommon.kt) — the UI
// consumes them from shared code; the per-OS ClientCert*.kt actuals below the
// native tree actualize sweepTempClientCerts directly.
/* Continue a server-presented chain with its issuer(s). Where possible the
issuer is resolved from the OS certificate store with full info; otherwise the
@@ -120,7 +109,7 @@ private fun onCurlDiscard(inBuffer: CPointer<ByteVar>, inSize: size_t, inCount:
request's client certificate if it has one (so mTLS endpoints work too).
inReq is already var-resolved. */
@OptIn(ExperimentalForeignApi::class)
fun inspectTlsChain(inReq: ApiRequest): TlsChain
actual fun inspectTlsChain(inReq: ApiRequest): TlsChain
{
val vCert = try { if (inReq.hasClientCert) prepareClientCert(inReq) else null }
catch (e: Throwable) { return TlsChain(emptyList(), e.message ?: "Client certificate error") }
@@ -185,7 +174,7 @@ private fun readCertInfo(inCurl: COpaquePointer): List<List<Pair<String, String>
/* Send a client-certificate request through libcurl and adapt the result into
the same ApiResponse the Ktor path produces. inReq is already var-resolved. */
@OptIn(ExperimentalForeignApi::class)
fun curlSendWithClientCert(inReq: ApiRequest): ApiResponse
actual fun curlSendWithClientCert(inReq: ApiRequest): ApiResponse
{
val vMark = TimeSource.Monotonic.markNow()
val vCert = try { prepareClientCert(inReq) }
+3 -13
View File
@@ -6,17 +6,10 @@ import com.compose.sdl.loadComposeResourceBytes
import com.compose.sdl.text.namedFontFamily
// ==================
// MARK: Monospace body font
// MARK: Monospace body font — native actuals (data.kres + IconFont)
// ==================
// Family name the body editor passes for monospace text. Resolves to the bundled
// Noto Sans Mono once registered; null means the font isn't in data.kres, in
// which case the body falls back to the default (proportional Noto Sans).
const val kMonoFamily = "noto-mono"
// The raw project family name string — used by the SyntaxHighlight tokeniser's
// wrap() call which measures via NativeTextMeasurer (accepts a name string).
val monoFontFamilyName: String? by lazy {
actual val monoFontFamilyName: String? by lazy {
val vBytes = loadComposeResourceBytes("font/NotoSansMono.ttf")
if (vBytes == null) {
println("apidemo: NotoSansMono.ttf not bundled — body uses the default font")
@@ -27,9 +20,6 @@ val monoFontFamilyName: String? by lazy {
}
}
// The material3 Text / BasicTextField-shaped FontFamily wrapper. Wraps the
// registered project family in a `NamedFont`-backed FontFamily so the m3 Text
// signature (which takes `FontFamily?` proper) can be given the mono family.
val monoFontFamily: FontFamily? by lazy {
actual val monoFontFamily: FontFamily? by lazy {
monoFontFamilyName?.let { namedFontFamily(it) }
}
File diff suppressed because it is too large Load Diff
+41 -4
View File
@@ -5,11 +5,12 @@
// apply the multiplatform plugin. Each subproject still applies the ones it needs.
plugins {
alias(libs.plugins.kotlin.multiplatform) apply false
alias(libs.plugins.kotlin.jvm) apply false
alias(libs.plugins.kotlin.plugin.compose) apply false
alias(libs.plugins.kotlin.plugin.serialization) apply false
alias(libs.plugins.compose.multiplatform) apply false
// Public-ABI dumps (api/<module>.klib.api). Used by scripts/compose-fidelity-check.py
// to diff our androidx.compose.* surface against the official Compose klib ABI.
// Public-ABI dumps (api/<module>.klib.api). Used by scripts/compose-coverage.py
// to diff our mirrored API surface against the official upstream klib ABI dumps.
alias(libs.plugins.binary.compatibility.validator)
}
@@ -17,7 +18,8 @@ plugins {
// surface worth tracking, so skip them.
apiValidation {
klib { enabled = true }
ignoredProjects.addAll(listOf("demo", "apidemo"))
// compose-desktop-native-bridge is a plain JVM Gradle plugin — no klib ABI to track.
ignoredProjects.addAll(listOf("demo", "apidemo", "compose-desktop-native-bridge"))
}
// Project coordinates. `group` is baked into every module's Kotlin/Native klib
@@ -47,6 +49,7 @@ allprojects {
val kAppModules = setOf(":demo", ":apidemo")
val kPublishedLibs = setOf(
":ui", ":ui-util", ":ui-geometry", ":ui-unit", ":ui-backhandler",
":ui-tooling-preview",
":animation-core", ":animation", ":animation-graphics",
":foundation", ":foundation-layout",
":material3", ":material-ripple",
@@ -108,10 +111,44 @@ subprojects {
}
}
// FULL-COMMONIZATION BRIDGE (repo-wide): a module may declare the OFFICIAL
// Maven Compose artifacts in its commonMain so metadata + jvm resolve them
// (e.g. :material-symbols' common API); every NATIVE target configuration
// swaps those modules for the port's project equivalents — the Maven
// artifacts ship no mingwX64/linux klibs. org.jetbrains.compose.runtime is
// deliberately NOT here: the port uses the official runtime klibs everywhere.
// (:demo carries the same pattern locally for components-resources.)
val vNativeTargetTokens = listOf("mingwX64", "linuxX64", "linuxArm64", "macosArm64")
allprojects {
configurations.configureEach {
if (vNativeTargetTokens.any { name.contains(it, ignoreCase = true) }) {
resolutionStrategy.dependencySubstitution {
substitute(module("org.jetbrains.compose.ui:ui")).using(project(":ui"))
// ui's split artifacts: ui-graphics + ui-text are merged INTO
// :ui in the port; ui-unit / ui-geometry have their own modules.
substitute(module("org.jetbrains.compose.ui:ui-graphics")).using(project(":ui"))
substitute(module("org.jetbrains.compose.ui:ui-text")).using(project(":ui"))
substitute(module("org.jetbrains.compose.ui:ui-unit")).using(project(":ui-unit"))
substitute(module("org.jetbrains.compose.ui:ui-geometry")).using(project(":ui-geometry"))
substitute(module("org.jetbrains.compose.ui:ui-util")).using(project(":ui-util"))
substitute(module("org.jetbrains.compose.ui:ui-tooling-preview")).using(project(":ui-tooling-preview"))
substitute(module("org.jetbrains.compose.foundation:foundation")).using(project(":foundation"))
substitute(module("org.jetbrains.compose.foundation:foundation-layout")).using(project(":foundation-layout"))
substitute(module("org.jetbrains.compose.animation:animation")).using(project(":animation"))
substitute(module("org.jetbrains.compose.animation:animation-core")).using(project(":animation-core"))
substitute(module("org.jetbrains.compose.material3:material3")).using(project(":material3"))
// navigation3-ui: the JB Maven artifact has no K/N desktop
// klibs — the port vendors it as :navigation3-ui.
substitute(module("org.jetbrains.androidx.navigation3:navigation3-ui")).using(project(":navigation3-ui"))
}
}
}
}
// Whether the current host can build the mingwX64 target. Kotlin/Native can
// only cross-compile mingwX64 cinterops from a Windows host — the sdl3_ttf /
// sdl3_image cinterops need Windows SDL3 headers under libs/ (produced by
// scripts/build-sdl/build-*.sh, which only runs on Windows). Declaring `mingwX64()` on
// scripts/build-sdl/build-all.py run on a Windows host). Declaring `mingwX64()` on
// a non-Windows host is safe for pure-Kotlin modules but blows up the moment
// a `depends = sdl3` cinterop tries to include SDL3_ttf/SDL_ttf.h.
// Override with `-PforceMingw=true` if you actually have the headers wired.
@@ -0,0 +1,238 @@
// Klib ABI Dump
// Targets: [linuxArm64, linuxX64, macosArm64, mingwX64]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
// - Show declarations: true
// Library unique name: <com.bitsycore.compose.sdl:components-resources>
open annotation class org.jetbrains.compose.resources/ExperimentalResourceApi : kotlin/Annotation { // org.jetbrains.compose.resources/ExperimentalResourceApi|null[0]
constructor <init>() // org.jetbrains.compose.resources/ExperimentalResourceApi.<init>|<init>(){}[0]
}
open annotation class org.jetbrains.compose.resources/InternalResourceApi : kotlin/Annotation { // org.jetbrains.compose.resources/InternalResourceApi|null[0]
constructor <init>() // org.jetbrains.compose.resources/InternalResourceApi.<init>|<init>(){}[0]
}
open annotation class org.jetbrains.compose.resources/ResourceContentHash : kotlin/Annotation { // org.jetbrains.compose.resources/ResourceContentHash|null[0]
constructor <init>(kotlin/Int) // org.jetbrains.compose.resources/ResourceContentHash.<init>|<init>(kotlin.Int){}[0]
final val hash // org.jetbrains.compose.resources/ResourceContentHash.hash|{}hash[0]
final fun <get-hash>(): kotlin/Int // org.jetbrains.compose.resources/ResourceContentHash.hash.<get-hash>|<get-hash>(){}[0]
}
final enum class org.jetbrains.compose.resources/DensityQualifier : kotlin/Enum<org.jetbrains.compose.resources/DensityQualifier>, org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/DensityQualifier|null[0]
enum entry HDPI // org.jetbrains.compose.resources/DensityQualifier.HDPI|null[0]
enum entry LDPI // org.jetbrains.compose.resources/DensityQualifier.LDPI|null[0]
enum entry MDPI // org.jetbrains.compose.resources/DensityQualifier.MDPI|null[0]
enum entry XHDPI // org.jetbrains.compose.resources/DensityQualifier.XHDPI|null[0]
enum entry XXHDPI // org.jetbrains.compose.resources/DensityQualifier.XXHDPI|null[0]
enum entry XXXHDPI // org.jetbrains.compose.resources/DensityQualifier.XXXHDPI|null[0]
final val dpi // org.jetbrains.compose.resources/DensityQualifier.dpi|{}dpi[0]
final fun <get-dpi>(): kotlin/Int // org.jetbrains.compose.resources/DensityQualifier.dpi.<get-dpi>|<get-dpi>(){}[0]
final val entries // org.jetbrains.compose.resources/DensityQualifier.entries|#static{}entries[0]
final fun <get-entries>(): kotlin.enums/EnumEntries<org.jetbrains.compose.resources/DensityQualifier> // org.jetbrains.compose.resources/DensityQualifier.entries.<get-entries>|<get-entries>#static(){}[0]
final fun valueOf(kotlin/String): org.jetbrains.compose.resources/DensityQualifier // org.jetbrains.compose.resources/DensityQualifier.valueOf|valueOf#static(kotlin.String){}[0]
final fun values(): kotlin/Array<org.jetbrains.compose.resources/DensityQualifier> // org.jetbrains.compose.resources/DensityQualifier.values|values#static(){}[0]
final object Companion { // org.jetbrains.compose.resources/DensityQualifier.Companion|null[0]
final fun selectByDensity(kotlin/Float): org.jetbrains.compose.resources/DensityQualifier // org.jetbrains.compose.resources/DensityQualifier.Companion.selectByDensity|selectByDensity(kotlin.Float){}[0]
final fun selectByValue(kotlin/Int): org.jetbrains.compose.resources/DensityQualifier // org.jetbrains.compose.resources/DensityQualifier.Companion.selectByValue|selectByValue(kotlin.Int){}[0]
}
}
final enum class org.jetbrains.compose.resources/ThemeQualifier : kotlin/Enum<org.jetbrains.compose.resources/ThemeQualifier>, org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/ThemeQualifier|null[0]
enum entry DARK // org.jetbrains.compose.resources/ThemeQualifier.DARK|null[0]
enum entry LIGHT // org.jetbrains.compose.resources/ThemeQualifier.LIGHT|null[0]
final val entries // org.jetbrains.compose.resources/ThemeQualifier.entries|#static{}entries[0]
final fun <get-entries>(): kotlin.enums/EnumEntries<org.jetbrains.compose.resources/ThemeQualifier> // org.jetbrains.compose.resources/ThemeQualifier.entries.<get-entries>|<get-entries>#static(){}[0]
final fun valueOf(kotlin/String): org.jetbrains.compose.resources/ThemeQualifier // org.jetbrains.compose.resources/ThemeQualifier.valueOf|valueOf#static(kotlin.String){}[0]
final fun values(): kotlin/Array<org.jetbrains.compose.resources/ThemeQualifier> // org.jetbrains.compose.resources/ThemeQualifier.values|values#static(){}[0]
final object Companion { // org.jetbrains.compose.resources/ThemeQualifier.Companion|null[0]
final fun selectByValue(kotlin/Boolean): org.jetbrains.compose.resources/ThemeQualifier // org.jetbrains.compose.resources/ThemeQualifier.Companion.selectByValue|selectByValue(kotlin.Boolean){}[0]
}
}
abstract interface org.jetbrains.compose.resources/Qualifier // org.jetbrains.compose.resources/Qualifier|null[0]
abstract interface org.jetbrains.compose.resources/ResourceReader { // org.jetbrains.compose.resources/ResourceReader|null[0]
abstract fun getUri(kotlin/String): kotlin/String // org.jetbrains.compose.resources/ResourceReader.getUri|getUri(kotlin.String){}[0]
abstract suspend fun read(kotlin/String): kotlin/ByteArray // org.jetbrains.compose.resources/ResourceReader.read|read(kotlin.String){}[0]
abstract suspend fun readPart(kotlin/String, kotlin/Long, kotlin/Long): kotlin/ByteArray // org.jetbrains.compose.resources/ResourceReader.readPart|readPart(kotlin.String;kotlin.Long;kotlin.Long){}[0]
}
final class org.jetbrains.compose.resources.vector.xmldom/MalformedXMLException : kotlin/Exception { // org.jetbrains.compose.resources.vector.xmldom/MalformedXMLException|null[0]
constructor <init>(kotlin/String?) // org.jetbrains.compose.resources.vector.xmldom/MalformedXMLException.<init>|<init>(kotlin.String?){}[0]
}
final class org.jetbrains.compose.resources/DrawableResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/DrawableResource|null[0]
constructor <init>(kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/DrawableResource.<init>|<init>(kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
}
final class org.jetbrains.compose.resources/FontResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/FontResource|null[0]
constructor <init>(kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/FontResource.<init>|<init>(kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
}
final class org.jetbrains.compose.resources/LanguageQualifier : org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/LanguageQualifier|null[0]
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/LanguageQualifier.<init>|<init>(kotlin.String){}[0]
final val language // org.jetbrains.compose.resources/LanguageQualifier.language|{}language[0]
final fun <get-language>(): kotlin/String // org.jetbrains.compose.resources/LanguageQualifier.language.<get-language>|<get-language>(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/LanguageQualifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/LanguageQualifier.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // org.jetbrains.compose.resources/LanguageQualifier.toString|toString(){}[0]
}
final class org.jetbrains.compose.resources/MissingResourceException : kotlin/Exception { // org.jetbrains.compose.resources/MissingResourceException|null[0]
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/MissingResourceException.<init>|<init>(kotlin.String){}[0]
}
final class org.jetbrains.compose.resources/PluralStringResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/PluralStringResource|null[0]
constructor <init>(kotlin/String, kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/PluralStringResource.<init>|<init>(kotlin.String;kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
final val key // org.jetbrains.compose.resources/PluralStringResource.key|{}key[0]
final fun <get-key>(): kotlin/String // org.jetbrains.compose.resources/PluralStringResource.key.<get-key>|<get-key>(){}[0]
}
final class org.jetbrains.compose.resources/RegionQualifier : org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/RegionQualifier|null[0]
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/RegionQualifier.<init>|<init>(kotlin.String){}[0]
final val region // org.jetbrains.compose.resources/RegionQualifier.region|{}region[0]
final fun <get-region>(): kotlin/String // org.jetbrains.compose.resources/RegionQualifier.region.<get-region>|<get-region>(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/RegionQualifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/RegionQualifier.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // org.jetbrains.compose.resources/RegionQualifier.toString|toString(){}[0]
}
final class org.jetbrains.compose.resources/ResourceEnvironment { // org.jetbrains.compose.resources/ResourceEnvironment|null[0]
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/ResourceEnvironment.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/ResourceEnvironment.hashCode|hashCode(){}[0]
}
final class org.jetbrains.compose.resources/ResourceItem { // org.jetbrains.compose.resources/ResourceItem|null[0]
constructor <init>(kotlin.collections/Set<org.jetbrains.compose.resources/Qualifier>, kotlin/String, kotlin/Long, kotlin/Long) // org.jetbrains.compose.resources/ResourceItem.<init>|<init>(kotlin.collections.Set<org.jetbrains.compose.resources.Qualifier>;kotlin.String;kotlin.Long;kotlin.Long){}[0]
final fun copy(kotlin.collections/Set<org.jetbrains.compose.resources/Qualifier> = ..., kotlin/String = ..., kotlin/Long = ..., kotlin/Long = ...): org.jetbrains.compose.resources/ResourceItem // org.jetbrains.compose.resources/ResourceItem.copy|copy(kotlin.collections.Set<org.jetbrains.compose.resources.Qualifier>;kotlin.String;kotlin.Long;kotlin.Long){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/ResourceItem.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/ResourceItem.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // org.jetbrains.compose.resources/ResourceItem.toString|toString(){}[0]
}
final class org.jetbrains.compose.resources/ScriptQualifier : org.jetbrains.compose.resources/Qualifier { // org.jetbrains.compose.resources/ScriptQualifier|null[0]
constructor <init>(kotlin/String) // org.jetbrains.compose.resources/ScriptQualifier.<init>|<init>(kotlin.String){}[0]
final val script // org.jetbrains.compose.resources/ScriptQualifier.script|{}script[0]
final fun <get-script>(): kotlin/String // org.jetbrains.compose.resources/ScriptQualifier.script.<get-script>|<get-script>(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/ScriptQualifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/ScriptQualifier.hashCode|hashCode(){}[0]
final fun isEmpty(): kotlin/Boolean // org.jetbrains.compose.resources/ScriptQualifier.isEmpty|isEmpty(){}[0]
final fun toString(): kotlin/String // org.jetbrains.compose.resources/ScriptQualifier.toString|toString(){}[0]
}
final class org.jetbrains.compose.resources/StringArrayResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/StringArrayResource|null[0]
constructor <init>(kotlin/String, kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/StringArrayResource.<init>|<init>(kotlin.String;kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
final val key // org.jetbrains.compose.resources/StringArrayResource.key|{}key[0]
final fun <get-key>(): kotlin/String // org.jetbrains.compose.resources/StringArrayResource.key.<get-key>|<get-key>(){}[0]
}
final class org.jetbrains.compose.resources/StringResource : org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/StringResource|null[0]
constructor <init>(kotlin/String, kotlin/String, kotlin.collections/Set<org.jetbrains.compose.resources/ResourceItem>) // org.jetbrains.compose.resources/StringResource.<init>|<init>(kotlin.String;kotlin.String;kotlin.collections.Set<org.jetbrains.compose.resources.ResourceItem>){}[0]
final val key // org.jetbrains.compose.resources/StringResource.key|{}key[0]
final fun <get-key>(): kotlin/String // org.jetbrains.compose.resources/StringResource.key.<get-key>|<get-key>(){}[0]
}
sealed class org.jetbrains.compose.resources/Resource { // org.jetbrains.compose.resources/Resource|null[0]
open fun equals(kotlin/Any?): kotlin/Boolean // org.jetbrains.compose.resources/Resource.equals|equals(kotlin.Any?){}[0]
open fun hashCode(): kotlin/Int // org.jetbrains.compose.resources/Resource.hashCode|hashCode(){}[0]
}
final object org.jetbrains.compose.resources/ResourceCaches // org.jetbrains.compose.resources/ResourceCaches|null[0]
final val org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop|#static{}org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop[0]
final val org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop|#static{}org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop[0]
final val org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop|#static{}org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop[0]
final val org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop // org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop|#static{}org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop[0]
final val org.jetbrains.compose.resources/LocalResourceReader // org.jetbrains.compose.resources/LocalResourceReader|{}LocalResourceReader[0]
final fun <get-LocalResourceReader>(): androidx.compose.runtime/ProvidableCompositionLocal<org.jetbrains.compose.resources/ResourceReader> // org.jetbrains.compose.resources/LocalResourceReader.<get-LocalResourceReader>|<get-LocalResourceReader>(){}[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop|#static{}org_jetbrains_compose_resources_DrawableResource$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop|#static{}org_jetbrains_compose_resources_FontResource$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop|#static{}org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop|#static{}org_jetbrains_compose_resources_ImageCache_Svg$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop|#static{}org_jetbrains_compose_resources_ImageCache_Vector$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop|#static{}org_jetbrains_compose_resources_LanguageQualifier$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop|#static{}org_jetbrains_compose_resources_MissingResourceException$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop|#static{}org_jetbrains_compose_resources_PluralStringResource$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop|#static{}org_jetbrains_compose_resources_RegionQualifier$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop|#static{}org_jetbrains_compose_resources_Resource$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop|#static{}org_jetbrains_compose_resources_ResourceCaches$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop|#static{}org_jetbrains_compose_resources_ResourceEnvironment$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop|#static{}org_jetbrains_compose_resources_ResourceItem$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop|#static{}org_jetbrains_compose_resources_ScriptQualifier$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop|#static{}org_jetbrains_compose_resources_StringArrayResource$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop|#static{}org_jetbrains_compose_resources_StringItem_Array$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop|#static{}org_jetbrains_compose_resources_StringItem_Plurals$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop|#static{}org_jetbrains_compose_resources_StringItem_Value$stableprop[0]
final val org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop|#static{}org_jetbrains_compose_resources_StringResource$stableprop[0]
final fun (kotlin/ByteArray).org.jetbrains.compose.resources/decodeToImageBitmap(): androidx.compose.ui.graphics/ImageBitmap // org.jetbrains.compose.resources/decodeToImageBitmap|decodeToImageBitmap@kotlin.ByteArray(){}[0]
final fun (kotlin/ByteArray).org.jetbrains.compose.resources/decodeToImageVector(androidx.compose.ui.unit/Density): androidx.compose.ui.graphics.vector/ImageVector // org.jetbrains.compose.resources/decodeToImageVector|decodeToImageVector@kotlin.ByteArray(androidx.compose.ui.unit.Density){}[0]
final fun (kotlin/ByteArray).org.jetbrains.compose.resources/decodeToSvgPainter(androidx.compose.ui.unit/Density): androidx.compose.ui.graphics.painter/Painter // org.jetbrains.compose.resources/decodeToSvgPainter|decodeToSvgPainter@kotlin.ByteArray(androidx.compose.ui.unit.Density){}[0]
final fun org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop_getter|org_jetbrains_compose_resources_plural_PluralRule_Condition_And$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop_getter|org_jetbrains_compose_resources_plural_PluralRule_Condition_Or$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.plural/org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop_getter|org_jetbrains_compose_resources_plural_PluralRule_Condition_Relation$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources.vector.xmldom/org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop_getter|org_jetbrains_compose_resources_vector_xmldom_MalformedXMLException$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/Font(org.jetbrains.compose.resources/FontResource, androidx.compose.ui.text.font/FontWeight?, androidx.compose.ui.text.font/FontStyle, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.ui.text.font/Font // org.jetbrains.compose.resources/Font|Font(org.jetbrains.compose.resources.FontResource;androidx.compose.ui.text.font.FontWeight?;androidx.compose.ui.text.font.FontStyle;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/Font(org.jetbrains.compose.resources/FontResource, androidx.compose.ui.text.font/FontWeight?, androidx.compose.ui.text.font/FontStyle, androidx.compose.ui.text.font/FontVariation.Settings?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.ui.text.font/Font // org.jetbrains.compose.resources/Font|Font(org.jetbrains.compose.resources.FontResource;androidx.compose.ui.text.font.FontWeight?;androidx.compose.ui.text.font.FontStyle;androidx.compose.ui.text.font.FontVariation.Settings?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/getResourceUri(kotlin/String): kotlin/String // org.jetbrains.compose.resources/getResourceUri|getResourceUri(kotlin.String){}[0]
final fun org.jetbrains.compose.resources/getSystemResourceEnvironment(): org.jetbrains.compose.resources/ResourceEnvironment // org.jetbrains.compose.resources/getSystemResourceEnvironment|getSystemResourceEnvironment(){}[0]
final fun org.jetbrains.compose.resources/imageResource(org.jetbrains.compose.resources/DrawableResource, androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics/ImageBitmap // org.jetbrains.compose.resources/imageResource|imageResource(org.jetbrains.compose.resources.DrawableResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_DrawableResource$stableprop_getter|org_jetbrains_compose_resources_DrawableResource$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_FontResource$stableprop_getter|org_jetbrains_compose_resources_FontResource$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop_getter|org_jetbrains_compose_resources_ImageCache_Bitmap$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Svg$stableprop_getter|org_jetbrains_compose_resources_ImageCache_Svg$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ImageCache_Vector$stableprop_getter|org_jetbrains_compose_resources_ImageCache_Vector$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_LanguageQualifier$stableprop_getter|org_jetbrains_compose_resources_LanguageQualifier$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_MissingResourceException$stableprop_getter|org_jetbrains_compose_resources_MissingResourceException$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_PluralStringResource$stableprop_getter|org_jetbrains_compose_resources_PluralStringResource$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_RegionQualifier$stableprop_getter|org_jetbrains_compose_resources_RegionQualifier$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_Resource$stableprop_getter|org_jetbrains_compose_resources_Resource$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceCaches$stableprop_getter|org_jetbrains_compose_resources_ResourceCaches$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceEnvironment$stableprop_getter|org_jetbrains_compose_resources_ResourceEnvironment$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ResourceItem$stableprop_getter|org_jetbrains_compose_resources_ResourceItem$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_ScriptQualifier$stableprop_getter|org_jetbrains_compose_resources_ScriptQualifier$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringArrayResource$stableprop_getter|org_jetbrains_compose_resources_StringArrayResource$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Array$stableprop_getter|org_jetbrains_compose_resources_StringItem_Array$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Plurals$stableprop_getter|org_jetbrains_compose_resources_StringItem_Plurals$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringItem_Value$stableprop_getter|org_jetbrains_compose_resources_StringItem_Value$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop_getter(): kotlin/Int // org.jetbrains.compose.resources/org_jetbrains_compose_resources_StringResource$stableprop_getter|org_jetbrains_compose_resources_StringResource$stableprop_getter(){}[0]
final fun org.jetbrains.compose.resources/painterResource(org.jetbrains.compose.resources/DrawableResource, androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics.painter/Painter // org.jetbrains.compose.resources/painterResource|painterResource(org.jetbrains.compose.resources.DrawableResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/pluralStringResource(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/pluralStringResource|pluralStringResource(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/pluralStringResource(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, kotlin/Array<out kotlin/Any>..., androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/pluralStringResource|pluralStringResource(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;kotlin.Array<out|kotlin.Any>...;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/rememberResourceEnvironment(androidx.compose.runtime/Composer?, kotlin/Int): org.jetbrains.compose.resources/ResourceEnvironment // org.jetbrains.compose.resources/rememberResourceEnvironment|rememberResourceEnvironment(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/stringArrayResource(org.jetbrains.compose.resources/StringArrayResource, androidx.compose.runtime/Composer?, kotlin/Int): kotlin.collections/List<kotlin/String> // org.jetbrains.compose.resources/stringArrayResource|stringArrayResource(org.jetbrains.compose.resources.StringArrayResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/stringResource(org.jetbrains.compose.resources/StringResource, androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/stringResource|stringResource(org.jetbrains.compose.resources.StringResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/stringResource(org.jetbrains.compose.resources/StringResource, kotlin/Array<out kotlin/Any>..., androidx.compose.runtime/Composer?, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/stringResource|stringResource(org.jetbrains.compose.resources.StringResource;kotlin.Array<out|kotlin.Any>...;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun org.jetbrains.compose.resources/vectorResource(org.jetbrains.compose.resources/DrawableResource, androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics.vector/ImageVector // org.jetbrains.compose.resources/vectorResource|vectorResource(org.jetbrains.compose.resources.DrawableResource;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final suspend fun org.jetbrains.compose.resources/getDrawableResourceBytes(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/DrawableResource): kotlin/ByteArray // org.jetbrains.compose.resources/getDrawableResourceBytes|getDrawableResourceBytes(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.DrawableResource){}[0]
final suspend fun org.jetbrains.compose.resources/getFontResourceBytes(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/FontResource): kotlin/ByteArray // org.jetbrains.compose.resources/getFontResourceBytes|getFontResourceBytes(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.FontResource){}[0]
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int){}[0]
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;kotlin.Array<out|kotlin.Any>...){}[0]
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/PluralStringResource, kotlin/Int): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.PluralStringResource;kotlin.Int){}[0]
final suspend fun org.jetbrains.compose.resources/getPluralString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/PluralStringResource, kotlin/Int, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getPluralString|getPluralString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.PluralStringResource;kotlin.Int;kotlin.Array<out|kotlin.Any>...){}[0]
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/StringResource): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.StringResource){}[0]
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/StringResource, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.StringResource;kotlin.Array<out|kotlin.Any>...){}[0]
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/StringResource): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.StringResource){}[0]
final suspend fun org.jetbrains.compose.resources/getString(org.jetbrains.compose.resources/StringResource, kotlin/Array<out kotlin/Any>...): kotlin/String // org.jetbrains.compose.resources/getString|getString(org.jetbrains.compose.resources.StringResource;kotlin.Array<out|kotlin.Any>...){}[0]
final suspend fun org.jetbrains.compose.resources/getStringArray(org.jetbrains.compose.resources/ResourceEnvironment, org.jetbrains.compose.resources/StringArrayResource): kotlin.collections/List<kotlin/String> // org.jetbrains.compose.resources/getStringArray|getStringArray(org.jetbrains.compose.resources.ResourceEnvironment;org.jetbrains.compose.resources.StringArrayResource){}[0]
final suspend fun org.jetbrains.compose.resources/getStringArray(org.jetbrains.compose.resources/StringArrayResource): kotlin.collections/List<kotlin/String> // org.jetbrains.compose.resources/getStringArray|getStringArray(org.jetbrains.compose.resources.StringArrayResource){}[0]
final suspend fun org.jetbrains.compose.resources/readResourceBytes(kotlin/String): kotlin/ByteArray // org.jetbrains.compose.resources/readResourceBytes|readResourceBytes(kotlin.String){}[0]
@@ -21,7 +21,7 @@ import com.compose.sdl.graphics.decodeEncodedImageBitmap
drawables ship at a single density, so no decode-time rescale applies. */
internal actual fun ByteArray.toImageBitmap(resourceDensity: Int, targetDensity: Int): ImageBitmap =
decodeEncodedImageBitmap(this)
?: error("Image decode failed — is the SDL renderer initialised before painterResource ran?")
?: error("Image decode failed — is the render backend initialised before painterResource ran?")
/* SVG on SDL: SDL3_image rasterises SVG at its intrinsic size (IMG_LoadSVG),
so the "element" is just the raw bytes and the painter is the rasterised
@@ -34,5 +34,5 @@ internal actual fun ByteArray.toSvgElement(): SvgElement = SvgElement(this)
internal actual fun SvgElement.toSvgPainter(density: Density): Painter =
BitmapPainter(
decodeEncodedImageBitmap(bytes)
?: error("SVG rasterisation failed — is the SDL renderer initialised before painterResource ran?")
?: error("SVG rasterisation failed — is the render backend initialised before painterResource ran?")
)
@@ -2078,17 +2078,6 @@ final object com.compose.sdl.icons/IconDefaults { // com.compose.sdl.icons/IconD
final fun <get-LocalContentColor>(): androidx.compose.ui.graphics/Color // com.compose.sdl.icons/IconDefaults.LocalContentColor.<get-LocalContentColor>|<get-LocalContentColor>(){}[0]
}
final object com.compose.sdl.icons/MaterialIconAxisDefaults { // com.compose.sdl.icons/MaterialIconAxisDefaults|null[0]
final const val Fill // com.compose.sdl.icons/MaterialIconAxisDefaults.Fill|{}Fill[0]
final fun <get-Fill>(): kotlin/Float // com.compose.sdl.icons/MaterialIconAxisDefaults.Fill.<get-Fill>|<get-Fill>(){}[0]
final const val Grade // com.compose.sdl.icons/MaterialIconAxisDefaults.Grade|{}Grade[0]
final fun <get-Grade>(): kotlin/Int // com.compose.sdl.icons/MaterialIconAxisDefaults.Grade.<get-Grade>|<get-Grade>(){}[0]
final const val OpticalSize // com.compose.sdl.icons/MaterialIconAxisDefaults.OpticalSize|{}OpticalSize[0]
final fun <get-OpticalSize>(): kotlin/Int // com.compose.sdl.icons/MaterialIconAxisDefaults.OpticalSize.<get-OpticalSize>|<get-OpticalSize>(){}[0]
final const val Weight // com.compose.sdl.icons/MaterialIconAxisDefaults.Weight|{}Weight[0]
final fun <get-Weight>(): kotlin/Int // com.compose.sdl.icons/MaterialIconAxisDefaults.Weight.<get-Weight>|<get-Weight>(){}[0]
}
final object com.compose.sdl.widgets/SplitPaneDefaults { // com.compose.sdl.widgets/SplitPaneDefaults|null[0]
final val DividerThickness // com.compose.sdl.widgets/SplitPaneDefaults.DividerThickness|{}DividerThickness[0]
final fun <get-DividerThickness>(): androidx.compose.ui.unit/Dp // com.compose.sdl.widgets/SplitPaneDefaults.DividerThickness.<get-DividerThickness>|<get-DividerThickness>(){}[0]
@@ -2220,7 +2209,6 @@ final val androidx.compose.foundation/androidx_compose_foundation_MarqueeDefault
final val androidx.compose.foundation/androidx_compose_foundation_MutatorMutex$stableprop // androidx.compose.foundation/androidx_compose_foundation_MutatorMutex$stableprop|#static{}androidx_compose_foundation_MutatorMutex$stableprop[0]
final val androidx.compose.foundation/androidx_compose_foundation_ScrollState$stableprop // androidx.compose.foundation/androidx_compose_foundation_ScrollState$stableprop|#static{}androidx_compose_foundation_ScrollState$stableprop[0]
final val com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop // com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop|#static{}com_compose_sdl_icons_IconDefaults$stableprop[0]
final val com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop // com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop|#static{}com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop[0]
final val com.compose.sdl.scrollbar/LocalScrollbarStyle // com.compose.sdl.scrollbar/LocalScrollbarStyle|{}LocalScrollbarStyle[0]
final fun <get-LocalScrollbarStyle>(): androidx.compose.runtime/ProvidableCompositionLocal<com.compose.sdl.scrollbar/ScrollbarStyle> // com.compose.sdl.scrollbar/LocalScrollbarStyle.<get-LocalScrollbarStyle>|<get-LocalScrollbarStyle>(){}[0]
final val com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop // com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop|#static{}com_compose_sdl_scrollbar_ScrollbarStyle$stableprop[0]
@@ -2294,6 +2282,8 @@ final fun (androidx.compose.ui.input.pointer/PointerEvent).androidx.compose.foun
final fun (androidx.compose.ui.input.pointer/PointerEvent).androidx.compose.foundation.gestures/calculateZoom(): kotlin/Float // androidx.compose.foundation.gestures/calculateZoom|calculateZoom@androidx.compose.ui.input.pointer.PointerEvent(){}[0]
final fun (androidx.compose.ui.text/AnnotatedString.Builder).androidx.compose.foundation.text/appendInlineContent(kotlin/String, kotlin/String = ...) // androidx.compose.foundation.text/appendInlineContent|appendInlineContent@androidx.compose.ui.text.AnnotatedString.Builder(kotlin.String;kotlin.String){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.content/contentReceiver(androidx.compose.foundation.content/ReceiveContentListener): androidx.compose.ui/Modifier // androidx.compose.foundation.content/contentReceiver|contentReceiver@androidx.compose.ui.Modifier(androidx.compose.foundation.content.ReceiveContentListener){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.draganddrop/dragAndDropSource(kotlin/Function1<androidx.compose.ui.geometry/Offset, androidx.compose.ui.draganddrop/DragAndDropTransferData?>): androidx.compose.ui/Modifier // androidx.compose.foundation.draganddrop/dragAndDropSource|dragAndDropSource@androidx.compose.ui.Modifier(kotlin.Function1<androidx.compose.ui.geometry.Offset,androidx.compose.ui.draganddrop.DragAndDropTransferData?>){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.draganddrop/dragAndDropSource(kotlin/Function1<androidx.compose.ui.graphics.drawscope/DrawScope, kotlin/Unit>, kotlin/Function1<androidx.compose.ui.geometry/Offset, androidx.compose.ui.draganddrop/DragAndDropTransferData?>): androidx.compose.ui/Modifier // androidx.compose.foundation.draganddrop/dragAndDropSource|dragAndDropSource@androidx.compose.ui.Modifier(kotlin.Function1<androidx.compose.ui.graphics.drawscope.DrawScope,kotlin.Unit>;kotlin.Function1<androidx.compose.ui.geometry.Offset,androidx.compose.ui.draganddrop.DragAndDropTransferData?>){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.draganddrop/dragAndDropTarget(kotlin/Function1<androidx.compose.ui.draganddrop/DragAndDropEvent, kotlin/Boolean>, androidx.compose.ui.draganddrop/DragAndDropTarget): androidx.compose.ui/Modifier // androidx.compose.foundation.draganddrop/dragAndDropTarget|dragAndDropTarget@androidx.compose.ui.Modifier(kotlin.Function1<androidx.compose.ui.draganddrop.DragAndDropEvent,kotlin.Boolean>;androidx.compose.ui.draganddrop.DragAndDropTarget){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.gestures/draggable(androidx.compose.foundation.gestures/DraggableState, androidx.compose.foundation.gestures/Orientation, kotlin/Boolean = ..., androidx.compose.foundation.interaction/MutableInteractionSource? = ..., kotlin/Boolean = ..., kotlin.coroutines/SuspendFunction2<kotlinx.coroutines/CoroutineScope, androidx.compose.ui.geometry/Offset, kotlin/Unit> = ..., kotlin.coroutines/SuspendFunction2<kotlinx.coroutines/CoroutineScope, kotlin/Float, kotlin/Unit> = ..., kotlin/Boolean = ...): androidx.compose.ui/Modifier // androidx.compose.foundation.gestures/draggable|draggable@androidx.compose.ui.Modifier(androidx.compose.foundation.gestures.DraggableState;androidx.compose.foundation.gestures.Orientation;kotlin.Boolean;androidx.compose.foundation.interaction.MutableInteractionSource?;kotlin.Boolean;kotlin.coroutines.SuspendFunction2<kotlinx.coroutines.CoroutineScope,androidx.compose.ui.geometry.Offset,kotlin.Unit>;kotlin.coroutines.SuspendFunction2<kotlinx.coroutines.CoroutineScope,kotlin.Float,kotlin.Unit>;kotlin.Boolean){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.foundation.gestures/draggable2D(androidx.compose.foundation.gestures/Draggable2DState, kotlin/Boolean = ..., androidx.compose.foundation.interaction/MutableInteractionSource? = ..., kotlin/Boolean = ..., kotlin/Function1<androidx.compose.ui.geometry/Offset, kotlin/Unit> = ..., kotlin/Function1<androidx.compose.ui.unit/Velocity, kotlin/Unit> = ..., kotlin/Boolean = ...): androidx.compose.ui/Modifier // androidx.compose.foundation.gestures/draggable2D|draggable2D@androidx.compose.ui.Modifier(androidx.compose.foundation.gestures.Draggable2DState;kotlin.Boolean;androidx.compose.foundation.interaction.MutableInteractionSource?;kotlin.Boolean;kotlin.Function1<androidx.compose.ui.geometry.Offset,kotlin.Unit>;kotlin.Function1<androidx.compose.ui.unit.Velocity,kotlin.Unit>;kotlin.Boolean){}[0]
@@ -2620,14 +2610,13 @@ final fun androidx.compose.foundation/rememberBasicTooltipState(kotlin/Boolean,
final fun androidx.compose.foundation/rememberOverscrollEffect(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.foundation/OverscrollEffect? // androidx.compose.foundation/rememberOverscrollEffect|rememberOverscrollEffect(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun androidx.compose.foundation/rememberScrollState(kotlin/Int, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.foundation/ScrollState // androidx.compose.foundation/rememberScrollState|rememberScrollState(kotlin.Int;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun com.compose.sdl.icons/IconFontIcon(kotlin/Int, kotlin/String, kotlin/String?, androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Color, androidx.compose.ui.unit/Dp, kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.icons/IconFontIcon|IconFontIcon(kotlin.Int;kotlin.String;kotlin.String?;androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Color;androidx.compose.ui.unit.Dp;kotlin.collections.List<androidx.compose.ui.text.font.FontVariation.Setting>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun com.compose.sdl.icons/MaterialIconAxes(kotlin/Float = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ...): kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting> // com.compose.sdl.icons/MaterialIconAxes|MaterialIconAxes(kotlin.Float;kotlin.Int;kotlin.Int;kotlin.Int){}[0]
final fun com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop_getter(): kotlin/Int // com.compose.sdl.icons/com_compose_sdl_icons_IconDefaults$stableprop_getter|com_compose_sdl_icons_IconDefaults$stableprop_getter(){}[0]
final fun com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop_getter(): kotlin/Int // com.compose.sdl.icons/com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop_getter|com_compose_sdl_icons_MaterialIconAxisDefaults$stableprop_getter(){}[0]
final fun com.compose.sdl.modifier/rememberMutableInteractionSource(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.foundation.interaction/MutableInteractionSource // com.compose.sdl.modifier/rememberMutableInteractionSource|rememberMutableInteractionSource(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun com.compose.sdl.scrollbar/HorizontalScrollbar(com.compose.sdl.scrollbar/ScrollbarAdapter, androidx.compose.ui/Modifier?, kotlin/Boolean, com.compose.sdl.scrollbar/ScrollbarStyle?, androidx.compose.foundation.interaction/MutableInteractionSource?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.scrollbar/HorizontalScrollbar|HorizontalScrollbar(com.compose.sdl.scrollbar.ScrollbarAdapter;androidx.compose.ui.Modifier?;kotlin.Boolean;com.compose.sdl.scrollbar.ScrollbarStyle?;androidx.compose.foundation.interaction.MutableInteractionSource?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun com.compose.sdl.scrollbar/VerticalScrollbar(com.compose.sdl.scrollbar/ScrollbarAdapter, androidx.compose.ui/Modifier?, kotlin/Boolean, com.compose.sdl.scrollbar/ScrollbarStyle?, androidx.compose.foundation.interaction/MutableInteractionSource?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.scrollbar/VerticalScrollbar|VerticalScrollbar(com.compose.sdl.scrollbar.ScrollbarAdapter;androidx.compose.ui.Modifier?;kotlin.Boolean;com.compose.sdl.scrollbar.ScrollbarStyle?;androidx.compose.foundation.interaction.MutableInteractionSource?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop_getter(): kotlin/Int // com.compose.sdl.scrollbar/com_compose_sdl_scrollbar_ScrollbarStyle$stableprop_getter|com_compose_sdl_scrollbar_ScrollbarStyle$stableprop_getter(){}[0]
final fun com.compose.sdl.scrollbar/defaultScrollbarStyle(): com.compose.sdl.scrollbar/ScrollbarStyle // com.compose.sdl.scrollbar/defaultScrollbarStyle|defaultScrollbarStyle(){}[0]
final fun com.compose.sdl.scrollbar/rememberScrollbarAdapter(androidx.compose.foundation.lazy/LazyListState, androidx.compose.runtime/Composer?, kotlin/Int): com.compose.sdl.scrollbar/ScrollbarAdapter // com.compose.sdl.scrollbar/rememberScrollbarAdapter|rememberScrollbarAdapter(androidx.compose.foundation.lazy.LazyListState;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun com.compose.sdl.scrollbar/rememberScrollbarAdapter(androidx.compose.foundation/ScrollState, androidx.compose.runtime/Composer?, kotlin/Int): com.compose.sdl.scrollbar/ScrollbarAdapter // com.compose.sdl.scrollbar/rememberScrollbarAdapter|rememberScrollbarAdapter(androidx.compose.foundation.ScrollState;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun com.compose.sdl.text/IconText(kotlin/String, kotlin/String, androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Color, androidx.compose.ui.unit/TextUnit, androidx.compose.ui.text.style/TextAlign, kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.text/IconText|IconText(kotlin.String;kotlin.String;androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Color;androidx.compose.ui.unit.TextUnit;androidx.compose.ui.text.style.TextAlign;kotlin.collections.List<androidx.compose.ui.text.font.FontVariation.Setting>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
final fun com.compose.sdl.text/IconText(kotlin/String, kotlin/String, androidx.compose.ui/Modifier?, androidx.compose.ui.graphics/Color, androidx.compose.ui.unit/TextUnit, androidx.compose.ui.text.style/TextAlign?, kotlin.collections/List<androidx.compose.ui.text.font/FontVariation.Setting>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // com.compose.sdl.text/IconText|IconText(kotlin.String;kotlin.String;androidx.compose.ui.Modifier?;androidx.compose.ui.graphics.Color;androidx.compose.ui.unit.TextUnit;androidx.compose.ui.text.style.TextAlign?;kotlin.collections.List<androidx.compose.ui.text.font.FontVariation.Setting>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
@@ -30,9 +30,12 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.awaitEachGesture
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import kotlin.math.abs
import kotlin.math.roundToInt
// ==================
@@ -141,6 +144,19 @@ private class LazyListScrollbarAdapter(private val state: LazyListState) : Scrol
get() = (state.layoutInfo.viewportEndOffset - state.layoutInfo.viewportStartOffset).toDouble()
override suspend fun scrollTo(scrollOffset: Double) {
val vDistance = scrollOffset - this.scrollOffset
// Within a viewport, scroll by EXACT pixels so a drag stays smooth. A lazy
// list's pixel geometry is only ESTIMATED (average visible item size), and
// that estimate drifts as differently-sized items scroll through the
// viewport — so index-snapping every frame makes the thumb jump. scrollBy
// sidesteps the estimate entirely. This is what Compose Desktop's own
// LazyListScrollbarAdapter does, and for the same reason.
if (abs(vDistance) <= viewportSize) {
state.scrollBy(vDistance.toFloat())
return
}
// Far jump (track-click paging past a viewport): no exact geometry to lean
// on, so estimate an index/offset from the average and snap to it.
val vAvg = averageItemSize()
if (vAvg <= 0.0) return
val vTarget = scrollOffset.coerceAtLeast(0.0)
@@ -193,7 +209,6 @@ private fun Scrollbar(
val vHoverSource = remember { MutableInteractionSource() }
val vHovered by vHoverSource.collectIsHoveredAsState()
var vDraggingThumb by remember { mutableStateOf(false) }
var vGrab by remember { mutableStateOf(0) }
// onSizeChanged reports PHYSICAL pixels (Option-B density flow), so every
// int/px carried through here — vTrackPx, vThumbLen, vThumbPos — is in
// physical pixels. Passing them into `.dp` doubles again through
@@ -230,15 +245,6 @@ private fun Scrollbar(
val vRawPos = if (vTravel <= 0) 0 else (vTravel * (vOffset / vMaxScroll)).roundToInt()
val vThumbPos = (if (reverseLayout) vTravel - vRawPos else vRawPos).coerceIn(0, vTravel)
// ============
// Map a track-relative position to a scroll offset and apply it.
fun scrollToTrackPos(inThumbTop: Int) {
if (vTravel <= 0) return
val vPos = inThumbTop.coerceIn(0, vTravel)
val vFrac = (if (reverseLayout) vTravel - vPos else vPos).toDouble() / vTravel
vScope.launch { adapter.scrollTo(vFrac * vMaxScroll) }
}
val vThumbLenDp = with(vDensity) { vThumbLen.toDp() }
val vThumbMod = (
if (isVertical) Modifier.offset { IntOffset(0, vThumbPos) }.width(style.thickness).height(vThumbLenDp)
@@ -251,33 +257,78 @@ private fun Scrollbar(
// ============
// Drag the thumb / page on track click — handled on the track so the
// coordinates have a stable (non-moving) origin.
// coordinates have a stable (non-moving) origin. The press is CONSUMED:
// a scrollbar owns the pointer input it handles, so content sharing this
// region (the scrollable beneath, or a parent that also reads pointer
// input) never reacts to the same press. Geometry is read LIVE from the
// adapter at press time — not from the captured render metrics above,
// which go stale between pointerInput relaunches — so a grab after a
// wheel-scroll still hit-tests against the thumb's current position.
Box(
modifier = Modifier
.matchTrackSize(isVertical, with(vDensity) { vTrackPx.toDp() }, style.thickness)
.pointerInput(isVertical, adapter, vTrackPx) {
detectDragGestures(
onDragStart = { offset ->
val vPress = (if (isVertical) offset.y else offset.x).toInt()
if (vPress in vThumbPos..(vThumbPos + vThumbLen)) {
vDraggingThumb = true
vGrab = vPress - vThumbPos
} else {
// Page toward the click by one viewport.
vDraggingThumb = false
val vDir = if (vPress < vThumbPos) -1.0 else 1.0
vScope.launch { adapter.scrollTo(vOffset + vDir * vViewport) }
}
},
onDrag = { change, _ ->
.pointerInput(isVertical, adapter, vTrackPx, reverseLayout) {
awaitEachGesture {
val vDown = awaitFirstDown(requireUnconsumed = false)
vDown.consume()
// Live geometry — stable for the drag's duration (content /
// viewport / track sizes don't change mid-drag).
val vContentPx = adapter.contentSize
val vViewportPx = adapter.viewportSize
val vMaxScrollPx = vContentPx - vViewportPx
if (vMaxScrollPx <= 0.0 || vTrackPx <= 0) return@awaitEachGesture
val vMinLen = style.minimalHeight.value.toInt()
val vLen = (vTrackPx * (vViewportPx / vContentPx)).roundToInt()
.coerceIn(vMinLen.coerceAtMost(vTrackPx), vTrackPx)
val vTravelPx = vTrackPx - vLen
val vRaw = if (vTravelPx <= 0) 0
else (vTravelPx * (adapter.scrollOffset / vMaxScrollPx)).roundToInt()
val vPos = (if (reverseLayout) vTravelPx - vRaw else vRaw).coerceIn(0, vTravelPx)
// Map a track-relative thumb-top to a scroll offset. The
// target uses the LIVE max scroll (read fresh each move),
// not the press-time value — the adapter compares it against
// its live scrollOffset, and mixing a stale scale with a live
// one makes the delta run away (grab at the bottom, drag up,
// and the list overshoots to the middle).
fun scrollToTrackPos(inThumbTop: Int) {
if (vTravelPx <= 0) return
val vLiveMax = adapter.contentSize - adapter.viewportSize
if (vLiveMax <= 0.0) return
val vClamped = inThumbTop.coerceIn(0, vTravelPx)
val vFrac = (if (reverseLayout) vTravelPx - vClamped else vClamped).toDouble() / vTravelPx
vScope.launch { adapter.scrollTo(vFrac * vLiveMax) }
}
val vPress = (if (isVertical) vDown.position.y else vDown.position.x).toInt()
val vGrab: Int
if (vPress in vPos..(vPos + vLen)) {
vDraggingThumb = true
vGrab = vPress - vPos
} else {
// Page toward the click by one viewport.
vDraggingThumb = false
vGrab = 0
val vDir = if (vPress < vPos) -1.0 else 1.0
vScope.launch { adapter.scrollTo(adapter.scrollOffset + vDir * vViewportPx) }
}
// Follow the pressed pointer to release, consuming every
// change so the interaction can't leak. Only a thumb grab
// drags-to-scroll; a track press just consumes.
do {
val vEvent = awaitPointerEvent()
val vChange = vEvent.changes.firstOrNull { it.id == vDown.id } ?: break
if (vDraggingThumb) {
val vCur = (if (isVertical) change.position.y else change.position.x).toInt()
val vCur = (if (isVertical) vChange.position.y else vChange.position.x).toInt()
scrollToTrackPos(vCur - vGrab)
}
},
onDragEnd = { vDraggingThumb = false },
onDragCancel = { vDraggingThumb = false },
)
vChange.consume()
} while (vEvent.changes.any { it.id == vDown.id && it.pressed })
vDraggingThumb = false
}
}
)
}
@@ -0,0 +1,42 @@
// Klib ABI Dump
// Targets: [linuxArm64, linuxX64, macosArm64, mingwX64]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
// - Show declarations: true
// Library unique name: <com.bitsycore.compose.sdl:material-ripple>
abstract interface androidx.compose.material.ripple/RippleTheme { // androidx.compose.material.ripple/RippleTheme|null[0]
abstract fun defaultColor(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.ui.graphics/Color // androidx.compose.material.ripple/RippleTheme.defaultColor|defaultColor(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
abstract fun rippleAlpha(androidx.compose.runtime/Composer?, kotlin/Int): androidx.compose.material.ripple/RippleAlpha // androidx.compose.material.ripple/RippleTheme.rippleAlpha|rippleAlpha(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final object Companion { // androidx.compose.material.ripple/RippleTheme.Companion|null[0]
final fun defaultRippleAlpha(androidx.compose.ui.graphics/Color, kotlin/Boolean): androidx.compose.material.ripple/RippleAlpha // androidx.compose.material.ripple/RippleTheme.Companion.defaultRippleAlpha|defaultRippleAlpha(androidx.compose.ui.graphics.Color;kotlin.Boolean){}[0]
final fun defaultRippleColor(androidx.compose.ui.graphics/Color, kotlin/Boolean): androidx.compose.ui.graphics/Color // androidx.compose.material.ripple/RippleTheme.Companion.defaultRippleColor|defaultRippleColor(androidx.compose.ui.graphics.Color;kotlin.Boolean){}[0]
}
}
final class androidx.compose.material.ripple/RippleAlpha { // androidx.compose.material.ripple/RippleAlpha|null[0]
constructor <init>(kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Float) // androidx.compose.material.ripple/RippleAlpha.<init>|<init>(kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Float){}[0]
final val draggedAlpha // androidx.compose.material.ripple/RippleAlpha.draggedAlpha|{}draggedAlpha[0]
final fun <get-draggedAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.draggedAlpha.<get-draggedAlpha>|<get-draggedAlpha>(){}[0]
final val focusedAlpha // androidx.compose.material.ripple/RippleAlpha.focusedAlpha|{}focusedAlpha[0]
final fun <get-focusedAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.focusedAlpha.<get-focusedAlpha>|<get-focusedAlpha>(){}[0]
final val hoveredAlpha // androidx.compose.material.ripple/RippleAlpha.hoveredAlpha|{}hoveredAlpha[0]
final fun <get-hoveredAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.hoveredAlpha.<get-hoveredAlpha>|<get-hoveredAlpha>(){}[0]
final val pressedAlpha // androidx.compose.material.ripple/RippleAlpha.pressedAlpha|{}pressedAlpha[0]
final fun <get-pressedAlpha>(): kotlin/Float // androidx.compose.material.ripple/RippleAlpha.pressedAlpha.<get-pressedAlpha>|<get-pressedAlpha>(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // androidx.compose.material.ripple/RippleAlpha.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // androidx.compose.material.ripple/RippleAlpha.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // androidx.compose.material.ripple/RippleAlpha.toString|toString(){}[0]
}
final val androidx.compose.material.ripple/LocalRippleTheme // androidx.compose.material.ripple/LocalRippleTheme|{}LocalRippleTheme[0]
final fun <get-LocalRippleTheme>(): androidx.compose.runtime/ProvidableCompositionLocal<androidx.compose.material.ripple/RippleTheme> // androidx.compose.material.ripple/LocalRippleTheme.<get-LocalRippleTheme>|<get-LocalRippleTheme>(){}[0]
final val androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop // androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop|#static{}androidx_compose_material_ripple_RippleAlpha$stableprop[0]
final fun androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop_getter(): kotlin/Int // androidx.compose.material.ripple/androidx_compose_material_ripple_RippleAlpha$stableprop_getter|androidx_compose_material_ripple_RippleAlpha$stableprop_getter(){}[0]
final fun androidx.compose.material.ripple/createRippleModifierNode(androidx.compose.foundation.interaction/InteractionSource, kotlin/Boolean, androidx.compose.ui.unit/Dp, androidx.compose.ui.graphics/ColorProducer, kotlin/Function0<androidx.compose.material.ripple/RippleAlpha>): androidx.compose.ui.node/DelegatableNode // androidx.compose.material.ripple/createRippleModifierNode|createRippleModifierNode(androidx.compose.foundation.interaction.InteractionSource;kotlin.Boolean;androidx.compose.ui.unit.Dp;androidx.compose.ui.graphics.ColorProducer;kotlin.Function0<androidx.compose.material.ripple.RippleAlpha>){}[0]
final fun androidx.compose.material.ripple/rememberRipple(kotlin/Boolean, androidx.compose.ui.unit/Dp, androidx.compose.ui.graphics/Color, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int): androidx.compose.foundation/Indication // androidx.compose.material.ripple/rememberRipple|rememberRipple(kotlin.Boolean;androidx.compose.ui.unit.Dp;androidx.compose.ui.graphics.Color;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){}[0]
File diff suppressed because it is too large Load Diff
@@ -146,6 +146,8 @@ fun nativeComposeApp(content: @Composable ApplicationScope.() -> Unit) {
// ============
// Main loop
var vGcLastTicks = SDL_GetTicks()
var vRenderedSinceGc = false
while (!runtime.exitRequested) {
Snapshot.sendApplyNotifications()
@@ -224,6 +226,23 @@ fun nativeComposeApp(content: @Composable ApplicationScope.() -> Unit) {
SDL_WaitEventTimeout(null, 10)
for (vW in runtime.windows) vW.resetFpsWindow()
}
// ============
// Native-memory nudge. Renderer resources (Skia surfaces / images /
// fonts, SDL textures) are freed by Cleaners that only run when the
// Kotlin/Native GC collects — and a Compose app's Kotlin heap is
// small enough that the allocation-driven scheduler can starve them
// for minutes while the NATIVE heap balloons (issue #2: memory
// "never released" while navigating). Collect periodically, only
// after rendering activity, between frames; costs ~ms at these
// heap sizes and keeps RSS tracking real usage.
if (vAnyRendered) vRenderedSinceGc = true
val vNowTicks = SDL_GetTicks()
if (vRenderedSinceGc && vNowTicks - vGcLastTicks >= 10_000uL) {
vGcLastTicks = vNowTicks
vRenderedSinceGc = false
collectNativeGarbage()
}
}
// ============
@@ -243,6 +262,11 @@ fun nativeComposeApp(content: @Composable ApplicationScope.() -> Unit) {
SDL_Quit()
}
/* Trigger a Kotlin/Native GC so Cleaner-managed renderer resources release
their native memory (see the main loop's native-memory nudge). */
@OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
private fun collectNativeGarbage() = kotlin.native.runtime.GC.collect()
/* Single-window compatibility wrapper — the pre-multi-window entry point.
Closing the window exits the app, exactly as before. */
fun nativeComposeWindow(
@@ -0,0 +1,255 @@
// Klib ABI Dump
// Targets: [linuxArm64, linuxX64, macosArm64, mingwX64]
// Rendering settings:
// - Signature version: 2
// - Show manifest properties: true
// - Show declarations: true
// Library unique name: <com.bitsycore.compose.sdl:ui-tooling-preview>
open annotation class androidx.compose.ui.tooling.preview/AndroidUiMode : kotlin/Annotation { // androidx.compose.ui.tooling.preview/AndroidUiMode|null[0]
constructor <init>() // androidx.compose.ui.tooling.preview/AndroidUiMode.<init>|<init>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/Preview : kotlin/Annotation { // androidx.compose.ui.tooling.preview/Preview|null[0]
constructor <init>(kotlin/String = ..., kotlin/String = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/String = ..., kotlin/Float = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Long = ..., kotlin/Int = ..., kotlin/String = ..., kotlin/Int = ...) // androidx.compose.ui.tooling.preview/Preview.<init>|<init>(kotlin.String;kotlin.String;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.String;kotlin.Float;kotlin.Boolean;kotlin.Boolean;kotlin.Long;kotlin.Int;kotlin.String;kotlin.Int){}[0]
final val apiLevel // androidx.compose.ui.tooling.preview/Preview.apiLevel|{}apiLevel[0]
final fun <get-apiLevel>(): kotlin/Int // androidx.compose.ui.tooling.preview/Preview.apiLevel.<get-apiLevel>|<get-apiLevel>(){}[0]
final val backgroundColor // androidx.compose.ui.tooling.preview/Preview.backgroundColor|{}backgroundColor[0]
final fun <get-backgroundColor>(): kotlin/Long // androidx.compose.ui.tooling.preview/Preview.backgroundColor.<get-backgroundColor>|<get-backgroundColor>(){}[0]
final val device // androidx.compose.ui.tooling.preview/Preview.device|{}device[0]
final fun <get-device>(): kotlin/String // androidx.compose.ui.tooling.preview/Preview.device.<get-device>|<get-device>(){}[0]
final val fontScale // androidx.compose.ui.tooling.preview/Preview.fontScale|{}fontScale[0]
final fun <get-fontScale>(): kotlin/Float // androidx.compose.ui.tooling.preview/Preview.fontScale.<get-fontScale>|<get-fontScale>(){}[0]
final val group // androidx.compose.ui.tooling.preview/Preview.group|{}group[0]
final fun <get-group>(): kotlin/String // androidx.compose.ui.tooling.preview/Preview.group.<get-group>|<get-group>(){}[0]
final val heightDp // androidx.compose.ui.tooling.preview/Preview.heightDp|{}heightDp[0]
final fun <get-heightDp>(): kotlin/Int // androidx.compose.ui.tooling.preview/Preview.heightDp.<get-heightDp>|<get-heightDp>(){}[0]
final val locale // androidx.compose.ui.tooling.preview/Preview.locale|{}locale[0]
final fun <get-locale>(): kotlin/String // androidx.compose.ui.tooling.preview/Preview.locale.<get-locale>|<get-locale>(){}[0]
final val name // androidx.compose.ui.tooling.preview/Preview.name|{}name[0]
final fun <get-name>(): kotlin/String // androidx.compose.ui.tooling.preview/Preview.name.<get-name>|<get-name>(){}[0]
final val showBackground // androidx.compose.ui.tooling.preview/Preview.showBackground|{}showBackground[0]
final fun <get-showBackground>(): kotlin/Boolean // androidx.compose.ui.tooling.preview/Preview.showBackground.<get-showBackground>|<get-showBackground>(){}[0]
final val showSystemUi // androidx.compose.ui.tooling.preview/Preview.showSystemUi|{}showSystemUi[0]
final fun <get-showSystemUi>(): kotlin/Boolean // androidx.compose.ui.tooling.preview/Preview.showSystemUi.<get-showSystemUi>|<get-showSystemUi>(){}[0]
final val uiMode // androidx.compose.ui.tooling.preview/Preview.uiMode|{}uiMode[0]
final fun <get-uiMode>(): kotlin/Int // androidx.compose.ui.tooling.preview/Preview.uiMode.<get-uiMode>|<get-uiMode>(){}[0]
final val wallpaper // androidx.compose.ui.tooling.preview/Preview.wallpaper|{}wallpaper[0]
final fun <get-wallpaper>(): kotlin/Int // androidx.compose.ui.tooling.preview/Preview.wallpaper.<get-wallpaper>|<get-wallpaper>(){}[0]
final val widthDp // androidx.compose.ui.tooling.preview/Preview.widthDp|{}widthDp[0]
final fun <get-widthDp>(): kotlin/Int // androidx.compose.ui.tooling.preview/Preview.widthDp.<get-widthDp>|<get-widthDp>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/PreviewDynamicColors : kotlin/Annotation { // androidx.compose.ui.tooling.preview/PreviewDynamicColors|null[0]
constructor <init>() // androidx.compose.ui.tooling.preview/PreviewDynamicColors.<init>|<init>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/PreviewFontScale : kotlin/Annotation { // androidx.compose.ui.tooling.preview/PreviewFontScale|null[0]
constructor <init>() // androidx.compose.ui.tooling.preview/PreviewFontScale.<init>|<init>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/PreviewLightDark : kotlin/Annotation { // androidx.compose.ui.tooling.preview/PreviewLightDark|null[0]
constructor <init>() // androidx.compose.ui.tooling.preview/PreviewLightDark.<init>|<init>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/PreviewParameter : kotlin/Annotation { // androidx.compose.ui.tooling.preview/PreviewParameter|null[0]
constructor <init>(kotlin.reflect/KClass<out androidx.compose.ui.tooling.preview/PreviewParameterProvider<*>>, kotlin/Int = ...) // androidx.compose.ui.tooling.preview/PreviewParameter.<init>|<init>(kotlin.reflect.KClass<out|androidx.compose.ui.tooling.preview.PreviewParameterProvider<*>>;kotlin.Int){}[0]
final val limit // androidx.compose.ui.tooling.preview/PreviewParameter.limit|{}limit[0]
final fun <get-limit>(): kotlin/Int // androidx.compose.ui.tooling.preview/PreviewParameter.limit.<get-limit>|<get-limit>(){}[0]
final val provider // androidx.compose.ui.tooling.preview/PreviewParameter.provider|{}provider[0]
final fun <get-provider>(): kotlin.reflect/KClass<out androidx.compose.ui.tooling.preview/PreviewParameterProvider<*>> // androidx.compose.ui.tooling.preview/PreviewParameter.provider.<get-provider>|<get-provider>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/PreviewScreenSizes : kotlin/Annotation { // androidx.compose.ui.tooling.preview/PreviewScreenSizes|null[0]
constructor <init>() // androidx.compose.ui.tooling.preview/PreviewScreenSizes.<init>|<init>(){}[0]
}
open annotation class androidx.compose.ui.tooling.preview/PreviewWrapper : kotlin/Annotation { // androidx.compose.ui.tooling.preview/PreviewWrapper|null[0]
constructor <init>(kotlin.reflect/KClass<out androidx.compose.ui.tooling.preview/PreviewWrapperProvider>) // androidx.compose.ui.tooling.preview/PreviewWrapper.<init>|<init>(kotlin.reflect.KClass<out|androidx.compose.ui.tooling.preview.PreviewWrapperProvider>){}[0]
final val wrapper // androidx.compose.ui.tooling.preview/PreviewWrapper.wrapper|{}wrapper[0]
final fun <get-wrapper>(): kotlin.reflect/KClass<out androidx.compose.ui.tooling.preview/PreviewWrapperProvider> // androidx.compose.ui.tooling.preview/PreviewWrapper.wrapper.<get-wrapper>|<get-wrapper>(){}[0]
}
abstract interface <#A: kotlin/Any?> androidx.compose.ui.tooling.preview/PreviewParameterProvider { // androidx.compose.ui.tooling.preview/PreviewParameterProvider|null[0]
abstract val values // androidx.compose.ui.tooling.preview/PreviewParameterProvider.values|{}values[0]
abstract fun <get-values>(): kotlin.sequences/Sequence<#A> // androidx.compose.ui.tooling.preview/PreviewParameterProvider.values.<get-values>|<get-values>(){}[0]
open val count // androidx.compose.ui.tooling.preview/PreviewParameterProvider.count|{}count[0]
open fun <get-count>(): kotlin/Int // androidx.compose.ui.tooling.preview/PreviewParameterProvider.count.<get-count>|<get-count>(){}[0]
open fun getDisplayName(kotlin/Int): kotlin/String? // androidx.compose.ui.tooling.preview/PreviewParameterProvider.getDisplayName|getDisplayName(kotlin.Int){}[0]
}
abstract interface androidx.compose.ui.tooling.preview/PreviewWrapperProvider { // androidx.compose.ui.tooling.preview/PreviewWrapperProvider|null[0]
abstract fun Wrap(kotlin/Function2<androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>, androidx.compose.runtime/Composer?, kotlin/Int) // androidx.compose.ui.tooling.preview/PreviewWrapperProvider.Wrap|Wrap(kotlin.Function2<androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
}
open class <#A: kotlin/Any?> androidx.compose.ui.tooling.preview.datasource/CollectionPreviewParameterProvider : androidx.compose.ui.tooling.preview/PreviewParameterProvider<#A> { // androidx.compose.ui.tooling.preview.datasource/CollectionPreviewParameterProvider|null[0]
constructor <init>(kotlin.collections/Collection<#A>) // androidx.compose.ui.tooling.preview.datasource/CollectionPreviewParameterProvider.<init>|<init>(kotlin.collections.Collection<1:0>){}[0]
open val values // androidx.compose.ui.tooling.preview.datasource/CollectionPreviewParameterProvider.values|{}values[0]
open fun <get-values>(): kotlin.sequences/Sequence<#A> // androidx.compose.ui.tooling.preview.datasource/CollectionPreviewParameterProvider.values.<get-values>|<get-values>(){}[0]
}
open class androidx.compose.ui.tooling.preview.datasource/LoremIpsum : androidx.compose.ui.tooling.preview/PreviewParameterProvider<kotlin/String> { // androidx.compose.ui.tooling.preview.datasource/LoremIpsum|null[0]
constructor <init>() // androidx.compose.ui.tooling.preview.datasource/LoremIpsum.<init>|<init>(){}[0]
constructor <init>(kotlin/Int) // androidx.compose.ui.tooling.preview.datasource/LoremIpsum.<init>|<init>(kotlin.Int){}[0]
open val values // androidx.compose.ui.tooling.preview.datasource/LoremIpsum.values|{}values[0]
open fun <get-values>(): kotlin.sequences/Sequence<kotlin/String> // androidx.compose.ui.tooling.preview.datasource/LoremIpsum.values.<get-values>|<get-values>(){}[0]
}
final object androidx.compose.ui.tooling.preview/AndroidUiModes { // androidx.compose.ui.tooling.preview/AndroidUiModes|null[0]
final const val UI_MODE_NIGHT_MASK // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_MASK|{}UI_MODE_NIGHT_MASK[0]
final fun <get-UI_MODE_NIGHT_MASK>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_MASK.<get-UI_MODE_NIGHT_MASK>|<get-UI_MODE_NIGHT_MASK>(){}[0]
final const val UI_MODE_NIGHT_NO // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_NO|{}UI_MODE_NIGHT_NO[0]
final fun <get-UI_MODE_NIGHT_NO>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_NO.<get-UI_MODE_NIGHT_NO>|<get-UI_MODE_NIGHT_NO>(){}[0]
final const val UI_MODE_NIGHT_UNDEFINED // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_UNDEFINED|{}UI_MODE_NIGHT_UNDEFINED[0]
final fun <get-UI_MODE_NIGHT_UNDEFINED>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_UNDEFINED.<get-UI_MODE_NIGHT_UNDEFINED>|<get-UI_MODE_NIGHT_UNDEFINED>(){}[0]
final const val UI_MODE_NIGHT_YES // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_YES|{}UI_MODE_NIGHT_YES[0]
final fun <get-UI_MODE_NIGHT_YES>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_NIGHT_YES.<get-UI_MODE_NIGHT_YES>|<get-UI_MODE_NIGHT_YES>(){}[0]
final const val UI_MODE_TYPE_APPLIANCE // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_APPLIANCE|{}UI_MODE_TYPE_APPLIANCE[0]
final fun <get-UI_MODE_TYPE_APPLIANCE>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_APPLIANCE.<get-UI_MODE_TYPE_APPLIANCE>|<get-UI_MODE_TYPE_APPLIANCE>(){}[0]
final const val UI_MODE_TYPE_CAR // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_CAR|{}UI_MODE_TYPE_CAR[0]
final fun <get-UI_MODE_TYPE_CAR>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_CAR.<get-UI_MODE_TYPE_CAR>|<get-UI_MODE_TYPE_CAR>(){}[0]
final const val UI_MODE_TYPE_DESK // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_DESK|{}UI_MODE_TYPE_DESK[0]
final fun <get-UI_MODE_TYPE_DESK>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_DESK.<get-UI_MODE_TYPE_DESK>|<get-UI_MODE_TYPE_DESK>(){}[0]
final const val UI_MODE_TYPE_MASK // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_MASK|{}UI_MODE_TYPE_MASK[0]
final fun <get-UI_MODE_TYPE_MASK>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_MASK.<get-UI_MODE_TYPE_MASK>|<get-UI_MODE_TYPE_MASK>(){}[0]
final const val UI_MODE_TYPE_NORMAL // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_NORMAL|{}UI_MODE_TYPE_NORMAL[0]
final fun <get-UI_MODE_TYPE_NORMAL>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_NORMAL.<get-UI_MODE_TYPE_NORMAL>|<get-UI_MODE_TYPE_NORMAL>(){}[0]
final const val UI_MODE_TYPE_TELEVISION // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_TELEVISION|{}UI_MODE_TYPE_TELEVISION[0]
final fun <get-UI_MODE_TYPE_TELEVISION>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_TELEVISION.<get-UI_MODE_TYPE_TELEVISION>|<get-UI_MODE_TYPE_TELEVISION>(){}[0]
final const val UI_MODE_TYPE_UNDEFINED // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_UNDEFINED|{}UI_MODE_TYPE_UNDEFINED[0]
final fun <get-UI_MODE_TYPE_UNDEFINED>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_UNDEFINED.<get-UI_MODE_TYPE_UNDEFINED>|<get-UI_MODE_TYPE_UNDEFINED>(){}[0]
final const val UI_MODE_TYPE_VR_HEADSET // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_VR_HEADSET|{}UI_MODE_TYPE_VR_HEADSET[0]
final fun <get-UI_MODE_TYPE_VR_HEADSET>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_VR_HEADSET.<get-UI_MODE_TYPE_VR_HEADSET>|<get-UI_MODE_TYPE_VR_HEADSET>(){}[0]
final const val UI_MODE_TYPE_WATCH // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_WATCH|{}UI_MODE_TYPE_WATCH[0]
final fun <get-UI_MODE_TYPE_WATCH>(): kotlin/Int // androidx.compose.ui.tooling.preview/AndroidUiModes.UI_MODE_TYPE_WATCH.<get-UI_MODE_TYPE_WATCH>|<get-UI_MODE_TYPE_WATCH>(){}[0]
}
final object androidx.compose.ui.tooling.preview/Devices { // androidx.compose.ui.tooling.preview/Devices|null[0]
final const val AUTOMOTIVE_1024p // androidx.compose.ui.tooling.preview/Devices.AUTOMOTIVE_1024p|{}AUTOMOTIVE_1024p[0]
final fun <get-AUTOMOTIVE_1024p>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.AUTOMOTIVE_1024p.<get-AUTOMOTIVE_1024p>|<get-AUTOMOTIVE_1024p>(){}[0]
final const val DEFAULT // androidx.compose.ui.tooling.preview/Devices.DEFAULT|{}DEFAULT[0]
final fun <get-DEFAULT>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.DEFAULT.<get-DEFAULT>|<get-DEFAULT>(){}[0]
final const val DESKTOP // androidx.compose.ui.tooling.preview/Devices.DESKTOP|{}DESKTOP[0]
final fun <get-DESKTOP>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.DESKTOP.<get-DESKTOP>|<get-DESKTOP>(){}[0]
final const val FOLDABLE // androidx.compose.ui.tooling.preview/Devices.FOLDABLE|{}FOLDABLE[0]
final fun <get-FOLDABLE>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.FOLDABLE.<get-FOLDABLE>|<get-FOLDABLE>(){}[0]
final const val NEXUS_10 // androidx.compose.ui.tooling.preview/Devices.NEXUS_10|{}NEXUS_10[0]
final fun <get-NEXUS_10>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_10.<get-NEXUS_10>|<get-NEXUS_10>(){}[0]
final const val NEXUS_5 // androidx.compose.ui.tooling.preview/Devices.NEXUS_5|{}NEXUS_5[0]
final fun <get-NEXUS_5>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_5.<get-NEXUS_5>|<get-NEXUS_5>(){}[0]
final const val NEXUS_5X // androidx.compose.ui.tooling.preview/Devices.NEXUS_5X|{}NEXUS_5X[0]
final fun <get-NEXUS_5X>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_5X.<get-NEXUS_5X>|<get-NEXUS_5X>(){}[0]
final const val NEXUS_6 // androidx.compose.ui.tooling.preview/Devices.NEXUS_6|{}NEXUS_6[0]
final fun <get-NEXUS_6>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_6.<get-NEXUS_6>|<get-NEXUS_6>(){}[0]
final const val NEXUS_6P // androidx.compose.ui.tooling.preview/Devices.NEXUS_6P|{}NEXUS_6P[0]
final fun <get-NEXUS_6P>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_6P.<get-NEXUS_6P>|<get-NEXUS_6P>(){}[0]
final const val NEXUS_7 // androidx.compose.ui.tooling.preview/Devices.NEXUS_7|{}NEXUS_7[0]
final fun <get-NEXUS_7>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_7.<get-NEXUS_7>|<get-NEXUS_7>(){}[0]
final const val NEXUS_7_2013 // androidx.compose.ui.tooling.preview/Devices.NEXUS_7_2013|{}NEXUS_7_2013[0]
final fun <get-NEXUS_7_2013>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_7_2013.<get-NEXUS_7_2013>|<get-NEXUS_7_2013>(){}[0]
final const val NEXUS_9 // androidx.compose.ui.tooling.preview/Devices.NEXUS_9|{}NEXUS_9[0]
final fun <get-NEXUS_9>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.NEXUS_9.<get-NEXUS_9>|<get-NEXUS_9>(){}[0]
final const val PHONE // androidx.compose.ui.tooling.preview/Devices.PHONE|{}PHONE[0]
final fun <get-PHONE>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PHONE.<get-PHONE>|<get-PHONE>(){}[0]
final const val PIXEL // androidx.compose.ui.tooling.preview/Devices.PIXEL|{}PIXEL[0]
final fun <get-PIXEL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL.<get-PIXEL>|<get-PIXEL>(){}[0]
final const val PIXEL_2 // androidx.compose.ui.tooling.preview/Devices.PIXEL_2|{}PIXEL_2[0]
final fun <get-PIXEL_2>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_2.<get-PIXEL_2>|<get-PIXEL_2>(){}[0]
final const val PIXEL_2_XL // androidx.compose.ui.tooling.preview/Devices.PIXEL_2_XL|{}PIXEL_2_XL[0]
final fun <get-PIXEL_2_XL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_2_XL.<get-PIXEL_2_XL>|<get-PIXEL_2_XL>(){}[0]
final const val PIXEL_3 // androidx.compose.ui.tooling.preview/Devices.PIXEL_3|{}PIXEL_3[0]
final fun <get-PIXEL_3>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_3.<get-PIXEL_3>|<get-PIXEL_3>(){}[0]
final const val PIXEL_3A // androidx.compose.ui.tooling.preview/Devices.PIXEL_3A|{}PIXEL_3A[0]
final fun <get-PIXEL_3A>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_3A.<get-PIXEL_3A>|<get-PIXEL_3A>(){}[0]
final const val PIXEL_3A_XL // androidx.compose.ui.tooling.preview/Devices.PIXEL_3A_XL|{}PIXEL_3A_XL[0]
final fun <get-PIXEL_3A_XL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_3A_XL.<get-PIXEL_3A_XL>|<get-PIXEL_3A_XL>(){}[0]
final const val PIXEL_3_XL // androidx.compose.ui.tooling.preview/Devices.PIXEL_3_XL|{}PIXEL_3_XL[0]
final fun <get-PIXEL_3_XL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_3_XL.<get-PIXEL_3_XL>|<get-PIXEL_3_XL>(){}[0]
final const val PIXEL_4 // androidx.compose.ui.tooling.preview/Devices.PIXEL_4|{}PIXEL_4[0]
final fun <get-PIXEL_4>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_4.<get-PIXEL_4>|<get-PIXEL_4>(){}[0]
final const val PIXEL_4A // androidx.compose.ui.tooling.preview/Devices.PIXEL_4A|{}PIXEL_4A[0]
final fun <get-PIXEL_4A>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_4A.<get-PIXEL_4A>|<get-PIXEL_4A>(){}[0]
final const val PIXEL_4_XL // androidx.compose.ui.tooling.preview/Devices.PIXEL_4_XL|{}PIXEL_4_XL[0]
final fun <get-PIXEL_4_XL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_4_XL.<get-PIXEL_4_XL>|<get-PIXEL_4_XL>(){}[0]
final const val PIXEL_5 // androidx.compose.ui.tooling.preview/Devices.PIXEL_5|{}PIXEL_5[0]
final fun <get-PIXEL_5>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_5.<get-PIXEL_5>|<get-PIXEL_5>(){}[0]
final const val PIXEL_6 // androidx.compose.ui.tooling.preview/Devices.PIXEL_6|{}PIXEL_6[0]
final fun <get-PIXEL_6>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_6.<get-PIXEL_6>|<get-PIXEL_6>(){}[0]
final const val PIXEL_6A // androidx.compose.ui.tooling.preview/Devices.PIXEL_6A|{}PIXEL_6A[0]
final fun <get-PIXEL_6A>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_6A.<get-PIXEL_6A>|<get-PIXEL_6A>(){}[0]
final const val PIXEL_6_PRO // androidx.compose.ui.tooling.preview/Devices.PIXEL_6_PRO|{}PIXEL_6_PRO[0]
final fun <get-PIXEL_6_PRO>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_6_PRO.<get-PIXEL_6_PRO>|<get-PIXEL_6_PRO>(){}[0]
final const val PIXEL_7 // androidx.compose.ui.tooling.preview/Devices.PIXEL_7|{}PIXEL_7[0]
final fun <get-PIXEL_7>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_7.<get-PIXEL_7>|<get-PIXEL_7>(){}[0]
final const val PIXEL_7A // androidx.compose.ui.tooling.preview/Devices.PIXEL_7A|{}PIXEL_7A[0]
final fun <get-PIXEL_7A>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_7A.<get-PIXEL_7A>|<get-PIXEL_7A>(){}[0]
final const val PIXEL_7_PRO // androidx.compose.ui.tooling.preview/Devices.PIXEL_7_PRO|{}PIXEL_7_PRO[0]
final fun <get-PIXEL_7_PRO>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_7_PRO.<get-PIXEL_7_PRO>|<get-PIXEL_7_PRO>(){}[0]
final const val PIXEL_8 // androidx.compose.ui.tooling.preview/Devices.PIXEL_8|{}PIXEL_8[0]
final fun <get-PIXEL_8>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_8.<get-PIXEL_8>|<get-PIXEL_8>(){}[0]
final const val PIXEL_8A // androidx.compose.ui.tooling.preview/Devices.PIXEL_8A|{}PIXEL_8A[0]
final fun <get-PIXEL_8A>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_8A.<get-PIXEL_8A>|<get-PIXEL_8A>(){}[0]
final const val PIXEL_8_PRO // androidx.compose.ui.tooling.preview/Devices.PIXEL_8_PRO|{}PIXEL_8_PRO[0]
final fun <get-PIXEL_8_PRO>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_8_PRO.<get-PIXEL_8_PRO>|<get-PIXEL_8_PRO>(){}[0]
final const val PIXEL_9 // androidx.compose.ui.tooling.preview/Devices.PIXEL_9|{}PIXEL_9[0]
final fun <get-PIXEL_9>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_9.<get-PIXEL_9>|<get-PIXEL_9>(){}[0]
final const val PIXEL_9_PRO // androidx.compose.ui.tooling.preview/Devices.PIXEL_9_PRO|{}PIXEL_9_PRO[0]
final fun <get-PIXEL_9_PRO>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_9_PRO.<get-PIXEL_9_PRO>|<get-PIXEL_9_PRO>(){}[0]
final const val PIXEL_9_PRO_FOLD // androidx.compose.ui.tooling.preview/Devices.PIXEL_9_PRO_FOLD|{}PIXEL_9_PRO_FOLD[0]
final fun <get-PIXEL_9_PRO_FOLD>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_9_PRO_FOLD.<get-PIXEL_9_PRO_FOLD>|<get-PIXEL_9_PRO_FOLD>(){}[0]
final const val PIXEL_9_PRO_XL // androidx.compose.ui.tooling.preview/Devices.PIXEL_9_PRO_XL|{}PIXEL_9_PRO_XL[0]
final fun <get-PIXEL_9_PRO_XL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_9_PRO_XL.<get-PIXEL_9_PRO_XL>|<get-PIXEL_9_PRO_XL>(){}[0]
final const val PIXEL_C // androidx.compose.ui.tooling.preview/Devices.PIXEL_C|{}PIXEL_C[0]
final fun <get-PIXEL_C>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_C.<get-PIXEL_C>|<get-PIXEL_C>(){}[0]
final const val PIXEL_FOLD // androidx.compose.ui.tooling.preview/Devices.PIXEL_FOLD|{}PIXEL_FOLD[0]
final fun <get-PIXEL_FOLD>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_FOLD.<get-PIXEL_FOLD>|<get-PIXEL_FOLD>(){}[0]
final const val PIXEL_TABLET // androidx.compose.ui.tooling.preview/Devices.PIXEL_TABLET|{}PIXEL_TABLET[0]
final fun <get-PIXEL_TABLET>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_TABLET.<get-PIXEL_TABLET>|<get-PIXEL_TABLET>(){}[0]
final const val PIXEL_XL // androidx.compose.ui.tooling.preview/Devices.PIXEL_XL|{}PIXEL_XL[0]
final fun <get-PIXEL_XL>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.PIXEL_XL.<get-PIXEL_XL>|<get-PIXEL_XL>(){}[0]
final const val TABLET // androidx.compose.ui.tooling.preview/Devices.TABLET|{}TABLET[0]
final fun <get-TABLET>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.TABLET.<get-TABLET>|<get-TABLET>(){}[0]
final const val TV_1080p // androidx.compose.ui.tooling.preview/Devices.TV_1080p|{}TV_1080p[0]
final fun <get-TV_1080p>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.TV_1080p.<get-TV_1080p>|<get-TV_1080p>(){}[0]
final const val TV_720p // androidx.compose.ui.tooling.preview/Devices.TV_720p|{}TV_720p[0]
final fun <get-TV_720p>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.TV_720p.<get-TV_720p>|<get-TV_720p>(){}[0]
final const val WEAR_OS_LARGE_ROUND // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_LARGE_ROUND|{}WEAR_OS_LARGE_ROUND[0]
final fun <get-WEAR_OS_LARGE_ROUND>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_LARGE_ROUND.<get-WEAR_OS_LARGE_ROUND>|<get-WEAR_OS_LARGE_ROUND>(){}[0]
final const val WEAR_OS_RECT // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_RECT|{}WEAR_OS_RECT[0]
final fun <get-WEAR_OS_RECT>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_RECT.<get-WEAR_OS_RECT>|<get-WEAR_OS_RECT>(){}[0]
final const val WEAR_OS_SMALL_ROUND // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_SMALL_ROUND|{}WEAR_OS_SMALL_ROUND[0]
final fun <get-WEAR_OS_SMALL_ROUND>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_SMALL_ROUND.<get-WEAR_OS_SMALL_ROUND>|<get-WEAR_OS_SMALL_ROUND>(){}[0]
final const val WEAR_OS_SQUARE // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_SQUARE|{}WEAR_OS_SQUARE[0]
final fun <get-WEAR_OS_SQUARE>(): kotlin/String // androidx.compose.ui.tooling.preview/Devices.WEAR_OS_SQUARE.<get-WEAR_OS_SQUARE>|<get-WEAR_OS_SQUARE>(){}[0]
}
final object androidx.compose.ui.tooling.preview/Wallpapers { // androidx.compose.ui.tooling.preview/Wallpapers|null[0]
final const val BLUE_DOMINATED_EXAMPLE // androidx.compose.ui.tooling.preview/Wallpapers.BLUE_DOMINATED_EXAMPLE|{}BLUE_DOMINATED_EXAMPLE[0]
final fun <get-BLUE_DOMINATED_EXAMPLE>(): kotlin/Int // androidx.compose.ui.tooling.preview/Wallpapers.BLUE_DOMINATED_EXAMPLE.<get-BLUE_DOMINATED_EXAMPLE>|<get-BLUE_DOMINATED_EXAMPLE>(){}[0]
final const val GREEN_DOMINATED_EXAMPLE // androidx.compose.ui.tooling.preview/Wallpapers.GREEN_DOMINATED_EXAMPLE|{}GREEN_DOMINATED_EXAMPLE[0]
final fun <get-GREEN_DOMINATED_EXAMPLE>(): kotlin/Int // androidx.compose.ui.tooling.preview/Wallpapers.GREEN_DOMINATED_EXAMPLE.<get-GREEN_DOMINATED_EXAMPLE>|<get-GREEN_DOMINATED_EXAMPLE>(){}[0]
final const val NONE // androidx.compose.ui.tooling.preview/Wallpapers.NONE|{}NONE[0]
final fun <get-NONE>(): kotlin/Int // androidx.compose.ui.tooling.preview/Wallpapers.NONE.<get-NONE>|<get-NONE>(){}[0]
final const val RED_DOMINATED_EXAMPLE // androidx.compose.ui.tooling.preview/Wallpapers.RED_DOMINATED_EXAMPLE|{}RED_DOMINATED_EXAMPLE[0]
final fun <get-RED_DOMINATED_EXAMPLE>(): kotlin/Int // androidx.compose.ui.tooling.preview/Wallpapers.RED_DOMINATED_EXAMPLE.<get-RED_DOMINATED_EXAMPLE>|<get-RED_DOMINATED_EXAMPLE>(){}[0]
final const val YELLOW_DOMINATED_EXAMPLE // androidx.compose.ui.tooling.preview/Wallpapers.YELLOW_DOMINATED_EXAMPLE|{}YELLOW_DOMINATED_EXAMPLE[0]
final fun <get-YELLOW_DOMINATED_EXAMPLE>(): kotlin/Int // androidx.compose.ui.tooling.preview/Wallpapers.YELLOW_DOMINATED_EXAMPLE.<get-YELLOW_DOMINATED_EXAMPLE>|<get-YELLOW_DOMINATED_EXAMPLE>(){}[0]
}
final val androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_CollectionPreviewParameterProvider$stableprop // androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_CollectionPreviewParameterProvider$stableprop|#static{}androidx_compose_ui_tooling_preview_datasource_CollectionPreviewParameterProvider$stableprop[0]
final val androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_LoremIpsum$stableprop // androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_LoremIpsum$stableprop|#static{}androidx_compose_ui_tooling_preview_datasource_LoremIpsum$stableprop[0]
final val androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_AndroidUiModes$stableprop // androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_AndroidUiModes$stableprop|#static{}androidx_compose_ui_tooling_preview_AndroidUiModes$stableprop[0]
final val androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Devices$stableprop // androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Devices$stableprop|#static{}androidx_compose_ui_tooling_preview_Devices$stableprop[0]
final val androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Wallpapers$stableprop // androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Wallpapers$stableprop|#static{}androidx_compose_ui_tooling_preview_Wallpapers$stableprop[0]
final fun androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_CollectionPreviewParameterProvider$stableprop_getter(): kotlin/Int // androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_CollectionPreviewParameterProvider$stableprop_getter|androidx_compose_ui_tooling_preview_datasource_CollectionPreviewParameterProvider$stableprop_getter(){}[0]
final fun androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_LoremIpsum$stableprop_getter(): kotlin/Int // androidx.compose.ui.tooling.preview.datasource/androidx_compose_ui_tooling_preview_datasource_LoremIpsum$stableprop_getter|androidx_compose_ui_tooling_preview_datasource_LoremIpsum$stableprop_getter(){}[0]
final fun androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_AndroidUiModes$stableprop_getter(): kotlin/Int // androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_AndroidUiModes$stableprop_getter|androidx_compose_ui_tooling_preview_AndroidUiModes$stableprop_getter(){}[0]
final fun androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Devices$stableprop_getter(): kotlin/Int // androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Devices$stableprop_getter|androidx_compose_ui_tooling_preview_Devices$stableprop_getter(){}[0]
final fun androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Wallpapers$stableprop_getter(): kotlin/Int // androidx.compose.ui.tooling.preview/androidx_compose_ui_tooling_preview_Wallpapers$stableprop_getter|androidx_compose_ui_tooling_preview_Wallpapers$stableprop_getter(){}[0]
@@ -0,0 +1,34 @@
// :ui-tooling-preview — androidx.compose.ui.tooling.preview.* (the common
// @Preview annotation + PreviewParameterProvider), vendored VERBATIM from
// upstream (compose/ui/ui-tooling-preview). The Maven artifact ships no
// mingwX64/linux klibs — apps declare the OFFICIAL coords in commonMain and
// the root bridge substitutes this module on native configurations. The
// annotations are IDE-only metadata: previews render through the app's JVM
// target against upstream Compose Desktop.
// Never hand-edit src/vendor/ — change the manifest + `python scripts/compose-fork/sync.py compose/ui/ui-tooling-preview`.
// Publication artifactId: ui-tooling-preview.
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.kotlin.plugin.compose)
}
val vHostSupportsMingw = rootProject.extra["vHostSupportsMingw"] as Boolean
kotlin {
linuxArm64(); linuxX64(); macosArm64(); if (vHostSupportsMingw) mingwX64()
applyDefaultHierarchyTemplate()
sourceSets {
commonMain {
dependencies {
api("org.jetbrains.compose.runtime:runtime:1.11.1")
}
kotlin.srcDir("src/vendor/common/kotlin")
}
nativeMain { kotlin.srcDir("src/vendor/native/kotlin") }
}
compilerOptions {
freeCompilerArgs.addAll(
"-Xexpect-actual-classes",
)
}
}
@@ -0,0 +1,23 @@
SET_REPO=https://github.com/JetBrains/compose-multiplatform-core@<COMPOSE_CORE_REF>
SET_FOLDER=compose/ui/ui-tooling-preview/src
commonMain/kotlin/ -> src/vendor/common/kotlin/
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/AndroidUiMode.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/AndroidUiMode.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/Device.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/Device.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/MultiPreviews.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/MultiPreviews.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/Preview.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/Preview.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/PreviewParameter.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/PreviewParameter.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/PreviewWrapper.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/PreviewWrapper.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/Wallpaper.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/Wallpaper.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/datasource/CollectionPreviewParameterProvider.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/datasource/CollectionPreviewParameterProvider.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/datasource/LoremIpsum.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/datasource/LoremIpsum.kt
# | commonMain/kotlin/androidx/compose/ui/tooling/preview/internal/JvmDefaultWithCompatibility.kt -> src/vendor/common/kotlin/androidx/compose/ui/tooling/preview/internal/JvmDefaultWithCompatibility.kt
nonJvmMain/kotlin/androidx/compose/ui/tooling/preview/internal/JvmDefaultWithCompatibility.nonJvm.kt -> src/vendor/native/kotlin/androidx/compose/ui/tooling/preview/internal/JvmDefaultWithCompatibility.native.kt
# >>> ---- DIAGNOSTIC GAPS ---- <<<<
# desktopMain (1)
# | desktopMain/kotlin/androidx/compose/desktop/ui/tooling/preview/Preview.kt -> src/vendor/desktop/kotlin/androidx/compose/desktop/ui/tooling/preview/Preview.kt
# jvmAndAndroidMain (1)
# | jvmAndAndroidMain/kotlin/androidx/compose/ui/tooling/preview/internal/JvmDefaultWithCompatibility.jvmAndAndroid.kt -> src/vendor/jvmAndAndroid/kotlin/androidx/compose/ui/tooling/preview/internal/JvmDefaultWithCompatibility.jvmAndAndroid.kt
# <<< ---- DIAGNOSTIC GAPS ---- >>>>
+93 -189
View File
@@ -1834,6 +1834,10 @@ abstract interface androidx.compose.ui/UiMediaScope { // androidx.compose.ui/UiM
}
}
abstract interface com.compose.sdl.graphics/EncodedImageDecoder { // com.compose.sdl.graphics/EncodedImageDecoder|null[0]
abstract fun decode(kotlin/ByteArray): androidx.compose.ui.graphics/ImageBitmap? // com.compose.sdl.graphics/EncodedImageDecoder.decode|decode(kotlin.ByteArray){}[0]
}
abstract interface com.compose.sdl.graphics/NativePainterCanvas { // com.compose.sdl.graphics/NativePainterCanvas|null[0]
abstract fun drawNativePainter(kotlin/String, com.compose.sdl.res/ResourceKind, kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Float, androidx.compose.ui.layout/ContentScale, kotlin/Float) // com.compose.sdl.graphics/NativePainterCanvas.drawNativePainter|drawNativePainter(kotlin.String;com.compose.sdl.res.ResourceKind;kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Float;androidx.compose.ui.layout.ContentScale;kotlin.Float){}[0]
}
@@ -2522,9 +2526,23 @@ final class androidx.compose.ui.autofill/AutofillTree { // androidx.compose.ui.a
final fun plusAssign(androidx.compose.ui.autofill/AutofillNode) // androidx.compose.ui.autofill/AutofillTree.plusAssign|plusAssign(androidx.compose.ui.autofill.AutofillNode){}[0]
}
final class androidx.compose.ui.draganddrop/DragAndDropEvent // androidx.compose.ui.draganddrop/DragAndDropEvent|null[0]
final class androidx.compose.ui.draganddrop/DragAndDropEvent { // androidx.compose.ui.draganddrop/DragAndDropEvent|null[0]
final val position // androidx.compose.ui.draganddrop/DragAndDropEvent.position|{}position[0]
final fun <get-position>(): androidx.compose.ui.geometry/Offset // androidx.compose.ui.draganddrop/DragAndDropEvent.position.<get-position>|<get-position>(){}[0]
final val transferData // androidx.compose.ui.draganddrop/DragAndDropEvent.transferData|{}transferData[0]
final fun <get-transferData>(): androidx.compose.ui.draganddrop/DragAndDropTransferData // androidx.compose.ui.draganddrop/DragAndDropEvent.transferData.<get-transferData>|<get-transferData>(){}[0]
}
final class androidx.compose.ui.draganddrop/DragAndDropTransferData // androidx.compose.ui.draganddrop/DragAndDropTransferData|null[0]
final class androidx.compose.ui.draganddrop/DragAndDropTransferData { // androidx.compose.ui.draganddrop/DragAndDropTransferData|null[0]
final val filePaths // androidx.compose.ui.draganddrop/DragAndDropTransferData.filePaths|{}filePaths[0]
final fun <get-filePaths>(): kotlin.collections/List<kotlin/String> // androidx.compose.ui.draganddrop/DragAndDropTransferData.filePaths.<get-filePaths>|<get-filePaths>(){}[0]
final val hasFiles // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasFiles|{}hasFiles[0]
final fun <get-hasFiles>(): kotlin/Boolean // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasFiles.<get-hasFiles>|<get-hasFiles>(){}[0]
final val hasText // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasText|{}hasText[0]
final fun <get-hasText>(): kotlin/Boolean // androidx.compose.ui.draganddrop/DragAndDropTransferData.hasText.<get-hasText>|<get-hasText>(){}[0]
final val text // androidx.compose.ui.draganddrop/DragAndDropTransferData.text|{}text[0]
final fun <get-text>(): kotlin/String? // androidx.compose.ui.draganddrop/DragAndDropTransferData.text.<get-text>|<get-text>(){}[0]
}
final class androidx.compose.ui.draw/CacheDrawScope : androidx.compose.ui.unit/Density { // androidx.compose.ui.draw/CacheDrawScope|null[0]
final val density // androidx.compose.ui.draw/CacheDrawScope.density|{}density[0]
@@ -3654,9 +3672,11 @@ final class androidx.compose.ui.platform/ClipEntry { // androidx.compose.ui.plat
final val clipMetadata // androidx.compose.ui.platform/ClipEntry.clipMetadata|{}clipMetadata[0]
final fun <get-clipMetadata>(): androidx.compose.ui.platform/ClipMetadata // androidx.compose.ui.platform/ClipEntry.clipMetadata.<get-clipMetadata>|<get-clipMetadata>(){}[0]
final fun getImage(): kotlin/ByteArray? // androidx.compose.ui.platform/ClipEntry.getImage|getImage(){}[0]
final fun getPlainText(): kotlin/String? // androidx.compose.ui.platform/ClipEntry.getPlainText|getPlainText(){}[0]
final object Companion { // androidx.compose.ui.platform/ClipEntry.Companion|null[0]
final fun withImage(kotlin/ByteArray): androidx.compose.ui.platform/ClipEntry // androidx.compose.ui.platform/ClipEntry.Companion.withImage|withImage(kotlin.ByteArray){}[0]
final fun withPlainText(kotlin/String): androidx.compose.ui.platform/ClipEntry // androidx.compose.ui.platform/ClipEntry.Companion.withPlainText|withPlainText(kotlin.String){}[0]
}
}
@@ -5348,136 +5368,6 @@ final class com.compose.sdl.element/GraphicsLayerNode : androidx.compose.ui/Modi
final fun <set-translationY>(kotlin/Float) // com.compose.sdl.element/GraphicsLayerNode.translationY.<set-translationY>|<set-translationY>(kotlin.Float){}[0]
}
final class com.compose.sdl.element/MiddleClickModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/MiddleClickNode> { // com.compose.sdl.element/MiddleClickModifier|null[0]
constructor <init>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/MiddleClickModifier.<init>|<init>(kotlin.Function0<kotlin.Unit>){}[0]
final val onClick // com.compose.sdl.element/MiddleClickModifier.onClick|{}onClick[0]
final fun <get-onClick>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/MiddleClickModifier.onClick.<get-onClick>|<get-onClick>(){}[0]
final fun create(): com.compose.sdl.element/MiddleClickNode // com.compose.sdl.element/MiddleClickModifier.create|create(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/MiddleClickModifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl.element/MiddleClickModifier.hashCode|hashCode(){}[0]
final fun update(com.compose.sdl.element/MiddleClickNode) // com.compose.sdl.element/MiddleClickModifier.update|update(com.compose.sdl.element.MiddleClickNode){}[0]
}
final class com.compose.sdl.element/MiddleClickNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/MiddleClickNode|null[0]
constructor <init>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/MiddleClickNode.<init>|<init>(kotlin.Function0<kotlin.Unit>){}[0]
final var onClick // com.compose.sdl.element/MiddleClickNode.onClick|{}onClick[0]
final fun <get-onClick>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/MiddleClickNode.onClick.<get-onClick>|<get-onClick>(){}[0]
final fun <set-onClick>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/MiddleClickNode.onClick.<set-onClick>|<set-onClick>(kotlin.Function0<kotlin.Unit>){}[0]
}
final class com.compose.sdl.element/OnDragModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/OnDragNode> { // com.compose.sdl.element/OnDragModifier|null[0]
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/OnDragModifier.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function0<kotlin.Unit>){}[0]
final val onDrag // com.compose.sdl.element/OnDragModifier.onDrag|{}onDrag[0]
final fun <get-onDrag>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragModifier.onDrag.<get-onDrag>|<get-onDrag>(){}[0]
final val onEnd // com.compose.sdl.element/OnDragModifier.onEnd|{}onEnd[0]
final fun <get-onEnd>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/OnDragModifier.onEnd.<get-onEnd>|<get-onEnd>(){}[0]
final val onStart // com.compose.sdl.element/OnDragModifier.onStart|{}onStart[0]
final fun <get-onStart>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragModifier.onStart.<get-onStart>|<get-onStart>(){}[0]
final fun create(): com.compose.sdl.element/OnDragNode // com.compose.sdl.element/OnDragModifier.create|create(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/OnDragModifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl.element/OnDragModifier.hashCode|hashCode(){}[0]
final fun update(com.compose.sdl.element/OnDragNode) // com.compose.sdl.element/OnDragModifier.update|update(com.compose.sdl.element.OnDragNode){}[0]
}
final class com.compose.sdl.element/OnDragNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/OnDragNode|null[0]
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>, kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/OnDragNode.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function0<kotlin.Unit>){}[0]
final var onDrag // com.compose.sdl.element/OnDragNode.onDrag|{}onDrag[0]
final fun <get-onDrag>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragNode.onDrag.<get-onDrag>|<get-onDrag>(){}[0]
final fun <set-onDrag>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnDragNode.onDrag.<set-onDrag>|<set-onDrag>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final var onEnd // com.compose.sdl.element/OnDragNode.onEnd|{}onEnd[0]
final fun <get-onEnd>(): kotlin/Function0<kotlin/Unit> // com.compose.sdl.element/OnDragNode.onEnd.<get-onEnd>|<get-onEnd>(){}[0]
final fun <set-onEnd>(kotlin/Function0<kotlin/Unit>) // com.compose.sdl.element/OnDragNode.onEnd.<set-onEnd>|<set-onEnd>(kotlin.Function0<kotlin.Unit>){}[0]
final var onStart // com.compose.sdl.element/OnDragNode.onStart|{}onStart[0]
final fun <get-onStart>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnDragNode.onStart.<get-onStart>|<get-onStart>(){}[0]
final fun <set-onStart>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnDragNode.onStart.<set-onStart>|<set-onStart>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
}
final class com.compose.sdl.element/OnPressedModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/OnPressedNode> { // com.compose.sdl.element/OnPressedModifier|null[0]
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnPressedModifier.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final val handler // com.compose.sdl.element/OnPressedModifier.handler|{}handler[0]
final fun <get-handler>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnPressedModifier.handler.<get-handler>|<get-handler>(){}[0]
final fun create(): com.compose.sdl.element/OnPressedNode // com.compose.sdl.element/OnPressedModifier.create|create(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/OnPressedModifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl.element/OnPressedModifier.hashCode|hashCode(){}[0]
final fun update(com.compose.sdl.element/OnPressedNode) // com.compose.sdl.element/OnPressedModifier.update|update(com.compose.sdl.element.OnPressedNode){}[0]
}
final class com.compose.sdl.element/OnPressedNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/OnPressedNode|null[0]
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnPressedNode.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final var handler // com.compose.sdl.element/OnPressedNode.handler|{}handler[0]
final fun <get-handler>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/OnPressedNode.handler.<get-handler>|<get-handler>(){}[0]
final fun <set-handler>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/OnPressedNode.handler.<set-handler>|<set-handler>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
}
final class com.compose.sdl.element/OnTextInputModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/OnTextInputNode> { // com.compose.sdl.element/OnTextInputModifier|null[0]
constructor <init>(kotlin/Function1<kotlin/String, kotlin/Unit>) // com.compose.sdl.element/OnTextInputModifier.<init>|<init>(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
final val handler // com.compose.sdl.element/OnTextInputModifier.handler|{}handler[0]
final fun <get-handler>(): kotlin/Function1<kotlin/String, kotlin/Unit> // com.compose.sdl.element/OnTextInputModifier.handler.<get-handler>|<get-handler>(){}[0]
final fun create(): com.compose.sdl.element/OnTextInputNode // com.compose.sdl.element/OnTextInputModifier.create|create(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/OnTextInputModifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl.element/OnTextInputModifier.hashCode|hashCode(){}[0]
final fun update(com.compose.sdl.element/OnTextInputNode) // com.compose.sdl.element/OnTextInputModifier.update|update(com.compose.sdl.element.OnTextInputNode){}[0]
}
final class com.compose.sdl.element/OnTextInputNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/OnTextInputNode|null[0]
constructor <init>(kotlin/Function1<kotlin/String, kotlin/Unit>) // com.compose.sdl.element/OnTextInputNode.<init>|<init>(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
final var handler // com.compose.sdl.element/OnTextInputNode.handler|{}handler[0]
final fun <get-handler>(): kotlin/Function1<kotlin/String, kotlin/Unit> // com.compose.sdl.element/OnTextInputNode.handler.<get-handler>|<get-handler>(){}[0]
final fun <set-handler>(kotlin/Function1<kotlin/String, kotlin/Unit>) // com.compose.sdl.element/OnTextInputNode.handler.<set-handler>|<set-handler>(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
}
final class com.compose.sdl.element/PressableModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/PressableNode> { // com.compose.sdl.element/PressableModifier|null[0]
constructor <init>(kotlin/Function1<kotlin/Boolean, kotlin/Unit>) // com.compose.sdl.element/PressableModifier.<init>|<init>(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
final val onChange // com.compose.sdl.element/PressableModifier.onChange|{}onChange[0]
final fun <get-onChange>(): kotlin/Function1<kotlin/Boolean, kotlin/Unit> // com.compose.sdl.element/PressableModifier.onChange.<get-onChange>|<get-onChange>(){}[0]
final fun create(): com.compose.sdl.element/PressableNode // com.compose.sdl.element/PressableModifier.create|create(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/PressableModifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl.element/PressableModifier.hashCode|hashCode(){}[0]
final fun update(com.compose.sdl.element/PressableNode) // com.compose.sdl.element/PressableModifier.update|update(com.compose.sdl.element.PressableNode){}[0]
}
final class com.compose.sdl.element/PressableNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/PressableNode|null[0]
constructor <init>(kotlin/Function1<kotlin/Boolean, kotlin/Unit>) // com.compose.sdl.element/PressableNode.<init>|<init>(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
final var onChange // com.compose.sdl.element/PressableNode.onChange|{}onChange[0]
final fun <get-onChange>(): kotlin/Function1<kotlin/Boolean, kotlin/Unit> // com.compose.sdl.element/PressableNode.onChange.<get-onChange>|<get-onChange>(){}[0]
final fun <set-onChange>(kotlin/Function1<kotlin/Boolean, kotlin/Unit>) // com.compose.sdl.element/PressableNode.onChange.<set-onChange>|<set-onChange>(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
}
final class com.compose.sdl.element/SecondaryClickModifier : androidx.compose.ui.node/ModifierNodeElement<com.compose.sdl.element/SecondaryClickNode> { // com.compose.sdl.element/SecondaryClickModifier|null[0]
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/SecondaryClickModifier.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final val onClick // com.compose.sdl.element/SecondaryClickModifier.onClick|{}onClick[0]
final fun <get-onClick>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/SecondaryClickModifier.onClick.<get-onClick>|<get-onClick>(){}[0]
final fun create(): com.compose.sdl.element/SecondaryClickNode // com.compose.sdl.element/SecondaryClickModifier.create|create(){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl.element/SecondaryClickModifier.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl.element/SecondaryClickModifier.hashCode|hashCode(){}[0]
final fun update(com.compose.sdl.element/SecondaryClickNode) // com.compose.sdl.element/SecondaryClickModifier.update|update(com.compose.sdl.element.SecondaryClickNode){}[0]
}
final class com.compose.sdl.element/SecondaryClickNode : androidx.compose.ui/Modifier.Node { // com.compose.sdl.element/SecondaryClickNode|null[0]
constructor <init>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/SecondaryClickNode.<init>|<init>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final var onClick // com.compose.sdl.element/SecondaryClickNode.onClick|{}onClick[0]
final fun <get-onClick>(): kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> // com.compose.sdl.element/SecondaryClickNode.onClick.<get-onClick>|<get-onClick>(){}[0]
final fun <set-onClick>(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>) // com.compose.sdl.element/SecondaryClickNode.onClick.<set-onClick>|<set-onClick>(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
}
final class com.compose.sdl.graphics/ProjectCanvas : androidx.compose.ui.graphics/Canvas { // com.compose.sdl.graphics/ProjectCanvas|null[0]
constructor <init>() // com.compose.sdl.graphics/ProjectCanvas.<init>|<init>(){}[0]
@@ -5649,8 +5539,6 @@ final class com.compose.sdl.node/ComposeRootHost { // com.compose.sdl.node/Compo
final val applier // com.compose.sdl.node/ComposeRootHost.applier|{}applier[0]
final fun <get-applier>(): androidx.compose.runtime/Applier<*> // com.compose.sdl.node/ComposeRootHost.applier.<get-applier>|<get-applier>(){}[0]
final val autofillTree // com.compose.sdl.node/ComposeRootHost.autofillTree|{}autofillTree[0]
final fun <get-autofillTree>(): androidx.compose.ui.autofill/AutofillTree // com.compose.sdl.node/ComposeRootHost.autofillTree.<get-autofillTree>|<get-autofillTree>(){}[0]
final val density // com.compose.sdl.node/ComposeRootHost.density|{}density[0]
final fun <get-density>(): androidx.compose.ui.unit/Density // com.compose.sdl.node/ComposeRootHost.density.<get-density>|<get-density>(){}[0]
final val focusManager // com.compose.sdl.node/ComposeRootHost.focusManager|{}focusManager[0]
@@ -5665,8 +5553,6 @@ final class com.compose.sdl.node/ComposeRootHost { // com.compose.sdl.node/Compo
final fun <get-layoutDirection>(): androidx.compose.ui.unit/LayoutDirection // com.compose.sdl.node/ComposeRootHost.layoutDirection.<get-layoutDirection>|<get-layoutDirection>(){}[0]
final val softwareKeyboardController // com.compose.sdl.node/ComposeRootHost.softwareKeyboardController|{}softwareKeyboardController[0]
final fun <get-softwareKeyboardController>(): androidx.compose.ui.platform/SoftwareKeyboardController // com.compose.sdl.node/ComposeRootHost.softwareKeyboardController.<get-softwareKeyboardController>|<get-softwareKeyboardController>(){}[0]
final val textInputService // com.compose.sdl.node/ComposeRootHost.textInputService|{}textInputService[0]
final fun <get-textInputService>(): androidx.compose.ui.text.input/TextInputService // com.compose.sdl.node/ComposeRootHost.textInputService.<get-textInputService>|<get-textInputService>(){}[0]
final val textToolbar // com.compose.sdl.node/ComposeRootHost.textToolbar|{}textToolbar[0]
final fun <get-textToolbar>(): androidx.compose.ui.platform/TextToolbar // com.compose.sdl.node/ComposeRootHost.textToolbar.<get-textToolbar>|<get-textToolbar>(){}[0]
final val viewConfiguration // com.compose.sdl.node/ComposeRootHost.viewConfiguration|{}viewConfiguration[0]
@@ -5676,9 +5562,12 @@ final class com.compose.sdl.node/ComposeRootHost { // com.compose.sdl.node/Compo
final fun attach() // com.compose.sdl.node/ComposeRootHost.attach|attach(){}[0]
final fun dispatchKeyEvent(androidx.compose.ui.input.key/KeyEvent): kotlin/Boolean // com.compose.sdl.node/ComposeRootHost.dispatchKeyEvent|dispatchKeyEvent(androidx.compose.ui.input.key.KeyEvent){}[0]
final fun dispatchTextInput(kotlin/String): kotlin/Boolean // com.compose.sdl.node/ComposeRootHost.dispatchTextInput|dispatchTextInput(kotlin.String){}[0]
final fun measureAndLayout() // com.compose.sdl.node/ComposeRootHost.measureAndLayout|measureAndLayout(){}[0]
final fun onPointer(kotlin/Float, kotlin/Float, kotlin/Int, kotlin/Int) // com.compose.sdl.node/ComposeRootHost.onPointer|onPointer(kotlin.Float;kotlin.Float;kotlin.Int;kotlin.Int){}[0]
final fun onDropBegin() // com.compose.sdl.node/ComposeRootHost.onDropBegin|onDropBegin(){}[0]
final fun onDropComplete() // com.compose.sdl.node/ComposeRootHost.onDropComplete|onDropComplete(){}[0]
final fun onDropFile(kotlin/String) // com.compose.sdl.node/ComposeRootHost.onDropFile|onDropFile(kotlin.String){}[0]
final fun onDropPosition(kotlin/Float, kotlin/Float) // com.compose.sdl.node/ComposeRootHost.onDropPosition|onDropPosition(kotlin.Float;kotlin.Float){}[0]
final fun onDropText(kotlin/String) // com.compose.sdl.node/ComposeRootHost.onDropText|onDropText(kotlin.String){}[0]
final fun onPointerRaw(kotlin/Float, kotlin/Float, kotlin/Int, kotlin/Int, kotlin/Long) // com.compose.sdl.node/ComposeRootHost.onPointerRaw|onPointerRaw(kotlin.Float;kotlin.Float;kotlin.Int;kotlin.Int;kotlin.Long){}[0]
final fun onWheel(kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Float, kotlin/Long) // com.compose.sdl.node/ComposeRootHost.onWheel|onWheel(kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Float;kotlin.Long){}[0]
final fun sendAnimationFrame(kotlin/Long) // com.compose.sdl.node/ComposeRootHost.sendAnimationFrame|sendAnimationFrame(kotlin.Long){}[0]
@@ -8387,6 +8276,45 @@ sealed class androidx.compose.ui.text.font/SystemFontFamily : androidx.compose.u
sealed class androidx.compose.ui.text/TtsAnnotation : androidx.compose.ui.text/AnnotatedString.Annotation // androidx.compose.ui.text/TtsAnnotation|null[0]
sealed class com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent|null[0]
final enum class DropPhase : kotlin/Enum<com.compose.sdl/AppEvent.DropPhase> { // com.compose.sdl/AppEvent.DropPhase|null[0]
enum entry BEGIN // com.compose.sdl/AppEvent.DropPhase.BEGIN|null[0]
enum entry COMPLETE // com.compose.sdl/AppEvent.DropPhase.COMPLETE|null[0]
enum entry FILE // com.compose.sdl/AppEvent.DropPhase.FILE|null[0]
enum entry POSITION // com.compose.sdl/AppEvent.DropPhase.POSITION|null[0]
enum entry TEXT // com.compose.sdl/AppEvent.DropPhase.TEXT|null[0]
final val entries // com.compose.sdl/AppEvent.DropPhase.entries|#static{}entries[0]
final fun <get-entries>(): kotlin.enums/EnumEntries<com.compose.sdl/AppEvent.DropPhase> // com.compose.sdl/AppEvent.DropPhase.entries.<get-entries>|<get-entries>#static(){}[0]
final fun valueOf(kotlin/String): com.compose.sdl/AppEvent.DropPhase // com.compose.sdl/AppEvent.DropPhase.valueOf|valueOf#static(kotlin.String){}[0]
final fun values(): kotlin/Array<com.compose.sdl/AppEvent.DropPhase> // com.compose.sdl/AppEvent.DropPhase.values|values#static(){}[0]
}
final class Drop : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.Drop|null[0]
constructor <init>(kotlin/UInt, com.compose.sdl/AppEvent.DropPhase, kotlin/Float = ..., kotlin/Float = ..., kotlin/String? = ...) // com.compose.sdl/AppEvent.Drop.<init>|<init>(kotlin.UInt;com.compose.sdl.AppEvent.DropPhase;kotlin.Float;kotlin.Float;kotlin.String?){}[0]
final val data // com.compose.sdl/AppEvent.Drop.data|{}data[0]
final fun <get-data>(): kotlin/String? // com.compose.sdl/AppEvent.Drop.data.<get-data>|<get-data>(){}[0]
final val phase // com.compose.sdl/AppEvent.Drop.phase|{}phase[0]
final fun <get-phase>(): com.compose.sdl/AppEvent.DropPhase // com.compose.sdl/AppEvent.Drop.phase.<get-phase>|<get-phase>(){}[0]
final val windowId // com.compose.sdl/AppEvent.Drop.windowId|{}windowId[0]
final fun <get-windowId>(): kotlin/UInt // com.compose.sdl/AppEvent.Drop.windowId.<get-windowId>|<get-windowId>(){}[0]
final val x // com.compose.sdl/AppEvent.Drop.x|{}x[0]
final fun <get-x>(): kotlin/Float // com.compose.sdl/AppEvent.Drop.x.<get-x>|<get-x>(){}[0]
final val y // com.compose.sdl/AppEvent.Drop.y|{}y[0]
final fun <get-y>(): kotlin/Float // com.compose.sdl/AppEvent.Drop.y.<get-y>|<get-y>(){}[0]
final fun component1(): kotlin/UInt // com.compose.sdl/AppEvent.Drop.component1|component1(){}[0]
final fun component2(): com.compose.sdl/AppEvent.DropPhase // com.compose.sdl/AppEvent.Drop.component2|component2(){}[0]
final fun component3(): kotlin/Float // com.compose.sdl/AppEvent.Drop.component3|component3(){}[0]
final fun component4(): kotlin/Float // com.compose.sdl/AppEvent.Drop.component4|component4(){}[0]
final fun component5(): kotlin/String? // com.compose.sdl/AppEvent.Drop.component5|component5(){}[0]
final fun copy(kotlin/UInt = ..., com.compose.sdl/AppEvent.DropPhase = ..., kotlin/Float = ..., kotlin/Float = ..., kotlin/String? = ...): com.compose.sdl/AppEvent.Drop // com.compose.sdl/AppEvent.Drop.copy|copy(kotlin.UInt;com.compose.sdl.AppEvent.DropPhase;kotlin.Float;kotlin.Float;kotlin.String?){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl/AppEvent.Drop.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl/AppEvent.Drop.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // com.compose.sdl/AppEvent.Drop.toString|toString(){}[0]
}
final class Key : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.Key|null[0]
constructor <init>(androidx.compose.ui.input.key/KeyEvent, kotlin/UInt = ...) // com.compose.sdl/AppEvent.Key.<init>|<init>(androidx.compose.ui.input.key.KeyEvent;kotlin.UInt){}[0]
@@ -8473,6 +8401,25 @@ sealed class com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent|null[0]
final fun toString(): kotlin/String // com.compose.sdl/AppEvent.TextInput.toString|toString(){}[0]
}
final class WindowActivation : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.WindowActivation|null[0]
constructor <init>(kotlin/UInt = ..., kotlin/Boolean? = ..., kotlin/Boolean? = ...) // com.compose.sdl/AppEvent.WindowActivation.<init>|<init>(kotlin.UInt;kotlin.Boolean?;kotlin.Boolean?){}[0]
final val focused // com.compose.sdl/AppEvent.WindowActivation.focused|{}focused[0]
final fun <get-focused>(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.focused.<get-focused>|<get-focused>(){}[0]
final val visible // com.compose.sdl/AppEvent.WindowActivation.visible|{}visible[0]
final fun <get-visible>(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.visible.<get-visible>|<get-visible>(){}[0]
final val windowId // com.compose.sdl/AppEvent.WindowActivation.windowId|{}windowId[0]
final fun <get-windowId>(): kotlin/UInt // com.compose.sdl/AppEvent.WindowActivation.windowId.<get-windowId>|<get-windowId>(){}[0]
final fun component1(): kotlin/UInt // com.compose.sdl/AppEvent.WindowActivation.component1|component1(){}[0]
final fun component2(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.component2|component2(){}[0]
final fun component3(): kotlin/Boolean? // com.compose.sdl/AppEvent.WindowActivation.component3|component3(){}[0]
final fun copy(kotlin/UInt = ..., kotlin/Boolean? = ..., kotlin/Boolean? = ...): com.compose.sdl/AppEvent.WindowActivation // com.compose.sdl/AppEvent.WindowActivation.copy|copy(kotlin.UInt;kotlin.Boolean?;kotlin.Boolean?){}[0]
final fun equals(kotlin/Any?): kotlin/Boolean // com.compose.sdl/AppEvent.WindowActivation.equals|equals(kotlin.Any?){}[0]
final fun hashCode(): kotlin/Int // com.compose.sdl/AppEvent.WindowActivation.hashCode|hashCode(){}[0]
final fun toString(): kotlin/String // com.compose.sdl/AppEvent.WindowActivation.toString|toString(){}[0]
}
final class WindowClose : com.compose.sdl/AppEvent { // com.compose.sdl/AppEvent.WindowClose|null[0]
constructor <init>(kotlin/UInt = ...) // com.compose.sdl/AppEvent.WindowClose.<init>|<init>(kotlin.UInt){}[0]
@@ -9299,16 +9246,6 @@ final val androidx.compose.ui.platform/androidx_compose_ui_platform_InspectorVal
final val androidx.compose.ui.platform/androidx_compose_ui_platform_PlatformWindowInsetsProviderNode$stableprop // androidx.compose.ui.platform/androidx_compose_ui_platform_PlatformWindowInsetsProviderNode$stableprop|#static{}androidx_compose_ui_platform_PlatformWindowInsetsProviderNode$stableprop[0]
final val androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElement$stableprop // androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElement$stableprop|#static{}androidx_compose_ui_platform_ValueElement$stableprop[0]
final val androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop // androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop|#static{}androidx_compose_ui_platform_ValueElementSequence$stableprop[0]
final val androidx.compose.ui.platform/currentClipboard // androidx.compose.ui.platform/currentClipboard|{}currentClipboard[0]
final fun <get-currentClipboard>(): androidx.compose.ui.platform/ClipboardManager // androidx.compose.ui.platform/currentClipboard.<get-currentClipboard>|<get-currentClipboard>(){}[0]
final val androidx.compose.ui.platform/defaultClipboard // androidx.compose.ui.platform/defaultClipboard|{}defaultClipboard[0]
final fun <get-defaultClipboard>(): androidx.compose.ui.platform/Clipboard // androidx.compose.ui.platform/defaultClipboard.<get-defaultClipboard>|<get-defaultClipboard>(){}[0]
final val androidx.compose.ui.platform/defaultClipboardManager // androidx.compose.ui.platform/defaultClipboardManager|{}defaultClipboardManager[0]
final fun <get-defaultClipboardManager>(): androidx.compose.ui.platform/ClipboardManager // androidx.compose.ui.platform/defaultClipboardManager.<get-defaultClipboardManager>|<get-defaultClipboardManager>(){}[0]
final val androidx.compose.ui.platform/platformClipboard // androidx.compose.ui.platform/platformClipboard|{}platformClipboard[0]
final fun <get-platformClipboard>(): androidx.compose.ui.platform/Clipboard // androidx.compose.ui.platform/platformClipboard.<get-platformClipboard>|<get-platformClipboard>(){}[0]
final val androidx.compose.ui.platform/platformClipboardManager // androidx.compose.ui.platform/platformClipboardManager|{}platformClipboardManager[0]
final fun <get-platformClipboardManager>(): androidx.compose.ui.platform/ClipboardManager // androidx.compose.ui.platform/platformClipboardManager.<get-platformClipboardManager>|<get-platformClipboardManager>(){}[0]
final val androidx.compose.ui.platform/safeContent // androidx.compose.ui.platform/safeContent|@androidx.compose.ui.platform.PlatformWindowInsets{}safeContent[0]
final fun (androidx.compose.ui.platform/PlatformWindowInsets).<get-safeContent>(): androidx.compose.ui.platform/PlatformInsets // androidx.compose.ui.platform/safeContent.<get-safeContent>|<get-safeContent>@androidx.compose.ui.platform.PlatformWindowInsets(){}[0]
final val androidx.compose.ui.platform/safeDrawing // androidx.compose.ui.platform/safeDrawing|@androidx.compose.ui.platform.PlatformWindowInsets{}safeDrawing[0]
@@ -9424,22 +9361,6 @@ final val com.compose.sdl.element/com_compose_sdl_element_ClipModifier$stablepro
final val com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop|#static{}com_compose_sdl_element_ClipNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop|#static{}com_compose_sdl_element_GraphicsLayerModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop|#static{}com_compose_sdl_element_GraphicsLayerNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop|#static{}com_compose_sdl_element_MiddleClickModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop|#static{}com_compose_sdl_element_MiddleClickNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop|#static{}com_compose_sdl_element_OnDragModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop|#static{}com_compose_sdl_element_OnDragNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop|#static{}com_compose_sdl_element_OnPressedModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop|#static{}com_compose_sdl_element_OnPressedNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop|#static{}com_compose_sdl_element_OnTextInputModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop|#static{}com_compose_sdl_element_OnTextInputNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop|#static{}com_compose_sdl_element_PressableModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop|#static{}com_compose_sdl_element_PressableNode$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop|#static{}com_compose_sdl_element_SecondaryClickModifier$stableprop[0]
final val com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop|#static{}com_compose_sdl_element_SecondaryClickNode$stableprop[0]
final val com.compose.sdl.graphics/a8 // com.compose.sdl.graphics/a8|@androidx.compose.ui.graphics.Color{}a8[0]
final fun (androidx.compose.ui.graphics/Color).<get-a8>(): kotlin/Int // com.compose.sdl.graphics/a8.<get-a8>|<get-a8>@androidx.compose.ui.graphics.Color(){}[0]
final val com.compose.sdl.graphics/b8 // com.compose.sdl.graphics/b8|@androidx.compose.ui.graphics.Color{}b8[0]
final fun (androidx.compose.ui.graphics/Color).<get-b8>(): kotlin/Int // com.compose.sdl.graphics/b8.<get-b8>|<get-b8>@androidx.compose.ui.graphics.Color(){}[0]
final val com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop|#static{}com_compose_sdl_graphics_PathCommand_Close$stableprop[0]
final val com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop|#static{}com_compose_sdl_graphics_PathCommand_CubicTo$stableprop[0]
final val com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop|#static{}com_compose_sdl_graphics_PathCommand_LineTo$stableprop[0]
@@ -9450,8 +9371,6 @@ final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectImageBitmap$s
final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop|#static{}com_compose_sdl_graphics_ProjectPaint$stableprop[0]
final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop|#static{}com_compose_sdl_graphics_ProjectPath$stableprop[0]
final val com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop|#static{}com_compose_sdl_graphics_ProjectPathIterator$stableprop[0]
final val com.compose.sdl.graphics/g8 // com.compose.sdl.graphics/g8|@androidx.compose.ui.graphics.Color{}g8[0]
final fun (androidx.compose.ui.graphics/Color).<get-g8>(): kotlin/Int // com.compose.sdl.graphics/g8.<get-g8>|<get-g8>@androidx.compose.ui.graphics.Color(){}[0]
final val com.compose.sdl.graphics/gradientCenter // com.compose.sdl.graphics/gradientCenter|@androidx.compose.ui.graphics.RadialGradient{}gradientCenter[0]
final fun (androidx.compose.ui.graphics/RadialGradient).<get-gradientCenter>(): androidx.compose.ui.geometry/Offset // com.compose.sdl.graphics/gradientCenter.<get-gradientCenter>|<get-gradientCenter>@androidx.compose.ui.graphics.RadialGradient(){}[0]
final val com.compose.sdl.graphics/gradientCenter // com.compose.sdl.graphics/gradientCenter|@androidx.compose.ui.graphics.SweepGradient{}gradientCenter[0]
@@ -9478,8 +9397,6 @@ final val com.compose.sdl.graphics/gradientTileMode // com.compose.sdl.graphics/
final fun (androidx.compose.ui.graphics/LinearGradient).<get-gradientTileMode>(): androidx.compose.ui.graphics/TileMode // com.compose.sdl.graphics/gradientTileMode.<get-gradientTileMode>|<get-gradientTileMode>@androidx.compose.ui.graphics.LinearGradient(){}[0]
final val com.compose.sdl.graphics/gradientTileMode // com.compose.sdl.graphics/gradientTileMode|@androidx.compose.ui.graphics.RadialGradient{}gradientTileMode[0]
final fun (androidx.compose.ui.graphics/RadialGradient).<get-gradientTileMode>(): androidx.compose.ui.graphics/TileMode // com.compose.sdl.graphics/gradientTileMode.<get-gradientTileMode>|<get-gradientTileMode>@androidx.compose.ui.graphics.RadialGradient(){}[0]
final val com.compose.sdl.graphics/r8 // com.compose.sdl.graphics/r8|@androidx.compose.ui.graphics.Color{}r8[0]
final fun (androidx.compose.ui.graphics/Color).<get-r8>(): kotlin/Int // com.compose.sdl.graphics/r8.<get-r8>|<get-r8>@androidx.compose.ui.graphics.Color(){}[0]
final val com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop // com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop|#static{}com_compose_sdl_icons_IconFont$stableprop[0]
final val com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop // com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop|#static{}com_compose_sdl_input_LegacyPointerEvent$stableprop[0]
final val com.compose.sdl.layout/intOffset // com.compose.sdl.layout/intOffset|@androidx.compose.ui.layout.LayoutCoordinates{}intOffset[0]
@@ -9512,12 +9429,14 @@ final val com.compose.sdl.window/com_compose_sdl_window_PopupHostState$stablepro
final val com.compose.sdl/LocalComposeNativeWindow // com.compose.sdl/LocalComposeNativeWindow|{}LocalComposeNativeWindow[0]
final fun <get-LocalComposeNativeWindow>(): androidx.compose.runtime/ProvidableCompositionLocal<com.compose.sdl/ComposeNativeWindow> // com.compose.sdl/LocalComposeNativeWindow.<get-LocalComposeNativeWindow>|<get-LocalComposeNativeWindow>(){}[0]
final val com.compose.sdl/com_compose_sdl_AppEvent$stableprop // com.compose.sdl/com_compose_sdl_AppEvent$stableprop|#static{}com_compose_sdl_AppEvent$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop|#static{}com_compose_sdl_AppEvent_Drop$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop|#static{}com_compose_sdl_AppEvent_Key$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop|#static{}com_compose_sdl_AppEvent_MouseWheel$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop|#static{}com_compose_sdl_AppEvent_Pointer$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop|#static{}com_compose_sdl_AppEvent_Quit$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop|#static{}com_compose_sdl_AppEvent_RedrawNeeded$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop|#static{}com_compose_sdl_AppEvent_TextInput$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop|#static{}com_compose_sdl_AppEvent_WindowActivation$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop|#static{}com_compose_sdl_AppEvent_WindowClose$stableprop[0]
final val com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop // com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop|#static{}com_compose_sdl_AppEvent_WindowResized$stableprop[0]
final val com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop // com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop|#static{}com_compose_sdl_ComposeNativeWindow$stableprop[0]
@@ -9655,6 +9574,8 @@ final var androidx.compose.ui/isDialogAnimationEnabled // androidx.compose.ui/is
final var androidx.compose.ui/useLegacyRenderNodeLayers // androidx.compose.ui/useLegacyRenderNodeLayers|@androidx.compose.ui.ComposeUiFlags{}useLegacyRenderNodeLayers[0]
final fun (androidx.compose.ui/ComposeUiFlags).<get-useLegacyRenderNodeLayers>(): kotlin/Boolean // androidx.compose.ui/useLegacyRenderNodeLayers.<get-useLegacyRenderNodeLayers>|<get-useLegacyRenderNodeLayers>@androidx.compose.ui.ComposeUiFlags(){}[0]
final fun (androidx.compose.ui/ComposeUiFlags).<set-useLegacyRenderNodeLayers>(kotlin/Boolean) // androidx.compose.ui/useLegacyRenderNodeLayers.<set-useLegacyRenderNodeLayers>|<set-useLegacyRenderNodeLayers>@androidx.compose.ui.ComposeUiFlags(kotlin.Boolean){}[0]
final var com.compose.sdl.graphics/encodedImageDecoder // com.compose.sdl.graphics/encodedImageDecoder|{}encodedImageDecoder[0]
final fun <get-encodedImageDecoder>(): com.compose.sdl.graphics/EncodedImageDecoder? // com.compose.sdl.graphics/encodedImageDecoder.<get-encodedImageDecoder>|<get-encodedImageDecoder>(){}[0]
final var com.compose.sdl.res/currentImageLoader // com.compose.sdl.res/currentImageLoader|{}currentImageLoader[0]
final fun <get-currentImageLoader>(): com.compose.sdl.res/ImageLoader // com.compose.sdl.res/currentImageLoader.<get-currentImageLoader>|<get-currentImageLoader>(){}[0]
final fun <set-currentImageLoader>(com.compose.sdl.res/ImageLoader) // com.compose.sdl.res/currentImageLoader.<set-currentImageLoader>|<set-currentImageLoader>(com.compose.sdl.res.ImageLoader){}[0]
@@ -9703,9 +9624,6 @@ final fun (androidx.compose.ui.graphics/Canvas).androidx.compose.ui.graphics/sca
final fun (androidx.compose.ui.graphics/Color).androidx.compose.ui.graphics/compositeOver(androidx.compose.ui.graphics/Color): androidx.compose.ui.graphics/Color // androidx.compose.ui.graphics/compositeOver|compositeOver@androidx.compose.ui.graphics.Color(androidx.compose.ui.graphics.Color){}[0]
final fun (androidx.compose.ui.graphics/Color).androidx.compose.ui.graphics/luminance(): kotlin/Float // androidx.compose.ui.graphics/luminance|luminance@androidx.compose.ui.graphics.Color(){}[0]
final fun (androidx.compose.ui.graphics/Color).androidx.compose.ui.graphics/toArgb(): kotlin/Int // androidx.compose.ui.graphics/toArgb|toArgb@androidx.compose.ui.graphics.Color(){}[0]
final fun (androidx.compose.ui.graphics/Color).com.compose.sdl.graphics/blend(androidx.compose.ui.graphics/Color, kotlin/Float): androidx.compose.ui.graphics/Color // com.compose.sdl.graphics/blend|blend@androidx.compose.ui.graphics.Color(androidx.compose.ui.graphics.Color;kotlin.Float){}[0]
final fun (androidx.compose.ui.graphics/Color).com.compose.sdl.graphics/darken(kotlin/Float): androidx.compose.ui.graphics/Color // com.compose.sdl.graphics/darken|darken@androidx.compose.ui.graphics.Color(kotlin.Float){}[0]
final fun (androidx.compose.ui.graphics/Color).com.compose.sdl.graphics/lighten(kotlin/Float): androidx.compose.ui.graphics/Color // com.compose.sdl.graphics/lighten|lighten@androidx.compose.ui.graphics.Color(kotlin.Float){}[0]
final fun (androidx.compose.ui.graphics/ImageBitmap).androidx.compose.ui.graphics/toPixelMap(kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/Int = ..., kotlin/IntArray = ..., kotlin/Int = ..., kotlin/Int = ...): androidx.compose.ui.graphics/PixelMap // androidx.compose.ui.graphics/toPixelMap|toPixelMap@androidx.compose.ui.graphics.ImageBitmap(kotlin.Int;kotlin.Int;kotlin.Int;kotlin.Int;kotlin.IntArray;kotlin.Int;kotlin.Int){}[0]
final fun (androidx.compose.ui.graphics/Matrix).androidx.compose.ui.graphics/isIdentity(): kotlin/Boolean // androidx.compose.ui.graphics/isIdentity|isIdentity@androidx.compose.ui.graphics.Matrix(){}[0]
final fun (androidx.compose.ui.graphics/Path).androidx.compose.ui.graphics/addOutline(androidx.compose.ui.graphics/Outline) // androidx.compose.ui.graphics/addOutline|addOutline@androidx.compose.ui.graphics.Path(androidx.compose.ui.graphics.Outline){}[0]
@@ -9908,12 +9826,6 @@ final fun (androidx.compose.ui/Modifier).androidx.compose.ui/preferredFrameRate(
final fun (androidx.compose.ui/Modifier).androidx.compose.ui/preferredFrameRate(kotlin/Float): androidx.compose.ui/Modifier // androidx.compose.ui/preferredFrameRate|preferredFrameRate@androidx.compose.ui.Modifier(kotlin.Float){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.ui/sensitiveContent(kotlin/Boolean = ...): androidx.compose.ui/Modifier // androidx.compose.ui/sensitiveContent|sensitiveContent@androidx.compose.ui.Modifier(kotlin.Boolean){}[0]
final fun (androidx.compose.ui/Modifier).androidx.compose.ui/zIndex(kotlin/Float): androidx.compose.ui/Modifier // androidx.compose.ui/zIndex|zIndex@androidx.compose.ui.Modifier(kotlin.Float){}[0]
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onDrag(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> = ..., kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit> = ..., kotlin/Function0<kotlin/Unit> = ...): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onDrag|onDrag@androidx.compose.ui.Modifier(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>;kotlin.Function0<kotlin.Unit>){}[0]
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onMiddleClick(kotlin/Function0<kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onMiddleClick|onMiddleClick@androidx.compose.ui.Modifier(kotlin.Function0<kotlin.Unit>){}[0]
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onPressed(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onPressed|onPressed@androidx.compose.ui.Modifier(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onSecondaryClick(kotlin/Function2<kotlin/Int, kotlin/Int, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onSecondaryClick|onSecondaryClick@androidx.compose.ui.Modifier(kotlin.Function2<kotlin.Int,kotlin.Int,kotlin.Unit>){}[0]
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/onTextInput(kotlin/Function1<kotlin/String, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/onTextInput|onTextInput@androidx.compose.ui.Modifier(kotlin.Function1<kotlin.String,kotlin.Unit>){}[0]
final fun (androidx.compose.ui/Modifier).com.compose.sdl.modifier/pressable(kotlin/Function1<kotlin/Boolean, kotlin/Unit>): androidx.compose.ui/Modifier // com.compose.sdl.modifier/pressable|pressable@androidx.compose.ui.Modifier(kotlin.Function1<kotlin.Boolean,kotlin.Unit>){}[0]
final fun (kotlin.collections/List<androidx.compose.ui.graphics.vector/PathNode>).androidx.compose.ui.graphics.vector/toPath(androidx.compose.ui.graphics/Path = ...): androidx.compose.ui.graphics/Path // androidx.compose.ui.graphics.vector/toPath|toPath@kotlin.collections.List<androidx.compose.ui.graphics.vector.PathNode>(androidx.compose.ui.graphics.Path){}[0]
final fun (kotlin/ByteArray).androidx.compose.ui.graphics/decodeToImageBitmap(): androidx.compose.ui.graphics/ImageBitmap // androidx.compose.ui.graphics/decodeToImageBitmap|decodeToImageBitmap@kotlin.ByteArray(){}[0]
final fun (kotlin/CharSequence).androidx.compose.ui.text/substring(androidx.compose.ui.text/TextRange): kotlin/String // androidx.compose.ui.text/substring|substring@kotlin.CharSequence(androidx.compose.ui.text.TextRange){}[0]
@@ -10168,6 +10080,7 @@ final fun androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElement
final fun androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop_getter(): kotlin/Int // androidx.compose.ui.platform/androidx_compose_ui_platform_ValueElementSequence$stableprop_getter|androidx_compose_ui_platform_ValueElementSequence$stableprop_getter(){}[0]
final fun androidx.compose.ui.platform/findComposeDefaultViewModelStoreOwner(androidx.compose.runtime/Composer?, kotlin/Int): androidx.lifecycle/ViewModelStoreOwner? // androidx.compose.ui.platform/findComposeDefaultViewModelStoreOwner|findComposeDefaultViewModelStoreOwner(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun androidx.compose.ui.platform/findDefaultNavigationEventDispatcherOwner(androidx.compose.runtime/Composer?, kotlin/Int): androidx.navigationevent/NavigationEventDispatcherOwner? // androidx.compose.ui.platform/findDefaultNavigationEventDispatcherOwner|findDefaultNavigationEventDispatcherOwner(androidx.compose.runtime.Composer?;kotlin.Int){}[0]
final fun androidx.compose.ui.platform/platformClipboard(): androidx.compose.ui.platform/Clipboard // androidx.compose.ui.platform/platformClipboard|platformClipboard(){}[0]
final fun androidx.compose.ui.scene/androidx_compose_ui_scene_ComposeScenePointer$stableprop_getter(): kotlin/Int // androidx.compose.ui.scene/androidx_compose_ui_scene_ComposeScenePointer$stableprop_getter|androidx_compose_ui_scene_ComposeScenePointer$stableprop_getter(){}[0]
final fun androidx.compose.ui.semantics/androidx_compose_ui_semantics_AccessibilityAction$stableprop_getter(): kotlin/Int // androidx.compose.ui.semantics/androidx_compose_ui_semantics_AccessibilityAction$stableprop_getter|androidx_compose_ui_semantics_AccessibilityAction$stableprop_getter(){}[0]
final fun androidx.compose.ui.semantics/androidx_compose_ui_semantics_CollectionInfo$stableprop_getter(): kotlin/Int // androidx.compose.ui.semantics/androidx_compose_ui_semantics_CollectionInfo$stableprop_getter|androidx_compose_ui_semantics_CollectionInfo$stableprop_getter(){}[0]
@@ -10303,18 +10216,6 @@ final fun com.compose.sdl.element/com_compose_sdl_element_ClipModifier$stablepro
final fun com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_ClipNode$stableprop_getter|com_compose_sdl_element_ClipNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerModifier$stableprop_getter|com_compose_sdl_element_GraphicsLayerModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_GraphicsLayerNode$stableprop_getter|com_compose_sdl_element_GraphicsLayerNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_MiddleClickModifier$stableprop_getter|com_compose_sdl_element_MiddleClickModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_MiddleClickNode$stableprop_getter|com_compose_sdl_element_MiddleClickNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnDragModifier$stableprop_getter|com_compose_sdl_element_OnDragModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnDragNode$stableprop_getter|com_compose_sdl_element_OnDragNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnPressedModifier$stableprop_getter|com_compose_sdl_element_OnPressedModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnPressedNode$stableprop_getter|com_compose_sdl_element_OnPressedNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnTextInputModifier$stableprop_getter|com_compose_sdl_element_OnTextInputModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_OnTextInputNode$stableprop_getter|com_compose_sdl_element_OnTextInputNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_PressableModifier$stableprop_getter|com_compose_sdl_element_PressableModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_PressableNode$stableprop_getter|com_compose_sdl_element_PressableNode$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickModifier$stableprop_getter|com_compose_sdl_element_SecondaryClickModifier$stableprop_getter(){}[0]
final fun com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop_getter(): kotlin/Int // com.compose.sdl.element/com_compose_sdl_element_SecondaryClickNode$stableprop_getter|com_compose_sdl_element_SecondaryClickNode$stableprop_getter(){}[0]
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_Close$stableprop_getter|com_compose_sdl_graphics_PathCommand_Close$stableprop_getter(){}[0]
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_CubicTo$stableprop_getter|com_compose_sdl_graphics_PathCommand_CubicTo$stableprop_getter(){}[0]
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_PathCommand_LineTo$stableprop_getter|com_compose_sdl_graphics_PathCommand_LineTo$stableprop_getter(){}[0]
@@ -10325,6 +10226,7 @@ final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectImageBitmap$s
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPaint$stableprop_getter|com_compose_sdl_graphics_ProjectPaint$stableprop_getter(){}[0]
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPath$stableprop_getter|com_compose_sdl_graphics_ProjectPath$stableprop_getter(){}[0]
final fun com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop_getter(): kotlin/Int // com.compose.sdl.graphics/com_compose_sdl_graphics_ProjectPathIterator$stableprop_getter|com_compose_sdl_graphics_ProjectPathIterator$stableprop_getter(){}[0]
final fun com.compose.sdl.graphics/decodeEncodedImageBitmap(kotlin/ByteArray): androidx.compose.ui.graphics/ImageBitmap? // com.compose.sdl.graphics/decodeEncodedImageBitmap|decodeEncodedImageBitmap(kotlin.ByteArray){}[0]
final fun com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop_getter(): kotlin/Int // com.compose.sdl.icons/com_compose_sdl_icons_IconFont$stableprop_getter|com_compose_sdl_icons_IconFont$stableprop_getter(){}[0]
final fun com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop_getter(): kotlin/Int // com.compose.sdl.input/com_compose_sdl_input_LegacyPointerEvent$stableprop_getter|com_compose_sdl_input_LegacyPointerEvent$stableprop_getter(){}[0]
final fun com.compose.sdl.node/com_compose_sdl_node_ComposeRootHost$stableprop_getter(): kotlin/Int // com.compose.sdl.node/com_compose_sdl_node_ComposeRootHost$stableprop_getter|com_compose_sdl_node_ComposeRootHost$stableprop_getter(){}[0]
@@ -10358,12 +10260,14 @@ final fun com.compose.sdl.window/com_compose_sdl_window_PopupHostState$stablepro
final fun com.compose.sdl.window/createPopupHostState(): com.compose.sdl.window/PopupHostState // com.compose.sdl.window/createPopupHostState|createPopupHostState(){}[0]
final fun com.compose.sdl/appDataDir(kotlin/String, kotlin/String): kotlin/String? // com.compose.sdl/appDataDir|appDataDir(kotlin.String;kotlin.String){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent$stableprop_getter|com_compose_sdl_AppEvent$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Drop$stableprop_getter|com_compose_sdl_AppEvent_Drop$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Key$stableprop_getter|com_compose_sdl_AppEvent_Key$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_MouseWheel$stableprop_getter|com_compose_sdl_AppEvent_MouseWheel$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Pointer$stableprop_getter|com_compose_sdl_AppEvent_Pointer$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_Quit$stableprop_getter|com_compose_sdl_AppEvent_Quit$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_RedrawNeeded$stableprop_getter|com_compose_sdl_AppEvent_RedrawNeeded$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_TextInput$stableprop_getter|com_compose_sdl_AppEvent_TextInput$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_WindowActivation$stableprop_getter|com_compose_sdl_AppEvent_WindowActivation$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_WindowClose$stableprop_getter|com_compose_sdl_AppEvent_WindowClose$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_AppEvent_WindowResized$stableprop_getter|com_compose_sdl_AppEvent_WindowResized$stableprop_getter(){}[0]
final fun com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop_getter(): kotlin/Int // com.compose.sdl/com_compose_sdl_ComposeNativeWindow$stableprop_getter|com_compose_sdl_ComposeNativeWindow$stableprop_getter(){}[0]
+1 -1
View File
@@ -32,7 +32,7 @@ plugins {
val useSdl3Everywhere = (findProperty("renderer") as? String) == "sdl3"
// All targets pull headers from the in-repo static build tree at <repo>/libs,
// populated by scripts/build-sdl/build-all.sh (or the per-library scripts).
// populated by scripts/build-sdl/build-all.py (optionally one library at a time).
// Same paths on macOS / Linux / Windows — the .def files are pathless and
// rely on these -I injections. Cross-target cinterop indexing under
// kotlin.mpp.enableCInteropCommonization is fine: clang silently ignores -I
@@ -6,7 +6,7 @@ headerFilter = SDL3/**
# archive location comes from :ui build.gradle.kts (-libraryPath) because
# .def files can't reference $rootDir. The linker options below list the
# system frameworks / libs SDL3's static build depends on (see the Libs
# line in libs/SDL3/lib/pkgconfig/sdl3.pc after build-sdl3.sh runs) —
# line in libs/SDL3/lib/pkgconfig/sdl3.pc after build-all.py runs) —
# cinterop propagates them through the klib to the final app link.
staticLibraries = libSDL3.a
@@ -5,6 +5,6 @@ depends = sdl3
# libSDL3_image.a + its vendored codec archives (PNG/JPG built-in via stb,
# WEBP, SVG built-in) are all baked into the cinterop klib. See sdl3.def —
# the static archive location is injected via :ui build.gradle.kts
# (-libraryPath). build-sdl3-image.sh normalises libzlibstatic.a → libz.a
# on Windows so the same filename works everywhere.
# (-libraryPath). build-all.py's sdl3-image step normalises libzlibstatic.a
# → libz.a on Windows so the same filename works everywhere.
staticLibraries = libSDL3_image.a libpng16.a libz.a libwebp.a libwebpdemux.a libwebpmux.a libsharpyuv.a
@@ -7,18 +7,22 @@ import androidx.compose.ui.graphics.ImageBitmap
// ==================
/* Decodes an ENCODED image (png / jpg / webp / bmp / gif / svg bytes) into a
drawable [ImageBitmap]. The active renderer registers its implementation —
the SDL backend goes through SDL3_image (see Sdl3EncodedImageDecoder); the
Skia renderer never registers because its resources pipeline decodes through
Skia directly (vendored skikoRenderer actuals in :components-resources).
drawable [ImageBitmap]. The active renderer registers its implementation at
backend construction — the SDL backend goes through SDL3_image
(Sdl3EncodedImageDecoder), the Skia backend through Image.makeFromEncoded /
SVGDOM (SkiaEncodedImageDecoder). :components-resources' actuals share this
hook under BOTH renderers (its skikoRendererMain reuses the SDL actuals).
Consumed by :components-resources' SDL actuals (`ByteArray.toImageBitmap`,
`SvgElement.toSvgPainter`) so painterResource(Res.drawable.x) works without
that module reaching into renderer internals. */
Consumed by `ByteArray.toImageBitmap` / `SvgElement.toSvgPainter` so
painterResource(Res.drawable.x) works without that module reaching into
renderer internals. */
interface EncodedImageDecoder {
fun decode(inBytes: ByteArray): ImageBitmap?
}
/* Volatile: written by the render backend on the main thread, read by the
resources pipeline on Dispatchers.Default workers. */
@kotlin.concurrent.Volatile
var encodedImageDecoder: EncodedImageDecoder? = null
internal set
@@ -31,29 +31,47 @@ internal var currentMainCanvas: Sdl3Canvas? = null
// blits it back — with the Icon tint applied through SDL_SetTextureColorMod.
@OptIn(ExperimentalForeignApi::class)
internal class SdlImageBitmap(
inRenderer: COpaquePointer,
private val fRenderer: COpaquePointer,
override val width: Int,
override val height: Int,
override val config: ImageBitmapConfig,
override val hasAlpha: Boolean,
override val colorSpace: ColorSpace,
// A pre-made texture (the encoded-image decode path — see
// Sdl3EncodedImageDecoder); null → create a render TARGET for the
// vector-rasterisation path below.
inDecodedTexture: COpaquePointer? = null,
// A surface decoded OFF the main thread (the encoded-image path — see
// Sdl3EncodedImageDecoder); converted to a texture on the first draw.
// null → create a render TARGET for the vector-rasterisation path below
// (that path always constructs on the main thread).
private var fDecodedSurface: CPointer<SDL_Surface>? = null,
) : ImageBitmap {
// RGBA render-target texture, premultiplied blend for compositing back (content
// is drawn over a transparent clear with ordinary BLEND, leaving premultiplied
// colours — see Sdl3ClipTargets for the same reasoning).
val texture: COpaquePointer? = inDecodedTexture ?: SDL_CreateTexture(
inRenderer.reinterpret(),
private var fTexture: COpaquePointer? = if (fDecodedSurface != null) null else SDL_CreateTexture(
fRenderer.reinterpret(),
SDL_PIXELFORMAT_RGBA32,
SDL_TextureAccess.SDL_TEXTUREACCESS_TARGET,
maxOf(1, width),
maxOf(1, height),
)?.also { SDL_SetTextureBlendMode(it.reinterpret(), SDL_BLENDMODE_BLEND_PREMULTIPLIED) }
// SDL renderer calls are NOT thread-safe, and the resources pipeline
// decodes on Dispatchers.Default workers — so the decode path hands over a
// plain SDL_Surface and the texture is created here, lazily, on the first
// access (createCanvas / the draw paths — main thread only). Decoded
// surfaces carry STRAIGHT alpha → ordinary BLEND, unlike the premultiplied
// render-target path above.
val texture: COpaquePointer?
get() {
fDecodedSurface?.let { vSurface ->
fTexture = SDL_CreateTextureFromSurface(fRenderer.reinterpret(), vSurface)
?.also { SDL_SetTextureBlendMode(it.reinterpret(), SDL_BLENDMODE_BLEND) }
SDL_DestroySurface(vSurface)
fDecodedSurface = null
}
return fTexture
}
override fun readPixels(
buffer: IntArray,
startX: Int,
@@ -116,24 +134,22 @@ internal class Sdl3EncodedImageDecoder(
override fun decode(inBytes: ByteArray): ImageBitmap? {
if (inBytes.isEmpty()) return null
// Pure decode only — IMG_Load_IO touches no renderer state, so it is
// safe on the resources pipeline's Dispatchers.Default workers. The
// texture is created from this surface on the first MAIN-THREAD draw
// (SdlImageBitmap.texture) — SDL renderer calls are not thread-safe.
val vSurface = inBytes.usePinned { vPinned ->
val vIo = SDL_IOFromConstMem(vPinned.addressOf(0), inBytes.size.convert())
?: return@usePinned null
sdl3_image.IMG_Load_IO(vIo.reinterpret(), true)
} ?: return null
val vSdlSurface = vSurface.reinterpret<SDL_Surface>()
val vW = vSdlSurface.pointed.w
val vH = vSdlSurface.pointed.h
val vTex = SDL_CreateTextureFromSurface(fRenderer.reinterpret(), vSdlSurface)
SDL_DestroySurface(vSdlSurface)
if (vTex == null) return null
SDL_SetTextureBlendMode(vTex.reinterpret(), SDL_BLENDMODE_BLEND)
return SdlImageBitmap(
fRenderer, vW, vH,
fRenderer, vSdlSurface.pointed.w, vSdlSurface.pointed.h,
config = ImageBitmapConfig.Argb8888,
hasAlpha = true,
colorSpace = androidx.compose.ui.graphics.colorspace.ColorSpaces.Srgb,
inDecodedTexture = vTex,
fDecodedSurface = vSdlSurface,
)
}
}
@@ -58,22 +58,6 @@ internal class SkiaImageCache {
}
}
/* SVGDOM → offscreen raster → Image. Falls back to a 100×100 canvas when
the document declares no explicit width/height (the Android-vector path
always supplies them). */
private fun rasterizeSvg(inBytes: ByteArray): Image? = runCatching {
val vDom = SVGDOM(Data.makeFromBytes(inBytes))
val vRoot = vDom.root
var vW = vRoot?.width?.value ?: 0f
var vH = vRoot?.height?.value ?: 0f
if (vW <= 0f) vW = 100f
if (vH <= 0f) vH = 100f
vDom.setContainerSize(vW, vH)
val vSurface = Surface.makeRasterN32Premul(vW.toInt().coerceAtLeast(1), vH.toInt().coerceAtLeast(1))
vDom.render(vSurface.canvas)
vSurface.makeImageSnapshot()
}.getOrNull()
// ==================
// MARK: Draw
// ==================
@@ -133,3 +117,23 @@ internal class SkiaImageCache {
fCache.clear()
}
}
// ==================
// MARK: SVG rasterisation (shared with SkiaEncodedImageDecoder)
// ==================
/* SVGDOM → offscreen raster → Image. Falls back to a 100×100 canvas when
the document declares no explicit width/height (the Android-vector path
always supplies them). */
internal fun rasterizeSvg(inBytes: ByteArray): Image? = runCatching {
val vDom = SVGDOM(Data.makeFromBytes(inBytes))
val vRoot = vDom.root
var vW = vRoot?.width?.value ?: 0f
var vH = vRoot?.height?.value ?: 0f
if (vW <= 0f) vW = 100f
if (vH <= 0f) vH = 100f
vDom.setContainerSize(vW, vH)
val vSurface = Surface.makeRasterN32Premul(vW.toInt().coerceAtLeast(1), vH.toInt().coerceAtLeast(1))
vDom.render(vSurface.canvas)
vSurface.makeImageSnapshot()
}.getOrNull()
@@ -5,6 +5,8 @@ import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.ImageBitmapConfig
import androidx.compose.ui.graphics.colorspace.ColorSpace
import androidx.compose.ui.graphics.colorspace.ColorSpaces
import com.compose.sdl.graphics.EncodedImageDecoder
import com.compose.sdl.graphics.OffscreenRenderer
import org.jetbrains.skia.Image
import org.jetbrains.skia.Surface
@@ -86,3 +88,32 @@ internal class SkiaOffscreenRenderer(
)
}
}
// ==================
// MARK: SkiaEncodedImageDecoder
// ==================
/* Encoded-image decode hook impl for the Skia renderer — the counterpart of
Sdl3EncodedImageDecoder, consumed by :components-resources' actuals
(painterResource / SVG). Raster formats go through Image.makeFromEncoded;
when that fails the bytes are retried as SVG through the same SVGDOM
rasterisation SkiaImageCache uses. Pure CPU raster (no GrContext), so it is
safe on the resources pipeline's Dispatchers.Default workers. */
internal class SkiaEncodedImageDecoder : EncodedImageDecoder {
override fun decode(inBytes: ByteArray): ImageBitmap? {
if (inBytes.isEmpty()) return null
val vImg = runCatching { Image.makeFromEncoded(inBytes) }.getOrNull()
?: rasterizeSvg(inBytes)
?: return null
val vBmp = SkiaImageBitmap(
vImg.width, vImg.height,
config = ImageBitmapConfig.Argb8888,
hasAlpha = true,
colorSpace = ColorSpaces.Srgb,
)
vBmp.surface.canvas.drawImage(vImg, 0f, 0f)
vImg.close()
return vBmp
}
}
@@ -33,6 +33,18 @@ internal class SkiaRenderBackend(
private val fSkiaImageCache = SkiaImageCache()
private var fCurrentCanvas: Canvas? = null
init {
// Encoded-image decode (painterResource / SVG in :components-resources).
// Registered at CONSTRUCTION, not first frame: the official resources
// pipeline decodes during COMPOSITION, which runs before beginFrame —
// and on Dispatchers.Default workers, which the CPU-raster Skia decoder
// tolerates. Without this the first painterResource on a Skia build
// dies with "Image decode failed" (issue #1).
if (com.compose.sdl.graphics.encodedImageDecoder == null) {
com.compose.sdl.graphics.encodedImageDecoder = SkiaEncodedImageDecoder()
}
}
override val textMeasurer: TextMeasurer
get() = fSkiaTextRenderer.textMeasurer
+85 -13
View File
@@ -13,6 +13,31 @@ plugins {
// Skip mingwX64 on non-Windows hosts; see root build.gradle.kts.
val vHostSupportsMingw = rootProject.extra["vHostSupportsMingw"] as Boolean
// JVM parity target's Compose version — the dev build matching the pinned
// COMPOSE_CORE_REF (see scripts/compose-fork/compose.properties). material3
// rides its OWN release train: same +dev build number, different base
// version. Gradle orders "+dev" qualifiers BELOW the plain version, so
// currentOs's beta01 would win conflict resolution — force the core-repo
// groups on every jvm configuration. Umbrella-repo groups (desktop,
// components) are NOT forced: their dev numbering differs.
val vComposeJvmVersion = "1.12.0-beta01+dev4324"
val vComposeM3JvmVersion = "1.12.0-alpha03+dev4324"
val vComposeJvmForced = mapOf(
"org.jetbrains.compose.runtime" to vComposeJvmVersion,
"org.jetbrains.compose.ui" to vComposeJvmVersion,
"org.jetbrains.compose.foundation" to vComposeJvmVersion,
"org.jetbrains.compose.animation" to vComposeJvmVersion,
"org.jetbrains.compose.material" to vComposeJvmVersion,
"org.jetbrains.compose.material3" to vComposeM3JvmVersion,
)
configurations.configureEach {
if (name.startsWith("jvm")) {
resolutionStrategy.eachDependency {
vComposeJvmForced[requested.group]?.let { useVersion(it) }
}
}
}
kotlin {
jvm()
@@ -72,30 +97,60 @@ kotlin {
// substitute it for the vendored :components-resources below
// (the Maven artifact ships no mingwX64/linux klibs).
implementation(compose.components.resources)
// Common API on both stacks (its native/jvm actuals pick the
// right rendering pipeline) — usable from shared screens.
implementation(project(":material-symbols"))
// Official Maven coords for everything the shared screens
// touch, so commonMain metadata (and the IDE's common
// analysis) resolve. Metadata + jvm resolve them from Maven;
// the NATIVE configurations substitute each for its port
// module (root build's FULL-COMMONIZATION BRIDGE). Every
// artifact must be declared DIRECTLY: transitives of a
// substituted module are invisible to the granular-metadata
// visibility check. The runtime is the official klib
// everywhere, never substituted (jvm configs force the +dev
// build above).
implementation("org.jetbrains.compose.runtime:runtime:1.11.1")
implementation("org.jetbrains.compose.ui:ui:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-graphics:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-text:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-unit:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-geometry:$vComposeJvmVersion")
implementation("org.jetbrains.compose.ui:ui-util:$vComposeJvmVersion")
// The common @Preview (androidx.compose.ui.tooling.preview) —
// IDE-only metadata; previews render through the jvm target.
implementation("org.jetbrains.compose.ui:ui-tooling-preview:$vComposeJvmVersion")
implementation("org.jetbrains.compose.foundation:foundation:$vComposeJvmVersion")
implementation("org.jetbrains.compose.foundation:foundation-layout:$vComposeJvmVersion")
implementation("org.jetbrains.compose.animation:animation:$vComposeJvmVersion")
implementation("org.jetbrains.compose.animation:animation-core:$vComposeJvmVersion")
implementation("org.jetbrains.compose.material3:material3:$vComposeM3JvmVersion")
// nav3 + lifecycle: real KMP Maven artifacts on every target
// (see "Known Compatible" in CLAUDE.md) — except navigation3-ui,
// which the bridge substitutes for the vendored :navigation3-ui
// on native.
implementation("androidx.navigation3:navigation3-runtime:1.1.4")
implementation("org.jetbrains.androidx.navigation3:navigation3-ui:1.2.0-alpha02")
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.11.0")
}
}
nativeMain {
dependencies {
implementation(project(":window"))
implementation(project(":material3"))
implementation(project(":material-symbols"))
implementation(project(":navigation3-ui"))
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.11.0")
}
}
jvmMain {
dependencies {
implementation("org.jetbrains.compose.runtime:runtime:1.12.0-alpha03")
implementation("org.jetbrains.compose.foundation:foundation:1.12.0-alpha03")
implementation("org.jetbrains.compose.animation:animation:1.12.0-alpha03")
implementation("org.jetbrains.compose.material3:material3:1.12.0-alpha03")
implementation("org.jetbrains.compose.ui:ui:1.12.0-alpha03")
// The +dev builds matching scripts/compose-fork's pinned
// COMPOSE_CORE_REF come from the version forcing above —
// byte-exact parity with the vendored sources, and (unlike
// the published beta01) desktop loadTypeface applies
// Font.variationSettings, so the Material Symbols
// variable-font axes work on JVM.
implementation("androidx.navigation3:navigation3-runtime:1.2.0-alpha05")
implementation("org.jetbrains.androidx.navigation3:navigation3-ui:1.2.0-alpha02")
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:2.11.0")
implementation(compose.desktop.currentOs)
implementation("org.jetbrains.compose.material:material-icons-extended:1.7.3")
}
}
}
@@ -238,3 +293,20 @@ for (variant in variants) {
}
}
}
// ==================
// MARK: Stage Material Symbols fonts onto the JVM classpath
// ==================
// The :material-symbols JVM actual loads each style's font from the classpath
// at font/<Style>.ttf — the JVM analog of the data.kres font/ entries above.
// Same style detection: only the fonts the sources actually reference.
tasks.named<ProcessResources>("jvmProcessResources") {
val vSymbolsProject = rootProject.project(":material-symbols")
for (vStyle in vUsedStyles) {
@Suppress("UNCHECKED_CAST")
val vFontFile = vSymbolsProject.extra["iconFontFile$vStyle"] as Provider<RegularFile>
val vDownloadTask = vSymbolsProject.extra["iconFontDownloadTask$vStyle"] as TaskProvider<*>
from(vFontFile) { into("font") }
dependsOn(vDownloadTask)
}
}
@@ -60,6 +60,7 @@ val CoreScreens: List<DemoScreen> = listOf(
val Material3Screens: List<DemoScreen> = listOf(
// Ordered by family: typography, buttons, inputs, containers, navigation, overlays.
DemoScreen("Text") { TextScreen() },
DemoScreen("Icons") { IconsScreen() },
DemoScreen("Buttons") { ButtonsScreen() },
DemoScreen("ButtonsExtra") { M3ButtonsExtraScreen() },
DemoScreen("Fab") { FabScreen() },
@@ -86,10 +87,17 @@ val Navigation3Screens: List<DemoScreen> = listOf(
DemoScreen("Navigation3") { Navigation3Screen() },
)
// Screens that aren't a Compose-artifact showcase: project utility modules
// (Material Symbols engine, ...).
val OthersScreens: List<DemoScreen> = listOf(
DemoScreen("MaterialSymbols") { MaterialSymbolsScreen() },
)
val commonCategories: List<DemoCategory> = listOf(
DemoCategory("core", "Core", CoreScreens),
DemoCategory("material3", "Material3", Material3Screens),
DemoCategory("navigation3", "Navigation3", Navigation3Screens),
DemoCategory("others", "Others", OthersScreens),
)
/* Platform extras that fill the dropdown dynamically: screens that can't be
@@ -0,0 +1,26 @@
package demo.shim
import androidx.compose.ui.platform.ClipEntry
// ==================
// MARK: DemoClipboard — portable ClipEntry construction / reading
// ==================
/* Upstream Compose has no COMMON way to build or read a ClipEntry — every
platform actual differs. This port mirrors upstream's macOS actual
(ClipEntry.withPlainText / getPlainText / getImage), while upstream JVM
desktop wraps an AWT Transferable and exposes nothing text-typed. Shared
screens go through these four helpers; each stack maps them 1:1 onto its
native shape. */
/* A ClipEntry carrying plain text, for Clipboard.setClipEntry. */
expect fun demoClipEntryOfText(text: String): ClipEntry
/* A ClipEntry carrying an image from already-PNG-encoded bytes. */
expect fun demoClipEntryOfPng(pngBytes: ByteArray): ClipEntry
/* The entry's plain text, or null when it carries none. */
expect fun ClipEntry.demoPlainText(): String?
/* The entry's image as PNG-encoded bytes, or null when it carries none. */
expect fun ClipEntry.demoPngImage(): ByteArray?
@@ -5,16 +5,18 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
// ==================
// MARK: DemoIcon — platform-neutral icon token
// ==================
/* A platform-neutral icon reference for the shared demo screens. On native it
maps to a Material Symbols codepoint rendered by the project icon-font engine
(com.compose.sdl.icons); on a future jvm target it maps to an
androidx.compose.material.icons ImageVector. Shared screens reference icons
ONLY through this enum, so the exact same code compiles on both stacks. */
/* A platform-neutral icon reference for the shared demo screens. Now that
:material-symbols exposes its API from commonMain (native draws through the
port's IconFont pipeline, JVM through upstream variable-font text), the
token resolves to a Material Symbols codepoint on BOTH stacks — the same
glyphs render everywhere, which is exactly what the parity build compares. */
enum class DemoIcon {
Home, Search, Person, Settings, Add, Edit, Favorite, Star, Close, Image,
Delete, Share, Check, MoreVert, ContentCopy, KeyboardArrowDown, Bookmark,
@@ -22,15 +24,50 @@ enum class DemoIcon {
ExpandMore, ExpandLess,
}
/* Renders [icon]. The portable stand-in for material3's Icon(imageVector, …) /
the project's MaterialSymbolsOutlined(codepoint, …). Deliberately exposes no
variable-font axes (fill / weight / grade / opticalSize) — those have no
upstream analog. */
/* Renders [icon] via MaterialSymbolsOutlined — the portable stand-in for
material3's Icon(imageVector, …). Color.Unspecified tint falls back to
material3's LocalContentColor inside MaterialSymbolsOutlined. */
@Composable
expect fun DemoIcon(
fun DemoIcon(
icon: DemoIcon,
contentDescription: String? = null,
modifier: Modifier = Modifier,
tint: Color = Color.Unspecified,
size: Dp = 24.dp,
)
) {
val codepoint = when (icon) {
DemoIcon.Home -> MaterialSymbols.Home
DemoIcon.Search -> MaterialSymbols.Search
DemoIcon.Person -> MaterialSymbols.Person
DemoIcon.Settings -> MaterialSymbols.Settings
DemoIcon.Add -> MaterialSymbols.Add
DemoIcon.Edit -> MaterialSymbols.Edit
DemoIcon.Favorite -> MaterialSymbols.Favorite
DemoIcon.Star -> MaterialSymbols.Star
DemoIcon.Close -> MaterialSymbols.Close
DemoIcon.Image -> MaterialSymbols.Image
DemoIcon.Delete -> MaterialSymbols.Delete
DemoIcon.Share -> MaterialSymbols.Share
DemoIcon.Check -> MaterialSymbols.Check
DemoIcon.MoreVert -> MaterialSymbols.MoreVert
DemoIcon.ContentCopy -> MaterialSymbols.ContentCopy
DemoIcon.KeyboardArrowDown -> MaterialSymbols.KeyboardArrowDown
DemoIcon.Bookmark -> MaterialSymbols.Bookmark
DemoIcon.Notifications -> MaterialSymbols.Notifications
DemoIcon.Menu -> MaterialSymbols.Menu
DemoIcon.ArrowBack -> MaterialSymbols.ArrowBack
DemoIcon.Save -> MaterialSymbols.Save
DemoIcon.Refresh -> MaterialSymbols.Refresh
DemoIcon.Download -> MaterialSymbols.Download
DemoIcon.Upload -> MaterialSymbols.Upload
DemoIcon.ExpandMore -> MaterialSymbols.ExpandMore
DemoIcon.ExpandLess -> MaterialSymbols.ExpandLess
}
MaterialSymbolsOutlined(
icon = codepoint,
contentDescription = contentDescription,
modifier = modifier,
tint = tint,
size = size,
)
}
@@ -1,42 +1,19 @@
package screens
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateDpAsState
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.animateIntAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -5,18 +5,17 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -4,22 +4,14 @@ package screens
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicSecureTextField
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
@@ -20,12 +20,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.PopupPositionProvider
// Foundation — the undecorated text primitive below material3's Text, plus the
@@ -1,13 +1,7 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -1,14 +1,15 @@
package screens
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.style.*
import androidx.compose.ui.unit.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
internal fun ButtonsScreen() {
@@ -1,14 +1,7 @@
package screens
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -18,8 +11,8 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -4,11 +4,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Card
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -3,19 +3,8 @@ package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.AssistChip
import androidx.compose.material3.ElevatedAssistChip
import androidx.compose.material3.ElevatedFilterChip
import androidx.compose.material3.ElevatedSuggestionChip
import androidx.compose.material3.FilterChip
import androidx.compose.material3.InputChip
import androidx.compose.material3.SuggestionChip
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
@@ -5,15 +5,12 @@ package screens
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -21,12 +18,11 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.Clipboard
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import demo.shim.demoDecodeImage
import demo.shim.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.jetbrains.compose.resources.readResourceBytes
@@ -43,9 +39,10 @@ private const val kLogoResourcePath = "composeResources/demo.generated.resources
// ==================
/* Round-trips text AND PNG images through the OS clipboard via LocalClipboard
(suspend, ClipEntry-typed) over SDL3's SDL_[GS]etClipboardText and
SDL_[GS]etClipboardData("image/png"). Text and images share one Compose
ClipEntry: getPlainText() vs getImage() surface whichever is present.
(suspend, ClipEntry-typed) — on native over SDL3's SDL_[GS]etClipboardText /
SDL_[GS]etClipboardData("image/png"), on JVM over the AWT clipboard.
ClipEntry construction/reading has NO common upstream API (each platform
actual differs), so this screen goes through demo.shim.DemoClipboard.
Non-composable callers reach it by capturing LocalClipboard.current +
rememberCoroutineScope() in composition and passing both into the callback. */
@Composable
@@ -68,8 +65,9 @@ internal fun ClipboardScreen() {
)
// ============
// Text copy — ClipEntry.withPlainText / getPlainText.
Section("Copy text", "scope.launch { clipboard.setClipEntry(ClipEntry.withPlainText(...)) }") {
// Text copy — demoClipEntryOfText (ClipEntry.withPlainText on native,
// AWT StringSelection on JVM).
Section("Copy text", "scope.launch { clipboard.setClipEntry(demoClipEntryOfText(...)) }") {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
OutlinedTextField(
value = draft,
@@ -78,7 +76,7 @@ internal fun ClipboardScreen() {
modifier = Modifier.fillMaxWidth(),
)
Button(onClick = {
scope.launch { clipboard.setClipEntry(ClipEntry.withPlainText(draft)) }
scope.launch { clipboard.setClipEntry(demoClipEntryOfText(draft)) }
note = "Copied ${draft.length} char(s) to the system clipboard."
}) {
Text("Copy text", color = MaterialTheme.colorScheme.onPrimary)
@@ -92,7 +90,7 @@ internal fun ClipboardScreen() {
// image-aware app (Preview / Paint / a browser tab) to verify.
Section(
"Copy image",
"readResourceBytes(\"drawable/compose_logo.png\") → ClipEntry.withImage(pngBytes). " +
"readResourceBytes(\"drawable/compose_logo.png\") → demoClipEntryOfPng(pngBytes). " +
"Paste into another app to verify.",
) {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
@@ -115,7 +113,7 @@ internal fun ClipboardScreen() {
scope.launch {
val vBytes = runCatching { readResourceBytes(kLogoResourcePath) }.getOrNull()
if (vBytes != null) {
clipboard.setClipEntry(ClipEntry.withImage(vBytes))
clipboard.setClipEntry(demoClipEntryOfPng(vBytes))
note = "Copied ${vBytes.size} byte(s) of PNG to the system clipboard."
} else {
note = "Failed to load the source image."
@@ -130,15 +128,15 @@ internal fun ClipboardScreen() {
// ============
// Paste — surfaces whatever's on the clipboard: text OR image.
Section("Paste", "clipboard.getClipEntry()?.getPlainText() / .getImage()") {
Section("Paste", "clipboard.getClipEntry()?.demoPlainText() / .demoPngImage()") {
Column(verticalArrangement = Arrangement.spacedBy(10.dp)) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
Button(onClick = {
pastedText = null; pastedImage = null; pastedNote = null
scope.launch {
val vEntry = clipboard.getClipEntry()
val vImage = vEntry?.getImage()
val vText = vEntry?.getPlainText()
val vImage = vEntry?.demoPngImage()
val vText = vEntry?.demoPlainText()
when {
vImage != null -> {
pastedImage = demoDecodeImage(vImage)
@@ -212,6 +210,6 @@ internal fun ClipboardScreen() {
modern Clipboard is intentionally suspend-only. */
private fun copyFromPlainFunction(scope: CoroutineScope, clipboard: Clipboard) {
scope.launch {
clipboard.setClipEntry(ClipEntry.withPlainText("Set from a plain, non-@Composable function."))
clipboard.setClipEntry(demoClipEntryOfText("Set from a plain, non-@Composable function."))
}
}
@@ -1,18 +1,23 @@
package screens
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.foundation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.unit.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
// ==================
// MARK: Colors screen — Material palette swatches
// ==================
@Preview
@Composable
internal fun ColorsScreen() {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
@@ -1,22 +1,15 @@
package screens
import androidx.compose.runtime.Composable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -1,13 +1,17 @@
package screens
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.style.*
import androidx.compose.ui.unit.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
internal fun CounterScreen() {
@@ -1,17 +1,12 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.dp
@@ -6,26 +6,8 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.PlainTooltip
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -4,23 +4,13 @@ import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.draganddrop.dragAndDropTarget
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draganddrop.DragAndDropEvent
@@ -3,16 +3,7 @@ package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FilledIconButton
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedIconButton
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
@@ -3,15 +3,7 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowColumn
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -3,25 +3,16 @@ package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -3,23 +3,12 @@ package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.dp
@@ -2,23 +2,13 @@ package screens
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -1,12 +1,7 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyHorizontalGrid
import androidx.compose.foundation.lazy.staggeredgrid.LazyHorizontalStaggeredGrid
@@ -0,0 +1,60 @@
package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.compose.sdl.icons.MaterialSymbols
import com.compose.sdl.icons.material.symbols.MaterialSymbolsOutlined
import com.compose.sdl.icons.material.symbols.MaterialSymbolsRounded
import com.compose.sdl.icons.material.symbols.MaterialSymbolsSharp
import demo.generated.resources.Res
import demo.generated.resources.heart
import org.jetbrains.compose.resources.painterResource
// ==================
// MARK: Icons screen — material3 icon APIs
// ==================
/* material3 icon APIs: Icon(painter) over compose resources and IconButton. */
@Composable
internal fun IconsScreen() {
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
ScreenTitle(
"Icons",
"material3 Icon(painter) over compose resources + IconButton.",
)
Section("Painter-based Icon", "Reads from composeResources/drawable/*.xml (Android vector) or *.svg.") {
Row(verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(16.dp)) {
Icon(painter = painterResource(Res.drawable.heart), contentDescription = "Heart")
Text("painterResource(Res.drawable.heart)", fontSize = 13.sp)
}
}
Section("IconButton", "40dp clickable circle. Hover overlay matches Material 1.") {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
IconButton(onClick = {}) {
MaterialSymbolsOutlined(MaterialSymbols.Favorite,
tint = MaterialTheme.colorScheme.primary, fill = 1f, weight = 600)
}
IconButton(onClick = {}) {
MaterialSymbolsRounded(MaterialSymbols.Share,
tint = MaterialTheme.colorScheme.onSurface)
}
IconButton(onClick = {}) {
MaterialSymbolsSharp(MaterialSymbols.MoreVert,
tint = MaterialTheme.colorScheme.onSurface)
}
}
}
}
}
@@ -1,21 +1,21 @@
package screens
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.draw.clip
import androidx.compose.runtime.*
import androidx.compose.foundation.*
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.painter.*
import androidx.compose.ui.layout.*
import androidx.compose.ui.unit.*
import demo.generated.resources.Res
import demo.generated.resources.compose_logo
import demo.generated.resources.heart
import demo.generated.resources.photo
import demo.generated.resources.star
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import demo.generated.resources.*
import org.jetbrains.compose.resources.painterResource
// ==================
@@ -1,10 +1,13 @@
package screens
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.width
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.unit.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
// ==================
// MARK: Interaction (hover / press / focus) screen
@@ -1,26 +1,21 @@
package screens
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.hoverable
import androidx.compose.foundation.interaction.HoverInteraction
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -1,13 +1,14 @@
package screens
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.unit.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
internal fun LayoutScreen() {
@@ -1,16 +1,23 @@
package screens
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.*
import androidx.compose.material3.*
import androidx.compose.ui.*
import androidx.compose.ui.graphics.*
import androidx.compose.ui.text.style.*
import androidx.compose.ui.unit.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
// ==================
// MARK: LazyColumn screen
@@ -1,22 +1,15 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -1,20 +1,11 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
@@ -4,13 +4,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.ListItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@@ -2,33 +2,9 @@
package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.AppBarColumn
import androidx.compose.material3.AppBarOverflowIndicator
import androidx.compose.material3.AppBarRow
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FlexibleBottomAppBar
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeFlexibleTopAppBar
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MediumFlexibleTopAppBar
import androidx.compose.material3.MediumTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TwoRowsTopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import demo.shim.DemoIcon
@@ -6,29 +6,8 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.ButtonGroup
import androidx.compose.material3.ElevatedToggleButton
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FilledIconToggleButton
import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.FilledTonalIconToggleButton
import androidx.compose.material3.IconToggleButton
import androidx.compose.material3.MultiChoiceSegmentedButtonRow
import androidx.compose.material3.OutlinedIconToggleButton
import androidx.compose.material3.OutlinedToggleButton
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SplitButtonDefaults
import androidx.compose.material3.SplitButtonLayout
import androidx.compose.material3.Text
import androidx.compose.material3.ToggleButton
import androidx.compose.material3.TonalToggleButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -3,14 +3,7 @@
package screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -2,34 +2,9 @@
package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.DismissibleDrawerSheet
import androidx.compose.material3.DismissibleNavigationDrawer
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.NavigationDrawerItem
import androidx.compose.material3.PermanentDrawerSheet
import androidx.compose.material3.PermanentNavigationDrawer
import androidx.compose.material3.Scrim
import androidx.compose.material3.Text
import androidx.compose.material3.rememberDrawerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -2,31 +2,9 @@
package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.FloatingActionButtonMenu
import androidx.compose.material3.FloatingActionButtonMenuItem
import androidx.compose.material3.HorizontalFloatingToolbar
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeExtendedFloatingActionButton
import androidx.compose.material3.LargeFloatingActionButton
import androidx.compose.material3.MediumExtendedFloatingActionButton
import androidx.compose.material3.MediumFloatingActionButton
import androidx.compose.material3.SmallExtendedFloatingActionButton
import androidx.compose.material3.Text
import androidx.compose.material3.ToggleFloatingActionButton
import androidx.compose.material3.VerticalFloatingToolbar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@@ -2,54 +2,10 @@
package screens
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.DropdownMenuGroup
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.DropdownMenuPopup
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.ExposedDropdownMenuAnchorType
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Label
import androidx.compose.material3.ListItemDefaults
import androidx.compose.material3.MaterialExpressiveTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MenuDefaults
import androidx.compose.material3.OutlinedSecureTextField
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.ProvideTextStyle
import androidx.compose.material3.RangeSlider
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScrollField
import androidx.compose.material3.ScrollFieldDefaults
import androidx.compose.material3.SecureTextField
import androidx.compose.material3.SegmentedListItem
import androidx.compose.material3.Snackbar
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.VerticalSlider
import androidx.compose.material3.rememberScrollFieldState
import androidx.compose.material3.rememberSliderState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

Some files were not shown because too many files have changed in this diff Show More