├── index.html ├── src ├── ios │ ├── CDVSpinnerDialog.h │ └── CDVSpinnerDialog.m ├── android │ ├── CallbackProgressDialog.java │ └── SpinnerDialog.java └── wp │ └── SpinnerDialog.cs ├── LICENSE ├── www └── spinner.js ├── package.json ├── plugin.xml └── README.md /index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/ios/CDVSpinnerDialog.h: -------------------------------------------------------------------------------- 1 | // 2 | // CDVSpinnerDialog.h 3 | // 4 | // Created by Domonkos Pál on 2014.01.27.. 5 | // 6 | // 7 | 8 | #import 9 | 10 | @interface CDVSpinnerDialog : CDVPlugin 11 | 12 | - (void)show:(CDVInvokedUrlCommand*)command; 13 | - (void)hide:(CDVInvokedUrlCommand*)command; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Domonkos Pal 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /www/spinner.js: -------------------------------------------------------------------------------- 1 | var exec = require('cordova/exec'); 2 | 3 | module.exports = { 4 | 5 | show: function (title, message, cancelCallback, iosOptions) { 6 | if (cancelCallback == true && typeof cancelCallback !== "function") { 7 | cancelCallback = function () { }; 8 | } 9 | var isPlatformIos = (navigator.userAgent.match(/iPad/i)) == "iPad" || (navigator.userAgent.match(/iPhone/i)) == "iPhone" ? true : false; 10 | var params = [title, message, !!cancelCallback]; 11 | if (isPlatformIos) { 12 | if (typeof iosOptions != "object") { 13 | iosOptions = { overlayOpacity: 0.35, textColorRed: 1, textColorGreen: 1, textColorBlue: 1 } 14 | } 15 | params = params.concat([(iosOptions.overlayOpacity || 0.35), (iosOptions.textColorRed || 1), (iosOptions.textColorGreen || 1), (iosOptions.textColorBlue || 1)]) 16 | } 17 | cordova.exec(cancelCallback, null, 'SpinnerDialog', 'show', params); 18 | 19 | }, 20 | hide: function (success, fail) { 21 | cordova.exec(success, fail, 'SpinnerDialog', 'hide', ["", ""]); 22 | } 23 | 24 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova-plugin-spinner-dialog", 3 | "version": "1.3.1", 4 | "description": "PhoneGap / Cordova waiting dialog (progress indicator) plugin with spinner for Android, iOS and Windows Phone 8. Maintained from original Paldom/SpinnerDialog repository.", 5 | "cordova": { 6 | "id": "cordova-plugin-spinner-dialog", 7 | "platforms": [ 8 | "android", 9 | "ios", 10 | "wp8" 11 | ] 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/Paldom/SpinnerDialog.git" 16 | }, 17 | "keywords": [ 18 | "phonegap", 19 | "android", 20 | "ios", 21 | "wp8", 22 | "windows", 23 | "phone", 24 | "spinner", 25 | "dialog", 26 | "progress", 27 | "indicator", 28 | "ecosystem:cordova", 29 | "cordova-android", 30 | "cordova-ios", 31 | "cordova-wp8" 32 | ], 33 | "author": "Domonkos Pal (https://github.com/Paldom)", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/Paldom/SpinnerDialog/issues" 37 | }, 38 | "homepage": "https://github.com/Paldom/SpinnerDialog#readme" 39 | } 40 | -------------------------------------------------------------------------------- /src/android/CallbackProgressDialog.java: -------------------------------------------------------------------------------- 1 | package hu.dpal.phonegap.plugins; 2 | 3 | import org.apache.cordova.CallbackContext; 4 | import org.apache.cordova.PluginResult; 5 | 6 | import android.app.ProgressDialog; 7 | import android.content.Context; 8 | import android.view.MotionEvent; 9 | 10 | import android.graphics.Color; 11 | import android.graphics.drawable.ColorDrawable; 12 | 13 | public class CallbackProgressDialog extends ProgressDialog { 14 | 15 | public static CallbackContext callbackContext; 16 | 17 | public CallbackProgressDialog(Context context) { 18 | super(context); 19 | } 20 | 21 | public static CallbackProgressDialog show(Context context, 22 | CharSequence title, CharSequence message, boolean indeterminate, 23 | boolean cancelable, OnCancelListener cancelListener, 24 | CallbackContext callbackContext) { 25 | CallbackProgressDialog.callbackContext = callbackContext; 26 | CallbackProgressDialog dialog = new CallbackProgressDialog(context); 27 | dialog.setTitle(title); 28 | dialog.setMessage(message); 29 | dialog.setIndeterminate(indeterminate); 30 | dialog.setCancelable(cancelable); 31 | dialog.setOnCancelListener(cancelListener); 32 | dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 33 | dialog.show(); 34 | return dialog; 35 | } 36 | 37 | private void sendCallback() { 38 | PluginResult pluginResult = new PluginResult(PluginResult.Status.OK); 39 | pluginResult.setKeepCallback(true); 40 | callbackContext.sendPluginResult(pluginResult); 41 | } 42 | 43 | @Override 44 | public void onBackPressed() { 45 | sendCallback(); 46 | } 47 | 48 | @Override 49 | public boolean onTouchEvent(MotionEvent event) { 50 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 51 | sendCallback(); 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | SpinnerDialog 8 | 9 | 10 | PhoneGap waiting dialog (progress indicator) plugin with spinner for Android, iOS and Windows Phone 8. 11 | 12 | MIT 13 | phonegap,android,ios,wp8,windows,phone,spinner,dialog,progress,indicator 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/android/SpinnerDialog.java: -------------------------------------------------------------------------------- 1 | package hu.dpal.phonegap.plugins; 2 | 3 | import java.util.Stack; 4 | 5 | import org.apache.cordova.CallbackContext; 6 | import org.apache.cordova.CordovaInterface; 7 | import org.apache.cordova.CordovaPlugin; 8 | import org.json.JSONArray; 9 | import org.json.JSONException; 10 | 11 | import android.app.ProgressDialog; 12 | import android.content.DialogInterface; 13 | import android.widget.ProgressBar; 14 | 15 | public class SpinnerDialog extends CordovaPlugin { 16 | 17 | public Stack spinnerDialogStack = new Stack(); 18 | 19 | public SpinnerDialog() { 20 | } 21 | 22 | public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { 23 | if (action.equals("show")) { 24 | 25 | final String title = "null".equals(args.getString(0)) ? null : args.getString(0); 26 | final String message = "null".equals(args.getString(1)) ? null : args.getString(1); 27 | final boolean isFixed = args.getBoolean(2); 28 | 29 | final CordovaInterface cordova = this.cordova; 30 | Runnable runnable = new Runnable() { 31 | public void run() { 32 | 33 | DialogInterface.OnCancelListener onCancelListener = new DialogInterface.OnCancelListener() { 34 | public void onCancel(DialogInterface dialog) { 35 | if (!isFixed) { 36 | while (!SpinnerDialog.this.spinnerDialogStack.empty()) { 37 | SpinnerDialog.this.spinnerDialogStack.pop().dismiss(); 38 | callbackContext.success(); 39 | } 40 | } 41 | } 42 | }; 43 | 44 | ProgressDialog dialog; 45 | if (isFixed) { 46 | dialog = CallbackProgressDialog.show(cordova.getActivity(), title, message, true, false, null, callbackContext); 47 | } else { 48 | dialog = ProgressDialog.show(cordova.getActivity(), title, message, true, true, onCancelListener); 49 | } 50 | 51 | if (title == null && message == null) { 52 | dialog.setContentView(new ProgressBar(cordova.getActivity())); 53 | } 54 | 55 | SpinnerDialog.this.spinnerDialogStack.push(dialog); 56 | 57 | } 58 | }; 59 | this.cordova.getActivity().runOnUiThread(runnable); 60 | 61 | } else if (action.equals("hide")) { 62 | 63 | Runnable runnable = new Runnable() { 64 | public void run() { 65 | 66 | if (!SpinnerDialog.this.spinnerDialogStack.empty()) { 67 | SpinnerDialog.this.spinnerDialogStack.pop().dismiss(); 68 | } 69 | 70 | } 71 | }; 72 | this.cordova.getActivity().runOnUiThread(runnable); 73 | 74 | } 75 | return true; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/wp/SpinnerDialog.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Phone.Controls; 2 | using Microsoft.Phone.Shell; 3 | using System.Windows; 4 | using System.Windows.Input; 5 | 6 | namespace WPCordovaClassLib.Cordova.Commands 7 | { 8 | public class SpinnerDialog : BaseCommand 9 | { 10 | 11 | private static ProgressIndicator progressIndicator; 12 | private static PhoneApplicationPage page; 13 | private static bool sysTrayVisibilityDetermined; 14 | private static bool sysTrayVisible; 15 | 16 | public void show(string options) 17 | { 18 | 19 | string[] args = JSON.JsonHelper.Deserialize(options); 20 | string title = args[0]; 21 | string message = args[1]; 22 | string isFixed = args[2]; 23 | 24 | if (message == null || "null".Equals(message)) 25 | { 26 | if (title != null && !"null".Equals(title)) 27 | { 28 | message = title; 29 | } 30 | } 31 | 32 | Deployment.Current.Dispatcher.BeginInvoke(() => 33 | { 34 | 35 | if (progressIndicator == null) 36 | { 37 | progressIndicator = new ProgressIndicator() { IsIndeterminate = true }; 38 | } 39 | progressIndicator.Text = message; 40 | progressIndicator.IsVisible = true; 41 | 42 | if (page == null) 43 | { 44 | page = (Application.Current.RootVisual as PhoneApplicationFrame).Content as PhoneApplicationPage; 45 | } 46 | 47 | if (isFixed == null || "false".Equals(isFixed)) 48 | { 49 | page.MouseLeftButtonUp += ButtonEventHandler; 50 | } 51 | 52 | SystemTray.SetProgressIndicator(page, progressIndicator); 53 | 54 | // determine systray visibility on first visit 55 | if (!sysTrayVisibilityDetermined) 56 | { 57 | sysTrayVisible = SystemTray.IsVisible; 58 | sysTrayVisibilityDetermined = true; 59 | } 60 | 61 | // show the tray if it's not visible, otherwise the spinner won't show up 62 | if (!sysTrayVisible) 63 | { 64 | SystemTray.IsVisible = true; 65 | } 66 | 67 | }); 68 | 69 | } 70 | 71 | private void ButtonEventHandler(object sender, MouseButtonEventArgs e) 72 | { 73 | hide(null); 74 | DispatchCommandResult(new PluginResult(PluginResult.Status.OK)); 75 | } 76 | 77 | public void hide(string options) 78 | { 79 | 80 | if (progressIndicator != null && page != null) 81 | { 82 | Deployment.Current.Dispatcher.BeginInvoke(() => 83 | { 84 | if (!sysTrayVisible) 85 | { 86 | SystemTray.IsVisible = false; 87 | } 88 | 89 | SystemTray.SetProgressIndicator(page, null); 90 | page.MouseLeftButtonUp -= ButtonEventHandler; 91 | }); 92 | } 93 | 94 | } 95 | 96 | } 97 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SpinnerDialog 2 | ============= 3 | 4 | PhoneGap waiting dialog / progress dialog plugin with spinner for Android, iOS and Windows Phone 8. 5 | 6 | ## Installation 7 | 8 | Latest stable release: ```phonegap local plugin add cordova-plugin-spinner-dialog``` 9 | or ```cordova plugin add cordova-plugin-spinner-dialog``` 10 | 11 | Current state from git: ```phonegap local plugin add https://github.com/Paldom/SpinnerDialog.git``` 12 | or ```cordova plugin add https://github.com/Paldom/SpinnerDialog.git``` 13 | 14 | ## Installation - PhoneGap Build 15 | 16 | Add following to config.xml: `````` 17 | 18 | For older versions, use the following: `````` 19 | or `````` 20 | 21 | ## Methods 22 | 23 | - `window.plugins.spinnerDialog.show` 24 | - `window.plugins.spinnerDialog.hide` 25 | 26 | ## window.plugins.spinnerDialog.show 27 | 28 | 29 | window.plugins.spinnerDialog.show([title], [message], [cancelCallback]) 30 | 31 | - __title__: Spinner title (Android only). Optional. _(String)_ 32 | - __message__: Spinner message. Optional. _(String)_ 33 | - __cancelCallback__: Callback to invoke when spinner cancel event fired (tap or Android hardware back button event). If set, spinner dialog will be fixed, you should explicitly call `window.plugins.spinnerDialog.hide`. Due to legacy reasons you can provide boolean value (true/false) to set spinner not cancelable. Optional, defaults to `false`. _(Function/Boolean)_ 34 | 35 | 36 | ## Supported Platforms 37 | 38 | - Android 39 | - iOS 40 | - Windows Phone 8 41 | 42 | ## Usage 43 | 44 | // Show spinner dialog 45 | window.plugins.spinnerDialog.show(); 46 | 47 | // Show spinner dialog with message 48 | // Note: spinner dialog is cancelable by default 49 | window.plugins.spinnerDialog.show(null, "message"); 50 | 51 | // Set spinner dialog fixed 52 | window.plugins.spinnerDialog.show(null, null, true); 53 | 54 | // Set spinner dialog fixed with callback 55 | // Note: callback fires on tap events and Android hardware back button click event 56 | window.plugins.spinnerDialog.show(null, null, function () {console.log("callback");}); 57 | 58 | // Show spinner dialog with title and message (Android only) 59 | window.plugins.spinnerDialog.show("title","message"); 60 | 61 | // Set spinner dialog fixed (cannot be canceled with screen touch or Android hardware button) 62 | window.plugins.spinnerDialog.show("title","message", true); 63 | 64 | // Overlay opacity and text color options (IOS only) 65 | window.plugins.spinnerDialog.show(null,"Message",true, {overlayOpacity: 0.35, textColorRed: 1, textColorGreen: 1, textColorBlue: 1}); 66 | 67 | // Change only overlay opacity (IOS only) 68 | window.plugins.spinnerDialog.show(null,"Message",true,{overlayOpacity:0.70}); 69 | 70 | // Change only text color (IOS only) 71 | window.plugins.spinnerDialog.show(null,"message",true, { textColorRed: 0.1, textColorGreen: 0.1, textColorBlue: 1}); 72 | 73 | 74 | // Hide spinner dialog 75 | window.plugins.spinnerDialog.hide(); 76 | 77 | 78 | 79 | Note: on Android platform, multiple show calls builds up a stack (LIFO) which means hide will dismiss the last spinner added with show call. 80 | 81 | ## License 82 | 83 | MIT License -------------------------------------------------------------------------------- /src/ios/CDVSpinnerDialog.m: -------------------------------------------------------------------------------- 1 | // 2 | // CDVSpinnerDialog.m 3 | // 4 | // Created by Domonkos Pál on 2014.01.27.. 5 | // 6 | // 7 | 8 | #import "CDVSpinnerDialog.h" 9 | 10 | @interface CDVSpinnerDialog () { 11 | UIActivityIndicatorView *indicator; 12 | NSString *callbackId; 13 | NSString *title; 14 | NSString *message; 15 | NSNumber *isFixed; 16 | NSString *alpha; 17 | NSString *red; 18 | NSString *green; 19 | NSString *blue; 20 | } 21 | 22 | @property (nonatomic, retain) UIActivityIndicatorView *indicator; 23 | @property (nonatomic, retain) UIView *overlay; 24 | @property (nonatomic, retain) UILabel *messageView; 25 | 26 | 27 | @end 28 | 29 | @implementation CDVSpinnerDialog 30 | 31 | @synthesize indicator = _indicator; 32 | @synthesize overlay = _overlay; 33 | @synthesize messageView = _messageView; 34 | 35 | -(CGRect)rectForView { 36 | if ((NSFoundationVersionNumber <= 1047.25 /* 7.1 */) && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) { 37 | return CGRectMake( 0.0f, 0.0f, [[UIScreen mainScreen]bounds].size.height, [UIScreen mainScreen].bounds.size.width); 38 | } 39 | return CGRectMake( 0.0f, 0.0f, [[UIScreen mainScreen]bounds].size.width, [UIScreen mainScreen].bounds.size.height); 40 | } 41 | 42 | - (void)handleTapGesture:(UITapGestureRecognizer *)gesture 43 | { 44 | CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK]; 45 | [result setKeepCallbackAsBool:true]; 46 | if (!isFixed.boolValue) { 47 | [result setKeepCallbackAsBool:false]; 48 | [self hide]; 49 | } 50 | [self.commandDelegate sendPluginResult:result callbackId:callbackId]; 51 | } 52 | 53 | - (UIView *)overlay { 54 | if (!_overlay) { 55 | _overlay = [[UIView alloc] initWithFrame:self.rectForView]; 56 | _overlay.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:[alpha floatValue]]; 57 | _indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 58 | _indicator.center = _overlay.center; 59 | [_indicator startAnimating]; 60 | [_overlay addSubview:_indicator]; 61 | 62 | _messageView = [[UILabel alloc] initWithFrame: self.rectForView]; 63 | [_messageView setText: message == nil ? title : message]; 64 | [_messageView setTextColor: [UIColor colorWithRed:[red floatValue] green:[green floatValue] blue:[blue floatValue] alpha:0.85]]; 65 | [_messageView setBackgroundColor: [UIColor colorWithRed:0 green:0 blue:0 alpha:0]]; 66 | [_messageView setTextAlignment: NSTextAlignmentCenter]; 67 | _messageView.center = (CGPoint){_overlay.center.x, _overlay.center.y + 40}; 68 | [_overlay addSubview:_messageView]; 69 | 70 | UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapGesture:)]; 71 | [_overlay addGestureRecognizer: tapRecognizer]; 72 | } 73 | return _overlay; 74 | } 75 | 76 | 77 | - (void) show:(CDVInvokedUrlCommand*)command { 78 | 79 | callbackId = command.callbackId; 80 | 81 | title = [command argumentAtIndex:0]; 82 | message = [command argumentAtIndex:1]; 83 | isFixed = [command argumentAtIndex:2]; 84 | alpha = [command argumentAtIndex:3]; 85 | red = [command argumentAtIndex:4]; 86 | green = [command argumentAtIndex:5]; 87 | blue = [command argumentAtIndex:6]; 88 | 89 | UIViewController *rootViewController = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; 90 | 91 | [rootViewController.view addSubview:self.overlay]; 92 | 93 | } 94 | 95 | - (void) hide:(CDVInvokedUrlCommand*)command { 96 | [self hide]; 97 | } 98 | 99 | - (void) hide { 100 | if (_overlay) { 101 | [self.indicator stopAnimating]; 102 | [self.indicator removeFromSuperview]; 103 | [self.messageView removeFromSuperview]; 104 | [self.overlay removeFromSuperview]; 105 | _indicator = nil; 106 | _messageView = nil; 107 | _overlay = nil; 108 | } 109 | } 110 | 111 | #pragma mark - PRIVATE METHODS 112 | 113 | 114 | @end 115 | 116 | 117 | --------------------------------------------------------------------------------