feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,164 @@
import * as React from 'react';
import { CameraCapturedPicture, CameraOrientation, CameraPictureOptions, CameraProps, CameraRecordingOptions, CameraType, ConstantsType, PermissionResponse, VideoCodec } from './Camera.types';
export default class Camera extends React.Component<CameraProps> {
/**
* Check whether the current device has a camera. This is useful for web and simulators cases.
* This isn't influenced by the Permissions API (all platforms), or HTTP usage (in the browser).
* You will still need to check if the native permission has been accepted.
* @platform web
*/
static isAvailableAsync(): Promise<boolean>;
/**
* Returns a list of camera types `['front', 'back']`. This is useful for desktop browsers which only have front-facing cameras.
* @platform web
*/
static getAvailableCameraTypesAsync(): Promise<CameraType[]>;
/**
* Queries the device for the available video codecs that can be used in video recording.
* @return A promise that resolves to a list of strings that represents available codecs.
* @platform ios
*/
static getAvailableVideoCodecsAsync(): Promise<VideoCodec[]>;
static Constants: ConstantsType;
static ConversionTables: {
type: Record<"front" | "back", string | number | undefined>;
flashMode: Record<"off" | "on" | "auto" | "torch", string | number | undefined>;
autoFocus: Record<"off" | "on" | "auto" | "singleShot", string | number | boolean | undefined>;
whiteBalance: Record<"auto" | "sunny" | "cloudy" | "shadow" | "incandescent" | "fluorescent" | "continuous" | "manual", string | number | undefined>;
};
static defaultProps: CameraProps;
/**
* @deprecated Use `getCameraPermissionsAsync` or `getMicrophonePermissionsAsync` instead.
* Checks user's permissions for accessing camera.
*/
static getPermissionsAsync(): Promise<PermissionResponse>;
/**
* Asks the user to grant permissions for accessing camera.
* On iOS this will require apps to specify both `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` entries in the **Info.plist**.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
* @deprecated Use `requestCameraPermissionsAsync` or `requestMicrophonePermissionsAsync` instead.
*/
static requestPermissionsAsync(): Promise<PermissionResponse>;
/**
* Checks user's permissions for accessing camera.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static getCameraPermissionsAsync(): Promise<PermissionResponse>;
/**
* Asks the user to grant permissions for accessing camera.
* On iOS this will require apps to specify an `NSCameraUsageDescription` entry in the **Info.plist**.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static requestCameraPermissionsAsync(): Promise<PermissionResponse>;
/**
* Check or request permissions to access the camera.
* This uses both `requestCameraPermissionsAsync` and `getCameraPermissionsAsync` to interact with the permissions.
*
* @example
* ```ts
* const [status, requestPermission] = Camera.useCameraPermissions();
* ```
*/
static useCameraPermissions: (options?: import("expo-modules-core").PermissionHookOptions<object> | undefined) => [PermissionResponse | null, () => Promise<PermissionResponse>, () => Promise<PermissionResponse>];
/**
* Checks user's permissions for accessing microphone.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static getMicrophonePermissionsAsync(): Promise<PermissionResponse>;
/**
* Asks the user to grant permissions for accessing the microphone.
* On iOS this will require apps to specify an `NSMicrophoneUsageDescription` entry in the **Info.plist**.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static requestMicrophonePermissionsAsync(): Promise<PermissionResponse>;
/**
* Check or request permissions to access the microphone.
* This uses both `requestMicrophonePermissionsAsync` and `getMicrophonePermissionsAsync` to interact with the permissions.
*
* @example
* ```ts
* const [status, requestPermission] = Camera.useMicrophonePermissions();
* ```
*/
static useMicrophonePermissions: (options?: import("expo-modules-core").PermissionHookOptions<object> | undefined) => [PermissionResponse | null, () => Promise<PermissionResponse>, () => Promise<PermissionResponse>];
_cameraHandle?: number | null;
_cameraRef?: React.Component | null;
_lastEvents: {
[eventName: string]: string;
};
_lastEventsTimes: {
[eventName: string]: Date;
};
/**
* Takes a picture and saves it to app's cache directory. Photos are rotated to match device's orientation
* (if `options.skipProcessing` flag is not enabled) and scaled to match the preview. Anyway on Android it is essential
* to set ratio prop to get a picture with correct dimensions.
* > **Note**: Make sure to wait for the [`onCameraReady`](#oncameraready) callback before calling this method.
* @param options An object in form of `CameraPictureOptions` type.
* @return Returns a Promise that resolves to `CameraCapturedPicture` object, where `uri` is a URI to the local image file on iOS,
* Android, and a base64 string on web (usable as the source for an `Image` element). The `width` and `height` properties specify
* the dimensions of the image. `base64` is included if the `base64` option was truthy, and is a string containing the JPEG data
* of the image in Base64--prepend that with `'data:image/jpg;base64,'` to get a data URI, which you can use as the source
* for an `Image` element for example. `exif` is included if the `exif` option was truthy, and is an object containing EXIF
* data for the image--the names of its properties are EXIF tags and their values are the values for those tags.
*
* > On native platforms, the local image URI is temporary. Use [`FileSystem.copyAsync`](filesystem/#filesystemcachedirectory)
* > to make a permanent copy of the image.
*/
takePictureAsync(options?: CameraPictureOptions): Promise<CameraCapturedPicture>;
/**
* Get aspect ratios that are supported by the device and can be passed via `ratio` prop.
* @return Returns a Promise that resolves to an array of strings representing ratios, eg. `['4:3', '1:1']`.
* @platform android
*/
getSupportedRatiosAsync(): Promise<string[]>;
/**
* Get picture sizes that are supported by the device for given `ratio`.
* @param ratio A string representing aspect ratio of sizes to be returned.
* @return Returns a Promise that resolves to an array of strings representing picture sizes that can be passed to `pictureSize` prop.
* The list varies across Android devices but is the same for every iOS.
*/
getAvailablePictureSizesAsync(ratio: string): Promise<string[]>;
/**
* Starts recording a video that will be saved to cache directory. Videos are rotated to match device's orientation.
* Flipping camera during a recording results in stopping it.
* @param options A map of `CameraRecordingOptions` type.
* @return Returns a Promise that resolves to an object containing video file `uri` property and a `codec` property on iOS.
* The Promise is returned if `stopRecording` was invoked, one of `maxDuration` and `maxFileSize` is reached or camera preview is stopped.
* @platform android
* @platform ios
*/
recordAsync(options?: CameraRecordingOptions): Promise<{
uri: string;
}>;
/**
* Stops recording if any is in progress.
*/
stopRecording(): Promise<void>;
/**
* Pauses the camera preview. It is not recommended to use `takePictureAsync` when preview is paused.
*/
pausePreview(): Promise<void>;
/**
* Resumes the camera preview.
*/
resumePreview(): Promise<void>;
_onCameraReady: () => void;
_onMountError: ({ nativeEvent }: {
nativeEvent: {
message: string;
};
}) => void;
_onResponsiveOrientationChanged: ({ nativeEvent, }: {
nativeEvent: {
orientation: CameraOrientation;
};
}) => void;
_onObjectDetected: (callback?: Function) => ({ nativeEvent }: {
nativeEvent: any;
}) => void;
_setReference: (ref?: React.Component) => void;
render(): JSX.Element;
}
export declare const Constants: ConstantsType, getPermissionsAsync: typeof Camera.getPermissionsAsync, requestPermissionsAsync: typeof Camera.requestPermissionsAsync, getCameraPermissionsAsync: typeof Camera.getCameraPermissionsAsync, requestCameraPermissionsAsync: typeof Camera.requestCameraPermissionsAsync, getMicrophonePermissionsAsync: typeof Camera.getMicrophonePermissionsAsync, requestMicrophonePermissionsAsync: typeof Camera.requestMicrophonePermissionsAsync;
//# sourceMappingURL=Camera.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../src/legacy/Camera.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,sBAAsB,EACtB,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,UAAU,EACX,MAAM,gBAAgB,CAAC;AAoDxB,MAAM,CAAC,OAAO,OAAO,MAAO,SAAQ,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC;IAC9D;;;;;OAKG;WACU,gBAAgB,IAAI,OAAO,CAAC,OAAO,CAAC;IAQjD;;;OAGG;WACU,4BAA4B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IASlE;;;;OAIG;WACU,4BAA4B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAQlE,MAAM,CAAC,SAAS,EAAE,aAAa,CAQ7B;IAGF,MAAM,CAAC,gBAAgB;;;;;MAAoB;IAE3C,MAAM,CAAC,YAAY,EAAE,WAAW,CAS9B;IAGF;;;OAGG;WACU,mBAAmB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQ/D;;;;;OAKG;WACU,uBAAuB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAQnE;;;OAGG;WACU,yBAAyB,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKrE;;;;OAIG;WACU,6BAA6B,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKzE;;;;;;;;OAQG;IACH,MAAM,CAAC,oBAAoB,yLAGxB;IAGH;;;OAGG;WACU,6BAA6B,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAKzE;;;;OAIG;WACU,iCAAiC,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAK7E;;;;;;;;OAQG;IACH,MAAM,CAAC,wBAAwB,yLAG5B;IAEH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;IACpC,WAAW,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAClD,gBAAgB,EAAE;QAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAM;IAGrD;;;;;;;;;;;;;;;OAeG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAMtF;;;;OAIG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAQlD;;;;;OAKG;IACG,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAOrE;;;;;;;;OAQG;IACG,WAAW,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAS7E;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAQnC;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAQpC,cAAc,aAIZ;IAEF,aAAa;qBAAoC;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE;eAIlE;IAEF,+BAA+B;qBAGhB;YAAE,aAAa,iBAAiB,CAAA;SAAE;eAK/C;IAEF,iBAAiB,cACH,QAAQ;qBACa,GAAG;eAgBlC;IAEJ,aAAa,SAAU,MAAM,SAAS,UAapC;IAEF,MAAM;CAsBP;AAED,eAAO,MACL,SAAS,iBACT,mBAAmB,qCACnB,uBAAuB,yCACvB,yBAAyB,2CACzB,6BAA6B,+CAC7B,6BAA6B,+CAC7B,iCAAiC,iDACzB,CAAC"}

