diff --git a/CodenameOne/src/com/codename1/ui/Sheet.java b/CodenameOne/src/com/codename1/ui/Sheet.java index 018413a1b5..abf843918b 100644 --- a/CodenameOne/src/com/codename1/ui/Sheet.java +++ b/CodenameOne/src/com/codename1/ui/Sheet.java @@ -478,7 +478,41 @@ public void paint(Graphics g, Rectangle rect) { cnt.revalidate(); } - if (cnt.getComponentCount() > 0) { + boolean foundSheet = false; + Component blocker = null; + for (Component child : cnt) { + if (child instanceof Sheet) { + foundSheet = true; + } else if (Boolean.TRUE.equals(child.getClientProperty("SheetBlocker"))) { + blocker = child; + } + } + + boolean needsBlocker = Form.activePeerCount > 0; + if (needsBlocker) { + if (blocker == null) { + blocker = new Button(); + blocker.putClientProperty("SheetBlocker", Boolean.TRUE); + blocker.setUIID("Container"); + blocker.getAllStyles().setBgTransparency(0); + int size = Math.max(CN.getDisplayWidth(), CN.getDisplayHeight()) * 2; + blocker.setPreferredSize(new com.codename1.ui.geom.Dimension(size, size)); + ((Button) blocker).addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent evt) { + hide(duration); + } + }); + cnt.addComponent(0, BorderLayout.CENTER, blocker); + } + } else { + if (blocker != null) { + cnt.removeComponent(blocker); + blocker = null; + } + } + + if (foundSheet) { $(".Sheet", cnt).each(new ComponentClosure() { @Override public void call(Component c) { @@ -514,8 +548,18 @@ public void call(Component c) { } }); - Component existing = cnt.getComponentAt(0); - cnt.replace(existing, this, null); + Component existing = null; + for(Component c : cnt) { + if (c instanceof Sheet) { + existing = c; + break; + } + } + if (existing != null) { + cnt.replace(existing, this, null); + } else { + cnt.add(getPosition(), this); + } cnt.animateLayout(duration); } else { cnt.add(getPosition(), this); diff --git a/scripts/android/screenshots/BrowserComponent.png b/scripts/android/screenshots/BrowserComponent.png index 11cfc7922a..e9414addfc 100644 Binary files a/scripts/android/screenshots/BrowserComponent.png and b/scripts/android/screenshots/BrowserComponent.png differ diff --git a/scripts/android/screenshots/kotlin.png b/scripts/android/screenshots/kotlin.png index 5c03ec4f70..7847d6acde 100644 Binary files a/scripts/android/screenshots/kotlin.png and b/scripts/android/screenshots/kotlin.png differ diff --git a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/BrowserComponentScreenshotTest.java b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/BrowserComponentScreenshotTest.java index ff7c9e39de..e187e20de6 100644 --- a/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/BrowserComponentScreenshotTest.java +++ b/scripts/hellocodenameone/common/src/main/java/com/codenameone/examples/hellocodenameone/tests/BrowserComponentScreenshotTest.java @@ -2,6 +2,8 @@ import com.codename1.ui.BrowserComponent; import com.codename1.ui.Form; +import com.codename1.ui.Label; +import com.codename1.ui.Sheet; import com.codename1.ui.layouts.BorderLayout; import com.codename1.ui.util.UITimer; import com.codename1.util.SuccessCallback; @@ -56,6 +58,10 @@ public void onSucess(BrowserComponent.JSRef result) { return; } + Sheet sheet = new Sheet(null, "Overlay Sheet"); + sheet.getContentPane().add(new Label("This is a sheet covering part of the browser")); + sheet.show(0); + UITimer.timer(2000, false, form, readyRunnable); readyRunnable = null; } diff --git a/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/tests/KotlinUiTest.kt b/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/tests/KotlinUiTest.kt index 239694cdde..c818c9130e 100644 --- a/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/tests/KotlinUiTest.kt +++ b/scripts/hellocodenameone/common/src/main/kotlin/com/codenameone/examples/hellocodenameone/tests/KotlinUiTest.kt @@ -4,13 +4,16 @@ import com.codename1.components.Accordion import com.codename1.components.MultiButton import com.codename1.components.Switch import com.codename1.ui.Button +import com.codename1.ui.CN import com.codename1.ui.CheckBox import com.codename1.ui.Container import com.codename1.ui.Label +import com.codename1.ui.Sheet import com.codename1.ui.Slider import com.codename1.ui.TextArea import com.codename1.ui.TextField import com.codename1.ui.layouts.BoxLayout +import com.codename1.ui.util.UITimer class KotlinUiTest : BaseTest() { override fun runTest(): Boolean { @@ -51,6 +54,13 @@ class KotlinUiTest : BaseTest() { kotlinForm.add(accordion) kotlinForm.show() + + CN.callSerially { + val sheet = Sheet(null, "Overlay Sheet") + sheet.contentPane.add(Label("This is a sheet covering part of the screen")) + sheet.show(0) + } + return true } } \ No newline at end of file diff --git a/scripts/run-ios-ui-tests.sh b/scripts/run-ios-ui-tests.sh index 20d2490376..a56fd88500 100755 --- a/scripts/run-ios-ui-tests.sh +++ b/scripts/run-ios-ui-tests.sh @@ -347,6 +347,7 @@ ri_log "Running DeviceRunner on destination '$SIM_DESTINATION'" DERIVED_DATA_DIR="$SCREENSHOT_TMP_DIR/derived" rm -rf "$DERIVED_DATA_DIR" BUILD_LOG="$ARTIFACTS_DIR/xcodebuild-build.log" +APP_CONSOLE_LOG="$ARTIFACTS_DIR/device-runner-console.log" ri_log "Building simulator app with xcodebuild" COMPILE_START=$(date +%s) @@ -461,16 +462,17 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" trap cleanup EXIT ri_log "Streaming simulator logs to $TEST_LOG" + CN1SS_PREDICATE='(eventMessage CONTAINS "CN1SS" OR composedMessage CONTAINS "CN1SS")' if [ -n "$SIM_DEVICE_ID" ]; then xcrun simctl terminate "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true xcrun simctl uninstall "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1 || true - xcrun simctl spawn "$SIM_DEVICE_ID" \ + stdbuf -oL xcrun simctl spawn "$SIM_DEVICE_ID" \ log stream --style json --level debug \ - --predicate 'eventMessage CONTAINS "CN1SS"' \ + --predicate "$CN1SS_PREDICATE" \ > "$TEST_LOG" 2>&1 & else - xcrun simctl spawn booted log stream --style compact --level debug --predicate 'composedMessage CONTAINS "CN1SS"' > "$TEST_LOG" 2>&1 & + stdbuf -oL xcrun simctl spawn booted log stream --style json --level debug --predicate "$CN1SS_PREDICATE" > "$TEST_LOG" 2>&1 & fi LOG_STREAM_PID=$! sleep 2 @@ -485,7 +487,8 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" INSTALL_END=$(date +%s) LAUNCH_START=$(date +%s) - if ! xcrun simctl launch "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" >/dev/null 2>&1; then + ri_log "Launching app with console capture -> $APP_CONSOLE_LOG" + if ! xcrun simctl launch --console-pty "$SIM_DEVICE_ID" "$BUNDLE_IDENTIFIER" 2>&1 | tee "$APP_CONSOLE_LOG"; then ri_log "FATAL: simctl launch failed" exit 11 fi @@ -498,7 +501,8 @@ APP_PROCESS_NAME="${WRAPPER_NAME%.app}" INSTALL_END=$(date +%s) LAUNCH_START=$(date +%s) - if ! xcrun simctl launch booted "$BUNDLE_IDENTIFIER" >/dev/null 2>&1; then + ri_log "Launching app with console capture -> $APP_CONSOLE_LOG" + if ! xcrun simctl launch --console-pty booted "$BUNDLE_IDENTIFIER" 2>&1 | tee "$APP_CONSOLE_LOG"; then ri_log "FATAL: simctl launch failed" exit 11 fi @@ -547,12 +551,34 @@ declare -a CN1SS_SOURCES=("SIMLOG:$TEST_LOG") LOG_CHUNKS="$(cn1ss_count_chunks "$TEST_LOG")"; LOG_CHUNKS="${LOG_CHUNKS//[^0-9]/}"; : "${LOG_CHUNKS:=0}" ri_log "Chunk counts -> simulator log: ${LOG_CHUNKS}" -if [ "${LOG_CHUNKS:-0}" = "0" ]; then - ri_log "STAGE:MARKERS_NOT_FOUND -> simulator output did not include CN1SS chunks" - ri_log "---- CN1SS lines (if any) ----" - (grep "CN1SS:" "$TEST_LOG" || true) | sed 's/^/[CN1SS] /' - exit 12 -fi + if [ "${LOG_CHUNKS:-0}" = "0" ]; then + COLLECTED_LOG_DIR="$ARTIFACTS_DIR/simulator-logs" + ensure_dir "$COLLECTED_LOG_DIR" + DEBUG_LOG="$COLLECTED_LOG_DIR/device-runner-debug.log" + if [ -n "$SIM_DEVICE_ID" ]; then + ri_log "Capturing simulator debug log to $DEBUG_LOG" + xcrun simctl spawn "$SIM_DEVICE_ID" log show --style syslog --last 30m > "$DEBUG_LOG" 2>/dev/null || true + else + ri_log "Capturing host simulator debug log to $DEBUG_LOG" + log show --style syslog --last 30m > "$DEBUG_LOG" 2>/dev/null || true + fi + CRASH_LOG_DIR="$COLLECTED_LOG_DIR/crash-reports" + ensure_dir "$CRASH_LOG_DIR" + ri_log "Collecting recent crash reports into $CRASH_LOG_DIR" + find "$HOME/Library/Logs/DiagnosticReports" -type f -name '*.crash' -mmin -120 -print -exec cp {} "$CRASH_LOG_DIR" \; 2>/dev/null || true + if [ -s "$FALLBACK_LOG" ]; then + ri_log "Appending fallback CN1SS log to $TEST_LOG" + { + echo "---- BEGIN FALLBACK CN1SS LOG ----" + cat "$FALLBACK_LOG" + echo "---- END FALLBACK CN1SS LOG ----" + } >> "$TEST_LOG" 2>/dev/null || true + fi + ri_log "STAGE:MARKERS_NOT_FOUND -> simulator output did not include CN1SS chunks" + ri_log "---- CN1SS lines (if any) ----" + (grep "CN1SS:" "$TEST_LOG" || true) | sed 's/^/[CN1SS] /' + exit 12 + fi TEST_NAMES_RAW="$(cn1ss_list_tests "$TEST_LOG" 2>/dev/null | awk 'NF' | sort -u || true)" declare -a TEST_NAMES=() @@ -657,6 +683,7 @@ comment_rc=$? cp -f "$BUILD_LOG" "$ARTIFACTS_DIR/xcodebuild-build.log" 2>/dev/null || true cp -f "$TEST_LOG" "$ARTIFACTS_DIR/device-runner.log" 2>/dev/null || true +cp -f "$APP_CONSOLE_LOG" "$ARTIFACTS_DIR/device-runner-console.log" 2>/dev/null || true exit $comment_rc