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
35 changes: 33 additions & 2 deletions CodenameOne/src/com/codename1/components/ShareButton.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import com.codename1.share.EmailShare;
import com.codename1.share.FacebookShare;
import com.codename1.share.SMSShare;
import com.codename1.share.ShareResult;
import com.codename1.share.ShareResultListener;
import com.codename1.share.ShareService;
import com.codename1.ui.Button;
import com.codename1.ui.Command;
Expand Down Expand Up @@ -76,6 +78,7 @@ public class ShareButton extends Button implements ActionListener {
private String textToShare;
private String imageToShare;
private String imageMimeType;
private ShareResultListener shareResultListener;

/// Default constructor
public ShareButton() {
Expand Down Expand Up @@ -133,6 +136,22 @@ public void addShareService(ShareService share) {
shareServices.addElement(share);
}

/// Listener invoked once when the underlying share sheet (native or
/// fallback dialog) finishes. May be `null` to clear a prior
/// listener.
///
/// On platforms that cannot observe the chosen target the listener
/// still fires with [ShareResult#sharedTo] passing a `null` package
/// name, so the app can resume its flow.
public void setShareResultListener(ShareResultListener listener) {
this.shareResultListener = listener;
}

/// Returns the listener registered via [#setShareResultListener] or null.
public ShareResultListener getShareResultListener() {
return shareResultListener;
}

/// invoked when the button is pressed
///
/// #### Parameters
Expand All @@ -145,13 +164,14 @@ public void actionPerformed(ActionEvent evt) {
Display.getInstance().callSerially(new Runnable() {
@Override
public void run() {
final ShareResultListener listener = shareResultListener;
if (Display.getInstance().isNativeShareSupported()) {
Display.getInstance().share(textToShare, imageToShare, imageMimeType, new Rectangle(
ShareButton.this.getAbsoluteX(),
ShareButton.this.getAbsoluteY(),
ShareButton.this.getWidth(),
ShareButton.this.getHeight()
));
), listener);
return;
}
Vector sharing;
Expand All @@ -171,17 +191,28 @@ public void run() {
share.setMessage(textToShare);
share.setImage(imageToShare, imageMimeType);
share.setOriginalForm(getComponentForm());
share.setShareResultListener(listener);
}
List l = new List(sharing);
l.setCommandList(true);
final Dialog dialog = new Dialog("Share");
dialog.setLayout(new BorderLayout());
dialog.addComponent(BorderLayout.CENTER, l);
dialog.placeButtonCommands(new Command[]{new Command("Cancel")});
final boolean[] picked = new boolean[1];
Command cancel = new Command("Cancel") {
@Override
public void actionPerformed(ActionEvent ev) {
if (!picked[0] && listener != null) {
listener.onResult(ShareResult.dismissed());
}
}
};
dialog.placeButtonCommands(new Command[]{cancel});
l.addActionListener(new ActionListener() {

@Override
public void actionPerformed(ActionEvent evt) {
picked[0] = true;
dialog.dispose();
}
});
Expand Down
18 changes: 18 additions & 0 deletions CodenameOne/src/com/codename1/impl/CodenameOneImplementation.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import com.codename1.media.MediaRecorderBuilder;
import com.codename1.messaging.Message;
import com.codename1.notifications.LocalNotification;
import com.codename1.share.ShareResult;
import com.codename1.share.ShareResultListener;
import com.codename1.payment.Purchase;
import com.codename1.payment.PurchaseCallback;
import com.codename1.push.PushCallback;
Expand Down Expand Up @@ -7241,6 +7243,22 @@ public void share(String text, String image, String mimeType, Rectangle sourceRe

}

/// Share variant that delivers an outcome through `listener`.
///
/// The default implementation delegates to the legacy
/// [#share(String,String,String,Rectangle)] entry point and reports
/// `SHARED_TO(null)` once it returns, since this base class has no
/// way to observe the platform sheet. Ports that can observe the
/// result (iOS, Android API 22+) override this method.
///
/// `listener` is guaranteed non-null by [com.codename1.ui.Display#share].
public void share(String text, String image, String mimeType, Rectangle sourceRect, ShareResultListener listener) {
share(text, image, mimeType, sourceRect);
if (listener != null) {
listener.onResult(ShareResult.sharedTo(null));
}
}

// BEGIN TRANSFORMATION METHODS---------------------------------------------------------

/// Called before internal paint of component starts
Expand Down
124 changes: 124 additions & 0 deletions CodenameOne/src/com/codename1/share/ShareResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.share;

/// Outcome of a share request initiated through [com.codename1.ui.Display#share]
/// or [com.codename1.components.ShareButton].
///
/// Status semantics:
///
/// - `SHARED_TO`: the user picked a target and the system accepted the
/// share. `getPackageName()` returns the chosen target's identifier:
/// the Android package name (e.g. `com.whatsapp`) or, on iOS,
/// the `UIActivityType` (e.g. `com.apple.UIKit.activity.PostToTwitter`).
/// - `DISMISSED`: the user cancelled the share sheet without picking a
/// target.
/// - `FAILED`: the share could not be completed. `getError()` may carry a
/// short, platform-supplied description (no stack traces).
///
/// Instances are immutable. Construct through the static factories.
public final class ShareResult {

/// Status of a [ShareResult].
public static final int STATUS_SHARED_TO = 1;

/// User dismissed/cancelled the share sheet.
public static final int STATUS_DISMISSED = 2;

/// Share could not be completed.
public static final int STATUS_FAILED = 3;

private final int status;
private final String packageName;
private final String error;

private ShareResult(int status, String packageName, String error) {
this.status = status;
this.packageName = packageName;
this.error = error;
}

/// Build a `SHARED_TO` result.
///
/// `packageName` is the platform-specific identifier of the chosen
/// target (Android package name or iOS `UIActivityType`). It may be
/// `null` when the platform does not expose the selection (older
/// Android versions, web share API).
public static ShareResult sharedTo(String packageName) {
return new ShareResult(STATUS_SHARED_TO, packageName, null);
}

/// Build a `DISMISSED` result.
public static ShareResult dismissed() {
return new ShareResult(STATUS_DISMISSED, null, null);
}

/// Build a `FAILED` result with an optional platform message.
public static ShareResult failed(String message) {
return new ShareResult(STATUS_FAILED, null, message);
}

/// Numeric status: one of [#STATUS_SHARED_TO], [#STATUS_DISMISSED], [#STATUS_FAILED].
public int getStatus() {
return status;
}

/// True iff status == [#STATUS_SHARED_TO].
public boolean isSharedTo() {
return status == STATUS_SHARED_TO;
}

/// True iff status == [#STATUS_DISMISSED].
public boolean isDismissed() {
return status == STATUS_DISMISSED;
}

/// True iff status == [#STATUS_FAILED].
public boolean isFailed() {
return status == STATUS_FAILED;
}

/// Chosen target identifier when the user picked a destination, otherwise null.
public String getPackageName() {
return packageName;
}

/// Platform-supplied message when [#isFailed] is true, otherwise null.
public String getError() {
return error;
}

@Override
public String toString() {
switch (status) {
case STATUS_SHARED_TO:
return "ShareResult{SHARED_TO " + packageName + "}";
case STATUS_DISMISSED:
return "ShareResult{DISMISSED}";
case STATUS_FAILED:
return "ShareResult{FAILED " + error + "}";
default:
return "ShareResult{?}";
}
}
}
33 changes: 33 additions & 0 deletions CodenameOne/src/com/codename1/share/ShareResultListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.share;

/// Receives the outcome of a share request. Always invoked on the EDT.
///
/// Pass into [com.codename1.ui.Display#share] or [com.codename1.components.ShareButton#setShareResultListener].
public interface ShareResultListener {

/// Called once when the share sheet finishes (target picked, dismissed,
/// or failed). Never invoked more than once for the same share request.
void onResult(ShareResult result);
}
36 changes: 36 additions & 0 deletions CodenameOne/src/com/codename1/share/ShareService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import com.codename1.ui.Image;
import com.codename1.ui.events.ActionEvent;

// ShareResult / ShareResultListener live in the same package.

/// This is an abstract sharing service.
///
/// @author Chen
Expand All @@ -18,6 +20,8 @@ public abstract class ShareService extends Command {
private String image;
private String mimeType;
private Form original;
private ShareResultListener shareResultListener;
private boolean resultDelivered;

/// Constructor with the service name and icon
///
Expand Down Expand Up @@ -107,6 +111,38 @@ public void finish() {
if (original != null) {
original.showBack();
}
if (!resultDelivered) {
deliverResult(ShareResult.sharedTo(getCommandName()));
}
}

/// Registers a listener to be notified once when the share completes.
///
/// Set by [com.codename1.components.ShareButton] before the service
/// is invoked. Subclasses normally do not call this directly.
public void setShareResultListener(ShareResultListener listener) {
this.shareResultListener = listener;
this.resultDelivered = false;
}

/// Returns the registered result listener (may be null).
public ShareResultListener getShareResultListener() {
return shareResultListener;
}

/// Delivers a [ShareResult] to the registered listener exactly once.
///
/// Subclasses can call this to report a `DISMISSED` (user cancelled)
/// or `FAILED` outcome. [#finish] already reports a default
/// `SHARED_TO(commandName)` if no explicit result was delivered.
protected void deliverResult(ShareResult result) {
if (resultDelivered) {
return;
}
resultDelivered = true;
if (shareResultListener != null && result != null) {
shareResultListener.onResult(result);
}
}

}
43 changes: 42 additions & 1 deletion CodenameOne/src/com/codename1/ui/Display.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import com.codename1.location.LocationManager;
import com.codename1.security.Biometrics;
import com.codename1.security.SecureStorage;
import com.codename1.share.ShareResult;
import com.codename1.share.ShareResultListener;
import com.codename1.media.Media;
import com.codename1.media.MediaRecorderBuilder;
import com.codename1.messaging.Message;
Expand Down Expand Up @@ -5154,7 +5156,46 @@ public void share(String text, String image, String mimeType) {
/// some platforms to provide a hint as to where the share dialog overlay should pop up. Particularly,
/// on the iPad with iOS 8 and higher.
public void share(String textOrPath, String image, String mimeType, Rectangle sourceRect) {
impl.share(textOrPath, image, mimeType, sourceRect);
share(textOrPath, image, mimeType, sourceRect, null);
}

/// Like [#share(String,String,String,Rectangle)] but reports the
/// outcome through `listener` on the EDT.
///
/// `listener` may be `null`. If the underlying platform cannot report
/// the outcome (older Android, Web Share API), the listener is still
/// invoked with [ShareResult#sharedTo] passing a `null` package name
/// so the app can resume its flow.
///
/// #### Parameters
///
/// - `textOrPath`: String to share, or path to file to share.
///
/// - `image`: file path to the image or null
///
/// - `mimeType`: type of the image or file. null if just sharing text
///
/// - `sourceRect`: source rectangle hint for the share popover. May be null.
///
/// - `listener`: callback for the share outcome. May be null.
public void share(String textOrPath, String image, String mimeType, Rectangle sourceRect, ShareResultListener listener) {
if (listener == null) {
impl.share(textOrPath, image, mimeType, sourceRect);
return;
}
final ShareResultListener finalListener = listener;
impl.share(textOrPath, image, mimeType, sourceRect, new ShareResultListener() {
@Override
public void onResult(final ShareResult result) {
final ShareResult r = result != null ? result : ShareResult.sharedTo(null);
callSerially(new Runnable() {
@Override
public void run() {
finalListener.onResult(r);
}
});
}
});
}

/// The localization manager allows adapting values for display in different locales thru parsing and formatting
Expand Down
Loading
Loading