View File

@@ -0,0 +1,325 @@
import { createPermissionHook, Platform, UnavailabilityError } from 'expo-modules-core';
import * as React from 'react';
import { findNodeHandle } from 'react-native';
import ExpoCamera from './ExpoCamera';
import CameraManager from './ExpoCameraManager';
import { ConversionTables, ensureNativeProps } from './utils/props';
const EventThrottleMs = 500;
const _PICTURE_SAVED_CALLBACKS = {};
let _GLOBAL_PICTURE_ID = 1;
function ensurePictureOptions(options) {
const pictureOptions = !options || typeof options !== 'object' ? {} : options;
if (!pictureOptions.quality) {
pictureOptions.quality = 1;
}
if (pictureOptions.onPictureSaved) {
const id = _GLOBAL_PICTURE_ID++;
_PICTURE_SAVED_CALLBACKS[id] = pictureOptions.onPictureSaved;
pictureOptions.id = id;
pictureOptions.fastMode = true;
}
return pictureOptions;
}
function ensureRecordingOptions(options) {
let recordingOptions = options || {};
if (!recordingOptions || typeof recordingOptions !== 'object') {
recordingOptions = {};
}
else if (typeof recordingOptions.quality === 'string') {
recordingOptions.quality = Camera.Constants.VideoQuality[recordingOptions.quality];
}
return recordingOptions;
}
function _onPictureSaved({ nativeEvent, }) {
const { id, data } = nativeEvent;
const callback = _PICTURE_SAVED_CALLBACKS[id];
if (callback) {
callback(data);
delete _PICTURE_SAVED_CALLBACKS[id];
}
}
export default class Camera extends React.Component {
/**
* Check whether the current device has a camera. This is useful for web and simulators cases.
* This isn't influenced by the Permissions API (all platforms), or HTTP usage (in the browser).
* You will still need to check if the native permission has been accepted.
* @platform web
*/
static async isAvailableAsync() {
if (!CameraManager.isAvailableAsync) {
throw new UnavailabilityError('expo-camera', 'isAvailableAsync');
}
return await CameraManager.isAvailableAsync();
}
/**
* Returns a list of camera types `['front', 'back']`. This is useful for desktop browsers which only have front-facing cameras.
* @platform web
*/
static async getAvailableCameraTypesAsync() {
if (!CameraManager.getAvailableCameraTypesAsync) {
throw new UnavailabilityError('expo-camera', 'getAvailableCameraTypesAsync');
}
return await CameraManager.getAvailableCameraTypesAsync();
}
// @needsAudit
/**
* Queries the device for the available video codecs that can be used in video recording.
* @return A promise that resolves to a list of strings that represents available codecs.
* @platform ios
*/
static async getAvailableVideoCodecsAsync() {
if (!CameraManager.getAvailableVideoCodecsAsync) {
throw new UnavailabilityError('Camera', 'getAvailableVideoCodecsAsync');
}
return await CameraManager.getAvailableVideoCodecsAsync();
}
static Constants = {
Type: CameraManager.Type,
FlashMode: CameraManager.FlashMode,
AutoFocus: CameraManager.AutoFocus,
WhiteBalance: CameraManager.WhiteBalance,
VideoQuality: CameraManager.VideoQuality,
VideoStabilization: CameraManager.VideoStabilization || {},
VideoCodec: CameraManager.VideoCodec,
};
// Values under keys from this object will be transformed to native options
static ConversionTables = ConversionTables;
static defaultProps = {
zoom: 0,
ratio: '4:3',
focusDepth: 0,
faceDetectorSettings: {},
type: CameraManager.Type.back,
autoFocus: CameraManager.AutoFocus.on,
flashMode: CameraManager.FlashMode.off,
whiteBalance: CameraManager.WhiteBalance.auto,
};
// @needsAudit
/**
* @deprecated Use `getCameraPermissionsAsync` or `getMicrophonePermissionsAsync` instead.
* Checks user's permissions for accessing camera.
*/
static async getPermissionsAsync() {
console.warn(`"getPermissionsAsync()" is now deprecated. Please use "getCameraPermissionsAsync()" or "getMicrophonePermissionsAsync()" instead.`);
return CameraManager.getPermissionsAsync();
}
// @needsAudit
/**
* Asks the user to grant permissions for accessing camera.
* On iOS this will require apps to specify both `NSCameraUsageDescription` and `NSMicrophoneUsageDescription` entries in the **Info.plist**.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
* @deprecated Use `requestCameraPermissionsAsync` or `requestMicrophonePermissionsAsync` instead.
*/
static async requestPermissionsAsync() {
console.warn(`"requestPermissionsAsync()" is now deprecated. Please use "requestCameraPermissionsAsync()" or "requestMicrophonePermissionsAsync()" instead.`);
return CameraManager.requestPermissionsAsync();
}
// @needsAudit
/**
* Checks user's permissions for accessing camera.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static async getCameraPermissionsAsync() {
return CameraManager.getCameraPermissionsAsync();
}
// @needsAudit
/**
* Asks the user to grant permissions for accessing camera.
* On iOS this will require apps to specify an `NSCameraUsageDescription` entry in the **Info.plist**.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static async requestCameraPermissionsAsync() {
return CameraManager.requestCameraPermissionsAsync();
}
// @needsAudit
/**
* Check or request permissions to access the camera.
* This uses both `requestCameraPermissionsAsync` and `getCameraPermissionsAsync` to interact with the permissions.
*
* @example
* ```ts
* const [status, requestPermission] = Camera.useCameraPermissions();
* ```
*/
static useCameraPermissions = createPermissionHook({
getMethod: Camera.getCameraPermissionsAsync,
requestMethod: Camera.requestCameraPermissionsAsync,
});
// @needsAudit
/**
* Checks user's permissions for accessing microphone.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static async getMicrophonePermissionsAsync() {
return CameraManager.getMicrophonePermissionsAsync();
}
// @needsAudit
/**
* Asks the user to grant permissions for accessing the microphone.
* On iOS this will require apps to specify an `NSMicrophoneUsageDescription` entry in the **Info.plist**.
* @return A promise that resolves to an object of type [PermissionResponse](#permissionresponse).
*/
static async requestMicrophonePermissionsAsync() {
return CameraManager.requestMicrophonePermissionsAsync();
}
// @needsAudit
/**
* Check or request permissions to access the microphone.
* This uses both `requestMicrophonePermissionsAsync` and `getMicrophonePermissionsAsync` to interact with the permissions.
*
* @example
* ```ts
* const [status, requestPermission] = Camera.useMicrophonePermissions();
* ```
*/
static useMicrophonePermissions = createPermissionHook({
getMethod: Camera.getMicrophonePermissionsAsync,
requestMethod: Camera.requestMicrophonePermissionsAsync,
});
_cameraHandle;
_cameraRef;
_lastEvents = {};
_lastEventsTimes = {};
// @needsAudit
/**
* Takes a picture and saves it to app's cache directory. Photos are rotated to match device's orientation
* (if `options.skipProcessing` flag is not enabled) and scaled to match the preview. Anyway on Android it is essential
* to set ratio prop to get a picture with correct dimensions.
* > **Note**: Make sure to wait for the [`onCameraReady`](#oncameraready) callback before calling this method.
* @param options An object in form of `CameraPictureOptions` type.
* @return Returns a Promise that resolves to `CameraCapturedPicture` object, where `uri` is a URI to the local image file on iOS,
* Android, and a base64 string on web (usable as the source for an `Image` element). The `width` and `height` properties specify
* the dimensions of the image. `base64` is included if the `base64` option was truthy, and is a string containing the JPEG data
* of the image in Base64--prepend that with `'data:image/jpg;base64,'` to get a data URI, which you can use as the source
* for an `Image` element for example. `exif` is included if the `exif` option was truthy, and is an object containing EXIF
* data for the image--the names of its properties are EXIF tags and their values are the values for those tags.
*
* > On native platforms, the local image URI is temporary. Use [`FileSystem.copyAsync`](filesystem/#filesystemcachedirectory)
* > to make a permanent copy of the image.
*/
async takePictureAsync(options) {
const pictureOptions = ensurePictureOptions(options);
return await CameraManager.takePicture(pictureOptions, this._cameraHandle);
}
/**
* Get aspect ratios that are supported by the device and can be passed via `ratio` prop.
* @return Returns a Promise that resolves to an array of strings representing ratios, eg. `['4:3', '1:1']`.
* @platform android
*/
async getSupportedRatiosAsync() {
if (!CameraManager.getSupportedRatios) {
throw new UnavailabilityError('Camera', 'getSupportedRatiosAsync');
}
return await CameraManager.getSupportedRatios(this._cameraHandle);
}
/**
* Get picture sizes that are supported by the device for given `ratio`.
* @param ratio A string representing aspect ratio of sizes to be returned.
* @return Returns a Promise that resolves to an array of strings representing picture sizes that can be passed to `pictureSize` prop.
* The list varies across Android devices but is the same for every iOS.
*/
async getAvailablePictureSizesAsync(ratio) {
if (!CameraManager.getAvailablePictureSizes) {
throw new UnavailabilityError('Camera', 'getAvailablePictureSizesAsync');
}
return await CameraManager.getAvailablePictureSizes(ratio, this._cameraHandle);
}
/**
* Starts recording a video that will be saved to cache directory. Videos are rotated to match device's orientation.
* Flipping camera during a recording results in stopping it.
* @param options A map of `CameraRecordingOptions` type.
* @return Returns a Promise that resolves to an object containing video file `uri` property and a `codec` property on iOS.
* The Promise is returned if `stopRecording` was invoked, one of `maxDuration` and `maxFileSize` is reached or camera preview is stopped.
* @platform android
* @platform ios
*/
async recordAsync(options) {
if (!CameraManager.record) {
throw new UnavailabilityError('Camera', 'recordAsync');
}
const recordingOptions = ensureRecordingOptions(options);
return await CameraManager.record(recordingOptions, this._cameraHandle);
}
/**
* Stops recording if any is in progress.
*/
async stopRecording() {
if (!CameraManager.stopRecording) {
throw new UnavailabilityError('Camera', 'stopRecording');
}
return await CameraManager.stopRecording(this._cameraHandle);
}
/**
* Pauses the camera preview. It is not recommended to use `takePictureAsync` when preview is paused.
*/
async pausePreview() {
if (!CameraManager.pausePreview) {
throw new UnavailabilityError('Camera', 'pausePreview');
}
return await CameraManager.pausePreview(this._cameraHandle);
}
/**
* Resumes the camera preview.
*/
async resumePreview() {
if (!CameraManager.resumePreview) {
throw new UnavailabilityError('Camera', 'resumePreview');
}
return await CameraManager.resumePreview(this._cameraHandle);
}
_onCameraReady = () => {
if (this.props.onCameraReady) {
this.props.onCameraReady();
}
};
_onMountError = ({ nativeEvent }) => {
if (this.props.onMountError) {
this.props.onMountError(nativeEvent);
}
};
_onResponsiveOrientationChanged = ({ nativeEvent, }) => {
if (this.props.onResponsiveOrientationChanged) {
this.props.onResponsiveOrientationChanged(nativeEvent);
}
};
_onObjectDetected = (callback) => ({ nativeEvent }) => {
const { type } = nativeEvent;
if (this._lastEvents[type] &&
this._lastEventsTimes[type] &&
JSON.stringify(nativeEvent) === this._lastEvents[type] &&
new Date().getTime() - this._lastEventsTimes[type].getTime() < EventThrottleMs) {
return;
}
if (callback) {
callback(nativeEvent);
this._lastEventsTimes[type] = new Date();
this._lastEvents[type] = JSON.stringify(nativeEvent);
}
};
_setReference = (ref) => {
if (ref) {
this._cameraRef = ref;
// TODO(Bacon): Unify these - perhaps with hooks?
if (Platform.OS === 'web') {
this._cameraHandle = ref;
}
else {
this._cameraHandle = findNodeHandle(ref);
}
}
else {
this._cameraRef = null;
this._cameraHandle = null;
}
};
render() {
const nativeProps = ensureNativeProps(this.props);
const onBarCodeScanned = this.props.onBarCodeScanned
? this._onObjectDetected(this.props.onBarCodeScanned)
: undefined;
const onFacesDetected = this._onObjectDetected(this.props.onFacesDetected);
return (<ExpoCamera {...nativeProps} ref={this._setReference} onCameraReady={this._onCameraReady} onMountError={this._onMountError} onBarCodeScanned={onBarCodeScanned} onFacesDetected={onFacesDetected} onPictureSaved={_onPictureSaved} onResponsiveOrientationChanged={this._onResponsiveOrientationChanged}/>);
}
}
export const { Constants, getPermissionsAsync, requestPermissionsAsync, getCameraPermissionsAsync, requestCameraPermissionsAsync, getMicrophonePermissionsAsync, requestMicrophonePermissionsAsync, } = Camera;
//# sourceMappingURL=Camera.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,515 @@
import { PermissionResponse, PermissionStatus, PermissionExpiration, PermissionHookOptions } from 'expo-modules-core';
import type { ViewProps } from 'react-native';
export declare enum CameraType {
front = "front",
back = "back"
}
export declare enum FlashMode {
on = "on",
off = "off",
auto = "auto",
torch = "torch"
}
export declare enum AutoFocus {
on = "on",
off = "off",
/**
* @platform web
*/
auto = "auto",
/**
* @platform web
*/
singleShot = "singleShot"
}
export declare enum WhiteBalance {
auto = "auto",
/**
* @platform android
* @platform ios
*/
sunny = "sunny",
/**
* @platform android
* @platform ios
*/
cloudy = "cloudy",
/**
* @platform android
* @platform ios
*/
shadow = "shadow",
/**
* @platform android
* @platform ios
*/
incandescent = "incandescent",
/**
* @platform android
* @platform ios
*/
fluorescent = "fluorescent",
/**
* @platform web
*/
continuous = "continuous",
/**
* @platform web
*/
manual = "manual"
}
export declare enum ImageType {
png = "png",
jpg = "jpg"
}
/**
* This option specifies what codec to use when recording a video.
* @platform ios
*/
export declare enum VideoCodec {
H264 = "avc1",
HEVC = "hvc1",
JPEG = "jpeg",
AppleProRes422 = "apcn",
AppleProRes4444 = "ap4h"
}
/**
* This option specifies the stabilization mode to use when recording a video.
* @platform ios
*/
export declare enum VideoStabilization {
off = "off",
standard = "standard",
cinematic = "cinematic",
auto = "auto"
}
export declare enum VideoQuality {
'2160p' = "2160p",
'1080p' = "1080p",
'720p' = "720p",
'480p' = "480p",
'4:3' = "4:3"
}
export declare enum CameraOrientation {
portrait = 1,
portraitUpsideDown = 2,
landscapeLeft = 3,
landscapeRight = 4
}
/**
* @hidden We do not expose related web methods in docs.
* @platform web
*/
export type ImageSize = {
width: number;
height: number;
};
/**
* @hidden We do not expose related web methods in docs.
* @platform web
*/
export type WebCameraSettings = {
autoFocus?: string;
flashMode?: string;
whiteBalance?: string;
exposureCompensation?: number;
colorTemperature?: number;
iso?: number;
brightness?: number;
contrast?: number;
saturation?: number;
sharpness?: number;
focusDistance?: number;
zoom?: number;
};
export type CameraCapturedPicture = {
/**
* Captured image width.
*/
width: number;
/**
* Captured image height.
*/
height: number;
/**
* On web, the value of `uri` is the same as `base64` because file system URLs are not supported in the browser.
*/
uri: string;
/**
* A Base64 representation of the image.
*/
base64?: string;
/**
* On Android and iOS this object may include various fields based on the device and operating system.
* On web, it is a partial representation of the [`MediaTrackSettings`](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackSettings) dictionary.
*/
exif?: Partial<MediaTrackSettings> | any;
};
export type CameraPictureOptions = {
/**
* Specify the compression quality from `0` to `1`. `0` means compress for small size, and `1` means compress for maximum quality.
*/
quality?: number;
/**
* Whether to also include the image data in Base64 format.
*/
base64?: boolean;
/**
* Whether to also include the EXIF data for the image.
*/
exif?: boolean;
/**
* Additional EXIF data to be included for the image. Only useful when `exif` option is set to `true`.
* @platform android
* @platform ios
*/
additionalExif?: Record<string, any>;
/**
* A callback invoked when picture is saved. If set, the promise of this method will resolve immediately with no data after picture is captured.
* The data that it should contain will be passed to this callback. If displaying or processing a captured photo right after taking it
* is not your case, this callback lets you skip waiting for it to be saved.
* @param picture
*/
onPictureSaved?: (picture: CameraCapturedPicture) => void;
/**
* If set to `true`, camera skips orientation adjustment and returns an image straight from the device's camera.
* If enabled, `quality` option is discarded (processing pipeline is skipped as a whole).
* Although enabling this option reduces image delivery time significantly, it may cause the image to appear in a wrong orientation
* in the `Image` component (at the time of writing, it does not respect EXIF orientation of the images).
* > **Note**: Enabling `skipProcessing` would cause orientation uncertainty. `Image` component does not respect EXIF
* > stored orientation information, that means obtained image would be displayed wrongly (rotated by 90°, 180° or 270°).
* > Different devices provide different orientations. For example some Sony Xperia or Samsung devices don't provide
* > correctly oriented images by default. To always obtain correctly oriented image disable `skipProcessing` option.
*/
skipProcessing?: boolean;
/**
* @platform web
*/
scale?: number;
/**
* @platform web
*/
imageType?: ImageType;
/**
* @platform web
*/
isImageMirror?: boolean;
/**
* @hidden
*/
id?: number;
/**
* @hidden
*/
fastMode?: boolean;
/**
* @hidden
*/
maxDownsampling?: number;
};
export type CameraRecordingOptions = {
/**
* Maximum video duration in seconds.
*/
maxDuration?: number;
/**
* Maximum video file size in bytes.
*/
maxFileSize?: number;
/**
* Specify the quality of recorded video. Use one of [`VideoQuality.<value>`](#videoquality).
* Possible values: for 16:9 resolution `2160p`, `1080p`, `720p`, `480p` : `Android only` and for 4:3 `4:3` (the size is 640x480).
* If the chosen quality is not available for a device, the highest available is chosen.
*/
quality?: number | string;
/**
* If present, video will be recorded with no sound.
*/
mute?: boolean;
/**
* If `true`, the recorded video will be flipped along the vertical axis. iOS flips videos recorded with the front camera by default,
* but you can reverse that back by setting this to `true`. On Android, this is handled in the user's device settings.
* @platform ios
*/
mirror?: boolean;
/**
* Only works if `useCamera2Api` is set to `true`. This option specifies a desired video bitrate. For example, `5*1000*1000` would be 5Mbps.
* @platform android
*/
videoBitrate?: number;
/**
* This option specifies what codec to use when recording the video. See [`VideoCodec`](#videocodec) for the possible values.
* @platform ios
*/
codec?: VideoCodec;
};
/**
* @hidden
*/
export type PictureSavedListener = (event: {
nativeEvent: {
data: CameraCapturedPicture;
id: number;
};
}) => void;
/**
* @hidden
*/
export type CameraReadyListener = () => void;
/**
* @hidden
*/
export type ResponsiveOrientationChangedListener = (event: {
nativeEvent: ResponsiveOrientationChanged;
}) => void;
export type ResponsiveOrientationChanged = {
orientation: CameraOrientation;
};
/**
* @hidden
*/
export type MountErrorListener = (event: {
nativeEvent: CameraMountError;
}) => void;
export type CameraMountError = {
message: string;
};
export type Point = {
x: number;
y: number;
};
export type BarCodeSize = {
/**
* The height value.
*/
height: number;
/**
* The width value.
*/
width: number;
};
/**
* These coordinates are represented in the coordinate space of the camera source (e.g. when you
* are using the camera view, these values are adjusted to the dimensions of the view).
*/
export type BarCodePoint = Point;
export type BarCodeBounds = {
/**
* The origin point of the bounding box.
*/
origin: BarCodePoint;
/**
* The size of the bounding box.
*/
size: BarCodeSize;
};
export type BarCodeScanningResult = {
/**
* The barcode type.
*/
type: string;
/**
* The parsed information encoded in the bar code.
*/
data: string;
/**
* The raw information encoded in the bar code.
* May be different from `data` depending on the barcode type.
* @platform android
* @hidden
*/
raw?: string;
/**
* Corner points of the bounding box.
* `cornerPoints` is not always available and may be empty. On iOS, for `code39` and `pdf417`
* you don't get this value.
*/
cornerPoints: BarCodePoint[];
/**
* The [BarCodeBounds](#barcodebounds) object.
* `bounds` in some case will be representing an empty rectangle.
* Moreover, `bounds` doesn't have to bound the whole barcode.
* For some types, they will represent the area used by the scanner.
*/
bounds: BarCodeBounds;
};
export type FaceDetectionResult = {
/**
* Array of objects representing results of face detection.
* See [`FaceFeature`](facedetector/#facefeature) in FaceDetector documentation for more details.
*/
faces: object[];
};
/**
* @hidden
*/
export type ConstantsType = {
Type: CameraType;
FlashMode: FlashMode;
AutoFocus: AutoFocus;
WhiteBalance: WhiteBalance;
VideoQuality: VideoQuality;
VideoStabilization: VideoStabilization;
VideoCodec: VideoCodec;
};
export type CameraProps = ViewProps & {
/**
* Camera facing. Use one of `CameraType`. When `CameraType.front`, use the front-facing camera.
* When `CameraType.back`, use the back-facing camera.
* @default CameraType.back
*/
type?: number | CameraType;
/**
* Camera flash mode. Use one of [`FlashMode.<value>`](#flashmode-1). When `FlashMode.on`, the flash on your device will
* turn on when taking a picture, when `FlashMode.off`, it won't. Setting to `FlashMode.auto` will fire flash if required,
* `FlashMode.torch` turns on flash during the preview.
* @default FlashMode.off
*/
flashMode?: number | FlashMode;
/**
* Camera white balance. Use one of [`WhiteBalance.<value>`](#whitebalance). If a device does not support any of these values previous one is used.
* @default WhiteBalance.auto
*/
whiteBalance?: number | WhiteBalance;
/**
* State of camera auto focus. Use one of [`AutoFocus.<value>`](#autofocus-1). When `AutoFocus.on`,
* auto focus will be enabled, when `AutoFocus.off`, it won't and focus will lock as it was in the moment of change,
* but it can be adjusted on some devices via `focusDepth` prop.
* @default AutoFocus.on
*/
autoFocus?: boolean | number | AutoFocus;
/**
* A value between `0` and `1` being a percentage of device's max zoom. `0` - not zoomed, `1` - maximum zoom.
* @default 0
*/
zoom?: number;
/**
* A string representing aspect ratio of the preview, eg. `4:3`, `16:9`, `1:1`. To check if a ratio is supported
* by the device use [`getSupportedRatiosAsync`](#getsupportedratiosasync).
* @default 4:3
* @platform android
*/
ratio?: string;
/**
* Distance to plane of the sharpest focus. A value between `0` and `1` where: `0` - infinity focus, `1` - focus as close as possible.
* For Android this is available only for some devices and when `useCamera2Api` is set to `true`.
* @default 0
*/
focusDepth?: number;
/**
* Callback invoked when camera preview has been set.
*/
onCameraReady?: () => void;
/**
* Whether to use Android's Camera2 API. See `Note` at the top of this page.
* @platform android
*/
useCamera2Api?: boolean;
/**
* A string representing the size of pictures [`takePictureAsync`](#takepictureasyncoptions) will take.
* Available sizes can be fetched with [`getAvailablePictureSizesAsync`](#getavailablepicturesizesasyncratio).
*/
pictureSize?: string;
/**
* The video stabilization mode used for a video recording. Use one of [`VideoStabilization.<value>`](#videostabilization).
* You can read more about each stabilization type in [Apple Documentation](https://developer.apple.com/documentation/avfoundation/avcapturevideostabilizationmode).
* @platform ios
*/
videoStabilizationMode?: VideoStabilization;
/**
* Callback invoked when camera preview could not been started.
* @param event Error object that contains a `message`.
*/
onMountError?: (event: CameraMountError) => void;
/**
* Settings exposed by [`BarCodeScanner`](bar-code-scanner) module. Supported settings: **barCodeTypes**.
* @example
* ```tsx
* <Camera
* barCodeScannerSettings={{
* barCodeTypes: [BarCodeScanner.Constants.BarCodeType.qr],
* }}
* />
* ```
*/
barCodeScannerSettings?: BarCodeSettings;
/**
* Callback that is invoked when a bar code has been successfully scanned. The callback is provided with
* an object of the [`BarCodeScanningResult`](#barcodescanningresult) shape, where the `type`
* refers to the bar code type that was scanned and the `data` is the information encoded in the bar code
* (in this case of QR codes, this is often a URL). See [`BarCodeScanner.Constants.BarCodeType`](bar-code-scanner#supported-formats)
* for supported values.
* @param scanningResult
*/
onBarCodeScanned?: (scanningResult: BarCodeScanningResult) => void;
/**
* A settings object passed directly to an underlying module providing face detection features.
* See [`DetectionOptions`](facedetector/#detectionoptions) in FaceDetector documentation for details.
*/
faceDetectorSettings?: object;
/**
* Callback invoked with results of face detection on the preview.
* See [`DetectionResult`](facedetector/#detectionresult) in FaceDetector documentation for more details.
* @param faces
*/
onFacesDetected?: (faces: FaceDetectionResult) => void;
/**
* A URL for an image to be shown while the camera is loading.
* @platform web
*/
poster?: string;
/**
* Whether to allow responsive orientation of the camera when the screen orientation is locked (i.e. when set to `true`
* landscape photos will be taken if the device is turned that way, even if the app or device orientation is locked to portrait)
* @platform ios
*/
responsiveOrientationWhenOrientationLocked?: boolean;
/**
* Callback invoked when responsive orientation changes. Only applicable if `responsiveOrientationWhenOrientationLocked` is `true`
* @param event result object that contains updated orientation of camera
* @platform ios
*/
onResponsiveOrientationChanged?: (event: ResponsiveOrientationChanged) => void;
};
/**
* @hidden
*/
export type CameraNativeProps = {
pointerEvents?: any;
style?: any;
ref?: Function;
onCameraReady?: CameraReadyListener;
onMountError?: MountErrorListener;
onBarCodeScanned?: (event: {
nativeEvent: BarCodeScanningResult;
}) => void;
onFacesDetected?: (event: {
nativeEvent: FaceDetectionResult;
}) => void;
onFaceDetectionError?: (event: {
nativeEvent: Error;
}) => void;
onPictureSaved?: PictureSavedListener;
onResponsiveOrientationChanged?: ResponsiveOrientationChangedListener;
type?: number | string;
flashMode?: number | string;
autoFocus?: string | boolean | number;
focusDepth?: number;
zoom?: number;
whiteBalance?: number | string;
pictureSize?: string;
barCodeScannerSettings?: BarCodeSettings;
faceDetectorSettings?: object;
barCodeScannerEnabled?: boolean;
faceDetectorEnabled?: boolean;
ratio?: string;
useCamera2Api?: boolean;
poster?: string;
responsiveOrientationWhenOrientationLocked?: boolean;
};
export type BarCodeSettings = {
barCodeTypes: string[];
interval?: number;
};
export { PermissionResponse, PermissionStatus, PermissionExpiration, PermissionHookOptions };
//# sourceMappingURL=Camera.types.d.ts.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,109 @@
import { PermissionStatus, } from 'expo-modules-core';
export var CameraType;
(function (CameraType) {
CameraType["front"] = "front";
CameraType["back"] = "back";
})(CameraType || (CameraType = {}));
export var FlashMode;
(function (FlashMode) {
FlashMode["on"] = "on";
FlashMode["off"] = "off";
FlashMode["auto"] = "auto";
FlashMode["torch"] = "torch";
})(FlashMode || (FlashMode = {}));
export var AutoFocus;
(function (AutoFocus) {
AutoFocus["on"] = "on";
AutoFocus["off"] = "off";
/**
* @platform web
*/
AutoFocus["auto"] = "auto";
/**
* @platform web
*/
AutoFocus["singleShot"] = "singleShot";
})(AutoFocus || (AutoFocus = {}));
export var WhiteBalance;
(function (WhiteBalance) {
WhiteBalance["auto"] = "auto";
/**
* @platform android
* @platform ios
*/
WhiteBalance["sunny"] = "sunny";
/**
* @platform android
* @platform ios
*/
WhiteBalance["cloudy"] = "cloudy";
/**
* @platform android
* @platform ios
*/
WhiteBalance["shadow"] = "shadow";
/**
* @platform android
* @platform ios
*/
WhiteBalance["incandescent"] = "incandescent";
/**
* @platform android
* @platform ios
*/
WhiteBalance["fluorescent"] = "fluorescent";
/**
* @platform web
*/
WhiteBalance["continuous"] = "continuous";
/**
* @platform web
*/
WhiteBalance["manual"] = "manual";
})(WhiteBalance || (WhiteBalance = {}));
export var ImageType;
(function (ImageType) {
ImageType["png"] = "png";
ImageType["jpg"] = "jpg";
})(ImageType || (ImageType = {}));
/**
* This option specifies what codec to use when recording a video.
* @platform ios
*/
export var VideoCodec;
(function (VideoCodec) {
VideoCodec["H264"] = "avc1";
VideoCodec["HEVC"] = "hvc1";
VideoCodec["JPEG"] = "jpeg";
VideoCodec["AppleProRes422"] = "apcn";
VideoCodec["AppleProRes4444"] = "ap4h";
})(VideoCodec || (VideoCodec = {}));
/**
* This option specifies the stabilization mode to use when recording a video.
* @platform ios
*/
export var VideoStabilization;
(function (VideoStabilization) {
VideoStabilization["off"] = "off";
VideoStabilization["standard"] = "standard";
VideoStabilization["cinematic"] = "cinematic";
VideoStabilization["auto"] = "auto";
})(VideoStabilization || (VideoStabilization = {}));
// @docsMissing
export var VideoQuality;
(function (VideoQuality) {
VideoQuality["2160p"] = "2160p";
VideoQuality["1080p"] = "1080p";
VideoQuality["720p"] = "720p";
VideoQuality["480p"] = "480p";
VideoQuality["4:3"] = "4:3";
})(VideoQuality || (VideoQuality = {}));
export var CameraOrientation;
(function (CameraOrientation) {
CameraOrientation[CameraOrientation["portrait"] = 1] = "portrait";
CameraOrientation[CameraOrientation["portraitUpsideDown"] = 2] = "portraitUpsideDown";
CameraOrientation[CameraOrientation["landscapeLeft"] = 3] = "landscapeLeft";
CameraOrientation[CameraOrientation["landscapeRight"] = 4] = "landscapeRight";
})(CameraOrientation || (CameraOrientation = {}));
export { PermissionStatus };
//# sourceMappingURL=Camera.types.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
import * as React from 'react';
import { CameraNativeProps } from './Camera.types';
declare const ExponentCamera: React.ComponentType<CameraNativeProps>;
export default ExponentCamera;
//# sourceMappingURL=ExpoCamera.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoCamera.d.ts","sourceRoot":"","sources":["../../src/legacy/ExpoCamera.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEnD,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,iBAAiB,CACb,CAAC;AAE/C,eAAe,cAAc,CAAC"}

