diff --git a/ios/Podfile.lock b/ios/Podfile.lock index cb7d6c3f3..6694ffdb1 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -17,6 +17,12 @@ PODS: - ZXingObjC/PDF417 - EXCamera (13.6.0): - ExpoModulesCore + - EXFaceDetector (12.4.0): + - ExpoModulesCore + - GoogleMLKit/FaceDetection (= 4.0.0) + - MLKitCommon (= 9.0.0) + - MLKitFaceDetection (= 3.0.0) + - MLKitVision (= 5.0.0) - EXFileSystem (15.4.2): - ExpoModulesCore - EXImageLoader (4.3.0): @@ -224,10 +230,27 @@ PODS: - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) + - GoogleMLKit/FaceDetection (4.0.0): + - GoogleMLKit/MLKitCore + - MLKitFaceDetection (~> 3.0.0) + - GoogleMLKit/MLKitCore (4.0.0): + - MLKitCommon (~> 9.0.0) - GoogleSignIn (7.0.0): - AppAuth (~> 1.5) - GTMAppAuth (< 3.0, >= 1.3) - GTMSessionFetcher/Core (< 4.0, >= 1.1) + - GoogleToolboxForMac/DebugUtils (2.3.2): + - GoogleToolboxForMac/Defines (= 2.3.2) + - GoogleToolboxForMac/Defines (2.3.2) + - GoogleToolboxForMac/Logger (2.3.2): + - GoogleToolboxForMac/Defines (= 2.3.2) + - "GoogleToolboxForMac/NSData+zlib (2.3.2)": + - GoogleToolboxForMac/Defines (= 2.3.2) + - "GoogleToolboxForMac/NSDictionary+URLArguments (2.3.2)": + - GoogleToolboxForMac/DebugUtils (= 2.3.2) + - GoogleToolboxForMac/Defines (= 2.3.2) + - "GoogleToolboxForMac/NSString+URLArguments (= 2.3.2)" + - "GoogleToolboxForMac/NSString+URLArguments (2.3.2)" - GoogleUtilities (7.11.5): - GoogleUtilities/AppDelegateSwizzler (= 7.11.5) - GoogleUtilities/Environment (= 7.11.5) @@ -261,10 +284,12 @@ PODS: - GoogleUtilities/MethodSwizzler - GoogleUtilities/UserDefaults (7.11.5): - GoogleUtilities/Logger + - GoogleUtilitiesComponents (1.1.0): + - GoogleUtilities/Logger - GTMAppAuth (2.0.0): - AppAuth/Core (~> 1.6) - GTMSessionFetcher/Core (< 4.0, >= 1.5) - - GTMSessionFetcher/Core (3.1.1) + - GTMSessionFetcher/Core (2.3.0) - hermes-engine (0.72.3): - hermes-engine/Pre-built (= 0.72.3) - hermes-engine/Pre-built (0.72.3) @@ -273,6 +298,24 @@ PODS: - lottie-react-native (6.3.1): - lottie-ios (~> 4.3.0) - React-Core + - MLImage (1.0.0-beta4) + - MLKitCommon (9.0.0): + - GoogleDataTransport (~> 9.0) + - GoogleToolboxForMac/Logger (~> 2.1) + - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" + - "GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)" + - GoogleUtilities/UserDefaults (~> 7.0) + - GoogleUtilitiesComponents (~> 1.0) + - GTMSessionFetcher/Core (< 3.0, >= 1.1) + - MLKitFaceDetection (3.0.0): + - MLKitCommon (~> 9.0) + - MLKitVision (~> 5.0) + - MLKitVision (5.0.0): + - GoogleToolboxForMac/Logger (~> 2.1) + - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" + - GTMSessionFetcher/Core (< 3.0, >= 1.1) + - MLImage (= 1.0.0-beta4) + - MLKitCommon (~> 9.0) - MoEngage-iOS-SDK (9.4.1) - MoEngageInApp (4.4.0): - MoEngage-iOS-SDK (< 9.5.0, >= 9.4.0) @@ -873,6 +916,7 @@ DEPENDENCIES: - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - EXBarCodeScanner (from `../node_modules/expo-barcode-scanner/ios`) - EXCamera (from `../node_modules/expo-camera/ios`) + - EXFaceDetector (from `../node_modules/expo-face-detector/ios`) - EXFileSystem (from `../node_modules/expo-file-system/ios`) - EXImageLoader (from `../node_modules/expo-image-loader/ios`) - Expo (from `../node_modules/expo`) @@ -1022,12 +1066,19 @@ SPEC REPOS: - fmt - GoogleAppMeasurement - GoogleDataTransport + - GoogleMLKit - GoogleSignIn + - GoogleToolboxForMac - GoogleUtilities + - GoogleUtilitiesComponents - GTMAppAuth - GTMSessionFetcher - libevent - lottie-ios + - MLImage + - MLKitCommon + - MLKitFaceDetection + - MLKitVision - MoEngage-iOS-SDK - MoEngageInApp - MoEngagePluginBase @@ -1053,6 +1104,8 @@ EXTERNAL SOURCES: :path: "../node_modules/expo-barcode-scanner/ios" EXCamera: :path: "../node_modules/expo-camera/ios" + EXFaceDetector: + :path: "../node_modules/expo-face-detector/ios" EXFileSystem: :path: "../node_modules/expo-file-system/ios" EXImageLoader: @@ -1239,6 +1292,7 @@ SPEC CHECKSUMS: DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 EXBarCodeScanner: 44783bf0be375ab18a838dcfef29dd648397000a EXCamera: 2dc2bd2828bca4e283018a0b5a84aec6639ff0b4 + EXFaceDetector: 2a950a570efa39a4724930abb65052ebba1128ea EXFileSystem: d7f59869885cfeab3ac771e2a8d0f5ed98cd3fdb EXImageLoader: 34b214f9387e98f3c73989f15d8d5b399c9ab3f7 Expo: d5956de70d4076190861f6730b93e75478b6faf8 @@ -1278,14 +1332,21 @@ SPEC CHECKSUMS: glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b GoogleAppMeasurement: d3dabccdb336fc0ae44b633c8abaa26559893cd9 GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 + GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e GoogleSignIn: b232380cf495a429b8095d3178a8d5855b42e842 + GoogleToolboxForMac: 8bef7c7c5cf7291c687cf5354f39f9db6399ad34 GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 + GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae - GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 + GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 hermes-engine: 10fbd3f62405c41ea07e71973ea61e1878d07322 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 lottie-ios: 25e7b2675dad5c3ddad369ac9baab03560c5bfdd lottie-react-native: c9f1db4f4124dcce9f8159e65d8dc6e8bcb11fb4 + MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b + MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390 + MLKitFaceDetection: 4981488f71ea8ed718cda692a29ab562637d9ae5 + MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49 MoEngage-iOS-SDK: b7af14646f44852527ba7420e52ff8bb56b7077d MoEngageInApp: 94f24b0b1a83ec247dc998f31b08124b09fcab96 MoEngagePluginBase: e865f388c39d0cf2c7847610876e63b0e5e31c22 diff --git a/package.json b/package.json index 7af586e7a..22afac27b 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "expo": "^49.0.0", "expo-barcode-scanner": "^12.5.3", "expo-camera": "^13.6.0", + "expo-face-detector": "12.4.0", "expo-haptics": "12.6.0", "exponential-backoff": "^3.1.0", "ffmpeg-kit-react-native": "6.0.0", diff --git a/patches/expo-face-detector+12.4.0.patch b/patches/expo-face-detector+12.4.0.patch new file mode 100644 index 000000000..cba71c116 --- /dev/null +++ b/patches/expo-face-detector+12.4.0.patch @@ -0,0 +1,19 @@ +diff --git a/node_modules/expo-face-detector/ios/EXFaceDetector.podspec b/node_modules/expo-face-detector/ios/EXFaceDetector.podspec +index ed661e3..9cf6103 100644 +--- a/node_modules/expo-face-detector/ios/EXFaceDetector.podspec ++++ b/node_modules/expo-face-detector/ios/EXFaceDetector.podspec +@@ -19,10 +19,10 @@ Pod::Spec.new do |s| + # even though `GoogleMLKit/FaceDetection` depends on all `MLKit*` references below + # framework generation code (prebuilds) cannot locate them properly, so these are defined explicitly + # TODO: research why xcodegen fails to detect dependencies of dependencies (resulted .xcodeproj is missing them) +- s.dependency 'GoogleMLKit/FaceDetection', '2.6.0' +- s.dependency 'MLKitFaceDetection', '1.5.0' +- s.dependency 'MLKitCommon', '5.0.0' +- s.dependency 'MLKitVision', '3.0.0' ++ s.dependency 'GoogleMLKit/FaceDetection', '4.0.0' ++ s.dependency 'MLKitFaceDetection', '3.0.0' ++ s.dependency 'MLKitCommon', '9.0.0' ++ s.dependency 'MLKitVision', '5.0.0' + + if !$ExpoUseSources&.include?(package['name']) && ENV['EXPO_USE_SOURCE'].to_i == 0 && File.exist?("#{s.name}.xcframework") && Gem::Version.new(Pod::VERSION) >= Gem::Version.new('1.10.0') + s.source_files = "#{s.name}/**/*.h" diff --git a/src/api/auth/types.ts b/src/api/auth/types.ts index 5c8cbffa0..4855c163c 100644 --- a/src/api/auth/types.ts +++ b/src/api/auth/types.ts @@ -20,7 +20,12 @@ type AchievementsConfig = { achievements?: {enabled: boolean}; }; +type FaceDetectionConfig = { + 'face-detection'?: {enabled: boolean}; +}; + export type AuthConfig = AuthCodeConfig & FaceAuthConfig & TeamConfig & - AchievementsConfig; + AchievementsConfig & + FaceDetectionConfig; diff --git a/src/assets/images/badges/camera_permission.png b/src/assets/images/badges/camera_permission.png new file mode 100644 index 000000000..ff27a48f4 Binary files /dev/null and b/src/assets/images/badges/camera_permission.png differ diff --git a/src/assets/images/badges/camera_permission@2x.png b/src/assets/images/badges/camera_permission@2x.png new file mode 100644 index 000000000..bbc1f2d47 Binary files /dev/null and b/src/assets/images/badges/camera_permission@2x.png differ diff --git a/src/assets/images/badges/camera_permission@3x.png b/src/assets/images/badges/camera_permission@3x.png new file mode 100644 index 000000000..3f78c4a99 Binary files /dev/null and b/src/assets/images/badges/camera_permission@3x.png differ diff --git a/src/assets/images/index.ts b/src/assets/images/index.ts index bc6d2cf03..19d2e4c26 100644 --- a/src/assets/images/index.ts +++ b/src/assets/images/index.ts @@ -68,6 +68,7 @@ export const Images = { placeholder1: require('./badges/placeholder1.png'), placeholder2: require('./badges/placeholder2.png'), faceAuth: require('./badges/face_auth.png'), + cameraPermission: require('./badges/camera_permission.png'), }, phone: { confirmPhoneNumber: require('./phone/confirmPhoneNumber.png'), diff --git a/src/screens/FaceRecognitionFlow/EmotionsAuthCameraFeed/components/GatherEmotionsStep/index.tsx b/src/screens/FaceRecognitionFlow/EmotionsAuthCameraFeed/components/GatherEmotionsStep/index.tsx index 5fb6a1cc7..7de71993d 100644 --- a/src/screens/FaceRecognitionFlow/EmotionsAuthCameraFeed/components/GatherEmotionsStep/index.tsx +++ b/src/screens/FaceRecognitionFlow/EmotionsAuthCameraFeed/components/GatherEmotionsStep/index.tsx @@ -52,7 +52,7 @@ export function GatherEmotionsStep({ }: Props) { const cameraRef = useRef(null); const [isCameraReady, setIsCameraReady] = useState(false); - const isDeviceAngleAllowed = useIsDeviceAngleAllowed(); + const isDeviceAngleAllowed = useIsDeviceAngleAllowed(isCameraReady); const emotions = useSelector(emotionsAuthEmotionsSelector); const session = useSelector(emotionsAuthSessionSelector); const emotionsAuthNextEmotionIndex = useSelector( diff --git a/src/screens/FaceRecognitionFlow/FaceAuthCameraFeed/components/TakeSelfieStep/index.tsx b/src/screens/FaceRecognitionFlow/FaceAuthCameraFeed/components/TakeSelfieStep/index.tsx index 32af35005..51e1c7aba 100644 --- a/src/screens/FaceRecognitionFlow/FaceAuthCameraFeed/components/TakeSelfieStep/index.tsx +++ b/src/screens/FaceRecognitionFlow/FaceAuthCameraFeed/components/TakeSelfieStep/index.tsx @@ -23,7 +23,7 @@ type Props = { export function TakeSelfieStep({onPictureTaken}: Props) { const cameraRef = useRef(null); const [isCameraReady, setIsCameraReady] = useState(false); - const isDeviceAngleAllowed = useIsDeviceAngleAllowed(); + const isDeviceAngleAllowed = useIsDeviceAngleAllowed(isCameraReady); const takePicture = async () => { if (cameraRef.current) { diff --git a/src/screens/FaceRecognitionFlow/components/CameraFeed/CameraFeed.tsx b/src/screens/FaceRecognitionFlow/components/CameraFeed/CameraFeed.tsx index d78198770..66751e146 100644 --- a/src/screens/FaceRecognitionFlow/components/CameraFeed/CameraFeed.tsx +++ b/src/screens/FaceRecognitionFlow/components/CameraFeed/CameraFeed.tsx @@ -2,6 +2,7 @@ import {commonStyles, windowWidth} from '@constants/styles'; import {useCameraPermissions} from '@hooks/useCameraPermissions'; +import {CameraPermissionNotice} from '@screens/FaceRecognitionFlow/components/CameraPermissionNotice'; import {FaceAuthOverlay} from '@screens/FaceRecognitionFlow/components/FaceAuthOverlay'; import {FaceRecognitionActions} from '@store/modules/FaceRecognition/actions'; import {cameraRatioSelector} from '@store/modules/FaceRecognition/selectors'; @@ -64,7 +65,9 @@ export const CameraFeed = React.forwardRef( - ) : null; + ) : ( + + ); }, ); export const cameraStyles = StyleSheet.create({ diff --git a/src/screens/FaceRecognitionFlow/components/CameraPermissionNotice/index.tsx b/src/screens/FaceRecognitionFlow/components/CameraPermissionNotice/index.tsx new file mode 100644 index 000000000..0f336fbe4 --- /dev/null +++ b/src/screens/FaceRecognitionFlow/components/CameraPermissionNotice/index.tsx @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import {Images} from '@images'; +import {PopUpButton} from '@screens/Modals/PopUp/components/PopUpButton'; +import {t} from '@translations/i18n'; +import {font} from '@utils/styles'; +import React from 'react'; +import {Image, Linking, ScrollView, StyleSheet, Text, View} from 'react-native'; +import {rem} from 'rn-units'; + +export function CameraPermissionNotice() { + return ( + + + + + {t('face_auth.camera_permission.title')} + + {t('face_auth.camera_permission.description')} + + + Linking.openSettings()} + /> + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: COLORS.white, + }, + contentContainer: { + flexGrow: 1, + backgroundColor: COLORS.white, + }, + imageContainer: { + alignSelf: 'center', + paddingTop: rem(88), + }, + title: { + paddingTop: rem(10), + ...font(24, 34, 'black', 'primaryDark', 'center'), + }, + description: { + paddingTop: rem(16), + paddingHorizontal: rem(48), + ...font(14, 20, 'medium', 'secondary', 'center'), + }, + footerContainer: { + flex: 1, + justifyContent: 'flex-end', + paddingHorizontal: rem(80), + }, + button: { + height: rem(40), + width: '100%', + alignItems: 'center', + justifyContent: 'center', + }, +}); diff --git a/src/screens/FaceRecognitionFlow/hooks/useIsDeviceAngleAllowed.tsx b/src/screens/FaceRecognitionFlow/hooks/useIsDeviceAngleAllowed.tsx index 205e044fb..78ba859c5 100644 --- a/src/screens/FaceRecognitionFlow/hooks/useIsDeviceAngleAllowed.tsx +++ b/src/screens/FaceRecognitionFlow/hooks/useIsDeviceAngleAllowed.tsx @@ -20,7 +20,7 @@ const THRESHOLD = ? -Math.sin(DEVICE_Y_ALLOWED_ROTATION_RADIANS) : GRAVITY - DEVICE_Y_ALLOWED_ROTATION_RADIANS; -export const useIsDeviceAngleAllowed = () => { +export const useIsDeviceAngleAllowed = (isReady: boolean) => { const [isAllowed, setIsAllowed] = useState(true); useEffect(() => { @@ -44,14 +44,14 @@ export const useIsDeviceAngleAllowed = () => { }, []); useEffect(() => { - if (!isAllowed) { + if (!isAllowed && isReady) { const interval = setInterval( hapticFeedback, DEVICE_ANGLE_WARNING_FEEDBACK_INTERVAL_MS, ); return () => clearInterval(interval); } - }, [isAllowed]); + }, [isAllowed, isReady]); return isAllowed; }; diff --git a/src/store/modules/Account/selectors/index.ts b/src/store/modules/Account/selectors/index.ts index 38a08755b..e5c67ec74 100644 --- a/src/store/modules/Account/selectors/index.ts +++ b/src/store/modules/Account/selectors/index.ts @@ -82,3 +82,6 @@ export const isTeamEnabledSelector = (state: RootState) => export const isAchievementsEnabledSelector = (state: RootState) => !!state.account.authConfig?.achievements?.enabled; + +export const isFaceDetectionEnabledSelector = (state: RootState) => + !!state.account.authConfig?.['face-detection']?.enabled; diff --git a/src/store/modules/FaceRecognition/sagas/initEmotionsAuth.ts b/src/store/modules/FaceRecognition/sagas/initEmotionsAuth.ts index 964b07d94..01a7d3851 100644 --- a/src/store/modules/FaceRecognition/sagas/initEmotionsAuth.ts +++ b/src/store/modules/FaceRecognition/sagas/initEmotionsAuth.ts @@ -2,15 +2,20 @@ import {is5xxApiError, isApiError} from '@api/client'; import {Api} from '@api/index'; -import {FACE_RECOGNITION_PICTURE_SIZE} from '@constants/faceRecognition'; -import {userIdSelector} from '@store/modules/Account/selectors'; +import { + isFaceDetectionEnabledSelector, + userIdSelector, +} from '@store/modules/Account/selectors'; import {FaceRecognitionActions} from '@store/modules/FaceRecognition/actions'; import { emotionsAuthEmotionsSelector, emotionsAuthSessionSelector, emotionsAuthStatusSelector, } from '@store/modules/FaceRecognition/selectors'; -import {isEmotionsAuthFinalised} from '@store/modules/FaceRecognition/utils'; +import { + getCroppedPictureUri, + isEmotionsAuthFinalised, +} from '@store/modules/FaceRecognition/utils'; import {shallowCompare} from '@utils/array'; import {showError} from '@utils/errors'; import {extractFramesWithFFmpeg, getPictureCropStartY} from '@utils/ffmpeg'; @@ -20,6 +25,29 @@ type Actions = ReturnType< typeof FaceRecognitionActions.EMOTIONS_AUTH.START.create >; +async function getCroppedFrames({ + frames, + pictureWidth, + cropStartY, + faceDetectionEnabled, +}: { + frames: string[]; + pictureWidth: number; + cropStartY: number; + faceDetectionEnabled: boolean; +}): Promise { + return Promise.all( + frames.map(frame => + getCroppedPictureUri({ + pictureUri: frame, + pictureWidth, + cropStartY, + faceDetectionEnabled, + }), + ), + ); +} + export function* initEmotionsAuthSaga(action: Actions) { try { const {videoUri, videoWidth, videoHeight} = action.payload; @@ -31,24 +59,36 @@ export function* initEmotionsAuthSaga(action: Actions) { userIdSelector, ); + const frames: SagaReturnType = yield call( + extractFramesWithFFmpeg, + { + inputUri: videoUri, + }, + ); + const cropStartY: SagaReturnType = yield call( getPictureCropStartY, {pictureWidth: videoWidth, pictureHeight: videoHeight}, ); - const frames: SagaReturnType = yield call( - extractFramesWithFFmpeg, + + const faceDetectionEnabled: ReturnType< + typeof isFaceDetectionEnabledSelector + > = yield select(isFaceDetectionEnabledSelector); + + const croppedFrames: SagaReturnType = yield call( + getCroppedFrames, { - inputUri: videoUri, + frames, + pictureWidth: videoWidth, cropStartY, - outputSize: FACE_RECOGNITION_PICTURE_SIZE, - width: videoWidth, + faceDetectionEnabled, }, ); const response: SagaReturnType = yield call(Api.faceRecognition.emotionsAuth, { userId, sessionId, - pictureUris: frames, + pictureUris: croppedFrames, }); const emotionsAuthStatus: ReturnType = yield select(emotionsAuthStatusSelector); diff --git a/src/store/modules/FaceRecognition/sagas/initFaceAuth.ts b/src/store/modules/FaceRecognition/sagas/initFaceAuth.ts index f3a501631..02afc64f9 100644 --- a/src/store/modules/FaceRecognition/sagas/initFaceAuth.ts +++ b/src/store/modules/FaceRecognition/sagas/initFaceAuth.ts @@ -2,13 +2,14 @@ import {is5xxApiError, isApiError} from '@api/client'; import {Api} from '@api/index'; -import {FACE_RECOGNITION_PICTURE_SIZE} from '@constants/faceRecognition'; -import {userIdSelector} from '@store/modules/Account/selectors'; +import { + isFaceDetectionEnabledSelector, + userIdSelector, +} from '@store/modules/Account/selectors'; import {FaceRecognitionActions} from '@store/modules/FaceRecognition/actions'; +import {getCroppedPictureUri} from '@store/modules/FaceRecognition/utils'; import {showError} from '@utils/errors'; -import {cropAndResizeWithFFmpeg, getPictureCropStartY} from '@utils/ffmpeg'; -import {getFilenameFromPath} from '@utils/file'; -import {cacheDirectory} from 'expo-file-system'; +import {getPictureCropStartY} from '@utils/ffmpeg'; import {call, put, SagaReturnType, select, spawn} from 'redux-saga/effects'; type Actions = ReturnType; @@ -22,15 +23,16 @@ export function* initFaceAuthSaga(action: Actions) { {pictureWidth, pictureHeight}, ); - const croppedPictureUri: SagaReturnType = - yield call(cropAndResizeWithFFmpeg, { - inputUri: pictureUri, - outputUri: `${cacheDirectory}/cropped_${getFilenameFromPath( - pictureUri, - )}`, - imgWidth: pictureWidth, + const faceDetectionEnabled: ReturnType< + typeof isFaceDetectionEnabledSelector + > = yield select(isFaceDetectionEnabledSelector); + + const croppedPictureUri: SagaReturnType = + yield call(getCroppedPictureUri, { + pictureUri, cropStartY, - outputSize: FACE_RECOGNITION_PICTURE_SIZE, + pictureWidth, + faceDetectionEnabled, }); const userId: ReturnType = yield select( userIdSelector, diff --git a/src/store/modules/FaceRecognition/utils.ts b/src/store/modules/FaceRecognition/utils.ts index d76651f78..56553f1a2 100644 --- a/src/store/modules/FaceRecognition/utils.ts +++ b/src/store/modules/FaceRecognition/utils.ts @@ -1,6 +1,16 @@ // SPDX-License-Identifier: ice License 1.0 +import {FACE_RECOGNITION_PICTURE_SIZE} from '@constants/faceRecognition'; import {EmotionsAuthStatus} from '@store/modules/FaceRecognition/types'; +import {cropAndResizeWithFFmpeg} from '@utils/ffmpeg'; +import {getFilenameFromPath} from '@utils/file'; +import * as FaceDetector from 'expo-face-detector'; +import { + FaceDetectorClassifications, + FaceDetectorLandmarks, + FaceDetectorMode, +} from 'expo-face-detector/src/FaceDetector'; +import {cacheDirectory} from 'expo-file-system'; export function isEmotionsAuthFinalised(status: EmotionsAuthStatus | null) { return ( @@ -12,8 +22,50 @@ export function isEmotionsAuthFinalised(status: EmotionsAuthStatus | null) { ); } -export function isEmotionsAuthInRecoverableFailureStatus( - status: EmotionsAuthStatus | null, -) { - return status === 'FAILED' || status === 'TRY_LATER'; +export async function getCroppedPictureUri({ + pictureUri, + pictureWidth, + cropStartY, + faceDetectionEnabled, +}: { + pictureUri: string; + pictureWidth: number; + cropStartY: number; + faceDetectionEnabled: boolean; +}) { + if (faceDetectionEnabled) { + const result = await FaceDetector.detectFacesAsync(pictureUri, { + mode: FaceDetectorMode.accurate, + detectLandmarks: FaceDetectorLandmarks.none, + runClassifications: FaceDetectorClassifications.none, + }); + const face = result?.faces?.[0]; + if (face) { + const {size, origin} = face.bounds; + const isTaller = size.height > size.width; + const faceCropStartX = isTaller + ? origin.x - (size.height - size.width) / 2 + : origin.x; + const faceCropStartY = origin.y; + const imgWidth = Math.max(size.width, size.height, pictureWidth); + return cropAndResizeWithFFmpeg({ + inputUri: pictureUri, + outputUri: `${cacheDirectory}/cropped_${getFilenameFromPath( + pictureUri, + )}`, + cropStartY: faceCropStartY, + cropStartX: faceCropStartX, + imgWidth, + outputSize: FACE_RECOGNITION_PICTURE_SIZE, + }); + } + } + return cropAndResizeWithFFmpeg({ + inputUri: pictureUri, + outputUri: `${cacheDirectory}/cropped_${getFilenameFromPath(pictureUri)}`, + imgWidth: pictureWidth, + cropStartY, + cropStartX: 0, + outputSize: FACE_RECOGNITION_PICTURE_SIZE, + }); } diff --git a/src/translations/locales/af.json b/src/translations/locales/af.json index cce1b0126..a3ebd78f9 100644 --- a/src/translations/locales/af.json +++ b/src/translations/locales/af.json @@ -1084,6 +1084,11 @@ "device_angle_warning": { "title": "Waarskuwing", "description": "Hou asseblief die telefoon regop terwyl jy na die kamera kyk" + }, + "camera_permission": { + "title": "Kamera toestemming", + "description": "Om voort te gaan, staan asseblief toegang tot die kamera toe.", + "action": "Staan toegang toe" } }, "override": { diff --git a/src/translations/locales/am.json b/src/translations/locales/am.json index 67d1bfa10..a29af9797 100644 --- a/src/translations/locales/am.json +++ b/src/translations/locales/am.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "ማስጠንቀቂያ", "description": "እባኮትን ወደ ካሜራ እየተመለከቱ ስልኩን ቀጥ አድርገው ይያዙት።" + }, + "camera_permission": { + "title": "የካሜራ ፍቃድ", + "description": "ለመቀጠል እባክዎን የካሜራ መዳረሻ ይፍቀዱ።", + "action": "መዳረሻ ፍቀድ" } }, "override": { diff --git a/src/translations/locales/ar.json b/src/translations/locales/ar.json index 9577847dc..7ecf90906 100644 --- a/src/translations/locales/ar.json +++ b/src/translations/locales/ar.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "تحذير", "description": "رجاءً احتفظ بالهاتف مستقيمًا أثناء النظر في الكاميرا" + }, + "camera_permission": { + "title": "إذن الكاميرا", + "description": "للمتابعة، يرجى السماح بالوصول إلى الكاميرا.", + "action": "السماح بالوصول" } }, "override": { diff --git a/src/translations/locales/az.json b/src/translations/locales/az.json index 5dae4e48d..0fb5e547e 100644 --- a/src/translations/locales/az.json +++ b/src/translations/locales/az.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Xəbərdarlıq", "description": "Kameraya baxarkən telefonu düz tutun, xahiş edirik" + }, + "camera_permission": { + "title": "Kamera icazəsi", + "description": "Davam etmək üçün, kamerağa girişi icazə verin.", + "action": "Girişə icazə verin" } }, "override": { diff --git a/src/translations/locales/bg.json b/src/translations/locales/bg.json index 3c3fd3a85..2ab958ecb 100644 --- a/src/translations/locales/bg.json +++ b/src/translations/locales/bg.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Предупреждение", "description": "Моля, дръжте телефона право, докато гледате камерата" + }, + "camera_permission": { + "title": "Разрешение за камера", + "description": "За да продължите, моля, разрешете достъп до камерата.", + "action": "Разрешете достъп" } }, "override": { diff --git a/src/translations/locales/bn.json b/src/translations/locales/bn.json index 9a2e9b651..4eededd70 100644 --- a/src/translations/locales/bn.json +++ b/src/translations/locales/bn.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "সতর্কতা", "description": "দয়া করে ক্যামেরা দেখার সময় ফোনটি সোজা রেখে রাখুন" + }, + "camera_permission": { + "title": "ক্যামেরা অনুমতি", + "description": "চালিয়ে যাওয়ার জন্য, দয়া করে ক্যামেরা অ্যাক্সেস অনুমতি দিন।", + "action": "অ্যাক্সেস অনুমতি দিন" } }, "override": { diff --git a/src/translations/locales/cs.json b/src/translations/locales/cs.json index ab6b89ac3..a0f2f786d 100644 --- a/src/translations/locales/cs.json +++ b/src/translations/locales/cs.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Varování", "description": "Prosím, držte telefon rovně při pohledu do kamery" + }, + "camera_permission": { + "title": "Oprávnění k fotoaparátu", + "description": "Pro pokračování povolte přístup k fotoaparátu.", + "action": "Povolit přístup" } }, "override": { diff --git a/src/translations/locales/de.json b/src/translations/locales/de.json index 495e6809c..aebefa2be 100644 --- a/src/translations/locales/de.json +++ b/src/translations/locales/de.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Warnung", "description": "Bitte halten Sie das Telefon gerade, während Sie in die Kamera schauen" + }, + "camera_permission": { + "title": "Kameraberechtigung", + "description": "Um fortzufahren, erlauben Sie bitte den Zugriff auf die Kamera.", + "action": "Zugriff erlauben" } }, "override": { diff --git a/src/translations/locales/el.json b/src/translations/locales/el.json index 28ce2ff2a..3018f0120 100644 --- a/src/translations/locales/el.json +++ b/src/translations/locales/el.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Προειδοποίηση", "description": "Κρατήστε το τηλέφωνο ευθύ, ενώ κοιτάτε την κάμερα, παρακαλώ" + }, + "camera_permission": { + "title": "Άδεια κάμερας", + "description": "Για να συνεχίσετε, παρακαλώ επιτρέψτε την πρόσβαση στην κάμερα.", + "action": "Επιτροπή πρόσβασης" } }, "override": { diff --git a/src/translations/locales/en.json b/src/translations/locales/en.json index a85c7b97a..c6544aad7 100644 --- a/src/translations/locales/en.json +++ b/src/translations/locales/en.json @@ -1078,6 +1078,11 @@ "device_angle_warning": { "title": "Warning", "description": "Please keep the phone straight while looking into camera" + }, + "camera_permission": { + "title": "Camera permission", + "description": "To continue, please allow access to camera.", + "action": "Allow access" } }, "override": { diff --git a/src/translations/locales/en.json.d.ts b/src/translations/locales/en.json.d.ts index 4f010a251..a5f9c3c72 100644 --- a/src/translations/locales/en.json.d.ts +++ b/src/translations/locales/en.json.d.ts @@ -672,6 +672,9 @@ export type Translations = { 'face_auth.emotions_recognition.emotions.surprise': null; 'face_auth.device_angle_warning.title': null; 'face_auth.device_angle_warning.description': null; + 'face_auth.camera_permission.title': null; + 'face_auth.camera_permission.description': null; + 'face_auth.camera_permission.action': null; 'override.whoInvitedYou.dontHaveInvitationCode': null; 'override.home.pioneer.description': null; 'override.home.tasks.invite_friends.description': null; diff --git a/src/translations/locales/es.json b/src/translations/locales/es.json index 4a13179f4..cc2af90cf 100644 --- a/src/translations/locales/es.json +++ b/src/translations/locales/es.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Advertencia", "description": "Por favor, mantén el teléfono recto mientras miras la cámara" + }, + "camera_permission": { + "title": "Permiso de cámara", + "description": "Para continuar, por favor permita el acceso a la cámara.", + "action": "Permitir acceso" } }, "override": { diff --git a/src/translations/locales/fa.json b/src/translations/locales/fa.json index d875f3ddc..dd2eb9570 100644 --- a/src/translations/locales/fa.json +++ b/src/translations/locales/fa.json @@ -1088,6 +1088,11 @@ "device_angle_warning": { "title": "اخطار", "description": "لطفاً تلفن را مستقیم نگه دارید در حین نگاه به دوربین" + }, + "camera_permission": { + "title": "مجوز دوربین", + "description": "برای ادامه، لطفا دسترسی به دوربین را اجازه دهید.", + "action": "اجازه دسترسی" } }, "override": { diff --git a/src/translations/locales/fr.json b/src/translations/locales/fr.json index 4f7177dc8..d94bee53b 100644 --- a/src/translations/locales/fr.json +++ b/src/translations/locales/fr.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Avertissement", "description": "Veuillez maintenir le téléphone droit en regardant dans l'appareil photo" + }, + "camera_permission": { + "title": "Permission de la caméra", + "description": "Pour continuer, veuillez autoriser l'accès à la caméra.", + "action": "Autoriser l'accès" } }, "override": { diff --git a/src/translations/locales/gu.json b/src/translations/locales/gu.json index 38c60d910..eec05336f 100644 --- a/src/translations/locales/gu.json +++ b/src/translations/locales/gu.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "ચેતવણી", "description": "કૃપા કરીને કેમેરામાં જોઇ રહ્યાં વખતે ફોનને સ્તંભન રાખો" + }, + "camera_permission": { + "title": "કેમેરા માટે પરવાહનીકરણ", + "description": "આગળ વધવા માટે, કૃપા કરીને કેમેરાને ઍક્સેસ આપવા માટે પરવાહનીકરણ આપો.", + "action": "ઍક્સેસ આપો" } }, "override": { diff --git a/src/translations/locales/he.json b/src/translations/locales/he.json index f01b828fd..735eeb112 100644 --- a/src/translations/locales/he.json +++ b/src/translations/locales/he.json @@ -1088,6 +1088,11 @@ "device_angle_warning": { "title": "אזהרה", "description": "אנא החזיקו את הטלפון במעמד הצפייה במצלמה" + }, + "camera_permission": { + "title": "רשות מצלמה", + "description": "להמשך, אנא אשר גישה למצלמה.", + "action": "לאשר גישה" } }, "override": { diff --git a/src/translations/locales/hi.json b/src/translations/locales/hi.json index 255f84f85..7cd1649a1 100644 --- a/src/translations/locales/hi.json +++ b/src/translations/locales/hi.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "चेतावनी", "description": "कृपया कैमरा में देखते समय फ़ोन को सीधा रखें" + }, + "camera_permission": { + "title": "कैमरा अनुमति", + "description": "आगे बढ़ने के लिए, कृपया कैमरे तक पहुँच देने की अनुमति दें।", + "action": "पहुँच देने की अनुमति दें" } }, "override": { diff --git a/src/translations/locales/hu.json b/src/translations/locales/hu.json index 78cb8d606..efb36891e 100644 --- a/src/translations/locales/hu.json +++ b/src/translations/locales/hu.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Figyelmeztetés", "description": "Kérjük, tartsa a telefont egyenesen, amikor a kamerába néz" + }, + "camera_permission": { + "title": "Kamera engedély", + "description": "Folytatáshoz engedélyezze a kamera hozzáférését.", + "action": "Hozzáférés engedélyezése" } }, "override": { diff --git a/src/translations/locales/id.json b/src/translations/locales/id.json index 6be019fae..c4b86d17b 100644 --- a/src/translations/locales/id.json +++ b/src/translations/locales/id.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Peringatan", "description": "Mohon tetapkan ponsel lurus saat melihat ke kamera" + }, + "camera_permission": { + "title": "Izin Kamera", + "description": "Untuk melanjutkan, harap izinkan akses ke kamera.", + "action": "Izinkan akses" } }, "override": { diff --git a/src/translations/locales/it.json b/src/translations/locales/it.json index 14965862a..6911bf7cb 100644 --- a/src/translations/locales/it.json +++ b/src/translations/locales/it.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Avviso", "description": "Si prega di tenere il telefono dritto mentre si guarda nella fotocamera" + }, + "camera_permission": { + "title": "Permesso fotocamera", + "description": "Per continuare, permetti l'accesso alla fotocamera.", + "action": "Permetti accesso" } }, "override": { diff --git a/src/translations/locales/ja.json b/src/translations/locales/ja.json index dd1ed39c1..4e10eb8f3 100644 --- a/src/translations/locales/ja.json +++ b/src/translations/locales/ja.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "警告", "description": "カメラを見ながら電話をまっすぐに保ってください" + }, + "camera_permission": { + "title": "カメラの許可", + "description": "続行するには、カメラへのアクセスを許可してください。", + "action": "アクセスを許可" } }, "override": { diff --git a/src/translations/locales/jv.json b/src/translations/locales/jv.json index d2c900683..bc39143bd 100644 --- a/src/translations/locales/jv.json +++ b/src/translations/locales/jv.json @@ -994,6 +994,11 @@ "device_angle_warning": { "title": "Peringatan", "description": "Monggo tuku telepon kokoh nalika ngelihat kamera" + }, + "camera_permission": { + "title": "Izin Kamera", + "description": "Supaya tetep terus, monggo restuiakses menyang kamera.", + "action": "Restuiakses dianjurake" } }, "override": { diff --git a/src/translations/locales/kn.json b/src/translations/locales/kn.json index 281b9cdc3..1850de41a 100644 --- a/src/translations/locales/kn.json +++ b/src/translations/locales/kn.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "ಎಚ್ಚರಿಕೆ", "description": "ಕ್ಯಾಮರಾವನ್ನು ನೋಡುವಾಗ ಫೋನ್ ಅನ್ನು ನೇರವಾಗಿ ಇರಿಸಿ" + }, + "camera_permission": { + "title": "ಕ್ಯಾಮೆರಾ ಅನುಮತಿ", + "description": "ಮುಂದುವರಿಸಲು, ದಯವಿಟ್ಟು ಕ್ಯಾಮೆರಾ ಅನುಮತಿಯನ್ನು ನೀಡಿ.", + "action": "ಅನುಮತಿ ನೀಡಿ" } }, "override": { diff --git a/src/translations/locales/ko.json b/src/translations/locales/ko.json index 3e35a6f7b..4065631a0 100644 --- a/src/translations/locales/ko.json +++ b/src/translations/locales/ko.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "경고", "description": "카메라를 보면서 전화를 곧게 유지해주세요" + }, + "camera_permission": { + "title": "카메라 권한", + "description": "계속하려면 카메라 접근을 허용하십시오.", + "action": "접근 허용" } }, "override": { diff --git a/src/translations/locales/mr.json b/src/translations/locales/mr.json index 5d32fc9a7..3d4b5683f 100644 --- a/src/translations/locales/mr.json +++ b/src/translations/locales/mr.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "चेतावणी", "description": "कॅमेऱ्यात पहात असताना कृपया फोन सरळ ठेवा" + }, + "camera_permission": { + "title": "कॅमेरा परवाहनी", + "description": "सुरुवात करण्यासाठी, कृपया कॅमेरा साठी प्रवेश द्या.", + "action": "प्रवेश द्या" } }, "override": { diff --git a/src/translations/locales/ms.json b/src/translations/locales/ms.json index 53b915f21..7e2e4cbc1 100644 --- a/src/translations/locales/ms.json +++ b/src/translations/locales/ms.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Arahan", "description": "Sila pegang telefon tegak sambil melihat ke kamera" + }, + "camera_permission": { + "title": "Kebenaran Kamera", + "description": "Untuk teruskan, sila benarkan akses kepada kamera.", + "action": "Benarkan akses" } }, "override": { diff --git a/src/translations/locales/nb.json b/src/translations/locales/nb.json index f244b96de..7528f30fd 100644 --- a/src/translations/locales/nb.json +++ b/src/translations/locales/nb.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Advarsel", "description": "Vennligst hold telefonen rett mens du ser inn i kameraet" + }, + "camera_permission": { + "title": "Kameratillatelse", + "description": "For å fortsette, vennligst gi tilgang til kameraet.", + "action": "Tillat tilgang" } }, "override": { diff --git a/src/translations/locales/nn.json b/src/translations/locales/nn.json index 7b0bf0d7e..0803ba551 100644 --- a/src/translations/locales/nn.json +++ b/src/translations/locales/nn.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Advarsel", "description": "Vennligst hald telefonen rett medan du ser inn i kameraet" + }, + "camera_permission": { + "title": "Kameratillatelse", + "description": "For å fortsette, vennligst gi tilgang til kameraet.", + "action": "Tillat tilgang" } }, "override": { diff --git a/src/translations/locales/pa.json b/src/translations/locales/pa.json index 0830aeb33..ccc3086cb 100644 --- a/src/translations/locales/pa.json +++ b/src/translations/locales/pa.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "ਚੇਤਾਵਨੀ", "description": "ਕਿਰਪਾ ਕਰਕੇ ਕੈਮਰੇ ਵਿੱਚ ਦੇਖਦੇ ਸਮੇਂ ਫ਼ੋਨ ਨੂੰ ਸਿੱਧਾ ਰੱਖੋ" + }, + "camera_permission": { + "title": "ਕੈਮਰਾ ਅਨੁਮਤੀ", + "description": "ਜਾਰੀ ਰੱਖਣ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਕੈਮਰੇ ਦੀ ਪਹੁੰਚ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ.", + "action": "ਪਹੁੰਚ ਦੀ ਇਜਾਜ਼ਤ ਦੇਣ." } }, "override": { diff --git a/src/translations/locales/pl.json b/src/translations/locales/pl.json index d194f7805..d8fdafab7 100644 --- a/src/translations/locales/pl.json +++ b/src/translations/locales/pl.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Ostrzeżenie", "description": "Proszę trzymać telefon prosto podczas patrzenia w kamerę" + }, + "camera_permission": { + "title": "Uprawnienia aparatu", + "description": "Aby kontynuować, proszę zezwolić na dostęp do aparatu.", + "action": "Zezwól na dostęp" } }, "override": { diff --git a/src/translations/locales/pt.json b/src/translations/locales/pt.json index 58c8f9450..dcca9b376 100644 --- a/src/translations/locales/pt.json +++ b/src/translations/locales/pt.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Aviso", "description": "Por favor, mantenha o telefone reto ao olhar para a câmera" + }, + "camera_permission": { + "title": "Permissão de Câmera", + "description": "Para continuar, por favor, permita o acesso à câmera.", + "action": "Permitir acesso" } }, "override": { diff --git a/src/translations/locales/ro.json b/src/translations/locales/ro.json index 0a52c4784..7ca8c1854 100644 --- a/src/translations/locales/ro.json +++ b/src/translations/locales/ro.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Avertisment", "description": "Vă rugăm să țineți telefonul drept în timp ce priviți în cameră" + }, + "camera_permission": { + "title": "Permisiune cameră", + "description": "Pentru a continua, vă rugăm să permiteți accesul la cameră.", + "action": "Permiteți accesul" } }, "override": { diff --git a/src/translations/locales/ru.json b/src/translations/locales/ru.json index ce94ce233..c71b8c119 100644 --- a/src/translations/locales/ru.json +++ b/src/translations/locales/ru.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Предупреждение", "description": "Пожалуйста, держите телефон прямо при смотрении в камеру" + }, + "camera_permission": { + "title": "Разрешение на камеру", + "description": "Для продолжения, пожалуйста, разрешите доступ к камере.", + "action": "Разрешить доступ" } }, "override": { diff --git a/src/translations/locales/sk.json b/src/translations/locales/sk.json index 08687e1de..f8e288bc8 100644 --- a/src/translations/locales/sk.json +++ b/src/translations/locales/sk.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Upozornenie", "description": "Prosím, držte telefón pri pohľade do kamery rovno" + }, + "camera_permission": { + "title": "Povolenie kamery", + "description": "Pre pokračovanie povolte prístup ku kamere.", + "action": "Povoliť prístup" } }, "override": { diff --git a/src/translations/locales/sl.json b/src/translations/locales/sl.json index 51d8e816e..7c87a9acc 100644 --- a/src/translations/locales/sl.json +++ b/src/translations/locales/sl.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Opozorilo", "description": "Prosimo, ohranite telefon pokonci med gledanjem v kamero" + }, + "camera_permission": { + "title": "Dovoljenje za kamero", + "description": "Za nadaljevanje dovolite dostop do kamere.", + "action": "Dovoli dostop" } }, "override": { diff --git a/src/translations/locales/sq.json b/src/translations/locales/sq.json index d36bf68f5..5b40b10a6 100644 --- a/src/translations/locales/sq.json +++ b/src/translations/locales/sq.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Paralajmërim", "description": "Ju lutemi mbani telefonin drejt ndërsa shikoni në kamerë" + }, + "camera_permission": { + "title": "Leja e kamerës", + "description": "Për të vazhduar, ju lutem lejoni qasjen në kamerë.", + "action": "Lejo qasjen" } }, "override": { diff --git a/src/translations/locales/sv.json b/src/translations/locales/sv.json index b91bf9136..ea7492635 100644 --- a/src/translations/locales/sv.json +++ b/src/translations/locales/sv.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Varning", "description": "Vänligen håll telefonen rak medan du tittar i kameran" + }, + "camera_permission": { + "title": "Kameratillstånd", + "description": "För att fortsätta, vänligen tillåt åtkomst till kameran.", + "action": "Tillåt åtkomst" } }, "override": { diff --git a/src/translations/locales/te.json b/src/translations/locales/te.json index 50c9c64e2..a4efecf7d 100644 --- a/src/translations/locales/te.json +++ b/src/translations/locales/te.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "హెచ్చరిక", "description": "దయచేసి కెమెరాలోకి చూస్తున్నప్పుడు ఫోన్‌ని నిటారుగా ఉంచండి" + }, + "camera_permission": { + "title": "కెమెరా అనుమతి", + "description": "కొన్నిసార్లు ప్రారంభించడానికి, దయచేసి కెమెరా యాక్సెస్ అనుమతి ఇవ్వండి.", + "action": "యాక్సెస్ ఇవ్వండి" } }, "override": { diff --git a/src/translations/locales/th.json b/src/translations/locales/th.json index 5d3fd3ab0..944a007fa 100644 --- a/src/translations/locales/th.json +++ b/src/translations/locales/th.json @@ -1082,6 +1082,11 @@ "device_angle_warning": { "title": "คำเตือน", "description": "โปรดเก็บโทรศัพท์ตรงขณะดูกล้อง" + }, + "camera_permission": { + "title": "การอนุญาตใช้กล้อง", + "description": "เพื่อดำเนินการต่อ โปรดอนุญาตการเข้าถึงกล้อง", + "action": "อนุญาตการเข้าถึง" } }, "override": { diff --git a/src/translations/locales/tl-ph.json b/src/translations/locales/tl-ph.json index 7c19da95b..a9a6fa26e 100644 --- a/src/translations/locales/tl-ph.json +++ b/src/translations/locales/tl-ph.json @@ -994,6 +994,11 @@ "device_angle_warning": { "title": "Babala", "description": "Mangyaring panatilihing tuwid ang telepono habang tinitingnan ang kamera" + }, + "camera_permission": { + "title": "Pahintulot ng Kamera", + "description": "Upang magpatuloy, paki-allow ang access sa kamera.", + "action": "Payagan ang access" } }, "override": { diff --git a/src/translations/locales/tr.json b/src/translations/locales/tr.json index c3a172016..64e721b8d 100644 --- a/src/translations/locales/tr.json +++ b/src/translations/locales/tr.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Uyarı", "description": "Lütfen kameraya bakarken telefonu düz tutun" + }, + "camera_permission": { + "title": "Kamera İzni", + "description": "Devam etmek için lütfen kameraya erişime izin verin.", + "action": "Erişime izin ver" } }, "override": { diff --git a/src/translations/locales/uk.json b/src/translations/locales/uk.json index 472031c37..5b082f87c 100644 --- a/src/translations/locales/uk.json +++ b/src/translations/locales/uk.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Попередження", "description": "Будь ласка, тримайте телефон прямо під час перегляду камери" + }, + "camera_permission": { + "title": "Дозвіл на камеру", + "description": "Для продовження, будь ласка, надайте доступ до камери.", + "action": "Надати доступ" } }, "override": { diff --git a/src/translations/locales/ur.json b/src/translations/locales/ur.json index 8fa879862..3b99628bf 100644 --- a/src/translations/locales/ur.json +++ b/src/translations/locales/ur.json @@ -1088,6 +1088,11 @@ "device_angle_warning": { "title": "وارننگ", "description": "براہ کرم کیمرے میں دیکھتے وقت فون کو سیدھا رکھیں" + }, + "camera_permission": { + "title": "کیمرہ اجازت", + "description": "جاری رہنے کے لئے براہ کرم کیمرے تک رسائی دیں۔", + "action": "رسائی دینے کی اجازت دیں" } }, "override": { diff --git a/src/translations/locales/vi.json b/src/translations/locales/vi.json index 8ba497ed4..d97cab6c0 100644 --- a/src/translations/locales/vi.json +++ b/src/translations/locales/vi.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "Cảnh báo", "description": "Vui lòng giữ điện thoại thẳng khi nhìn vào máy ảnh" + }, + "camera_permission": { + "title": "Quyền truy cập máy ảnh", + "description": "Để tiếp tục, vui lòng cho phép truy cập máy ảnh.", + "action": "Cho phép truy cập" } }, "override": { diff --git a/src/translations/locales/zh-cn.json b/src/translations/locales/zh-cn.json index 5022198fc..fa03b2a8d 100644 --- a/src/translations/locales/zh-cn.json +++ b/src/translations/locales/zh-cn.json @@ -1070,6 +1070,11 @@ "device_angle_warning": { "title": "警告", "description": "查看相机时,请保持手机竖直" + }, + "camera_permission": { + "title": "相机权限", + "description": "请允许访问相机以继续。", + "action": "允许访问" } }, "override": { diff --git a/src/translations/locales/zh-hant.json b/src/translations/locales/zh-hant.json index 2d067500c..4d9518ce6 100644 --- a/src/translations/locales/zh-hant.json +++ b/src/translations/locales/zh-hant.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "警告", "description": "查看相機時,請保持手機垂直" + }, + "camera_permission": { + "title": "相機權限", + "description": "請允許訪問相機以繼續。", + "action": "允許訪問" } }, "override": { diff --git a/src/translations/locales/zh.json b/src/translations/locales/zh.json index 7b99f9aea..fde8c6b7f 100644 --- a/src/translations/locales/zh.json +++ b/src/translations/locales/zh.json @@ -1081,6 +1081,11 @@ "device_angle_warning": { "title": "警告", "description": "查看相机时,请保持手机垂直" + }, + "camera_permission": { + "title": "相机权限", + "description": "请允许访问相机以继续。", + "action": "允许访问" } }, "override": { diff --git a/src/utils/ffmpeg.ts b/src/utils/ffmpeg.ts index 97d47f3a2..82167ec79 100644 --- a/src/utils/ffmpeg.ts +++ b/src/utils/ffmpeg.ts @@ -36,15 +36,23 @@ export async function cropAndResizeWithFFmpeg({ imgWidth, outputSize, cropStartY, + cropStartX, }: { inputUri: string; outputUri: string; imgWidth: number; outputSize: number; cropStartY: number; + cropStartX: number; }) { try { - const command = `-i "${inputUri}" -vf "crop=${imgWidth}:${imgWidth}:0:${cropStartY},scale=${outputSize}:${outputSize}" -update true "${outputUri}"`; + const command = `-i "${inputUri}" -vf "crop=${imgWidth}:${imgWidth}:${Math.max( + cropStartX, + 0, + )}:${Math.max( + cropStartY, + 0, + )},scale=${outputSize}:${outputSize}" -update true "${outputUri}"`; const session = await FFmpegKit.execute(command); const returnCode = await session?.getReturnCode(); @@ -61,21 +69,15 @@ export async function cropAndResizeWithFFmpeg({ export async function extractFramesWithFFmpeg({ inputUri, - width, - outputSize, - cropStartY, }: { inputUri: string; - width: number; - outputSize: number; - cropStartY: number; }): Promise { let output; try { const outputUri = `${cacheDirectory}/${getFilenameFromPathWithoutExtension( inputUri, )}_%03d.jpg`; - const command = `-i "${inputUri}" -vf "crop=${width}:${width}:0:${cropStartY},scale=${outputSize}:${outputSize},setsar=1,fps=3" "${outputUri}"`; + const command = `-i "${inputUri}" -vf "setsar=1,fps=3" "${outputUri}"`; const session = await FFmpegKit.execute(command); const returnCode = await session?.getReturnCode(); diff --git a/yarn.lock b/yarn.lock index fe2b5fdf8..d260bf4c7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6199,6 +6199,11 @@ expo-constants@~14.4.2: "@expo/config" "~8.1.0" uuid "^3.3.2" +expo-face-detector@12.4.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/expo-face-detector/-/expo-face-detector-12.4.0.tgz#cc6d021edbcc29a5b35ccb705bc5b7183eff7984" + integrity sha512-RWmbpXIerb/M82OIqRCVOlfBR7jzsL/zMZ5p/It39E6QNtNsfqbuR+WGe3+tE5hKB8fmhTqZBjUMGJaDMnww9g== + expo-file-system@~15.4.0, expo-file-system@~15.4.2: version "15.4.2" resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-15.4.2.tgz#f18e9d84f06a50eb4084b4a34ca7ca9c5a42f92e"