Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ jobs:
BASE_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.before }}
run: |
set -euo pipefail
# This job runs inside the pr-ci-container, where GitHub's
# checkout safe.directory entry can be written under a different
# HOME than this shell step uses. Mark the workspace safe before
# diffing the PR so unrelated cn1libs are not rebuilt.
git config --global --add safe.directory "$GITHUB_WORKSPACE"

all_libs=(
cn1-ai-mlkit-text
Expand Down Expand Up @@ -283,6 +288,7 @@ jobs:
CN1LIB_MODULES: ${{ steps.cn1libs.outputs.modules }}
run: |
set -euo pipefail
git config --global --add safe.directory "$GITHUB_WORKSPACE"
python3 ../scripts/gen-ai-cn1libs.py > /tmp/gen-ai.log
# Capture a list of changed files instead of using --exit-code/--quiet,
# which interacted poorly with the surrounding `set -e -o pipefail`.
Expand Down
49 changes: 44 additions & 5 deletions .github/workflows/release-on-maven-central.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ jobs:

# --- Game Builder editor -------------------------------------------------
# The cn1:gamebuilder goal resolves
# com.codenameone:codenameone-gamebuilder:<version>:jar-with-dependencies
# from Maven Central. That editor lives outside the maven/ reactor
# com.codenameone:codenameone-gamebuilder:<version> and its runtime
# dependencies from Maven Central. That editor lives outside the maven/ reactor
# (scripts/gamebuilder), compiles at Java 17, and depends on the
# core/javase/plugin published above, so it is built and deployed in a
# second pass here. These steps run only when the core release succeeded;
Expand Down Expand Up @@ -125,7 +125,8 @@ jobs:
# -Dmaven.test.skip=true also skips test *compilation* (the editor's
# JUnit test deps are irrelevant to the published jar). -Pgamebuilder-
# central adds the sources/javadoc jars, GPG signatures and the
# central-publishing bundle; -Pexecutable-jar builds the fat jar.
# central-publishing bundle; -Pexecutable-jar builds the desktop
# launcher jar and copies runtime dependencies for local runs.
# -Dcodename1.platform=javase is REQUIRED: it activates the parent's
# `javase` profile (which contributes the editor module) by property.
# That profile is activeByDefault, but any explicit -P activation
Expand All @@ -151,14 +152,52 @@ jobs:
# Propagation to repo1 can take 30+ minutes, so this is a best-effort
# sanity poll, not a gate.
set +e
url="https://repo1.maven.org/maven2/com/codenameone/codenameone-gamebuilder/${GITHUB_REF_NAME}/codenameone-gamebuilder-${GITHUB_REF_NAME}-jar-with-dependencies.jar"
url="https://repo1.maven.org/maven2/com/codenameone/codenameone-gamebuilder/${GITHUB_REF_NAME}/codenameone-gamebuilder-${GITHUB_REF_NAME}.jar"
for i in $(seq 1 15); do
code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
if [ "$code" = "200" ]; then
echo "Confirmed codenameone-gamebuilder ${GITHUB_REF_NAME} (jar-with-dependencies) on Maven Central"
echo "Confirmed codenameone-gamebuilder ${GITHUB_REF_NAME} on Maven Central"
exit 0
fi
echo "[$i/15] Waiting on Maven Central for codenameone-gamebuilder (code=$code)"
sleep 20
done
echo "codenameone-gamebuilder ${GITHUB_REF_NAME} not visible on repo1 yet; it may still be propagating from Sonatype Central."

# --- Signing Wizard editor ---------------------------------------------
# The cn1:certificatewizard goal resolves
# com.codenameone:codenameone-certificatewizard:<version> and its runtime
# dependencies from Maven Central. The editor is a Java-17 Codename One desktop app in
# scripts/certificatewizard and uses the generated OpenAPI client for the
# Apple signing service.
- name: Deploy Signing Wizard editor to Maven Central
if: steps.deploy.outcome == 'success' || steps.confirm.outcome == 'success'
run: |
export GPG_TTY=$(tty)
cd scripts/certificatewizard
xvfb-run -a mvn -Pexecutable-jar -Pcertificatewizard-central deploy \
-Dcodename1.platform=javase \
-Dgpg.passphrase=$MAVEN_GPG_PASSPHRASE \
-Dcn1.version=$GITHUB_REF_NAME -Dcn1.plugin.version=$GITHUB_REF_NAME \
-Dmaven.test.skip=true
env:
MAVEN_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}