View File

@@ -0,0 +1,4 @@
import { requireNativeViewManager } from 'expo-modules-core';
const ExponentCamera = requireNativeViewManager('ExpoCameraLegacy');
export default ExponentCamera;
//# sourceMappingURL=ExpoCamera.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoCamera.js","sourceRoot":"","sources":["../../src/legacy/ExpoCamera.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAK7D,MAAM,cAAc,GAClB,wBAAwB,CAAC,kBAAkB,CAAC,CAAC;AAE/C,eAAe,cAAc,CAAC","sourcesContent":["import { requireNativeViewManager } from 'expo-modules-core';\nimport * as React from 'react';\n\nimport { CameraNativeProps } from './Camera.types';\n\nconst ExponentCamera: React.ComponentType<CameraNativeProps> =\n requireNativeViewManager('ExpoCameraLegacy');\n\nexport default ExponentCamera;\n"]}

View File

@@ -0,0 +1,13 @@
import * as React from 'react';
import { CameraCapturedPicture, CameraNativeProps, CameraPictureOptions } from './Camera.types';
export interface ExponentCameraRef {
getAvailablePictureSizes: (ratio: string) => Promise<string[]>;
takePicture: (options: CameraPictureOptions) => Promise<CameraCapturedPicture>;
resumePreview: () => Promise<void>;
pausePreview: () => Promise<void>;
}
declare const ExponentCamera: React.ForwardRefExoticComponent<Pick<CameraNativeProps & {
children?: React.ReactNode;
}, "type" | "flashMode" | "children" | "pointerEvents" | "style" | "zoom" | "pictureSize" | "poster" | "responsiveOrientationWhenOrientationLocked" | "ratio" | "onCameraReady" | "onMountError" | "onResponsiveOrientationChanged" | "onPictureSaved" | "autoFocus" | "whiteBalance" | "onBarCodeScanned" | "onFacesDetected" | "onFaceDetectionError" | "focusDepth" | "barCodeScannerSettings" | "faceDetectorSettings" | "barCodeScannerEnabled" | "faceDetectorEnabled" | "useCamera2Api"> & React.RefAttributes<ExponentCameraRef>>;
export default ExponentCamera;
//# sourceMappingURL=ExpoCamera.web.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoCamera.web.d.ts","sourceRoot":"","sources":["../../src/legacy/ExpoCamera.web.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EAErB,MAAM,gBAAgB,CAAC;AAOxB,MAAM,WAAW,iBAAiB;IAChC,wBAAwB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/D,WAAW,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAC/E,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED,QAAA,MAAM,cAAc;eAE0D,MAAM,SAAS;ygBA+G5F,CAAC;AAEF,eAAe,cAAc,CAAC"}

