Merge pull request #2200 from ecency/sa/-qr-screen

[WIP] QR Screen
This commit is contained in:
Feruz M 2022-03-16 20:32:53 +02:00 committed by GitHub
commit 0f80e6c0d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 422 additions and 9 deletions

View File

@ -153,6 +153,8 @@ android {
abiFilters "armeabi-v7a",'x86',"arm64-v8a",'x86_64'
}
missingDimensionStrategy 'store', 'play'
missingDimensionStrategy 'react-native-camera', 'general'
missingDimensionStrategy 'react-native-camera', 'mlkit'
}
dexOptions {

View File

@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
<uses-permission android:name="android.permission.VIBRATE"/>
<queries>
<intent>

View File

@ -5,7 +5,8 @@ platform :ios, '10.0'
target 'Ecency' do
config = use_native_modules!
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
# Pods for Ecency
use_react_native!(:path => config["reactNativePath"])

View File

@ -140,6 +140,8 @@ PODS:
- nanopb/encode (= 1.30906.0)
- nanopb/decode (1.30906.0)
- nanopb/encode (1.30906.0)
- Permission-Camera (3.3.0):
- RNPermissions
- PromisesObjC (1.2.12)
- Protobuf (3.17.0)
- RCTRequired (0.63.4)
@ -308,6 +310,14 @@ PODS:
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsinspector (0.63.4)
- react-native-camera (4.2.1):
- React-Core
- react-native-camera/RCT (= 4.2.1)
- react-native-camera/RN (= 4.2.1)
- react-native-camera/RCT (4.2.1):
- React-Core
- react-native-camera/RN (4.2.1):
- React-Core
- react-native-cameraroll (1.8.1):
- React
- react-native-config (1.4.2):
@ -443,6 +453,8 @@ PODS:
- TOCropViewController
- RNOS (1.2.6):
- React
- RNPermissions (3.3.0):
- React-Core
- RNReanimated (1.13.2):
- React-Core
- RNScreens (2.18.1):
@ -477,6 +489,7 @@ DEPENDENCIES:
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- lottie-ios (from `../node_modules/lottie-ios`)
- lottie-react-native (from `../node_modules/lottie-react-native`)
- Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
@ -489,6 +502,7 @@ DEPENDENCIES:
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-camera (from `../node_modules/react-native-camera`)
- "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)"
- react-native-config (from `../node_modules/react-native-config`)
- react-native-date-picker (from `../node_modules/react-native-date-picker`)
@ -525,6 +539,7 @@ DEPENDENCIES:
- RNIap (from `../node_modules/react-native-iap`)
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- RNOS (from `../node_modules/react-native-os`)
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
@ -583,6 +598,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/lottie-ios"
lottie-react-native:
:path: "../node_modules/lottie-react-native"
Permission-Camera:
:path: "../node_modules/react-native-permissions/ios/Camera"
RCTRequired:
:path: "../node_modules/react-native/Libraries/RCTRequired"
RCTTypeSafety:
@ -603,6 +620,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-camera:
:path: "../node_modules/react-native-camera"
react-native-cameraroll:
:path: "../node_modules/@react-native-community/cameraroll"
react-native-config:
@ -675,6 +694,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-image-crop-picker"
RNOS:
:path: "../node_modules/react-native-os"
RNPermissions:
:path: "../node_modules/react-native-permissions"
RNReanimated:
:path: "../node_modules/react-native-reanimated"
RNScreens:
@ -720,6 +741,7 @@ SPEC CHECKSUMS:
lottie-react-native: 96361a9891cf651534ea35c4f85f33d4cf14ed13
MatomoTracker: 24a846c9d3aa76933183fe9d47fd62c9efa863fb
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
Permission-Camera: 597646618d1edcc055a3f660844c2ee6de8e0596
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
Protobuf: 7327d4444215b5f18e560a97f879ff5503c4581c
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
@ -732,6 +754,7 @@ SPEC CHECKSUMS:
React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
react-native-camera: 3eae183c1d111103963f3dd913b65d01aef8110f
react-native-cameraroll: e2917a5e62da9f10c3d525e157e25e694d2d6dfa
react-native-config: c98128a72bc2c3a1ca72caec0b021f0fa944aa29
react-native-date-picker: 242eec7af56cea5fb2706d5db5d3837060b3884b
@ -768,6 +791,7 @@ SPEC CHECKSUMS:
RNIap: 536b64f090a3d2e707b4f55d9aa5351482f20ea4
RNImageCropPicker: 08ba3a2e2f4f8833d606f01906c371e382c4dea9
RNOS: 6f2f9a70895bbbfbdad7196abd952e7b01d45027
RNPermissions: bcd846e8f5a7f39e921cc7ca7172e2de0e698b6f
RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad
RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
@ -779,6 +803,6 @@ SPEC CHECKSUMS:
toolbar-android: 85f3ef4d691469f2d304e7dee4bca013aa1ba1ff
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
PODFILE CHECKSUM: 9c48318ea254e2c78005a7a0c2d8bfc14ddd783d
PODFILE CHECKSUM: d6141a7068f8cadf52fa413e9f123818237316d9
COCOAPODS: 1.11.2

View File

@ -84,6 +84,7 @@
"react-native-actionsheet": "ecency/react-native-actionsheet",
"react-native-animatable": "^1.3.3",
"react-native-autoheight-webview": "^1.5.8",
"react-native-camera": "^4.2.1",
"react-native-config": "luggit/react-native-config#master",
"react-native-crypto": "^2.2.0",
"react-native-date-picker": "^3.2.7",
@ -108,9 +109,11 @@
"react-native-modal-translucent": "^5.0.0",
"react-native-navigation-bar-color": "^1.0.0",
"react-native-os": "^1.0.1",
"react-native-permissions": "^3.3.0",
"react-native-portalize": "^1.0.7",
"react-native-progress": "^5.0.0",
"react-native-push-notification": "^7.3.1",
"react-native-qrcode-scanner": "^1.5.5",
"react-native-qrcode-svg": "^6.0.3",
"react-native-randombytes": "^3.6.1",
"react-native-reanimated": "^1",

View File

@ -95,6 +95,7 @@ import { QuickProfileModal } from './organisms';
import QuickReplyModal from './quickReplyModal/quickReplyModalView';
import Tooltip from './tooltip/tooltipView';
import VideoPlayer from './videoPlayer/videoPlayerView';
import QRModal from './qrModal/qrModalView';
// Basic UI Elements
import {
@ -238,4 +239,5 @@ export {
QuickReplyModal,
Tooltip,
VideoPlayer,
QRModal,
};

View File

@ -0,0 +1,39 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
sheetContent: {
backgroundColor: '$black',
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
zIndex: 999,
},
container: {
flex: 1,
},
mainContainer: {
backgroundColor: '$black',
height: '100%',
},
scannerContainer: {
backgroundColor: '$black',
},
cameraContainer: {
backgroundColor: '$black',
},
cameraStyle: {
width: '100%',
height: '100%',
},
activityIndicatorContainer: {
position: 'absolute',
top: 0,
bottom: 0,
left: 0,
right: 0,
justifyContent: 'center',
alignItems: 'center',
},
activityIndicator: {},
});

