diff options
Diffstat (limited to 'StoneIsland/plugins/cordova-plugin-dialogs/src')
14 files changed, 2047 insertions, 0 deletions
diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/android/Notification.java b/StoneIsland/plugins/cordova-plugin-dialogs/src/android/Notification.java new file mode 100755 index 00000000..3bc3cee6 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/android/Notification.java @@ -0,0 +1,483 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova.dialogs; + +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaInterface; +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.PluginResult; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.widget.EditText; +import android.widget.TextView; + + +/** + * This class provides access to notifications on the device. + * + * Be aware that this implementation gets called on + * navigator.notification.{alert|confirm|prompt}, and that there is a separate + * implementation in org.apache.cordova.CordovaChromeClient that gets + * called on a simple window.{alert|confirm|prompt}. + */ +public class Notification extends CordovaPlugin { + + public int confirmResult = -1; + public ProgressDialog spinnerDialog = null; + public ProgressDialog progressDialog = null; + + /** + * Constructor. + */ + public Notification() { + } + + /** + * Executes the request and returns PluginResult. + * + * @param action The action to execute. + * @param args JSONArray of arguments for the plugin. + * @param callbackContext The callback context used when calling back into JavaScript. + * @return True when the action was valid, false otherwise. + */ + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + /* + * Don't run any of these if the current activity is finishing + * in order to avoid android.view.WindowManager$BadTokenException + * crashing the app. Just return true here since false should only + * be returned in the event of an invalid action. + */ + if(this.cordova.getActivity().isFinishing()) return true; + + if (action.equals("beep")) { + this.beep(args.getLong(0)); + } + else if (action.equals("alert")) { + this.alert(args.getString(0), args.getString(1), args.getString(2), callbackContext); + return true; + } + else if (action.equals("confirm")) { + this.confirm(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext); + return true; + } + else if (action.equals("prompt")) { + this.prompt(args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), callbackContext); + return true; + } + else if (action.equals("activityStart")) { + this.activityStart(args.getString(0), args.getString(1)); + } + else if (action.equals("activityStop")) { + this.activityStop(); + } + else if (action.equals("progressStart")) { + this.progressStart(args.getString(0), args.getString(1)); + } + else if (action.equals("progressValue")) { + this.progressValue(args.getInt(0)); + } + else if (action.equals("progressStop")) { + this.progressStop(); + } + else { + return false; + } + + // Only alert and confirm are async. + callbackContext.success(); + return true; + } + + //-------------------------------------------------------------------------- + // LOCAL METHODS + //-------------------------------------------------------------------------- + + /** + * Beep plays the default notification ringtone. + * + * @param count Number of times to play notification + */ + public void beep(final long count) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + Ringtone notification = RingtoneManager.getRingtone(cordova.getActivity().getBaseContext(), ringtone); + + // If phone is not set to silent mode + if (notification != null) { + for (long i = 0; i < count; ++i) { + notification.play(); + long timeout = 5000; + while (notification.isPlaying() && (timeout > 0)) { + timeout = timeout - 100; + try { + Thread.sleep(100); + } catch (InterruptedException e) { + } + } + } + } + } + }); + } + + /** + * Builds and shows a native Android alert with given Strings + * @param message The message the alert should display + * @param title The title of the alert + * @param buttonLabel The label of the button + * @param callbackContext The callback context + */ + public synchronized void alert(final String message, final String title, final String buttonLabel, final CallbackContext callbackContext) { + final CordovaInterface cordova = this.cordova; + + Runnable runnable = new Runnable() { + public void run() { + + AlertDialog.Builder dlg = createDialog(cordova); // new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + dlg.setMessage(message); + dlg.setTitle(title); + dlg.setCancelable(true); + dlg.setPositiveButton(buttonLabel, + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0)); + } + }); + dlg.setOnCancelListener(new AlertDialog.OnCancelListener() { + public void onCancel(DialogInterface dialog) + { + dialog.dismiss(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0)); + } + }); + + changeTextDirection(dlg); + }; + }; + this.cordova.getActivity().runOnUiThread(runnable); + } + + /** + * Builds and shows a native Android confirm dialog with given title, message, buttons. + * This dialog only shows up to 3 buttons. Any labels after that will be ignored. + * The index of the button pressed will be returned to the JavaScript callback identified by callbackId. + * + * @param message The message the dialog should display + * @param title The title of the dialog + * @param buttonLabels A comma separated list of button labels (Up to 3 buttons) + * @param callbackContext The callback context. + */ + public synchronized void confirm(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) { + final CordovaInterface cordova = this.cordova; + + Runnable runnable = new Runnable() { + public void run() { + AlertDialog.Builder dlg = createDialog(cordova); // new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + dlg.setMessage(message); + dlg.setTitle(title); + dlg.setCancelable(true); + + // First button + if (buttonLabels.length() > 0) { + try { + dlg.setNegativeButton(buttonLabels.getString(0), + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1)); + } + }); + } catch (JSONException e) { } + } + + // Second button + if (buttonLabels.length() > 1) { + try { + dlg.setNeutralButton(buttonLabels.getString(1), + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2)); + } + }); + } catch (JSONException e) { } + } + + // Third button + if (buttonLabels.length() > 2) { + try { + dlg.setPositiveButton(buttonLabels.getString(2), + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3)); + } + }); + } catch (JSONException e) { } + } + dlg.setOnCancelListener(new AlertDialog.OnCancelListener() { + public void onCancel(DialogInterface dialog) + { + dialog.dismiss(); + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0)); + } + }); + + changeTextDirection(dlg); + }; + }; + this.cordova.getActivity().runOnUiThread(runnable); + } + + /** + * Builds and shows a native Android prompt dialog with given title, message, buttons. + * This dialog only shows up to 3 buttons. Any labels after that will be ignored. + * The following results are returned to the JavaScript callback identified by callbackId: + * buttonIndex Index number of the button selected + * input1 The text entered in the prompt dialog box + * + * @param message The message the dialog should display + * @param title The title of the dialog + * @param buttonLabels A comma separated list of button labels (Up to 3 buttons) + * @param callbackContext The callback context. + */ + public synchronized void prompt(final String message, final String title, final JSONArray buttonLabels, final String defaultText, final CallbackContext callbackContext) { + + final CordovaInterface cordova = this.cordova; + + Runnable runnable = new Runnable() { + public void run() { + final EditText promptInput = new EditText(cordova.getActivity()); + promptInput.setHint(defaultText); + AlertDialog.Builder dlg = createDialog(cordova); // new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + dlg.setMessage(message); + dlg.setTitle(title); + dlg.setCancelable(true); + + dlg.setView(promptInput); + + final JSONObject result = new JSONObject(); + + // First button + if (buttonLabels.length() > 0) { + try { + dlg.setNegativeButton(buttonLabels.getString(0), + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + try { + result.put("buttonIndex",1); + result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); + } catch (JSONException e) { e.printStackTrace(); } + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); + } + }); + } catch (JSONException e) { } + } + + // Second button + if (buttonLabels.length() > 1) { + try { + dlg.setNeutralButton(buttonLabels.getString(1), + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + try { + result.put("buttonIndex",2); + result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); + } catch (JSONException e) { e.printStackTrace(); } + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); + } + }); + } catch (JSONException e) { } + } + + // Third button + if (buttonLabels.length() > 2) { + try { + dlg.setPositiveButton(buttonLabels.getString(2), + new AlertDialog.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + try { + result.put("buttonIndex",3); + result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); + } catch (JSONException e) { e.printStackTrace(); } + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); + } + }); + } catch (JSONException e) { } + } + dlg.setOnCancelListener(new AlertDialog.OnCancelListener() { + public void onCancel(DialogInterface dialog){ + dialog.dismiss(); + try { + result.put("buttonIndex",0); + result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText()); + } catch (JSONException e) { e.printStackTrace(); } + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result)); + } + }); + + changeTextDirection(dlg); + }; + }; + this.cordova.getActivity().runOnUiThread(runnable); + } + + /** + * Show the spinner. + * + * @param title Title of the dialog + * @param message The message of the dialog + */ + public synchronized void activityStart(final String title, final String message) { + if (this.spinnerDialog != null) { + this.spinnerDialog.dismiss(); + this.spinnerDialog = null; + } + final Notification notification = this; + final CordovaInterface cordova = this.cordova; + Runnable runnable = new Runnable() { + public void run() { + notification.spinnerDialog = createProgressDialog(cordova); // new ProgressDialog(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + notification.spinnerDialog.setTitle(title); + notification.spinnerDialog.setMessage(message); + notification.spinnerDialog.setCancelable(true); + notification.spinnerDialog.setIndeterminate(true); + notification.spinnerDialog.setOnCancelListener( + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + notification.spinnerDialog = null; + } + }); + notification.spinnerDialog.show(); + } + }; + this.cordova.getActivity().runOnUiThread(runnable); + } + + /** + * Stop spinner. + */ + public synchronized void activityStop() { + if (this.spinnerDialog != null) { + this.spinnerDialog.dismiss(); + this.spinnerDialog = null; + } + } + + /** + * Show the progress dialog. + * + * @param title Title of the dialog + * @param message The message of the dialog + */ + public synchronized void progressStart(final String title, final String message) { + if (this.progressDialog != null) { + this.progressDialog.dismiss(); + this.progressDialog = null; + } + final Notification notification = this; + final CordovaInterface cordova = this.cordova; + Runnable runnable = new Runnable() { + public void run() { + notification.progressDialog = createProgressDialog(cordova); // new ProgressDialog(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + notification.progressDialog.setTitle(title); + notification.progressDialog.setMessage(message); + notification.progressDialog.setCancelable(true); + notification.progressDialog.setMax(100); + notification.progressDialog.setProgress(0); + notification.progressDialog.setOnCancelListener( + new DialogInterface.OnCancelListener() { + public void onCancel(DialogInterface dialog) { + notification.progressDialog = null; + } + }); + notification.progressDialog.show(); + } + }; + this.cordova.getActivity().runOnUiThread(runnable); + } + + /** + * Set value of progress bar. + * + * @param value 0-100 + */ + public synchronized void progressValue(int value) { + if (this.progressDialog != null) { + this.progressDialog.setProgress(value); + } + } + + /** + * Stop progress dialog. + */ + public synchronized void progressStop() { + if (this.progressDialog != null) { + this.progressDialog.dismiss(); + this.progressDialog = null; + } + } + + @SuppressLint("NewApi") + private AlertDialog.Builder createDialog(CordovaInterface cordova) { + int currentapiVersion = android.os.Build.VERSION.SDK_INT; + if (currentapiVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { + return new AlertDialog.Builder(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + } else { + return new AlertDialog.Builder(cordova.getActivity()); + } + } + + @SuppressLint("InlinedApi") + private ProgressDialog createProgressDialog(CordovaInterface cordova) { + int currentapiVersion = android.os.Build.VERSION.SDK_INT; + if (currentapiVersion >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + return new ProgressDialog(cordova.getActivity(), AlertDialog.THEME_DEVICE_DEFAULT_LIGHT); + } else { + return new ProgressDialog(cordova.getActivity()); + } + } + + @SuppressLint("NewApi") + private void changeTextDirection(Builder dlg){ + int currentapiVersion = android.os.Build.VERSION.SDK_INT; + dlg.create(); + AlertDialog dialog = dlg.show(); + if (currentapiVersion >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { + TextView messageview = (TextView)dialog.findViewById(android.R.id.message); + messageview.setTextDirection(android.view.View.TEXT_DIRECTION_LOCALE); + } + } +} diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/blackberry10/index.js b/StoneIsland/plugins/cordova-plugin-dialogs/src/blackberry10/index.js new file mode 100644 index 00000000..3660f667 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/blackberry10/index.js @@ -0,0 +1,87 @@ +/* +* Copyright 2013 Research In Motion Limited. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +function showDialog(args, dialogType, result) { + //Unpack and map the args + var msg = JSON.parse(decodeURIComponent(args[0])), + title = JSON.parse(decodeURIComponent(args[1])), + btnLabel = JSON.parse(decodeURIComponent(args[2])); + + if (!Array.isArray(btnLabel)) { + //Converts to array for (string) and (string,string, ...) cases + btnLabel = btnLabel.split(","); + } + + if (msg && typeof msg === "string") { + msg = msg.replace(/^"|"$/g, "").replace(/\\"/g, '"'); + } else { + result.error("message is undefined"); + return; + } + + var messageObj = { + title : title, + htmlmessage : msg, + dialogType : dialogType, + optionalButtons : btnLabel + }; + + //TODO replace with getOverlayWebview() when available in webplatform + qnx.webplatform.getWebViews()[2].dialog.show(messageObj, function (data) { + if (typeof data === "number") { + //Confirm dialog call back needs to be called with one-based indexing [1,2,3 etc] + result.callbackOk(++data, false); + } else { + //Prompt dialog callback expects object + result.callbackOk({ + buttonIndex: data.ok ? 1 : 0, + input1: (data.oktext) ? decodeURIComponent(data.oktext) : "" + }, false); + } + }); + + result.noResult(true); +} + +module.exports = { + alert: function (success, fail, args, env) { + var result = new PluginResult(args, env); + + if (Object.keys(args).length < 3) { + result.error("Notification action - alert arguments not found."); + } else { + showDialog(args, "CustomAsk", result); + } + }, + confirm: function (success, fail, args, env) { + var result = new PluginResult(args, env); + + if (Object.keys(args).length < 3) { + result.error("Notification action - confirm arguments not found."); + } else { + showDialog(args, "CustomAsk", result); + } + }, + prompt: function (success, fail, args, env) { + var result = new PluginResult(args, env); + + if (Object.keys(args).length < 3) { + result.error("Notification action - prompt arguments not found."); + } else { + showDialog(args, "JavaScriptPrompt", result); + } + } +}; diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/firefoxos/notification.js b/StoneIsland/plugins/cordova-plugin-dialogs/src/firefoxos/notification.js new file mode 100644 index 00000000..b6986fd0 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/firefoxos/notification.js @@ -0,0 +1,154 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +var modulemapper = require('cordova/modulemapper'); + + +var origOpenFunc = modulemapper.getOriginalSymbol(window, 'window.open'); + + +function _empty() {} + + +function modal(message, callback, title, buttonLabels, domObjects) { + var mainWindow = window; + var modalWindow = origOpenFunc(); + var modalDocument = modalWindow.document; + + modalDocument.write( + '<html><head>' + + '<link rel="stylesheet" type="text/css" href="/css/index.css" />' + + '<link rel="stylesheet" type="text/css" href="/css/notification.css" />' + + '</head><body></body></html>'); + + var box = modalDocument.createElement('form'); + box.setAttribute('role', 'dialog'); + // prepare and append empty section + var section = modalDocument.createElement('section'); + box.appendChild(section); + // add title + var boxtitle = modalDocument.createElement('h1'); + boxtitle.appendChild(modalDocument.createTextNode(title)); + section.appendChild(boxtitle); + // add message + var boxMessage = modalDocument.createElement('p'); + boxMessage.appendChild(modalDocument.createTextNode(message)); + section.appendChild(boxMessage); + // inject what's needed + if (domObjects) { + section.appendChild(domObjects); + } + // add buttons and assign callbackButton on click + var menu = modalDocument.createElement('menu'); + box.appendChild(menu); + for (var index = 0; index < buttonLabels.length; index++) { + addButton(buttonLabels[index], index, (index === 0)); + } + modalDocument.body.appendChild(box); + + function addButton(label, index, recommended) { + var thisButtonCallback = makeCallbackButton(index + 1); + var button = modalDocument.createElement('button'); + button.appendChild(modalDocument.createTextNode(label)); + button.addEventListener('click', thisButtonCallback, false); + if (recommended) { + // TODO: default one listens to Enter key + button.classList.add('recommend'); + } + menu.appendChild(button); + } + + // TODO: onUnload listens to the cancel key + function onUnload() { + var result = 0; + if (modalDocument.getElementById('prompt-input')) { + result = { + input1: '', + buttonIndex: 0 + } + } + mainWindow.setTimeout(function() { + callback(result); + }, 10); + }; + modalWindow.addEventListener('unload', onUnload, false); + + // call callback and destroy modal + function makeCallbackButton(labelIndex) { + return function() { + if (modalWindow) { + modalWindow.removeEventListener('unload', onUnload, false); + modalWindow.close(); + } + // checking if prompt + var promptInput = modalDocument.getElementById('prompt-input'); + var response; + if (promptInput) { + response = { + input1: promptInput.value, + buttonIndex: labelIndex + }; + } + response = response || labelIndex; + callback(response); + } + } +} + +var Notification = { + vibrate: function(milliseconds) { + navigator.vibrate(milliseconds); + }, + alert: function(successCallback, errorCallback, args) { + var message = args[0]; + var title = args[1]; + var _buttonLabels = [args[2]]; + var _callback = (successCallback || _empty); + modal(message, _callback, title, _buttonLabels); + }, + confirm: function(successCallback, errorCallback, args) { + var message = args[0]; + var title = args[1]; + var buttonLabels = args[2]; + var _callback = (successCallback || _empty); + modal(message, _callback, title, buttonLabels); + }, + prompt: function(successCallback, errorCallback, args) { + var message = args[0]; + var title = args[1]; + var buttonLabels = args[2]; + var defaultText = args[3]; + var inputParagraph = document.createElement('p'); + inputParagraph.classList.add('input'); + var inputElement = document.createElement('input'); + inputElement.setAttribute('type', 'text'); + inputElement.id = 'prompt-input'; + if (defaultText) { + inputElement.setAttribute('placeholder', defaultText); + } + inputParagraph.appendChild(inputElement); + modal(message, successCallback, title, buttonLabels, inputParagraph); + } +}; + + +module.exports = Notification; +require('cordova/exec/proxy').add('Notification', Notification); diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.bundle/beep.wav b/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.bundle/beep.wav Binary files differnew file mode 100644 index 00000000..05f5997f --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.bundle/beep.wav diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.h b/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.h new file mode 100644 index 00000000..9253f6a9 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.h @@ -0,0 +1,37 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> +#import <AudioToolbox/AudioServices.h> +#import <Cordova/CDVPlugin.h> + +@interface CDVNotification : CDVPlugin <UIAlertViewDelegate>{} + +- (void)alert:(CDVInvokedUrlCommand*)command; +- (void)confirm:(CDVInvokedUrlCommand*)command; +- (void)prompt:(CDVInvokedUrlCommand*)command; +- (void)beep:(CDVInvokedUrlCommand*)command; + +@end + +@interface CDVAlertView : UIAlertView {} +@property (nonatomic, copy) NSString* callbackId; + +@end diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.m b/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.m new file mode 100644 index 00000000..1581ad3c --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/ios/CDVNotification.m @@ -0,0 +1,221 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +#import "CDVNotification.h" + +#define DIALOG_TYPE_ALERT @"alert" +#define DIALOG_TYPE_PROMPT @"prompt" + +static void soundCompletionCallback(SystemSoundID ssid, void* data); + +@implementation CDVNotification + +/* + * showDialogWithMessage - Common method to instantiate the alert view for alert, confirm, and prompt notifications. + * Parameters: + * message The alert view message. + * title The alert view title. + * buttons The array of customized strings for the buttons. + * defaultText The input text for the textbox (if textbox exists). + * callbackId The commmand callback id. + * dialogType The type of alert view [alert | prompt]. + */ +- (void)showDialogWithMessage:(NSString*)message title:(NSString*)title buttons:(NSArray*)buttons defaultText:(NSString*)defaultText callbackId:(NSString*)callbackId dialogType:(NSString*)dialogType +{ + + NSUInteger count = [buttons count]; +#ifdef __IPHONE_8_0 + if (NSClassFromString(@"UIAlertController")) { + + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + + if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3) { + + CGRect alertFrame = [UIScreen mainScreen].applicationFrame; + + if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) { + // swap the values for the app frame since it is now in landscape + CGFloat temp = alertFrame.size.width; + alertFrame.size.width = alertFrame.size.height; + alertFrame.size.height = temp; + } + + alertController.view.frame = alertFrame; + } + + for (int n = 0; n < count; n++) { + + UIAlertAction* action = [UIAlertAction actionWithTitle:[buttons objectAtIndex:n] style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) + { + CDVPluginResult* result; + + if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) { + + NSString* value0 = [[alertController.textFields objectAtIndex:0] text]; + NSDictionary* info = @{ + @"buttonIndex":@(n + 1), + @"input1":(value0 ? value0 : [NSNull null]) + }; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info]; + + } else { + + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)(n + 1)]; + + } + + [self.commandDelegate sendPluginResult:result callbackId:callbackId]; + + }]; + [alertController addAction:action]; + + } + + if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) { + + [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { + textField.text = defaultText; + }]; + } + + + + [self.viewController presentViewController:alertController animated:YES completion:nil]; + + } else { +#endif + CDVAlertView* alertView = [[CDVAlertView alloc] + initWithTitle:title + message:message + delegate:self + cancelButtonTitle:nil + otherButtonTitles:nil]; + + alertView.callbackId = callbackId; + + + + for (int n = 0; n < count; n++) { + [alertView addButtonWithTitle:[buttons objectAtIndex:n]]; + } + + if ([dialogType isEqualToString:DIALOG_TYPE_PROMPT]) { + alertView.alertViewStyle = UIAlertViewStylePlainTextInput; + UITextField* textField = [alertView textFieldAtIndex:0]; + textField.text = defaultText; + } + + [alertView show]; +#ifdef __IPHONE_8_0 + } +#endif + +} + +- (void)alert:(CDVInvokedUrlCommand*)command +{ + NSString* callbackId = command.callbackId; + NSString* message = [command argumentAtIndex:0]; + NSString* title = [command argumentAtIndex:1]; + NSString* buttons = [command argumentAtIndex:2]; + + [self showDialogWithMessage:message title:title buttons:@[buttons] defaultText:nil callbackId:callbackId dialogType:DIALOG_TYPE_ALERT]; +} + +- (void)confirm:(CDVInvokedUrlCommand*)command +{ + NSString* callbackId = command.callbackId; + NSString* message = [command argumentAtIndex:0]; + NSString* title = [command argumentAtIndex:1]; + NSArray* buttons = [command argumentAtIndex:2]; + + [self showDialogWithMessage:message title:title buttons:buttons defaultText:nil callbackId:callbackId dialogType:DIALOG_TYPE_ALERT]; +} + +- (void)prompt:(CDVInvokedUrlCommand*)command +{ + NSString* callbackId = command.callbackId; + NSString* message = [command argumentAtIndex:0]; + NSString* title = [command argumentAtIndex:1]; + NSArray* buttons = [command argumentAtIndex:2]; + NSString* defaultText = [command argumentAtIndex:3]; + + [self showDialogWithMessage:message title:title buttons:buttons defaultText:defaultText callbackId:callbackId dialogType:DIALOG_TYPE_PROMPT]; +} + +/** + * Callback invoked when an alert dialog's buttons are clicked. + */ +- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + CDVAlertView* cdvAlertView = (CDVAlertView*)alertView; + CDVPluginResult* result; + + // Determine what gets returned to JS based on the alert view type. + if (alertView.alertViewStyle == UIAlertViewStyleDefault) { + // For alert and confirm, return button index as int back to JS. + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsInt:(int)(buttonIndex + 1)]; + } else { + // For prompt, return button index and input text back to JS. + NSString* value0 = [[alertView textFieldAtIndex:0] text]; + NSDictionary* info = @{ + @"buttonIndex":@(buttonIndex + 1), + @"input1":(value0 ? value0 : [NSNull null]) + }; + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:info]; + } + [self.commandDelegate sendPluginResult:result callbackId:cdvAlertView.callbackId]; +} + +static void playBeep(int count) { + SystemSoundID completeSound; + NSInteger cbDataCount = count; + NSURL* audioPath = [[NSBundle mainBundle] URLForResource:@"CDVNotification.bundle/beep" withExtension:@"wav"]; + #if __has_feature(objc_arc) + AudioServicesCreateSystemSoundID((__bridge CFURLRef)audioPath, &completeSound); + #else + AudioServicesCreateSystemSoundID((CFURLRef)audioPath, &completeSound); + #endif + AudioServicesAddSystemSoundCompletion(completeSound, NULL, NULL, soundCompletionCallback, (void*)(cbDataCount-1)); + AudioServicesPlaySystemSound(completeSound); +} + +static void soundCompletionCallback(SystemSoundID ssid, void* data) { + int count = (int)data; + AudioServicesRemoveSystemSoundCompletion (ssid); + AudioServicesDisposeSystemSoundID(ssid); + if (count > 0) { + playBeep(count); + } +} + +- (void)beep:(CDVInvokedUrlCommand*)command +{ + NSNumber* count = [command argumentAtIndex:0 withDefault:[NSNumber numberWithInt:1]]; + playBeep([count intValue]); +} + + +@end + +@implementation CDVAlertView + +@synthesize callbackId; + +@end diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.cpp b/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.cpp new file mode 100644 index 00000000..d0adf892 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.cpp @@ -0,0 +1,85 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "notification.h" + +#include <QApplication> + +void Dialogs::beep(int scId, int ecId, int times) { + Q_UNUSED(scId) + Q_UNUSED(ecId) + Q_UNUSED(times) + + _player.setVolume(100); + _player.setMedia(QUrl::fromLocalFile("/usr/share/sounds/ubuntu/stereo/bell.ogg")); + _player.play(); +} + +void Dialogs::alert(int scId, int ecId, const QString &message, const QString &title, const QString &buttonLabel) { + QStringList list; + list.append(buttonLabel); + + confirm(scId, ecId, message, title, list); +} + +void Dialogs::confirm(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels) { + Q_UNUSED(ecId); + + if (_alertCallback) { + qCritical() << "can't open second dialog"; + return; + } + _alertCallback = scId; + + QString s1, s2, s3; + if (buttonLabels.size() > 0) + s1 = buttonLabels[0]; + if (buttonLabels.size() > 1) + s2 = buttonLabels[1]; + if (buttonLabels.size() > 2) + s3 = buttonLabels[2]; + + QString path = m_cordova->get_app_dir() + "/../qml/notification.qml"; + QString qml = QString("PopupUtils.open(%1, root, { root: root, cordova: cordova, title: %2, text: %3, promptVisible: false, button1Text: %4, button2Text: %5, button3Text: %6 })") + .arg(CordovaInternal::format(path)).arg(CordovaInternal::format(title)).arg(CordovaInternal::format(message)) + .arg(CordovaInternal::format(s1)).arg(CordovaInternal::format(s2)).arg(CordovaInternal::format(s3)); + + m_cordova->execQML(qml); +} + +void Dialogs::prompt(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels, const QString &defaultText) { + Q_UNUSED(ecId); + + if (_alertCallback) { + qCritical() << "can't open second dialog"; + return; + } + _alertCallback = scId; + + QString s1, s2, s3; + if (buttonLabels.size() > 0) + s1 = buttonLabels[0]; + if (buttonLabels.size() > 1) + s2 = buttonLabels[1]; + if (buttonLabels.size() > 2) + s3 = buttonLabels[2]; + QString path = m_cordova->get_app_dir() + "/../qml/notification.qml"; + QString qml = QString("PopupUtils.open(%1, root, { root: root, cordova: cordova, title: %2, text: %3, promptVisible: true, defaultPromptText: %7, button1Text: %4, button2Text: %5, button3Text: %6 })") + .arg(CordovaInternal::format(path)).arg(CordovaInternal::format(title)).arg(CordovaInternal::format(message)) + .arg(CordovaInternal::format(s1)).arg(CordovaInternal::format(s2)) + .arg(CordovaInternal::format(s3)).arg(CordovaInternal::format(defaultText)); + + m_cordova->execQML(qml); +} diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.h b/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.h new file mode 100644 index 00000000..53430738 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.h @@ -0,0 +1,64 @@ +/* + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NOTIFICATION_H +#define NOTIFICATION_H + +#include <QtQuick> +#include <QMediaPlayer> +#include <cplugin.h> +#include <cordova.h> + +class Dialogs: public CPlugin { + Q_OBJECT +public: + explicit Dialogs(Cordova *cordova): CPlugin(cordova), _alertCallback(0) { + } + + virtual const QString fullName() override { + return Dialogs::fullID(); + } + + virtual const QString shortName() override { + return "Notification"; + } + + static const QString fullID() { + return "Notification"; + } +public slots: + void beep(int scId, int ecId, int times); + void alert(int scId, int ecId, const QString &message, const QString &title, const QString &buttonLabel); + void confirm(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels); + void prompt(int scId, int ecId, const QString &message, const QString &title, const QStringList &buttonLabels, const QString &defaultText); + + void notificationDialogButtonPressed(int buttonId, const QString &text, bool prompt) { + if (prompt) { + QVariantMap res; + res.insert("buttonIndex", buttonId); + res.insert("input1", text); + this->cb(_alertCallback, res); + } else { + this->cb(_alertCallback, buttonId); + } + _alertCallback = 0; + } + +private: + int _alertCallback; + QMediaPlayer _player; +}; + +#endif diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.qml b/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.qml new file mode 100644 index 00000000..5fdc7d31 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/ubuntu/notification.qml @@ -0,0 +1,65 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +import QtQuick 2.0 +import Ubuntu.Components.Popups 0.1 +import Ubuntu.Components 0.1 + +Dialog { + id: dialogue + property string button1Text + property string button2Text + property string button3Text + property bool promptVisible + property string defaultPromptText + + TextField { + id: prompt + text: defaultPromptText + visible: promptVisible + focus: true + } + Button { + text: button1Text + color: "orange" + onClicked: { + root.exec("Notification", "notificationDialogButtonPressed", [1, prompt.text, promptVisible]); + PopupUtils.close(dialogue) + } + } + Button { + text: button2Text + visible: button2Text.length > 0 + color: "orange" + onClicked: { + root.exec("Notification", "notificationDialogButtonPressed", [2, prompt.text, promptVisible]); + PopupUtils.close(dialogue) + } + } + Button { + text: button3Text + visible: button3Text.length > 0 + onClicked: { + root.exec("Notification", "notificationDialogButtonPressed", [3, prompt.text, promptVisible]); + PopupUtils.close(dialogue) + } + } +} diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/windows/NotificationProxy.js b/StoneIsland/plugins/cordova-plugin-dialogs/src/windows/NotificationProxy.js new file mode 100644 index 00000000..d1eb3448 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/windows/NotificationProxy.js @@ -0,0 +1,249 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * +*/ + +/*global Windows:true */ + +var cordova = require('cordova'); + +var isAlertShowing = false; +var alertStack = []; + +// CB-8928: When toStaticHTML is undefined, prompt fails to run +function _cleanHtml(html) { return html; } +if (typeof toStaticHTML !== 'undefined') { + _cleanHtml = toStaticHTML; +} + +// Windows does not provide native UI for promp dialog so we use some +// simple html-based implementation until it is available +function createPromptDialog(title, message, buttons, defaultText, callback) { + + var isPhone = cordova.platformId == "windows" && WinJS.Utilities.isPhone;; + + var dlgWrap = document.createElement("div"); + dlgWrap.style.position = "absolute"; + dlgWrap.style.width = "100%"; + dlgWrap.style.height = "100%"; + dlgWrap.style.backgroundColor = "rgba(0,0,0,0.25)"; + dlgWrap.style.zIndex = "100000"; + + var dlg = document.createElement("div"); + dlg.style.width = "100%"; + dlg.style.minHeight = "180px"; + dlg.style.height = "auto"; + dlg.style.overflow = "auto"; + dlg.style.backgroundColor = "white"; + dlg.style.position = "relative"; + dlg.style.lineHeight = "2"; + + if (isPhone) { + dlg.style.padding = "0px 5%"; + } else { + dlg.style.top = "50%"; // center vertically + dlg.style.transform = "translateY(-50%)"; + dlg.style.padding = "0px 30%"; + } + + // dialog layout template + dlg.innerHTML = _cleanHtml("<span id='lbl-title' style='font-size: 24pt'></span><br/>" // title + + "<span id='lbl-message'></span><br/>" // message + + "<input id='prompt-input' style='width: 100%'/><br/>"); // input fields + + dlg.querySelector('#lbl-title').appendChild(document.createTextNode(title)); + dlg.querySelector('#lbl-message').appendChild(document.createTextNode(message)); + dlg.querySelector('#prompt-input').setAttribute('placeholder', defaultText); + + function makeButtonCallback(idx) { + return function () { + var value = promptInput = dlg.querySelector('#prompt-input').value; + dlgWrap.parentNode.removeChild(dlgWrap); + + if (callback) { + callback({ input1: value, buttonIndex: idx }); + } + } + } + + function addButton(idx, label) { + var button = document.createElement('button'); + button.style.margin = "8px 0 8px 16px"; + button.style.float = "right"; + button.style.fontSize = "12pt"; + button.tabIndex = idx; + button.onclick = makeButtonCallback(idx + 1); + if (idx == 0) { + button.style.color = "white"; + button.style.backgroundColor = "#464646"; + } else { + button.style.backgroundColor = "#cccccc"; + } + button.style.border = "none"; + button.appendChild(document.createTextNode(label)); + dlg.appendChild(button); + } + + // reverse order is used since we align buttons to the right + for (var idx = buttons.length - 1; idx >= 0; idx--) { + addButton(idx, buttons[idx]); + } + + dlgWrap.appendChild(dlg); + document.body.appendChild(dlgWrap); + + // make sure input field is under focus + dlg.querySelector('#prompt-input').focus(); + + return dlgWrap; +} + +module.exports = { + alert:function(win, loseX, args) { + + if (isAlertShowing) { + var later = function () { + module.exports.alert(win, loseX, args); + }; + alertStack.push(later); + return; + } + isAlertShowing = true; + + var message = args[0]; + var _title = args[1]; + var _buttonLabel = args[2]; + + var md = new Windows.UI.Popups.MessageDialog(message, _title); + md.commands.append(new Windows.UI.Popups.UICommand(_buttonLabel)); + md.showAsync().then(function() { + isAlertShowing = false; + win && win(); + + if (alertStack.length) { + setTimeout(alertStack.shift(), 0); + } + + }); + }, + + prompt: function (win, lose, args) { + if (isAlertShowing) { + var later = function () { + module.exports.prompt(win, lose, args); + }; + alertStack.push(later); + return; + } + + isAlertShowing = true; + + var message = args[0], + title = args[1], + buttons = args[2], + defaultText = args[3]; + + try { + createPromptDialog(title, message, buttons, defaultText, function (evt) { + isAlertShowing = false; + if (win) { + win(evt); + } + }); + + } catch (e) { + // set isAlertShowing flag back to false in case of exception + isAlertShowing = false; + if (alertStack.length) { + setTimeout(alertStack.shift(), 0); + } + // rethrow exception + throw e; + } + }, + + confirm:function(win, loseX, args) { + + if (isAlertShowing) { + var later = function () { + module.exports.confirm(win, loseX, args); + }; + alertStack.push(later); + return; + } + + isAlertShowing = true; + + try { + var message = args[0]; + var _title = args[1]; + var buttons = args[2]; + + var md = new Windows.UI.Popups.MessageDialog(message, _title); + + buttons.forEach(function(buttonLabel) { + md.commands.append(new Windows.UI.Popups.UICommand(buttonLabel)); + }); + + md.showAsync().then(function(res) { + isAlertShowing = false; + var result = res ? buttons.indexOf(res.label) + 1 : 0; + win && win(result); + if (alertStack.length) { + setTimeout(alertStack.shift(), 0); + } + + }); + } catch (e) { + // set isAlertShowing flag back to false in case of exception + isAlertShowing = false; + if (alertStack.length) { + setTimeout(alertStack.shift(), 0); + } + // rethrow exception + throw e; + } + }, + + beep:function(winX, loseX, args) { + + // set a default args if it is not set + args = args && args.length ? args : ["1"]; + + var snd = new Audio('ms-winsoundevent:Notification.Default'); + var count = parseInt(args[0]) || 1; + snd.msAudioCategory = "Alerts"; + + var onEvent = function () { + if (count > 0) { + snd.play(); + } else { + snd.removeEventListener("ended", onEvent); + snd = null; + winX && winX(); // notification.js just sends null, but this is future friendly + } + count--; + }; + snd.addEventListener("ended", onEvent); + onEvent(); + + } +}; + +require("cordova/exec/proxy").add("Notification",module.exports); diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/Notification.cs b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/Notification.cs new file mode 100644 index 00000000..b6216848 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/Notification.cs @@ -0,0 +1,482 @@ +/* + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using System; +using System.Windows; +using System.Windows.Controls; +using Microsoft.Devices; +using System.Runtime.Serialization; +using System.Threading; +using System.Windows.Resources; +using Microsoft.Phone.Controls; +using Microsoft.Xna.Framework.Audio; +using WPCordovaClassLib.Cordova.UI; +using System.Diagnostics; + + +namespace WPCordovaClassLib.Cordova.Commands +{ + public class Notification : BaseCommand + { + static ProgressBar progressBar = null; + const int DEFAULT_DURATION = 5; + + private NotificationBox notifyBox; + + private class NotifBoxData + { + public NotificationBox previous {get;set;} + public string callbackId { get; set; } + } + + private PhoneApplicationPage Page + { + get + { + PhoneApplicationPage page = null; + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + page = frame.Content as PhoneApplicationPage; + } + return page; + } + } + + // blink api - doesn't look like there is an equivalent api we can use... + + [DataContract] + public class AlertOptions + { + [OnDeserializing] + public void OnDeserializing(StreamingContext context) + { + // set defaults + this.message = "message"; + this.title = "Alert"; + this.buttonLabel = "ok"; + } + + /// <summary> + /// message to display in the alert box + /// </summary> + [DataMember] + public string message; + + /// <summary> + /// title displayed on the alert window + /// </summary> + [DataMember] + public string title; + + /// <summary> + /// text to display on the button + /// </summary> + [DataMember] + public string buttonLabel; + } + + [DataContract] + public class PromptResult + { + [DataMember] + public int buttonIndex; + + [DataMember] + public string input1; + + public PromptResult(int index, string text) + { + this.buttonIndex = index; + this.input1 = text; + } + } + + public void alert(string options) + { + string[] args = JSON.JsonHelper.Deserialize<string[]>(options); + AlertOptions alertOpts = new AlertOptions(); + alertOpts.message = args[0]; + alertOpts.title = args[1]; + alertOpts.buttonLabel = args[2]; + string aliasCurrentCommandCallbackId = args[3]; + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + PhoneApplicationPage page = Page; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + var previous = notifyBox; + notifyBox = new NotificationBox(); + notifyBox.Tag = new NotifBoxData { previous = previous, callbackId = aliasCurrentCommandCallbackId }; + notifyBox.PageTitle.Text = alertOpts.title; + notifyBox.SubTitle.Text = alertOpts.message; + Button btnOK = new Button(); + btnOK.Content = alertOpts.buttonLabel; + btnOK.Click += new RoutedEventHandler(btnOK_Click); + btnOK.Tag = 1; + notifyBox.ButtonPanel.Children.Add(btnOK); + grid.Children.Add(notifyBox); + + if (previous == null) + { + page.BackKeyPress += page_BackKeyPress; + } + } + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION)); + } + }); + } + + public void prompt(string options) + { + string[] args = JSON.JsonHelper.Deserialize<string[]>(options); + string message = args[0]; + string title = args[1]; + string buttonLabelsArray = args[2]; + string[] buttonLabels = JSON.JsonHelper.Deserialize<string[]>(buttonLabelsArray); + string defaultText = args[3]; + string aliasCurrentCommandCallbackId = args[4]; + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + PhoneApplicationPage page = Page; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + var previous = notifyBox; + notifyBox = new NotificationBox(); + notifyBox.Tag = new NotifBoxData { previous = previous, callbackId = aliasCurrentCommandCallbackId }; + notifyBox.PageTitle.Text = title; + notifyBox.SubTitle.Text = message; + + //TextBox textBox = new TextBox(); + //textBox.Text = defaultText; + //textBox.AcceptsReturn = true; + //notifyBox.ContentScroller.Content = textBox; + + notifyBox.InputText.Text = defaultText; + notifyBox.InputText.Visibility = Visibility.Visible; + + for (int i = 0; i < buttonLabels.Length; ++i) + { + Button button = new Button(); + button.Content = buttonLabels[i]; + button.Tag = i + 1; + button.Click += promptBoxbutton_Click; + notifyBox.ButtonPanel.Orientation = Orientation.Vertical; + notifyBox.ButtonPanel.Children.Add(button); + } + + grid.Children.Add(notifyBox); + if (previous != null) + { + page.BackKeyPress += page_BackKeyPress; + } + } + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION)); + } + }); + } + + public void confirm(string options) + { + string[] args = JSON.JsonHelper.Deserialize<string[]>(options); + AlertOptions alertOpts = new AlertOptions(); + alertOpts.message = args[0]; + alertOpts.title = args[1]; + alertOpts.buttonLabel = args[2]; + string aliasCurrentCommandCallbackId = args[3]; + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + PhoneApplicationPage page = Page; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + var previous = notifyBox; + notifyBox = new NotificationBox(); + notifyBox.Tag = new NotifBoxData { previous = previous, callbackId = aliasCurrentCommandCallbackId }; + notifyBox.PageTitle.Text = alertOpts.title; + notifyBox.SubTitle.Text = alertOpts.message; + + string[] labels = JSON.JsonHelper.Deserialize<string[]>(alertOpts.buttonLabel); + + if (labels == null) + { + labels = alertOpts.buttonLabel.Split(','); + } + + for (int n = 0; n < labels.Length; n++) + { + Button btn = new Button(); + btn.Content = labels[n]; + btn.Tag = n; + btn.Click += new RoutedEventHandler(btnOK_Click); + notifyBox.ButtonPanel.Children.Add(btn); + } + + grid.Children.Add(notifyBox); + if (previous == null) + { + page.BackKeyPress += page_BackKeyPress; + } + } + } + else + { + DispatchCommandResult(new PluginResult(PluginResult.Status.INSTANTIATION_EXCEPTION)); + } + }); + } + + void promptBoxbutton_Click(object sender, RoutedEventArgs e) + { + Button button = sender as Button; + FrameworkElement promptBox = null; + int buttonIndex = 0; + string callbackId = string.Empty; + string text = string.Empty; + if (button != null) + { + buttonIndex = (int)button.Tag; + promptBox = button.Parent as FrameworkElement; + while ((promptBox = promptBox.Parent as FrameworkElement) != null && + !(promptBox is NotificationBox)) ; + } + + if (promptBox != null) + { + NotificationBox box = promptBox as NotificationBox; + + text = box.InputText.Text; + + PhoneApplicationPage page = Page; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + grid.Children.Remove(promptBox); + } + + NotifBoxData data = promptBox.Tag as NotifBoxData; + promptBox = data.previous as NotificationBox; + callbackId = data.callbackId as string; + + if (promptBox == null) + { + page.BackKeyPress -= page_BackKeyPress; + } + } + } + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, new PromptResult(buttonIndex, text)), callbackId); + } + + void page_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e) + { + PhoneApplicationPage page = sender as PhoneApplicationPage; + string callbackId = ""; + if (page != null && notifyBox != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + grid.Children.Remove(notifyBox); + NotifBoxData notifBoxData = notifyBox.Tag as NotifBoxData; + notifyBox = notifBoxData.previous as NotificationBox; + callbackId = notifBoxData.callbackId as string; + } + if (notifyBox == null) + { + page.BackKeyPress -= page_BackKeyPress; + } + e.Cancel = true; + } + + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, 0), callbackId); + } + + void btnOK_Click(object sender, RoutedEventArgs e) + { + Button btn = sender as Button; + FrameworkElement notifBoxParent = null; + int retVal = 0; + string callbackId = ""; + if (btn != null) + { + retVal = (int)btn.Tag + 1; + + notifBoxParent = btn.Parent as FrameworkElement; + while ((notifBoxParent = notifBoxParent.Parent as FrameworkElement) != null && + !(notifBoxParent is NotificationBox)) ; + } + if (notifBoxParent != null) + { + PhoneApplicationPage page = Page; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + grid.Children.Remove(notifBoxParent); + } + + NotifBoxData notifBoxData = notifBoxParent.Tag as NotifBoxData; + notifyBox = notifBoxData.previous as NotificationBox; + callbackId = notifBoxData.callbackId as string; + + if (notifyBox == null) + { + page.BackKeyPress -= page_BackKeyPress; + } + } + + } + DispatchCommandResult(new PluginResult(PluginResult.Status.OK, retVal), callbackId); + } + + + + public void beep(string options) + { + string[] args = JSON.JsonHelper.Deserialize<string[]>(options); + int times = int.Parse(args[0]); + + string resourcePath = BaseCommand.GetBaseURL() + "Plugins/cordova-plugin-dialogs/notification-beep.wav"; + + StreamResourceInfo sri = Application.GetResourceStream(new Uri(resourcePath, UriKind.Relative)); + + if (sri != null) + { + SoundEffect effect = SoundEffect.FromStream(sri.Stream); + SoundEffectInstance inst = effect.CreateInstance(); + ThreadPool.QueueUserWorkItem((o) => + { + // cannot interact with UI !! + do + { + inst.Play(); + Thread.Sleep(effect.Duration + TimeSpan.FromMilliseconds(100)); + } + while (--times > 0); + + }); + + } + + // TODO: may need a listener to trigger DispatchCommandResult after the alarm has finished executing... + DispatchCommandResult(); + } + + // Display an indeterminate progress indicator + public void activityStart(string unused) + { + + Deployment.Current.Dispatcher.BeginInvoke(() => + { + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + + if (page != null) + { + var temp = page.FindName("LayoutRoot"); + Grid grid = temp as Grid; + if (grid != null) + { + if (progressBar != null) + { + grid.Children.Remove(progressBar); + } + progressBar = new ProgressBar(); + progressBar.IsIndeterminate = true; + progressBar.IsEnabled = true; + + grid.Children.Add(progressBar); + } + } + } + }); + } + + + // Remove our indeterminate progress indicator + public void activityStop(string unused) + { + Deployment.Current.Dispatcher.BeginInvoke(() => + { + if (progressBar != null) + { + progressBar.IsEnabled = false; + PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame; + if (frame != null) + { + PhoneApplicationPage page = frame.Content as PhoneApplicationPage; + if (page != null) + { + Grid grid = page.FindName("LayoutRoot") as Grid; + if (grid != null) + { + grid.Children.Remove(progressBar); + } + } + } + progressBar = null; + } + }); + } + + public void vibrate(string vibrateDuration) + { + + int msecs = 200; // set default + + try + { + string[] args = JSON.JsonHelper.Deserialize<string[]>(vibrateDuration); + + msecs = int.Parse(args[0]); + if (msecs < 1) + { + msecs = 1; + } + } + catch (FormatException) + { + + } + + VibrateController.Default.Start(TimeSpan.FromMilliseconds(msecs)); + + // TODO: may need to add listener to trigger DispatchCommandResult when the vibration ends... + DispatchCommandResult(); + } + } +} diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/NotificationBox.xaml b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/NotificationBox.xaml new file mode 100644 index 00000000..2d564fba --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/NotificationBox.xaml @@ -0,0 +1,79 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +--> +<UserControl x:Class="WPCordovaClassLib.Cordova.UI.NotificationBox" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + mc:Ignorable="d" + FontFamily="{StaticResource PhoneFontFamilyNormal}" + FontSize="{StaticResource PhoneFontSizeNormal}" + Foreground="{StaticResource PhoneForegroundBrush}" + d:DesignHeight="800" d:DesignWidth="480" VerticalAlignment="Stretch"> + + <!--TitlePanel contains the name of the application and page title--> + <Grid x:Name="LayoutRoot" + Background="{StaticResource PhoneSemitransparentBrush}"> + <Grid.RowDefinitions> + <RowDefinition Height="*"></RowDefinition> + </Grid.RowDefinitions> + + <Grid x:Name="TitlePanel" + Grid.Row="0" + VerticalAlignment="Top" + Background="{StaticResource PhoneSemitransparentBrush}"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"></RowDefinition> + <RowDefinition Height="*"></RowDefinition> + <RowDefinition Height="Auto"></RowDefinition> + </Grid.RowDefinitions> + + <TextBlock x:Name="PageTitle" + Text="Title" + Margin="10,10" + Grid.Row="0" + Style="{StaticResource PhoneTextTitle2Style}"/> + + <ScrollViewer x:Name="ContentScroller" + Grid.Row="1" + MinHeight="120" + Margin="10,10"> + <StackPanel Orientation="Vertical"> + <TextBlock x:Name="SubTitle" + Text="Subtitle" + Width="Auto" + TextWrapping="Wrap" + Style="{StaticResource PhoneTextTitle3Style}"/> + <TextBox x:Name="InputText" + Visibility="Collapsed"/> + </StackPanel> + </ScrollViewer> + + <ScrollViewer HorizontalScrollBarVisibility="Auto" + Grid.Row="2" + VerticalScrollBarVisibility="Disabled"> + <StackPanel x:Name="ButtonPanel" + Margin="10,10" + Orientation="Horizontal"/> + </ScrollViewer> + + </Grid> + </Grid> + +</UserControl> diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/NotificationBox.xaml.cs b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/NotificationBox.xaml.cs new file mode 100644 index 00000000..50b2f2a8 --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/NotificationBox.xaml.cs @@ -0,0 +1,41 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Shapes; + +namespace WPCordovaClassLib.Cordova.UI +{ + public partial class NotificationBox : UserControl + { + public NotificationBox() + { + InitializeComponent(); + } + } +} diff --git a/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/notification-beep.wav b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/notification-beep.wav Binary files differnew file mode 100644 index 00000000..d0ad085f --- /dev/null +++ b/StoneIsland/plugins/cordova-plugin-dialogs/src/wp/notification-beep.wav |