View File

@@ -0,0 +1,108 @@
import { CodedError } from 'expo-modules-core';
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import createElement from 'react-native-web/dist/exports/createElement';
import { CameraType, } from './Camera.types';
import CameraManager from './ExpoCameraManager.web';
import { capture } from '../web/WebCameraUtils';
import { PictureSizes } from '../web/WebConstants';
import { useWebCameraStream } from '../web/useWebCameraStream';
import { useWebQRScanner } from '../web/useWebQRScanner';
const ExponentCamera = React.forwardRef(({ type, pictureSize, poster, ...props }, ref) => {
const video = React.useRef(null);
const native = useWebCameraStream(video, type, props, {
onCameraReady() {
if (props.onCameraReady) {
props.onCameraReady();
}
},
onMountError: props.onMountError,
});
const isQRScannerEnabled = React.useMemo(() => {
return !!(props.barCodeScannerSettings?.barCodeTypes?.includes('qr') && !!props.onBarCodeScanned);
}, [props.barCodeScannerSettings?.barCodeTypes, props.onBarCodeScanned]);
useWebQRScanner(video, {
interval: props.barCodeScannerSettings?.interval,
isEnabled: isQRScannerEnabled,
captureOptions: { scale: 1, isImageMirror: native.type === CameraType.front },
onScanned(event) {
if (props.onBarCodeScanned) {
props.onBarCodeScanned(event);
}
},
// onError: props.onMountError,
});
// const [pause, setPaused]
React.useImperativeHandle(ref, () => ({
async getAvailablePictureSizes(ratio) {
return PictureSizes;
},
async takePicture(options) {
if (!video.current || video.current?.readyState !== video.current?.HAVE_ENOUGH_DATA) {
throw new CodedError('ERR_CAMERA_NOT_READY', 'HTMLVideoElement does not have enough camera data to construct an image yet.');
}
const settings = native.mediaTrackSettings;
if (!settings) {
throw new CodedError('ERR_CAMERA_NOT_READY', 'MediaStream is not ready yet.');
}
return capture(video.current, settings, {
...options,
// This will always be defined, the option gets added to a queue in the upper-level. We should replace the original so it isn't called twice.
onPictureSaved(picture) {
if (options.onPictureSaved) {
options.onPictureSaved(picture);
}
if (props.onPictureSaved) {
props.onPictureSaved({ nativeEvent: { data: picture, id: -1 } });
}
},
});
},
async resumePreview() {
if (video.current) {
video.current.play();
}
},
async pausePreview() {
if (video.current) {
video.current.pause();
}
},
}), [native.mediaTrackSettings, props.onPictureSaved]);
// TODO(Bacon): Create a universal prop, on native the microphone is only used when recording videos.
// Because we don't support recording video in the browser we don't need the user to give microphone permissions.
const isMuted = true;
const style = React.useMemo(() => {
const isFrontFacingCamera = native.type === CameraManager.Type.front;
return [
StyleSheet.absoluteFill,
styles.video,
{
pointerEvents: props.pointerEvents,
// Flip the camera
transform: isFrontFacingCamera ? [{ scaleX: -1 }] : undefined,
},
];
}, [props.pointerEvents, native.type]);
return (<View style={[styles.videoWrapper, props.style]}>
<Video autoPlay playsInline muted={isMuted} poster={poster}
// webkitPlaysinline
ref={video} style={style}/>
{props.children}
</View>);
});
export default ExponentCamera;
const Video = React.forwardRef((props, ref) => createElement('video', { ...props, ref }));
const styles = StyleSheet.create({
videoWrapper: {
flex: 1,
alignItems: 'stretch',
pointerEvents: 'box-none',
},
video: {
width: '100%',
height: '100%',
objectFit: 'cover',
},
});
//# sourceMappingURL=ExpoCamera.web.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,3 @@
declare const CameraManager: Record<string, any>;
export default CameraManager;
//# sourceMappingURL=ExpoCameraManager.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoCameraManager.d.ts","sourceRoot":"","sources":["../../src/legacy/ExpoCameraManager.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAA2C,CAAC;AAEnF,eAAe,aAAa,CAAC"}

