@nstudio/nativescript-camera-plus
Version:
An advanced, embeddable camera for NativeScript.
1,152 lines • 48.1 kB
JavaScript
/**********************************************************************************
* (c) 2017, nStudio, LLC & LiveShopper, LLC
*
* Version 1.1.0 team@nstudio.io
**********************************************************************************/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
import { AndroidApplication, Application, Device, ImageAsset, Utils, View } from '@nativescript/core';
import * as permissions from '@nativescript-community/perms';
import { CameraLens, CameraPlusBase, CameraVideoQuality, CLog, GetSetProperty, WhiteBalance } from './common';
import * as CamHelpers from './helpers';
import { SelectedAsset } from './selected-asset';
export { CameraVideoQuality, WhiteBalance } from './common';
const REQUEST_VIDEO_CAPTURE = 999;
const WRAP_CONTENT = -2;
const ALIGN_PARENT_TOP = 10;
const ALIGN_PARENT_BOTTOM = 12;
const ALIGN_PARENT_LEFT = 9;
const ALIGN_PARENT_RIGHT = 11;
const CENTER_HORIZONTAL = 14;
const DIRECTORY_PICTURES = 'DIRECTORY_PICTURES';
const DIRECTORY_MOVIES = 'DIRECTORY_MOVIES';
const FOCUS_MODE_AUTO = 'auto';
const FOCUS_MODE_EDOF = 'edof';
const FOCUS_MODE_CONTINUOUS_PICTURE = 'continuous-picture';
const FOCUS_MODE_CONTINUOUS_VIDEO = 'continuous-video';
const FLASH_MODE_ON = 'on';
const FLASH_MODE_OFF = 'off';
const CAMERA_FACING_FRONT = 1; // front camera
const CAMERA_FACING_BACK = 0; // rear camera
const RESULT_CODE_PICKER_IMAGES = 941;
const RESULT_OK = -1;
// AndroidX support
// Snapshot-friendly functions
const CAMERA = () => android.Manifest.permission.CAMERA;
const RECORD_AUDIO = () => android.Manifest.permission.RECORD_AUDIO;
const READ_EXTERNAL_STORAGE = () => android.Manifest.permission.READ_EXTERNAL_STORAGE;
const WRITE_EXTERNAL_STORAGE = () => android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
// Since these device.* properties resolve directly to the android.* namespace,
// the snapshot will fail if they resolve during import, so must be done via a function
const DEVICE_INFO_STRING = () => `Device: ${Device.manufacturer} ${Device.model} on SDK: ${Device.sdkVersion}`;
function buildStoragePermissions(ctx) {
let perms;
const version = ctx.getApplicationInfo().targetSdkVersion;
if (version >= 33) {
perms = { photo: {}, video: {} };
}
else if (version >= 30) {
perms = { storage: { read: true, write: false } };
}
else {
perms = { ...perms, storage: { read: true, write: true } };
}
return perms;
}
export class CameraPlus extends CameraPlusBase {
constructor() {
super();
this.flashOnIcon = 'ic_flash_on_white';
this.flashOffIcon = 'ic_flash_off_white';
this.toggleCameraIcon = 'ic_switch_camera_white';
this.confirmPhotos = true;
this.saveToGallery = false;
this.takePicIcon = 'ic_camera_white';
this.galleryIcon = 'ic_photo_library_white';
this.insetButtons = false;
this.insetButtonsPercent = 0.1;
this.enableAudio = true;
this._flashBtn = null; // reference to native flash button
this._takePicBtn = null; // reference to native take picture button
this._toggleCamBtn = null; // reference to native toggle camera button
this._galleryBtn = null; // reference to native open gallery button
this._defaultLens = CameraLens.TelePhoto;
this._togglingCamera = false;
this._camera = null;
this._textureSurface = null;
this.flashOnIcon = this.flashOnIcon ? this.flashOnIcon : 'ic_flash_on_white';
this.flashOffIcon = this.flashOffIcon ? this.flashOffIcon : 'ic_flash_off_white';
this.toggleCameraIcon = this.toggleCameraIcon ? this.toggleCameraIcon : 'ic_switch_camera_white';
this.takePicIcon = this.takePicIcon ? this.takePicIcon : 'ic_camera_alt_white';
this.galleryIcon = this.galleryIcon ? this.galleryIcon : 'ic_photo_library_white';
this.cameraId = CameraPlus.defaultCamera === 'front' ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK;
this._onLayoutChangeListener = this._onLayoutChangeFn.bind(this);
this._permissionListener = this._permissionListenerFn.bind(this);
this._lastCameraOptions = [];
}
isVideoEnabled() {
return this.enableVideo === true || CameraPlus.enableVideo;
}
isAudioEnabled() {
return this.enableAudio === true || CameraPlus.enableAudio;
}
isWideAngleSupported() {
return this._camera?.isWideAngleSupported?.() ?? false;
}
// @ts-ignore
get defaultLens() {
if (this._camera) {
switch (this._camera.getDefaultLens()) {
case io.github.triniwiz.fancycamera.CameraLens.auto:
if (this.isWideAngleSupported()) {
return CameraLens.Auto;
}
else {
return CameraLens.TelePhoto;
}
case io.github.triniwiz.fancycamera.CameraLens.telephoto:
return CameraLens.TelePhoto;
case io.github.triniwiz.fancycamera.CameraLens.wide:
return CameraLens.Wide;
case io.github.triniwiz.fancycamera.CameraLens.ultrawide:
return CameraLens.UltraWide;
}
}
return this._defaultLens;
}
set defaultLens(value) {
this._defaultLens = value;
if (this._camera) {
switch (value) {
case CameraLens.Auto:
if (this.isWideAngleSupported()) {
this._camera.setDefaultLens(io.github.triniwiz.fancycamera.CameraLens.auto);
}
else {
this._camera.setDefaultLens(io.github.triniwiz.fancycamera.CameraLens.telephoto);
}
break;
case CameraLens.TelePhoto:
this._camera.setDefaultLens(io.github.triniwiz.fancycamera.CameraLens.telephoto);
break;
case CameraLens.Wide:
this._camera.setDefaultLens(io.github.triniwiz.fancycamera.CameraLens.wide);
break;
case CameraLens.UltraWide:
this._camera.setDefaultLens(io.github.triniwiz.fancycamera.CameraLens.ultrawide);
break;
}
}
}
// @ts-ignore
get ratio() {
return this._camera ? this._camera.getRatio() : '4:3';
}
set ratio(value) {
if (this._camera) {
this._camera.setRatio(value);
}
}
// @ts-ignore
get zoom() {
return this._camera ? this._camera.getZoom() : 0;
}
set zoom(value) {
if (this._camera) {
this._camera.setZoom(value);
}
}
// @ts-ignore
get pinchToZoom() {
return this._camera?.getEnablePinchZoom() ?? false;
}
set pinchToZoom(value) {
if (this._camera) {
this._camera.setEnablePinchZoom(value);
}
}
// @ts-ignore
get tapToFocus() {
return this._camera?.getEnableTapToFocus() ?? false;
}
set tapToFocus(value) {
if (this._camera) {
this._camera.setEnableTapToFocus(value);
}
}
// @ts-ignore
set whiteBalance(value) {
if (this._camera) {
switch (value) {
case WhiteBalance.Cloudy:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Cloudy);
break;
case WhiteBalance.Fluorescent:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Fluorescent);
break;
case WhiteBalance.Incandescent:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Incandescent);
break;
case WhiteBalance.Shadow:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Shadow);
break;
case WhiteBalance.Sunny:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Sunny);
break;
case WhiteBalance.Twilight:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Twilight);
break;
case WhiteBalance.WarmFluorescent:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.WarmFluorescent);
break;
default:
this._camera.setWhiteBalance(io.github.triniwiz.fancycamera.WhiteBalance.Auto);
break;
}
}
}
get whiteBalance() {
if (this._camera) {
switch (this._camera.getWhiteBalance()) {
case io.github.triniwiz.fancycamera.WhiteBalance.Cloudy:
return WhiteBalance.Cloudy;
case io.github.triniwiz.fancycamera.WhiteBalance.Fluorescent:
return WhiteBalance.Fluorescent;
case io.github.triniwiz.fancycamera.WhiteBalance.Incandescent:
return WhiteBalance.Incandescent;
case io.github.triniwiz.fancycamera.WhiteBalance.Shadow:
return WhiteBalance.Shadow;
case io.github.triniwiz.fancycamera.WhiteBalance.Sunny:
return WhiteBalance.Sunny;
case io.github.triniwiz.fancycamera.WhiteBalance.Twilight:
return WhiteBalance.Twilight;
case io.github.triniwiz.fancycamera.WhiteBalance.WarmFluorescent:
return WhiteBalance.WarmFluorescent;
default:
return WhiteBalance.Auto;
}
}
return WhiteBalance.Auto;
}
/**
* @param ratio get the sizes for a given ratio, i.e. '16:9'.
*/
getAvailablePictureSizes(ratio) {
const sizes = [];
if (this._camera && typeof ratio === 'string') {
const nativeSizes = this._camera.getAvailablePictureSizes(ratio);
if (nativeSizes) {
const length = nativeSizes.length;
for (let i = 0; i < length; i++) {
const size = nativeSizes[i];
sizes.push(`${size.getWidth()}x${size.getHeight()}`);
}
}
}
return sizes;
}
getSupportedRatios() {
const ratios = [];
if (this._camera) {
const nativeRatios = this._camera.getGetSupportedRatios();
for (let i = 0; i < nativeRatios.length; i++) {
const ratio = nativeRatios[i];
ratios.push(ratio);
}
}
return ratios;
}
// @ts-ignore
set pictureSize(value) {
if (this._camera) {
this._camera.setPictureSize(value);
}
}
get pictureSize() {
return this._camera ? this._camera.getPictureSize() : '0x0';
}
get camera() {
return this._camera;
}
/**
* Create the native view
*/
createNativeView() {
// create the Android RelativeLayout
Application.android.on('activityRequestPermissions', this._permissionListener);
this._nativeView = new android.widget.RelativeLayout(this._context);
this._camera = new io.github.triniwiz.fancycamera.FancyCamera(this._context);
this._camera.setLayoutParams(new android.view.ViewGroup.LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT, android.view.ViewGroup.LayoutParams.MATCH_PARENT));
this._camera.setEnableAudio(CameraPlus.enableAudio);
// ensure defaultLens set after camera is created
this.defaultLens = this._defaultLens;
this._nativeView.addView(this._camera);
return this._nativeView;
}
_onLayoutChangeFn(args) {
const size = this.getActualSize();
CLog('xml width/height:', size.width + 'x' + size.height);
this._initDefaultButtons();
}
_permissionListenerFn(args) {
if (this._camera) {
CLog('', this._camera.hasCameraPermission() || this._camera.hasPermission());
if (this._camera.hasCameraPermission() || this._camera.hasPermission()) {
this._camera.startPreview();
}
}
}
initNativeView() {
super.initNativeView();
this.on(View.layoutChangedEvent, this._onLayoutChangeListener);
const listenerImpl = io.github.triniwiz.fancycamera.CameraEventListenerUI.extend({
owner: null,
// eslint-disable-next-line @typescript-eslint/no-empty-function
onReadyUI() { },
// eslint-disable-next-line @typescript-eslint/no-empty-function
onCameraCloseUI() { },
onCameraErrorUI(message, ex) {
console.log('onCameraError', message);
ex.printStackTrace();
const owner = this.owner ? this.owner.get() : null;
if (owner) {
owner._lastCameraOptions.shift();
CLog(message, null);
owner.sendEvent(CameraPlus.errorEvent, null, message);
if (owner.isRecording) {
owner.isRecording = false;
}
}
},
async onCameraPhotoUI(event) {
const owner = this.owner ? this.owner.get() : null;
const file = event;
const options = owner._lastCameraOptions.shift();
let confirmPic;
let confirmPicRetakeText;
let confirmPicSaveText;
let saveToGallery;
let reqWidth;
let reqHeight;
let shouldKeepAspectRatio;
let shouldAutoSquareCrop = owner.autoSquareCrop;
const density = Utils.layout.getDisplayDensity();
if (options) {
confirmPic = options.confirm ? true : false;
confirmPicRetakeText = options.confirmRetakeText ? options.confirmRetakeText : owner.confirmRetakeText;
confirmPicSaveText = options.confirmSaveText ? options.confirmSaveText : owner.confirmSaveText;
saveToGallery = options.saveToGallery ? true : false;
reqWidth = options.width ? options.width * density : 0;
reqHeight = options.height ? options.height * density : reqWidth;
shouldKeepAspectRatio = Utils.isNullOrUndefined(options.keepAspectRatio) ? true : options.keepAspectRatio;
shouldAutoSquareCrop = !!options.autoSquareCrop;
}
else {
// use xml property getters or their defaults
CLog('Using property getters for defaults, no options.');
confirmPic = owner.confirmPhotos;
saveToGallery = owner.saveToGallery;
}
if (confirmPic === true) {
owner.sendEvent(CameraPlus.confirmScreenShownEvent);
const result = await CamHelpers.createImageConfirmationDialog(file.getAbsolutePath(), confirmPicRetakeText, confirmPicSaveText).catch((ex) => {
CLog('Error createImageConfirmationDialog', ex);
});
owner.sendEvent(CameraPlus.confirmScreenDismissedEvent);
CLog(`confirmation result = ${result}`);
if (result !== true) {
file.delete();
return;
}
const asset = CamHelpers.assetFromPath(file.getAbsolutePath(), reqWidth, reqHeight, shouldKeepAspectRatio);
owner.sendEvent(CameraPlus.photoCapturedEvent, asset);
return;
}
else {
const asset = CamHelpers.assetFromPath(file.getAbsolutePath(), reqWidth, reqHeight, shouldKeepAspectRatio);
owner.sendEvent(CameraPlus.photoCapturedEvent, asset);
return;
}
},
onCameraOpenUI() {
const owner = this.owner ? this.owner.get() : null;
if (owner) {
owner._initDefaultButtons();
if (owner._togglingCamera) {
owner.sendEvent(CameraPlus.toggleCameraEvent, owner.camera);
owner._ensureCorrectFlashIcon();
owner._togglingCamera = true;
}
else {
owner.sendEvent('loaded', owner.camera);
}
}
},
onCameraVideoStartUI() {
const owner = this.owner ? this.owner.get() : null;
if (owner) {
owner.isRecording = true;
owner.sendEvent(CameraPlus.videoRecordingStartedEvent, owner.camera);
}
},
onCameraVideoUI(event) {
const owner = this.owner ? this.owner.get() : null;
if (owner) {
owner.sendEvent(CameraPlus.videoRecordingReadyEvent, event.getAbsolutePath());
CLog(`Recording complete`);
owner.isRecording = false;
}
},
// eslint-disable-next-line @typescript-eslint/no-empty-function
onCameraAnalysisUI(imageAnalysis) { },
});
const listener = new listenerImpl();
listener.owner = new WeakRef(this);
this._camera.setListener(listener);
// ensure defaultLens set after camera is created
this.defaultLens = this._defaultLens;
this.cameraId = this._cameraId;
}
disposeNativeView() {
CLog('disposeNativeView.');
this.off(View.layoutChangedEvent, this._onLayoutChangeListener);
Application.android.off('activityRequestPermissions', this._permissionListener);
this.releaseCamera();
super.disposeNativeView();
}
get cameraId() {
return this._cameraId;
}
set cameraId(id) {
if (this._camera) {
switch (id) {
case CAMERA_FACING_FRONT:
this._camera.setPosition(io.github.triniwiz.fancycamera.CameraPosition.FRONT);
this._cameraId = CAMERA_FACING_FRONT;
break;
default:
this._camera.setPosition(io.github.triniwiz.fancycamera.CameraPosition.BACK);
this._cameraId = CAMERA_FACING_BACK;
break;
}
}
this._cameraId = id;
}
/**
* Takes a picture with from the camera preview.
*/
takePicture(options) {
if (this._camera) {
options = options || {};
CLog(JSON.stringify(options));
const hasCamPerm = this.hasCameraPermission();
if (!hasCamPerm) {
CLog('Application does not have permission to use Camera.');
return;
}
if (!!options.useCameraOptions && typeof options.width === 'number' && typeof options.height === 'number') {
this._camera.setOverridePhotoWidth(options.width);
this._camera.setOverridePhotoHeight(options.height);
}
this._camera.setSaveToGallery(!!options.saveToGallery);
this._camera.setAutoSquareCrop(!!options.autoSquareCrop);
this._lastCameraOptions.push(options);
this._camera.takePhoto();
}
}
releaseCamera() {
if (this._camera) {
this._camera.release();
}
}
// @ts-ignore
get autoFocus() {
return this._camera ? this._camera.getAutoFocus() : false;
}
set autoFocus(focus) {
if (this._camera) {
this._camera.setAutoFocus(focus);
}
}
/**
* Toggle the opened camera. Only supported on devices with multiple cameras.
*/
toggleCamera() {
if (this._camera) {
this._togglingCamera = true;
this._camera.toggleCamera();
const camNumber = this.getNumberOfCameras();
if (camNumber <= 1) {
CLog(`Android Device has ${camNumber} camera.`);
return;
}
this.sendEvent(CameraPlus.toggleCameraEvent, this.camera);
// need to check flash mode when toggling...
// front cam may not have flash - and just ensure the correct icon shows
this._ensureCorrectFlashIcon();
// try to set focus mode when camera gets toggled
this._ensureFocusMode();
}
}
async record(options) {
options = options || {};
if (this._camera) {
this._camera.setDisableHEVC(!!options.disableHEVC);
this._camera.setSaveToGallery(!!options.saveToGallery);
switch (options.quality) {
case CameraVideoQuality.HIGHEST:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.HIGHEST);
break;
case CameraVideoQuality.LOWEST:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.LOWEST);
break;
case CameraVideoQuality.MAX_2160P:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.MAX_2160P);
break;
case CameraVideoQuality.MAX_1080P:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.MAX_1080P);
break;
case CameraVideoQuality.MAX_720P:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.MAX_720P);
break;
case CameraVideoQuality.QVGA:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.QVGA);
break;
default:
this._camera.setQuality(io.github.triniwiz.fancycamera.Quality.MAX_480P);
break;
}
// -1 uses profile value;
this._camera.setMaxAudioBitRate(options.androidMaxAudioBitRate || -1);
this._camera.setMaxVideoBitrate(options.androidMaxVideoBitRate || -1);
this._camera.setMaxVideoFrameRate(options.androidMaxFrameRate || -1);
const permResult = await this.requestVideoRecordingPermissions();
CLog(permResult);
if (permResult) {
this._camera.startRecording();
}
}
}
/**
* Stop recording video
*/
stop() {
this.stopRecording();
}
stopRecording() {
if (this._camera) {
CLog(`*** stopping mediaRecorder ***`);
this._camera.stopRecording();
}
}
/**
* Open the device image picker
* @param options
*/
chooseFromLibrary(options) {
return new Promise((resolve, reject) => {
try {
const createThePickerIntent = () => {
const intent = new android.content.Intent();
intent.setType('*/*');
if (!options) {
options = {
showImages: true,
showVideos: this.isVideoEnabled(),
};
}
if (options.showImages === undefined) {
options.showImages = true;
}
if (options.showVideos === undefined) {
options.showVideos = true;
}
let length = 0;
if (options.showImages) {
length++;
}
if (options.showVideos) {
length++;
}
const mimetypes = Array.create(java.lang.String, length);
let index = 0;
if (options.showImages) {
mimetypes[index] = 'image/*';
index++;
}
if (options.showVideos) {
mimetypes[index] = 'video/*';
}
// not in platform-declaration typings
intent.putExtra(android.content.Intent.EXTRA_MIME_TYPES, mimetypes);
intent.setAction('android.intent.action.GET_CONTENT');
// set the multiple picker mode
if (this.galleryPickerMode === 'multiple') {
intent.putExtra('android.intent.extra.ALLOW_MULTIPLE', true);
}
const onImagePickerResultEventListener = (event) => {
if (event.requestCode === RESULT_CODE_PICKER_IMAGES && event.resultCode === RESULT_OK) {
try {
const data = event.intent;
const selectedImages = this.getSelectedImages(data);
this.sendEvent(CameraPlus.imagesSelectedEvent, selectedImages);
resolve(selectedImages);
}
catch (error) {
CLog(error);
this.sendEvent(CameraPlus.errorEvent, error, 'Error with the image picker result.');
reject(error);
}
}
else {
const error = new Error(`Image picker activity result code ${event.resultCode}`);
this.sendEvent(CameraPlus.errorEvent, error, error.message);
reject(error);
}
// Cleanup, remove bound listener.
Application.android.off(AndroidApplication.activityResultEvent, onImagePickerResultEventListener);
};
// Bind listener
Application.android.on(AndroidApplication.activityResultEvent, onImagePickerResultEventListener);
// Start the intent
Application.android.foregroundActivity.startActivityForResult(intent, RESULT_CODE_PICKER_IMAGES);
};
// Ensure storage permissions
if (!this.hasStoragePermissions()) {
permissions.request('storage').then((res) => {
const permType = res[0];
switch (permType) {
case 'authorized':
createThePickerIntent();
break;
default:
{
const error = new Error('request for storage permissions denied');
this.sendEvent(CameraPlus.errorEvent, error, 'Error choosing an image from the device library.');
reject(error);
}
break;
}
});
return;
}
createThePickerIntent();
}
catch (e) {
this.sendEvent(CameraPlus.errorEvent, e, 'Error choosing an image from the device library.');
reject(e);
}
});
}
/**
* Collect images from intent and return a collection of Image Assets.
*
* @param intent
*/
getSelectedImages(intent) {
const selectedImages = [];
const clipData = intent.getClipData();
const imageFromUri = (uri) => {
const selectedAssetUri = new SelectedAsset(uri).fileUri;
return new ImageAsset(selectedAssetUri);
};
if (clipData !== null) {
for (let i = 0; i < clipData.getItemCount(); i++) {
const clipItem = clipData.getItemAt(i);
const uri = clipItem.getUri();
const asset = imageFromUri(uri);
selectedImages.push(asset);
}
}
else {
const uri = intent.getData();
const asset = imageFromUri(uri);
selectedImages.push(asset);
}
return selectedImages;
}
/**
* Toggles the flash mode of the camera.
*/
toggleFlash() {
if (this._camera) {
// @ts-ignore
this._camera.toggleFlash();
}
}
/**
* Request permission to use device camera.
* @param explanation
*/
requestCameraPermissions(explanation = '') {
return new Promise((resolve, reject) => {
permissions
.request('camera')
.then((res) => {
const permType = res[0];
switch (permType) {
case 'authorized':
resolve(true);
break;
default:
resolve(false);
break;
}
})
.catch((err) => {
this.sendEvent(CameraPlus.errorEvent, err, 'Error requesting Camera permissions.');
reject(false);
});
});
}
/**
* Returns true if the CAMERA permission has been granted.
*/
hasCameraPermission() {
return new Promise((resolve) => {
permissions.check('camera').then((res) => {
const permType = res[0];
switch (permType) {
case 'authorized':
resolve(true);
break;
default:
resolve(false);
break;
}
});
});
}
/**
* Request permission to use record audio for video.
* @param explanation
*/
requestAudioPermissions(explanation = '') {
return new Promise((resolve, reject) => {
permissions
.request('microphone')
.then((res) => {
const permType = res[0];
resolve(permType === 'authorized');
})
.catch((err) => {
this.sendEvent(CameraPlus.errorEvent, err, 'Error requesting Audio permission.');
reject(false);
});
});
}
/**
* Returns true if the RECORD_AUDIO permission has been granted.
*/
hasAudioPermission() {
return new Promise((resolve) => {
permissions.check('microphone').then((res) => {
const permType = res[0];
switch (permType) {
case 'authorized':
resolve(true);
break;
default:
resolve(false);
break;
}
});
});
}
/**
* Request permission to read/write to external storage.
* @param explanation
*/
requestStoragePermissions(explanation = '') {
return new Promise((resolve, reject) => {
const ctx = Utils.android.getApplicationContext() ?? this._context;
const version = ctx.getApplicationInfo().targetSdkVersion;
const perms = buildStoragePermissions(ctx);
permissions
.request(perms)
.then((res) => {
if (version >= 33) {
resolve(res?.['photo'] === 'authorized' && res?.['video'] === 'authorized');
}
else if (version >= 30) {
resolve(res?.['android.permission.READ_EXTERNAL_STORAGE'] === 'authorized');
}
else {
resolve(res?.['android.permission.READ_EXTERNAL_STORAGE'] === 'authorized' && res?.['android.permission.WRITE_EXTERNAL_STORAGE'] === 'authorized');
}
})
.catch((err) => {
this.sendEvent(CameraPlus.errorEvent, err, 'Error requesting Storage permissions.');
resolve(false);
});
});
}
/**
* Returns true if the WRITE_EXTERNAL_STORAGE && READ_EXTERNAL_STORAGE permissions have been granted.
*/
async hasStoragePermissions() {
const ctx = Utils.android.getApplicationContext() ?? this._context;
const version = ctx.getApplicationInfo().targetSdkVersion;
const perms = buildStoragePermissions(ctx);
try {
const res = await permissions.checkMultiple(perms);
if (version >= 33) {
return res?.['photo'] === 'authorized' && res?.['video'] === 'authorized';
}
else if (version >= 30) {
return res?.['android.permission.READ_EXTERNAL_STORAGE'] === 'authorized';
}
else {
return res?.['android.permission.READ_EXTERNAL_STORAGE'] === 'authorized' && res?.['android.permission.WRITE_EXTERNAL_STORAGE'] === 'authorized';
}
}
catch (error) {
return false;
}
}
requestVideoRecordingPermissions(explanation = '') {
return new Promise((resolve, reject) => {
const rejectError = (err) => {
this.sendEvent(CameraPlus.errorEvent, err, 'Error requesting Video permissions.');
resolve(false);
};
const perms = {
microphone: {},
camera: {},
};
permissions
.request(perms)
.then((res) => {
resolve(res?.['android.permission.RECORD_AUDIO'] === 'authorized' && res?.['android.permission.CAMERA'] === 'authorized');
})
.catch((err) => {
rejectError(err);
});
});
}
async hasVideoRecordingPermissions() {
try {
const res = await permissions.check('microphone');
return res[0] === 'authorized';
}
catch (error) {
return false;
}
}
/**
* Gets current camera selection
*/
getCurrentCamera() {
if (!this._camera)
return 'rear';
switch (this._camera.getPosition()) {
case io.github.triniwiz.fancycamera.CameraPosition.FRONT:
return 'front';
default:
return 'rear';
}
}
/**
* Check if the device has a camera
*/
isCameraAvailable() {
if (Utils.android.getApplicationContext().getPackageManager().hasSystemFeature('android.hardware.camera')) {
return true;
}
else {
return false;
}
}
/**
* Returns number of cameras on device
*/
getNumberOfCameras() {
if (!this._camera)
return 0;
return this._camera.getNumberOfCameras();
}
/**
* Check if device has flash modes
* @param camera
*/
hasFlash() {
if (!this._camera) {
return false;
}
return this._camera.getHasFlash();
}
/**
* Return the current flash mode of the device. Will return null if the flash mode is not supported by device.
*/
getFlashMode() {
if (this.hasFlash()) {
if (this._camera.getFlashMode() !== io.github.triniwiz.fancycamera.CameraFlashMode.OFF) {
return 'on';
}
return 'off';
}
return null;
}
/**
* Helper method to ensure the correct icon (on/off) is shown on flash.
* Useful when toggling cameras.
*/
_ensureCorrectFlashIcon() {
// get current flash mode and set correct image drawable
const currentFlashMode = this.getFlashMode();
CLog('_ensureCorrectFlashIcon flash mode', currentFlashMode);
// if the flash mode is null then we need to remove the button from the parent layout
if (currentFlashMode === null) {
// if we have the button - remove it from parent
if (this._flashBtn) {
this._flashBtn.setVisibility(android.view.View.GONE);
}
return;
}
// ensure flashBtn is here - if currentFlashMode is null then don't show/assign the flash button
if (this._flashBtn === undefined || this._flashBtn === null) {
return;
}
// make sure we have our flash icon button visible - sometimes toggling might set to GONE
this._flashBtn.setVisibility(android.view.View.VISIBLE);
// reset the image in the button first
this._flashBtn.setImageResource(android.R.color.transparent);
const flashIcon = currentFlashMode === FLASH_MODE_OFF ? this.flashOffIcon : this.flashOnIcon;
const imageDrawable = CamHelpers.getImageDrawable(flashIcon);
this._flashBtn.setImageResource(imageDrawable);
}
_ensureFocusMode() {
// setup autoFocus if possible
}
_initFlashButton() {
this._flashBtn = CamHelpers.createImageButton();
// set correct flash icon on button
this._ensureCorrectFlashIcon();
const shape = CamHelpers.createTransparentCircleDrawable();
this._flashBtn.setBackgroundDrawable(shape);
const ref = new WeakRef(this);
this._flashBtn.setOnClickListener(new android.view.View.OnClickListener({
onClick: (args) => {
const owner = ref.get();
if (owner) {
owner.toggleFlash();
owner._ensureCorrectFlashIcon();
}
},
}));
const flashParams = new android.widget.RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
if (this.insetButtons === true) {
// need to get the width of the screen
const layoutWidth = this._nativeView.getWidth();
CLog(`layoutWidth = ${layoutWidth}`);
const xMargin = layoutWidth * this.insetButtonsPercent;
const layoutHeight = this._nativeView.getHeight();
CLog(`layoutHeight = ${layoutHeight}`);
const yMargin = layoutHeight * this.insetButtonsPercent;
// add margin to left and top where the button is positioned
flashParams.setMargins(xMargin, yMargin, 8, 8);
}
else {
flashParams.setMargins(8, 8, 8, 8);
}
flashParams.addRule(ALIGN_PARENT_TOP);
flashParams.addRule(ALIGN_PARENT_LEFT);
this._nativeView.addView(this._flashBtn, flashParams);
}
_initGalleryButton() {
this._galleryBtn = CamHelpers.createImageButton();
const openGalleryDrawable = CamHelpers.getImageDrawable(this.galleryIcon);
this._galleryBtn.setImageResource(openGalleryDrawable);
const shape = CamHelpers.createTransparentCircleDrawable();
this._galleryBtn.setBackgroundDrawable(shape);
const ref = new WeakRef(this);
this._galleryBtn.setOnClickListener(new android.view.View.OnClickListener({
onClick: (args) => {
const owner = ref.get();
if (owner) {
owner.chooseFromLibrary();
}
},
}));
const galleryParams = new android.widget.RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
if (this.insetButtons === true) {
const layoutWidth = this._nativeView.getWidth();
CLog(`layoutWidth = ${layoutWidth}`);
const xMargin = layoutWidth * this.insetButtonsPercent;
const layoutHeight = this._nativeView.getHeight();
CLog(`layoutHeight = ${layoutHeight}`);
const yMargin = layoutHeight * this.insetButtonsPercent;
// add margin to bottom and left where button is positioned
galleryParams.setMargins(xMargin, 8, 8, yMargin);
}
else {
galleryParams.setMargins(8, 8, 8, 8);
}
galleryParams.addRule(ALIGN_PARENT_BOTTOM);
galleryParams.addRule(ALIGN_PARENT_LEFT);
this._nativeView.addView(this._galleryBtn, galleryParams);
}
_initToggleCameraButton() {
this._toggleCamBtn = CamHelpers.createImageButton();
const switchCameraDrawable = CamHelpers.getImageDrawable(this.toggleCameraIcon);
this._toggleCamBtn.setImageResource(switchCameraDrawable);
const shape = CamHelpers.createTransparentCircleDrawable();
this._toggleCamBtn.setBackgroundDrawable(shape);
const ref = new WeakRef(this);
this._toggleCamBtn.setOnClickListener(new android.view.View.OnClickListener({
onClick: (view) => {
const owner = ref.get();
if (owner) {
owner.toggleCamera();
}
},
}));
const toggleCamParams = new android.widget.RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
if (this.insetButtons === true) {
const layoutWidth = this._nativeView.getWidth();
CLog(`layoutWidth = ${layoutWidth}`);
const xMargin = layoutWidth * this.insetButtonsPercent;
const layoutHeight = this._nativeView.getHeight();
CLog(`layoutHeight = ${layoutHeight}`);
const yMargin = layoutHeight * this.insetButtonsPercent;
toggleCamParams.setMargins(8, yMargin, xMargin, 8);
}
else {
toggleCamParams.setMargins(8, 8, 8, 8);
}
toggleCamParams.addRule(ALIGN_PARENT_TOP);
toggleCamParams.addRule(ALIGN_PARENT_RIGHT);
this._nativeView.addView(this._toggleCamBtn, toggleCamParams);
}
_initTakePicButton() {
this._takePicBtn = CamHelpers.createImageButton();
const takePicDrawable = CamHelpers.getImageDrawable(this.takePicIcon);
this._takePicBtn.setImageResource(takePicDrawable); // set the icon
const shape = CamHelpers.createTransparentCircleDrawable();
this._takePicBtn.setBackgroundDrawable(shape); // set the transparent background
const ref = new WeakRef(this);
this._takePicBtn.setOnClickListener(new android.view.View.OnClickListener({
onClick: (args) => {
CLog(`The default Take Picture event will attempt to save the image to gallery.`);
const opts = {
saveToGallery: true,
confirm: this.confirmPhotos ? true : false,
autoSquareCrop: this.autoSquareCrop,
};
const owner = ref.get();
if (owner) {
owner.takePicture(opts);
}
},
}));
const takePicParams = new android.widget.RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
if (this.insetButtons === true) {
const layoutHeight = this._nativeView.getHeight();
CLog(`layoutHeight = ${layoutHeight}`);
const yMargin = layoutHeight * this.insetButtonsPercent;
takePicParams.setMargins(8, 8, 8, yMargin);
}
else {
takePicParams.setMargins(8, 8, 8, 8);
}
takePicParams.addRule(ALIGN_PARENT_BOTTOM);
takePicParams.addRule(CENTER_HORIZONTAL);
this._nativeView.addView(this._takePicBtn, takePicParams);
}
/**
* Creates the default buttons depending on the options to show the various default buttons.
*/
_initDefaultButtons() {
try {
// flash button setup - if the device doesn't support flash do not setup/show this button
if (this.showFlashIcon === true && this.getFlashMode() !== null && this._flashBtn === null) {
this._initFlashButton();
}
// gallery button setup
if (this.showGalleryIcon === true && this._galleryBtn === null) {
this._initGalleryButton();
}
// camera toggle button setup
if (this.showToggleIcon === true && this.getNumberOfCameras() > 1 && this._toggleCamBtn === null) {
this._initToggleCameraButton();
}
// take picture button setup
if (this.showCaptureIcon === true && this._takePicBtn === null) {
if (this.showFlashIcon === true && this.getFlashMode() !== null && this._flashBtn === null) {
this._initFlashButton();
}
// gallery button setup
if (this.showGalleryIcon === true && this._galleryBtn === null) {
this._initGalleryButton();
}
// camera toggle button setup
if (this.showToggleIcon === true && this.getNumberOfCameras() > 1 && this._toggleCamBtn === null) {
this._initToggleCameraButton();
}
// take picture button setup
if (this.showCaptureIcon === true && this._takePicBtn === null) {
this._initTakePicButton();
}
}
}
catch (ex) {
CLog('_initDefaultButtons error', ex);
}
}
}
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "flashOnIcon", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "flashOffIcon", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "toggleCameraIcon", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "confirmPhotos", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "saveToGallery", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "takePicIcon", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "galleryIcon", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "insetButtons", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "insetButtonsPercent", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Boolean)
], CameraPlus.prototype, "enableVideo", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Boolean)
], CameraPlus.prototype, "isRecording", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Object)
], CameraPlus.prototype, "enableAudio", void 0);
//# sourceMappingURL=index.android.js.map