Skip to content

Improvements to baseline based on porting exercise#5055

Open
shai-almog wants to merge 28 commits into
masterfrom
improvements-from-immich-port
Open

Improvements to baseline based on porting exercise#5055
shai-almog wants to merge 28 commits into
masterfrom
improvements-from-immich-port

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

A coherent set of framework, build-tool, and theme additions surfaced by porting the Immich Flutter mobile client to Codename One. Each item was driven by a concrete pain point in that port; the port itself is the regression fixture (it still compiles + passes cn1:compliance-check after every change in this branch).

Subset additions (Ports/CLDC11 + vm/JavaAPI)

  • Map: 11 Java 8 default methods (getOrDefault, putIfAbsent, remove(K,V), replace(K,V) / replace(K,V,V), forEach, replaceAll, computeIfAbsent, computeIfPresent, compute, merge).
  • BiFunction (was missing in the function package).
  • Iterable.forEach(Consumer), Collection.removeIf(Predicate), List.replaceAll(UnaryOperator), List.sort(Comparator).
  • All four primitive atomics: AtomicReference, AtomicInteger, AtomicLong, AtomicBoolean.

Core framework

  • Rest.fetchAsJsonList — top-level JSON arrays no longer need the {"root":[...]} envelope trick.
  • Rest.fetchAsMapped(Class<T>) / fetchAsMappedList(Class<T>) — typed POJO responses via the @Mapped binding framework from Build-time POJO annotation frameworks: JSON/XML mapping, component binding, SQLite ORM #5047.
  • Component.setPullToRefresh(Runnable) alias for addPullToRefresh.
  • URLImage.RequestDecorator + setDefaultRequestDecorator + setDefaultBearerToken + per-call decorator overload on createToStorage. Eliminates the "URLImage doesn't pass headers" workaround for authenticated image endpoints.
  • JSONWriter — complement of JSONParser. One-shot toJson(Object) plus fluent JSONWriter.object().put(...).toJson() / JSONWriter.array() builders. Streaming variants for Writer / OutputStream.
  • Tabs.setAnimatedIndicator(boolean) — Material 3 / iOS 26 sliding-underline indicator. Gated by tabsAnimatedIndicatorBool + duration / thickness constants + TabIndicator UIID color. Off in framework default, on by default in modern native themes.
  • MorphTransition.snapshotMode(boolean) — opt-in image-snapshot path that captures source / dest as clipped Images at initTransition() and tweens those rather than re-painting live components. Solves the source-inside-scrolling-container off-viewport-leak case. Default (live-paint) path unchanged for back-compat.
  • DefaultLookAndFeel.drawModernPullToRefresh — Material 3 arc-spinner pull-to-refresh painted via Graphics.drawArc. Sweep grows 0°→330° as the user pulls, then spins continuously while the task runs. Gated by pullToRefreshModernBool theme constant; on by default in modern themes.
  • com.codename1.io.websocket package — WebSocket Java API moved from the cn1-websockets cn1lib into core. Per-platform native impls remain in the cn1lib repo for a follow-up.

Maven plugin

  • StubGenerator.isValidType accepts String[] (was rejected). All primitive arrays were already accepted.
  • New cn1:generate-openapi-client mojo — reads an OpenAPI 3.x JSON spec (URL or local file), emits one @Mapped POJO per components.schemas entry and one <Tag>Api.java per tag. Each generated method routes through Rest.<verb> + Mappers.toJson + fetchAsMapped / fetchAsMappedList. Four JUnit tests in OpenApiCodegenTest, plus the Petstore reference spec is exercised end-to-end (6 models + 3 Api classes generated, 9 .class files compile cleanly against codenameone-core).
  • codenameone-core moved from test to compile scope in the plugin pom so the codegen can use com.codename1.io.JSONParser for spec parsing.

Native themes