View File

@@ -0,0 +1,4 @@
import { requireNativeModule } from 'expo-modules-core';
const CameraManager = requireNativeModule('ExpoCameraLegacy');
export default CameraManager;
//# sourceMappingURL=ExpoCameraManager.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoCameraManager.js","sourceRoot":"","sources":["../../src/legacy/ExpoCameraManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,aAAa,GAAwB,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;AAEnF,eAAe,aAAa,CAAC","sourcesContent":["import { requireNativeModule } from 'expo-modules-core';\n\nconst CameraManager: Record<string, any> = requireNativeModule('ExpoCameraLegacy');\n\nexport default CameraManager;\n"]}

View File

@@ -0,0 +1,41 @@
import { CameraCapturedPicture, CameraPictureOptions, PermissionResponse } from './Camera.types';
import { ExponentCameraRef } from './ExpoCamera.web';
declare const _default: {
readonly Type: {
back: string;
front: string;
};
readonly FlashMode: {
on: string;
off: string;
auto: string;
torch: string;
};
readonly AutoFocus: {
on: string;
off: string;
auto: string;
singleShot: string;
};
readonly WhiteBalance: {
auto: string;
continuous: string;
manual: string;
};
readonly VideoQuality: {};
readonly VideoStabilization: {};
isAvailableAsync(): Promise<boolean>;
takePicture(options: CameraPictureOptions, camera: ExponentCameraRef): Promise<CameraCapturedPicture>;
pausePreview(camera: ExponentCameraRef): Promise<void>;
resumePreview(camera: ExponentCameraRef): Promise<void>;
getAvailableCameraTypesAsync(): Promise<string[]>;
getAvailablePictureSizes(ratio: string, camera: ExponentCameraRef): Promise<string[]>;
getPermissionsAsync(): Promise<PermissionResponse>;
requestPermissionsAsync(): Promise<PermissionResponse>;
getCameraPermissionsAsync(): Promise<PermissionResponse>;
requestCameraPermissionsAsync(): Promise<PermissionResponse>;
getMicrophonePermissionsAsync(): Promise<PermissionResponse>;
requestMicrophonePermissionsAsync(): Promise<PermissionResponse>;
};
export default _default;
//# sourceMappingURL=ExpoCameraManager.web.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ExpoCameraManager.web.d.ts","sourceRoot":"","sources":["../../src/legacy/ExpoCameraManager.web.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EAEpB,kBAAkB,EAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;wBA0JzB,QAAQ,OAAO,CAAC;yBAI/B,oBAAoB,UACrB,iBAAiB,GACxB,QAAQ,qBAAqB,CAAC;yBAGN,iBAAiB,GAAG,QAAQ,IAAI,CAAC;0BAGhC,iBAAiB,GAAG,QAAQ,IAAI,CAAC;oCAGvB,QAAQ,MAAM,EAAE,CAAC;oCAYjB,MAAM,UAAU,iBAAiB,GAAG,QAAQ,MAAM,EAAE,CAAC;2BAe9D,QAAQ,kBAAkB,CAAC;+BAGvB,QAAQ,kBAAkB,CAAC;iCAGzB,QAAQ,kBAAkB,CAAC;qCAGvB,QAAQ,kBAAkB,CAAC;qCAG3B,QAAQ,kBAAkB,CAAC;yCAGvB,QAAQ,kBAAkB,CAAC;;AA7FxE,wBA4GE"}