- name: Confirm Signing Wizard editor on Maven Central
if: steps.deploy.outcome == 'success' || steps.confirm.outcome == 'success'
continue-on-error: true
run: |
set +e
url="https://repo1.maven.org/maven2/com/codenameone/codenameone-certificatewizard/${GITHUB_REF_NAME}/codenameone-certificatewizard-${GITHUB_REF_NAME}.jar"
for i in $(seq 1 15); do
code=$(curl -s -o /dev/null -w "%{http_code}" "$url")
if [ "$code" = "200" ]; then
echo "Confirmed codenameone-certificatewizard ${GITHUB_REF_NAME} on Maven Central"
exit 0
fi
echo "[$i/15] Waiting on Maven Central for codenameone-certificatewizard (code=$code)"
sleep 20
done
echo "codenameone-certificatewizard ${GITHUB_REF_NAME} not visible on repo1 yet; it may still be propagating from Sonatype Central."
35 changes: 35 additions & 0 deletions CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java
Original file line number Diff line number Diff line change
Expand Up @@ -7394,6 +7394,41 @@ public void openGallery(final ActionListener response, int type) {

}

/// Opens a native file chooser when the platform provides one. The callback
/// source is a `String` path readable by `FileSystemStorage`, or `null` when
/// the user cancels.
///
/// #### Parameters
///
/// - `response`: callback receiving the selected file path
/// - `accept`: comma-separated list of accepted file extensions or MIME types
public void openFileChooser(final ActionListener response, String accept) {
final Dialog d = new Dialog("Select a file");
d.setLayout(new BorderLayout());
FileTreeModel model = new FileTreeModel(true);
if (accept != null) {
Vector tokens = StringUtil.tokenizeString(accept, ',');
for (int iter = 0; iter < tokens.size(); iter++) {
String token = ((String) tokens.elementAt(iter)).trim();
int slash = token.indexOf('/');
if (token.length() > 0 && slash < 0 && !"*".equals(token)) {
if (token.startsWith(".")) {
token = token.substring(1);
}
model.addExtensionFilter(token);
}
}
}

FileTree t = new OpenGalleryFileTree(model, response, d);
d.addComponent(BorderLayout.CENTER, t);
d.placeButtonCommands(new Command[]{new Command("Cancel")});
Command c = d.showAtPosition(2, 2, 2, 2, true);
if (c != null) {
response.actionPerformed(null);
}
}

