Compare commits

..
10 Commits
7 changed files with 165 additions and 38 deletions
+35 -9
View File
@@ -63,18 +63,19 @@ Toast is compatible with [Cordova Plugman](https://github.com/apache/cordova-plu
Using the Cordova CLI and the [Cordova Plugin Registry](http://plugins.cordova.io)
```
$ cordova plugin add nl.x-services.plugins.toast
$ cordova plugin add cordova-plugin-x-toast
$ cordova prepare
```
Or using the phonegap CLI
```
$ phonegap local plugin add nl.x-services.plugins.toast
$ phonegap local plugin add cordova-plugin-x-toast
```
Toast.js is brought in automatically. There is no need to change or add anything in your html.
### Manually
You'd better use the CLI, but here goes:
1\. Add the following xml to your `config.xml` in the root directory of your `www` folder:
```xml
@@ -118,11 +119,7 @@ Toast works with PhoneGap build too, but only with PhoneGap 3.0 and up.
Just add the following xml to your `config.xml` to always use the latest version of this plugin:
```xml
<gap:plugin name="nl.x-services.plugins.toast" source="plugins.cordova.io" />
```
or to use a specific version:
```xml
<gap:plugin name="nl.x-services.plugins.toast" source="plugins.cordova.io" version="2.0.6" />
<gap:plugin name="cordova-plugin-x-toast" source="npm" />
```
Toast.js is brought in automatically. There is no need to change or add anything in your html.
@@ -154,7 +151,7 @@ You can copy-paste these lines of code for a quick test:
Since 2.1.0 you can add pixels to move the toast up or down.
Note that `showWithOptions` can be used instead of the functions above, but it's not useful unless you want to pass `addPixelsY`.
```js
function showTop() {
function showBottom() {
window.plugins.toast.showWithOptions(
{
message: "hey there",
@@ -177,7 +174,34 @@ function hide() {
}
```
### WP8 quircks
### Receiving a callback when a Toast is tapped
On iOS and Android the success handler of your `show` function will be notified (again) when the toast was tapped.
So the first time the success handler fires is when the toast is shown, and in case the user taps the toast it will be
called again. You can distinguish between those events of course:
```js
window.plugins.toast.showWithOptions(
{
message: "hey there",
duration: "short",
position: "bottom",
addPixelsY: -40 // added a negative value to move it up a bit (default 0)
},
// implement the success callback
function(result) {
if (result && result.event) {
console.log("The toast was tapped");
console.log("Event: " + result.event); // will be defined, with a value of "touch" when it was tapped by the user
console.log("Message: " + result.message); // will be equal to the message you passed in
} else {
console.log("The toast has been shown");
}
}
);
```
### WP8 quirks
The WP8 implementation needs a little more work, but it's perfectly useable when you keep this in mind:
* You can't show two Toasts simultaneously.
* Wait until the first Toast is hidden before the second is shown, otherwise the second one will be hidden quickly.
@@ -191,6 +215,8 @@ The Android code was entirely created by me.
For iOS most credits go to this excellent [Toast for iOS project by Charles Scalesse] (https://github.com/scalessec/Toast).
## 6. CHANGELOG
2.3.0: The plugin will now report back to JS if Toasts were tapped by the user.
2.0.1: iOS messages are hidden when another one is shown. [Thanks Richie Min!](https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin/pull/13)
2.0: WP8 support
+41
View File
@@ -0,0 +1,41 @@
{
"name": "cordova-plugin-x-toast",
"version": "2.3.0",
"description": "This plugin allows you to show a Toast. A Toast is a little non intrusive buttonless popup which automatically disappears.",
"cordova": {
"id": "cordova-plugin-x-toast",
"platforms": [
"ios",
"android",
"wp8",
"blackberry10"
]
},
"repository": {
"type": "git",
"url": "git+https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin.git"
},
"keywords": [
"Toast",
"Notification",
"Message",
"Alert",
"ecosystem:cordova",
"cordova-ios",
"cordova-android",
"cordova-wp8",
"cordova-blackberry10"
],
"engines": [
{
"name": "cordova",
"version": ">=3.0.0"
}
],
"author": "Eddy Verbruggen <eddyverbruggen@gmail.com> (https://github.com/EddyVerbruggen)",
"license": "MIT",
"bugs": {
"url": "https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin/issues"
},
"homepage": "https://github.com/EddyVerbruggen/Toast-PhoneGap-Plugin#readme"
}
+2 -2
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="nl.x-services.plugins.toast"
version="2.1.1">
id="cordova-plugin-x-toast"
version="2.3.0">
<name>Toast</name>
+37 -2
View File
@@ -1,8 +1,13 @@
package nl.xservices.plugins;
import android.os.Build;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -24,6 +29,8 @@ public class Toast extends CordovaPlugin {
private android.widget.Toast mostRecentToast;
private static final boolean IS_AT_LEAST_ANDROID5 = Build.VERSION.SDK_INT >= 21;
// note that webView.isPaused() is not Xwalk compatible, so tracking it poor-man style
private boolean isPaused;
@@ -52,10 +59,16 @@ public class Toast extends CordovaPlugin {
cordova.getActivity().runOnUiThread(new Runnable() {
public void run() {
android.widget.Toast toast = android.widget.Toast.makeText(
cordova.getActivity().getApplicationContext(),
IS_AT_LEAST_ANDROID5 ? cordova.getActivity().getWindow().getContext() : cordova.getActivity().getApplicationContext(),
message,
"short".equals(duration) ? android.widget.Toast.LENGTH_SHORT : android.widget.Toast.LENGTH_LONG);
// if we want to change the background color some day, we can use this
// try {
// final Method setTintMethod = Drawable.class.getMethod("setTint", int.class);
// setTintMethod.invoke(toast.getView().getBackground(), Color.RED); // default is Color.DKGRAY
// } catch (Exception ignore) {
// }
if ("top".equals(position)) {
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 20 + addPixelsY);
} else if ("bottom".equals(position)) {
@@ -67,9 +80,31 @@ public class Toast extends CordovaPlugin {
return;
}
toast.getView().setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
JSONObject json = new JSONObject();
try {
json.put("event", "touch");
json.put("message", message);
} catch (JSONException e) {
e.printStackTrace();
}
callbackContext.success(json);
return true;
} else {
return false;
}
}
});
toast.show();
mostRecentToast = toast;
callbackContext.success();
PluginResult pr = new PluginResult(PluginResult.Status.OK);
pr.setKeepCallback(true);
callbackContext.sendPluginResult(pr);
}
});
+2 -1
View File
@@ -1,11 +1,12 @@
#import <Foundation/Foundation.h>
#import <Cordova/CDV.h>
@interface UIView (Toast)
// each makeToast method creates a view and displays it as toast
- (void)makeToast:(NSString *)message;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY commandDelegate:(id <CDVCommandDelegate>)commandDelegate callbackId:(NSString *)callbackId;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position image:(UIImage *)image;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position title:(NSString *)title;
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)interval position:(id)position title:(NSString *)title image:(UIImage *)image;
+41 -23
View File
@@ -48,6 +48,11 @@ static const NSString * CSToastActivityViewKey = @"CSToastActivityViewKey";
static UIView *prevToast = NULL;
// doesn't matter these are static
static id commandDelegate;
static id callbackId;
static id msg;
@interface UIView (ToastPrivate)
- (void)hideToast:(UIView *)toast;
@@ -56,7 +61,6 @@ static UIView *prevToast = NULL;
- (CGPoint)centerPointForPosition:(id)position withToast:(UIView *)toast withAddedPixelsY:(int) addPixelsY;
- (UIView *)viewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image;
- (CGSize)sizeForString:(NSString *)string font:(UIFont *)font constrainedToSize:(CGSize)constrainedSize lineBreakMode:(NSLineBreakMode)lineBreakMode;
@end
@@ -73,24 +77,27 @@ static UIView *prevToast = NULL;
[self showToast:toast duration:duration position:position];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY {
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position addPixelsY:(int)addPixelsY commandDelegate:(id <CDVCommandDelegate>)_commandDelegate callbackId:(NSString *)_callbackId {
commandDelegate = _commandDelegate;
callbackId = _callbackId;
msg = message;
UIView *toast = [self viewForMessage:message title:nil image:nil];
[self showToast:toast duration:duration position:position addedPixelsY:addPixelsY];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title {
UIView *toast = [self viewForMessage:message title:title image:nil];
[self showToast:toast duration:duration position:position];
[self showToast:toast duration:duration position:position];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position image:(UIImage *)image {
UIView *toast = [self viewForMessage:message title:nil image:image];
[self showToast:toast duration:duration position:position];
[self showToast:toast duration:duration position:position];
}
- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title image:(UIImage *)image {
UIView *toast = [self viewForMessage:message title:title image:image];
[self showToast:toast duration:duration position:position];
[self showToast:toast duration:duration position:position];
}
- (void)showToast:(UIView *)toast {
@@ -101,26 +108,24 @@ static UIView *prevToast = NULL;
[self showToast:toast duration:CSToastDefaultDuration position:CSToastDefaultPosition addedPixelsY:0];
}
- (void)showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)point addedPixelsY:(int) addPixelsY {
- (void)showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)point addedPixelsY:(int) addPixelsY {
[self hideToast];
prevToast = toast;
toast.center = [self centerPointForPosition:point withToast:toast withAddedPixelsY:addPixelsY];
toast.alpha = 0.0;
// note that we changed this to be always true
if (CSToastHidesOnTap) {
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:toast action:@selector(handleToastTapped:)];
[toast addGestureRecognizer:recognizer];
toast.userInteractionEnabled = YES;
toast.exclusiveTouch = YES;
}
if ([[[UIDevice currentDevice] systemVersion] compare:@"8.0" options:NSNumericSearch] != NSOrderedAscending) {
// on iOS8 when InAppBrowser is active, the Toast is below it,
[self.superview.superview addSubview:toast];
} else {
// ..on iOS7 however with this fix on landscape the Toast isn't rotated automatically
[self.superview addSubview:toast];
}
// make sure that if InAppBrowser is active, we're still showing Toasts on top of it
UIViewController *vc = [self getTopMostViewController];
UIView *v = [vc view];
[v addSubview:toast];
[UIView animateWithDuration:CSToastFadeDuration
delay:0.0
@@ -132,7 +137,15 @@ static UIView *prevToast = NULL;
// associate the timer with the toast view
objc_setAssociatedObject (toast, &CSToastTimerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}];
}
- (UIViewController*) getTopMostViewController {
UIViewController *presentingViewController = [[[UIApplication sharedApplication] delegate] window].rootViewController;
while (presentingViewController.presentedViewController != nil) {
presentingViewController = presentingViewController.presentedViewController;
}
return presentingViewController;
}
- (void)hideToast {
@@ -163,6 +176,11 @@ static UIView *prevToast = NULL;
[timer invalidate];
[self hideToast:recognizer.view];
// also send an event back to JS
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:msg, @"message", @"touch", @"event", nil];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:dict];
[commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
}
#pragma mark - Toast Activity Methods
@@ -175,31 +193,31 @@ static UIView *prevToast = NULL;
// sanity
UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey);
if (existingActivityView != nil) return;
UIView *activityView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CSToastActivityWidth, CSToastActivityHeight)];
activityView.center = [self centerPointForPosition:position withToast:activityView withAddedPixelsY:0];
activityView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:CSToastOpacity];
activityView.alpha = 0.0;
activityView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
activityView.layer.cornerRadius = CSToastCornerRadius;
if (CSToastDisplayShadow) {
activityView.layer.shadowColor = [UIColor blackColor].CGColor;
activityView.layer.shadowOpacity = CSToastShadowOpacity;
activityView.layer.shadowRadius = CSToastShadowRadius;
activityView.layer.shadowOffset = CSToastShadowOffset;
}
UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicatorView.center = CGPointMake(activityView.bounds.size.width / 2, activityView.bounds.size.height / 2);
[activityView addSubview:activityIndicatorView];
[activityIndicatorView startAnimating];
// associate the activity view with self
objc_setAssociatedObject (self, &CSToastActivityViewKey, activityView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[self addSubview:activityView];
[UIView animateWithDuration:CSToastFadeDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
@@ -238,7 +256,7 @@ static UIView *prevToast = NULL;
} else if ([point isKindOfClass:[NSValue class]]) {
return [point CGPointValue];
}
NSLog(@"Warning: Invalid position for toast.");
return [self centerPointForPosition:CSToastDefaultPosition withToast:toast withAddedPixelsY:addPixelsY];
}
+7 -1
View File
@@ -30,9 +30,15 @@
return;
}
[self.webView makeToast:message duration:durationInt position:position addPixelsY:addPixelsY == nil ? 0 : [addPixelsY intValue]];
[self.webView makeToast:message
duration:durationInt
position:position
addPixelsY:addPixelsY == nil ? 0 : [addPixelsY intValue]
commandDelegate:self.commandDelegate
callbackId:command.callbackId];
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
pluginResult.keepCallback = [NSNumber numberWithBool:YES];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}