iOS Modern + Android Material both enable tabsAnimatedIndicatorBool, pullToRefreshModernBool, plus the supporting duration / thickness / diameter constants. New TabIndicator UIID with light + dark variants pinned to --accent-color / --accent-color-dark. Binary Themes/*.res files regenerated via scripts/build-native-themes.sh.

Screenshot tests

Three new screenshot-grid tests under scripts/hellocodenameone/.../tests/, registered in Cn1ssDeviceRunner and the HTML5 skip list:

  • MorphTransitionTest — baseline live-paint morph.
  • MorphTransitionScrolledSourceTest — source in a scrolling list (the case snapshotMode is designed to solve).
  • MorphTransitionSnapshotTest — locks the snapshot-path baseline.

Documentation

Every shipped item is now reflected in both docs/developer-guide/* and scripts/initializr/.../skill/references/*:

  • io.asciidocRest.fetchAsJsonList / fetchAsMapped / fetchAsMappedList, JSONWriter, WebSocket.
  • graphics.asciidocURLImage.RequestDecorator + setDefaultBearerToken.
  • Animations.asciidocMorphTransition.snapshotMode.
  • The-Components-Of-Codename-One.asciidoc — animated tab indicator (in the existing Tabs section).
  • Miscellaneous-Features.asciidoc — modern arc-spinner pull-to-refresh (in the existing Pull to refresh section).
  • Native-Themes.asciidoc — the six new theme constants (3 tabs, 3 pull-to-refresh).
  • appendix_goal_generate_openapi_client.adoc — new Maven goal page.
  • Maven-Appendix-Goals.adoc — wires the new goal into the appendix.
  • skill/references/java-api-subset.md, ui-components.md, build-and-run.md, native-interfaces.md — same coverage as the dev guide, restructured for the agent context.

Test plan

  • mvn -B install -Plocal-dev-javase -DskipTests (full multi-module build) — green
  • mvn -B test -pl :codenameone-maven-plugin -Dtest=OpenApiCodegenTest — 4 tests, 0 failures
  • scripts/build-native-themes.sh — both modern themes recompile under strictNoCef=true
  • OpenAPI Petstore round-trip — 9 .class files compile cleanly
  • Immich port (external regression fixture) — mvn clean compile cn1:compliance-check BUILD SUCCESS
  • Run the three new MorphTransition screenshot tests on iOS / Android / JavaSE devices to capture baselines
  • Visually inspect the animated tab indicator on iOS + Android skins in the simulator
  • Visually inspect the modern pull-to-refresh arc-spinner on iOS + Android skins

🤖 Generated with Claude Code

A coherent set of framework, build-tool, and theme additions surfaced
by porting Immich's Flutter client to Codename One. Each item was driven
by a concrete pain point in that port; the Immich port is the
regression fixture for the cn1:compliance-check + Rest builder + typed
binding paths.

Java API subset (Ports/CLDC11 + vm/JavaAPI):
- Map: 11 Java 8 default methods (getOrDefault, putIfAbsent,
  remove(K,V), replace(K,V) / replace(K,V,V), forEach, replaceAll,
  computeIfAbsent, computeIfPresent, compute, merge).
- BiFunction added to java.util.function (was missing).
- Iterable.forEach(Consumer), Collection.removeIf(Predicate),
  List.replaceAll(UnaryOperator), List.sort(Comparator).
- All four primitive atomics: AtomicReference (already in vm/JavaAPI,
  mirrored to CLDC11), AtomicInteger, AtomicLong, AtomicBoolean.

Core framework:
- Rest.fetchAsJsonList -- top-level JSON arrays unwrap automatically
  rather than forcing callers through the {"root":[...]} envelope trick.
- Rest.fetchAsMapped(Class<T>) / fetchAsMappedList(Class<T>) -- typed
  POJO responses via the @mapped binding framework merged in PR #5047.
- Component.setPullToRefresh(Runnable) alias for addPullToRefresh
  (more discoverable; same single-task slot).
- URLImage.RequestDecorator interface + setDefaultRequestDecorator +
  setDefaultBearerToken + per-call decorator overload on
  createToStorage. Eliminates the "URLImage doesn't pass headers"
  workaround for authenticated image endpoints.
- JSONWriter -- mirror of JSONParser. One-shot toJson(Object) plus
  fluent JSONWriter.object().put(...).toJson() / JSONWriter.array()
  builders. Streaming variants for writer / OutputStream.
- Tabs.setAnimatedIndicator(boolean) -- Material 3 NavigationBar /
  iOS 26 sliding-underline indicator. Gated by tabsAnimatedIndicatorBool
  theme constant + duration/thickness constants + TabIndicator UIID
  color. Off by default in framework, on by default in modern native
  themes.
- MorphTransition.snapshotMode(boolean) -- opt-in image-snapshot path
  that captures source/dest as clipped Images at initTransition() and
  tweens those rather than re-painting the live components. Solves the
  source-inside-scrolling-container off-viewport-leak case. Default
  (live-paint) path unchanged.
- DefaultLookAndFeel.drawModernPullToRefresh -- Material 3 arc-spinner
  pull-to-refresh painted directly via Graphics.drawArc. Sweep grows
  0deg -> 330deg as the user pulls, then spins continuously while the
  refresh task runs. Gated by pullToRefreshModernBool theme constant;
  on by default in modern themes.
- com.codename1.io.websocket package -- WebSocket Java API moved from
  the cn1-websockets cn1lib into core. Per-platform native impls
  remain in the cn1lib repo for a follow-up.

Maven plugin:
- StubGenerator.isValidType accepts String[] (was rejected). All
  primitive arrays were already accepted.
- New cn1:generate-openapi-client mojo -- reads an OpenAPI 3.x JSON
  spec (URL or local file), emits one @mapped POJO per
  components.schemas entry and one <Tag>Api.java per tag. Each
  generated method routes through Rest.<verb> + Mappers.toJson +
  fetchAsMapped / fetchAsMappedList. Tested end-to-end against the
  Swagger Petstore reference spec: 6 models + 3 Api classes generated,
  compiles cleanly against codenameone-core. Four JUnit tests in
  OpenApiCodegenTest cover inline-spec generation, identifier /
  class-name sanitisation, and a real-Petstore round-trip.
- codenameone-core moved from test to compile scope in the plugin
  pom so the codegen can use com.codename1.io.JSONParser for spec
  parsing.

Native themes:
- iOS Modern + Android Material both enable tabsAnimatedIndicatorBool,
  pullToRefreshModernBool, plus the supporting duration / thickness /
  diameter constants. New TabIndicator UIID with light + dark variants
  pinned to --accent-color / --accent-color-dark. Binary
  Themes/*.res files regenerated via scripts/build-native-themes.sh.

Tests (scripts/hellocodenameone):
- MorphTransitionTest -- baseline live-paint morph.
- MorphTransitionScrolledSourceTest -- source in a scrolling list
  (the case snapshotMode is designed to solve).
- MorphTransitionSnapshotTest -- snapshot-mode baseline.
- All three registered in Cn1ssDeviceRunner.DEFAULT_TEST_CLASSES and
  the HTML5 skip list.

Documentation:
- docs/developer-guide/io.asciidoc -- new sections for
  fetchAsJsonList / fetchAsMapped / fetchAsMappedList, JSONWriter,
  WebSocket.
- docs/developer-guide/graphics.asciidoc -- URLImage RequestDecorator
  + setDefaultBearerToken.
- docs/developer-guide/Animations.asciidoc -- MorphTransition
  snapshotMode.
- docs/developer-guide/The-Components-Of-Codename-One.asciidoc --
  animated tab indicator under the Tabs section.
- docs/developer-guide/Miscellaneous-Features.asciidoc -- modern
  arc-spinner pull-to-refresh under the existing Pull to refresh
  section.
- docs/developer-guide/Native-Themes.asciidoc -- the six new theme
  constants (3 tabs, 3 pull-to-refresh) added to the tuning-constants
  table.
- docs/developer-guide/appendix_goal_generate_openapi_client.adoc --
  new Maven goal documentation page.
- docs/developer-guide/Maven-Appendix-Goals.adoc -- includes the new
  goal in the appendix.

Skill (scripts/initializr/.../skill/):
- references/java-api-subset.md -- fetchAsMapped section,
  URLImage.RequestDecorator section, JSONWriter section, OidcClient
  section, WebSocket-in-core mention, refreshed subset gotchas.
- references/ui-components.md -- MorphTransition.snapshotMode,
  Tabs animated indicator, modern pull-to-refresh, package-split
  table for components / spinner / ui.
- references/build-and-run.md -- Hot Reload modes,
  cn1:generate-openapi-client invocation.
- references/native-interfaces.md -- corrected allowed-types list
  to include String[] and primitive arrays; iOS NSData* marshal
  caveat.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog shai-almog changed the title Improvements driven by the Immich Flutter port comparison Improvements to baseline based on porting exercise May 27, 2026
Two corrections to the previous round, both PR feedback:

1. WebSocket: replace WebSocketNativeImpl (NativeInterface pattern) with
   WebSocketImpl + createWebSocketImpl factory on
   CodenameOneImplementation. The Java API still lives under
   com.codename1.io.websocket but each per-platform port now subclasses
   WebSocketImpl directly and returns it from createWebSocketImpl --
   same pattern Media / Storage / LocationManager use. The
   WebSocketImpl talks directly to the native WebSocket API (no
   NativeInterface marshaling, no static-callback string-id
   round-trip). Util gets a narrow Util.createWebSocketImpl(parent)
   delegate so WebSocket (in a sub-package) can reach the impl
   accessor; pattern matches Util.secureRandomBytes.

2. CLDC11 contains stubs, not implementations. AtomicReference /
   AtomicInteger / AtomicLong / AtomicBoolean now have empty stub
   bodies (return 0 / null / false). The Java 8 default methods on
   Map / Collection / List / Iterable also drop their real
   implementations -- stubbed bodies returning null / false / no-op.
   Actual runtime behaviour comes from the platform (Android JDK on
   Android, vm/JavaAPI on ParparVM, the host JDK in the JavaSE
   simulator); CLDC11 java-runtime.jar is only used by the
   compile-time compliance check.

Also fixes the validate-java25-markdown-docs.sh CI step which rejected
the classic /** Javadoc markers introduced in the new atomic classes
-- all four are now /// markdown comments.

Verified: full mvn install green, errorprone clean,
validate-java25-markdown-docs passes, the immich-cn1-port external
fixture still passes cn1:compliance-check.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

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

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: No alerts found (report)
  • Paragraph capitalization: No paragraph capitalization issues (report)
  • LanguageTool: No grammar matches (report)
  • Image references: No unused images detected (report)

@github-actions
Copy link
Copy Markdown
Contributor

Cloudflare Preview

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

Android screenshot updates

Compared 121 screenshots: 119 matched, 2 missing references.

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

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

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

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

Native Android coverage

  • 📊 Line coverage: 12.70% (7386/58152 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 10.33% (37008/358123), branch 4.27% (1447/33852), complexity 5.37% (1747/32519), method 9.39% (1430/15235), class 15.40% (327/2123)
    • 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 1175.000 ms
Base64 CN1 encode 327.000 ms
Base64 encode ratio (CN1/native) 0.278x (72.2% faster)
Base64 native decode 1033.000 ms
Base64 CN1 decode 272.000 ms
Base64 decode ratio (CN1/native) 0.263x (73.7% faster)
Image encode benchmark status skipped (SIMD unsupported)

- SpotBugs: drop redundant null checks where getComponentStyle() /
  getThemeConstant() return non-null by contract (Tabs, DefaultLookAndFeel).
  Guard the snapshot-mode draw path against an uninitialised
  fromToComponents array even though the field is populated by
  initTransition() before paint() is ever called -- SpotBugs is
  flow-insensitive and complains otherwise.
- Vale: US-English spellings (behaviour -> behavior, colour -> color,
  serialisation -> serialization, etc.) across the new doc sections.
  Remove a "cannot" -> "can't" and two "e.g." -> "for example".
  Rephrase one parenthetical to drop a stray first-person "I" that
  vale was flagging on a downstream line via cumulative column
  tracking. Drop a couple of unnecessary hyphens
  ("currently-selected" -> "currently selected" etc).
- Asciidoctor: replace HTML entity &deg; with the literal degree
  symbol (asciidoctor doesn't recognise &deg; and errors out parsing
  the formatted-text run).
- LanguageTool: add "unobfuscated" to the accept list (existing prose
  on master uses the word but no LT run had previously been triggered
  there since the term was introduced).

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

github-actions Bot commented May 27, 2026

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 715 total, 0 failed, 3 skipped

Benchmark Results

  • Execution Time: 11024 ms

  • Hotspots (Top 20 sampled methods):

    • 22.52% java.util.ArrayList.indexOf (431 samples)
    • 19.28% java.lang.String.indexOf (369 samples)
    • 18.03% com.codename1.tools.translator.Parser.isMethodUsed (345 samples)
    • 6.48% com.codename1.tools.translator.BytecodeMethod.addToConstantPool (124 samples)
    • 4.81% java.lang.Object.hashCode (92 samples)
    • 1.99% com.codename1.tools.translator.ByteCodeClass.updateAllDependencies (38 samples)
    • 1.93% java.lang.System.identityHashCode (37 samples)
    • 1.62% com.codename1.tools.translator.ByteCodeClass.calcUsedByNative (31 samples)
    • 1.36% com.codename1.tools.translator.ByteCodeClass.markDependent (26 samples)
    • 1.36% com.codename1.tools.translator.Parser.generateClassAndMethodIndexHeader (26 samples)
    • 1.20% com.codename1.tools.translator.Parser.getClassByName (23 samples)
    • 1.04% com.codename1.tools.translator.BytecodeMethod.optimize (20 samples)
    • 0.99% com.codename1.tools.translator.BytecodeMethod.appendMethodSignatureSuffixFromDesc (19 samples)
    • 0.73% com.codename1.tools.translator.BytecodeMethod.isMethodUsedByNative (14 samples)
    • 0.68% sun.nio.fs.UnixNativeDispatcher.open0 (13 samples)
    • 0.63% java.lang.StringCoding.encode (12 samples)
    • 0.57% com.codename1.tools.translator.BytecodeMethod.equals (11 samples)
    • 0.57% sun.nio.ch.FileDispatcherImpl.write0 (11 samples)
    • 0.57% java.lang.StringBuilder.append (11 samples)
    • 0.52% com.codename1.tools.translator.BytecodeMethod.appendCMethodPrefix (10 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 and others added 2 commits May 27, 2026 23:14
- URLImage:895 -- drop the redundant
  com.codename1.util.FailureCallback fully-qualified reference; the
  short form FailureCallback is already imported at the top of the
  file. PMD's UnnecessaryFullyQualifiedName rule.
- LanguageTool accept-list -- add "Petstore", "Swagger", "Api", and
  the "tween" family ("tween", "tweens", "tweened", "tweening").
  All four are technical terms LanguageTool's English dictionary
  doesn't recognise but that the new docs use as prose ("the indicator
  tweens its x / width", "the Swagger Petstore reference spec",
  "Each generated Api method").

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

PMD: shorten redundant FQNs in RequestBuilder/URLImage/MorphTransition.
Docs: replace ambiguous hyphenated "class-loading" wording flagged by
LanguageTool with "classloader" in two Annotation-* chapters.
Android baselines: capture MorphTransition{,Scrolled,Snapshot}Test PNGs
extracted from CI logs; refresh TabsTheme_dark/light for the animated
indicator visual flag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

iOS screenshot updates

Compared 121 screenshots: 119 matched, 2 missing references.

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

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

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

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 66000 ms
Simulator Boot (Run) 1000 ms
App Install 11000 ms
App Launch 7000 ms
Test Execution 314000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 477.000 ms
Base64 CN1 encode 1236.000 ms
Base64 encode ratio (CN1/native) 2.591x (159.1% slower)
Base64 native decode 278.000 ms
Base64 CN1 decode 853.000 ms
Base64 decode ratio (CN1/native) 3.068x (206.8% slower)
Base64 SIMD encode 397.000 ms
Base64 encode ratio (SIMD/native) 0.832x (16.8% faster)
Base64 encode ratio (SIMD/CN1) 0.321x (67.9% faster)
Base64 SIMD decode 374.000 ms
Base64 decode ratio (SIMD/native) 1.345x (34.5% slower)
Base64 decode ratio (SIMD/CN1) 0.438x (56.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 63.000 ms
Image createMask (SIMD on) 8.000 ms
Image createMask ratio (SIMD on/off) 0.127x (87.3% faster)
Image applyMask (SIMD off) 126.000 ms
Image applyMask (SIMD on) 51.000 ms
Image applyMask ratio (SIMD on/off) 0.405x (59.5% faster)
Image modifyAlpha (SIMD off) 104.000 ms
Image modifyAlpha (SIMD on) 47.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.452x (54.8% faster)
Image modifyAlpha removeColor (SIMD off) 125.000 ms
Image modifyAlpha removeColor (SIMD on) 62.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.496x (50.4% faster)
Image PNG encode (SIMD off) 888.000 ms
Image PNG encode (SIMD on) 746.000 ms
Image PNG encode ratio (SIMD on/off) 0.840x (16.0% faster)
Image JPEG encode 422.000 ms

Split combined int declarations in Tabs.java and reword "tweens its"
in the Tabs animated-indicator chapter to "animates its" so it no
longer trips MORFOLOGIK_RULE_EN_US.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 27, 2026

iOS Metal screenshot updates

Compared 121 screenshots: 119 matched, 2 missing references.

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

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

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

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 70000 ms
Simulator Boot (Run) 0 ms
App Install 12000 ms
App Launch 12000 ms
Test Execution 283000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 929.000 ms
Base64 CN1 encode 1924.000 ms
Base64 encode ratio (CN1/native) 2.071x (107.1% slower)
Base64 native decode 390.000 ms
Base64 CN1 decode 1163.000 ms
Base64 decode ratio (CN1/native) 2.982x (198.2% slower)
Base64 SIMD encode 531.000 ms
Base64 encode ratio (SIMD/native) 0.572x (42.8% faster)
Base64 encode ratio (SIMD/CN1) 0.276x (72.4% faster)
Base64 SIMD decode 475.000 ms
Base64 decode ratio (SIMD/native) 1.218x (21.8% slower)
Base64 decode ratio (SIMD/CN1) 0.408x (59.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 102.000 ms
Image createMask (SIMD on) 12.000 ms
Image createMask ratio (SIMD on/off) 0.118x (88.2% faster)
Image applyMask (SIMD off) 202.000 ms
Image applyMask (SIMD on) 111.000 ms
Image applyMask ratio (SIMD on/off) 0.550x (45.0% faster)
Image modifyAlpha (SIMD off) 150.000 ms
Image modifyAlpha (SIMD on) 84.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.560x (44.0% faster)
Image modifyAlpha removeColor (SIMD off) 230.000 ms
Image modifyAlpha removeColor (SIMD on) 128.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.557x (44.3% faster)
Image PNG encode (SIMD off) 1538.000 ms
Image PNG encode (SIMD on) 1525.000 ms
Image PNG encode ratio (SIMD on/off) 0.992x (0.8% faster)
Image JPEG encode 735.000 ms

shai-almog and others added 6 commits May 28, 2026 00:46
Brace the two type-test branches that returned without curly braces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the single-statement bodies of two if checks and one for loop
that PMD flagged in writeJson and writeString.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the early-continue body where MorphTransition skips zero-area
morph entries; satisfies PMD ControlStatementBraces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wrap the inline `if (f > 0) return f;` bodies in
modernIndicatorDiameterMm and modernIndicatorStrokeMm so they pass
PMD ControlStatementBraces.

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

The Form host parameter was never read inside the Animation closure --
the repaint runs against `cmp` directly. Drop the parameter and the
call site arg.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Break the inline `{ return ... }` bodies in ObjectBuilder/ArrayBuilder
across multiple lines so they satisfy the LeftCurlyCheck rule.

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

github-actions Bot commented May 28, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

shai-almog and others added 9 commits May 28, 2026 04:00
Baselines captured from the green Test iOS UI build scripts run on
this branch (artifacts ios-ui-tests / ios-ui-tests-metal). The
screenshots show the expected source → destination interpolation
across six animation frames.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Input validation gesture suite was failing on cache-miss every
run because its src_hash differs from build-port's even on the same
SHA. Mirror the workaround already in scripts-ios.yml by reusing
needs.build-port.outputs.cn1_built_cache_key instead of recomputing
the hash here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The com.codename1.io.websocket package landed without iOS, Android,
JavaSE, or JavaScript port implementations -- isSupported() returned
false everywhere, leaving callers stranded. Drop the public API
(WebSocket, WebSocketImpl, WebSocketState), the framework factory
hooks (CodenameOneImplementation.createWebSocketImpl, Util's
delegate), and the developer-guide + initializr skill sections that
documented the half-wired contract. The existing cn1-websockets
cn1lib remains the supported transport until a fully-ported in-core
replacement is ready.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…h tests; trim skill

- Strip the "guess from Flutter" alias rationale on Component.setPullToRefresh
  and the Flutter "hot reload" comparison in the build-and-run skill ref.
- DefaultLookAndFeel.modernSpinStartTime now reads AnimationTime.now() so
  screenshot tests can drive the rotation deterministically.
- Add TabsAnimatedIndicatorScreenshotTest and PullToRefreshSpinnerScreenshotTest
  under scripts/hellocodenameone -- both extend AbstractAnimationScreenshotTest
  so the 2x3 grid harness produces a baseline image of each animation phase.
- Compress the Tabs animated-indicator and modern pull-to-refresh sections
  in ui-components.md to a single short paragraph; the LLM doesn't need the
  per-constant table when both features are on by default in the modern
  themes. Same trim for MorphTransition.snapshotMode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove OpenApiCodegen.java, GenerateOpenApiClientMojo.java,
  OpenApiCodegenTest.java and the matching developer-guide appendix.
- Add com.codename1.annotations.rest.{RestClient, GET, POST, PUT,
  DELETE, PATCH, Path, Query, Header, Body} -- the contract the new
  cn1:generate-openapi mojo emits onto each interface method.
- Add com.codename1.io.rest.RestClients -- the runtime registry the
  generated cn1app.RestClientBootstrap fills in; each interface's
  static of(baseUrl) factory routes through it so the generated impl
  class never appears in project source.
- New appendix_goal_generate_openapi.adoc describes the redesign;
  skill references point at cn1:generate-openapi instead of the
  removed generate-openapi-client goal.

Build-time processor + mojo + records-support follow in subsequent
phases on this branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AnnotatedClass.isRecord() reads the ACC_RECORD bit from the class
file's access flags (inlined constant for ASM-version safety).

MappingAnnotationProcessor:
  - For records, skip the concrete-class / public-no-arg-ctor checks
    and walk non-public component fields (record components are
    private final but carry component names).
  - Reject Property / ListProperty components on records -- they imply
    mutation and records are immutable.
  - emit* helpers thread `isRecord` so reads go through `o.name()`
    accessors and writes target local variables `_name` instead of
    `o.name` field assignment.
  - For records, `fromMap` and `readXml` declare per-component locals
    with kind-appropriate defaults, populate them, and return via the
    canonical constructor `new T(_a, _b, ...)` in bytecode declaration
    order (= canonical-ctor parameter order).

RecordMappingTest exercises a Pet record end-to-end on JDK 17;
skipped on JDK 8. POJO regression tests remain green.

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

RestClientAnnotationProcessor (sibling to MappingAnnotationProcessor):
  - Scans `@RestClient`-annotated interfaces.
  - Per method, reads the one HTTP-verb annotation (@GET/@POST/@PUT/
    @DELETE/@patch) plus the parameter-level @Path/@Query/@Header/@Body
    annotations now exposed by ClassScanner.
  - Resolves the response payload type from the trailing
    `OnComplete<Response<T>>` generic signature -- `List<X>` routes
    through `fetchAsMappedList`, `String` through `fetchAsString`,
    everything else through `fetchAsMapped(T.class, ...)`.
  - Emits `<Tag>ApiImpl` (final class implementing the user interface)
    plus a sibling `cn1app.RestClientBootstrap` that registers each
    impl with `RestClients` -- the build-server splice pattern
    `MapperBootstrap` already uses applies here unchanged.

GenerateOpenApiMojo (`cn1:generate-openapi`):
  - Inputs `-Dcn1.openapi.spec=<path|url>` and
    `-Dcn1.openapi.basePackage=<pkg>`. Optional outputDirectory /
    overwrite knobs.
  - Detects `maven.compiler.release` / `target`. >= 17 emits Java
    records, otherwise classes. The `@Mapped` processor already
    handles both shapes.
  - Schema unification: identical property shapes collapse to a
    single record/class.
  - Per OpenAPI tag emits one `@RestClient`-annotated interface
    under <basePackage> with a static `of(String baseUrl)` factory
    that delegates to `RestClients.create(...)`.

Supporting changes:
  - ClassScanner / MethodInfo now capture per-parameter annotations
    and the method's generic signature.
  - META-INF service registration adds the new processor.
  - skill ref + appendix updated to the actual mojo flag form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Asciidoctor parsed `<path|url>` as an in-table cell delimiter and
dropped the surrounding row. Switch to angle-bracket-free PATH /
PKG / DIR placeholders matching other appendices.

Vale: "is not" -> "isn't", "fully-qualified" -> "fully qualified".
LanguageTool: replace "bookkeep imports" with "track imports".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
shai-almog and others added 7 commits May 28, 2026 20:02
…r.fieldType

REFERENCE / PROPERTY / LIST_PROPERTY all fall back to the binaryName
shape; SpotBugs DB_DUPLICATE_SWITCH_CLAUSES wants them folded into a
single case label.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The runner registers each screenshot test explicitly (no auto-scan);
the new animation tests need both a `new XScreenshotTest()` line in
the suite array and an entry in `isJsSkippedAnimationTest` (matching
how Morph* are already gated -- JS chunk-emission is unreliable for
animation grids today).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DB_DUPLICATE_BRANCHES on the substring offset: both arms of
`sign > 0 ? 0 : 0` evaluated to the same value. `start` already
points at the sign character so the substring offset is just
`start..i`. The `sign` local was load-bearing for nothing else, so
drop it too.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add com.codename1.annotations.rest.Cookie parameter annotation.
- RestClientAnnotationProcessor recognises @cookie, collapses any
  @cookie params on a method into a single `Cookie: a=1; b=2` header
  with URL-encoded values.
- GenerateOpenApiMojo emits @cookie for OpenAPI `in: cookie`
  parameters instead of dropping them.
- Appendix loses the apologetic "Scope (MVP)" framing and the
  "tracked as follow-ups" trailer; the supported-feature list is
  now declarative.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Private fields with a matching public `getX()` (or `isX()` for
booleans) plus `setX(FieldType)` are now first-class @mapped
targets. Property / ListProperty fields only need the getter --
the field itself isn't replaced, only its inner value mutated.

MappingAnnotationProcessor:
  - Per-field strategy stored as `useAccessor` + `getterName` +
    `setterName` on MappedField; `findGetter` / `findSetter` probe
    the declared methods on the class.
  - The `readExpr` / `writeStmt` helpers picks between record-
    accessor / bean-getter / public-field at each emit site so the
    record, public-field, and accessor-POJO paths converge.
  - `URL` -> `getURL` matches `java.beans.Introspector` (literal
    first, lowercased variant `getUrl` as a fallback).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
DefaultLookAndFeel only takes the arc-spinner path when
`pullToRefreshModernBool` is on. The bare framework theme defaults
to off, so the previous render fell through to the legacy rotating
arrow and the new Android baseline showed nothing modern. Overlay
the constant via addThemeProps -- same mechanism the iOS Modern /
Android Material native themes use -- and restore the theme on
finishCapture so subsequent suite tests aren't affected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
actions/setup-java@v4 has been hitting Cloudflare 520 on Zulu's
mirror repeatedly today (Build Android JDK 21 + javascript-screenshots
keep failing at the Setup JDK step). Adoptium Temurin is hosted on
GitHub's own infrastructure and matches the OpenJDK reference
distribution, so it's both more reliable and more conventional.

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.

1 participant