Skip to content

Commit

Permalink
Allow embedding the scanner in a page #136
Browse files Browse the repository at this point in the history
  • Loading branch information
EddyVerbruggen committed Feb 12, 2018
1 parent 43381e1 commit 23395be
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 116 deletions.
9 changes: 9 additions & 0 deletions demo/app/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@
.tab-content {
color: #808080;
padding: 0 18;
}

.scanner-round {
width: 260;
height: 260;
margin-top: 16;
border-radius: 130;
border-width: 8;
border-color: #ddd;
}
Binary file added demo/app/images/crosshair.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 9 additions & 5 deletions demo/app/main-page.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import * as observable from "tns-core-modules/data/observable";
import * as pages from "tns-core-modules/ui/page";
import { HelloWorldModel } from "./main-view-model";
import {HelloWorldModel} from "./main-view-model";

// Event handler for Page "loaded" event attached in main-page.xml
export function pageLoaded(args: observable.EventData) {
// Get the event sender
let page = <pages.Page>args.object;
page.bindingContext = new HelloWorldModel();
}
// Get the event sender
let page = <pages.Page>args.object;
page.bindingContext = new HelloWorldModel();
}

export function onScanResult(scanResult: any) {
console.log(`onScanResult: ${scanResult.text} (${scanResult.format})`);
}
40 changes: 25 additions & 15 deletions demo/app/main-page.xml
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded">
<Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:Barcode="nativescript-barcodescanner" loaded="pageLoaded">
<TabView class="tab-view">
<TabView.items>
<TabViewItem title="About">
<TabViewItem.view>
<StackLayout class="tab-content">
<Image margin="10" src="~/res/telerik-logo.png"/>
<Label class="h3" text="BarcodeScanner plugin demo"/>
<Label class="body" text="The BarcodeScanner plugin supports extracting data from a large range of barcodes, including QR codes. Your app will receive the type of barcode and the encode value." textWrap="true"/>
</StackLayout>
</TabViewItem.view>
</TabViewItem>
<TabViewItem title="Demo">
<TabViewItem.view>
<ScrollView>
Expand All @@ -23,11 +14,21 @@
<Button class="btn btn-outline btn-rounded-sm" text="has permission?" tap="{{ doCheckHasCameraPermission }}"/>
<Button class="btn btn-primary btn-rounded-sm" text="request permission" tap="{{ doRequestCameraPermission }}"/>

<!--iOS>
<ContentView height="240" width="240">
<Barcode:BarcodeScannerView></Barcode:BarcodeScannerView>
</ContentView>
</iOS-->
<iOS>
<Label class="h3" text="Scanner declared in XML"/>
<Label class="body" text="Beeps and logs to console when a QR_CODE or EAN_13 is scanned. The image was added to show how to add an arbitrary overlay." textWrap="true"/>
<GridLayout>
<Barcode:BarcodeScannerView
class="scanner-round"
formats="QR_CODE, EAN_13"
beepOnScan="true"
reportDuplicates="true"
preferFrontCamera="false"
scanResult="onScanResult" />
<Image src="~/images/crosshair.png" width="140" height="140" style="margin-top: 14; opacity: 0.3" horizontalAlignment="center" verticalAlignment="center"/>
<!--<Label text="......................................." style="margin-top: 8; color: #FFF; opacity: 0.5" horizontalAlignment="center" verticalAlignment="center"/>-->
</GridLayout>
</iOS>

<Label class="h3" text="Scan QR, EAN-13, or CODE_128"/>
<Label class="body" text="You can use the volume buttons to toggle the torch." textWrap="true"/>
Expand All @@ -49,6 +50,15 @@
</ScrollView>
</TabViewItem.view>
</TabViewItem>
<TabViewItem title="About">
<TabViewItem.view>
<StackLayout class="tab-content">
<Image margin="10" src="~/res/telerik-logo.png"/>
<Label class="h3" text="BarcodeScanner plugin demo"/>
<Label class="body" text="The BarcodeScanner plugin supports extracting data from a large range of barcodes, including QR codes. Your app will receive the type of barcode and the encode value." textWrap="true"/>
</StackLayout>
</TabViewItem.view>
</TabViewItem>
</TabView.items>
</TabView>
</Page>
95 changes: 76 additions & 19 deletions src/barcodescanner-common.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {ContentView} from "tns-core-modules/ui/content-view";
import {Property} from "tns-core-modules/ui/core/properties";
import {booleanConverter} from "tns-core-modules/ui/core/view-base";

