Skip to content

Rebuild native themes via CSS compiler (phase 2: module split)#4793

Draft
liannacasper wants to merge 75 commits intomasterfrom
rebuild-themes
Draft

Rebuild native themes via CSS compiler (phase 2: module split)#4793
liannacasper wants to merge 75 commits intomasterfrom
rebuild-themes

Conversation

@liannacasper
Copy link
Copy Markdown
Collaborator

Summary

First slice of the native-themes refactor planned in /plan. Extracts the Codename One CSS compiler into a thin maven/css-compiler module with clean dependencies (core + flute + sac) so the shipped iOS Modern (liquid-glass) and Android Material themes can be generated at framework build time without pulling in JavaSE / JavaFX / CEF / the Designer GUI.

  • Phase 1strictNoCef flag + enforceNoCef() pre-scan in CSSTheme + -no-cef CLI arg on CN1CSSCLI + new NoCefCSSCLI minimal entry point.
  • Phase 2EditableResources physically moved into maven/css-compiler; designer/javase imports stripped; four throwing hooks introduced; EditableResourcesEditor subclass in the Designer overrides the hooks. New com.codename1.ui.util.SVGDocument interface in core replaces the compile-time dep on impl.javase.SVG. CSSTheme, ResourcesMutator, Color, helpers, and the com.codename1.ui.util.xml package moved alongside. maven/designer now depends on codenameone-css-compiler.
  • Build pipelinescripts/build-native-themes.sh + smoke CSS at native-themes/{ios-modern,android-material}/theme.css + Themes/.gitignore.
  • CIpr.yml gains a step that installs css-compiler and runs the native-themes build; designer.yml switched to Maven for building the Designer jar + CLI CSS smoke + native-themes smoke under xvfb.

Plan: /Users/shai/.claude/plans/at-the-moment-we-dapper-origami.md (approved earlier).

Known follow-ups (not in this PR)

  • Ant Designer build (CodenameOneDesigner/build.xml) still expects all CSS classes under src/; needs source-root awareness of maven/css-compiler or NetBeans/Ant devs to switch to Maven.
  • ResourceEditorView ~line 2382 still calls EditableResources.open(...) returning a base instance — fine for the override-resource side path but a future EditableResourcesEditor.open(...) factory would be tidier.
  • Phase 3+ (real component CSS, port installNativeTheme() rewrites, simulator bundling + override menu, cn1.nativeTheme build hint, screenshot fidelity tests).

