Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
132 commits
Select commit Hold shift + click to select a range
243ba93
Native theme fidelity suite + Material 3 fidelity fixes
shai-almog Jun 24, 2026
f108bb2
ci: mark iOS fidelity job non-blocking (ParparVM native-render blocker)
shai-almog Jun 24, 2026
ebe84de
ci: make build-fidelity-app.sh executable (exit 126 in CI)
shai-almog Jun 24, 2026
993dc7e
ci: fix build-test (ASCII), update javase goldens, seed fidelity goldens
shai-almog Jun 24, 2026
1c0a57d
ci: commit CI-density Android goldens + baseline, drop seed flags
shai-almog Jun 24, 2026
8f954b4
iOS native render fix (MRC bugs) + better fidelity report stats
shai-almog Jun 24, 2026
125623a
iOS fidelity: real native-widget screenshots from a standalone native…
shai-almog Jun 24, 2026
a146833
fidelity: crop both renders to common region instead of failing on size
shai-almog Jun 24, 2026
b448f7b
fidelity metric: gate on structural salience, not just mean colour delta
shai-almog Jun 24, 2026
1d0d2d0
iOS native refs: adopt iOS 26 Liquid Glass widget styles
shai-almog Jun 24, 2026
c05219a
iOS glass: shared backdrop PNG so Liquid Glass shows (native + CN1)
shai-almog Jun 24, 2026
89d03bc
Merge remote-tracking branch 'origin/master' into native-theme-fideli…
shai-almog Jun 24, 2026
89970ec
iOS fidelity: tune to real iOS 26 Liquid Glass; Slider iOS thumb mode…
shai-almog Jun 24, 2026
bad9898
iOS+Android fidelity feedback: glass commands, pill buttons, switch/s…
shai-almog Jun 24, 2026
50d7134
CI: arm64-only iOS fidelity build (neon); revert Material to 1.12.0 (…
shai-almog Jun 24, 2026
16a6a67
Slider: fix PMD violations (empty catch blocks + one-declaration-per-…
shai-almog Jun 24, 2026
b08b37a
PMD: allow comment-documented empty catches; comment the remaining em…
shai-almog Jun 24, 2026
e0a23df
Refresh 32 Android instrumentation theme screenshot goldens for theme…
shai-almog Jun 25, 2026
d3c211b
iOS fidelity round: slider/switch/checkbox/tabs/dialog/toolbar to nat…
shai-almog Jun 25, 2026
658aeb9
Fidelity metric: mask the shared glass backdrop, score only the widget
shai-almog Jun 25, 2026
4ff96fa
Native Liquid-Glass (backdrop-filter:blur) paint integration + Spinne…
shai-almog Jun 25, 2026
5b058d4
Fidelity: real wallpaper backdrop so the glass blur is visible + meas…
shai-almog Jun 25, 2026
0088007
Spinner: render the iOS picker wheel (centred rows, depth fade, selec…
shai-almog Jun 25, 2026
5774c2a
Tabs: more opaque glass pill (whiter light / darker dark) to match na…
shai-almog Jun 25, 2026
eba61bb
iOS batch: switch pill thumb, button states, glass strength, toolbar …
shai-almog Jun 25, 2026
1385906
Android: transparent toolbar bg, switch off-thumb +2px, thinner/darke…
shai-almog Jun 25, 2026
7f5089a
Refresh JavaSE simulator ios-modern native-theme golden for the theme…
shai-almog Jun 25, 2026
7370fc1
Remove button pressed states (native can't render them); toolbar tint…
shai-almog Jun 25, 2026
098c2c1
Refresh watch + JS theme goldens for the switch/title theme changes
shai-almog Jun 25, 2026
b110ddf
Fix stale committed theme .res: regenerate from theme.css + guard in CI
shai-almog Jun 25, 2026
f173b0c
Android fidelity: icon+label native Tabs ref, left-aligned dialog + s…
shai-almog Jun 25, 2026
aaf38d5
iOS fidelity: frost the Tabs glass pill closer to native opacity
shai-almog Jun 25, 2026
f980e96
iOS fidelity: stronger Toolbar glass blur (20->64px) to match UIKit
shai-almog Jun 25, 2026
caf068e
Refresh JS/Android/JavaSE screenshot goldens for the native-theme cha…
shai-almog Jun 25, 2026
9ad7c35
Merge remote-tracking branch 'origin/master' into native-theme-fideli…
shai-almog Jun 25, 2026
40abbbf
Android Material dialog: visible outline stroke + correct surface color
shai-almog Jun 25, 2026
87aac3f
iOS glass: boost backdrop saturation (vibrancy) in blurRegion
shai-almog Jun 26, 2026
c7a24a3
Dialog: cap packed width on wide screens so the body wraps into a card
shai-almog Jun 26, 2026
9639305
Dialog width cap: fix unit (mm, not 300 "dips") so it actually constr…
shai-almog Jun 26, 2026
ea6aaa3
Remove titer dev-override artifact from tracking (local build only)
shai-almog Jun 26, 2026
46c9e52
Dialog width cap: use density-robust screen-percentage (mm was unreli…
shai-almog Jun 26, 2026
cbc1b6e
DialogTheme test: render the inline dialog as a centered card, not a …
shai-almog Jun 26, 2026
02d1013
iOS Liquid Glass: real live-screen backdrop-filter:blur (Metal BlurRe…
shai-almog Jun 26, 2026
f647cb4
iOS Modern: make Toolbar/TitleArea translucent so the glass actually …
shai-almog Jun 27, 2026
36eb474
iOS Modern: real floating glass Tabs pill with content scrolling unde…
shai-almog Jun 27, 2026
2cf3ada
iOS Modern: selected-tab glass capsule (layered glass on the focused …
shai-almog Jun 27, 2026
5fa6d0d
iOS Modern: visible Tabs glass (lighter frost) + fix selected-tab shift
shai-almog Jun 27, 2026
48fe6a1
iOS Modern Tabs: shorter pill, selected capsule reaches edges + visible
shai-almog Jun 28, 2026
648ee77
Fidelity: glass-isolation test harness (GlassPanel over varied bg + T…
shai-almog Jun 28, 2026
89268e3
iOS Modern Tabs: fix GlassPanel circle->rect, match pill geometry, tu…
shai-almog Jun 28, 2026
688e5f4
FontImage.createSFOrMaterial: real Apple SF Symbols on iOS, Material …
shai-almog Jun 28, 2026
f760729
iOS glass: reverse-engineered UIVisualEffectView material (measured t…
shai-almog Jun 28, 2026
011dcef
iOS glass: shape-mask + clamped-edge blur + per-UIID chrome material
shai-almog Jun 28, 2026
10a9fd4
iOS glass: frosted (desaturated, whiter) light Toolbar chrome material
shai-almog Jun 28, 2026
9e7550f
fidelity: TabOne minimal isolation case (one text-only tab) + center fix
shai-almog Jun 28, 2026
2c65567
iOS glass: crisp edge (edge-replicated blur pad) + GlassText/GlassIco…
shai-almog Jun 28, 2026
cbe7662
iOS tabs: translucent chrome bar so the selected capsule shows (glass…
shai-almog Jun 28, 2026
8c7ecb1
iOS glass: real Liquid Glass optics -- edge refraction (lensing) + sp…
shai-almog Jun 28, 2026
9620046
iOS SF Symbols: fix the renderer sizing so tab icons use Apple's real…
shai-almog Jun 29, 2026
83de165
iOS tabs: selection capsule is the Liquid Glass indicator (un-invert)
shai-almog Jun 29, 2026
52e2a90
iOS 26 tabs: sliding Liquid Glass selection capsule (animation #1)
shai-almog Jun 29, 2026
8c270d0
Tabs: equal-width tab cells (tabsEqualWidthBool) -- even native-style…
shai-almog Jun 29, 2026
74c12ec
iOS tabs: un-invert bar vs selection background (bar=frost, selection…
shai-almog Jun 29, 2026
31d31b6
iOS tabs: bar passes backdrop colour through + kill selected double-r…
shai-almog Jun 29, 2026
d226f8f
iOS tabs: selection capsule fills the full pill height (kill the "ring")
shai-almog Jun 29, 2026
969e648
iOS tabs: selection capsule fills the whole cell (not the inset tab box)
shai-almog Jun 29, 2026
dbec268
iOS tabs: pill matches native size (the whole bar was too small)
shai-almog Jun 29, 2026
c948835
iOS tabs: subtle selection rim; bar passes more colour (blur-luma gap…
shai-almog Jun 29, 2026
283d339
iOS tabs: crisp selection-capsule edge -- kill the "thick gray gap"
shai-almog Jun 29, 2026
0c139fd
iOS tabs: kill the inner-pill "ring" around the selected capsule
shai-almog Jun 29, 2026
d60648c
iOS tabs: render the SF tab icons at native size (fix the too-small s…
shai-almog Jun 29, 2026
cc2b663
iOS Modern: real live-screen Liquid Glass + honest fidelity capture
shai-almog Jun 29, 2026
fa997b0
iOS Modern: FlatButton dark cream + Toolbar blur tuning
shai-almog Jun 29, 2026
12c91c7
iOS glass: feather the bottom edge of rectangular chrome bars
shai-almog Jun 29, 2026
af39c5d
iOS-26 Liquid Glass tab selection: GPU lens drop + spring morph
shai-almog Jun 30, 2026
11f51e6
docs: document the iOS-26 Liquid Glass tab selection morph + drop a d…
shai-almog Jun 30, 2026
f633707
Review #7: extract the tab-morph math into a pure, testable TabSelect…
shai-almog Jul 2, 2026
e99ab12
Review #5: comparison mode from declared test intent, not image heuri…
shai-almog Jul 2, 2026
872778a
Review #4: explicit geometry fidelity metrics in the comparator, repo…
shai-almog Jul 2, 2026
2cf1387
Fix NativeThemeBindingsTest: pin the accent binding to RaisedButton's…
shai-almog Jul 2, 2026
f96b232
Review #6: deterministic animation-frame validation of the tab morph
shai-almog Jul 2, 2026
a84a9d0
iOS-26 Liquid Glass Switch: droplet thumb morph, model-driven and fra…
shai-almog Jul 2, 2026
4571dd3
Reviews #1/#2/#8: typed GlassRecipe materials + named morph presets
shai-almog Jul 2, 2026
1739fb4
Review #3: live-glass patch cache + explicit cost/caching policy + pr…
shai-almog Jul 2, 2026
4898af5
docs: theme coverage tracker + recipe/preset/frame-validation guide
shai-almog Jul 2, 2026
b8f5246
fidelity frames: capture each frozen frame on its own form
shai-almog Jul 2, 2026
a11f1af
Harden the validation layer (adversarial-review round) + fix a 2012 i…
shai-almog Jul 2, 2026
1b9dc23
iOS on-device verification round: frame goldens, honest baseline, dro…
shai-almog Jul 2, 2026
b3a52f4
Fix the three CI gates the push tripped: markdown docs, guide quality…
shai-almog Jul 2, 2026
5aaefd1
guide: reference the native-vs-CN1 morph comparison figure
shai-almog Jul 2, 2026
6cc807f
Fix PMD OneDeclarationPerLine + the DialogTheme body clip on narrow s…
shai-almog Jul 2, 2026
d540f20
Fix width-capped dialogs clipping their span text + PMD nits + 2 goldens
shai-almog Jul 2, 2026
d5d78f8
Versioned golden sets: native references are LOCAL captures, pinned p…
shai-almog Jul 2, 2026
b10c1c8
Standalone Android native-ref app, real pressed states, native animat…
shai-almog Jul 2, 2026
226f261
docs + native-ref notes: prominentGlass pressed is interactive-only
shai-almog Jul 2, 2026
34fb0fe
android-m3 golden set captured locally on the CI emulator profile
shai-almog Jul 2, 2026
4f72ea1
SpanLabel width cap: measure by laying out, not by arithmetic
shai-almog Jul 2, 2026
3a43fd5
Accept post-fix DialogTheme goldens + restore the dark M3 dialog's ra…
shai-almog Jul 2, 2026
cfe0266
Accept the Android dark DialogTheme golden with the restored card radius
shai-almog Jul 2, 2026
06b1e52
Honest Android tab reference + tile-size parity + real FAB pressed style
shai-almog Jul 2, 2026
bc053b1
fidelity README: retire the same-run rationale, document the golden c…
shai-almog Jul 2, 2026
5467c72
Accept the JS dark DialogTheme golden with the restored card radius
shai-almog Jul 2, 2026
a1f2419
Fidelity CI: enforce the 480x800@160dpi golden contract + dark dialog…
shai-almog Jul 2, 2026
1bfa63d
Android dark theme: explicit toolbar surface + honest disabled tonal …
shai-almog Jul 2, 2026
bd308b7
Android tabs: align bar content with native TabLayout vertical metrics
shai-almog Jul 2, 2026
89e9dc5
Accept the Android CN1SS goldens for the M3 dialog/tabs/disabled fixes
shai-almog Jul 2, 2026
7b7ef61
Accept the JS CN1SS goldens for the M3 dialog/tabs/disabled fixes
shai-almog Jul 2, 2026
a48825c
Refresh the Linux GTK goldens for the Material 3 native-theme work
shai-almog Jul 2, 2026
83d762f
ci: re-trigger the full validation board for the golden refreshes
shai-almog Jul 2, 2026
572d953
workflows: add manual dispatch to the validation suites
shai-almog Jul 2, 2026
399e43b
iOS/tvOS golden refresh for the branch render changes + watchOS SF guard
shai-almog Jul 2, 2026
b742c7f
Accept the Mac native golden churn for the branch render changes
shai-almog Jul 2, 2026
2d291f4
Merge master into native-theme-fidelity-suite
shai-almog Jul 2, 2026
ddb0a57
iOS legacy GL: fix gradient y-offset on non-power-of-2 heights
shai-almog Jul 2, 2026
0696ca2
watchOS: serialize op-queue drains (fixes frozen screenshot suite)
shai-almog Jul 2, 2026
e331e08
Accept the iOS GL graphics-draw-gradient golden for the y-offset fix
shai-almog Jul 2, 2026
305ca23
Refresh 42 watchOS goldens after the drain fix unfroze the suite
shai-almog Jul 2, 2026
ea6c749
watchOS: take the screenshot bitmap read under the drain lock
shai-almog Jul 3, 2026
0f7945c
Android M3 Tabs to 92/95: equal cells, 14px labels, bar height
shai-almog Jul 3, 2026
e9daf14
Android M3 Dialog to ~96: command row metrics vs the native alert
shai-almog Jul 3, 2026
60818d3
Merge remote-tracking branch 'origin/master' into native-theme-fideli…
shai-almog Jul 3, 2026
89e5588
Accept Android Tabs/Dialog golden churn; drop the Since marker
shai-almog Jul 3, 2026
14682a5
Accept the JS-port Tabs/Dialog golden churn from the M3 tuning
shai-almog Jul 3, 2026
27bc384
Accept the Linux GTK Tabs/Dialog golden churn from the M3 tuning
shai-almog Jul 3, 2026
021c542
iOS glass round: toolbar items/insets, dark lens polarity, frost levels
shai-almog Jul 3, 2026
e5790a8
Accept iOS + Mac golden churn from the glass tuning round
shai-almog Jul 3, 2026
e545a01
Accept Metal/tvOS/watchOS golden churn from the glass tuning round
shai-almog Jul 3, 2026
f5c31f1
tvOS: per-test glass-noise tolerance + re-anchor the themed goldens
shai-almog Jul 3, 2026
87fca6f
iOS toolbar title baseline + tighter tab-pill blur
shai-almog Jul 3, 2026
b579d10
Accept TabsMorph frame goldens + re-anchor fidelity baselines
shai-almog Jul 3, 2026
8b7a699
Accept themed-screen churn from the toolbar-baseline commit + sim retry
shai-almog Jul 3, 2026
14bd5b4
iOS tabs to measured native geometry + SF Symbol state glyphs
shai-almog Jul 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/workflows/linux-build-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
name: Linux native build + run (GTK3, x64 + arm64)

on:
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/linux-build-run.yml'
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/scripts-android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
name: Test Android build scripts

'on':
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/scripts-android.yml'
Expand Down
275 changes: 275 additions & 0 deletions .github/workflows/scripts-fidelity.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
---
name: Native theme fidelity

# Measures how close Codename One's native themes render to the REAL native OS
# widgets. Runs the fidelity app on an Android emulator (Material 3) and an iOS
# simulator (Modern theme, Metal pipeline): each component is rendered as the CN1
# widget AND the native widget IN THE SAME ENVIRONMENT, and the two are diffed.
# Comparing same-environment renders makes the score robust to the subtle
# rendering differences between CI machines; the committed goldens + baselines
# are re-seedable drift artifacts (FIDELITY_UPDATE_GOLDENS / _BASELINE).

'on':
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/scripts-fidelity.yml'
- 'scripts/setup-workspace.sh'
- 'scripts/build-android-port.sh'
- 'scripts/build-ios-port.sh'
- 'scripts/build-android-app.sh'
- 'scripts/build-ios-app.sh'
- 'scripts/build-fidelity-app.sh'
- 'scripts/run-android-fidelity-tests.sh'
- 'scripts/run-ios-fidelity-tests.sh'
- 'scripts/lib/cn1ss.sh'
- 'scripts/common/java/**'
- 'scripts/fidelity-app/**'
- 'native-themes/ios-modern/**'
- '!native-themes/ios-modern/**/*.md'
- 'native-themes/android-material/**'
- '!native-themes/android-material/**/*.md'
- 'CodenameOne/src/**'
- '!CodenameOne/src/**/*.md'
- 'Ports/Android/**'
- '!Ports/Android/**/*.md'
- 'Ports/iOSPort/**'
- '!Ports/iOSPort/**/*.md'
- 'vm/**'
- '!vm/**/*.md'
- 'maven/**'
- '!maven/core-unittests/**'
- '!docs/**'
push:
branches: [master]
paths:
- '.github/workflows/scripts-fidelity.yml'
- 'scripts/build-fidelity-app.sh'
- 'scripts/run-android-fidelity-tests.sh'
- 'scripts/run-ios-fidelity-tests.sh'
- 'scripts/lib/cn1ss.sh'
- 'scripts/common/java/**'
- 'scripts/fidelity-app/**'
- 'native-themes/ios-modern/**'
- 'native-themes/android-material/**'
- 'CodenameOne/src/**'
- 'Ports/Android/**'
- 'Ports/iOSPort/**'
- 'vm/**'
- 'maven/**'
- '!maven/core-unittests/**'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
fidelity-android:
name: Fidelity (Android, Material 3)
permissions:
contents: read
pull-requests: write
issues: write
runs-on: ubuntu-latest
timeout-minutes: 60
env:
GITHUB_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
GH_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
CN1SS_FAIL_ON_MISMATCH: '1'
CN1SS_FIDELITY_EPSILON: '2.0'
# CI renders differ subtly from a developer machine, so the committed
# goldens captured elsewhere will not match here. Re-seed goldens AND
# baseline from this environment's own native renders, then the same-run
# comparison + ratchet gate are evaluated against this environment.
# Refresh the per-environment native goldens (drift artifact); the
# ratchet gates the CN1-vs-native SCORE against the committed baseline,
# which is portable across environments because both sides are rendered
# here. A score gap beyond the epsilon fails loudly, surfacing a real
# environment/theme difference to investigate (then reseed deliberately).
FIDELITY_UPDATE_GOLDENS: '1'
steps:
- uses: actions/checkout@v6
- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> "$GITHUB_ENV"
- name: Cache codenameone-tools
uses: actions/cache@v5
with:
path: ${{ runner.temp }}/codenameone-tools
key: ${{ runner.os }}-cn1-tools-${{ hashFiles('scripts/setup-workspace.sh') }}
restore-keys: |
${{ runner.os }}-cn1-tools-
- name: Cache Maven repository
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-fidelity-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2-
- name: Cache Gradle
uses: actions/cache@v5
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-fidelity-${{ hashFiles('scripts/fidelity-app/**/gradle*') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Setup workspace
run: ./scripts/setup-workspace.sh -q -DskipTests
- name: Build Android port
run: ./scripts/build-android-port.sh -q -DskipTests
- name: Regenerate native themes from CSS
# The fidelity app bundles a committed .res; theme.css is the source of
# truth. Recompile here so a stale committed copy can never silently
# render an old theme (the cause of phantom "regressions").
run: ./scripts/build-native-themes.sh
- name: Build fidelity app (Android)
id: build
run: |
mkdir -p ~/.codenameone
cp maven/UpdateCodenameOne.jar ~/.codenameone/
./scripts/build-fidelity-app.sh android -q -DskipTests
- name: Enable KVM for Android emulator
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- name: Run fidelity suite (emulator)
uses: reactivecircus/android-emulator-runner@v2
with:
# The emulator profile is part of the android-m3 golden-set contract:
# the committed native references (scripts/build-android-native-ref.sh)
# are captured LOCALLY on the same API level AND the same 480x800 @
# 160dpi screen, so CI never generates references -- it only renders
# the CN1 side and diffs. The wm size/density override below is
# load-bearing: the runner's default AVD screen (320x640) is narrower
# than the 60mm tile (377px at 160dpi), which silently clamped every
# CN1 tile to the 320px screen width and skewed all comparator scores.
api-level: 36
arch: x86_64
target: google_apis
disk-size: 2048M
# TRANSITIONAL: the first run under committed-goldens scoring re-anchors
# the baseline (upload below); once that baseline is committed, drop
# FIDELITY_UPDATE_BASELINE so the ratchet gates for real.
script: adb shell wm size 480x800 && adb shell wm density 160 && FIDELITY_UPDATE_BASELINE=1 ./scripts/run-android-fidelity-tests.sh "${{ steps.build.outputs.gradle_project_dir }}"
- name: Upload fidelity artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: android-fidelity
path: |
artifacts/android-fidelity/**
scripts/fidelity-app/baseline/android-m3-fidelity-baseline.json
if-no-files-found: warn
retention-days: 14

fidelity-ios-metal:
name: Fidelity (iOS Modern, Metal)
permissions:
contents: read
pull-requests: write
issues: write
runs-on: macos-15
timeout-minutes: 90
env:
GITHUB_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
GH_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
CN1SS_FAIL_ON_MISMATCH: '1'
CN1SS_FIDELITY_EPSILON: '2.0'
# iOS native references are COMMITTED goldens generated offline by
# scripts/build-ios-native-ref.sh (a real-UIWindow native app); they are not
# regenerated here, so no FIDELITY_UPDATE_GOLDENS.
steps:
- uses: actions/checkout@v6
- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> "$GITHUB_ENV"
- name: Cache codenameone-tools
uses: actions/cache@v5
with:
path: ${{ runner.temp }}/codenameone-tools
key: ${{ runner.os }}-cn1-tools-${{ hashFiles('scripts/setup-workspace.sh') }}
restore-keys: |
${{ runner.os }}-cn1-tools-
- name: Cache Maven repository
uses: actions/cache@v5
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-fidelity-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2-
- name: Setup workspace
run: ./scripts/setup-workspace.sh -q -DskipTests
- name: Build iOS port
run: ./scripts/build-ios-port.sh -q -DskipTests
- name: Regenerate native themes from CSS
# The fidelity app bundles a committed .res; theme.css is the source of
# truth. Recompile here so a stale committed copy can never silently
# render an old theme (the cause of phantom "regressions").
run: ./scripts/build-native-themes.sh
- name: Install Metal toolchain
run: xcodebuild -downloadComponent MetalToolchain || true
- name: Build fidelity app (iOS, Metal)
id: build
run: |
mkdir -p ~/.codenameone
cp maven/UpdateCodenameOne.jar ~/.codenameone/
./scripts/build-fidelity-app.sh ios -q -DskipTests
- name: Build simulator app
id: simapp
run: |
set -euo pipefail
WS="$(find scripts/fidelity-app/ios/target -name '*.xcworkspace' -maxdepth 3 | head -n1)"
PROJ_DIR="$(dirname "$WS")"
SCHEME="$(xcodebuild -workspace "$WS" -list 2>/dev/null | awk '/Schemes:/{f=1;next} f&&NF{print $1; exit}')"
DD="$PROJ_DIR/dd"
# arm64-only: the macos-15 runner is Apple Silicon and the x86_64
# simulator slice fails to build the ParparVM SIMD code (clang
# '_Builtin_intrinsics.arm.neon requires feature neon' module error).
xcodebuild -workspace "$WS" -scheme "$SCHEME" -sdk iphonesimulator \
-configuration Debug -derivedDataPath "$DD" \
ARCHS=arm64 ONLY_ACTIVE_ARCH=YES VALID_ARCHS=arm64 \
CODE_SIGNING_ALLOWED=NO build
APP="$(find "$DD/Build/Products" -maxdepth 2 -name '*.app' -type d | head -n1)"
echo "app_path=$APP" >> "$GITHUB_OUTPUT"
- name: Boot simulator (runtime matching the golden set)
id: sim
run: |
set -euo pipefail
# The golden set names the OS design generation it was captured on
# (ios-26-metal). The suite MUST run on a matching runtime: a different
# iOS generation renders different SF fonts/glyphs and produces phantom
# regressions. Fail loudly if the runner lacks the runtime -- the fix is
# pinning a runner image/Xcode that ships it, never regenerating
# references on whatever the runner happens to have.
RUNTIME="$(xcrun simctl list runtimes | grep -Eo 'com.apple.CoreSimulator.SimRuntime.iOS-26[0-9-]*' | head -n1)"
if [ -z "$RUNTIME" ]; then
echo "::error::No iOS 26 simulator runtime on this runner (required by golden set ios-26-metal)."
xcrun simctl list runtimes
exit 78
fi
UDID="$(xcrun simctl list devices "$RUNTIME" available | grep -E 'iPhone 16 \(' | grep -Eo '[0-9A-F-]{36}' | head -n1 || true)"
if [ -z "$UDID" ]; then
UDID="$(xcrun simctl create "iPhone16-fidelity" "iPhone 16" "$RUNTIME")"
fi
xcrun simctl boot "$UDID"
xcrun simctl bootstatus "$UDID" -b
echo "udid=$UDID" >> "$GITHUB_OUTPUT"
- name: Run fidelity suite (simulator, Metal)
# TRANSITIONAL: the first run on the runner's own iOS 26 runtime
# re-anchors the baseline (upload below); once committed, drop
# FIDELITY_UPDATE_BASELINE so the ratchet gates for real.
run: FIDELITY_UPDATE_BASELINE=1 ./scripts/run-ios-fidelity-tests.sh "${{ steps.simapp.outputs.app_path }}" "${{ steps.sim.outputs.udid }}"
- name: Upload fidelity artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: ios-fidelity
path: |
artifacts/ios-fidelity/**
scripts/fidelity-app/baseline/ios-26-metal-fidelity-baseline.json
if-no-files-found: warn
retention-days: 14
4 changes: 4 additions & 0 deletions .github/workflows/scripts-ios.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Test iOS UI build scripts

on:
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/scripts-ios.yml'
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/scripts-javascript.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Test JavaScript screenshot scripts

on:
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/scripts-javascript.yml'
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/scripts-javase.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
name: Test JavaSE simulator integration scripts

on:
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/scripts-javase.yml'
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/windows-cross-build-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
name: Windows cross-build + run (Linux build -> Windows run)

on:
# Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter
# diff limit, so pull_request triggers stopped firing -- dispatch with
# gh workflow run <file> --ref <branch>
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/windows-cross-build-run.yml'
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,4 @@ package.json
# Google Maps JS API key injected by CI for the GoogleWebMap screenshot test
# (from the GOOGLE_MAPS_API_KEY secret). A secret value, never committed.
/scripts/hellocodenameone/common/src/main/resources/google-maps-key.txt
scripts/fidelity-app/common/src/main/resources/*ThemeDev.res
34 changes: 34 additions & 0 deletions CodenameOne/src/com/codename1/components/FloatingActionButton.java
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,24 @@ public void setUIID(String id) {
}

private void updateBorder() {
// Material 3 made the FAB a rounded SQUARE (squircle). A theme that sets
// fabCornerRadiusMM gets a RoundRectBorder of that corner radius (with the
// component's own bg colour filling it) instead of the legacy full circle.
String cr = getUIManager().getThemeConstant("fabCornerRadiusMM", null);
if (cr != null) {
try {
float mm = Float.parseFloat(cr.trim());
getUnselectedStyle().setBorder(com.codename1.ui.plaf.RoundRectBorder.create()
.cornerRadius(mm).shadowOpacity(shadowOpacity));
getSelectedStyle().setBorder(com.codename1.ui.plaf.RoundRectBorder.create()
.cornerRadius(mm).shadowOpacity(shadowOpacity));
getPressedStyle().setBorder(com.codename1.ui.plaf.RoundRectBorder.create()
.cornerRadius(mm).shadowOpacity(shadowOpacity));
return;
} catch (NumberFormatException ignore) {
// malformed constant -> fall through to the legacy circular FAB
}
}
getUnselectedStyle().setBorder(RoundBorder.create().
color(getUnselectedStyle().getBgColor()).
shadowOpacity(shadowOpacity).rectangle(rectangle));
Expand Down Expand Up @@ -281,6 +299,22 @@ public FloatingActionButton createSubFAB(char icon, String text) {
@Override
protected Dimension calcPreferredSize() {
if (autoSizing && getIcon() != null) {
// Material 3's standard FAB is a fixed 56dp square (24dp icon). A theme
// can pin that exact diameter via fabDiameterMM, which is more faithful
// than the legacy icon*11/4 (=2.75x) heuristic that yields ~71dp. Falls
// back to the heuristic when the constant is absent.
String diaMm = com.codename1.ui.plaf.UIManager.getInstance()
.getThemeConstant("fabDiameterMM", null);
if (diaMm != null) {
try {
int d = Display.getInstance().convertToPixels(Float.parseFloat(diaMm));
if (d > 0) {
return new Dimension(d, d);
}
} catch (NumberFormatException ignore) {
// malformed fabDiameterMM constant -> fall back to the icon-derived size
}
}
return new Dimension(getIcon().getWidth() * 11 / 4, getIcon().getHeight() * 11 / 4);
}
return super.calcPreferredSize();
Expand Down
Loading
Loading