export interface ScanResult {
text: string;
format: string;
Expand Down Expand Up @@ -103,24 +107,77 @@ export interface ScanOptions extends IOS, Android {
Android?: Android;
}

// export abstract class BarcodeScannerView extends ContentView {
// }

export declare class BarcodeScanner {
private _observer;
private _observerActive;
private _currentVolume;
private _scanner;
constructor();
private _hasCameraPermission;
private _hasDeniedCameraPermission;
private _addVolumeObserver;
private _removeVolumeObserver;
private _enableTorch;
private _disableTorch;
available(): Promise<boolean>;
hasCameraPermission(): Promise<boolean>;
requestCameraPermission(): Promise<boolean>;
stop(): Promise<any>;
scan(arg: ScanOptions): Promise<ScanResult>;
private _observer;
private _observerActive;
private _currentVolume;
private _scanner;
constructor();
private _hasCameraPermission;
private _hasDeniedCameraPermission;
private _addVolumeObserver;
private _removeVolumeObserver;
private _enableTorch;
private _disableTorch;
available(): Promise<boolean>;
hasCameraPermission(): Promise<boolean>;
requestCameraPermission(): Promise<boolean>;
stop(): Promise<any>;
scan(arg: ScanOptions): Promise<ScanResult>;
}


/**** View-related stuff below ****/
export const formatsProperty = new Property<BarcodeScannerView, string>({
name: "formats",
defaultValue: null,
});

export const preferFrontCameraProperty = new Property<BarcodeScannerView, boolean>({
name: "preferFrontCamera",
defaultValue: false,
valueConverter: booleanConverter
});

export const beepOnScanProperty = new Property<BarcodeScannerView, boolean>({
name: "beepOnScan",
defaultValue: true,
valueConverter: booleanConverter
});

export const reportDuplicatesProperty = new Property<BarcodeScannerView, boolean>({
name: "reportDuplicates",
defaultValue: false,
valueConverter: booleanConverter
});

export abstract class BarcodeScannerView extends ContentView {

static scanResultEvent: string = "scanResult";

protected formats: string;
protected preferFrontCamera: boolean;
protected beepOnScan: boolean;
protected reportDuplicates: boolean;

[formatsProperty.setNative](value: string) {
this.formats = value;
}

[preferFrontCameraProperty.setNative](value: boolean) {
this.preferFrontCamera = value;
}

[beepOnScanProperty.setNative](value: boolean) {
this.beepOnScan = value;
}

[reportDuplicatesProperty.setNative](value: boolean) {
this.reportDuplicates = value;
}
}

formatsProperty.register(BarcodeScannerView);
preferFrontCameraProperty.register(BarcodeScannerView);
beepOnScanProperty.register(BarcodeScannerView);
reportDuplicatesProperty.register(BarcodeScannerView);
142 changes: 65 additions & 77 deletions src/barcodescanner.ios.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,64 @@
import { ScanOptions, ScanResult } from "./barcodescanner-common";
import {BarcodeScannerView as BarcodeScannerBaseView, ScanOptions, ScanResult} from "./barcodescanner-common";
import * as utils from "tns-core-modules/utils/utils";
import * as frame from "tns-core-modules/ui/frame";

/* no luck yet
export class BarcodeScannerView extends BarcodeScannerBaseView {

private _reader: any;
private _scanner: any;
private _ios: any;
private _continuous: boolean;
constructor() {
super();
// let authStatus = AVCaptureDevice.authorizationStatusForMediaType(AVMediaTypeVideo);
// if (authStatus !== AVAuthorizationStatus.Authorized) {
// }
private _reader: QRCodeReader;
private _scanner: QRCodeReaderViewController;

let closeButtonLabel = "bla";
let types = [AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
public createNativeView(): Object {
let v = super.createNativeView();
this.initView();
return v;
}

this._reader = QRCodeReader.readerWithMetadataObjectTypes(types);
initView() {
const types = getBarcodeTypes(this.formats);
this._reader = QRCodeReader.readerWithMetadataObjectTypes(<any>types);

let torch = false;
let flip = false;
let startScanningAtLoad = true;
// this._scanner = QRCodeReaderViewController.readerWithCancelButtonTitleCodeReaderStartScanningAtLoadShowSwitchCameraButtonShowTorchButton(closeButtonLabel, this._reader, startScanningAtLoad, flip, torch);
// this._scanner.modalPresentationStyle = UIModalPresentationStyle.FormSheet;
let closeButtonLabel = null;
let cancelLabelBackgroundColor = null;

// Assign first to local variable, otherwise it will be garbage collected since delegate is weak reference.
if (this.preferFrontCamera) {
this._reader.switchDeviceInput();
}

let isContinuous = false;
// this._scanDelegate = QRCodeReaderDelegateImpl.initWithOwner(new WeakRef(this));
this._scanner = QRCodeReaderViewController.readerWithCancelButtonTitleCodeReaderStartScanningAtLoadShowSwitchCameraButtonShowTorchButtonCancelButtonBackgroundColor(
closeButtonLabel, this._reader, true, flip, torch, cancelLabelBackgroundColor);
this._scanner.modalPresentationStyle = UIModalPresentationStyle.CurrentContext;

const that = this;
let delegate = QRCodeReaderDelegateImpl.initWithOwner(new WeakRef(this));
delegate.setCallback(true, isContinuous, true, (reader: string, text: string, format: string) => {
// Remove the local variable for the delegate.
delegate = undefined;
});
// this._scanner.delegate = delegate;
console.log("--- this._reader.previewLayer: " + this._reader.previewLayer);
// this._ios = this._reader.previewLayer; // TODO
delegate.setCallback(
this.beepOnScan,
true,
this.reportDuplicates,
(text: string, format: string) => {
that.notify({
eventName: BarcodeScannerBaseView.scanResultEvent,
object: that,
format: format,
text: text
});
});
this._scanner.delegate = delegate;

console.log("--- ios: " + this.ios);
if (this.ios) {
this.ios.layer.insertSublayerAtIndex(this._reader.previewLayer, 0);
}
// instead of a delegate we can use setCompletionWithBlock: https://github.com/yannickl/QRCodeReaderViewController/blob/master/QRCodeReaderViewController/QRCodeReader.h#L201
setTimeout(() => {
this._reader.startScanning();
}, 4000);
}
}

public onLayout(left: number, top: number, right: number, bottom: number): void {
super.onLayout(left, top, right, bottom);
if (this.ios) {
console.log(">>> yes, layout");
this._reader.previewLayer.frame = this.ios.layer.bounds;
} else {
console.log(">>> no, layout");
}
}
get ios(): any {
return this._ios;
}
set continuous(value: boolean) {
this._continuous = value;
}
}
*/

export class BarcodeScanner {
private _observer: NSObject;
Expand Down Expand Up @@ -197,30 +180,7 @@ export class BarcodeScanner {

this._closeCallback = arg.closeCallback;

let types = [];
if (arg.formats) {
let formats = arg.formats.split(",");
for (let format of formats) {
format = format.trim();
if (format === "QR_CODE") types.push(AVMetadataObjectTypeQRCode);
else if (format === "PDF_417") types.push(AVMetadataObjectTypePDF417Code);
else if (format === "AZTEC") types.push(AVMetadataObjectTypeAztecCode);
else if (format === "UPC_E") types.push(AVMetadataObjectTypeUPCECode);
else if (format === "CODE_39") types.push(AVMetadataObjectTypeCode39Code);
else if (format === "CODE_39_MOD_43") types.push(AVMetadataObjectTypeCode39Mod43Code);
else if (format === "CODE_93") types.push(AVMetadataObjectTypeCode93Code);
else if (format === "CODE_128") types.push(AVMetadataObjectTypeCode128Code);
else if (format === "DATA_MATRIX") types.push(AVMetadataObjectTypeDataMatrixCode);
else if (format === "EAN_8") types.push(AVMetadataObjectTypeEAN8Code);
else if (format === "EAN_13") types.push(AVMetadataObjectTypeEAN13Code);
else if (format === "ITF") types.push(AVMetadataObjectTypeITF14Code);
}
} else {
types = [AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypeDataMatrixCode, AVMetadataObjectTypeITF14Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
}
const types = getBarcodeTypes(arg.formats);

const reader = QRCodeReader.readerWithMetadataObjectTypes(<any>types);

Expand Down Expand Up @@ -292,12 +252,40 @@ export class BarcodeScanner {
}
}

const getBarcodeTypes = (formatsString: string) => {
const types = [];
if (formatsString) {
let formats = formatsString.split(",");
for (let format of formats) {
format = format.trim();
if (format === "QR_CODE") types.push(AVMetadataObjectTypeQRCode);
else if (format === "PDF_417") types.push(AVMetadataObjectTypePDF417Code);
else if (format === "AZTEC") types.push(AVMetadataObjectTypeAztecCode);
else if (format === "UPC_E") types.push(AVMetadataObjectTypeUPCECode);
else if (format === "CODE_39") types.push(AVMetadataObjectTypeCode39Code);
else if (format === "CODE_39_MOD_43") types.push(AVMetadataObjectTypeCode39Mod43Code);
else if (format === "CODE_93") types.push(AVMetadataObjectTypeCode93Code);
else if (format === "CODE_128") types.push(AVMetadataObjectTypeCode128Code);
else if (format === "DATA_MATRIX") types.push(AVMetadataObjectTypeDataMatrixCode);
else if (format === "EAN_8") types.push(AVMetadataObjectTypeEAN8Code);
else if (format === "EAN_13") types.push(AVMetadataObjectTypeEAN13Code);
else if (format === "ITF") types.push(AVMetadataObjectTypeITF14Code);
}
} else {
types.push(AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypeDataMatrixCode, AVMetadataObjectTypeITF14Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode);
}
return types;
};

class QRCodeReaderDelegateImpl extends NSObject implements QRCodeReaderDelegate {
public static ObjCProtocols = [QRCodeReaderDelegate];

private _owner: WeakRef<BarcodeScanner>;
private _owner: WeakRef<any>;

public static initWithOwner(owner: WeakRef<BarcodeScanner>): QRCodeReaderDelegateImpl {
public static initWithOwner(owner: WeakRef<any>): QRCodeReaderDelegateImpl {
let delegate = <QRCodeReaderDelegateImpl>QRCodeReaderDelegateImpl.new();
delegate._owner = owner;
return delegate;
Expand Down

0 comments on commit 23395be

Please sign in to comment.