View File

@ -0,0 +1,163 @@
import React, { useEffect, useRef, useState } from 'react';
import { ActivityIndicator, Alert, PermissionsAndroid, Platform, Text, View } from 'react-native';
import ActionSheet from 'react-native-actions-sheet';
import EStyleSheet from 'react-native-extended-stylesheet';
import styles from './qrModalStyles';
import { useAppDispatch, useAppSelector } from '../../hooks';
import { toggleQRModal } from '../../redux/actions/uiAction';
import QRCodeScanner from 'react-native-qrcode-scanner';
import { deepLinkParser } from '../../utils/deepLinkParser';
import { useIntl } from 'react-intl';
import { navigate } from '../../navigation/service';
import { Icon } from '..';
import { Dimensions } from 'react-native';
import { check, request, PERMISSIONS, RESULTS, openSettings } from 'react-native-permissions';
export interface QRModalProps {}
const screenHeight = Dimensions.get('window').height;
export const QRModal = ({}: QRModalProps) => {
const dispatch = useAppDispatch();
const intl = useIntl();
const isVisibleQRModal = useAppSelector((state) => state.ui.isVisibleQRModal);
const currentAccount = useAppSelector((state) => state.account.currentAccount);
const [isScannerActive, setIsScannerActive] = useState(true);
const [isProcessing, setIsProcessing] = useState(false);
const sheetModalRef = useRef<ActionSheet>();
const scannerRef = useRef(null);
useEffect(() => {
if (isVisibleQRModal) {
requestCameraPermission();
sheetModalRef.current.show();
} else {
sheetModalRef.current.hide();
}
}, [isVisibleQRModal]);
const requestCameraPermission = async () => {
if (Platform.OS === 'ios') {
const permissionStatus = await check(PERMISSIONS.IOS.CAMERA);
if (permissionStatus !== RESULTS.GRANTED) {
request(PERMISSIONS.IOS.CAMERA).then((result) => {
if (result === RESULTS.GRANTED) {
console.log('Camera permission granted');
} else {
console.log('Camera permission blocked');
Alert.alert(
'Unable to get Camera permission',
'Please grant camera permission in ecency settings.',
[
{
text: 'Close',
onPress: () => {
_onClose();
},
style: 'cancel',
},
{
text: 'Allow',
onPress: () => {
openSettings();
},
},
],
);
}
});
}
}
if (Platform.OS === 'android') {
try {
const permissionStatus = await PermissionsAndroid.check(
PermissionsAndroid.PERMISSIONS.CAMERA,
);
if (!permissionStatus) {
const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.CAMERA, {
title: 'Ecency Camera Permission',
message: 'To scan QR, Ecency needs your permission.',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
});
if (granted === PermissionsAndroid.RESULTS.GRANTED) {
console.log('Camera permission granted');
} else {
console.log('Camera permission denied');
}
}
} catch (err) {
console.warn(err);
}
}
};
const _onClose = () => {
dispatch(toggleQRModal(false));
};
const onSuccess = (e) => {
setIsScannerActive(false);
_handleDeepLink(e.data);
};
const _handleDeepLink = async (url) => {
setIsProcessing(true);
const deepLinkData = await deepLinkParser(url, currentAccount);
const { routeName, params, key } = deepLinkData || {};
setIsProcessing(false);
if (routeName && params && key) {
setIsScannerActive(false);
_onClose();
navigate(deepLinkData);
} else {
Alert.alert('Unsupported URL!', 'Please scan a valid ecency url.', [
{
text: 'Close',
onPress: () => {
_onClose();
},
style: 'cancel',
},
{
text: 'Rescan',
onPress: () => {
setIsScannerActive(true);
scannerRef.current?.reactivate();
},
},
]);
}
};
return (
<ActionSheet
ref={sheetModalRef}
gestureEnabled={true}
containerStyle={{ ...styles.sheetContent, height: screenHeight }}
onClose={_onClose}
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
>
<View style={styles.mainContainer}>
<QRCodeScanner
reactivate={isScannerActive}
showMarker={true}
ref={scannerRef}
onRead={onSuccess}
topViewStyle={{ display: 'none' }}
bottomViewStyle={{ display: 'none' }}
containerStyle={styles.scannerContainer}
cameraContainerStyle={styles.cameraContainer}
cameraStyle={styles.cameraStyle}
/>
{isProcessing && (
<View style={styles.activityIndicatorContainer}>
<ActivityIndicator color={'white'} style={styles.activityIndicator} />
</View>
)}
</View>
</ActionSheet>
);
};
export default QRModal;