View File

@@ -0,0 +1,213 @@
import { UnavailabilityError } from 'expo-modules-core';
import { CameraType, PermissionStatus, } from './Camera.types';
import { canGetUserMedia, isBackCameraAvailableAsync, isFrontCameraAvailableAsync, } from '../web/WebUserMediaManager';
function getUserMedia(constraints) {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
return navigator.mediaDevices.getUserMedia(constraints);
}
// Some browsers partially implement mediaDevices. We can't just assign an object
// with getUserMedia as it would overwrite existing properties.
// Here, we will just add the getUserMedia property if it's missing.
// First get ahold of the legacy getUserMedia, if present
const getUserMedia =
// TODO: this method is deprecated, migrate to https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
function () {
const error = new Error('Permission unimplemented');
error.code = 0;
error.name = 'NotAllowedError';
throw error;
};
return new Promise((resolve, reject) => {
getUserMedia.call(navigator, constraints, resolve, reject);
});
}
function handleGetUserMediaError({ message }) {
// name: NotAllowedError
// code: 0
if (message === 'Permission dismissed') {
return {
status: PermissionStatus.UNDETERMINED,
expires: 'never',
canAskAgain: true,
granted: false,
};
}
else {
// TODO: Bacon: [OSX] The system could deny access to chrome.
// TODO: Bacon: add: { status: 'unimplemented' }
return {
status: PermissionStatus.DENIED,
expires: 'never',
canAskAgain: true,
granted: false,
};
}
}
async function handleRequestPermissionsAsync() {
try {
await getUserMedia({
video: true,
});
return {
status: PermissionStatus.GRANTED,
expires: 'never',
canAskAgain: true,
granted: true,
};
}
catch ({ message }) {
return handleGetUserMediaError({ message });
}
}
async function handlePermissionsQueryAsync(query) {
if (!navigator?.permissions?.query) {
throw new UnavailabilityError('expo-camera', 'navigator.permissions API is not available');
}
try {
const { state } = await navigator.permissions.query({ name: query });
switch (state) {
case 'prompt':
return {
status: PermissionStatus.UNDETERMINED,
expires: 'never',
canAskAgain: true,
granted: false,
};
case 'granted':
return {
status: PermissionStatus.GRANTED,
expires: 'never',
canAskAgain: true,
granted: true,
};
case 'denied':
return {
status: PermissionStatus.DENIED,
expires: 'never',
canAskAgain: true,
granted: false,
};
}
}
catch (e) {
// Firefox doesn't support querying for the camera permission, so return undetermined status
if (e instanceof TypeError) {
return {
status: PermissionStatus.UNDETERMINED,
expires: 'never',
canAskAgain: true,
granted: false,
};
}
throw e;
}
}
export default {
get Type() {
return {
back: 'back',
front: 'front',
};
},
get FlashMode() {
return {
on: 'on',
off: 'off',
auto: 'auto',
torch: 'torch',
};
},
get AutoFocus() {
return {
on: 'on',
off: 'off',
auto: 'auto',
singleShot: 'singleShot',
};
},
get WhiteBalance() {
return {
auto: 'auto',
continuous: 'continuous',
manual: 'manual',
};
},
get VideoQuality() {
return {};
},
get VideoStabilization() {
return {};
},
async isAvailableAsync() {
return canGetUserMedia();
},
async takePicture(options, camera) {
return await camera.takePicture(options);
},
async pausePreview(camera) {
await camera.pausePreview();
},
async resumePreview(camera) {
return await camera.resumePreview();
},
async getAvailableCameraTypesAsync() {
if (!canGetUserMedia() || !navigator.mediaDevices.enumerateDevices)
return [];
const devices = await navigator.mediaDevices.enumerateDevices();
const types = await Promise.all([
(await isFrontCameraAvailableAsync(devices)) && CameraType.front,
(await isBackCameraAvailableAsync()) && CameraType.back,
]);
return types.filter(Boolean);
},
async getAvailablePictureSizes(ratio, camera) {
return await camera.getAvailablePictureSizes(ratio);
},
/* async getSupportedRatios(camera: ExponentCameraRef): Promise<string[]> {
// TODO: Support on web
},
async record(
options?: CameraRecordingOptions,
camera: ExponentCameraRef
): Promise<{ uri: string }> {
// TODO: Support on web
},
async stopRecording(camera: ExponentCameraRef): Promise<void> {
// TODO: Support on web
}, */
async getPermissionsAsync() {
return handlePermissionsQueryAsync('camera');
},
async requestPermissionsAsync() {
return handleRequestPermissionsAsync();
},
async getCameraPermissionsAsync() {
return handlePermissionsQueryAsync('camera');
},
async requestCameraPermissionsAsync() {
return handleRequestPermissionsAsync();
},
async getMicrophonePermissionsAsync() {
return handlePermissionsQueryAsync('microphone');
},
async requestMicrophonePermissionsAsync() {
try {
await getUserMedia({
audio: true,
});
return {
status: PermissionStatus.GRANTED,
expires: 'never',
canAskAgain: true,
granted: true,
};
}
catch ({ message }) {
return handleGetUserMediaError({ message });
}
},
};
//# sourceMappingURL=ExpoCameraManager.web.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
export { default as Camera } from './Camera';
export { Constants, getPermissionsAsync, requestPermissionsAsync, getCameraPermissionsAsync, requestCameraPermissionsAsync, getMicrophonePermissionsAsync, requestMicrophonePermissionsAsync, } from './Camera';
export * from './Camera.types';
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/legacy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAC7B,iCAAiC,GAClC,MAAM,UAAU,CAAC;AAElB,cAAc,gBAAgB,CAAC"}

