From 6bccd5089c574e66bc765f374f18f0a14de4b98c Mon Sep 17 00:00:00 2001 From: Robert Gardner Date: Tue, 5 May 2020 20:55:04 -0700 Subject: [PATCH] feat: make ccard images available (#116) * Make credit card images accessible to the plugin. * bump version --- CHANGELOG.md | 4 ++ demo-angular/app/app.module.ts | 6 ++- demo-angular/app/app.routing.ts | 8 ++-- demo-angular/app/demo/home.component.html | 6 ++- demo-angular/app/demo/images.component.html | 17 ++++++++ demo-angular/app/demo/images.component.ts | 24 +++++++++++ src/index.d.ts | 3 +- src/package.json | 2 +- src/stripe.android.ts | 45 +++++++++++++++++++++ src/stripe.ios.ts | 31 ++++++++++++++ 10 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 demo-angular/app/demo/images.component.html create mode 100644 demo-angular/app/demo/images.component.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 84c84ac..1c8117e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ Changelog +## 6.6.0 (2020, May 5) +### Updates +- [(# 115)](https://github.com/triniwiz/nativescript-stripe/issues/115) Make Stripe's credit card images visible to clients + ## 6.5.0 (2020, April 22) ### Updates - [(# 108)](https://github.com/triniwiz/nativescript-stripe/issues/108) Update to Stripe Android SDK v12. No new functionality. Should be backward compatible with v6.4.0. diff --git a/demo-angular/app/app.module.ts b/demo-angular/app/app.module.ts index 76fb3cf..a1a50c1 100644 --- a/demo-angular/app/app.module.ts +++ b/demo-angular/app/app.module.ts @@ -5,10 +5,11 @@ import { AppComponent } from "./app.component"; import { AppRoutingModule } from "./app.routing"; import { CreditCardViewComponent } from "./demo/creditcardview.component"; import { HomeComponent } from "./demo/home.component"; -import { StandardComponent } from "./demo/standard.component"; +import { ImagesComponent } from "./demo/images.component"; +import { ItentModalComponent } from "./demo/intent-modal.component"; import { IntentComponent } from "./demo/intent.component"; +import { StandardComponent } from "./demo/standard.component"; import { StripeService } from "./demo/stripe.service"; -import { ItentModalComponent } from "./demo/intent-modal.component"; // Uncomment and add to NgModule imports if you need to use two-way binding // import { NativeScriptFormsModule } from "nativescript-angular/forms"; @@ -30,6 +31,7 @@ import { ItentModalComponent } from "./demo/intent-modal.component"; HomeComponent, StandardComponent, CreditCardViewComponent, + ImagesComponent, IntentComponent, ItentModalComponent ], diff --git a/demo-angular/app/app.routing.ts b/demo-angular/app/app.routing.ts index 6ddd65d..8cb1498 100644 --- a/demo-angular/app/app.routing.ts +++ b/demo-angular/app/app.routing.ts @@ -3,19 +3,21 @@ import { Routes } from "@angular/router"; import { NativeScriptRouterModule } from "nativescript-angular/router"; import { CreditCardViewComponent } from "./demo/creditcardview.component"; import { HomeComponent } from "./demo/home.component"; -import { StandardComponent } from "./demo/standard.component"; +import { ImagesComponent } from "./demo/images.component"; import { IntentComponent } from "./demo/intent.component"; +import { StandardComponent } from "./demo/standard.component"; const routes: Routes = [ { path: "", redirectTo: "/home", pathMatch: "full" }, { path: "home", component: HomeComponent }, { path: "std", component: StandardComponent }, { path: "ccview", component: CreditCardViewComponent }, - { path: "intent", component: IntentComponent } + { path: "intent", component: IntentComponent }, + { path: "images", component: ImagesComponent } ]; @NgModule({ imports: [NativeScriptRouterModule.forRoot(routes)], exports: [NativeScriptRouterModule] }) -export class AppRoutingModule { } \ No newline at end of file +export class AppRoutingModule { } diff --git a/demo-angular/app/demo/home.component.html b/demo-angular/app/demo/home.component.html index fde3093..5f95312 100644 --- a/demo-angular/app/demo/home.component.html +++ b/demo-angular/app/demo/home.component.html @@ -12,4 +12,8 @@ - \ No newline at end of file + + + + + diff --git a/demo-angular/app/demo/images.component.html b/demo-angular/app/demo/images.component.html new file mode 100644 index 0000000..7416a43 --- /dev/null +++ b/demo-angular/app/demo/images.component.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/demo-angular/app/demo/images.component.ts b/demo-angular/app/demo/images.component.ts new file mode 100644 index 0000000..ca6edab --- /dev/null +++ b/demo-angular/app/demo/images.component.ts @@ -0,0 +1,24 @@ +import { Component } from "@angular/core"; +import { Card, CardBrand } from "nativescript-stripe"; + +type ImageTable = { + [brand: string]: any; +}; + +@Component({ + selector: "stp-images", + moduleId: module.id, + templateUrl: "images.component.html", +}) +export class ImagesComponent { + images: ImageTable = {}; + + constructor() { + let brands: CardBrand[] = ["Visa", "Amex", "MasterCard", "Discover", "JCB", "DinersClub", "Unknown"]; + brands.forEach(b => this.images[b] = Card.cardImage(b)); + } + + get brands(): string[] { + return Object.keys(this.images); + } +} diff --git a/src/index.d.ts b/src/index.d.ts index d1237a1..0087f62 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -65,6 +65,7 @@ export declare class Card implements CardCommon { readonly fingerprint: string; readonly funding: string; readonly country: string; + static cardImage(brand: CardBrand): any; } export declare class CreditCardView extends CreditCardViewBase { readonly android: any /*com.stripe.android.view.CardInputWidget*/; @@ -194,4 +195,4 @@ export declare const enum StripeRedirectState { InProgress = 1, Cancelled = 2, Completed = 3 -} \ No newline at end of file +} diff --git a/src/package.json b/src/package.json index b4d68c2..1766f17 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "nativescript-stripe", - "version": "6.5.0", + "version": "6.6.0", "description": "NativeScript Stripe sdk", "main": "stripe", "typings": "index.d.ts", diff --git a/src/stripe.android.ts b/src/stripe.android.ts index dd57918..bd2e42c 100644 --- a/src/stripe.android.ts +++ b/src/stripe.android.ts @@ -389,6 +389,51 @@ export class Card implements CardCommon { get country(): string { return this.native.getCountry(); } + + /** + * Returns an image for a card given its brand. + * The returned value can be used as [src] in an Image tag. + */ + static cardImage(brand: CardBrand): any { + return getBitmapFromResource(com.stripe.android.model.Card.getBrandIcon(Card.fromCardBrand(brand))); + } + + private static fromCardBrand(brand: CardBrand): string { + switch (brand.toLowerCase()) { + case 'visa': + return com.stripe.android.model.Card.CardBrand.VISA; + case 'amex': + case 'americanexpress': + case 'american_express': + case 'american express': + return com.stripe.android.model.Card.CardBrand.AMERICAN_EXPRESS; + case 'mastercard': + return com.stripe.android.model.Card.CardBrand.MASTERCARD; + case 'discover': + return com.stripe.android.model.Card.CardBrand.DISCOVER; + case 'jcb': + return com.stripe.android.model.Card.CardBrand.JCB; + case 'dinersclub': + case 'diners_club': + case 'diners club': + return com.stripe.android.model.Card.CardBrand.DINERS_CLUB; + } + return com.stripe.android.model.Card.CardBrand.UNKNOWN; + } + +} + +function getBitmapFromResource(resID: number): android.graphics.Bitmap { + let image = androidApp.foregroundActivity.getResources().getDrawable(resID, null); + if (image instanceof android.graphics.Bitmap) { + return image; + } + let bitmap = android.graphics.Bitmap.createBitmap(image.getIntrinsicWidth(), + image.getIntrinsicHeight(), android.graphics.Bitmap.Config.ARGB_8888); + let canvas = new android.graphics.Canvas(bitmap); + image.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + image.draw(canvas); + return bitmap; } export class CreditCardView extends CreditCardViewBase { diff --git a/src/stripe.ios.ts b/src/stripe.ios.ts index 7a4b191..c5c8cda 100644 --- a/src/stripe.ios.ts +++ b/src/stripe.ios.ts @@ -419,6 +419,29 @@ export class Card implements CardCommon { return 'Unknown'; } + private static fromCardBrand(brand: CardBrand): STPCardBrand { + switch (brand.toLowerCase()) { + case 'visa': + return STPCardBrand.Visa; + case 'amex': + case 'americanexpress': + case 'american_express': + case 'american express': + return STPCardBrand.Amex; + case 'mastercard': + return STPCardBrand.MasterCard; + case 'discover': + return STPCardBrand.Discover; + case 'jcb': + return STPCardBrand.JCB; + case 'dinersclub': + case 'diners_club': + case 'diners club': + return STPCardBrand.DinersClub; + } + return STPCardBrand.Unknown; + } + /** * Not available in IOS */ @@ -436,6 +459,14 @@ export class Card implements CardCommon { get country(): string { return this.native.addressCountry; } + + /** + * Returns an image for a card given its brand. + * The returned value can be used as [src] in an Image tag. + */ + static cardImage(brand: CardBrand): any { + return STPImageLibrary.brandImageForCardBrand(Card.fromCardBrand(brand)); + } } export class CreditCardView extends CreditCardViewBase {