View File

@ -12,6 +12,7 @@ import { injectIntl, useIntl } from 'react-intl';
import LinearGradient from 'react-native-linear-gradient';
import VersionNumber from 'react-native-version-number';
import { isEmpty } from 'lodash';
import { useDispatch } from 'react-redux';
import { getStorageType } from '../../../realm/realm';
// Components
@ -28,6 +29,7 @@ import { getVotingPower } from '../../../utils/manaBar';
// Styles
import styles from './sideMenuStyles';
import { OptionsModal } from '../../atoms';
import { toggleQRModal } from '../../../redux/actions/uiAction';
// Images
const SIDE_MENU_BACKGROUND = require('../../../assets/side_menu_background.png');
@ -40,6 +42,7 @@ const SideMenuView = ({
handlePressOptions,
}) => {
const intl = useIntl();
const dispatch = useDispatch();
const ActionSheetRef = useRef(null);
const [menuItems, setMenuItems] = useState(
@ -81,6 +84,10 @@ const SideMenuView = ({
});
return;
} */
if (item.id === 'qr') {
dispatch(toggleQRModal(true));
return;
}
navigateToRoute(item.route);
};
@ -102,7 +109,11 @@ const SideMenuView = ({
>
<View style={styles.itemWrapper}>
{item.item.icon && (
<Icon iconType="SimpleLineIcons" style={styles.listItemIcon} name={item.item.icon} />
<Icon
iconType={item.item.iconType ? item.item.iconType : 'SimpleLineIcons'}
style={styles.listItemIcon}
name={item.item.icon}
/>
)}
{item.item.username && (
<UserAvatar noAction username={item.item.username} style={styles.otherUserAvatar} />

View File

@ -274,7 +274,8 @@
"create_a_new_account": "Create a new account",
"add_an_existing_account": "Add an existing account",
"accounts": "Accounts",
"refer":"Refer & Earn"
"refer":"Refer & Earn",
"qr": "QR Scan"
},
"header": {
"title": "Login to customize your feed",
@ -743,6 +744,11 @@
"delegate_hp": "Delegate HP",
"earned": "Earned Points",
"pending": "Pending Points",
"empty_text": "Refer your loved ones today and earn free points"
"empty_text": "Refer your loved ones today and earn free points",
},
"qr":{
"qr_scan": "QR Scan",
"open": "Open URL",
"detected_url": "Detected URL"
}
}

View File

@ -32,6 +32,7 @@ export default {
COMMUNITIES: `Communities${SCREEN_SUFFIX}`,
WEB_BROWSER: `WebBrowser${SCREEN_SUFFIX}`,
REFER: `Refer${SCREEN_SUFFIX}`,
QR: `QR${SCREEN_SUFFIX}`,
},
DRAWER: {
MAIN: `Main${DRAWER_SUFFIX}`,

View File

@ -25,6 +25,13 @@ const authMenuItems = [
icon: 'people',
id: 'communities',
},
{
name: 'QR Scan',
route: '',
icon: 'qrcode-scan',
iconType: 'MaterialCommunityIcons',
id: 'qr',
},
{
name: 'Refer $ Earn',
route: ROUTES.SCREENS.REFER,

View File

@ -10,7 +10,8 @@ import {
HIDE_ACTION_MODAL,
SET_AVATAR_CACHE_STAMP,
SHOW_PROFILE_MODAL,
HIDE_PROFILE_MODAL
HIDE_PROFILE_MODAL,
TOGGLE_QR_MODAL
} from '../constants/constants';
export const updateActiveBottomTab = (payload:string) => ({
@ -70,3 +71,8 @@ export const setAvatarCacheStamp = (payload:number) => ({
payload,
type:SET_AVATAR_CACHE_STAMP
})
export const toggleQRModal = (payload:boolean) => ({
payload,
type: TOGGLE_QR_MODAL,
});

View File

@ -52,6 +52,7 @@ export const TOAST_NOTIFICATION = 'TOAST_NOTIFICATION';
export const HIDE_POSTS_THUMBNAILS = 'HIDE_POSTS_THUMBNAILS';
export const RC_OFFER = 'RC_OFFER';
export const TOGGLE_ACCOUNTS_BOTTOM_SHEET = 'TOGGLE_ACCOUNTS_BOTTOM_SHEET';
export const TOGGLE_QR_MODAL = 'TOGGLE_QR_MODAL';
export const SHOW_ACTION_MODAL = 'SHOW_ACTION_MODAL';
export const HIDE_ACTION_MODAL = 'HIDE_ACTION_MODAL';
export const SET_AVATAR_CACHE_STAMP = 'SET_AVATAR_CACHE_STAMP';

View File

@ -9,6 +9,7 @@ import {
SET_AVATAR_CACHE_STAMP,
SHOW_PROFILE_MODAL,
HIDE_PROFILE_MODAL,
TOGGLE_QR_MODAL,
} from '../constants/constants';
interface UiState {
@ -21,6 +22,7 @@ interface UiState {
actionModalData:any;
avatarCacheStamp:number;
profileModalUsername:string;
isVisibleQRModal:boolean;
}
const initialState:UiState = {
@ -32,7 +34,8 @@ const initialState:UiState = {
actionModalVisible: false,
actionModalData: null,
avatarCacheStamp: 0,
profileModalUsername: ''
profileModalUsername: '',
isVisibleQRModal: false,
};
export default function (state = initialState, action) {
@ -101,6 +104,11 @@ export default function (state = initialState, action) {
...state,
avatarCacheStamp: action.payload
}
case TOGGLE_QR_MODAL:
return {
...state,
isVisibleQRModal: action.payload,
};
default:
return state;
}

View File

@ -5,6 +5,7 @@ import AsyncStorage from '@react-native-community/async-storage';
import Reactotron from '../../../reactotron-config';
import reducer from '../reducers';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
const transformCacheVoteMap = createTransform(
(inboundState:any) => ({
@ -35,11 +36,11 @@ const persistConfig = {
// Blacklist (Don't Save Specific Reducers)
blacklist: ['nav', 'application', 'communities', 'user'],
timeout: 0,
transforms:[transformCacheVoteMap,transformWalkthroughMap]
transforms:[transformCacheVoteMap,transformWalkthroughMap],
};
// Middleware: Redux Persist Persisted Reducer
const persistedReducer = persistReducer(persistConfig, reducer);
const persistedReducer = persistReducer(persistConfig, reducer as any);
const middleware = [thunk];

View File

@ -26,6 +26,7 @@ import {
ActionModal,
ForegroundNotification,
QuickProfileModal,
QRModal,
} from '../../../components';
// Themes (Styles)
@ -174,6 +175,7 @@ class ApplicationScreen extends Component {
<AccountsBottomSheet />
<ActionModal />
<QuickProfileModal navigation={{ navigate }} />
<QRModal />
</View>
);
}

View File

@ -0,0 +1,90 @@
import { getPost, getUser } from '../providers/hive/dhive';
import postUrlParser from './postUrlParser';
import parseAuthUrl from './parseAuthUrl';
import get from 'lodash/get';
import ROUTES from '../constants/routeNames';
export const deepLinkParser = async (url, currentAccount) => {
if (!url || url.indexOf('ShareMedia://') >= 0) return;
let routeName;
let params;
let content;
let profile;
let keey;
const postUrl = postUrlParser(url);
console.log('postUrl : ', postUrl);
const { author, permlink, feedType, tag } = postUrl || {};
if (author) {
if (
!permlink ||
permlink === 'wallet' ||
permlink === 'points' ||
permlink === 'comments' ||
permlink === 'replies' ||
permlink === 'posts'
) {
let deepLinkFilter;
if (permlink) {
deepLinkFilter = permlink === 'points' ? 'wallet' : permlink;
}
profile = await getUser(author);
routeName = ROUTES.SCREENS.PROFILE;
params = {
username: get(profile, 'name'),
reputation: get(profile, 'reputation'),
deepLinkFilter, //TODO: process this in profile screen
};
keey = get(profile, 'name');
} else if (permlink === 'communities') {
routeName = ROUTES.SCREENS.WEB_BROWSER;
params = {
url: url,
};
keey = 'WebBrowser';
} else if (permlink) {
content = await getPost(author, permlink, currentAccount.name);
routeName = ROUTES.SCREENS.POST;
params = {
content,
};
keey = `${author}/${permlink}`;
}
}
if (feedType === 'hot' || feedType === 'trending' || feedType === 'created') {
if (!tag) {
routeName = ROUTES.SCREENS.TAG_RESULT;
} else if (/hive-[1-3]\d{4,6}$/.test(tag)) {
routeName = ROUTES.SCREENS.COMMUNITY;
} else {
routeName = ROUTES.SCREENS.TAG_RESULT;
}
params = {
tag,
filter: feedType,
};
keey = `${feedType}/${tag || ''}`;
}
if (!routeName) {
const { mode, referredUser } = parseAuthUrl(url) || {};
if (mode === 'SIGNUP') {
routeName = ROUTES.SCREENS.REGISTER;
params = {
referredUser,
};
keey = `${mode}/${referredUser || ''}`;
}
}
return {
routeName: routeName,
params: params,
key: keey,
};
};

View File

@ -1475,6 +1475,13 @@
htmlparser2 "^6.1.0"
ramda "^0.27.1"
"@react-native-async-storage/async-storage@^1.13.4":
version "1.16.1"
resolved "https://registry.yarnpkg.com/@react-native-async-storage/async-storage/-/async-storage-1.16.1.tgz#1dbaa9e0f9736e4ab8fc04c628bbb608fd80b068"
integrity sha512-aQ7ka+Ii1e/q+7AVFIZPt4kDeSH8b784wMDtz19Kf4A7hf+OgCHBlUQpOXsrv8XxhlBxu0hv4tfrDO15ChnV0Q==
dependencies:
merge-options "^3.0.4"
"@react-native-community/async-storage@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@react-native-community/async-storage/-/async-storage-1.5.0.tgz#647ffcd832272068b0be57332e08d73036ed391f"
@ -5733,6 +5740,11 @@ is-observable@^1.1.0:
dependencies:
symbol-observable "^1.1.0"
is-plain-obj@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
is-plain-object@^2.0.3, is-plain-object@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
@ -7028,6 +7040,13 @@ mdn-data@2.0.14:
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
merge-options@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/merge-options/-/merge-options-3.0.4.tgz#84709c2aa2a4b24c1981f66c179fe5565cc6dbb7"
integrity sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==
dependencies:
is-plain-obj "^2.1.0"
merge-stream@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"
@ -8529,6 +8548,13 @@ react-native-autoheight-webview@^1.5.8:
dependencies:
prop-types "^15.7.2"
react-native-camera@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/react-native-camera/-/react-native-camera-4.2.1.tgz#caf74081f055e89d7e9b0cd5108965d808c60e90"
integrity sha512-+Vkql24PFYQfsPRznJCvPwJQfyzCnjlcww/iZ4Ej80bgivKjL9eU0IMQIXp4yi6XCrKi4voWXxIDPMupQZKeIQ==
dependencies:
prop-types "^15.6.2"
react-native-config@luggit/react-native-config#master:
version "1.4.2"
resolved "https://codeload.github.com/luggit/react-native-config/tar.gz/81f599f5f912b84c41c9ef2901faf54995638c4e"
@ -8707,6 +8733,16 @@ react-native-os@^1.0.1:
resolved "https://registry.yarnpkg.com/react-native-os/-/react-native-os-1.2.6.tgz#1bb16d78ccad1143972183a04f443cf1af9fbefa"
integrity sha512-OlT+xQAcvkcnf7imgXiu+myMkqDt4xw2bP5SlVo19hEn5XHBkPMLX7dk3sSGxxncH/ToMDsf1KLyrPabNVtadA==
react-native-permissions@^2.0.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/react-native-permissions/-/react-native-permissions-2.2.2.tgz#3d2a63f6b7d6be52fc86e30f77412a9566283028"
integrity sha512-ihf4shQDSX5Oo9ChQXb9kr13mmyyNem5MaEvOpr3dCjhBOBWyEMztXm9/uPK1Qg5PsNpaYLa1KpcPZDCw87LXg==
react-native-permissions@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/react-native-permissions/-/react-native-permissions-3.3.0.tgz#f63b7f91457dd2b11991ca46ebe4262a8eb1f73c"
integrity sha512-F0Yjcp0V340lQW2ibg1lTGmStsMoWsBtosSCRIZOatOQAsNMp77zL6SdYcIGwJUBMVDX3BMraB4AX4Ph3cW1NA==
react-native-portalize@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/react-native-portalize/-/react-native-portalize-1.0.7.tgz#8b3c742a06f863654d526ea1075a8596625f8482"
@ -8724,6 +8760,15 @@ react-native-push-notification@^7.3.1:
resolved "https://registry.yarnpkg.com/react-native-push-notification/-/react-native-push-notification-7.3.1.tgz#1495feacd25169b998446dcf7b448a197ae5dca0"
integrity sha512-5kSKPvDU23uZRmzgKTsGhbwGNvB2tidu1VnInBHP53ZD0VEPSBl5fbpuTfHH98ED+Gp1SCcT2/e6bJWkIspKvg==
react-native-qrcode-scanner@^1.5.5:
version "1.5.5"
resolved "https://registry.yarnpkg.com/react-native-qrcode-scanner/-/react-native-qrcode-scanner-1.5.5.tgz#0d20101712715da108742a2bbbd0397569031b01"
integrity sha512-il79uStkFqUvofqXJQfOL30qgQyU17MUKxj7IGHv6oT2OxIY/vutTwuPPDbsivtv0yTMHP4dGx/79oys4eAuNw==
dependencies:
"@react-native-async-storage/async-storage" "^1.13.4"
prop-types "^15.5.10"
react-native-permissions "^2.0.2"
react-native-qrcode-svg@^6.0.3:
version "6.1.1"
resolved "https://registry.yarnpkg.com/react-native-qrcode-svg/-/react-native-qrcode-svg-6.1.1.tgz#19dd15545b1cbcfc1b2738af170e9fd0f1d4d8a0"