View File

@@ -0,0 +1,4 @@
export { default as Camera } from './Camera';
export { Constants, getPermissionsAsync, requestPermissionsAsync, getCameraPermissionsAsync, requestCameraPermissionsAsync, getMicrophonePermissionsAsync, requestMicrophonePermissionsAsync, } from './Camera';
export * from './Camera.types';
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/legacy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,uBAAuB,EACvB,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAC7B,iCAAiC,GAClC,MAAM,UAAU,CAAC;AAElB,cAAc,gBAAgB,CAAC","sourcesContent":["export { default as Camera } from './Camera';\nexport {\n Constants,\n getPermissionsAsync,\n requestPermissionsAsync,\n getCameraPermissionsAsync,\n requestCameraPermissionsAsync,\n getMicrophonePermissionsAsync,\n requestMicrophonePermissionsAsync,\n} from './Camera';\n\nexport * from './Camera.types';\n"]}

View File

@@ -0,0 +1,10 @@
import { CameraNativeProps, CameraType, FlashMode, AutoFocus, WhiteBalance, CameraProps } from '../Camera.types';
export declare const ConversionTables: {
type: Record<keyof typeof CameraType, CameraNativeProps['type']>;
flashMode: Record<keyof typeof FlashMode, CameraNativeProps['flashMode']>;
autoFocus: Record<keyof typeof AutoFocus, CameraNativeProps['autoFocus']>;
whiteBalance: Record<keyof typeof WhiteBalance, CameraNativeProps['whiteBalance']>;
};
export declare function convertNativeProps(props?: CameraProps): CameraNativeProps;
export declare function ensureNativeProps(props?: CameraProps): CameraNativeProps;
//# sourceMappingURL=props.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../../src/legacy/utils/props.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACZ,MAAM,iBAAiB,CAAC;AAIzB,eAAO,MAAM,gBAAgB,EAAE;IAC7B,IAAI,EAAE,MAAM,CAAC,MAAM,OAAO,UAAU,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC;IACjE,SAAS,EAAE,MAAM,CAAC,MAAM,OAAO,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,SAAS,EAAE,MAAM,CAAC,MAAM,OAAO,SAAS,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC;IAC1E,YAAY,EAAE,MAAM,CAAC,MAAM,OAAO,YAAY,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC;CAMpF,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAgBzE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,iBAAiB,CAqBxE"}

