Skip to content

Fix tap-status-bar-to-scroll when global Toolbar is in use (#3589)#4814

Merged
shai-almog merged 1 commit into
masterfrom
fix/3589-statusbar-scrolls-up-with-toolbar
Apr 26, 2026
Merged

Fix tap-status-bar-to-scroll when global Toolbar is in use (#3589)#4814
shai-almog merged 1 commit into
masterfrom
fix/3589-statusbar-scrolls-up-with-toolbar

Conversation

@liannacasper
Copy link
Copy Markdown
Collaborator

Summary

  • Fixes Tapping a button in the StatusBar does not work on iOS device (iPhone Xr) #3589: tap-on-iOS-status-bar-to-scroll-to-top didn't work when a global Toolbar was in use, even with paintsTitleBarBool and statusBarScrollsUpBool enabled.
  • Root cause: Toolbar.initTitleBarStatus() created a plain Container as the StatusBar component and never honored statusBarScrollsUpBool. The iOS native shim (cn1StatusBarTapProxy) forwards a fake tap at (displayWidth/2, 0), but with no Button to receive it, nothing scrolled.
  • The Toolbar path now mirrors Form.createStatusBar(): when statusBarScrollsUpBool is true (default), it creates a Button whose action listener calls findScrollableChild(...) + scrollRectToVisible(...). When the constant is false, the legacy plain-Container behavior is preserved.
  • No public API change — Form.findScrollableChild(...) is package-private and Toolbar shares the package.

Test plan

  • Build a Maven app with paintsTitleBarBool: true and statusBarScrollsUpBool: true, default global Toolbar, scrollable content (≥ a screenful).
  • On a real iOS device: tap the system status bar → content scrolls to top.
  • On the simulator: programmatically click the StatusBar button area → content scrolls to top.
  • Verify with statusBarScrollsUpBool: false: tap does not scroll, layout/sizing unchanged.
  • Verify on a notched device that the StatusBar UIID still sizes correctly (height comes from the StatusBar UIID's theme padding in this branch, mirroring Form.createStatusBar).

🤖 Generated with Claude Code

Toolbar.initTitleBarStatus created a plain Container as the StatusBar,
ignoring statusBarScrollsUpBool. With the global Toolbar (the modern
default), the iOS fake tap forwarded by cn1StatusBarTapProxy at
(width/2, 0) landed on a non-clickable Container, so scroll-to-top
never fired. Mirror Form.createStatusBar by creating a Button with
the scroll-to-top listener when statusBarScrollsUpBool is true.

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

✅ 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
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 26, 2026

Compared 37 screenshots: 37 matched.

Native Android coverage

  • 📊 Line coverage: 7.92% (4203/53043 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 6.21% (20710/333558), branch 3.02% (972/32174), complexity 3.69% (1135/30766), method 6.50% (932/14344), class 10.68% (203/1900)
    • 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)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 7.92% (4203/53043 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 6.21% (20710/333558), branch 3.02% (972/32174), complexity 3.69% (1135/30766), method 6.50% (932/14344), class 10.68% (203/1900)
    • 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 802.000 ms
Base64 CN1 encode 152.000 ms
Base64 encode ratio (CN1/native) 0.190x (81.0% faster)
Base64 native decode 761.000 ms
Base64 CN1 decode 163.000 ms
Base64 decode ratio (CN1/native) 0.214x (78.6% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog shai-almog merged commit 9f42c53 into master Apr 26, 2026
14 of 15 checks passed
@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 26, 2026

iOS screenshot updates

Compared 37 screenshots: 0 matched, 37 updated.

  • BrowserComponent — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • graphics-affine-scale — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-affine-scale
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-affine-scale.png in workflow artifacts.

  • graphics-clip — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-clip
    Preview info: JPEG preview quality 40; JPEG preview quality 40; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-clip.png in workflow artifacts.

  • graphics-draw-arc — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-arc
    Preview info: JPEG preview quality 20; JPEG preview quality 20; downscaled to 590x1278.
    Full-resolution PNG saved as graphics-draw-arc.png in workflow artifacts.

  • graphics-draw-gradient — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-gradient
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-draw-gradient.png in workflow artifacts.

  • graphics-draw-image-rect — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-image-rect
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 590x1278.
    Full-resolution PNG saved as graphics-draw-image-rect.png in workflow artifacts.

  • graphics-draw-line — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-line
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 590x1278.
    Full-resolution PNG saved as graphics-draw-line.png in workflow artifacts.

  • graphics-draw-rect — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-rect
    Preview info: JPEG preview quality 20; JPEG preview quality 20; downscaled to 590x1278.
    Full-resolution PNG saved as graphics-draw-rect.png in workflow artifacts.

  • graphics-draw-round-rect — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-round-rect
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-draw-round-rect.png in workflow artifacts.

  • graphics-draw-shape — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-shape
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-draw-shape.png in workflow artifacts.

  • graphics-draw-string — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-string
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 413x895.
    Full-resolution PNG saved as graphics-draw-string.png in workflow artifacts.

  • graphics-draw-string-decorated — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-draw-string-decorated
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 590x1278.
    Full-resolution PNG saved as graphics-draw-string-decorated.png in workflow artifacts.

  • graphics-fill-arc — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-fill-arc
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-fill-arc.png in workflow artifacts.

  • graphics-fill-polygon — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-fill-polygon
    Preview info: JPEG preview quality 30; JPEG preview quality 30; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-fill-polygon.png in workflow artifacts.

  • graphics-fill-rect — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-fill-rect
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-fill-rect.png in workflow artifacts.

  • graphics-fill-round-rect — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-fill-round-rect
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-fill-round-rect.png in workflow artifacts.

  • graphics-fill-shape — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-fill-shape
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-fill-shape.png in workflow artifacts.

  • graphics-fill-triangle — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-fill-triangle
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-fill-triangle.png in workflow artifacts.

  • graphics-rotate — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-rotate
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-rotate.png in workflow artifacts.

  • graphics-scale — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-scale
    Preview info: JPEG preview quality 60; JPEG preview quality 60; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-scale.png in workflow artifacts.

  • graphics-stroke-test — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-stroke-test
    Preview info: JPEG preview quality 20; JPEG preview quality 20; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-stroke-test.png in workflow artifacts.

  • graphics-tile-image — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-tile-image
    Preview info: JPEG preview quality 10; JPEG preview quality 10; downscaled to 413x895.
    Full-resolution PNG saved as graphics-tile-image.png in workflow artifacts.

  • graphics-transform-camera — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-camera
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-camera.png in workflow artifacts.

  • graphics-transform-perspective — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-perspective
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-perspective.png in workflow artifacts.

  • graphics-transform-rotation — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-rotation
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-rotation.png in workflow artifacts.

  • graphics-transform-translation — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    graphics-transform-translation
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-transform-translation.png in workflow artifacts.

  • ImageViewerNavigationModes — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • kotlin — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

    kotlin
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as kotlin.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.

  • LightweightPickerButtons — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • MainActivity — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • MediaPlayback — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • Sheet — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • TabsBehavior — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • TextAreaAlignmentStates — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • ToastBarTopPosition — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

  • ValidatorLightweightPicker — updated screenshot. Screenshot differs (1179x2556 px, bit depth 8).

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

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 70000 ms
Simulator Boot (Run) 2000 ms
App Install 11000 ms
App Launch 7000 ms
Test Execution 161000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1231.000 ms
Base64 CN1 encode 2249.000 ms
Base64 encode ratio (CN1/native) 1.827x (82.7% slower)
Base64 native decode 934.000 ms
Base64 CN1 decode 942.000 ms
Base64 decode ratio (CN1/native) 1.009x (0.9% slower)
Base64 SIMD encode 582.000 ms
Base64 encode ratio (SIMD/native) 0.473x (52.7% faster)
Base64 encode ratio (SIMD/CN1) 0.259x (74.1% faster)
Base64 SIMD decode 687.000 ms
Base64 decode ratio (SIMD/native) 0.736x (26.4% faster)
Base64 decode ratio (SIMD/CN1) 0.729x (27.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 87.000 ms
Image createMask (SIMD on) 28.000 ms
Image createMask ratio (SIMD on/off) 0.322x (67.8% faster)
Image applyMask (SIMD off) 231.000 ms
Image applyMask (SIMD on) 61.000 ms
Image applyMask ratio (SIMD on/off) 0.264x (73.6% faster)
Image modifyAlpha (SIMD off) 175.000 ms
Image modifyAlpha (SIMD on) 70.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.400x (60.0% faster)
Image modifyAlpha removeColor (SIMD off) 281.000 ms
Image modifyAlpha removeColor (SIMD on) 64.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.228x (77.2% faster)
Image PNG encode (SIMD off) 1228.000 ms
Image PNG encode (SIMD on) 824.000 ms
Image PNG encode ratio (SIMD on/off) 0.671x (32.9% faster)
Image JPEG encode 537.000 ms

liannacasper pushed a commit that referenced this pull request Apr 26, 2026
The previous fix attempt ran into a compile error because
Component.setSafeArea does not exist - setSafeArea is only defined on
Container. Replacing the StatusBar Container with a Button (as #4814
did) therefore drops safe-area support entirely, which is what made
36 of 37 iOS screenshot baselines diverge.

Keep the StatusBar as a Container (so setSafeArea(true) and the
StatusBar UIID styling continue to apply unchanged), and attach a
pointer-released listener to it for the scroll-to-top behavior #4814
introduced. The synthetic iOS tap forwarded by cn1StatusBarTapProxy
still fires Component.pointerReleased, which dispatches to that
listener.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
liannacasper added a commit that referenced this pull request Apr 26, 2026
…sion) (#4815)

* Toolbar: restore setSafeArea on StatusBar button branch (#4814 regression)

The fix in #4814 wrapped the StatusBar component creation in an
if/else but only set setSafeArea(true) on the Container fallback.
With the default statusBarScrollsUpBool=true the new Button branch
ran without safe-area treatment, so the iOS top inset was no longer
reserved and every form shifted vertically. iOS screenshot tests
caught this: 36 of 37 baselines diverged on the merge commit.

Move setSafeArea(true) below the if/else so it applies to both the
Button and Container cases, matching the pre-#4814 behavior.

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

* Toolbar: keep StatusBar as a Container to preserve safeArea behavior

The previous fix attempt ran into a compile error because
Component.setSafeArea does not exist - setSafeArea is only defined on
Container. Replacing the StatusBar Container with a Button (as #4814
did) therefore drops safe-area support entirely, which is what made
36 of 37 iOS screenshot baselines diverge.

Keep the StatusBar as a Container (so setSafeArea(true) and the
StatusBar UIID styling continue to apply unchanged), and attach a
pointer-released listener to it for the scroll-to-top behavior #4814
introduced. The synthetic iOS tap forwarded by cn1StatusBarTapProxy
still fires Component.pointerReleased, which dispatches to that
listener.

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

---------

Co-authored-by: Shai Almog <67850168+shai-almog@users.noreply.github.com>
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.

Tapping a button in the StatusBar does not work on iOS device (iPhone Xr)

2 participants