/// Opens the device image gallery
///
/// #### Parameters
Expand Down
9 changes: 8 additions & 1 deletion CodenameOne/src/com/codename1/io/rest/RequestBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ private Connection createRequest(boolean parseJson) {
if (contentType != null) {
req.setContentType(contentType);
}
req.setFailSilently(false);
req.setFailSilently(hasErrorCodeHandler());
if (cache != null) {
req.setCacheMode(cache);
}
Expand Down Expand Up @@ -1093,6 +1093,13 @@ private Connection createRequest(boolean parseJson) {
return req;
}

private boolean hasErrorCodeHandler() {
return byteArrayErrorCallback != null
|| stringErrorCallback != null
|| jsonErrorCallback != null
|| propertyErrorCallback != null;
}

private static class FetchAsPropertyListActionListener implements ActionListener<NetworkEvent> {
private final Connection request;
private final String root;
Expand Down
14 changes: 14 additions & 0 deletions CodenameOne/src/com/codename1/ui/CN.java
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,20 @@ public static void openGallery(ActionListener response, int type) {
Display.impl.openGallery(response, type);
}

/// Opens a file chooser for arbitrary user-selected files.
///
/// The callback source is a `String` path readable by
/// `FileSystemStorage.openInputStream()`, or `null` if cancelled. `accept`
/// is a comma-separated list of extensions or MIME types.
///
/// #### Parameters
///
/// - `response`: callback receiving the selected file path
/// - `accept`: comma-separated extensions or MIME types, or `null` for all files
public static void openFileChooser(ActionListener response, String accept) {
Display.impl.openFileChooser(response, accept);
}

/// Returns a 2-3 letter code representing the platform name for the platform override
///
/// #### Returns
Expand Down
23 changes: 23 additions & 0 deletions CodenameOne/src/com/codename1/ui/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -2058,6 +2058,9 @@ public void fireMagnifyGesture(int x, int y, float scale) {
} catch (Throwable t) {
cmp = null;
}
if (cmp == null) {
cmp = f;
}
while (cmp != null) {
if (cmp.pinch(scale)) {
return;
Expand Down Expand Up @@ -4895,6 +4898,26 @@ public void openGallery(ActionListener response, int type) {
impl.openGallery(response, type);
}

/// Opens a file chooser for arbitrary user-selected files.
///
/// The callback source is a `String` path that can be read with
/// `FileSystemStorage.openInputStream()`, or `null` if the user cancelled.
/// The `accept` argument is a comma-separated list of file extensions
/// (`"pdf,txt"`, `"p8"`) or MIME types (`"application/pdf"`). Platforms with
/// native document pickers use them; other ports fall back to a Codename One
/// file tree.
///
/// Unlike `openGallery()`, this API is not for media-library access and does
/// not add photo/music build hints.
///
/// #### Parameters
///
/// - `response`: callback receiving the selected file path
/// - `accept`: comma-separated extensions or MIME types, or `null` for all files
public void openFileChooser(ActionListener response, String accept) {
impl.openFileChooser(response, accept);
}

/// Checks to see if the given gallery type is supported on the current platform.
///
/// #### Parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9618,11 +9618,11 @@ public boolean isGalleryTypeSupported(int type) {



public void openGallery(final ActionListener response, int type){
if (!isGalleryTypeSupported(type)) {
throw new IllegalArgumentException("Gallery type "+type+" not supported on this platform.");
}
if (getActivity() == null) {
public void openGallery(final ActionListener response, int type){
if (!isGalleryTypeSupported(type)) {
throw new IllegalArgumentException("Gallery type "+type+" not supported on this platform.");
}
if (getActivity() == null) {
throw new RuntimeException("Cannot open galery in background mode");
}
if (PermissionsHelper.requiresExternalStoragePermissionForMediaAccess()) {
Expand Down Expand Up @@ -9686,14 +9686,64 @@ public void openGallery(final ActionListener response, int type){
galleryIntent.putExtra(Intent.EXTRA_MIME_TYPES, Display.getInstance().getProperty("android.openGallery.accept", "*/*").split(","));
}else{
galleryIntent.setType("*/*");
}
this.getActivity().startActivityForResult(galleryIntent, multi ? OPEN_GALLERY_MULTI: OPEN_GALLERY);
}

class NativeImage extends Image {

public NativeImage(Bitmap nativeImage) {
super(nativeImage);
}
this.getActivity().startActivityForResult(galleryIntent, multi ? OPEN_GALLERY_MULTI: OPEN_GALLERY);
}

@Override
public void openFileChooser(final ActionListener response, String accept) {
if (getActivity() == null) {
throw new RuntimeException("Cannot open file chooser in background mode");
}
if(editInProgress()) {
stopEditing(true);
}
callback = new EventDispatcher();
callback.addListener(response);
Intent pickerIntent = new Intent();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
pickerIntent.setAction(Intent.ACTION_OPEN_DOCUMENT);
} else {
pickerIntent.setAction(Intent.ACTION_GET_CONTENT);
}
pickerIntent.addCategory(Intent.CATEGORY_OPENABLE);
pickerIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
pickerIntent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
}
String[] mimeTypes = getFileChooserMimeTypes(accept);
pickerIntent.setType("*/*");
if (mimeTypes.length > 0) {
pickerIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
}
this.getActivity().startActivityForResult(pickerIntent, OPEN_GALLERY);
}

private String[] getFileChooserMimeTypes(String accept) {
if (accept == null || accept.trim().length() == 0 || "*/*".equals(accept.trim())) {
return new String[0];
}
ArrayList<String> out = new ArrayList<String>();
String[] tokens = accept.split(",");
for (int iter = 0; iter < tokens.length; iter++) {
String token = tokens[iter].trim();
if (token.length() == 0 || "*".equals(token)) {
continue;
}
if (token.indexOf('/') > 0) {
out.add(token);
}
}
if (out.isEmpty()) {
out.add("*/*");
}
return out.toArray(new String[out.size()]);
}

class NativeImage extends Image {

public NativeImage(Bitmap nativeImage) {
super(nativeImage);
}
}

Expand Down
Loading
Loading