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 @@
+