@nstudio/nativescript-camera-plus
Version:
An advanced, embeddable camera for NativeScript.
1,097 lines • 72 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 { Color, Device, File, ImageAsset, knownFolders, path, Utils, View } from '@nativescript/core';
import { CameraPlusBase, CameraVideoQuality, CLog, GetSetProperty, CameraLens as CLens } from './common';
export * from './common';
export { CameraVideoQuality, WhiteBalance } from './common';
var QBImagePickerControllerDelegateImpl = /** @class */ (function (_super) {
__extends(QBImagePickerControllerDelegateImpl, _super);
function QBImagePickerControllerDelegateImpl() {
return _super !== null && _super.apply(this, arguments) || this;
}
QBImagePickerControllerDelegateImpl.new = function () {
return _super.new.call(this);
};
QBImagePickerControllerDelegateImpl.prototype.initWithCallback = function (owner, callback) {
this._owner = owner;
this._callback = callback;
return this;
};
QBImagePickerControllerDelegateImpl.prototype.initWithCallbackAndOptions = function (owner, callback, options) {
this._owner = owner;
this._callback = callback;
if (options) {
this._width = options.width;
this._height = options.height;
this._keepAspectRatio = Utils.isNullOrUndefined(options.keepAspectRatio) ? true : options.keepAspectRatio;
}
else {
this._keepAspectRatio = true; // always default to true
}
return this;
};
// create date from a string with format yyyy:MM:dd HH:mm:ss (like the format used in image description)
QBImagePickerControllerDelegateImpl.prototype.createDateFromString = function (value) {
var year = parseInt(value.substr(0, 4));
var month = parseInt(value.substr(5, 2));
var date = parseInt(value.substr(8, 2));
var hour = parseInt(value.substr(11, 2));
var minutes = parseInt(value.substr(14, 2));
var seconds = parseInt(value.substr(17, 2));
return new Date(year, month - 1, date, hour, minutes, seconds);
};
QBImagePickerControllerDelegateImpl.prototype.qb_imagePickerControllerDidFinishPickingAssets = function (picker, assets) {
var _this = this;
var selection = [];
var manager = PHImageManager.defaultManager();
// let scale = UIScreen.mainScreen.scale;
var targetSize = PHImageManagerMaximumSize;
var requestOptions = PHImageRequestOptions.alloc().init();
requestOptions.resizeMode = PHImageRequestOptionsResizeMode.Exact;
requestOptions.synchronous = false;
requestOptions.deliveryMode = PHImageRequestOptionsDeliveryMode.HighQualityFormat;
requestOptions.normalizedCropRect = CGRectMake(0, 0, 1, 1);
requestOptions.version = PHImageRequestOptionsVersion.Original;
requestOptions.networkAccessAllowed = true;
var cnt = 0;
var next = function () {
cnt++;
if (cnt === assets.count) {
this._callback(selection);
this._owner.get().closePicker();
}
else {
requestImg(cnt);
}
};
var requestImg = function (i) {
// Do something with the asset
var asset = assets.objectAtIndex(i);
if (asset.mediaType === PHAssetMediaType.Image) {
// ios >= 13 added this api to get the original image
if (manager.requestImageDataAndOrientationForAssetOptionsResultHandler) {
manager.requestImageDataAndOrientationForAssetOptionsResultHandler(asset, requestOptions, function (imageData, dataUti, orientation, info) {
var image = new UIImage({ data: imageData });
var imageAsset = new ImageAsset(image);
if (_this._width)
imageAsset.options.width = _this._width;
if (_this._height)
imageAsset.options.height = _this._height;
imageAsset.options.keepAspectRatio = _this._keepAspectRatio;
selection.push(imageAsset);
next.call(_this);
});
}
else {
manager.requestImageForAssetTargetSizeContentModeOptionsResultHandler(asset, targetSize, PHImageContentMode.AspectFill, requestOptions, function (image, info) {
var imageAsset = new ImageAsset(image);
if (_this._width)
imageAsset.options.width = _this._width;
if (_this._height)
imageAsset.options.height = _this._height;
imageAsset.options.keepAspectRatio = _this._keepAspectRatio;
selection.push(imageAsset);
next.call(_this);
});
}
}
else if (asset.mediaType === PHAssetMediaType.Video) {
var requestOptions_1 = PHVideoRequestOptions.alloc().init();
requestOptions_1.version = PHVideoRequestOptionsVersion.Original;
requestOptions_1.networkAccessAllowed = true;
manager.requestAVAssetForVideoOptionsResultHandler(asset, requestOptions_1, function (videoAsset, audioMix, info) {
if (videoAsset.isKindOfClass(AVURLAsset.class())) {
var docsPath = knownFolders.documents();
var pathParts = videoAsset.URL.toString().split(path.separator);
var filename = pathParts[pathParts.length - 1];
var localFilePath = path.join(docsPath.path, 'camera-plus-videos', filename);
var targetURL = NSURL.fileURLWithPath(localFilePath);
if (File.exists(localFilePath)) {
docsPath.getFile('camera-plus-videos/' + filename).remove();
}
else {
// make sure the folder exists, or else copyItemAtURLToURLError
// will complain about it
docsPath.getFolder('camera-plus-videos');
}
// the video can be compied from gallery only when the request is open
// so we move the video to the documents folder
var result = NSFileManager.defaultManager.copyItemAtURLToURLError(videoAsset.URL, targetURL);
if (result) {
selection.push(localFilePath);
}
}
next.call(_this);
});
}
};
requestImg(0);
};
QBImagePickerControllerDelegateImpl.prototype.qb_imagePickerControllerDidCancel = function (picker) {
this._owner.get().closePicker();
};
QBImagePickerControllerDelegateImpl.ObjCProtocols = [QBImagePickerControllerDelegate];
return QBImagePickerControllerDelegateImpl;
}(NSObject));
var SwiftyDelegate = /** @class */ (function (_super) {
__extends(SwiftyDelegate, _super);
function SwiftyDelegate() {
return _super !== null && _super.apply(this, arguments) || this;
}
SwiftyDelegate.initWithOwner = function (owner) {
var delegate = SwiftyDelegate.new();
delegate._owner = owner;
return delegate;
};
SwiftyDelegate.prototype.swiftyCamDidFailToConfigure = function (swiftyCam) {
CLog('swiftyCamDidFailToConfigure:');
};
SwiftyDelegate.prototype.swiftyCamDidFailToRecordVideo = function (swiftyCam, error) {
CLog('swiftyCamDidFailToRecordVideo:');
};
SwiftyDelegate.prototype.swiftyCamNotAuthorized = function (swiftyCam) {
CLog('swiftyCamNotAuthorized:');
};
SwiftyDelegate.prototype.swiftyCamSessionDidStopRunning = function (swiftyCam) {
CLog('swiftyCamSessionDidStopRunning:');
};
SwiftyDelegate.prototype.swiftyCamSessionDidStartRunning = function (swiftyCam) {
CLog('swiftyCamSessionDidStartRunning:');
this._owner.get().doLayout();
};
SwiftyDelegate.prototype.swiftyCamDidBeginRecordingVideo = function (swiftyCam, camera) {
CLog('swiftyCamDidBeginRecordingVideo:', camera);
this._owner.get().didStartRecording(camera);
};
SwiftyDelegate.prototype.swiftyCamDidChangeZoomLevel = function (swiftyCam, zoom) {
CLog('swiftyCamDidChangeZoomLevel:', zoom);
};
SwiftyDelegate.prototype.swiftyCamDidFinishProcessVideoAt = function (swiftyCam, url) {
CLog('swiftyCamDidFinishProcessVideoAt:', url);
this._owner.get().recordingReady(url.path);
};
SwiftyDelegate.prototype.swiftyCamDidFinishRecordingVideo = function (swiftyCam, camera) {
CLog('swiftyCamDidFinishRecordingVideo:', camera);
this._owner.get().didFinishRecording(camera);
};
SwiftyDelegate.prototype.swiftyCamDidFocusAtPoint = function (swiftyCam, point) {
CLog('swiftyCamDidFocusAtPoint:', point);
};
SwiftyDelegate.prototype.swiftyCamDidSwitchCameras = function (swiftyCam, camera) {
CLog('swiftyCamDidSwitchCameras:', camera);
this._owner.get().didSwitchCamera(camera);
};
SwiftyDelegate.prototype.swiftyCamDidTake = function (swiftyCam, photo) {
CLog('swiftyCamDidTake:', photo);
try {
// UIImageWriteToSavedPhotosAlbum(photo, this._owner.get(), 'thisImage:hasBeenSavedInPhotoAlbumWithError:usingContextInfo:', null);
this._owner.get().tookPhoto(photo);
}
catch (err) {
CLog(err);
}
};
SwiftyDelegate.ObjCProtocols = [SwiftyCamViewControllerDelegate];
return SwiftyDelegate;
}(NSObject));
const MySwifty = SwiftyCamViewController.extend({
cleanup() {
this._swiftyDelegate = null;
},
set enableVideo(value) {
this._enableVideo = value;
},
set pickerDelegate(value) {
this._pickerDelegate = value;
},
closePicker() {
Utils.dispatchToMainThread(() => {
rootVC().dismissViewControllerAnimatedCompletion(true, () => {
this.pickerDelegate = null;
});
});
},
viewDidLoad() {
CLog('MySwifty viewdidload');
super.viewDidLoad();
const owner = this._owner && this._owner.get();
if (owner) {
owner._updatePhotoQuality();
}
this.view.userInteractionEnabled = true;
const doubleTapEnabled = this._owner.get().doubleTapCameraSwitch;
this.doubleTapCameraSwitch = doubleTapEnabled;
CLog('doubleTapCameraSwitch:', doubleTapEnabled);
// CLog('view.frame.size:', this.view.frame.size.width + 'x' + this.view.frame.size.height);
// retain delegate in javascript to ensure garbage collector does not get it
this._swiftyDelegate = SwiftyDelegate.initWithOwner(new WeakRef(this));
this.cameraDelegate = this._swiftyDelegate;
CLog('this.cameraDelegate:', this.cameraDelegate);
},
doLayout() {
const size = this._owner.get().getActualSize();
const nativeView = this._owner.get().nativeView;
const frame = nativeView.frame;
nativeView.frame = CGRectMake(frame.origin.x, frame.origin.y, size.width, size.height);
nativeView.setNeedsLayout();
},
viewDidLayoutSubviews() {
CLog('MySwifty viewDidLayoutSubviews');
super.viewDidLayoutSubviews();
},
viewDidAppear(animated) {
super.viewDidAppear(animated);
CLog('MySwifty viewDidAppear');
},
viewWillAppear(animated) {
super.viewWillAppear(animated);
CLog('MySwifty viewWillAppear');
},
// public deviceDidRotate() {
// super.deviceDidRotate();
// CLog('deviceDidRotate!');
// if (this.previewLayer && this.previewLayer.videoPreviewLayer) {
// this.previewLayer.videoPreviewLayer.connection.videoOrientation = this.getPreviewLayerOrientation();
// }
// }
// public resize(width?: any, height?: any) {
// if (typeof width !== 'number') {
// width = screen.mainScreen.widthDIPs;
// }
// if (typeof height !== 'number') {
// height = screen.mainScreen.heightDIPs;
// }
// CLog('resizing to:', width + 'x' + height);
// this.view.frame = CGRectMake(0, 0, width, height);
// CLog('view.bounds:', this.view.bounds.size.width + 'x' + this.view.bounds.size.height);
// if (!this._resized) {
// this._resized = true;
// this._addButtons();
// this.viewDidAppear(true);
// }
// }
snapPicture(options) {
CLog('CameraPlus takePic options:', options);
if (options) {
this._snapPicOptions = options;
}
else {
this._snapPicOptions = {
confirm: this._owner.get().confirmPhotos, // from property setter
confirmRetakeText: this._owner.get().confirmRetakeText,
confirmSaveText: this._owner.get().confirmSaveText,
saveToGallery: this._owner.get().saveToGallery,
};
}
this.takePhoto();
},
recordVideo(options) {
options = options || {};
if (this._enableVideo) {
if (this.isVideoRecording) {
CLog('CameraPlus stop video recording.');
this.stopVideoRecording();
}
else {
CLog('CameraPlus record video options:', options);
if (options) {
this._videoOptions = options;
}
else {
this._videoOptions = {
confirm: this._owner.get().confirmVideo, // from property setter
saveToGallery: this._owner.get().saveToGallery,
};
}
if (!this._videoOptions.disableHEVC && parseFloat(Device.sdkVersion) >= 11) {
this.videoCodecType = AVVideoCodecTypeHEVC;
}
switch (this._videoOptions.quality) {
case CameraVideoQuality.MAX_2160P:
this.videoQuality = 7 /* VideoQuality.Resolution3840x2160 */;
break;
case CameraVideoQuality.MAX_1080P:
this.videoQuality = 6 /* VideoQuality.Resolution1920x1080 */;
break;
case CameraVideoQuality.MAX_720P:
this.videoQuality = 5 /* VideoQuality.Resolution1280x720 */;
break;
case CameraVideoQuality.HIGHEST:
this.videoQuality = 0 /* VideoQuality.High */;
break;
case CameraVideoQuality.LOWEST:
this.videoQuality = 2 /* VideoQuality.Low */;
break;
case CameraVideoQuality.QVGA:
this.videoQuality = 3 /* VideoQuality.Resolution352x288 */;
break;
default:
this.videoQuality = 4 /* VideoQuality.Resolution640x480 */;
break;
}
const status = PHPhotoLibrary.authorizationStatus();
if (status === 0 /* PHAuthorizationStatus.NotDetermined */) {
PHPhotoLibrary.requestAuthorization(() => {
this.startVideoRecording();
});
}
else {
this.startVideoRecording();
}
}
}
},
didStartRecording(camera) {
this._owner.get().sendEvent(CameraPlus.videoRecordingStartedEvent, camera);
},
recordingReady(recordingPath) {
CLog(`recordingReady path: ${recordingPath}`);
const configSaveToGallery = this._videoOptions.saveToGallery || this._owner.get().saveToGallery;
if (configSaveToGallery) {
CLog(`recordingReady saveToGallery ${configSaveToGallery}`);
// TODO: discuss why callback handler(videoDidFinishSavingWithErrorContextInfo) does not emit event correctly - the path passed to the handler is the same as handled here so just go ahead and emit here for now
this._owner.get().sendEvent(CameraPlus.videoRecordingReadyEvent, recordingPath);
const status = PHPhotoLibrary.authorizationStatus();
if (status === 3 /* PHAuthorizationStatus.Authorized */) {
UISaveVideoAtPathToSavedPhotosAlbum(recordingPath, this, 'videoDidFinishSavingWithErrorContextInfo', null);
}
}
else {
CLog(`video not saved to gallery but recording is at: ${recordingPath}`);
this._owner.get().sendEvent(CameraPlus.videoRecordingReadyEvent, recordingPath);
}
},
didFinishRecording(camera) {
this._owner.get().sendEvent(CameraPlus.videoRecordingFinishedEvent, camera);
},
videoDidFinishSavingWithErrorContextInfo(vidPath, error, contextInfo) {
if (error) {
CLog('video save to camera roll error:');
CLog(error);
return;
}
CLog(`video saved`, vidPath);
// ideally could just rely on this, but this will not emit the event (commenting for now and instead doing above in recordready - TODO: discuss why)
// this._owner.get().sendEvent(CameraPlus.videoRecordingReadyEvent, path);
},
switchCam() {
CLog('CameraPlus switchCam');
this.switchCamera();
},
toggleFlash() {
this._flashEnabled = !this._flashEnabled;
this.flashEnabled = this._flashEnabled; // super class behavior
CLog('CameraPlus flash enabled:', this._flashEnabled);
this._flashBtnHandler();
},
openGallery() {
CLog('CameraPlus openGallery');
const width = this._owner.get().galleryPickerWidth;
const height = this._owner.get().galleryPickerHeight;
const keepAspectRatio = this._owner.get().keepAspectRatio;
const showVideos = this._enableVideo;
this.chooseFromLibrary({ width, height, keepAspectRatio, showVideos });
},
// public thisImageHasBeenSavedInPhotoAlbumWithErrorUsingContextInfo(image, error, context) {
// CLog('thisImageHasBeenSavedInPhotoAlbumWithErrorUsingContextInfo', image);
// if (error) {
// CLog(error);
// }
// }
tookPhoto(photo) {
this._photoToSave = photo;
CLog('tookPhoto!');
if (this._snapPicOptions && this._snapPicOptions.autoSquareCrop) {
const width = photo.size.width;
const height = photo.size.height;
let originalWidth = width;
let originalHeight = height;
let x = 0;
let y = 0;
if (originalWidth < originalHeight) {
x = (originalHeight - originalWidth) / 2;
originalHeight = originalWidth;
}
else {
y = (originalWidth - originalHeight) / 2;
originalWidth = originalHeight;
}
const rect = CGRectMake(x, y, originalWidth, originalHeight);
const ref = CGImageCreateWithImageInRect(photo.CGImage, rect);
this._photoToSave = UIImage.imageWithCGImageScaleOrientation(ref, photo.scale, photo.imageOrientation);
CGImageRelease(ref);
}
if (this._snapPicOptions && this._snapPicOptions.confirm) {
// show the confirmation
const safeAreaWidthOffset = this.view.safeAreaInsets ? this.view.safeAreaInsets.left + this.view.safeAreaInsets.right : 0;
const safeAreaHeightOffset = this.view.safeAreaInsets ? this.view.safeAreaInsets.bottom + this.view.safeAreaInsets.top : 0;
const safeAreaLeft = this.view.safeAreaInsets ? this.view.safeAreaInsets.left : 0;
const safeAreaTop = this.view.safeAreaInsets ? this.view.safeAreaInsets.top : 0;
const width = this.view.bounds.size.width - safeAreaWidthOffset;
const height = this.view.bounds.size.height - safeAreaHeightOffset;
this._imageConfirmBg = UIView.alloc().initWithFrame(CGRectMake(safeAreaLeft, safeAreaTop, width, height));
this._imageConfirmBg.backgroundColor = UIColor.blackColor;
// confirm user wants to keep photo
const imageConfirm = UIImageView.alloc().init();
imageConfirm.contentMode = 1 /* UIViewContentMode.ScaleAspectFit */;
imageConfirm.image = this._photoToSave;
imageConfirm.frame = CGRectMake(0, 50, width, height - 50);
// add 'Retake' in bottom left and 'Save Photo' in bottom right
const retakeBtn = createButton(this, CGRectMake(10, 10, 75, 50), this._snapPicOptions.confirmRetakeText ? this._snapPicOptions.confirmRetakeText : 'Retake', 'resetPreview');
const saveBtn = createButton(this, CGRectMake(width - 170, 10, 150, 50), this._snapPicOptions.confirmSaveText ? this._snapPicOptions.confirmSaveText : 'Save', 'savePhoto', 'right');
this._imageConfirmBg.addSubview(imageConfirm);
this._imageConfirmBg.addSubview(retakeBtn);
this._imageConfirmBg.addSubview(saveBtn);
this.view.addSubview(this._imageConfirmBg);
this._owner.get().sendEvent(CameraPlus.confirmScreenShownEvent);
}
else {
// no confirmation - just save
this.savePhoto();
return;
}
},
resetPreview() {
if (this._imageConfirmBg) {
this._imageConfirmBg.removeFromSuperview();
this._imageConfirmBg = null;
this._owner.get().sendEvent(CameraPlus.confirmScreenDismissedEvent);
}
},
savePhoto() {
if (this._photoToSave) {
const asset = new ImageAsset(this._photoToSave);
const useCameraOptions = this._snapPicOptions ? this._snapPicOptions.useCameraOptions : false;
const handleSuccess = () => {
this._owner.get().sendEvent(CameraPlus.photoCapturedEvent, asset);
this.resetPreview();
};
if (!useCameraOptions) {
if ((this._snapPicOptions && this._snapPicOptions.saveToGallery) || this._owner.get().saveToGallery) {
UIImageWriteToSavedPhotosAlbum(this._photoToSave, null, null, null);
}
}
if (this._snapPicOptions) {
if (typeof this._snapPicOptions.keepAspectRatio === 'boolean') {
asset.options.keepAspectRatio = this._snapPicOptions.keepAspectRatio;
}
if (typeof this._snapPicOptions.height === 'number') {
asset.options.height = this._snapPicOptions.height;
}
if (typeof this._snapPicOptions.width === 'number') {
asset.options.width = this._snapPicOptions.width;
}
}
if (!useCameraOptions) {
handleSuccess();
}
else {
if ((this._snapPicOptions && this._snapPicOptions.saveToGallery) || this._owner.get().saveToGallery) {
asset.getImageAsync((image, error) => {
if (image) {
UIImageWriteToSavedPhotosAlbum(image, null, null, null);
handleSuccess();
}
else {
CLog(`Failed to save image: ${error}`);
}
});
}
}
}
},
didSwitchCamera(camera) {
this._owner.get().sendEvent(CameraPlus.toggleCameraEvent, camera);
},
isCameraAvailable() {
return UIImagePickerController.isSourceTypeAvailable(1 /* UIImagePickerControllerSourceType.Camera */);
},
chooseFromLibrary(options) {
return new Promise((resolve, reject) => {
this._pickerDelegate = null;
const imagePickerController = QBImagePickerController.new();
let reqWidth = 0;
let reqHeight = 0;
let keepAspectRatio = true;
if (options) {
reqWidth = options.width || reqWidth;
reqHeight = options.height || reqHeight;
keepAspectRatio = Utils.isNullOrUndefined(options.keepAspectRatio) ? true : options.keepAspectRatio;
}
else {
options = {
showImages: true,
showVideos: this._enableVideo,
};
}
const authStatus = PHPhotoLibrary.authorizationStatus();
if (reqWidth && reqHeight) {
this._pickerDelegate = QBImagePickerControllerDelegateImpl.new().initWithCallbackAndOptions(new WeakRef(this), (result) => {
CLog('chosen from library:', result);
this._owner.get().sendEvent(CameraPlus.imagesSelectedEvent, result);
resolve(result);
}, { width: reqWidth, height: reqHeight, keepAspectRatio: keepAspectRatio });
}
else {
this._pickerDelegate = QBImagePickerControllerDelegateImpl.new().initWithCallback(new WeakRef(this), (result) => {
CLog('chosen from library:', result);
this._owner.get().sendEvent(CameraPlus.imagesSelectedEvent, result);
resolve(result);
});
}
imagePickerController.delegate = this._pickerDelegate;
const galleryPickerMode = this._owner.get().galleryPickerMode;
CLog('galleryPickerMode:', galleryPickerMode);
const galleryMax = this._owner.get().galleryMax;
CLog('galleryMax:', galleryMax);
imagePickerController.allowsMultipleSelection = galleryPickerMode === 'multiple';
imagePickerController.maximumNumberOfSelection = galleryMax;
imagePickerController.showsNumberOfSelectedAssets = true;
imagePickerController.modalPresentationStyle = 3 /* UIModalPresentationStyle.CurrentContext */;
let mediaType = 0 /* QBImagePickerMediaType.Any */;
if (options.showImages === undefined) {
options.showImages = true;
}
if (!options.showImages && options.showVideos) {
mediaType = 2 /* QBImagePickerMediaType.Video */;
}
else {
if (options.showImages && !options.showVideos) {
mediaType = 1 /* QBImagePickerMediaType.Image */;
}
}
imagePickerController.mediaType = mediaType;
rootVC().presentViewControllerAnimatedCompletion(imagePickerController, true, null);
});
},
_addButtons() {
CLog('adding buttons...');
const width = this.view.bounds.size.width;
const height = this.view.bounds.size.height;
if (this._owner.get().showToggleIcon) {
CLog('adding toggle/switch camera button...');
const switchCameraBtn = createButton(this, CGRectMake(width - 100, 20, 100, 50), null, 'switchCam', null, createIcon('toggle', CGSizeMake(65, 50)));
switchCameraBtn.transform = CGAffineTransformMakeScale(0.75, 0.75);
this.view.addSubview(switchCameraBtn);
}
this._flashBtnHandler();
if (this._owner.get().showGalleryIcon === true) {
CLog('adding show gallery button...');
const galleryBtn = createButton(this, CGRectMake(20, height - 80, 50, 50), null, 'openGallery', null, createIcon('gallery'));
galleryBtn.transform = CGAffineTransformMakeScale(0.75, 0.75);
this.view.addSubview(galleryBtn);
}
if (this._owner.get().showCaptureIcon) {
CLog('adding show capture button...');
const heightOffset = this._owner.get().isIPhoneX ? 200 : 110;
const picOutline = createButton(this, CGRectMake(width / 2 - 20, height - heightOffset, 50, 50), null, null, null, createIcon('picOutline'));
picOutline.transform = CGAffineTransformMakeScale(1.5, 1.5);
this.view.addSubview(picOutline);
const takePicBtn = createButton(this, CGRectMake(width / 2 - 21.5, height - (heightOffset + 0.7), 50, 50), null, this._enableVideo ? 'recordVideo' : 'snapPicture', null, createIcon('takePic'));
// takePicBtn.transform = CGAffineTransformMakeScale(1.5, 1.5);
this.view.addSubview(takePicBtn);
}
},
_flashBtnHandler() {
if (this._owner.get().showFlashIcon) {
CLog('adding flash button...');
if (this._flashBtn)
this._flashBtn.removeFromSuperview();
if (this.flashEnabled) {
this._flashBtn = createButton(this, CGRectMake(20, 20, 50, 50), null, 'toggleFlash', null, createIcon('flash'));
}
else {
this._flashBtn = createButton(this, CGRectMake(20, 20, 50, 50), null, 'toggleFlash', null, createIcon('flashOff'));
}
this._flashBtn.transform = CGAffineTransformMakeScale(0.75, 0.75);
this.view.addSubview(this._flashBtn);
}
},
}, {
exposedMethods: {
switchCam: { returns: interop.types.void },
resetPreview: { returns: interop.types.void },
savePhoto: { returns: interop.types.void },
snapPicture: { returns: interop.types.void },
toggleFlash: { returns: interop.types.void },
openGallery: { returns: interop.types.void },
recordVideo: { returns: interop.types.void },
videoDidFinishSavingWithErrorContextInfo: {
returns: interop.types.void,
params: [NSString, NSError, interop.Pointer],
},
},
});
MySwifty['initWithOwner'] = function (owner, defaultCamera = 'rear') {
CLog('MySwifty initWithOwner');
// const ctrl: MySwifty = <MySwifty>MySwifty.alloc().init();
const ctrl = MySwifty.new();
CLog('view', ctrl);
CLog('ctrl', ctrl);
ctrl._owner = owner;
// set default camera
ctrl.defaultCamera = defaultCamera === 'rear' ? 0 /* CameraSelection.Rear */ : 1 /* CameraSelection.Front */;
CLog('ctrl.disableAudio:', ctrl.disableAudio);
CLog('ctrl.defaultCamera:', defaultCamera);
return ctrl;
};
export class CameraPlus extends CameraPlusBase {
constructor() {
super();
this.enableAudio = true;
// library picker handling
this._galleryMax = 3;
this._pictureQuality = 'High';
CLog('CameraPlus constructor');
this._onLayoutChangeListener = this._onLayoutChangeFn.bind(this);
this._swifty = MySwifty.initWithOwner(new WeakRef(this), CameraPlus.defaultCamera);
this._swifty.shouldPrompToAppSettings = false;
// experimenting with static flag (this is usually explicitly false)
// enable device orientation
this._swifty.shouldUseDeviceOrientation = CameraPlus.useDeviceOrientation;
this._detectDevice();
}
isVideoEnabled() {
return this.enableVideo === true || CameraPlus.enableVideo;
}
isAudioEnabled() {
return this.enableAudio === true || CameraPlus.enableAudio;
}
isWideAngleSupported() {
if (Utils.ios.MajorVersion >= 13) {
return true;
}
return false;
}
// @ts-ignore
get defaultLens() {
if (this._swifty) {
switch (this._swifty.defaultLens) {
case 0 /* CameraLens.Auto */:
return CLens.Auto;
case 1 /* CameraLens.Telephoto */:
return CLens.TelePhoto;
case 2 /* CameraLens.Wide */:
return CLens.Wide;
case 3 /* CameraLens.Ultrawide */:
return CLens.UltraWide;
}
}
return CLens.TelePhoto;
}
set defaultLens(value) {
if (this._swifty) {
switch (value) {
case CLens.Auto:
this._swifty.defaultLens = 0 /* CameraLens.Auto */;
break;
case CLens.TelePhoto:
this._swifty.defaultLens = 1 /* CameraLens.Telephoto */;
break;
case CLens.Wide:
this._swifty.defaultLens = 2 /* CameraLens.Wide */;
break;
case CLens.UltraWide:
this._swifty.defaultLens = 3 /* CameraLens.Ultrawide */;
break;
}
}
}
createNativeView() {
// this._swifty.videoGravity = SwiftyCamVideoGravity.ResizeAspectFill;
const videoEnabled = this.isVideoEnabled();
this._swifty.enableVideo = videoEnabled;
if (!videoEnabled) {
// disable audio if no video support
this._swifty.disableAudio = !this.isVideoEnabled();
}
else {
this._swifty.disableAudio = !this.isAudioEnabled();
}
CLog('CameraPlus createNativeView');
CLog('video enabled:', this.isVideoEnabled());
CLog('default camera:', CameraPlus.defaultCamera);
CLog('view:', this._swifty.view);
this._swifty.view.autoresizingMask = 2 /* UIViewAutoresizing.FlexibleWidth */ | 16 /* UIViewAutoresizing.FlexibleHeight */;
return this._swifty.view;
}
get cropByPreview() {
return this._cropByPreview;
}
set cropByPreview(value) {
if (typeof value === 'string') {
value = Boolean(value);
}
if (typeof value === 'boolean') {
if (this._swifty) {
this._swifty.cropByPreview = value;
}
}
this._cropByPreview = value;
}
// @ts-ignore
get pinchToZoom() {
return this._swifty?.pinchToZoom ?? false;
}
set pinchToZoom(value) {
if (this._swifty) {
this._swifty.pinchToZoom = value;
}
}
// @ts-ignore
get tapToFocus() {
return this._swifty?.tapToFocus ?? false;
}
set tapToFocus(value) {
if (this._swifty) {
this._swifty.tapToFocus = value;
}
}
_updatePhotoQuality() {
if (this._swifty) {
switch (this._pictureQuality) {
case '3840x2160':
this._swifty.videoQuality = 7 /* VideoQuality.Resolution3840x2160 */;
this._pictureQuality = '3840x2160';
break;
case '1920x1080':
this._swifty.videoQuality = 6 /* VideoQuality.Resolution1920x1080 */;
this._pictureQuality = '1920x1080';
break;
case '1280x720':
this._swifty.videoQuality = 5 /* VideoQuality.Resolution1280x720 */;
this._pictureQuality = '1280x720';
break;
case '640x480':
this._swifty.videoQuality = 4 /* VideoQuality.Resolution640x480 */;
this._pictureQuality = '640x480';
break;
case '352x288':
this._swifty.videoQuality = 3 /* VideoQuality.Resolution352x288 */;
this._pictureQuality = '352x288';
break;
case 'Medium':
this._swifty.videoQuality = 1 /* VideoQuality.Medium */;
this._pictureQuality = 'Medium';
break;
case 'Low':
this._swifty.videoQuality = 2 /* VideoQuality.Low */;
this._pictureQuality = 'Low';
break;
case 'Photo':
this._swifty.videoQuality = 10 /* VideoQuality.Photo */;
this._pictureQuality = 'Photo';
break;
default:
this._swifty.videoQuality = 0 /* VideoQuality.High */;
this._pictureQuality = 'High';
break;
}
}
}
getAvailablePictureSizes(ratio) {
return ['3840x2160', '1920x1080', '1280x720', '640x480', '352x288', 'Photo', 'High', 'Medium', 'Low'];
}
// @ts-ignore
set pictureSize(value) {
this._pictureQuality = value;
this._updatePhotoQuality();
}
get pictureSize() {
return this._pictureQuality;
}
_onLayoutChangeFn(args) {
if (this._swifty && this._swifty.view) {
const size = this.getActualSize();
CLog(`xml width/height: ${size.width}x${size.height}`);
const frame = this._swifty.view.frame;
this._swifty.view.frame = CGRectMake(frame.origin.x, frame.origin.y, size.width, size.height);
if (this._swifty.previewLayer) {
this._swifty.previewLayer.frame = CGRectMake(frame.origin.x, frame.origin.y, size.width, size.height);
this._swifty.view.setNeedsLayout();
this._swifty.previewLayer.setNeedsLayout();
}
}
}
initNativeView() {
CLog('initNativeView.');
this.on(View.layoutChangedEvent, this._onLayoutChangeListener);
this._updatePhotoQuality();
if (this.cropByPreview) {
this._swifty.cropByPreview = this.cropByPreview;
}
this._swifty.viewWillAppear(true);
}
disposeNativeView() {
CLog('disposeNativeView.');
this._swifty.cleanup();
this.off(View.layoutChangedEvent, this._onLayoutChangeListener);
super.disposeNativeView();
}
onLoaded() {
super.onLoaded();
this._swifty._addButtons();
this._swifty.viewDidAppear(true);
}
onUnloaded() {
this._swifty.viewDidDisappear(true);
super.onUnloaded();
}
get isIPhoneX() {
return this._isIPhoneX;
}
get galleryPickerWidth() {
return this._galleryPickerWidth;
}
set galleryPickerWidth(value) {
this._galleryPickerWidth = value;
}
get galleryPickerHeight() {
return this._galleryPickerHeight;
}
set galleryPickerHeight(value) {
this._galleryPickerHeight = value;
}
get keepAspectRatio() {
return this._keepAspectRatio;
}
set keepAspectRatio(value) {
this._keepAspectRatio = value;
}
get galleryMax() {
return this._galleryMax;
}
set galleryMax(value) {
this._galleryMax = value;
}
/**
* Toggle Camera front/back
*/
toggleCamera() {
this._swifty.switchCam();
}
/**
* Toggle flash mode
*/
toggleFlash() {
this._swifty.toggleFlash();
}
/**
* Return the current flash mode (either 'on' or 'off' for iOS)
*/
getFlashMode() {
return this._swifty.flashEnabled ? 'on' : 'off';
}
/**
* Open library picker
* @param options IChooseOptions
*/
chooseFromLibrary(options) {
return this._swifty.chooseFromLibrary(options);
}
/**
* Snap photo and display confirm save
*/
takePicture(options) {
this._updatePhotoQuality();
this._swifty.snapPicture(options);
}
/**
* Record video
*/
record(options) {
if (this.isVideoEnabled()) {
CLog(`Start Video Recording: ${options && JSON.stringify(options)}`);
this._swifty.recordVideo(options);
}
return Promise.resolve();
}
/**
* Stop recording video
*/
stop() {
if (this.isVideoEnabled()) {
CLog('Stop Video Recording');
this._swifty.stopVideoRecording();
}
}
/**
* Gets current camera selection
*/
getCurrentCamera() {
const cam = this._swifty.currentCamera;
if (cam === 1 /* CameraSelection.Front */) {
return 'front';
}
else {
return 'rear';
}
}
/**
* Is camera available for use
*/
isCameraAvailable() {
return this._swifty.isCameraAvailable();
}
_detectDevice() {
if (typeof this._isIPhoneX === 'undefined') {
/* tslint:disable-next-line: no-any */
let name = NSCCamplusHelpers.getDeviceIdentifier();
// Get machine name for Simulator
if (name === 'x86_64' || name === 'i386' || name === 'arm64') {
name = NSProcessInfo.processInfo.environment.objectForKey('SIMULATOR_MODEL_IDENTIFIER');
}
// this._log.debug('isIPhoneX name:', name);
const parts = name.toLowerCase().split('iphone');
if (parts && parts.length > 1) {
const versionNumber = parseInt(parts[1]);
if (!isNaN(versionNumber)) {
// all above or greater than 11 are X devices
this._isIPhoneX = versionNumber >= 11;
}
}
if (!this._isIPhoneX) {
// consider iphone x global and iphone x gsm
this._isIPhoneX = name.indexOf('iPhone10,3') === 0 || name.indexOf('iPhone10,6') === 0;
}
}
}
}
CameraPlus.useDeviceOrientation = false; // experimental
__decorate([
GetSetProperty(),
__metadata("design:type", Boolean)
], CameraPlus.prototype, "enableVideo", void 0);
__decorate([
GetSetProperty(),
__metadata("design:type", Boolean)
], CameraPlus.prototype, "enableAudio", void 0);
const rootVC = function () {
const appWindow = UIApplication.sharedApplication.keyWindow;
return Utils.ios.getVisibleViewController(appWindow.rootViewController);
};
const createButton = function (target, frame, label, eventName, align, img, imgSelected) {
let btn;
if (frame) {
btn = UIButton.alloc().initWithFrame(frame);
}
else {
btn = UIButton.alloc().init();
}
if (label) {
btn.setTitleForState(label, 0 /* UIControlState.Normal */);
btn.setTitleColorForState(new Color('#fff').ios, 0 /* UIControlState.Normal */);
btn.titleLabel.font = UIFont.systemFontOfSize(19);
}
else if (img) {
btn.setImageForState(img, 0 /* UIControlState.Normal */);
if (imgSelected) {
btn.setImageForState(img, 1 /* UIControlState.Highlighted */);
btn.setImageForState(img, 4 /* UIControlState.Selected */);
}
}
if (align) {
btn.contentHorizontalAlignment = align === 'right' ? 2 /* UIControlContentHorizontalAlignment.Right */ : 1 /* UIControlContentHorizontalAlignment.Left */;
// if (align == 'right') {
// btn.contentEdgeInsets = UIEdgeInsetsMake(0, 10, 0, 0);
// }
}
if (eventName) {
btn.addTargetActionForControlEvents(target, eventName, 64 /* UIControlEvents.TouchUpInside */);
}
return btn;
};
const addShadow = function (button) {
button.layer.shadowColor = UIColor.blackColor.CGColor;
button.layer.shadowOffset = CGSizeMake(0, 0);
button.layer.shadowRadius = 5;
button.layer.shadowOpacity = 1;
};
const createIcon = function (type, size, color) {
switch (type) {
case 'flash':
UIGraphicsBeginImageContextWithOptions(size || CGSizeMake(50, 50), false, 0);
drawFlash(color);
break;
case 'flashOff':
UIGraphicsBeginImageContextWithOptions(size || CGSizeMake(50, 50), false, 0);
drawFlashOff(color);
break;
case 'toggle':
UIGraphicsBeginImageContextWithOptions(size || CGSizeMake(50, 50), false, 0);
drawToggle(color);
break;
case 'picOutline':
UIGraphicsBeginImageContextWithOptions(size || CGSizeMake(50, 50), false, 0);
drawPicOutline(color);
break;
case 'takePic':
UIGraphicsBeginImageContextWithOptions(size || CGSizeMake(50, 50), false, 0);
drawCircle(color);
break;
case 'gallery':
UIGraphicsBeginImageContextWithOptions(size || CGSizeMake(50, 50), false, 0);
drawGallery(color);
break;
}
const img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
};
const drawFlash = function (color) {
const iconColor = new Color(color || '#fff').ios;
//// Bezier Drawing
const bezierPath = UIBezierPath.bezierPath();
bezierPath.moveToPoint(CGPointMake(23.17, 0.58));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(11.19, 13.65), CGPointMake(22.79, 0.97), CGPointMake(17.38, 6.83));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(0, 26.66), CGPointMake(3.2, 22.41), CGPointMake(-0.07, 26.24));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(6.91, 27.44), CGPointMake(0.1, 27.26), CGPointMake(0.34, 27.29));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(13.61, 28.15), CGPointMake(13.34, 27.58), CGPointMake(13.71, 27.61));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(10.61, 37.07), CGPointMake(13.54, 28.45), CGPointMake(12.18, 32.46));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(7.83, 45.92), CGPointMake(9.02, 41.64), CGPointMake(7.76, 45.62));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(8.85, 46.43), CGPointMake(7.89, 46.25), CGPointMake(8.27, 46.43));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(21.54, 33.48), CGPointMake(9.59, 46.43), CGPointMake(11.36, 44.63));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(33.2, 19.87), CGPointMake(30.18, 23.97), CGPointMake(33.27, 20.35));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(26.57, 19.12), CGPointMake(33.1, 19.21), CGPointMake(33, 19.21));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(20, 18.67), CGPointMake(21.71, 19.06), CGPointMake(20, 18.94));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(22.76, 9.88), CGPointMake(20, 18.49), CGPointMake(21.23, 14.52));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(25.38, 0.73), CGPointMake(24.26, 5.21), CGPointMake(25.45, 1.12));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(23.17, 0.58), CGPointMake(25.24, -0.17), CGPointMake(24.05, -0.26));
bezierPath.miterLimit = 4;
bezierPath.closePath();
iconColor.setFill();
bezierPath.fill();
};
const drawFlashOff = function (color) {
const iconColor = new Color(color || '#fff').ios;
//// Bezier Drawing
const bezierPath = UIBezierPath.bezierPath();
bezierPath.moveToPoint(CGPointMake(21.13, 4.5));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(15.1, 12.28), CGPointMake(19.18, 7.01), CGPointMake(16.45, 10.51));
bezierPath.addLineToPoint(CGPointMake(12.66, 15.45));
bezierPath.addLineToPoint(CGPointMake(7.09, 9.64));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(0.8, 3.9), CGPointMake(2.5, 4.82), CGPointMake(1.41, 3.84));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(0, 4.73), CGPointMake(0.29, 3.96), CGPointMake(0.06, 4.2));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(17.83, 24.13), CGPointMake(-0.06, 5.36), CGPointMake(2.7, 8.39));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(36.44, 42.69), CGPointMake(32.87, 39.81), CGPointMake(35.86, 42.78));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(37.21, 41.88), CGPointMake(36.89, 42.63), CGPointMake(37.15, 42.36));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(31.64, 35.24), CGPointMake(37.3, 41.28), CGPointMake(36.29, 40.11));
bezierPath.addLineToPoint(CGPointMake(25.98, 29.31));
bezierPath.addLineToPoint(CGPointMake(29.34, 24.94));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(32.62, 19.91), CGPointMake(31.76, 21.83), CGPointMake(32.67, 20.39));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(27.02, 19.16), CGPointMake(32.53, 19.25), CGPointMake(32.44, 19.25));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(21.48, 18.71), CGPointMake(22.91, 19.1), CGPointMake(21.48, 18.98));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake(23.8, 9.91), CGPointMake(21.48, 18.53), CGPointMake(22.51, 14.55));
bezierPath.addCurveToPointControlPoint1ControlPoint2(CGPointMake