From 642b7d7e6e1bbee74d2ede30b7c4f7edef018035 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Fri, 28 Aug 2020 15:55:28 -0400 Subject: [PATCH 01/11] fix(package): Update dependencies to fix vulnerabilities --- package-lock.json | 445 ++++++++++++++++++++++++---------------------- 1 file changed, 231 insertions(+), 214 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f05c5d..bf276bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -648,13 +648,13 @@ "optional": true }, "compare-func": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz", - "integrity": "sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", "dev": true, "requires": { "array-ify": "^1.0.0", - "dot-prop": "^3.0.0" + "dot-prop": "^5.1.0" } }, "compare-versions": { @@ -670,22 +670,49 @@ "dev": true }, "conventional-changelog-angular": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz", - "integrity": "sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA==", + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.11.tgz", + "integrity": "sha512-nSLypht/1yEflhuTogC03i7DX7sOrXGsRn14g131Potqi6cbGbGEE9PSDEHKldabB6N76HiSyw9Ph+kLmC04Qw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "q": "^1.5.1" + }, + "dependencies": { + "compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "requires": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + } } }, "conventional-changelog-writer": { - "version": "4.0.16", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz", - "integrity": "sha512-jmU1sDJDZpm/dkuFxBeRXvyNcJQeKhGtVcFFkwTphUAzyYWcwz2j36Wcv+Mv2hU3tpvLMkysOPXJTLO55AUrYQ==", + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.17.tgz", + "integrity": "sha512-IKQuK3bib/n032KWaSb8YlBFds+aLmzENtnKtxJy3+HqDq5kohu3g/UdNbIHeJWygfnEbZjnCKFxAW0y7ArZAw==", "dev": true, "requires": { - "compare-func": "^1.3.1", + "compare-func": "^2.0.0", "conventional-commits-filter": "^2.0.6", "dateformat": "^3.0.0", "handlebars": "^4.7.6", @@ -837,12 +864,12 @@ } }, "dot-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", - "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", "dev": true, "requires": { - "is-obj": "^1.0.0" + "is-obj": "^2.0.0" } }, "duplexer2": { @@ -1417,9 +1444,9 @@ "dev": true }, "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, "is-plain-obj": { @@ -1491,6 +1518,14 @@ "requires": { "chevrotain": "6.5.0", "lodash": "4.17.15" + }, + "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + } } }, "java-properties": { @@ -1578,9 +1613,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", "dev": true }, "lodash.capitalize": { @@ -1916,9 +1951,9 @@ "dev": true }, "npm": { - "version": "6.14.5", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.5.tgz", - "integrity": "sha512-CDwa3FJd0XJpKDbWCST484H+mCNjF26dPrU+xnREW+upR0UODjMEfXPl3bxWuAwZIX6c2ASg1plLO7jP8ehWeA==", + "version": "6.14.8", + "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.8.tgz", + "integrity": "sha512-HBZVBMYs5blsj94GTeQZel7s9odVuuSUHy1+AlZh7rPVux1os2ashvEGLy/STNK7vUjbrCg5Kq9/GXisJgdf6A==", "dev": true, "requires": { "JSONStream": "^1.3.5", @@ -1927,7 +1962,7 @@ "ansistyles": "~0.1.3", "aproba": "^2.0.0", "archy": "~1.0.0", - "bin-links": "^1.1.7", + "bin-links": "^1.1.8", "bluebird": "^3.5.5", "byte-size": "^5.0.1", "cacache": "^12.0.3", @@ -1948,7 +1983,7 @@ "find-npm-prefix": "^1.0.2", "fs-vacuum": "~1.2.10", "fs-write-stream-atomic": "~1.0.10", - "gentle-fs": "^2.3.0", + "gentle-fs": "^2.3.1", "glob": "^7.1.6", "graceful-fs": "^4.2.4", "has-unicode": "~2.0.1", @@ -1963,14 +1998,14 @@ "is-cidr": "^3.0.0", "json-parse-better-errors": "^1.0.2", "lazy-property": "~1.0.0", - "libcipm": "^4.0.7", + "libcipm": "^4.0.8", "libnpm": "^3.0.1", "libnpmaccess": "^3.0.2", "libnpmhook": "^5.0.3", "libnpmorg": "^1.0.1", "libnpmsearch": "^2.0.2", "libnpmteam": "^1.0.2", - "libnpx": "^10.2.2", + "libnpx": "^10.2.4", "lock-verify": "^2.1.0", "lockfile": "^1.0.4", "lodash._baseindexof": "*", @@ -1985,22 +2020,22 @@ "lodash.uniq": "~4.5.0", "lodash.without": "~4.4.0", "lru-cache": "^5.1.1", - "meant": "~1.0.1", + "meant": "^1.0.2", "mississippi": "^3.0.0", "mkdirp": "^0.5.5", "move-concurrently": "^1.0.1", "node-gyp": "^5.1.0", "nopt": "^4.0.3", "normalize-package-data": "^2.5.0", - "npm-audit-report": "^1.3.2", + "npm-audit-report": "^1.3.3", "npm-cache-filename": "~1.0.2", "npm-install-checks": "^3.0.2", - "npm-lifecycle": "^3.1.4", + "npm-lifecycle": "^3.1.5", "npm-package-arg": "^6.1.1", "npm-packlist": "^1.4.8", "npm-pick-manifest": "^3.0.2", "npm-profile": "^4.0.4", - "npm-registry-fetch": "^4.0.4", + "npm-registry-fetch": "^4.0.7", "npm-user-validate": "~1.0.0", "npmlog": "~4.1.2", "once": "~1.4.0", @@ -2209,7 +2244,7 @@ } }, "bin-links": { - "version": "1.1.7", + "version": "1.1.8", "bundled": true, "dev": true, "requires": { @@ -2364,26 +2399,41 @@ } }, "cliui": { - "version": "4.1.0", + "version": "5.0.0", "bundled": true, "dev": true, "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" }, "dependencies": { "ansi-regex": { - "version": "3.0.0", + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", "bundled": true, "dev": true }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, "strip-ansi": { - "version": "4.0.0", + "version": "5.2.0", "bundled": true, "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^4.1.0" } } } @@ -2498,11 +2548,11 @@ } }, "configstore": { - "version": "3.1.2", + "version": "3.1.5", "bundled": true, "dev": true, "requires": { - "dot-prop": "^4.1.0", + "dot-prop": "^4.2.1", "graceful-fs": "^4.1.2", "make-dir": "^1.0.0", "unique-string": "^1.0.0", @@ -2678,7 +2728,7 @@ } }, "dot-prop": { - "version": "4.2.0", + "version": "4.2.1", "bundled": true, "dev": true, "requires": { @@ -2745,6 +2795,11 @@ "bundled": true, "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "bundled": true, + "dev": true + }, "encoding": { "version": "0.1.12", "bundled": true, @@ -2870,14 +2925,6 @@ "bundled": true, "dev": true }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, "flush-write-stream": { "version": "1.0.3", "bundled": true, @@ -3076,7 +3123,7 @@ "dev": true }, "gentle-fs": { - "version": "2.3.0", + "version": "2.3.1", "bundled": true, "dev": true, "requires": { @@ -3106,7 +3153,7 @@ } }, "get-caller-file": { - "version": "1.0.3", + "version": "2.0.5", "bundled": true, "dev": true }, @@ -3330,11 +3377,6 @@ "validate-npm-package-name": "^3.0.0" } }, - "invert-kv": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, "ip": { "version": "1.1.5", "bundled": true, @@ -3519,16 +3561,8 @@ "bundled": true, "dev": true }, - "lcid": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "invert-kv": "^2.0.0" - } - }, "libcipm": { - "version": "4.0.7", + "version": "4.0.8", "bundled": true, "dev": true, "requires": { @@ -3538,7 +3572,7 @@ "find-npm-prefix": "^1.0.2", "graceful-fs": "^4.1.11", "ini": "^1.3.5", - "lock-verify": "^2.0.2", + "lock-verify": "^2.1.0", "mkdirp": "^0.5.1", "npm-lifecycle": "^3.0.0", "npm-logical-tree": "^1.2.1", @@ -3697,7 +3731,7 @@ } }, "libnpx": { - "version": "10.2.2", + "version": "10.2.4", "bundled": true, "dev": true, "requires": { @@ -3708,16 +3742,7 @@ "update-notifier": "^2.3.0", "which": "^1.3.0", "y18n": "^4.0.0", - "yargs": "^11.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "yargs": "^14.2.3" } }, "lock-verify": { @@ -3848,36 +3873,11 @@ "ssri": "^6.0.0" } }, - "map-age-cleaner": { - "version": "0.1.3", - "bundled": true, - "dev": true, - "requires": { - "p-defer": "^1.0.0" - } - }, "meant": { - "version": "1.0.1", + "version": "1.0.2", "bundled": true, "dev": true }, - "mem": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "bundled": true, - "dev": true - } - } - }, "mime-db": { "version": "1.35.0", "bundled": true, @@ -3899,6 +3899,11 @@ "brace-expansion": "^1.1.7" } }, + "minimist": { + "version": "1.2.5", + "bundled": true, + "dev": true + }, "minizlib": { "version": "1.3.3", "bundled": true, @@ -3980,11 +3985,6 @@ "bundled": true, "dev": true }, - "nice-try": { - "version": "1.0.5", - "bundled": true, - "dev": true - }, "node-fetch-npm": { "version": "2.0.2", "bundled": true, @@ -4044,7 +4044,7 @@ } }, "npm-audit-report": { - "version": "1.3.2", + "version": "1.3.3", "bundled": true, "dev": true, "requires": { @@ -4074,7 +4074,7 @@ } }, "npm-lifecycle": { - "version": "3.1.4", + "version": "3.1.5", "bundled": true, "dev": true, "requires": { @@ -4140,7 +4140,7 @@ } }, "npm-registry-fetch": { - "version": "4.0.4", + "version": "4.0.7", "bundled": true, "dev": true, "requires": { @@ -4154,7 +4154,7 @@ }, "dependencies": { "safe-buffer": { - "version": "5.2.0", + "version": "5.2.1", "bundled": true, "dev": true } @@ -4231,44 +4231,6 @@ "bundled": true, "dev": true }, - "os-locale": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "bundled": true, - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "execa": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - } - } - }, "os-tmpdir": { "version": "1.0.2", "bundled": true, @@ -4283,42 +4245,11 @@ "os-tmpdir": "^1.0.0" } }, - "p-defer": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "p-finally": { "version": "1.0.0", "bundled": true, "dev": true }, - "p-is-promise": { - "version": "2.1.0", - "bundled": true, - "dev": true - }, - "p-limit": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "p-limit": "^1.1.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, "package-json": { "version": "4.0.1", "bundled": true, @@ -4583,13 +4514,6 @@ "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true - } } }, "read": { @@ -4715,7 +4639,7 @@ "dev": true }, "require-main-filename": { - "version": "1.0.1", + "version": "2.0.0", "bundled": true, "dev": true }, @@ -4914,7 +4838,7 @@ } }, "spdx-license-ids": { - "version": "3.0.3", + "version": "3.0.5", "bundled": true, "dev": true }, @@ -5365,22 +5289,41 @@ } }, "wrap-ansi": { - "version": "2.1.0", + "version": "5.1.0", "bundled": true, "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, "string-width": { - "version": "1.0.2", + "version": "3.1.0", "bundled": true, "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" } } } @@ -5421,37 +5364,105 @@ "dev": true }, "yargs": { - "version": "11.1.1", + "version": "14.2.3", "bundled": true, "dev": true, "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.1.0", + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^3.0.0", "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" }, "dependencies": { - "y18n": { - "version": "3.2.1", + "ansi-regex": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", "bundled": true, "dev": true + }, + "string-width": { + "version": "3.1.0", + "bundled": true, + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "bundled": true, + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } } } }, "yargs-parser": { - "version": "9.0.2", + "version": "15.0.1", "bundled": true, "dev": true, "requires": { - "camelcase": "^4.1.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "bundled": true, + "dev": true + } } } } @@ -5731,6 +5742,12 @@ "prettier": "2.0.4" }, "dependencies": { + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, "prettier": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz", From 5ea71fbab6f416b9a483e5e97c41880f486380fd Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 11:49:14 -0400 Subject: [PATCH 02/11] chore: Use AndroidX --- android/build.gradle | 28 +++++++++++------- android/gradle.properties | 7 +++++ android/gradle/wrapper/gradle-wrapper.jar | Bin 53636 -> 55616 bytes .../gradle/wrapper/gradle-wrapper.properties | 3 +- .../android/ExampleInstrumentedTest.java | 24 ++++++++------- android/src/main/AndroidManifest.xml | 2 +- .../main/res/layout/bridge_layout_main.xml | 4 +-- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index a73bc99..9622a2a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,23 +1,29 @@ +ext { + junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.12' + androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.1' + androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.2.0' +} + buildscript { repositories { - jcenter() google() + jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.2' + classpath 'com.android.tools.build:gradle:3.6.1' } } apply plugin: 'com.android.library' android { - compileSdkVersion 28 + compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 29 defaultConfig { - minSdkVersion 21 - targetSdkVersion 28 + minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21 + targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 29 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { @@ -40,8 +46,8 @@ repositories { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':capacitor-android') - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' -} - + testImplementation "junit:junit:$junitVersion" + androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" + implementation "com.stripe:stripeterminal:1.0.17" +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index aac7c9b..bb8b131 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -15,3 +15,10 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true + +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app's APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Automatically convert third-party libraries to use AndroidX +android.enableJetifier=true \ No newline at end of file diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 13372aef5e24af05341d49695ee84e5f9b594659..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch literal 55616 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�J+L&6O)2CL%pxI@Gv&XXKx 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 V&}jHG + package="io.event1.capacitorstripeterminal.capacitorstripeterminal"> \ No newline at end of file diff --git a/android/src/main/res/layout/bridge_layout_main.xml b/android/src/main/res/layout/bridge_layout_main.xml index b69e589..3f165bf 100644 --- a/android/src/main/res/layout/bridge_layout_main.xml +++ b/android/src/main/res/layout/bridge_layout_main.xml @@ -1,5 +1,5 @@ - - + \ No newline at end of file From 438e73209b2fed6b73b3398b3ab3f3613e17f99f Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 11:52:18 -0400 Subject: [PATCH 03/11] feat(android): Add ability to init and discover readers ref #3 --- .../StripeTerminal.java | 20 -- .../StripeTerminal.java | 293 ++++++++++++++++++ .../TerminalUtils.java | 34 ++ package.json | 3 + src/plugin.ts | 42 +-- 5 files changed, 351 insertions(+), 41 deletions(-) delete mode 100644 android/src/main/java/io/event1/capacitor-stripe-terminal/StripeTerminal.java create mode 100644 android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java create mode 100644 android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java diff --git a/android/src/main/java/io/event1/capacitor-stripe-terminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitor-stripe-terminal/StripeTerminal.java deleted file mode 100644 index 7134aea..0000000 --- a/android/src/main/java/io/event1/capacitor-stripe-terminal/StripeTerminal.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.event1.capacitor-stripe-terminal; - -import com.getcapacitor.JSObject; -import com.getcapacitor.NativePlugin; -import com.getcapacitor.Plugin; -import com.getcapacitor.PluginCall; -import com.getcapacitor.PluginMethod; - -@NativePlugin() -public class StripeTerminal extends Plugin { - - @PluginMethod() - public void echo(PluginCall call) { - String value = call.getString("value"); - - JSObject ret = new JSObject(); - ret.put("value", value); - call.success(ret); - } -} diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java new file mode 100644 index 0000000..b5a9a6c --- /dev/null +++ b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java @@ -0,0 +1,293 @@ +package io.event1.capacitorstripeterminal; + +import com.getcapacitor.JSArray; +import com.getcapacitor.JSObject; +import com.getcapacitor.NativePlugin; +import com.getcapacitor.Plugin; +import com.getcapacitor.PluginCall; +import com.getcapacitor.PluginMethod; +import com.stripe.stripeterminal.Terminal; +import com.stripe.stripeterminal.callable.Callback; +import com.stripe.stripeterminal.callable.Cancelable; +import com.stripe.stripeterminal.callable.ConnectionTokenCallback; +import com.stripe.stripeterminal.callable.ConnectionTokenProvider; +import com.stripe.stripeterminal.callable.DiscoveryListener; +import com.stripe.stripeterminal.callable.PaymentIntentCallback; +import com.stripe.stripeterminal.callable.ReaderCallback; +import com.stripe.stripeterminal.callable.ReaderDisplayListener; +import com.stripe.stripeterminal.callable.ReaderSoftwareUpdateCallback; +import com.stripe.stripeterminal.callable.ReaderSoftwareUpdateListener; +import com.stripe.stripeterminal.callable.TerminalListener; +import com.stripe.stripeterminal.log.LogLevel; +import com.stripe.stripeterminal.model.external.ConnectionStatus; +import com.stripe.stripeterminal.model.external.ConnectionTokenException; +import com.stripe.stripeterminal.model.external.DeviceType; +import com.stripe.stripeterminal.model.external.DiscoveryConfiguration; +import com.stripe.stripeterminal.model.external.PaymentIntent; +import com.stripe.stripeterminal.model.external.PaymentIntentParameters; +import com.stripe.stripeterminal.model.external.PaymentStatus; +import com.stripe.stripeterminal.model.external.Reader; +import com.stripe.stripeterminal.model.external.ReaderDisplayMessage; +import com.stripe.stripeterminal.model.external.ReaderEvent; +import com.stripe.stripeterminal.model.external.ReaderInputOptions; +import com.stripe.stripeterminal.model.external.ReaderSoftwareUpdate; +import com.stripe.stripeterminal.model.external.TerminalException; +import java.util.List; +import javax.annotation.Nonnull; +import org.jetbrains.annotations.NotNull; + +@NativePlugin +public class StripeTerminal + extends Plugin + implements ConnectionTokenProvider, TerminalListener, DiscoveryListener { + Cancelable pendingDiscoverReaders = null; + ConnectionTokenCallback pendingConnectionTokenCallback = null; + ReaderEvent lastReaderEvent = ReaderEvent.CARD_REMOVED; + List discoveredReadersList = null; + + @PluginMethod + public void initialize(PluginCall call) { + try { + // Check if stripe is initialized + Terminal.getInstance(); + + JSObject ret = new JSObject(); + ret.put("isInitialized", true); + + call.resolve(ret); + return; + } catch (IllegalStateException e) {} + + pendingConnectionTokenCallback = null; + abortDiscoverReaders(); + // abortCreatePayment(); + // abortInstallUpdate(); + + LogLevel logLevel = LogLevel.VERBOSE; + ConnectionTokenProvider tokenProvider = this; + TerminalListener terminalListener = this; + + String err = ""; + boolean isInitialized = false; + try { + Terminal.initTerminal( + getBridge().getActivity(), + logLevel, + tokenProvider, + terminalListener + ); + lastReaderEvent = ReaderEvent.CARD_REMOVED; + isInitialized = true; + } catch (TerminalException e) { + e.printStackTrace(); + err = e.getErrorMessage(); + isInitialized = false; + } catch (IllegalStateException ex) { + ex.printStackTrace(); + err = ex.getMessage(); + isInitialized = true; + } + + JSObject ret = new JSObject(); + ret.put("isInitialized", isInitialized); + + if (!isInitialized) { + ret.put("error", err); + call.error(err); + return; + } + + call.resolve(ret); + } + + @PluginMethod + public void setConnectionToken(PluginCall call) { + String token = call.getString("token"); + String errorMessage = call.getString("errorMessage"); + + if (pendingConnectionTokenCallback != null) { + if (errorMessage != null && !errorMessage.trim().isEmpty()) { + pendingConnectionTokenCallback.onFailure( + new ConnectionTokenException(errorMessage) + ); + } else { + pendingConnectionTokenCallback.onSuccess(token); + } + + call.resolve(); + } + + pendingConnectionTokenCallback = null; + } + + @PluginMethod + public void discoverReaders(final PluginCall call) { + // Attempt to abort any pending discoverReader calls first. + abortDiscoverReaders(); + + Boolean simulated = call.getBoolean("simulated"); + DeviceType deviceType = DeviceType.values()[call.getInt("deviceType")]; + + DiscoveryConfiguration discoveryConfiguration = new DiscoveryConfiguration( + 0, + deviceType, + simulated + ); + Callback statusCallback = new Callback() { + + @Override + public void onSuccess() { + pendingDiscoverReaders = null; + call.resolve(); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + pendingDiscoverReaders = null; + call.error(e.getErrorMessage()); + } + }; + + abortDiscoverReaders(); + pendingDiscoverReaders = + Terminal + .getInstance() + .discoverReaders(discoveryConfiguration, this, statusCallback); + } + + @PluginMethod + public void abortDiscoverReaders(final PluginCall call) { + if ( + pendingDiscoverReaders != null && !pendingDiscoverReaders.isCompleted() + ) { + pendingDiscoverReaders.cancel( + new Callback() { + + @Override + public void onSuccess() { + pendingDiscoverReaders = null; + call.resolve(); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage()); + } + } + ); + } else { + call.resolve(); + } + } + + public void abortDiscoverReaders() { + if ( + pendingDiscoverReaders != null && !pendingDiscoverReaders.isCompleted() + ) { + pendingDiscoverReaders.cancel( + new Callback() { + + @Override + public void onSuccess() { + pendingDiscoverReaders = null; + } + + @Override + public void onFailure(@Nonnull TerminalException e) {} + } + ); + } + } + + @PluginMethod + public void connectReader(final PluginCall call) { + String serialNumber = call.getString("serialNumber"); + Reader selectedReader = null; + if (discoveredReadersList != null && discoveredReadersList.size() > 0) { + for (Reader reader : discoveredReadersList) { + if (reader != null) { + if (reader.getSerialNumber().equals(serialNumber)) { + selectedReader = reader; + } + } + } + } + + if (selectedReader != null) { + Terminal + .getInstance() + .connectReader( + selectedReader, + new ReaderCallback() { + + @Override + public void onSuccess(@Nonnull Reader reader) { + JSObject ret = new JSObject(); + ret.put("reader", TerminalUtils.serializeReader(reader)); + call.resolve(ret); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage(), e); + } + } + ); + } else { + call.error("No reader found with provided serial number"); + } + } + + @PluginMethod + public void getConnectionStatus(PluginCall call) { + ConnectionStatus status = Terminal.getInstance().getConnectionStatus(); + + JSObject ret = new JSObject(); + ret.put("status", status.ordinal()); + call.resolve(ret); + } + + @Override + public void fetchConnectionToken( + @NotNull ConnectionTokenCallback connectionTokenCallback + ) { + pendingConnectionTokenCallback = connectionTokenCallback; + + JSObject ret = new JSObject(); + notifyListeners("requestConnectionToken", ret); + } + + @Override + public void onConnectionStatusChange( + @NotNull ConnectionStatus connectionStatus + ) {} + + @Override + public void onPaymentStatusChange(@NotNull PaymentStatus paymentStatus) {} + + @Override + public void onReportLowBatteryWarning() {} + + @Override + public void onReportReaderEvent(@NotNull ReaderEvent readerEvent) {} + + @Override + public void onUnexpectedReaderDisconnect(@NotNull Reader reader) {} + + @Override + public void onUpdateDiscoveredReaders(@NotNull List list) { + discoveredReadersList = list; + + JSArray readersDiscoveredArr = new JSArray(); + for (Reader reader : list) { + if (reader != null) { + readersDiscoveredArr.put(TerminalUtils.serializeReader(reader)); + } + } + + JSObject ret = new JSObject(); + ret.put("readers", readersDiscoveredArr); + + notifyListeners("readersDiscovered", ret); + } +} diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java b/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java new file mode 100644 index 0000000..5b3445f --- /dev/null +++ b/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java @@ -0,0 +1,34 @@ +package io.event1.capacitorstripeterminal; + +import com.getcapacitor.JSObject; +import com.stripe.stripeterminal.model.external.Reader; + +public class TerminalUtils { + + public static JSObject serializeReader(Reader reader) { + JSObject object = new JSObject(); + + if (reader != null) { + double batteryLevel = 0; + if (reader.getBatteryLevel() != null) batteryLevel = + (double) reader.getBatteryLevel(); + object.put("batteryLevel", batteryLevel); + + int readerType = 0; + if (reader.getDeviceType() != null) readerType = + reader.getDeviceType().ordinal(); + object.put("deviceType", readerType); + + String serial = ""; + + if (reader.getSerialNumber() != null) serial = reader.getSerialNumber(); + object.put("serialNumber", serial); + + String softwareVersion = ""; + if (reader.getSoftwareVersion() != null) softwareVersion = + reader.getSoftwareVersion(); + object.put("deviceSoftwareVersion", softwareVersion); + } + return object; + } +} diff --git a/package.json b/package.json index 68d72a6..674ec9e 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,9 @@ "capacitor": { "ios": { "src": "ios" + }, + "android": { + "src": "android" } }, "repository": { diff --git a/src/plugin.ts b/src/plugin.ts index bceaf00..f41de64 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -23,29 +23,29 @@ export class StripeTerminalPlugin { constructor(options: StripeTerminalConfig) { this._fetchConnectionToken = options.fetchConnectionToken - StripeTerminal.initialize().then(() => { - this.listeners['connectionTokenListener'] = StripeTerminal.addListener( - 'requestConnectionToken', - () => { - this._fetchConnectionToken() - .then(token => { - if (token) { - StripeTerminal.setConnectionToken({ token }, null) - } else { - throw new Error( - 'User-supplied `fetchConnectionToken` resolved successfully, but no token was returned.' - ) - } - }) - .catch(err => - StripeTerminal.setConnectionToken( - null, - err.message || 'Error in user-supplied `fetchConnectionToken`.' + this.listeners['connectionTokenListener'] = StripeTerminal.addListener( + 'requestConnectionToken', + () => { + this._fetchConnectionToken() + .then(token => { + if (token) { + StripeTerminal.setConnectionToken({ token }, null) + } else { + throw new Error( + 'User-supplied `fetchConnectionToken` resolved successfully, but no token was returned.' ) + } + }) + .catch(err => + StripeTerminal.setConnectionToken( + null, + err.message || 'Error in user-supplied `fetchConnectionToken`.' ) - } - ) - }) + ) + } + ) + + StripeTerminal.initialize() } private _listenerToObservable( From 30483ab7beae281cc9cc3a2e57c4819065fd16b7 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 13:11:14 -0400 Subject: [PATCH 04/11] feat(android): Add ability to connect/disconnect readers --- .../StripeTerminal.java | 40 ++++++++++++++++++- src/definitions.ts | 5 ++- src/plugin.ts | 29 ++++++++++++-- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java index b5a9a6c..a1020a3 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java @@ -238,12 +238,45 @@ public void onFailure(@Nonnull TerminalException e) { } } + @PluginMethod + public void disconnectReader(final PluginCall call) { + if (Terminal.getInstance().getConnectedReader() == null) { + call.resolve(); + } else { + Terminal + .getInstance() + .disconnectReader( + new Callback() { + + @Override + public void onSuccess() { + call.resolve(); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage(), e); + } + } + ); + } + } + + @PluginMethod + public void getConnectedReader(PluginCall call) { + Reader reader = Terminal.getInstance().getConnectedReader(); + JSObject ret = new JSObject(); + ret.put("reader", TerminalUtils.serializeReader(reader)); + call.resolve(ret); + } + @PluginMethod public void getConnectionStatus(PluginCall call) { ConnectionStatus status = Terminal.getInstance().getConnectionStatus(); JSObject ret = new JSObject(); ret.put("status", status.ordinal()); + ret.put("isAndroid", true); call.resolve(ret); } @@ -260,7 +293,12 @@ public void fetchConnectionToken( @Override public void onConnectionStatusChange( @NotNull ConnectionStatus connectionStatus - ) {} + ) { + JSObject ret = new JSObject(); + ret.put("status", connectionStatus.ordinal()); + ret.put("isAndroid", true); + notifyListeners("didChangeConnectionStatus", ret); + } @Override public void onPaymentStatusChange(@NotNull PaymentStatus paymentStatus) {} diff --git a/src/definitions.ts b/src/definitions.ts index b0ad762..6ca7bf4 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -310,7 +310,10 @@ export interface StripeTerminalInterface extends Plugin { getConnectedReader(): Promise<{ reader: Reader }> - getConnectionStatus(): Promise<{ status: ConnectionStatus }> + getConnectionStatus(): Promise<{ + status: ConnectionStatus + isAndroid?: boolean + }> disconnectReader(): Promise diff --git a/src/plugin.ts b/src/plugin.ts index f41de64..475ea09 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -14,6 +14,13 @@ import { const { StripeTerminal } = Plugins +// The Android connection status enum is different from iOS, this maps Android to iOS +const AndroidConnectionStatusMap = { + 0: ConnectionStatus.NotConnected, + 1: ConnectionStatus.Connecting, + 2: ConnectionStatus.Connected +} + export class StripeTerminalPlugin { private _fetchConnectionToken: () => Promise = () => Promise.reject('You must initialize StripeTerminalPlugin first.') @@ -48,6 +55,20 @@ export class StripeTerminalPlugin { StripeTerminal.initialize() } + private translateConnectionStatus(data: { + status: ConnectionStatus + isAndroid?: boolean + }): ConnectionStatus { + let status: ConnectionStatus = data.status + + if (data.isAndroid) { + // the connection status on android is different than on iOS so we have to translate it + status = AndroidConnectionStatusMap[data.status] + } + + return status + } + private _listenerToObservable( name: string, transformFunc?: (data: any) => any @@ -122,7 +143,7 @@ export class StripeTerminalPlugin { try { const data = await StripeTerminal.getConnectionStatus() - return data.status + return this.translateConnectionStatus(data) } catch (err) { throw err } @@ -149,9 +170,9 @@ export class StripeTerminalPlugin { // get current value StripeTerminal.getConnectionStatus() .then((status: any) => { - // only send the inital value if the event listner hasn't already + // only send the initial value if the event listener hasn't already if (!hasSentEvent) { - subscriber.next(status.status) + subscriber.next(this.translateConnectionStatus(status)) } }) .catch((err: any) => { @@ -163,7 +184,7 @@ export class StripeTerminalPlugin { 'didChangeConnectionStatus', (status: any) => { hasSentEvent = true - subscriber.next(status.status) + subscriber.next(this.translateConnectionStatus(status)) } ) From f2ee76598f3a1e7a4311e546d2f3f058d928e0c9 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 13:32:08 -0400 Subject: [PATCH 05/11] feat(android): Implement reader status event listeners --- .../StripeTerminal.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java index a1020a3..3585f1a 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java @@ -301,16 +301,32 @@ public void onConnectionStatusChange( } @Override - public void onPaymentStatusChange(@NotNull PaymentStatus paymentStatus) {} + public void onPaymentStatusChange(@NotNull PaymentStatus paymentStatus) { + JSObject ret = new JSObject(); + ret.put("status", paymentStatus.ordinal()); + + notifyListeners("didChangePaymentStatus", ret); + } @Override - public void onReportLowBatteryWarning() {} + public void onReportLowBatteryWarning() { + notifyListeners("didReportLowBatteryWarning", new JSObject()); + } @Override - public void onReportReaderEvent(@NotNull ReaderEvent readerEvent) {} + public void onReportReaderEvent(@NotNull ReaderEvent readerEvent) { + lastReaderEvent = readerEvent; + JSObject ret = new JSObject(); + ret.put("event", readerEvent.ordinal()); + notifyListeners("didReportReaderEvent", ret); + } @Override - public void onUnexpectedReaderDisconnect(@NotNull Reader reader) {} + public void onUnexpectedReaderDisconnect(@NotNull Reader reader) { + JSObject ret = new JSObject(); + ret.put("reader", TerminalUtils.serializeReader(reader)); + notifyListeners("didReportUnexpectedReaderDisconnect", ret); + } @Override public void onUpdateDiscoveredReaders(@NotNull List list) { From cdebf5090ec3548bd8c9f820468a2d20b6b9abdb Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 16:05:57 -0400 Subject: [PATCH 06/11] feat(android): Add ability to retrieve payment intents, collect payment methods, and process payments ref #3 --- .../StripeTerminal.java | 175 +++++++++++++++++- .../TerminalUtils.java | 24 +++ src/plugin.ts | 4 + 3 files changed, 202 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java index 3585f1a..d909a66 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java @@ -39,9 +39,17 @@ @NativePlugin public class StripeTerminal extends Plugin - implements ConnectionTokenProvider, TerminalListener, DiscoveryListener { + implements + ConnectionTokenProvider, + TerminalListener, + DiscoveryListener, + ReaderDisplayListener { Cancelable pendingDiscoverReaders = null; + Cancelable pendingCollectPaymentMethod = null; ConnectionTokenCallback pendingConnectionTokenCallback = null; + String lastCurrency = null; + + PaymentIntent currentPaymentIntent = null; ReaderEvent lastReaderEvent = ReaderEvent.CARD_REMOVED; List discoveredReadersList = null; @@ -280,6 +288,149 @@ public void getConnectionStatus(PluginCall call) { call.resolve(ret); } + @PluginMethod + public void retrievePaymentIntent(final PluginCall call) { + String clientSecret = call.getString("clientSecret"); + + if (clientSecret != null) { + Terminal + .getInstance() + .retrievePaymentIntent( + clientSecret, + new PaymentIntentCallback() { + + @Override + public void onSuccess(@Nonnull PaymentIntent paymentIntent) { + currentPaymentIntent = paymentIntent; + JSObject ret = new JSObject(); + ret.put( + "intent", + TerminalUtils.serializePaymentIntent(paymentIntent, "") + ); + call.resolve(ret); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + currentPaymentIntent = null; + call.error(e.getErrorMessage(), e); + } + } + ); + } else { + call.reject("Client secret cannot be null"); + } + } + + @PluginMethod + public void collectPaymentMethod(final PluginCall call) { + if (currentPaymentIntent != null) { + pendingCollectPaymentMethod = + Terminal + .getInstance() + .collectPaymentMethod( + currentPaymentIntent, + this, + new PaymentIntentCallback() { + + @Override + public void onSuccess(@Nonnull PaymentIntent paymentIntent) { + pendingCollectPaymentMethod = null; + currentPaymentIntent = paymentIntent; + + JSObject ret = new JSObject(); + ret.put( + "intent", + TerminalUtils.serializePaymentIntent( + paymentIntent, + lastCurrency + ) + ); + + call.resolve(ret); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + pendingCollectPaymentMethod = null; + call.error(e.getErrorMessage(), e.getErrorCode().toString(), e); + } + } + ); + } else { + call.reject( + "There is no active payment intent. Make sure you called retrievePaymentIntent first" + ); + } + } + + @PluginMethod + public void abortCollectPaymentMethod(final PluginCall call) { + if ( + pendingCollectPaymentMethod != null && + !pendingCollectPaymentMethod.isCompleted() + ) { + pendingCollectPaymentMethod.cancel( + new Callback() { + + @Override + public void onSuccess() { + pendingCollectPaymentMethod = null; + call.resolve(); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage()); + } + } + ); + } + } + + @PluginMethod + public void processPayment(final PluginCall call) { + if (currentPaymentIntent != null) { + Terminal + .getInstance() + .processPayment( + currentPaymentIntent, + new PaymentIntentCallback() { + + @Override + public void onSuccess(@Nonnull PaymentIntent paymentIntent) { + currentPaymentIntent = paymentIntent; + + JSObject ret = new JSObject(); + ret.put( + "intent", + TerminalUtils.serializePaymentIntent( + paymentIntent, + lastCurrency + ) + ); + call.resolve(ret); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage(), e.getErrorCode().toString(), e); + } + } + ); + } else { + call.reject( + "There is no active payment intent. Make sure you called retrievePaymentIntent first" + ); + } + } + + @PluginMethod + public void clearCachedCredentials(PluginCall call) { + Terminal.getInstance().clearCachedCredentials(); + call.resolve(); + } + @Override public void fetchConnectionToken( @NotNull ConnectionTokenCallback connectionTokenCallback @@ -344,4 +495,26 @@ public void onUpdateDiscoveredReaders(@NotNull List list) { notifyListeners("readersDiscovered", ret); } + + @Override + public void onRequestReaderDisplayMessage( + @NotNull ReaderDisplayMessage readerDisplayMessage + ) { + JSObject ret = new JSObject(); + ret.put("value", readerDisplayMessage.ordinal()); + ret.put("text", readerDisplayMessage.toString()); + + notifyListeners("didRequestReaderDisplayMessage", ret); + } + + @Override + public void onRequestReaderInput( + @NotNull ReaderInputOptions readerInputOptions + ) { + JSObject ret = new JSObject(); + ret.put("value", readerInputOptions.toString()); + ret.put("isAndroid", true); + + notifyListeners("didRequestReaderInput", ret); + } } diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java b/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java index 5b3445f..10ea290 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java @@ -1,6 +1,7 @@ package io.event1.capacitorstripeterminal; import com.getcapacitor.JSObject; +import com.stripe.stripeterminal.model.external.PaymentIntent; import com.stripe.stripeterminal.model.external.Reader; public class TerminalUtils { @@ -31,4 +32,27 @@ public static JSObject serializeReader(Reader reader) { } return object; } + + public static JSObject serializePaymentIntent( + PaymentIntent paymentIntent, + String currency + ) { + JSObject object = new JSObject(); + + object.put("stripeId", paymentIntent.getId()); + object.put("created", paymentIntent.getCreated()); + object.put("status", paymentIntent.getStatus().ordinal()); + object.put("amount", paymentIntent.getAmount()); + object.put("currency", currency); + + JSObject metaData = new JSObject(); + if (paymentIntent.getMetadata() != null) { + for (String key : paymentIntent.getMetadata().keySet()) { + metaData.put(key, String.valueOf(paymentIntent.getMetadata().get(key))); + } + } + object.put("metadata", metaData); + + return object; + } } diff --git a/src/plugin.ts b/src/plugin.ts index 475ea09..2d9ff3a 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -226,6 +226,10 @@ export class StripeTerminalPlugin { public readerInput(): Observable { return this._listenerToObservable('didRequestReaderInput', (data: any) => { + if (data.isAndroid) { + return data.value + } + return parseFloat(data.value) }) } From 9b022bb2b0fe855d827e227f3fa906f235c25dd2 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 16:40:23 -0400 Subject: [PATCH 07/11] feat(android): Add ability to check for & install reader firmware updates --- .../StripeTerminal.java | 112 +++++++++++++++++- .../TerminalUtils.java | 16 +++ 2 files changed, 125 insertions(+), 3 deletions(-) diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java index d909a66..fa1333a 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java @@ -34,6 +34,7 @@ import com.stripe.stripeterminal.model.external.TerminalException; import java.util.List; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.jetbrains.annotations.NotNull; @NativePlugin @@ -43,7 +44,8 @@ public class StripeTerminal ConnectionTokenProvider, TerminalListener, DiscoveryListener, - ReaderDisplayListener { + ReaderDisplayListener, + ReaderSoftwareUpdateListener { Cancelable pendingDiscoverReaders = null; Cancelable pendingCollectPaymentMethod = null; ConnectionTokenCallback pendingConnectionTokenCallback = null; @@ -52,6 +54,8 @@ public class StripeTerminal PaymentIntent currentPaymentIntent = null; ReaderEvent lastReaderEvent = ReaderEvent.CARD_REMOVED; List discoveredReadersList = null; + ReaderSoftwareUpdate readerSoftwareUpdate; + Cancelable pendingInstallUpdate = null; @PluginMethod public void initialize(PluginCall call) { @@ -68,8 +72,7 @@ public void initialize(PluginCall call) { pendingConnectionTokenCallback = null; abortDiscoverReaders(); - // abortCreatePayment(); - // abortInstallUpdate(); + abortInstallUpdate(); LogLevel logLevel = LogLevel.VERBOSE; ConnectionTokenProvider tokenProvider = this; @@ -431,6 +434,101 @@ public void clearCachedCredentials(PluginCall call) { call.resolve(); } + @PluginMethod + public void checkForUpdate(final PluginCall call) { + Terminal + .getInstance() + .checkForUpdate( + new ReaderSoftwareUpdateCallback() { + + @Override + public void onSuccess( + @Nullable ReaderSoftwareUpdate readerSoftwareUpdate + ) { + StripeTerminal.this.readerSoftwareUpdate = readerSoftwareUpdate; + + JSObject ret = new JSObject(); + ret.put( + "update", + TerminalUtils.serializeUpdate(readerSoftwareUpdate) + ); + + call.resolve(ret); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage(), e); + } + } + ); + } + + @PluginMethod + public void installUpdate(final PluginCall call) { + pendingInstallUpdate = + Terminal + .getInstance() + .installUpdate( + readerSoftwareUpdate, + this, + new Callback() { + + @Override + public void onSuccess() { + readerSoftwareUpdate = null; + pendingInstallUpdate = null; + call.resolve(); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage(), e); + } + } + ); + } + + @PluginMethod + public void abortInstallUpdate(final PluginCall call) { + if (pendingInstallUpdate != null && !pendingInstallUpdate.isCompleted()) { + pendingInstallUpdate.cancel( + new Callback() { + + @Override + public void onSuccess() { + pendingInstallUpdate = null; + call.resolve(); + } + + @Override + public void onFailure(@Nonnull TerminalException e) { + call.error(e.getErrorMessage(), e); + } + } + ); + } else { + call.resolve(); + } + } + + public void abortInstallUpdate() { + if (pendingInstallUpdate != null && !pendingInstallUpdate.isCompleted()) { + pendingInstallUpdate.cancel( + new Callback() { + + @Override + public void onSuccess() { + pendingInstallUpdate = null; + } + + @Override + public void onFailure(@Nonnull TerminalException e) {} + } + ); + } + } + @Override public void fetchConnectionToken( @NotNull ConnectionTokenCallback connectionTokenCallback @@ -517,4 +615,12 @@ public void onRequestReaderInput( notifyListeners("didRequestReaderInput", ret); } + + @Override + public void onReportReaderSoftwareUpdateProgress(float v) { + JSObject ret = new JSObject(); + ret.put("progress", v); + + notifyListeners("didReportReaderSoftwareUpdateProgress", ret); + } } diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java b/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java index 10ea290..e5f3fbd 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/TerminalUtils.java @@ -3,6 +3,7 @@ import com.getcapacitor.JSObject; import com.stripe.stripeterminal.model.external.PaymentIntent; import com.stripe.stripeterminal.model.external.Reader; +import com.stripe.stripeterminal.model.external.ReaderSoftwareUpdate; public class TerminalUtils { @@ -55,4 +56,19 @@ public static JSObject serializePaymentIntent( return object; } + + public static JSObject serializeUpdate( + ReaderSoftwareUpdate readerSoftwareUpdate + ) { + JSObject object = new JSObject(); + + if (readerSoftwareUpdate != null) { + ReaderSoftwareUpdate.UpdateTimeEstimate updateTimeEstimate = readerSoftwareUpdate.getTimeEstimate(); + + object.put("estimatedUpdateTime", updateTimeEstimate.getDescription()); + object.put("deviceSoftwareVersion", readerSoftwareUpdate.getVersion()); + } + + return object; + } } From 7a176b5b70e31c5d695b47d6ed1db2692c6526ab Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Sat, 29 Aug 2020 16:50:55 -0400 Subject: [PATCH 08/11] docs(README): Add Android setup instructions --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a07a94a..2860c59 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,20 @@ Follow all Stripe instructions under ["Configure your app"](https://stripe.com/d ### Android -(not supported yet) +Follow all Stripe instructions under ["Configure your app"](https://stripe.com/docs/terminal/sdk/android#configure). + +Add the plugin to your `MainActivity.java`. + +```java +// import it at the top +import io.event1.capacitorstripeterminal.StripeTerminal; + +this.init(savedInstanceState, new ArrayList>() {{ + // Additional plugins you've installed go here + // Ex: add(TotallyAwesomePlugin.class); + add(StripeTerminal.class); +}}); +``` ## Usage From 2cb517cea1fc43d3bb41396c6244448966dffbf2 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Tue, 1 Sep 2020 18:12:40 -0400 Subject: [PATCH 09/11] feat(android): Add getPermissions method to ask for location permission and automatically enable bluetooth when initialized --- .../StripeTerminal.java | 53 ++++++++- ios/Plugin/Plugin.m | 1 + ios/Plugin/Plugin.swift | 4 + src/definitions.ts | 2 + src/plugin.ts | 104 ++++++++++-------- 5 files changed, 120 insertions(+), 44 deletions(-) diff --git a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java index fa1333a..5b7df54 100644 --- a/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java +++ b/android/src/main/java/io/event1/capacitorstripeterminal/StripeTerminal.java @@ -1,5 +1,7 @@ package io.event1.capacitorstripeterminal; +import android.Manifest; +import android.bluetooth.BluetoothAdapter; import com.getcapacitor.JSArray; import com.getcapacitor.JSObject; import com.getcapacitor.NativePlugin; @@ -37,7 +39,10 @@ import javax.annotation.Nullable; import org.jetbrains.annotations.NotNull; -@NativePlugin +@NativePlugin( + permissionRequestCode = StripeTerminal.REQUEST_CODE, + permissions = { Manifest.permission.ACCESS_FINE_LOCATION } +) public class StripeTerminal extends Plugin implements @@ -46,6 +51,7 @@ public class StripeTerminal DiscoveryListener, ReaderDisplayListener, ReaderSoftwareUpdateListener { + public static final int REQUEST_CODE = 0x6424; // Unique request code Cancelable pendingDiscoverReaders = null; Cancelable pendingCollectPaymentMethod = null; ConnectionTokenCallback pendingConnectionTokenCallback = null; @@ -57,8 +63,53 @@ public class StripeTerminal ReaderSoftwareUpdate readerSoftwareUpdate; Cancelable pendingInstallUpdate = null; + @PluginMethod + public void getPermissions(PluginCall call) { + if (!hasRequiredPermissions()) { + requestPermissions(call); + } else { + JSObject result = new JSObject(); + result.put("granted", true); + call.success(result); + } + } + + @Override + protected void handleRequestPermissionsResult( + int requestCode, + String[] permissions, + int[] grantResults + ) { + super.handleRequestPermissionsResult( + requestCode, + permissions, + grantResults + ); + + PluginCall savedCall = getSavedCall(); + JSObject result = new JSObject(); + + if (!hasRequiredPermissions()) { + result.put("granted", false); + savedCall.success(result); + } else { + result.put("granted", true); + savedCall.success(result); + } + } + @PluginMethod public void initialize(PluginCall call) { + if (!hasRequiredPermissions()) { + call.error("Location permission is required."); + } + + // turn on bluetooth + BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter(); + if (bluetooth.isEnabled() == false) { + bluetooth.enable(); + } + try { // Check if stripe is initialized Terminal.getInstance(); diff --git a/ios/Plugin/Plugin.m b/ios/Plugin/Plugin.m index 39af398..4e50a30 100644 --- a/ios/Plugin/Plugin.m +++ b/ios/Plugin/Plugin.m @@ -20,6 +20,7 @@ CAP_PLUGIN_METHOD(collectPaymentMethod, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(processPayment, CAPPluginReturnPromise); CAP_PLUGIN_METHOD(clearCachedCredentials, CAPPluginReturnPromise); + CAP_PLUGIN_METHOD(getPermissions, CAPPluginReturnPromise); ) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index c6189f8..c03331d 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -25,6 +25,10 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega // self.notifyListeners("log", data: ["logline": logline]) } + @objc func getPermissions(_ call: CAPPluginCall) { + call.resolve(["granted": true]) + } + @objc func initialize(_ call: CAPPluginCall) { DispatchQueue.main.async { Terminal.setTokenProvider(self) diff --git a/src/definitions.ts b/src/definitions.ts index 6ca7bf4..96e7e73 100644 --- a/src/definitions.ts +++ b/src/definitions.ts @@ -334,4 +334,6 @@ export interface StripeTerminalInterface extends Plugin { processPayment(): Promise<{ intent: PaymentIntent }> clearCachedCredentials(): Promise + + getPermissions(): Promise<{ granted: boolean }> } diff --git a/src/plugin.ts b/src/plugin.ts index 2d9ff3a..a792521 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -22,6 +22,8 @@ const AndroidConnectionStatusMap = { } export class StripeTerminalPlugin { + public isInitialized = false + private _fetchConnectionToken: () => Promise = () => Promise.reject('You must initialize StripeTerminalPlugin first.') @@ -30,6 +32,10 @@ export class StripeTerminalPlugin { constructor(options: StripeTerminalConfig) { this._fetchConnectionToken = options.fetchConnectionToken + this.init() + } + + private async init() { this.listeners['connectionTokenListener'] = StripeTerminal.addListener( 'requestConnectionToken', () => { @@ -52,7 +58,9 @@ export class StripeTerminalPlugin { } ) - StripeTerminal.initialize() + await StripeTerminal.initialize() + + this.isInitialized = true } private translateConnectionStatus(data: { @@ -90,9 +98,19 @@ export class StripeTerminalPlugin { }) } + private ensureInitialized() { + if (!this.isInitialized) { + throw new Error( + 'StripeTerminalPlugin must be initialized before you can use any methods.' + ) + } + } + public discoverReaders( options: DiscoveryConfiguration ): Observable { + this.ensureInitialized() + return new Observable(subscriber => { // start discovery StripeTerminal.discoverReaders(options) @@ -120,50 +138,46 @@ export class StripeTerminalPlugin { } public async connectReader(reader: Reader): Promise { - try { - const data = await StripeTerminal.connectReader(reader) + this.ensureInitialized() - return data.reader - } catch (err) { - throw err - } + const data = await StripeTerminal.connectReader(reader) + + return data.reader } public async getConnectedReader(): Promise { - try { - const data = await StripeTerminal.getConnectedReader() + this.ensureInitialized() - return data.reader - } catch (err) { - throw err - } + const data = await StripeTerminal.getConnectedReader() + + return data.reader } public async getConnectionStatus(): Promise { - try { - const data = await StripeTerminal.getConnectionStatus() + this.ensureInitialized() - return this.translateConnectionStatus(data) - } catch (err) { - throw err - } + const data = await StripeTerminal.getConnectionStatus() + + return this.translateConnectionStatus(data) } public async disconnectReader(): Promise { + this.ensureInitialized() + return StripeTerminal.disconnectReader() } public async checkForUpdate(): Promise { - try { - const data = await StripeTerminal.checkForUpdate() + this.ensureInitialized() - return data && data.update - } catch (err) { - throw err - } + const data = await StripeTerminal.checkForUpdate() + + return data && data.update } public connectionStatus(): Observable { + this.ensureInitialized() + return new Observable(subscriber => { let hasSentEvent = false @@ -197,6 +211,8 @@ export class StripeTerminalPlugin { } public installUpdate(): Observable { + this.ensureInitialized() + return new Observable(subscriber => { // initiate the installation StripeTerminal.installUpdate() @@ -246,43 +262,45 @@ export class StripeTerminalPlugin { public async retrievePaymentIntent( clientSecret: string ): Promise { - try { - const data = await StripeTerminal.retrievePaymentIntent({ clientSecret }) + this.ensureInitialized() - return data && data.intent - } catch (err) { - throw err - } + const data = await StripeTerminal.retrievePaymentIntent({ clientSecret }) + + return data && data.intent } public async collectPaymentMethod(): Promise { - try { - const data = await StripeTerminal.collectPaymentMethod() + this.ensureInitialized() - return data && data.intent - } catch (err) { - throw err - } + const data = await StripeTerminal.collectPaymentMethod() + + return data && data.intent } public async abortCollectPaymentMethod(): Promise { + this.ensureInitialized() + return StripeTerminal.abortCollectPaymentMethod() } public async processPayment(): Promise { - try { - const data = await StripeTerminal.processPayment() + this.ensureInitialized() - return data && data.intent - } catch (err) { - throw err - } + const data = await StripeTerminal.processPayment() + + return data && data.intent } public async clearCachedCredentials(): Promise { + this.ensureInitialized() + return StripeTerminal.clearCachedCredentials() } + public static async getPermissions(): Promise<{ granted: boolean }> { + return StripeTerminal.getPermissions() + } + public addListener(eventName: string, listenerFunc: Function) { return StripeTerminal.addListener(eventName, listenerFunc) } From f843fb6e6fdc3281ed51441f8c00c0b9644261f1 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Tue, 1 Sep 2020 18:22:48 -0400 Subject: [PATCH 10/11] docs(README): Add special instructions for Android setup --- README.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2860c59..e77cdcb 100644 --- a/README.md +++ b/README.md @@ -55,9 +55,7 @@ Follow all Stripe instructions under ["Configure your app"](https://stripe.com/d ### Android -Follow all Stripe instructions under ["Configure your app"](https://stripe.com/docs/terminal/sdk/android#configure). - -Add the plugin to your `MainActivity.java`. +Add the plugin to your `MainActivity.java`: ```java // import it at the top @@ -70,6 +68,36 @@ this.init(savedInstanceState, new ArrayList>() {{ }}); ``` +Add the `ACCESS_FINE_LOCATION`, `BLUETOOTH`, and `BLUETOOTH_ADMIN` permissions to your app's manifest: + +```xml + + + + + + + +``` + +On Android, you must also make sure that Location permission has been granted by the user: + +```javascript +const response = await StripeTerminalPlugin.getPermissions() + +if (!response.granted) { + throw new Error('Location permission is required.') +} + +const terminal = new StripeTerminalPlugin() +``` + +If the user does not grant permission, `StripeTerminalPlugin` will throw an error when you try to initialize it so you will have to handle that. + +_Hint: If the user denies Location permission the first time you ask for it, Android will not display a prompt to the user on subsequent requests for permission and `response.granted` will always be `false`. You will have to ask the user to go into the app's settings to allow Location permission._ + ## Usage ```javascript From 763e837c30db09f1f678db0c6fd79a92de881ea5 Mon Sep 17 00:00:00 2001 From: Noah Prail Date: Thu, 3 Sep 2020 08:18:28 -0400 Subject: [PATCH 11/11] chore: Format Swift code --- ios/Plugin/Plugin.swift | 110 ++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/ios/Plugin/Plugin.swift b/ios/Plugin/Plugin.swift index c03331d..13a2618 100644 --- a/ios/Plugin/Plugin.swift +++ b/ios/Plugin/Plugin.swift @@ -14,17 +14,17 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega private var pendingCollectPaymentMethod: Cancelable? private var currentUpdate: ReaderSoftwareUpdate? private var currentPaymentIntent: PaymentIntent? - + private var readers: [Reader]? - + func logMsg(items: Any...) { print("SWIFT \(items)") } - + func onLogEntry(logline _: String) { // self.notifyListeners("log", data: ["logline": logline]) } - + @objc func getPermissions(_ call: CAPPluginCall) { call.resolve(["granted": true]) } @@ -33,23 +33,23 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega DispatchQueue.main.async { Terminal.setTokenProvider(self) Terminal.shared.delegate = self - + Terminal.setLogListener { logline in self.onLogEntry(logline: logline) } // Terminal.shared.logLevel = LogLevel.verbose; - + self.abortDiscoverReaders() self.abortInstallUpdate() - + call.resolve() } } - + @objc func setConnectionToken(_ call: CAPPluginCall) { let token = call.getString("token") ?? "" let errorMessage = call.getString("errorMessage") ?? "" - + if let completion = pendingConnectionTokenCompletionBlock { if !errorMessage.isEmpty { let error = NSError(domain: "io.event1.capacitor-stripe-terminal", @@ -59,38 +59,38 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega } else { completion(token, nil) } - + pendingConnectionTokenCompletionBlock = nil call.resolve() } } - + public func fetchConnectionToken(_ completion: @escaping ConnectionTokenCompletionBlock) { pendingConnectionTokenCompletionBlock = completion notifyListeners("requestConnectionToken", data: [:]) } - + @objc func discoverReaders(_ call: CAPPluginCall) { // Attempt to abort any pending discoverReader calls first. abortDiscoverReaders() - + let simulated = call.getBool("simulated") ?? true let method = UInt(call.getInt("discoveryMethod") ?? 0) let device = UInt(call.getInt("deviceType") ?? 0) let locationId = call.getString("locationId") ?? nil - + let deviceType = DeviceType(rawValue: device) ?? DeviceType.chipper2X let discoveryMethod = DiscoveryMethod(rawValue: method) ?? DiscoveryMethod.bluetoothProximity - + pendingDiscoverReaders = nil - + let config = DiscoveryConfiguration(deviceType: deviceType, discoveryMethod: discoveryMethod, locationId: locationId, simulated: simulated) pendingDiscoverReaders = Terminal.shared.discoverReaders(config, delegate: self, completion: { error in self.pendingDiscoverReaders = nil - + if let error = error { call.error(error.localizedDescription, error) } else { @@ -98,7 +98,7 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega } }) } - + @objc func abortDiscoverReaders(_ call: CAPPluginCall? = nil) { if pendingDiscoverReaders != nil { pendingDiscoverReaders?.cancel { error in @@ -109,21 +109,21 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega } } } - + call?.resolve() } - + @objc func connectReader(_ call: CAPPluginCall) { guard let serialNumber = call.getString("serialNumber") else { call.reject("Must provide a serial number") return } - - guard let selectedReader = self.readers?.first(where: { $0.serialNumber == serialNumber }) else { + + guard let selectedReader = readers?.first(where: { $0.serialNumber == serialNumber }) else { call.reject("No reader found") return } - + // this must be run on the main thread // https://stackoverflow.com/questions/44767778/main-thread-checker-ui-api-called-on-a-background-thread-uiapplication-appli DispatchQueue.main.async { @@ -138,13 +138,13 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega }) } } - + @objc func disconnectReader(_ call: CAPPluginCall) { if Terminal.shared.connectedReader == nil { call.resolve() return } - + DispatchQueue.main.async { Terminal.shared.disconnectReader { error in if let error = error { @@ -155,7 +155,7 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega } } } - + @objc func checkForUpdate(_ call: CAPPluginCall) { Terminal.shared.checkForUpdate { _update, error in self.currentUpdate = _update @@ -168,7 +168,7 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega } } } - + @objc func installUpdate(_ call: CAPPluginCall) { if let update = currentUpdate { pendingInstallUpdate = Terminal.shared.installUpdate(update, delegate: self, completion: { error in @@ -182,7 +182,7 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega }) } } - + @objc func abortInstallUpdate(_ call: CAPPluginCall? = nil) { if pendingInstallUpdate != nil { pendingInstallUpdate?.cancel { error in @@ -193,35 +193,35 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega call?.resolve() } } - + return } - + call?.resolve() } - + @objc func getConnectionStatus(_ call: CAPPluginCall) { call.resolve(["status": Terminal.shared.connectionStatus.rawValue]) } - + @objc func getConnectedReader(_ call: CAPPluginCall) { var reader: Any = [:] if Terminal.shared.connectedReader != nil { reader = StripeTerminalUtils.serializeReader(reader: Terminal.shared.connectedReader!) } - + call.resolve(["reader": reader]) } - + @objc func retrievePaymentIntent(_ call: CAPPluginCall) { guard let clientSecret = call.getString("clientSecret") else { call.reject("Must provide a clientSecret") return } - + Terminal.shared.retrievePaymentIntent(clientSecret: clientSecret) { retrieveResult, retrieveError in self.currentPaymentIntent = retrieveResult - + if let error = retrieveError { call.error(error.localizedDescription, error) } else if let paymentIntent = retrieveResult { @@ -229,7 +229,7 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega } } } - + @objc func abortCollectPaymentMethod(_ call: CAPPluginCall? = nil) { if pendingCollectPaymentMethod != nil { pendingCollectPaymentMethod?.cancel { error in @@ -240,18 +240,18 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega call?.resolve() } } - + return } - + call?.resolve() } - + @objc func collectPaymentMethod(_ call: CAPPluginCall) { if let intent = currentPaymentIntent { pendingCollectPaymentMethod = Terminal.shared.collectPaymentMethod(intent, delegate: self) { collectResult, collectError in self.pendingCollectPaymentMethod = nil - + if let error = collectError { call.error(error.localizedDescription, error) } else if let paymentIntent = collectResult { @@ -263,7 +263,7 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega call.reject("There is no active payment intent. Make sure you called retrievePaymentIntent first") } } - + @objc func processPayment(_ call: CAPPluginCall) { if let intent = currentPaymentIntent { Terminal.shared.processPayment(intent) { paymentIntent, error in @@ -278,48 +278,48 @@ public class StripeTerminal: CAPPlugin, ConnectionTokenProvider, DiscoveryDelega call.reject("There is no active payment intent. Make sure you called retrievePaymentIntent first") } } - + @objc func clearCachedCredentials(_ call: CAPPluginCall) { Terminal.shared.clearCachedCredentials() call.resolve() } - + // MARK: DiscoveryDelegate - + public func terminal(_: Terminal, didUpdateDiscoveredReaders readers: [Reader]) { self.readers = readers - + let readersJSON = readers.map { (reader: Reader) -> [String: Any] in StripeTerminalUtils.serializeReader(reader: reader) } - + notifyListeners("readersDiscovered", data: ["readers": readersJSON]) } - + // MARK: TerminalDelegate - + public func terminal(_: Terminal, didReportUnexpectedReaderDisconnect reader: Reader) { logMsg(items: "didReportUnexpectedReaderDisconnect \(reader)") notifyListeners("didReportUnexpectedReaderDisconnect", data: ["reader": StripeTerminalUtils.serializeReader(reader: reader)]) } - + public func terminal(_: Terminal, didChangeConnectionStatus status: ConnectionStatus) { notifyListeners("didChangeConnectionStatus", data: ["status": status.rawValue]) } - + // MARK: ReaderSoftwareUpdateDelegate - + public func terminal(_: Terminal, didReportReaderSoftwareUpdateProgress progress: Float) { notifyListeners("didReportReaderSoftwareUpdateProgress", data: ["progress": progress]) } - + // MARK: ReaderDisplayDelegate - + public func terminal(_: Terminal, didRequestReaderInput inputOptions: ReaderInputOptions = []) { notifyListeners("didRequestReaderInput", data: ["value": inputOptions.rawValue]) } - + public func terminal(_: Terminal, didRequestReaderDisplayMessage displayMessage: ReaderDisplayMessage) { notifyListeners("didRequestReaderDisplayMessage", data: ["value": displayMessage.rawValue]) }