View File

@@ -0,0 +1,42 @@
import { Platform } from 'expo-modules-core';
import CameraManager from '../ExpoCameraManager';
// Values under keys from this object will be transformed to native options
export const ConversionTables = {
type: CameraManager.Type,
flashMode: CameraManager.FlashMode,
autoFocus: CameraManager.AutoFocus,
whiteBalance: CameraManager.WhiteBalance,
};
export function convertNativeProps(props) {
if (!props || typeof props !== 'object') {
return {};
}
const nativeProps = {};
for (const [key, value] of Object.entries(props)) {
if (typeof value === 'string' && ConversionTables[key]) {
nativeProps[key] = ConversionTables[key][value];
}
else {
nativeProps[key] = value;
}
}
return nativeProps;
}
export function ensureNativeProps(props) {
const newProps = convertNativeProps(props);
if (newProps.onBarCodeScanned) {
newProps.barCodeScannerEnabled = true;
}
if (newProps.onFacesDetected) {
newProps.faceDetectorEnabled = true;
}
if (Platform.OS !== 'android') {
delete newProps.ratio;
delete newProps.useCamera2Api;
}
if (Platform.OS !== 'web') {
delete newProps.poster;
}
return newProps;
}
//# sourceMappingURL=props.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"props.js","sourceRoot":"","sources":["../../../src/legacy/utils/props.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAU7C,OAAO,aAAa,MAAM,sBAAsB,CAAC;AAEjD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAKzB;IACF,IAAI,EAAE,aAAa,CAAC,IAAI;IACxB,SAAS,EAAE,aAAa,CAAC,SAAS;IAClC,SAAS,EAAE,aAAa,CAAC,SAAS;IAClC,YAAY,EAAE,aAAa,CAAC,YAAY;CACzC,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QACvC,OAAO,EAAE,CAAC;KACX;IAED,MAAM,WAAW,GAAsB,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,gBAAgB,CAAC,GAAG,CAAC,EAAE;YACtD,WAAW,CAAC,GAAG,CAAC,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;SACjD;aAAM;YACL,WAAW,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;SAC1B;KACF;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAmB;IACnD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAE3C,IAAI,QAAQ,CAAC,gBAAgB,EAAE;QAC7B,QAAQ,CAAC,qBAAqB,GAAG,IAAI,CAAC;KACvC;IAED,IAAI,QAAQ,CAAC,eAAe,EAAE;QAC5B,QAAQ,CAAC,mBAAmB,GAAG,IAAI,CAAC;KACrC;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,SAAS,EAAE;QAC7B,OAAO,QAAQ,CAAC,KAAK,CAAC;QACtB,OAAO,QAAQ,CAAC,aAAa,CAAC;KAC/B;IAED,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE;QACzB,OAAO,QAAQ,CAAC,MAAM,CAAC;KACxB;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["import { Platform } from 'expo-modules-core';\n\nimport {\n CameraNativeProps,\n CameraType,\n FlashMode,\n AutoFocus,\n WhiteBalance,\n CameraProps,\n} from '../Camera.types';\nimport CameraManager from '../ExpoCameraManager';\n\n// Values under keys from this object will be transformed to native options\nexport const ConversionTables: {\n type: Record<keyof typeof CameraType, CameraNativeProps['type']>;\n flashMode: Record<keyof typeof FlashMode, CameraNativeProps['flashMode']>;\n autoFocus: Record<keyof typeof AutoFocus, CameraNativeProps['autoFocus']>;\n whiteBalance: Record<keyof typeof WhiteBalance, CameraNativeProps['whiteBalance']>;\n} = {\n type: CameraManager.Type,\n flashMode: CameraManager.FlashMode,\n autoFocus: CameraManager.AutoFocus,\n whiteBalance: CameraManager.WhiteBalance,\n};\n\nexport function convertNativeProps(props?: CameraProps): CameraNativeProps {\n if (!props || typeof props !== 'object') {\n return {};\n }\n\n const nativeProps: CameraNativeProps = {};\n\n for (const [key, value] of Object.entries(props)) {\n if (typeof value === 'string' && ConversionTables[key]) {\n nativeProps[key] = ConversionTables[key][value];\n } else {\n nativeProps[key] = value;\n }\n }\n\n return nativeProps;\n}\n\nexport function ensureNativeProps(props?: CameraProps): CameraNativeProps {\n const newProps = convertNativeProps(props);\n\n if (newProps.onBarCodeScanned) {\n newProps.barCodeScannerEnabled = true;\n }\n\n if (newProps.onFacesDetected) {\n newProps.faceDetectorEnabled = true;\n }\n\n if (Platform.OS !== 'android') {\n delete newProps.ratio;\n delete newProps.useCamera2Api;\n }\n\n if (Platform.OS !== 'web') {\n delete newProps.poster;\n }\n\n return newProps;\n}\n"]}