Test plan

  • pr.yml matrix (Java 8/17/21) builds green including the new "Build CSS compiler and smoke native-themes" step.
  • designer.yml builds the Designer jar via Maven, the CLI CSS compile smoke produces a non-empty .res, and the native-themes smoke step writes Themes/iOSModernTheme.res + Themes/AndroidMaterialTheme.res.
  • ant.yml (Java CI) full reactor mvn install -Plocal-dev-javase passes.
  • Manual: ./scripts/build-native-themes.sh locally after mvn -pl css-compiler -am install produces both .res files and an intentional forbidden rule (e.g. box-shadow: 0 2px 4px #000 in a theme CSS) fails the build with the offending-UIID list.
  • Manual: open an existing .res file in the Designer GUI and confirm all resource types still open editors correctly (proves the EditableResourcesEditor wiring).

🤖 Generated with Claude Code

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

Android screenshot updates

Compared 65 screenshots: 37 matched, 28 missing references.

  • ButtonTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ButtonTheme_dark.png.

    ButtonTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ButtonTheme_dark.png in workflow artifacts.

  • ButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ButtonTheme_light.png.

    ButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ButtonTheme_light.png in workflow artifacts.

  • CheckBoxRadioTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/CheckBoxRadioTheme_dark.png.

    CheckBoxRadioTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as CheckBoxRadioTheme_dark.png in workflow artifacts.

  • CheckBoxRadioTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/CheckBoxRadioTheme_light.png.

    CheckBoxRadioTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as CheckBoxRadioTheme_light.png in workflow artifacts.

  • DialogTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/DialogTheme_dark.png.

    DialogTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as DialogTheme_dark.png in workflow artifacts.

  • DialogTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/DialogTheme_light.png.

    DialogTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as DialogTheme_light.png in workflow artifacts.

  • FloatingActionButtonTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/FloatingActionButtonTheme_dark.png.

    FloatingActionButtonTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as FloatingActionButtonTheme_dark.png in workflow artifacts.

  • FloatingActionButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/FloatingActionButtonTheme_light.png.

    FloatingActionButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as FloatingActionButtonTheme_light.png in workflow artifacts.

  • ListTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ListTheme_dark.png.

    ListTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ListTheme_dark.png in workflow artifacts.

  • ListTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ListTheme_light.png.

    ListTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ListTheme_light.png in workflow artifacts.

  • MultiButtonTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/MultiButtonTheme_dark.png.

    MultiButtonTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as MultiButtonTheme_dark.png in workflow artifacts.

  • MultiButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/MultiButtonTheme_light.png.

    MultiButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as MultiButtonTheme_light.png in workflow artifacts.

  • PaletteOverrideTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/PaletteOverrideTheme_dark.png.

    PaletteOverrideTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as PaletteOverrideTheme_dark.png in workflow artifacts.

  • PaletteOverrideTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/PaletteOverrideTheme_light.png.

    PaletteOverrideTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as PaletteOverrideTheme_light.png in workflow artifacts.

  • PickerTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/PickerTheme_dark.png.

    PickerTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as PickerTheme_dark.png in workflow artifacts.

  • PickerTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/PickerTheme_light.png.

    PickerTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as PickerTheme_light.png in workflow artifacts.

  • ShowcaseTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ShowcaseTheme_dark.png.

    ShowcaseTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ShowcaseTheme_dark.png in workflow artifacts.

  • ShowcaseTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ShowcaseTheme_light.png.

    ShowcaseTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ShowcaseTheme_light.png in workflow artifacts.

  • SpanLabelTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SpanLabelTheme_dark.png.

    SpanLabelTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SpanLabelTheme_dark.png in workflow artifacts.

  • SpanLabelTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SpanLabelTheme_light.png.

    SpanLabelTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SpanLabelTheme_light.png in workflow artifacts.

  • SwitchTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SwitchTheme_dark.png.

    SwitchTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SwitchTheme_dark.png in workflow artifacts.

  • SwitchTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SwitchTheme_light.png.

    SwitchTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SwitchTheme_light.png in workflow artifacts.

  • TabsTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TabsTheme_dark.png.

    TabsTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TabsTheme_dark.png in workflow artifacts.

  • TabsTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TabsTheme_light.png.

    TabsTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TabsTheme_light.png in workflow artifacts.

  • TextFieldTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TextFieldTheme_dark.png.

    TextFieldTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TextFieldTheme_dark.png in workflow artifacts.

  • TextFieldTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TextFieldTheme_light.png.

    TextFieldTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TextFieldTheme_light.png in workflow artifacts.

  • ToolbarTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ToolbarTheme_dark.png.

    ToolbarTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ToolbarTheme_dark.png in workflow artifacts.

  • ToolbarTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ToolbarTheme_light.png.

    ToolbarTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ToolbarTheme_light.png in workflow artifacts.

Native Android coverage

  • 📊 Line coverage: 8.68% (4646/53524 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 6.81% (22874/335748), branch 3.25% (1050/32302), complexity 4.04% (1248/30918), method 7.07% (1021/14432), class 11.61% (223/1920)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 922.000 ms
Base64 CN1 encode 247.000 ms
Base64 encode ratio (CN1/native) 0.268x (73.2% faster)
Base64 native decode 1062.000 ms
Base64 CN1 decode 222.000 ms
Base64 decode ratio (CN1/native) 0.209x (79.1% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

Compared 7 screenshots: 7 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

Compared 34 screenshots: 34 matched.
✅ JavaScript-port screenshot tests passed.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: 15218 alert(s) (1111 errors, 4495 warnings, 9612 suggestions) (exit code 1) (report)
  • Image references: No unused images detected (report)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 644 total, 0 failed, 2 skipped

Benchmark Results

  • Execution Time: 9992 ms

  • Hotspots (Top 20 sampled methods):

    • 23.62% java.lang.String.indexOf (411 samples)
    • 20.80% com.codename1.tools.translator.Parser.isMethodUsed (362 samples)
    • 11.03% java.util.ArrayList.indexOf (192 samples)
    • 6.03% com.codename1.tools.translator.Parser.addToConstantPool (105 samples)
    • 5.11% java.lang.Object.hashCode (89 samples)
    • 2.64% java.lang.System.identityHashCode (46 samples)
    • 2.36% com.codename1.tools.translator.ByteCodeClass.markDependent (41 samples)
    • 2.24% com.codename1.tools.translator.BytecodeMethod.optimize (39 samples)
    • 1.61% com.codename1.tools.translator.BytecodeMethod.addToConstantPool (28 samples)
    • 1.55% com.codename1.tools.translator.ByteCodeClass.calcUsedByNative (27 samples)
    • 1.55% com.codename1.tools.translator.ByteCodeClass.updateAllDependencies (27 samples)
    • 1.26% com.codename1.tools.translator.Parser.cullMethods (22 samples)
    • 1.15% com.codename1.tools.translator.ByteCodeClass.fillVirtualMethodTable (20 samples)
    • 1.09% com.codename1.tools.translator.Parser.generateClassAndMethodIndexHeader (19 samples)
    • 1.03% com.codename1.tools.translator.Parser.getClassByName (18 samples)
    • 0.92% com.codename1.tools.translator.BytecodeMethod.isMethodUsedByNative (16 samples)
    • 0.86% com.codename1.tools.translator.BytecodeMethod.appendCMethodPrefix (15 samples)
    • 0.80% com.codename1.tools.translator.BytecodeMethod.equals (14 samples)
    • 0.80% sun.nio.ch.FileDispatcherImpl.write0 (14 samples)
    • 0.63% java.lang.StringCoding.encode (11 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

iOS screenshot updates

Compared 65 screenshots: 36 matched, 1 updated, 28 missing references.

  • ButtonTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ButtonTheme_dark.png.

    ButtonTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ButtonTheme_dark.png in workflow artifacts.

  • ButtonTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ButtonTheme_light.png.

    ButtonTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ButtonTheme_light.png in workflow artifacts.

  • CheckBoxRadioTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/CheckBoxRadioTheme_dark.png.

    CheckBoxRadioTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as CheckBoxRadioTheme_dark.png in workflow artifacts.

  • CheckBoxRadioTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/CheckBoxRadioTheme_light.png.

    CheckBoxRadioTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as CheckBoxRadioTheme_light.png in workflow artifacts.

  • DialogTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/DialogTheme_dark.png.

    DialogTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as DialogTheme_dark.png in workflow artifacts.

  • DialogTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/DialogTheme_light.png.

    DialogTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as DialogTheme_light.png in workflow artifacts.

  • FloatingActionButtonTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/FloatingActionButtonTheme_dark.png.

    FloatingActionButtonTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as FloatingActionButtonTheme_dark.png in workflow artifacts.

  • FloatingActionButtonTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/FloatingActionButtonTheme_light.png.

    FloatingActionButtonTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as FloatingActionButtonTheme_light.png in workflow artifacts.

  • landscape — updated screenshot. Screenshot differs (2556x1179 px, bit depth 8).

    landscape
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as landscape.png in workflow artifacts.

  • ListTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ListTheme_dark.png.

    ListTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ListTheme_dark.png in workflow artifacts.

  • ListTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ListTheme_light.png.

    ListTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ListTheme_light.png in workflow artifacts.

  • MultiButtonTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/MultiButtonTheme_dark.png.

    MultiButtonTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as MultiButtonTheme_dark.png in workflow artifacts.

  • MultiButtonTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/MultiButtonTheme_light.png.

    MultiButtonTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as MultiButtonTheme_light.png in workflow artifacts.

  • PaletteOverrideTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/PaletteOverrideTheme_dark.png.

    PaletteOverrideTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as PaletteOverrideTheme_dark.png in workflow artifacts.

  • PaletteOverrideTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/PaletteOverrideTheme_light.png.

    PaletteOverrideTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as PaletteOverrideTheme_light.png in workflow artifacts.

  • PickerTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/PickerTheme_dark.png.

    PickerTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as PickerTheme_dark.png in workflow artifacts.

  • PickerTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/PickerTheme_light.png.

    PickerTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as PickerTheme_light.png in workflow artifacts.

  • ShowcaseTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ShowcaseTheme_dark.png.

    ShowcaseTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ShowcaseTheme_dark.png in workflow artifacts.

  • ShowcaseTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ShowcaseTheme_light.png.

    ShowcaseTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ShowcaseTheme_light.png in workflow artifacts.

  • SpanLabelTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/SpanLabelTheme_dark.png.

    SpanLabelTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as SpanLabelTheme_dark.png in workflow artifacts.

  • SpanLabelTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/SpanLabelTheme_light.png.

    SpanLabelTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as SpanLabelTheme_light.png in workflow artifacts.

  • SwitchTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/SwitchTheme_dark.png.

    SwitchTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as SwitchTheme_dark.png in workflow artifacts.

  • SwitchTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/SwitchTheme_light.png.

    SwitchTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as SwitchTheme_light.png in workflow artifacts.

  • TabsTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/TabsTheme_dark.png.

    TabsTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as TabsTheme_dark.png in workflow artifacts.

  • TabsTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/TabsTheme_light.png.

    TabsTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as TabsTheme_light.png in workflow artifacts.

  • TextFieldTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/TextFieldTheme_dark.png.

    TextFieldTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as TextFieldTheme_dark.png in workflow artifacts.

  • TextFieldTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/TextFieldTheme_light.png.

    TextFieldTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as TextFieldTheme_light.png in workflow artifacts.

  • ToolbarTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ToolbarTheme_dark.png.

    ToolbarTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ToolbarTheme_dark.png in workflow artifacts.

  • ToolbarTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ToolbarTheme_light.png.

    ToolbarTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ToolbarTheme_light.png in workflow artifacts.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 157 seconds

Build and Run Timing

Metric Duration
Simulator Boot 70000 ms
Simulator Boot (Run) 0 ms
App Install 13000 ms
App Launch 7000 ms
Test Execution 208000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 957.000 ms
Base64 CN1 encode 1310.000 ms
Base64 encode ratio (CN1/native) 1.369x (36.9% slower)
Base64 native decode 787.000 ms
Base64 CN1 decode 1164.000 ms
Base64 decode ratio (CN1/native) 1.479x (47.9% slower)
Base64 SIMD encode 374.000 ms
Base64 encode ratio (SIMD/native) 0.391x (60.9% faster)
Base64 encode ratio (SIMD/CN1) 0.285x (71.5% faster)
Base64 SIMD decode 385.000 ms
Base64 decode ratio (SIMD/native) 0.489x (51.1% faster)
Base64 decode ratio (SIMD/CN1) 0.331x (66.9% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 56.000 ms
Image createMask (SIMD on) 10.000 ms
Image createMask ratio (SIMD on/off) 0.179x (82.1% faster)
Image applyMask (SIMD off) 123.000 ms
Image applyMask (SIMD on) 57.000 ms
Image applyMask ratio (SIMD on/off) 0.463x (53.7% faster)
Image modifyAlpha (SIMD off) 114.000 ms
Image modifyAlpha (SIMD on) 59.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.518x (48.2% faster)
Image modifyAlpha removeColor (SIMD off) 137.000 ms
Image modifyAlpha removeColor (SIMD on) 63.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.460x (54.0% faster)
Image PNG encode (SIMD off) 914.000 ms
Image PNG encode (SIMD on) 788.000 ms
Image PNG encode ratio (SIMD on/off) 0.862x (13.8% faster)
Image JPEG encode 532.000 ms

shai-almog and others added 20 commits April 25, 2026 13:16
First slice of the native-themes refactor: the CSS compiler now lives in
its own Maven module with clean dependencies (core + flute + sac) so the
shipped platform themes (iOS Modern liquid-glass + Android Material) can
be generated at framework build time without pulling in JavaSE / JavaFX /
CEF / the Designer GUI.

Phase 1 (no-cef enforcement):
- CSSTheme.strictNoCef static flag + enforceNoCef() pre-scan that lists
  every UIID state requiring CEF-backed image rasterization and throws
  before any WebView call.
- CN1CSSCLI gained a -no-cef CLI arg.
- New NoCefCSSCLI minimal entry point (no JavaSEPort/BrowserComponent
  bootstrap) with a throwing WebViewProvider as a safety net.

Phase 2 (module split):
- New maven/css-compiler Maven module; registered in the reactor between
  factory and sqlite-jdbc. Produces a jar and a fat
  jar-with-dependencies whose main class is NoCefCSSCLI.
- maven/designer now depends on codenameone-css-compiler.
- EditableResources physically moved into maven/css-compiler, with its
  com.codename1.designer.* and com.codename1.impl.javase.* imports
  stripped. GUI functionality exposed as protected throwing hooks
  (persistUIContainer, onOpenFileComplete, writeUIXml,
  getRuntimeNativeTheme) plus a settable loadedBaseFile field and an
  inline IS_MAC constant replacing ResourceEditorApp.IS_MAC.
- New EditableResourcesEditor subclass lives in the Designer and
  overrides every hook, reinstating the GUI behavior (UserInterfaceEditor,
  ThemeEditor, JavaSEPortWithSVGSupport, getResourceEditor, ...).
- New com.codename1.ui.util.SVGDocument interface in core; javase-svg's
  SVG class implements it. EditableResources casts to SVGDocument so the
  thin module avoids the compile-time dep on impl.javase.SVG.
- EditableResourcesForCSS, CSSTheme, ResourcesMutator, Color,
  MissingNativeBrowserException, PollingFileWatcher, and the
  com.codename1.ui.util.xml package moved alongside EditableResources.
- Designer callers bulk-updated: new EditableResources(...) ->
  new EditableResourcesEditor(...) with imports added, in
  ResourceEditorView, ResourceEditorApp, AddThemeResource, AddUIResource,
  CodenameOneTask, CN1CSSCLI, CN1CSSCompiler, CN1CSSInstallerCLI.
- ResourceEditorView.loadedResources retyped to EditableResourcesEditor.

Build pipeline:
- scripts/build-native-themes.sh drives the thin jar (prefers a fresh
  target/ build, falls back to ~/.m2). Writes iOSModernTheme.res and
  AndroidMaterialTheme.res under Themes/ (gitignored).
- Smoke CSS sources in native-themes/{ios-modern,android-material}/theme.css
  with light+dark tokens and includeNativeBool:false to avoid the
  self-inheriting recursion trap.
- native-themes/README.md documents the CEF-free subset.

CI:
- pr.yml gains a step that installs css-compiler and runs the
  native-themes build, failing on missing outputs.
- designer.yml switched from Ant to Maven for building the Designer jar
  and running the CLI CSS smoke test (the Ant Designer build is broken
  until its source roots are taught about maven/css-compiler; Maven is
  the preferred path per CLAUDE.md anyway). Also runs the native-themes
  smoke under xvfb.

Known follow-ups (not in this commit):
- Ant-based Designer build (CodenameOneDesigner/build.xml) still expects
  all CSS classes under src/; local NetBeans/Ant developers will need
  source-tree awareness of maven/css-compiler or a switch to Maven.
- ResourceEditorView line ~2382 still calls EditableResources.open(...)
  returning a base instance; fine for the override-resource side path
  but a future EditableResourcesEditor.open(...) factory would be tidier.
- Phase 3+ (real CSS themes, port integration, simulator bundling,
  build hints, screenshot tests) pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
maven/designer/pom.xml declared a dependency on codenameone-css-compiler
without a version, expecting the root pom's dependencyManagement to fill
it in. The entry was missing, so every downstream module failed to
resolve the POM (observed in PR CI). Add the managed version entry next
to codenameone-core.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI (Java CI + Designer CI) surfaced two classes of errors that the
refactor missed:

1. Accessor/helper classes declared in core-like packages but living in
   the Designer source tree (EditorFont, EditorTTFFont, CodenameOneAccessor,
   animations.AnimationAccessor, plaf.Accessor, plaf.ProtectedUIManager)
   were left behind when EditableResources moved to the css-compiler
   module. They use package-private access into core, so they must
   travel with EditableResources. Moved them into the css-compiler src
   tree. Designer still sees them via the codenameone-css-compiler
   dependency.

2. EditableResources.openFile() directly instantiated
   CodenameOneDesigner's UIBuilderOverride to materialize an XML-stored
   UI container before re-serializing. UIBuilderOverride imports
   com.codename1.designer.* (ActionCommand, UserInterfaceEditor) so it
   cannot live in the thin module. Introduced a new protected hook
   loadUIContainerFromXml(ComponentEntry) that returns null in the
   base (triggering the binary-blob fallback already in the loop) and
   is overridden by EditableResourcesEditor to drive UIBuilderOverride.

3. SimpleWebServer and WebviewSnapshotter (used by ResourcesMutator's
   CEF image rasterization) had clean imports and were still referenced
   by the compile path, so they moved to the css-compiler module too.
   In strict-no-cef builds they are still never invoked.

4. SVGDocument.java switched from /** classic Javadoc to /// markdown
   comments per the repo's java25-markdown-docs style validator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two leftover references prevented the css-compiler module from compiling:

- EditableResources.saveXMLFile() still instantiated UIBuilderOverride
  directly in the MAGIC_UI branch to materialize a container from a
  binary UI resource before writing it back as XML. Wrapped in a new
  materializeUIContainer(resourceName) hook; base throws, the Designer
  EditableResourcesEditor overrides with the UIBuilderOverride call.
- ResourcesMutator.createScreenshots() used Logger.getLogger(CN1CSSCompiler
  .class.getName()) purely as a logger name. Rerouted to
  Logger.getLogger(ResourcesMutator.class.getName()).

Also tightened NoCefCSSCLI's header comment (plain text instead of a
broken {@link CN1CSSCLI} reference that javadoc-plugin would flag).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
.claude/scheduled_tasks.lock slipped into the previous commit because it
wasn't covered by .gitignore. It's a Claude Code session-local
scheduled-wakeup lock, not repo content. Untrack and ignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ditor

Retyping ResourceEditorView.loadedResources to EditableResourcesEditor
broke generateStateMachineCodeEx (takes a base EditableResources and
assigns it to the field). Narrower fix: field stays base-typed and the
single .getResourceEditor(...) call site casts to the editor subclass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two CI fixes on top of the now-green Java CI:

- build-native-themes.sh: ensure_jar() used log() (which went to stdout)
  AND echo "$jar" inside the same function whose output was captured via
  $(...) by the caller. Result: the log line "Using CSS compiler jar:
  <path>" got concatenated with the path and handed to java -jar, which
  responded with "Unable to access jarfile". Redirect log() to stderr so
  only the jar path lands on stdout.
- designer.yml: the Maven-produced
  codenameone-designer-*-jar-with-dependencies.jar is actually a ZIP
  wrapper around the runnable designer_1.jar (see the antrun
  add-designer-jar-with-dependencies execution in maven/designer/pom.xml).
  Unzip to a temp dir and run the inner jar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both PR CI and Designer CI are hitting 'Cannot assign field "cssFile"
because "theme" is null' at NoCefCSSCLI.java - meaning CSSTheme.load
returned null without any diagnostic. The Designer's original NPE
catch logged nothing for non-"encoding properties" NPEs (the
Logger.log line was commented out). Re-enable logging for the general
case, null-guard the message check, and have NoCefCSSCLI fail with a
helpful message if the parser returns null. Next CI run should show
the real stack trace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stack trace from PR CI shows:
  at com.codename1.io.Util.copy(Util.java:211)
  at com.codename1.io.Util.readInputStream(Util.java:402)
  at com.codename1.designer.css.CSSTheme.load(CSSTheme.java:7110)
  at com.codename1.designer.css.NoCefCSSCLI.main(NoCefCSSCLI.java:55)

Util.copy(in, out, bufferSize) unconditionally dereferences
Util.getImplementation() to route cleanup() through the platform impl.
In the native-themes build the css-compiler runs headless - no Display
has been initialized, no Util implementation is set, and the unwrapped
null crashes before CSSTheme can even parse the CSS. Guard the cleanup
path: if no implementation is set, close the streams directly (which is
what every impl's cleanup(Object) ends up doing for InputStream/OutputStream
anyway).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Designer CI logs (now with working stack traces) show:
  CSSException: Unsupported CSS condition type 10 for ElementSelectorImpl
  at com.codename1.designer.css.CSSTheme.getElementForSelector(CSSTheme.java:6561)

My smoke CSS used :pressed / :disabled pseudo-classes. The CN1 CSS
compiler actually handles state selectors as dot-class conditions
(.pressed, .disabled) - see docs/developer-guide/css.asciidoc line 38
("Button.pressed defines styles for the 'Button' UIID's 'pressed' state")
and the SAC_CLASS_CONDITION branch in CSSTheme.getElementForSelector.
The pseudo-class syntax (condition type 10) is not recognized. Switch
smoke themes to .state syntax and clarify the native-themes README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Next NPE after the pseudo-class fix:
  at com.codename1.ui.Font.<init>(Font.java:176)
  at com.codename1.ui.Font.createSystemFont(Font.java:452)
  at CSSTheme$Element.getThemeFont(CSSTheme.java:4671)
  at CSSTheme.updateResources(CSSTheme.java:1887)

Font(int, int, int) dereferences Display.getInstance().getImplementation()
to create a native font - null in the headless css-compiler run. The
smoke themes don't need a font to exercise the no-cef pipeline end to
end, so drop font-family. Phase 3 will add a minimal headless impl (or
make Font creation degrade gracefully when Display is uninitialized) so
real themes can specify fonts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3: replace the smoke placeholder CSS with real component coverage.
Both themes now style ~25 UIIDs each with light/dark palettes, including:

- base (Component, Form, ContentPane, Container)
- typography (Label, SecondaryLabel, TertiaryLabel, SpanLabel*)
- buttons (Button, RaisedButton, FlatButton + .pressed / .disabled)
- text input (TextField, TextArea, TextHint + focused/disabled)
- selection controls (CheckBox, RadioButton, OnOffSwitch + .selected)
- toolbar (Toolbar, TitleArea, Title, MainTitle, Back/Title commands)
- tabs (Tabs, TabsContainer, Tab, Selected/UnselectedTab)
- side menu (SideNavigationPanel, SideCommand)
- list + MultiButton (List, ListRenderer, MultiButton, MultiLine1..4)
- dialog/sheet (Dialog, DialogBody, DialogTitle, Dialog{Content,Command}Area)
- FAB (FloatingActionButton + .pressed)
- misc (Separator, PopupContent)

Palettes:
- iOS Modern — Apple system colors (accent=#007aff light / #0a84ff dark,
  Apple grouped-background surfaces, separator colors); liquid-glass feel
  is approximated via solid fills with subtle tonal surface variants.
- Android Material — Material 3 baseline tonal palette (primary=#6750a4
  light / #d0bcff dark, Material surface-container tiers). Elevation is
  approximated with surface-container-high tonal values since box-shadow
  would force CEF rasterization.

Font.java (core) small fix: the package-private Font(int,int,int)
constructor used to NPE when Display.impl was null. The css-compiler
native-themes build is headless (no Display.init) and needs to serialize
font descriptors without actually allocating native font handles. Guard
the createFont call; headless serialization writes face/style/size only
and the native handle is recreated when the resource is loaded in a
running app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3 Designer CI revealed:
  RuntimeException: Unsupported CSS property cn1-pill-border
  RuntimeException: Unsupported CSS property cn1-round-border

Those are not top-level CSS properties in the CN1 compiler; they are
values of the cn1-background-type property. Rewrite to
  cn1-background-type: cn1-pill-border;
  cn1-background-type: cn1-round-border;

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iter)

Phase 3 CI error was a cascade: the CSS compiler's
transformDarkModeMediaQueries turns any selector inside
@media (prefers-color-scheme: dark) into $DarkSelector. For component
selectors this produces the wanted $DarkButton etc. But for :root the
rewrite emits $DarkComponent:root which Flute rejects ("encountered
' '. Was expecting ':' <IDENT> <FUNCTION>"), and every declaration
inside that dark :root block is skipped. The light :root block then
survives just fine, but because Flute aborts the dark block early the
parser never registers those variables. When update_resources later
tries to serialize a fg color it finds a raw var() FUNCTION
lexical-unit instead of a resolved color and throws
"Unsupported color type 41".

Simplest path that keeps the compiler as-is: drop CSS variables from
the shipped themes and inline hex values per UIID. Light values go in
the top-level rules, dark values go in the @media
(prefers-color-scheme: dark) block which the compiler maps to
$DarkUIID. Every UIID now has a matching dark entry. When the
compiler grows real :root-in-@media support (separate change), we can
re-introduce variables.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two more headless NPEs surfaced by the real themes:

1. EditorTTFFont.refresh() loaded /com/codename1/impl/javase/Roboto-*.ttf
   via getClass().getResourceAsStream. That resource ships in the javase
   port jar, not in our thin css-compiler jar, so the stream is null and
   java.awt.Font.createFont(null) throws IOException. Guard the null
   stream and return early; the .res serialization only needs the
   nativeFontName descriptor, and the native AWT font is recreated at
   app runtime when the platform impl is available.

2. RoundBorder.<init> calls Display.getInstance().convertToPixels(2) to
   set its shadowSpread - which dereferences a null impl in the headless
   build. Make convertToPixels return a 1:1 fallback when impl is null.
   Conversions are recomputed at runtime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Next NPE in Phase 3:
  at com.codename1.ui.Font.getFace(Font.java:742)
  at com.codename1.ui.util.EditableResources.saveTheme(EditableResources.java:2095)

EditableResources serializes system fonts by calling Font.getFace(),
getSize(), getStyle(), each of which dereferences Display.impl. In the
headless css-compiler build impl is null. Capture face/style/size in
the Font(int,int,int) constructor into headlessFace/Style/Size fields
and return them from the three accessors when impl is null. Non-system
fonts (TTF, bitmap) never enter this path and keep the fields at zero.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Feedback: "SVGDocument should be package private to avoid polluting the
UI. Looking at the code I don't see why it needs to be in the core API
to begin with."

Deleted com.codename1.ui.util.SVGDocument from core. Reverted
javase-svg's SVG class to a plain class (no implements). The few
EditableResources code paths that need SVG fields now go through a
package-private static SvgBridge inside EditableResources itself,
which reflectively calls SVG's methods. This is cold code from the
css-compiler point of view (SVG paths only fire when the resource
being serialized contains SVG images, which the native-themes build
never produces) so reflection overhead is a non-issue. Bridge lives
where it is used, no cross-module interface or API surface is added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port integration for the CSS-generated iOSModernTheme.res and
AndroidMaterialTheme.res:

- IOSImplementation.installNativeTheme() resolves theme by the
  existing ios.themeMode hint. "modern" / "liquid" / "auto" loads
  /iOSModernTheme.res (with a graceful fall-through to iOS7Theme if
  the generator hasn't produced it yet, so apps still boot in a
  partial build); "ios7" / "flat" keeps the flat theme; everything
  else falls back to the pre-flat iPhone theme. "auto" now defaults
  to modern, per the decided release plan.

- AndroidImplementation.installNativeTheme() reads a new
  cn1.androidTheme property ("material" | "hololight" | "legacy");
  and.hololight=true still maps to hololight for back-compat. Default
  is material. Drops the SDK_INT<14 gate (universal Android today)
  and swaps the holo-unless-hint logic for the cleaner hint-first
  path. Falls back to holo light if the apk doesn't contain the
  modern .res (partial build).

- Ports/iOSPort/build.xml -pre-compile copies
  ../../Themes/iOSModernTheme.res into nativeSources/ so it ends up
  in dist/nativeios.jar alongside the legacy .res files.
  failonerror=false lets the port still build if
  scripts/build-native-themes.sh hasn't produced the file yet
  (runtime fallback kicks in).

- Ports/Android/build.xml -pre-compile copies
  ../../Themes/AndroidMaterialTheme.res into src/ so it lands on the
  APK classpath via the existing <fileset dir="src" includes="*.res"/>
  jar packaging. Same failonerror=false guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The java25-markdown-docs validator rejects /** ... */ Javadoc blocks
in CodenameOne/ and Ports/CLDC11/. My Phase 3 edit to Font.java added
one for the headlessFace/Style/Size fields. Convert to /// markdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpotBugs on core-unittests flagged DE_MIGHT_IGNORE for the inline
catch (IOException ignored) blocks I added for the headless close
fallback. Refactor into a closeQuietly(Closeable) helper that prints
the exception to stderr instead of silently swallowing it. Semantics
preserved (close failure doesn't propagate) but no more "might ignore"
warning.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
shai-almog and others added 21 commits April 25, 2026 13:16
The last run narrows the ButtonTheme hang to the Form(title, layout)
constructor - the trace emits runAppearance.enter, setDarkMode.done,
refreshTheme.done, then never reaches form.created. Three candidates
inside that constructor: the no-arg Form chain, setLayout, or
setTitle (which resolves Title/TitleArea/Toolbar UIIDs against the
freshly installed modern theme). Split the call into the three
sequential steps with a log line between each so the next iOS run
names the exact step that deadlocks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous run pins the hang to new Form() itself - form.newCtor.begin
is the last log, nothing after. Form's field initializers resolve
styles for Title (via Label("", "Title")) and Container (via
titleArea = new Container(...)); the ctor body then resolves Form,
TitleArea, ContentPane, Toolbar (via initGlobalToolbar).

Probe each of those UIIDs' Style up front with a log before/after,
so the next iOS run names the UIID whose getComponentStyle call
goes into the infinite loop on the freshly-installed modern theme.
Likely suspect: Title (only UIID in the modern theme that uses
"native:MainBold", and the iOS port may round-trip to native code
to resolve that font which could deadlock).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Last iOS UI run pins the BottomTheme hang to getComponentStyle('TitleArea')
- the probe emits probeStyle.begin uiid=TitleArea but never reaches .done.
TitleArea is the only probe UIID that uses cn1-derive to reference a
sibling (Toolbar) in the freshly-installed modern theme; Title
(which uses native:MainBold but no derive) resolves fine and Android
renders the same derive-heavy structure without issue.

Inline Toolbar's fg/bg/margin into TitleArea as a workaround so
the iOS screenshots can make progress. The underlying cn1-derive
resolver bug on iOS (after setThemeProps swaps the prop table
mid-flight) still needs a real fix in the port / UIManager; that
is tracked for a follow-up once the fidelity captures confirm this
is the only affected UIID.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The per-step runAppearance trace and probeStyle helper served their
one-off purpose of narrowing the iOS cn1-derive hang to TitleArea
and landing the inline-Toolbar-props workaround. Keep the install
path INFO/WARN/ERR lines (they are useful any time a platform fails
to pick up a native theme) and collapse the Form construction back
to the one-line new Form(title, layout) form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
14 tests x (light + dark) x 2 platforms = 56 PNGs captured from
run 24862307480 (iOS UI build scripts) and 24862307487 (Test
Android build scripts) on 12d47fd.

The new theme-fidelity tests were previously producing
missing_expected status (non-fatal under CN1SS_FAIL_ON_MISMATCH=1)
because no goldens existed - reviewers got no visual diff in PR
comments and future theme regressions would not be caught. With
these goldens in place the tests become regression-worthy and
the PR-comment diff report lights them up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mpler derives

User feedback on the first round of modern-theme captures:

1. Dialog blends into the Form in Android light mode (floating
   text + buttons without a visible dialog surface). Bumped
   Material 3 Dialog bg from surface-container (#f3edf7) to
   surface-container-highest (#e6e0e9) so it sits visibly above
   the surface (#fef7ff). iOS Dialog stays pure white against the
   grouped-form #f2f2f7 background. Both themes now inline
   Dialog/DialogBody/DialogTitle/PopupContent props instead of
   using cross-UIID cn1-derive.

2. Android Title label renders as a white rectangle on the
   off-white TitleArea (Title has no explicit bg). Gave Title an
   explicit background-color matching TitleArea and bumped
   font-size to 4.5mm (the default size is too small for a title
   on both platforms).

3. iOS Tabs appeared top-left-aligned instead of the iOS 26 bottom
   navigation-bar look. Added @tabPlacementInt=2 (Component.BOTTOM)
   and @tabsFillRowsBool=true to both modern themes; styled
   TabsContainer as a rounded-rect pill with a surface-container
   fill and distinct selected-Tab pill inside it. Mirrors the
   Material 3 bottom-nav-rail look on Android and approximates
   the iOS 26 pill tab group. A real backdrop-filter glass is
   still future work and will need port-side code.

4. cn1-derive cross-dependency limit: per user, inheritance
   should stay simple (child refines parent). Inlined
   TitleArea/Toolbar, DialogTitle/Title, DialogBody/Dialog,
   PopupContent/Dialog, RadioButton/CheckBox, TextArea/TextField
   so only refinement-style derives (Label variants, Button
   variants, Tab variants, MainTitle from Title) remain.

5. Doc: auto stays on legacy for now. The build-hint docs
   previously said the default had flipped; reverted to reflect
   the agreed behaviour - auto (unset) keeps iOS 7 / Holo Light
   and we will flip in a later release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The 7338c18 theme edits (bottom tabs, distinct dialog bg,
explicit title bg, font-size bumps, derives inlined) intentionally
change the rendered pixels of every theme-fidelity test on both
iOS and Android. Leaving the existing goldens in place would make
CN1SS report 28 "different" captures on Android and tank the
build under CN1SS_FAIL_ON_MISMATCH=1.

Drop the goldens so the next CI run reports missing_expected
(non-fatal) and produces a clean diff report; regenerate them
after visually confirming the new captures match the design
intent.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codify the inheritance rule ("child refines parent" only) and the
set of currently-inlined cross-context pairs so future contributors
know why TitleArea/DialogTitle/etc. don't cn1-derive. Also note
that real backdrop-filter glass needs a separate PR (port-side
UIVisualEffectView / RenderEffect mapping for a new
cn1-backdrop-filter CSS primitive).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tabs.initLaf reads the tabPlacementInt theme constant (Component.TOP /
BOTTOM / LEFT / RIGHT) and assigns it to the tabPlacement field - but
the constructor has already added tabsContainer to BorderLayout.NORTH
from the default field value. Writing the field alone leaves the
tabsContainer in NORTH regardless of what the theme asked for.

Route through setTabPlacement() so the container is re-parented to
the correct BorderLayout slot. The condition guards against a
revalidate cascade when the constant matches the current placement.

Found while verifying the modern theme puts tabs at the bottom (iOS
26 / Material 3 bottom-nav-rail look).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Component() super-ctor invokes initLaf polymorphically before the
Tabs ctor body has allocated tabsContainer. The previous form of
this fix called setTabPlacement() unconditionally, which NPE'd
inside setTabsLayout() (tabsContainer.setLayout on null) and left
the container stuck at NORTH from the original field-default
assignment.

Check tabsContainer==null: on the first call during super() just
stash tabPlace into the field, and rely on the ctor's own
setTabPlacement(tabPlacement) call at line 156 to reparent the
then-allocated container. On subsequent refreshTheme-triggered
initLaf calls, the container exists and we reparent if needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The existing assignment in Tabs.initLaf does not take effect because
initLaf fires during Component()'s super-ctor - at which point
Tabs's tabPlacement field hasn't been set, and even if initLaf
updates it, the field assignment is inside the (not-yet-started)
subclass initialisation phase and the constructor's own
setTabPlacement call reads the value Java initialised to default
(TOP=0), never the theme's value.

Read the constant directly in the new Tabs() path (tabP == -1)
before the setTabPlacement call so the container actually lands
in the theme-specified slot. initLaf continues to handle
subsequent refreshTheme cycles for the tabsContainer != null case.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Android captures on 3a2efe0 still show tabs at TOP despite the
direct-read fix in the ctor. Either getThemeConstant returns -1
at this call site (theme constants not yet populated?), or the
setTabPlacement call hits an unexpected early-return path. Log
the values so the next Android run tells us which is the case.
Log lines are throwaway and will be removed once the root cause
is fixed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
buildTheme() strips @-prefixed keys into a separate themeConstants
map and drops them from the main themeProps map. refreshTheme()
rebuilt the input to setThemePropsImpl from themeProps alone, so
every constant (tabPlacementInt, tabsFillRowsBool,
paintsTitleBarBool, switchTrackScaleY, etc.) was silently lost on
the second call. Diagnosed via a CI println in the Tabs ctor:
getThemeConstant("tabPlacementInt", -1) returned -1 even though
setThemeProps had been called with the constant moments earlier.

Re-add the @-prefixed keys from themeConstants when rebuilding the
input Hashtable so setThemePropsImpl -> buildTheme sees the shape
it expects. Also drop the diagnostic println from Tabs.java now
that the root cause is fixed.

This unblocks the Android/iOS modern-theme captures rendering
tabs at the bottom (tabPlacementInt=2) instead of stuck at TOP
because the refresh-then-construct flow in
DualAppearanceBaseTest.runAppearance was silently resetting the
placement constant back to the default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…contrast fixes

User review round 2 on 95290d2 captures:

* Android fonts / padding were too tall for the small emulator
  screen. Bumped everything down a notch - Label 3.5mm, Title 4mm,
  Button padding 1.5/3mm, CheckBox/Radio 0.5/1.5mm, TextField
  1.5/2.5mm. Keeps Material 3 proportions without overflowing.
* Android bottom-tab change reverted. Material 3 Tabs stay at TOP
  (bottom-rail is a separate component, not Tabs). Removed
  @tabPlacementInt/tabsFillRowsBool from the Android theme and
  restored the flat underline-by-color top-tab styling.
* iOS TabsContainer + selected/pressed Tab switched from
  border-radius to cn1-pill-border so the group is a true pill.
* Button / RaisedButton / FlatButton now declare
  text-align: center explicitly (the legend overlay was
  complaining about left-aligned button text).
* RaisedButton.pressed had no explicit text color so it was
  invisible against the darker pressed fill. Pinned to #ffffff on
  iOS and #21005d on Android.
* Android Raised vs default Button now use different container
  tones (elevated #eaddff vs primary #6750a4) so the pair stays
  distinct in both light and dark mode. Showcase dark no longer
  collapses them.
* iOS Dark Dialog moved from #1c1c1e (matched form bg) to
  #2c2c2e (elevated surface) so the dialog doesn't look like
  floating text in dark mode.
* CheckBox / RadioButton gained icon-gap: 2mm for breathing room
  between the symbol and the label text.

native-themes/README.md cn1-derive rule was not changed in this
commit; the cn1-pill-border / border-radius + border CEF caveats
still apply.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds docs/developer-guide/Native-Themes.asciidoc and registers it
in developer-guide.asciidoc between Advanced-Theming and css.

Covers:
* How to enable the iOS liquid-glass / Android Material 3 themes
  via ios.themeMode / cn1.androidTheme / cn1.nativeTheme, plus the
  and.hololight back-compat hint.
* Default stays on legacy; auto flip is planned for later.
* Dark mode wiring (@media prefers-color-scheme: dark ->
  $DarkUIID, Display.setDarkMode, system appearance).
* Overriding the palette statically (includeNativeBool: true in
  the user theme) and dynamically (UIManager.addThemeProps +
  refreshTheme), with a pointer at the runtime-override example
  test.
* Complete table of @constants each theme exposes (commandBehavior,
  tabPlacementInt, tabsFillRowsBool, switchThumbScaleY,
  switchTrackScaleX, ios7StatusBarHack, etc.) with their iOS and
  Android defaults and what each one controls.
* Catalogue of every styled UIID grouped by role: base,
  typography, buttons, inputs, navigation / containers, dialogs
  / overlays.
* cn1-derive rule of thumb ("child refines parent") with safe and
  deliberately-avoided examples; names the cross-context chains
  that now inline their props instead of deriving.
* CEF-free subset constraints (allowed vs forbidden CSS).
* Future backdrop-filter glass primitive as out-of-scope work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…radio icons

User feedback on d412866 round:

* Add an opt-in textured backdrop (diagonal-stripe palette, light
  and dark variants) to DualAppearanceBaseTest. Dialog and Tabs
  tests opt in so any translucent surface reveals its see-through
  tint instead of blending into a plain Form bg. Non-translucent
  tests keep the clean surface.

* Beef up the iOS MultiButton styling: 3mm/4mm padding, 4mm primary
  bold line, 3.5mm secondary regular, 3mm tertiary/quaternary,
  left-aligned text, 3mm icon gap. Matches the iOS Settings row
  density the user expected.

* Per-platform CheckBox/RadioButton icons: DefaultLookAndFeel now
  honours four new optional theme constants
  (@checkBoxCheckedIconInt / @checkBoxUncheckedIconInt /
  @radioCheckedIconInt / @radioUncheckedIconInt) containing the
  Material icon codepoint to use for each state. Existing themes
  that don't set these see no change. The iOS modern theme uses
  CHECK_CIRCLE / CHECK_CIRCLE_OUTLINE for checkboxes
  (Reminders-app circle aesthetic) and keeps the circular radio
  glyphs; Android Material keeps the default square check-box so
  Material 3 look is preserved.

* Dev guide documents the four new icon constants alongside the
  existing @constants table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Setting the texture via form.getUnselectedStyle().setBgPainter
silently did not take effect on Android: the captures on
aeff616 still showed the plain theme form bg. The Form's
style pipeline installs a BGPainter at component-init time that
gets re-initialised on show(), so any post-ctor setBgPainter
replacement is discarded before the paint loop runs.

Instead override paintBackground on the anonymous Form subclass
used by runAppearance and paint the texture directly there when
useTexturedBackdrop() is true. Same painter, same colours; just
a location that actually survives the style pipeline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The paintBackground override does paint the diagonal-stripe
texture, but the ContentPane / TitleArea above it have their own
opaque bgColor from the modern theme and immediately wash over it
with a solid surface fill. Setting bgTransparency=0 on those
sub-containers when useTexturedBackdrop() is true lets the texture
read through, so any translucent widget on top of them shows its
see-through tint against the stripes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…alignment

User feedback round 4:

* Remove headless-Display fallbacks added to CodenameOne core for
  the css-compiler. Replace them with a proper
  HeadlessCssCompilerImplementation in maven/css-compiler that gets
  installed into Display.impl + Util.implInstance via reflection at
  the start of NoCefCSSCLI.main, mirroring the unit-test module's
  TestCodenameOneImplementation pattern. CN1 core no longer carries
  compiler-only stubs.
* Tabs.initLaf reads tabPlacementInt via the component's own
  getUIManager() instead of UIManager.getInstance().
* BuildHintSchemaDefaults gets a class-level Javadoc that explains
  why it exists (publishes hint schema metadata for the simulator's
  Build Hints UI), what fails without it, and that it is unrelated
  to live CSS recompilation.
* Native-Themes developer-guide chapter rewritten:
  - Drops implementation-detail constants (commandBehavior,
    ios7StatusBarHack, paintsTitleBarBool) and the CEF-free /
    Platform-constraints sections - those are framework-internal,
    not user-facing.
  - Documents each platform's design palette (Material 3 baseline
    + Apple system) with a colour-role -> UIID mapping so brand
    overrides are obvious.
  - Notes that Display.setDarkMode(null) follows the device.
  - Calls out platform-specific UIIDs (iOS Settings-style
    MultiButton, top-tab vs bottom-pill behaviour, status-bar
    treatment).
  - Documents the four optional check-box / radio glyph constants
    and the @switchTrackScale / @tabPlacementInt tuning constants.
* iOS Dialog now uses rgba(.., 0.78) so it reads as translucent
  over the textured backdrop. DialogBody / Title / ContentPane /
  CommandArea are transparent so the Dialog surface paints once
  and the rounded corners no longer expose a different inner
  shade. Same treatment for dark mode (rgba(44,44,46,0.78)).
* iOS Tabs container + selected tab use rgba so the pill group
  reads as glass-frosted. Dark mode unselected tab text stays on
  the translucent dark surface.
* Android Dialog sub-UIIDs (Body / Title / ContentPane /
  CommandArea) are transparent so the Dialog surface is the only
  fill - fixes the visible body-vs-dialog colour mismatch in
  light mode.
* iOS MultiButton: rgba surface + 1mm/3mm margin + 3mm border-radius
  so the rows read as separated cards instead of edge-to-edge
  stripes.
* Switch (both themes) zero padding + margin tuned so the track's
  left edge lands at the same x as the Label text-left of the row
  above (fixes the visible misalignment).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generated projects now ship with ios.themeMode=modern,
cn1.androidTheme=material, and the cross-platform
cn1.nativeTheme=modern hint already set in the project's
codenameone_settings.properties. New apps get the iOS liquid-glass
+ Android Material 3 themes by default; existing projects are
unaffected because the cn1 framework itself still defaults to
legacy when these hints are unset.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sets ios.themeMode=modern, cn1.androidTheme=material,
cn1.nativeTheme=modern in the playground's
codenameone_settings.properties so users browsing the playground
see the iOS liquid-glass and Material 3 looks while they explore
components.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

shai-almog and others added 7 commits April 25, 2026 14:20
The pass-4 revert that removed headless fallbacks left an unused
import. PMD flagged it as UnnecessaryImport. Drop it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…emplates

* Root-cause fix for the iOS cn1-derive hang: UIManager.resetThemeProps
  unconditionally injected a defensive Toolbar.derive=TitleArea
  default. When a user theme declared TitleArea.derive=Toolbar (the
  iOS modern theme does), themeProps ended up with both directions
  and createStyle's derive resolver looped forever between them.
  Diagnosed via instrumented Log.p tracing on the
  derive-investigation branch (PR #4810): Toolbar resolution
  derived TitleArea, TitleArea derived Toolbar, lather/rinse/SIGTERM.
  Skip the legacy default whenever the installed theme already wires
  TitleArea -> Toolbar.

  iOS modern theme reverts the workaround that inlined Toolbar's
  props into TitleArea; cn1-derive: Toolbar now works correctly.

* iOS Tabs polish: TabbedPane (the inner content area) gets an
  explicit surface fill in both light and dark blocks so the tab
  pages stay opaque against the textured backdrop in both modes
  (was opaque-light / transparent-dark). The pill TabsContainer is
  the only translucent piece. Tab text + icons stay neutral
  (#000 light / #fff dark) regardless of selection state - the
  selected pill now uses surface-tertiary for visible contrast
  instead of an accent colour. Reduced TabsContainer / Tab padding
  so the selected pill centers vertically inside the group.

* iOS Dark Dialog opacity bumped from 0.78 to 0.95 - lower opacity
  let bright textured-backdrop stripes bleed through and clash
  with the white text. The light Dialog stays at 0.78 because the
  light backdrop palette is gentle enough that text contrast is
  fine at that level.

* Generative templates: scripts/initializr and scripts/cn1playground
  ship a common.zip that the host app expands into newly-generated
  CN1 projects. Both zips's bundled common/codenameone_settings.properties
  now include the three modern-theme hints by default so any project
  spawned by initializr or by the playground starts with the
  liquid-glass + Material 3 themes pre-selected. The host apps'
  own preview settings (which I touched earlier) keep the modern
  themes for their in-app preview.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DialogTheme tests use SpanLabel for the dialog body text. The
default Label fill is opaque (no background-color in my CSS, so it
falls to defaultStyle = surface white / dark). Inside a translucent
Dialog the SpanLabel's white block was painting over the parent
Dialog's translucency and reading as a visible different shade.

Set SpanLabel + SpanLabelText to background-color: transparent on
both themes; Label itself stays as it was.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpanLabel (CodenameOne/src/com/codename1/components/SpanLabel.java
line 91) sets its outer UIID to "Container", not "SpanLabel". The
SpanLabel { background-color: transparent; } rule I added in the
previous pass therefore never reached the actual rendered widget -
the resolved Container style filled an opaque surface-coloured
block over whatever parent lay below. In the Dialog test that block
read as a visibly different shade inside the dialog body.

Make Container transparent by default in both modern themes.
Container is a layout-only UIID; the specific UIIDs that DO want a
surface (Form, Dialog, Tab, FloatingActionButton, etc.) all declare
their bgColor explicitly so this change does not regress them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpanLabel.java line 97 sets its internal TextArea's UIID to
"Label". Default Label had no explicit background-color and was
falling back to the opaque defaultStyle, painting a visible white
block behind the wrapped dialog body text - distinct from the
Dialog's own translucent surface.

Set Label background-color: transparent on both modern themes.
UIIDs that need a label-with-fill (RaisedButton, FAB, etc.)
declare their bgColor explicitly so this change doesn't regress
them.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Tabs.java: gate setSafeArea on `tabsSafeAreaBool` theme constant so a
  floating-pill tab bar can opt out of the internal safe-area padding
  (back-compat default true).
- iOS Modern theme: tabsSafeAreaBool=false, tighten Tab vertical padding,
  bump TabsContainer bottom margin to clear the home indicator since the
  internal inset is gone.
- UIManager.refreshTheme: switch to entrySet iteration to silence
  SpotBugs WMI_WRONG_MAP_ITERATOR.
- cn1playground CN1Playground: layerIosTheme/layerAndroidTheme prefer
  the modern Theme.res files for the live preview, fall back to legacy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Tabs.java: when tabsSafeAreaBool=false the pill (tabsContainer) gets a
  parent Container (tabsContainerHost) that absorbs the safe-area inset
  as bottom padding. The pill draws tightly while still clearing the
  home indicator, instead of either inflating its own background into
  the indicator zone (the previous behaviour) or losing the indicator
  clearance entirely (the prior fix). Legacy themes leave
  tabsSafeAreaBool=true and behave exactly as before.
- iOS Modern theme: revert the 5mm bottom-margin hack and the squeezed
  Tab vertical padding now that the wrapper handles indicator clearance.
- cn1playground: drop the legacy iOS7/iPhone/androidTheme fallbacks in
  layerIosTheme/layerAndroidTheme so the live preview always uses the
  modern themes.
- initializr: override Lifecycle.init to layer iOSModernTheme on top of
  whatever the JavaScript port supplied. The deployed JS port doesn't
  yet pick up ios.themeMode=modern, so the live preview previously
  inherited the legacy iOS7 base.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RFE: Create an example of how to mimic the new liquid glass look and feel in CN1

2 participants