From 66482cd9e20460878e20a002778e7a0aa0d95682 Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Wed, 13 Aug 2014 10:18:36 -0300 Subject: [PATCH 1/3] Add clipboard plugin --- mobile/cordova_plugins.js | 10 ++- .../www/clipboard.js | 36 +++++++++++ mobile/res/xml/config.xml | 3 + .../verso/cordova/clipboard/Clipboard.java | 62 +++++++++++++++++++ 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 mobile/plugins/com.verso.cordova.clipboard/www/clipboard.js create mode 100644 mobile/src/com/verso/cordova/clipboard/Clipboard.java diff --git a/mobile/cordova_plugins.js b/mobile/cordova_plugins.js index 695e5081b..aab670afa 100644 --- a/mobile/cordova_plugins.js +++ b/mobile/cordova_plugins.js @@ -20,6 +20,13 @@ module.exports = [ "clobbers": [ "navigator.splashscreen" ] + }, + { + "file": "plugins/com.verso.cordova.clipboard/www/clipboard.js", + "id": "com.verso.cordova.clipboard.Clipboard", + "clobbers": [ + "cordova.plugins.clipboard" + ] } ]; module.exports.metadata = @@ -27,7 +34,8 @@ module.exports.metadata = { "de.appplant.cordova.plugin.email-composer": "0.8.2dev", "com.phonegap.plugins.barcodescanner": "1.0.1", - "org.apache.cordova.splashscreen": "0.3.0" + "org.apache.cordova.splashscreen": "0.3.0", + "com.verso.cordova.clipboard": "0.1.0" } // BOTTOM OF METADATA }); \ No newline at end of file diff --git a/mobile/plugins/com.verso.cordova.clipboard/www/clipboard.js b/mobile/plugins/com.verso.cordova.clipboard/www/clipboard.js new file mode 100644 index 000000000..129c11130 --- /dev/null +++ b/mobile/plugins/com.verso.cordova.clipboard/www/clipboard.js @@ -0,0 +1,36 @@ +cordova.define("com.verso.cordova.clipboard.Clipboard", function(require, exports, module) { var cordova = require('cordova'); + +/** + * Clipboard plugin for Cordova + * + * @constructor + */ +function Clipboard () {} + +/** + * Sets the clipboard content + * + * @param {String} text The content to copy to the clipboard + * @param {Function} onSuccess The function to call in case of success (takes the copied text as argument) + * @param {Function} onFail The function to call in case of error + */ +Clipboard.prototype.copy = function (text, onSuccess, onFail) { + if (typeof text === "undefined" || text === null) text = ""; + cordova.exec(onSuccess, onFail, "Clipboard", "copy", [text]); +}; + +/** + * Gets the clipboard content + * + * @param {Function} onSuccess The function to call in case of success + * @param {Function} onFail The function to call in case of error + */ +Clipboard.prototype.paste = function (onSuccess, onFail) { + cordova.exec(onSuccess, onFail, "Clipboard", "paste", []); +}; + +// Register the plugin +var clipboard = new Clipboard(); +module.exports = clipboard; + +}); diff --git a/mobile/res/xml/config.xml b/mobile/res/xml/config.xml index 86c57a5ca..871fce104 100644 --- a/mobile/res/xml/config.xml +++ b/mobile/res/xml/config.xml @@ -28,4 +28,7 @@ + + + diff --git a/mobile/src/com/verso/cordova/clipboard/Clipboard.java b/mobile/src/com/verso/cordova/clipboard/Clipboard.java new file mode 100644 index 000000000..438ebc1ea --- /dev/null +++ b/mobile/src/com/verso/cordova/clipboard/Clipboard.java @@ -0,0 +1,62 @@ +package com.verso.cordova.clipboard; + +import org.apache.cordova.CordovaPlugin; +import org.apache.cordova.PluginResult; +import org.apache.cordova.CallbackContext; + +import org.json.JSONArray; +import org.json.JSONException; + +import android.content.Context; +import android.content.ClipboardManager; +import android.content.ClipData; +import android.content.ClipDescription; + +public class Clipboard extends CordovaPlugin { + + private static final String actionCopy = "copy"; + private static final String actionPaste = "paste"; + + @Override + public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { + ClipboardManager clipboard = (ClipboardManager) cordova.getActivity().getSystemService(Context.CLIPBOARD_SERVICE); + + if (action.equals(actionCopy)) { + try { + String text = args.getString(0); + ClipData clip = ClipData.newPlainText("Text", text); + + clipboard.setPrimaryClip(clip); + + callbackContext.success(text); + + return true; + } catch (JSONException e) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION)); + } catch (Exception e) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.toString())); + } + } else if (action.equals(actionPaste)) { + if (!clipboard.getPrimaryClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.NO_RESULT)); + } + + try { + ClipData.Item item = clipboard.getPrimaryClip().getItemAt(0); + String text = item.getText().toString(); + + if (text == null) text = ""; + + callbackContext.success(text); + + return true; + } catch (Exception e) { + callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, e.toString())); + } + } + + return false; + } +} + + From 7d27ff70cb64abcc28a32be948de71849b7d6e3d Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Wed, 13 Aug 2014 13:33:56 -0300 Subject: [PATCH 2/3] Add toast plugin --- mobile/cordova_plugins.js | 14 ++++- .../nl.x-services.plugins.toast/test/tests.js | 59 +++++++++++++++++++ .../nl.x-services.plugins.toast/www/Toast.js | 42 +++++++++++++ mobile/res/xml/config.xml | 3 + mobile/src/nl/xservices/plugins/Toast.java | 56 ++++++++++++++++++ 5 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 mobile/plugins/nl.x-services.plugins.toast/test/tests.js create mode 100644 mobile/plugins/nl.x-services.plugins.toast/www/Toast.js create mode 100644 mobile/src/nl/xservices/plugins/Toast.java diff --git a/mobile/cordova_plugins.js b/mobile/cordova_plugins.js index aab670afa..887842e5e 100644 --- a/mobile/cordova_plugins.js +++ b/mobile/cordova_plugins.js @@ -27,6 +27,17 @@ module.exports = [ "clobbers": [ "cordova.plugins.clipboard" ] + }, + { + "file": "plugins/nl.x-services.plugins.toast/www/Toast.js", + "id": "nl.x-services.plugins.toast.Toast", + "clobbers": [ + "window.plugins.toast" + ] + }, + { + "file": "plugins/nl.x-services.plugins.toast/test/tests.js", + "id": "nl.x-services.plugins.toast.tests" } ]; module.exports.metadata = @@ -35,7 +46,8 @@ module.exports.metadata = "de.appplant.cordova.plugin.email-composer": "0.8.2dev", "com.phonegap.plugins.barcodescanner": "1.0.1", "org.apache.cordova.splashscreen": "0.3.0", - "com.verso.cordova.clipboard": "0.1.0" + "com.verso.cordova.clipboard": "0.1.0", + "nl.x-services.plugins.toast": "2.0" } // BOTTOM OF METADATA }); \ No newline at end of file diff --git a/mobile/plugins/nl.x-services.plugins.toast/test/tests.js b/mobile/plugins/nl.x-services.plugins.toast/test/tests.js new file mode 100644 index 000000000..1d079d4d8 --- /dev/null +++ b/mobile/plugins/nl.x-services.plugins.toast/test/tests.js @@ -0,0 +1,59 @@ +cordova.define("nl.x-services.plugins.toast.tests", function(require, exports, module) { exports.defineAutoTests = function() { + + var fail = function (done) { + expect(true).toBe(false); + done(); + }, + succeed = function (done) { + expect(true).toBe(true); + done(); + }; + + describe('Plugin availability', function () { + it("window.plugins.toast should exist", function() { + expect(window.plugins.toast).toBeDefined(); + }); + }); + + describe('API functions', function () { + it("should define show", function() { + expect(window.plugins.toast.show).toBeDefined(); + }); + + it("should define showShortTop", function() { + expect(window.plugins.toast.showShortTop).toBeDefined(); + }); + + it("should define showShortCenter", function() { + expect(window.plugins.toast.showShortCenter).toBeDefined(); + }); + + it("should define showShortBottom", function() { + expect(window.plugins.toast.showShortBottom).toBeDefined(); + }); + + it("should define showLongTop", function() { + expect(window.plugins.toast.showLongTop).toBeDefined(); + }); + + it("should define showLongCenter", function() { + expect(window.plugins.toast.showLongCenter).toBeDefined(); + }); + + it("should define showLongBottom", function() { + expect(window.plugins.toast.showLongBottom).toBeDefined(); + }); + }); + + describe('Invalid usage', function () { + it("should fail due to an invalid position", function(done) { + window.plugins.toast.show('hi', 'short', 'nowhere', fail.bind(null, done), succeed.bind(null, done)); + }); + + it("should fail due to an invalid duration", function(done) { + window.plugins.toast.show('hi', 'medium', 'top', fail.bind(null, done), succeed.bind(null, done)); + }); + }); +}; + +}); diff --git a/mobile/plugins/nl.x-services.plugins.toast/www/Toast.js b/mobile/plugins/nl.x-services.plugins.toast/www/Toast.js new file mode 100644 index 000000000..cad6dab44 --- /dev/null +++ b/mobile/plugins/nl.x-services.plugins.toast/www/Toast.js @@ -0,0 +1,42 @@ +cordova.define("nl.x-services.plugins.toast.Toast", function(require, exports, module) { function Toast() { +} + +Toast.prototype.show = function (message, duration, position, successCallback, errorCallback) { + cordova.exec(successCallback, errorCallback, "Toast", "show", [message, duration, position]); +}; + +Toast.prototype.showShortTop = function (message, successCallback, errorCallback) { + this.show(message, "short", "top", successCallback, errorCallback); +}; + +Toast.prototype.showShortCenter = function (message, successCallback, errorCallback) { + this.show(message, "short", "center", successCallback, errorCallback); +}; + +Toast.prototype.showShortBottom = function (message, successCallback, errorCallback) { + this.show(message, "short", "bottom", successCallback, errorCallback); +}; + +Toast.prototype.showLongTop = function (message, successCallback, errorCallback) { + this.show(message, "long", "top", successCallback, errorCallback); +}; + +Toast.prototype.showLongCenter = function (message, successCallback, errorCallback) { + this.show(message, "long", "center", successCallback, errorCallback); +}; + +Toast.prototype.showLongBottom = function (message, successCallback, errorCallback) { + this.show(message, "long", "bottom", successCallback, errorCallback); +}; + +Toast.install = function () { + if (!window.plugins) { + window.plugins = {}; + } + + window.plugins.toast = new Toast(); + return window.plugins.toast; +}; + +cordova.addConstructor(Toast.install); +}); diff --git a/mobile/res/xml/config.xml b/mobile/res/xml/config.xml index 871fce104..dfd9181ad 100644 --- a/mobile/res/xml/config.xml +++ b/mobile/res/xml/config.xml @@ -31,4 +31,7 @@ + + + diff --git a/mobile/src/nl/xservices/plugins/Toast.java b/mobile/src/nl/xservices/plugins/Toast.java new file mode 100644 index 000000000..6d44a77e4 --- /dev/null +++ b/mobile/src/nl/xservices/plugins/Toast.java @@ -0,0 +1,56 @@ +package nl.xservices.plugins; + +import android.view.Gravity; +import org.apache.cordova.CallbackContext; +import org.apache.cordova.CordovaPlugin; +import org.json.JSONArray; +import org.json.JSONException; + +public class Toast extends CordovaPlugin { + + private static final String ACTION_SHOW_EVENT = "show"; + + @Override + public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException { + if (ACTION_SHOW_EVENT.equals(action)) { + + final String message = args.getString(0); + final String duration = args.getString(1); + final String position = args.getString(2); + + cordova.getActivity().runOnUiThread(new Runnable() { + public void run() { + android.widget.Toast toast = android.widget.Toast.makeText(webView.getContext(), message, 0); + + if ("top".equals(position)) { + toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL, 0, 20); + } else if ("bottom".equals(position)) { + toast.setGravity(Gravity.BOTTOM|Gravity.CENTER_HORIZONTAL, 0, 20); + } else if ("center".equals(position)) { + toast.setGravity(Gravity.CENTER_VERTICAL|Gravity.CENTER_HORIZONTAL, 0, 0); + } else { + callbackContext.error("invalid position. valid options are 'top', 'center' and 'bottom'"); + return; + } + + if ("short".equals(duration)) { + toast.setDuration(android.widget.Toast.LENGTH_SHORT); + } else if ("long".equals(duration)) { + toast.setDuration(android.widget.Toast.LENGTH_LONG); + } else { + callbackContext.error("invalid duration. valid options are 'short' and 'long'"); + return; + } + + toast.show(); + callbackContext.success(); + } + }); + + return true; + } else { + callbackContext.error("toast." + action + " is not a supported function. Did you mean '" + ACTION_SHOW_EVENT + "'?"); + return false; + } + } +} From b60e8ed40753ba191ea9d9521e824a8dc168021c Mon Sep 17 00:00:00 2001 From: Yemel Jardi Date: Wed, 13 Aug 2014 13:34:47 -0300 Subject: [PATCH 3/3] Add copy to clipboard button --- js/controllers/addresses.js | 6 ++++++ views/modals/qr-address.html | 3 +++ 2 files changed, 9 insertions(+) diff --git a/js/controllers/addresses.js b/js/controllers/addresses.js index c81a10fc3..cef87776f 100644 --- a/js/controllers/addresses.js +++ b/js/controllers/addresses.js @@ -19,6 +19,12 @@ angular.module('copayApp.controllers').controller('AddressesController', $scope.openAddressModal = function(address) { var ModalInstanceCtrl = function ($scope, $modalInstance, address) { $scope.address = address; + $scope.isMobile = !!window.cordova; + + $scope.mobileCopy = function(address) { + window.cordova.plugins.clipboard.copy(address); + window.plugins.toast.showShortBottom('Copied to clipboard'); + } $scope.cancel = function () { $modalInstance.dismiss('cancel'); diff --git a/views/modals/qr-address.html b/views/modals/qr-address.html index b1768df8d..7fb9a63ed 100644 --- a/views/modals/qr-address.html +++ b/views/modals/qr-address.html @@ -11,6 +11,9 @@



+