From c2210f0c41cb297081c664c3116e57b059c24875 Mon Sep 17 00:00:00 2001 From: ice-orion <102020833+ice-orion@users.noreply.github.com> Date: Tue, 25 Apr 2023 17:05:44 +0400 Subject: [PATCH] profile QR code (#42) Adds QR code feature: * QR code screen that can be opened from the profile screen (from a button in header). QR code contains user's username encoded and can be shared; * QR code scan feature on Who-Invited-You welcome screen, that simplifies username input. Also: * Refactor InviteShare screen since initially it shared most of the UI with QRCodeShare screen; * Groupes common button components to `@components/Buttons/**`; * Adds `unsafeUserSelector`; * Refactors Profile -> `AvatarHeader`; * Adds `share` service. --- .eslintrc.js | 4 + babel.config.js | 7 +- ios/Podfile | 1 + ios/Podfile.lock | 84 ++++++- package.json | 7 +- patches/react-native-reanimated+2.13.0.patch | 106 -------- src/App.tsx | 2 +- src/assets/images/index.ts | 11 + .../images/share/email.png} | Bin .../images/share/email@2x.png} | Bin .../images/share/email@3x.png} | Bin .../images/share/facebook.png} | Bin .../images/share/facebook@2x.png} | Bin .../images/share/facebook@3x.png} | Bin .../images/share/link.png} | Bin .../images/share/link@2x.png} | Bin .../images/share/link@3x.png} | Bin .../images/share/more.png} | Bin .../images/share/more@2x.png} | Bin .../images/share/more@3x.png} | Bin src/assets/images/share/share_providers.png | Bin 0 -> 7739 bytes .../images/share/share_providers@2x.png | Bin 0 -> 20631 bytes .../images/share/share_providers@3x.png | Bin 0 -> 38564 bytes .../images/share/sms.png} | Bin .../images/share/sms@2x.png} | Bin .../images/share/sms@3x.png} | Bin .../images/share/telegram.png} | Bin .../images/share/telegram@2x.png} | Bin .../images/share/telegram@3x.png} | Bin .../images/share/twitter.png} | Bin .../images/share/twitter@2x.png} | Bin .../images/share/twitter@3x.png} | Bin .../images/share/whatsApp.png} | Bin .../images/share/whatsApp@2x.png} | Bin .../images/share/whatsApp@3x.png} | Bin src/assets/svg/QRCodeEyeIcon.tsx | 17 ++ src/assets/svg/QRCodeIcon.tsx | 33 +++ src/assets/svg/ShareIcon.android.tsx | 22 ++ src/assets/svg/ShareIcon.ios.tsx | 20 ++ .../{ => Buttons}/BackButton/index.tsx | 0 .../{ => Buttons}/InviteButton/index.tsx | 0 .../{ => Buttons}/PrimaryButton/index.tsx | 0 .../{ => Buttons}/ResendButton/index.tsx | 0 .../Forms/ConfirmPhoneNumberForm/index.tsx | 2 +- .../Forms/ModifyEmailForm/index.tsx | 2 +- .../Forms/ModifyPhoneNumberForm/index.tsx | 2 +- src/components/Inputs/CommonInput/index.tsx | 2 +- src/navigation/Main.tsx | 3 + src/navigation/Router.tsx | 2 +- src/navigation/Welcome.tsx | 10 + .../components/AnimatedSplash/index.tsx | 0 .../Header/components/QRCodeShareButton.tsx | 34 +++ .../components/InitializationError/index.tsx | 2 +- .../components/PreStakingCall.tsx | 2 +- .../AuthFlow/ConfirmEmailLink/index.tsx | 2 +- src/screens/AuthFlow/ConfirmPhone/index.tsx | 4 +- src/screens/AuthFlow/InvalidLink/index.tsx | 4 +- .../AuthFlow/ResetPasswordLink/index.tsx | 2 +- .../SignIn/components/Header/index.tsx | 2 +- .../SignIn/components/SubmitButton/index.tsx | 5 +- .../hooks/useInviteFriendsWalkthrough.tsx | 2 +- .../Home/components/Overview/index.tsx | 2 +- src/screens/InviteFlow/InviteFriend/index.tsx | 2 +- .../assets/images/instagramIcon.png | Bin 4832 -> 0 bytes .../assets/images/instagramIcon@2x.png | Bin 14339 -> 0 bytes .../assets/images/instagramIcon@3x.png | Bin 28271 -> 0 bytes .../InviteShare/components/Copied/index.tsx | 8 +- .../components/ShareButton/index.tsx | 34 +++ .../components/ShareCard/index.tsx | 71 ++++++ .../components/InviteShareCard/index.tsx | 115 +++++++++ .../components/ShareButton/index.tsx | 50 ---- .../components/ShareButton/types.ts | 12 - .../components/ShareCard/index.tsx | 228 ------------------ src/screens/InviteFlow/InviteShare/index.tsx | 4 +- .../components/PrivacyButton/index.tsx | 54 +++++ .../QRCode/components/QRCodeEye.tsx | 26 ++ .../QRCode/components/QRCodeField.tsx | 47 ++++ .../QRCode/components/QRCodeLogo.tsx | 44 ++++ .../components/QRCode/constants.ts | 3 + .../QRCodePreview/components/QRCode/index.tsx | 73 ++++++ .../QRCodePreview/components/QRCode/utils.ts | 17 ++ .../components/QRCodeAvatar/index.tsx | 50 ++++ .../components/QRCodePreview/index.tsx | 102 ++++++++ .../components/QRShareCard/index.tsx | 76 ++++++ src/screens/InviteFlow/QRCodeShare/index.tsx | 40 +++ src/screens/Modals/DateSelector/index.tsx | 2 +- .../PopUp/components/PopUpButton/index.tsx | 5 +- .../Modals/ProfilePrivacyEdit/step3/index.tsx | 5 +- .../hooks/useCameraPermissions.tsx | 19 ++ .../QRCodeScanner/hooks/useDetectBarcode.tsx | 29 +++ src/screens/Modals/QRCodeScanner/index.tsx | 56 +++++ .../components/EmptyNotifications/index.tsx | 2 +- .../Badges/components/BadgeCard.tsx | 2 +- .../Badges/components}/ImageCardCompact.tsx | 0 src/screens/ProfileFlow/Badges/index.tsx | 7 +- .../components/ContactsAvatarButton/index.tsx | 54 +++++ .../components/EditAvatarButton/index.tsx | 58 +++++ .../AvatarHeader/hooks/useAnimatedStyles.ts | 2 +- .../Profile/components/AvatarHeader/index.tsx | 181 +++++--------- .../Profile/components/Invite/index.tsx | 2 +- .../PersonalInformation/index.tsx | 7 +- .../Staking/components/Footer/index.tsx | 2 +- .../hooks/useContactsListRenderItems.tsx | 2 +- .../components/AllowContactsButton.tsx | 2 +- .../hooks/useModifyPhoneNumberWalkthrough.tsx | 2 +- .../TierList/components/EmptyTier/index.tsx | 2 +- .../FinalizeRegistrationStep/index.tsx | 2 +- .../ClaimUsername/hooks/useClaimUsername.ts | 4 +- .../WelcomeFlow/ClaimUsername/index.tsx | 2 +- .../WelcomeFlow/ConfirmEmailLink/index.tsx | 2 +- .../WelcomeFlow/IceBonus/hooks/useIceBonus.ts | 4 +- src/screens/WelcomeFlow/IceBonus/index.tsx | 2 +- .../Onboarding/components/Controls/index.tsx | 2 +- .../Onboarding/hooks/useFinishOnboarding.ts | 5 +- .../WelcomeFlow/SetEmail/hooks/useSetEmail.ts | 4 +- src/screens/WelcomeFlow/SetEmail/index.tsx | 2 +- .../WhoInvitedYou/components/QRCodeButton.tsx | 49 ++++ .../WhoInvitedYou/hooks/useWhoInvitedYou.ts | 4 +- .../WelcomeFlow/WhoInvitedYou/index.tsx | 4 +- src/services/auth/signin/apple.ts | 2 +- src/services/auth/signin/facebook.ts | 2 +- src/services/auth/signin/google.ts | 2 +- src/services/auth/signin/twitter.ts | 2 +- src/services/share/index.ts | 50 ++++ .../hooks/useUpdateHiddenProfileElements.ts | 4 +- src/store/modules/Account/selectors/index.ts | 7 + src/store/modules/Analytics/constants.ts | 3 +- .../AppCommon/sagas/intervalUpdates.ts | 9 +- .../Contacts/sagas/inviteContactSaga.ts | 4 +- .../modules/Permissions/actions/index.ts | 3 +- .../modules/Permissions/reducer/index.ts | 4 + .../sagas/checkAllPermissionsSaga.ts | 14 +- .../Permissions/sagas/getPermissionsSaga.ts | 4 +- .../modules/Permissions/selectors/index.ts | 2 +- .../sagas/validateRefUsernameSaga.ts | 2 +- .../Validation/sagas/validateUsernameSaga.ts | 2 +- src/translations/locales/en.json | 7 +- src/translations/locales/en.json.d.ts | 3 + src/utils/string.ts | 9 - src/utils/username.ts | 18 ++ tsconfig.json | 10 +- yarn.lock | 61 ++++- 142 files changed, 1567 insertions(+), 638 deletions(-) delete mode 100644 patches/react-native-reanimated+2.13.0.patch rename src/{screens/InviteFlow/InviteShare/assets/images/emailIcon.png => assets/images/share/email.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/emailIcon@2x.png => assets/images/share/email@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/emailIcon@3x.png => assets/images/share/email@3x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/newsfeedIcon.png => assets/images/share/facebook.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/newsfeedIcon@2x.png => assets/images/share/facebook@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/newsfeedIcon@3x.png => assets/images/share/facebook@3x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/linkIcon.png => assets/images/share/link.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/linkIcon@2x.png => assets/images/share/link@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/linkIcon@3x.png => assets/images/share/link@3x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/moreIcon.png => assets/images/share/more.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/moreIcon@2x.png => assets/images/share/more@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/moreIcon@3x.png => assets/images/share/more@3x.png} (100%) create mode 100755 src/assets/images/share/share_providers.png create mode 100755 src/assets/images/share/share_providers@2x.png create mode 100755 src/assets/images/share/share_providers@3x.png rename src/{screens/InviteFlow/InviteShare/assets/images/smsIcon.png => assets/images/share/sms.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/smsIcon@2x.png => assets/images/share/sms@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/smsIcon@3x.png => assets/images/share/sms@3x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/telegramIcon.png => assets/images/share/telegram.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/telegramIcon@2x.png => assets/images/share/telegram@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/telegramIcon@3x.png => assets/images/share/telegram@3x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/twitterIcon.png => assets/images/share/twitter.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/twitterIcon@2x.png => assets/images/share/twitter@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/twitterIcon@3x.png => assets/images/share/twitter@3x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/whatsAppIcon.png => assets/images/share/whatsApp.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/whatsAppIcon@2x.png => assets/images/share/whatsApp@2x.png} (100%) rename src/{screens/InviteFlow/InviteShare/assets/images/whatsAppIcon@3x.png => assets/images/share/whatsApp@3x.png} (100%) create mode 100644 src/assets/svg/QRCodeEyeIcon.tsx create mode 100644 src/assets/svg/QRCodeIcon.tsx create mode 100644 src/assets/svg/ShareIcon.android.tsx create mode 100644 src/assets/svg/ShareIcon.ios.tsx rename src/components/{ => Buttons}/BackButton/index.tsx (100%) rename src/components/{ => Buttons}/InviteButton/index.tsx (100%) rename src/components/{ => Buttons}/PrimaryButton/index.tsx (100%) rename src/components/{ => Buttons}/ResendButton/index.tsx (100%) rename src/{ => navigation}/components/AnimatedSplash/index.tsx (100%) create mode 100644 src/navigation/components/Header/components/QRCodeShareButton.tsx rename src/{ => navigation}/components/InitializationError/index.tsx (96%) delete mode 100644 src/screens/InviteFlow/InviteShare/assets/images/instagramIcon.png delete mode 100644 src/screens/InviteFlow/InviteShare/assets/images/instagramIcon@2x.png delete mode 100644 src/screens/InviteFlow/InviteShare/assets/images/instagramIcon@3x.png create mode 100644 src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareButton/index.tsx create mode 100644 src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareCard/index.tsx create mode 100644 src/screens/InviteFlow/InviteShare/components/InviteShareCard/index.tsx delete mode 100644 src/screens/InviteFlow/InviteShare/components/ShareButton/index.tsx delete mode 100644 src/screens/InviteFlow/InviteShare/components/ShareButton/types.ts delete mode 100644 src/screens/InviteFlow/InviteShare/components/ShareCard/index.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/PrivacyButton/index.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeEye.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeField.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeLogo.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/constants.ts create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/index.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/utils.ts create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCodeAvatar/index.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/index.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/components/QRShareCard/index.tsx create mode 100644 src/screens/InviteFlow/QRCodeShare/index.tsx create mode 100644 src/screens/Modals/QRCodeScanner/hooks/useCameraPermissions.tsx create mode 100644 src/screens/Modals/QRCodeScanner/hooks/useDetectBarcode.tsx create mode 100644 src/screens/Modals/QRCodeScanner/index.tsx rename src/{components/Cards => screens/ProfileFlow/Badges/components}/ImageCardCompact.tsx (100%) create mode 100644 src/screens/ProfileFlow/Profile/components/AvatarHeader/components/ContactsAvatarButton/index.tsx create mode 100644 src/screens/ProfileFlow/Profile/components/AvatarHeader/components/EditAvatarButton/index.tsx create mode 100644 src/screens/WelcomeFlow/WhoInvitedYou/components/QRCodeButton.tsx create mode 100644 src/services/share/index.ts create mode 100644 src/utils/username.ts diff --git a/.eslintrc.js b/.eslintrc.js index ebec796ea..d5e43d43e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -62,6 +62,10 @@ module.exports = { message: 'Please use useSafeAreaFrame from @hooks/useSafeAreaFrame or useSafeAreaInsets from @hooks/useSafeAreaInsets', }, + { + name: 'react-native-share', + message: 'Please use custom wrapper from @services/share', + }, ], }, ], diff --git a/babel.config.js b/babel.config.js index b2bf3706a..a228ab965 100644 --- a/babel.config.js +++ b/babel.config.js @@ -32,7 +32,12 @@ module.exports = api => { }, }, ], - 'react-native-reanimated/plugin', + [ + 'react-native-reanimated/plugin', + { + globals: ['__scanCodes'], // https://github.com/rodgomesc/vision-camera-code-scanner#installation + }, + ], ], exclude: ['**/*.png', '**/*.jpg', '**/*.gif'], }; diff --git a/ios/Podfile b/ios/Podfile index 5f470d8d3..da2fb3e19 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -15,6 +15,7 @@ target 'ice' do pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts" + pod 'Permission-Camera', :path => "#{permissions_path}/Camera" pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications" pod 'ReactNativeMoEngage', :path => '../node_modules/react-native-moengage' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0586908d4..91f02a0d6 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -188,10 +188,27 @@ PODS: - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) + - GoogleMLKit/BarcodeScanning (4.0.0): + - GoogleMLKit/MLKitCore + - MLKitBarcodeScanning (~> 3.0.0) + - GoogleMLKit/MLKitCore (4.0.0): + - MLKitCommon (~> 9.0.0) - GoogleSignIn (6.2.4): - AppAuth (~> 1.5) - GTMAppAuth (~> 1.3) - GTMSessionFetcher/Core (< 3.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.1): - GoogleUtilities/AppDelegateSwizzler (= 7.11.1) - GoogleUtilities/Environment (= 7.11.1) @@ -225,6 +242,8 @@ PODS: - GoogleUtilities/MethodSwizzler - GoogleUtilities/UserDefaults (7.11.1): - GoogleUtilities/Logger + - GoogleUtilitiesComponents (1.1.0): + - GoogleUtilities/Logger - GTMAppAuth (1.3.1): - AppAuth/Core (~> 1.6) - GTMSessionFetcher/Core (< 3.0, >= 1.5) @@ -235,6 +254,24 @@ PODS: - lottie-react-native (5.1.4): - lottie-ios (~> 3.4.0) - React-Core + - MLImage (1.0.0-beta4) + - MLKitBarcodeScanning (3.0.0): + - MLKitCommon (~> 9.0) + - MLKitVision (~> 5.0) + - 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) + - 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) @@ -249,6 +286,8 @@ PODS: - nanopb/decode (2.30909.0) - nanopb/encode (2.30909.0) - OpenSSL-Universal (1.1.1100) + - Permission-Camera (3.6.1): + - RNPermissions - Permission-Contacts (3.6.1): - RNPermissions - Permission-Notifications (3.6.1): @@ -518,6 +557,8 @@ PODS: - react-native-twitter-signin (1.2.0): - React - TwitterKit5 + - react-native-view-shot (3.6.0): + - React-Core - React-perflogger (0.70.8) - React-RCTActionSheet (0.70.8): - React-Core/RCTActionSheetHeaders (= 0.70.8) @@ -640,7 +681,7 @@ PODS: - React-Core - RNReactNativeHapticFeedback (1.14.0): - React-Core - - RNReanimated (2.13.0): + - RNReanimated (2.16.0): - DoubleConversion - FBLazyVector - FBReactNativeSpec @@ -692,6 +733,13 @@ PODS: - TwitterCore (3.2.0) - TwitterKit5 (5.2.0): - TwitterCore (>= 3.1.0) + - vision-camera-code-scanner (0.2.0): + - GoogleMLKit/BarcodeScanning + - React-Core + - VisionCamera (2.15.4): + - React + - React-callinvoker + - React-Core - Yoga (1.14.0) - YogaKit (1.18.1): - Yoga (~> 1.14) @@ -733,6 +781,7 @@ DEPENDENCIES: - lottie-react-native (from `../node_modules/lottie-react-native`) - MoEngageRichNotification - OpenSSL-Universal (= 1.1.1100) + - Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`) - Permission-Contacts (from `../node_modules/react-native-permissions/ios/Contacts`) - Permission-Notifications (from `../node_modules/react-native-permissions/ios/Notifications`) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) @@ -761,6 +810,7 @@ DEPENDENCIES: - react-native-restart (from `../node_modules/react-native-restart`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) - "react-native-twitter-signin (from `../node_modules/@react-native-twitter-signin/twitter-signin`)" + - react-native-view-shot (from `../node_modules/react-native-view-shot`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) @@ -799,6 +849,8 @@ DEPENDENCIES: - RNShare (from `../node_modules/react-native-share`) - RNSound (from `../node_modules/react-native-sound`) - RNSVG (from `../node_modules/react-native-svg`) + - vision-camera-code-scanner (from `../node_modules/vision-camera-code-scanner`) + - VisionCamera (from `../node_modules/react-native-vision-camera`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -831,12 +883,19 @@ SPEC REPOS: - fmt - GoogleAppMeasurement - GoogleDataTransport + - GoogleMLKit - GoogleSignIn + - GoogleToolboxForMac - GoogleUtilities + - GoogleUtilitiesComponents - GTMAppAuth - GTMSessionFetcher - libevent - lottie-ios + - MLImage + - MLKitBarcodeScanning + - MLKitCommon + - MLKitVision - MoEngage-iOS-SDK - MoEngageInApp - MoEngagePluginBase @@ -869,6 +928,8 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/sdks/hermes/hermes-engine.podspec" lottie-react-native: :path: "../node_modules/lottie-react-native" + Permission-Camera: + :path: "../node_modules/react-native-permissions/ios/Camera" Permission-Contacts: :path: "../node_modules/react-native-permissions/ios/Contacts" Permission-Notifications: @@ -921,6 +982,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-safe-area-context" react-native-twitter-signin: :path: "../node_modules/@react-native-twitter-signin/twitter-signin" + react-native-view-shot: + :path: "../node_modules/react-native-view-shot" React-perflogger: :path: "../node_modules/react-native/ReactCommon/reactperflogger" React-RCTActionSheet: @@ -997,6 +1060,10 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-sound" RNSVG: :path: "../node_modules/react-native-svg" + vision-camera-code-scanner: + :path: "../node_modules/vision-camera-code-scanner" + VisionCamera: + :path: "../node_modules/react-native-vision-camera" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" @@ -1035,20 +1102,28 @@ SPEC CHECKSUMS: glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b GoogleAppMeasurement: 3bc3a6484b7bb20dd8489242c4dd3c92a3e5107b GoogleDataTransport: 8378d1fa8ac49753ea6ce70d65a7cb70ce5f66e6 + GoogleMLKit: 2bd0dc6253c4d4f227aad460f69215a504b2980e GoogleSignIn: 5651ce3a61e56ca864160e79b484cd9ed3f49b7a + GoogleToolboxForMac: 8bef7c7c5cf7291c687cf5354f39f9db6399ad34 GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 + GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe GTMAppAuth: 0ff230db599948a9ad7470ca667337803b3fc4dd GTMSessionFetcher: 3a63d75eecd6aa32c2fc79f578064e1214dfdec2 hermes-engine: 0b19f33a9c2ec1dbdede3232606eeb1101db4cec libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8 lottie-react-native: b702fab740cdb952a8e2354713d3beda63ff97b0 + MLImage: 7bb7c4264164ade9bf64f679b40fb29c8f33ee9b + MLKitBarcodeScanning: 04e264482c5f3810cb89ebc134ef6b61e67db505 + MLKitCommon: c1b791c3e667091918d91bda4bba69a91011e390 + MLKitVision: 8baa5f46ee3352614169b85250574fde38c36f49 MoEngage-iOS-SDK: b7af14646f44852527ba7420e52ff8bb56b7077d MoEngageInApp: 94f24b0b1a83ec247dc998f31b08124b09fcab96 MoEngagePluginBase: e865f388c39d0cf2c7847610876e63b0e5e31c22 MoEngageRichNotification: 007cb006358994209e017c6ce52808809cf0b3fc nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c + Permission-Camera: bf6791b17c7f614b6826019fcfdcc286d3a107f6 Permission-Contacts: 2484d274171688b1ca80978b949ac771259b51f0 Permission-Notifications: 150484ae586eb9be4e32217582a78350a9bb31c3 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef @@ -1076,6 +1151,7 @@ SPEC CHECKSUMS: react-native-restart: 7595693413fe3ca15893702f2c8306c62a708162 react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a react-native-twitter-signin: 423e8d20eb26fddc14852d3f1435a8b39358f49d + react-native-view-shot: 705f999ac2a24e4e6c909c0ca65c732ed33ca2ff React-perflogger: e9249a18e055cae96fdf685bf6145cbea62506c8 React-RCTActionSheet: a6d2a544a4605a111ce80fa9319cc870ca3ea778 React-RCTAnimation: 21b776b15aa5451a0b5bcb342fd2f346817c1101 @@ -1107,7 +1183,7 @@ SPEC CHECKSUMS: RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c RNRate: ef3bcff84f39bb1d1e41c5593d3eea4aab2bd73a RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c - RNReanimated: ce445c233a6ff5600223484a88ad5704945d972a + RNReanimated: 436a3a1eca0e6dd0ab7507189f62c87f601daba6 RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19 RNSentry: eff1f32fe84682feb09a36c5e5f513d6ef964b70 RNSha256: 80bea5b2e7005f813f6438cb41e573b3d531146c @@ -1120,9 +1196,11 @@ SPEC CHECKSUMS: TOCropViewController: edfd4f25713d56905ad1e0b9f5be3fbe0f59c863 TwitterCore: 8cbc9ad34d91c63a0035ea05bfbfc0d7ca72a28c TwitterKit5: 64095dfefcf39be2355711ef27112d55e340d90e + vision-camera-code-scanner: dda884a7f3ec8243a2a6d6489b91860648371bca + VisionCamera: e9a95af10e00aaebe99d648ff4519fd336e16ffe Yoga: d6133108734e69e8c0becc6ba587294b94829687 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: a0a70da9b17b6dcb979881a8adf8d0c60ce75015 +PODFILE CHECKSUM: f2f9a829491725083020e6fb3920d99dc7e56e4b COCOAPODS: 1.11.3 diff --git a/package.json b/package.json index 26020bc6c..a915f6019 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "lodash": "^4.17.21", "lottie-react-native": "^5.1.4", "node-libs-browser": "^2.2.1", + "qrcode": "^1.5.1", "react": "18.1.0", "react-native": "0.70.8", "react-native-awesome-slider": "^2.3.0", @@ -85,7 +86,7 @@ "react-native-pager-view": "6.1.1", "react-native-permissions": "^3.6.1", "react-native-rate": "^1.2.12", - "react-native-reanimated": "2.13.0", + "react-native-reanimated": "2.15.0", "react-native-restart": "^0.0.27", "react-native-safe-area-context": "^4.4.1", "react-native-screens": "3.13.1", @@ -95,6 +96,8 @@ "react-native-sound": "^0.11.2", "react-native-store-version": "^1.4.1", "react-native-svg": "^13.6.0", + "react-native-view-shot": "^3.6.0", + "react-native-vision-camera": "^2.15.4", "react-redux": "^8.0.5", "react-string-replace": "^1.1.0", "redux": "^4.2.0", @@ -104,6 +107,7 @@ "rn-android-keyboard-adjust": "^2.1.2", "rn-units": "^2.0.5", "url-parse": "^1.5.10", + "vision-camera-code-scanner": "^0.2.0", "yarn": "^1.22.19" }, "devDependencies": { @@ -118,6 +122,7 @@ "@types/i18n-js": "^3.8.3", "@types/jest": "^29.2.3", "@types/lodash": "^4.14.189", + "@types/qrcode": "^1.5.0", "@types/react-native": "0.70.6", "@types/react-test-renderer": "^18.0.0", "@types/url-parse": "^1.4.8", diff --git a/patches/react-native-reanimated+2.13.0.patch b/patches/react-native-reanimated+2.13.0.patch deleted file mode 100644 index f7a22e584..000000000 --- a/patches/react-native-reanimated+2.13.0.patch +++ /dev/null @@ -1,106 +0,0 @@ -Remove this patch when react-native-renaimated is updated to either 3.1.0 or 2.15.0 - -diff --git a/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NodesManager.java b/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NodesManager.java -index 2f32309..d535669 100644 ---- a/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NodesManager.java -+++ b/node_modules/react-native-reanimated/android/src/main/java/com/swmansion/reanimated/NodesManager.java -@@ -61,6 +61,7 @@ import java.util.Queue; - import java.util.Set; - import java.util.concurrent.ConcurrentLinkedQueue; - import java.util.concurrent.Semaphore; -+import java.util.concurrent.TimeUnit; - import java.util.concurrent.atomic.AtomicBoolean; - import javax.annotation.Nullable; - -@@ -248,13 +249,11 @@ public class NodesManager implements EventDispatcherListener { - } - }); - if (trySynchronously) { -- while (true) { -- try { -- semaphore.acquire(); -- break; -- } catch (InterruptedException e) { -- // noop -- } -+ try { -+ semaphore.tryAcquire(16, TimeUnit.MILLISECONDS); -+ } catch (InterruptedException e) { -+ // if the thread is interruped we just continue and let the layout update happen -+ // asynchronously - } - } - } -diff --git a/node_modules/react-native-reanimated/ios/REANodesManager.m b/node_modules/react-native-reanimated/ios/REANodesManager.m -index 675f484..fda5bb2 100644 ---- a/node_modules/react-native-reanimated/ios/REANodesManager.m -+++ b/node_modules/react-native-reanimated/ios/REANodesManager.m -@@ -109,6 +109,8 @@ @implementation REANodesManager { - BOOL _tryRunBatchUpdatesSynchronously; - REAEventHandler _eventHandler; - volatile void (^_mounting)(void); -+ NSObject *_syncLayoutUpdatesWaitLock; -+ volatile BOOL _syncLayoutUpdatesWaitTimedOut; - NSMutableDictionary *_componentUpdateBuffer; - volatile atomic_bool _shouldFlushUpdateBuffer; - NSMutableDictionary *_viewRegistry; -@@ -128,6 +130,7 @@ - (instancetype)initWithModule:(REAModule *)reanimatedModule uiManager:(RCTUIMan - _operationsInBatch = [NSMutableArray new]; - _componentUpdateBuffer = [NSMutableDictionary new]; - _viewRegistry = [_uiManager valueForKey:@"_viewRegistry"]; -+ _syncLayoutUpdatesWaitLock = [NSObject new]; - _shouldFlushUpdateBuffer = false; - } - -@@ -232,8 +235,14 @@ - (void)onAnimationFrame:(CADisplayLink *)displayLink - - (BOOL)uiManager:(RCTUIManager *)manager performMountingWithBlock:(RCTUIManagerMountingBlock)block - { - RCTAssert(_mounting == nil, @"Mouting block is expected to not be set"); -- _mounting = block; -- return YES; -+ @synchronized(_syncLayoutUpdatesWaitLock) { -+ if (_syncLayoutUpdatesWaitTimedOut) { -+ return NO; -+ } else { -+ _mounting = block; -+ return YES; -+ } -+ } - } - - - (void)performOperations -@@ -250,6 +259,7 @@ - (void)performOperations - - __weak typeof(self) weakSelf = self; - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); -+ _syncLayoutUpdatesWaitTimedOut = NO; - RCTExecuteOnUIManagerQueue(^{ - __typeof__(self) strongSelf = weakSelf; - if (strongSelf == nil) { -@@ -266,7 +276,7 @@ - (void)performOperations - } - - if (canUpdateSynchronously) { -- [strongSelf.uiManager runSyncUIUpdatesWithObserver:self]; -+ [strongSelf.uiManager runSyncUIUpdatesWithObserver:strongSelf]; - dispatch_semaphore_signal(semaphore); - } - // In case canUpdateSynchronously=true we still have to send uiManagerWillPerformMounting event -@@ -274,7 +284,16 @@ - (void)performOperations - [strongSelf.uiManager setNeedsLayout]; - }); - if (trySynchronously) { -- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); -+ // The 16ms timeout here aims to match the frame duration. It may make sense to read that parameter -+ // from CADisplayLink but it is easier to hardcode it for the time being. -+ // The reason why we use frame duration here is that if takes longer than one frame to complete layout tasks -+ // there is no point of synchronizing layout with the UI interaction as we get that one frame delay anyways. -+ long result = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC)); -+ if (result != 0) { -+ @synchronized(_syncLayoutUpdatesWaitLock) { -+ _syncLayoutUpdatesWaitTimedOut = YES; -+ } -+ } - } - - if (_mounting) { diff --git a/src/App.tsx b/src/App.tsx index 17437081b..199882dea 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {AnimatedSplash} from '@components/AnimatedSplash'; +import {AnimatedSplash} from '@navigation/components/AnimatedSplash'; import {Router} from '@navigation/Router'; import {persistor, store} from '@store/configureStore'; import React from 'react'; diff --git a/src/assets/images/index.ts b/src/assets/images/index.ts index b7bcbc1fe..5a07c3eda 100644 --- a/src/assets/images/index.ts +++ b/src/assets/images/index.ts @@ -92,4 +92,15 @@ export const Images = { telegram: require('./popup/telegram.png'), earlyAccess: require('./popup/earlyAccess.png'), }, + share: { + telegram: require('./share/telegram.png'), + twitter: require('./share/twitter.png'), + whatsApp: require('./share/whatsApp.png'), + email: require('./share/email.png'), + facebook: require('./share/facebook.png'), + link: require('./share/link.png'), + more: require('./share/more.png'), + sms: require('./share/sms.png'), + shareProviders: require('./share/share_providers.png'), + }, } as const; diff --git a/src/screens/InviteFlow/InviteShare/assets/images/emailIcon.png b/src/assets/images/share/email.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/emailIcon.png rename to src/assets/images/share/email.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/emailIcon@2x.png b/src/assets/images/share/email@2x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/emailIcon@2x.png rename to src/assets/images/share/email@2x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/emailIcon@3x.png b/src/assets/images/share/email@3x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/emailIcon@3x.png rename to src/assets/images/share/email@3x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/newsfeedIcon.png b/src/assets/images/share/facebook.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/newsfeedIcon.png rename to src/assets/images/share/facebook.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/newsfeedIcon@2x.png b/src/assets/images/share/facebook@2x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/newsfeedIcon@2x.png rename to src/assets/images/share/facebook@2x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/newsfeedIcon@3x.png b/src/assets/images/share/facebook@3x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/newsfeedIcon@3x.png rename to src/assets/images/share/facebook@3x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/linkIcon.png b/src/assets/images/share/link.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/linkIcon.png rename to src/assets/images/share/link.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/linkIcon@2x.png b/src/assets/images/share/link@2x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/linkIcon@2x.png rename to src/assets/images/share/link@2x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/linkIcon@3x.png b/src/assets/images/share/link@3x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/linkIcon@3x.png rename to src/assets/images/share/link@3x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/moreIcon.png b/src/assets/images/share/more.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/moreIcon.png rename to src/assets/images/share/more.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/moreIcon@2x.png b/src/assets/images/share/more@2x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/moreIcon@2x.png rename to src/assets/images/share/more@2x.png diff --git a/src/screens/InviteFlow/InviteShare/assets/images/moreIcon@3x.png b/src/assets/images/share/more@3x.png similarity index 100% rename from src/screens/InviteFlow/InviteShare/assets/images/moreIcon@3x.png rename to src/assets/images/share/more@3x.png diff --git a/src/assets/images/share/share_providers.png b/src/assets/images/share/share_providers.png new file mode 100755 index 0000000000000000000000000000000000000000..0d5b8d467f924941a6222e5ff82a5de72eb597b3 GIT binary patch literal 7739 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 BJDUIi literal 0 HcmV?d00001 diff --git a/src/assets/images/share/share_providers@2x.png b/src/assets/images/share/share_providers@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..e479b6d01ed0c3946ac868aa6d45ff4be511d7af GIT binary patch literal 20631 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 literal 0 HcmV?d00001 diff --git a/src/assets/images/share/share_providers@3x.png b/src/assets/images/share/share_providers@3x.png new file mode 100755 index 0000000000000000000000000000000000000000..0df5a69261fa13d36d1cf8a31a5ba9c0880170c4 GIT binary patch literal 38564 zcmV)XK&`)tP)W!1*Tx0>L(zkPvVI z3@%{H4I5WUwq>iYtX{VF_RfFiPCGOAzTLN~D|?Uh_Pu-W+_`h-o;knMW-c&J<1|j= zG*06*PGgP)jzJ=#2Klv2ekRI~`aRzqYRGd+qx`hWPn-O#GQU>|AzJY^AlYBGpKPDa zH{bRXQ>*!GHQz~}$^Ke}w+S&GQ{T4FfN>tnq=?7VcOCrr%%X7~%jU6sV^UEge4jPi z&)b;CMjDfx#~RJ&m>QE~9-z%bxlVpggMKg;WDW&2LJNk+pzyah=1*$U`>x)7e3 z4+U94%KNMl$2dhiwgO&Y9tu)@)rhwckD30mWASkF*vhv802we|fy2*ZE8hxA4&yP) zUn_9v`sRM;zGDS^7>}twJCsUtA!K>%u44&&jv|jWLid*fpK%^5j8?+S z{bOFiIpm}sj{MvrKU-+*&|~s*BgP<+?yu`i8^;Q5k)JPY2keXv`e;N>gp$~+0~ETojGjYKZwr$9QJk&$!|huAIamnpnP>%5o*c> zrq>k9-vSHkOOlV;zjS6P4uI~IpWBYK`mh8Vn*dGF|l+KW>(F@q_TQUESrQ;QX_PK z-H9VihR0N&HH_jkGo?6)18d(hiCl<-*dp1y>~VB}3j zbqQ6;KASwfEZIGCVWpTntsJu!RblqRDtWvZqohV01s)^ql2!e6Ge+r--P=vr+^S?3 zu(>Ul$hFOFqS?=791l7~!!RHg6bh*+DJ1_=A|c$dNoA8IXwSyUb*JFC+JzF3CZj-V#1RsrqXlLK$oIe5ia5|gHvOQ5dADd$hZ!le^1X?nrJv=K*+#}qK%iUNUob1UJMy+e3q zUoQD{4G@I&XeC&X-_)zWi1ecL8*( zd|0>PFp%ss3(Ug`0R_ry+g`y-P0veE-ih8^k7iVlzkvmlmpoP%QZ6Yot7I+eR3{C7L4tKPopouw zIOQFa3I*#sahMdF(HIyCh@agtC_jWf-K1dzW^j@2H{|IDM;3I5Mixe@tSl$x7M(l0 zNSrsj80XF^$Q#j!!=%`Z#=uaZ{PVtzcy{njdQ}3m7g*MufJ0`(djQ+ETTT@;wnav( zEYCUtd1~oQTvoOSr<4>7)_39vD9?u-pqUW3b+~fM#q;onUOdy-m$7^MhGZvvthV$TRJyNOZip2)cm{xY0GfIGfhUU-bY&cxov$I zPJ`DX(OS!9zhPjl!fO&ni+8M_sIGFK1Z$i>^+KFpe-;X$L#EgiDg>0P`mT*#xbMxL z1fY*LDcAUl8D+R-SzY1|AAuU>=b}R;5DMk7P0~VsRa(l=KirgnGLl$GC^yJ3js8y- ztqrmmz)cEr+ec_Dh7qpp7?Z1Bxir^YxU?2$T{Z=0T|NZ`&=KdcE@>IxzkU$U?8sqD zi}u8r4iL^|oeUxUTTssQ8k{w43}rv`l6}G{-EQ#e-a?|yBtMJDs6a`ltDn=WMPgll z?37aJ4j)n6H{#Ipmkj6FaoLU_^%u;1I;$=u#vHv@5L}eKmqf;uXf8% zPbz*qR!F(QFI!T9%NAFRR8(0xw;kxThC+pa0_I0|KTMlCHo#i4iUN1F-a-7h*~eAQ z;Fxx8ldsDvnR&=vkJlxCPb!@(POm>3XGowP!K!Y=K?;OIfJOoH?Q1*mm9?FR+3;du!r%)c-w7LTi-@TKR3tK~hPEtr2B-%F{>xJ<}VF5hDkHcKv(e6Of z7Fn5`oG^KMxw!n}v#{v25nbSoI08JTfcd_4gZR<aG}tx9qdmkBUdIa%eUh$)&(%FxE3F)T!u@^7LC-HMjS%LhSOmKXcME!>y|qf zfH@|WX!f}aCyW%UZo~mREEA(q%1mC@Spdw*Nd-PXr-_Sf&`!$a^-|`k&jWJ4cBpuD zfk1sg0zvkfay8}!nqvW&V^RS9<+CS_lw8(`1LLs~73Pf+m>)@ixgADwg}~x$URSC4 zA-G49flE?IAL2lrZe3I_y!|9Z9*IqmK%H3Bmw#e5MxevOV-}e2lfbOv$~Io?NH9PR zXc+glh=65S%0QR+yrB04E^R2r$4-?N_3%Kw651=+h*3}>%8ZIDf4S>P+B?)~o8;T+ zn+eM^PJQ!gM`Vel_If_Fl@mn@k?{L;yG@pCU{)vprxn+Tk4m7vw0tp!A!U@^cBn&9 zha8{_(ViZWuI#Tp(|ODQb4<#T{`eWy31H`;Q9Uf#XE#7AGnuZSmi}h^pz*(wgsqZ6nAt|sk{jnl@G0L8`Mn%)u_DsQt+K)|nR#Ub z*2B#Fu+2AE^IQO2i7aD6vI_t$+WfJRDcYT46=@BQNz z>C$dzCzak&7T?Wi(aLPx8j?$E*2Pin=ZmaD0W^|PrhxgoJuj2`PWc58^;58)>3%j6hfLKZpt#Pg@*~w@ZY)ujrWaL< zk5(-o38w6d~gvat)fxTUWc;eo@^w77rixgOL zfJ6ks@YoO-Xl^?MWSjhzDwsM?U(1!ZB(lnzL^84!Q<6w_-EYl<$^_3tjTo87hV?YO zvNwl+ezu?Xbdhe9(NV3x0ikMR#-s>GShjoClpqJdc6VCyiO&?=s}&V-PlTtS=ood4 zNaE9%E*Lh?W>_9GMw#NV8?%n9A}3KFQSa z)IK;_o(b4C4>zl>OJ`k~Sk!r_5qY$B<33Y7mT3jvCM{-VHNVwJC6hgN<<#M<=}fJC zByX0Q9`&tTH%RNb-+-b%4PNpwSm1ygTErY!c?IlvG_T5AgIel(byK)9HqXh5)DW=E zk*we~Dr7%hA+6~PuAhNC)QCJFJ)Ad7xwF5!WR|&*Guj*Vny%>LZUOA@cx27{e+VI$8$m3~v zWndS+-1#K!G45>QeS{GJ$be-2av54%vRimC29123^tpmH6@p*LG+bKKkk+)gv?8xH z-H1aFmp&u_J)Gctt69zY=riZmBpKg%NP*2o*0pAsTJ_h8tisA-{>9D*(KD1-&4KFd zN4Zt+AmWgWHB;C=E_6jOmr|XYlYfiMw{X%^gRa`L#{kYTuAIyMwpAK!o+Xf_&RkHt z2p>4^WBIIU)lWCedhT+kXu)}BR$;Y>$W2c*za^~Ze59=DugKW+FjKPvMQ|j+`NTcD zao^Y8gu_F?221$-A3kYW*Bh}1V^79o5RoPsS7#FiJ^H!%d;G@lzre zy>fW~ZaW5G40k$_bqB`$5>I4`MOXpUSTc_C-x z!S+FuM|2^;LVNI;59Is=hLb&4x|_|gKZvc+#P$lNN3yc43e&%rRW705s6I#JS@@(8 z2MN*#4ba00&P~mO_{)de5|Dm7&~>L&;uELWi-zU;k*+F&k?h zE!`^J-NU%NEst4nZiox?NSF5g|Gtf$dw8#TF5dEGW&*$fFfIo_%Owvua$`8&2X?(! zu>?~PocKk2-LS1Oh3BZ)^zZ!RiOF{cIglPM)bz~uLHyG*{nXW$6W)~^N$=#+>R8U` z9&k#kaDXY`$7l?ok!oV=u;f!g(&g-S0{9x#op~O#HSRInt>EUS`1sN?d~9jnB*jD# z91fh7OZzX|9!X-&c_~hU3l|yjlkpI>I&fJ>N=xeA!WbJo?o)Q2S$J-Ex;mxE@?UWN z^x|6lecjb!T5+b!JEaJYh7Jm#ja&QWtYeR?@5R@iJ$4hp4wTd~qF=nME}zTWKBN>l zYnS#nv9o&zj1vsbN)~X@HXUb%0CypCVKB@i<#i2r9t&#g$WAisMPNkiN^?SU4@(%oXeTe03P6tdLXFF zC99o)*NcGu`SqJZ4(~rAX_gkAd-8ZhCexK!k>&|v_ z!^|D}!N(E8C_F)ZSv@2|W7#ec$fsuUa)GrE)0w*Cf_vdplO&xlt?194S0<`Q$z#fu z{e{*Cq)WRaNL+AkH0FMGDvm>8V;NJdE7~qHfBaN5zF$B03_T~cZImU(B;F)9WxSJ; zwJ)-sZ6B+q%#a}c7j>721ts;!AjM`_s#Mv%wjhHX%Mhb}7{?NkZEXc1ESl2G|J1QGoKab@f%&oSrbyMon znOEVm*;k=ZdaK5p3#9_$(g7)O{`Wt6gZA(4waOO~YmW)Jz&!QlRRI7S6K4-Gj3o{a z#3^7!Ff}24jbYlA0&Y!Ld}2-#n=X_TFyH;k03qL$ry#PE2N=~>(FiW*APFyz+dFmr ztot9PPvUxGFwbb;!bwH=;)+VBM6yC?(_l0Hs`U{C&ZgSrFMKSS$tP#L3+B=$7jw3S zoLL_sH9u-=;!ML)m5f~@BBYJod%kuU%;x(kDnn)zg$mOj*1k(zTDb%n)QAIccOMWy z59i)^yMwc(LP6Srb6;}`3|*m=1_!Hv0$vr(c83F=AHg^}Hk$oDe&rxA z!yN;FELS|cze^=RUp8xGkbb*^v!y~oT3O7>a#kP>?MR8OWBnCB9ZRX;Nvxm6=8EyI z#BQ0SCNcmTT}QCC1i?PQ8GKGEGbZEfZzW{|%ZlRi8l>l7B>JbP`|$9l0WbF5ltmGa zHQU^zncm%MP1IopEQ=*;P{{c%v$zFqrwe^Q`pZnCa-OK@I_|gyN3ia&Nmoo(xZYtv zZLd3{T8J-QUNs^}ZENAP{;W#*ZQgL_nk`J}6_ryFrra<`{ zf4WY7_v#%c$N_j4s#_tENAhgujLGN909-ihfuCp25h66rHOD#3vRP>spPawfSS{p6 zLefq$9D+b;^~YHN#qJj&FKd%psCnMWKD7c_KKjR}d-2G|L8P_OAalvf=-B#X)1y*8 zEN-omQ&NP>$|h%JdaK~zkG8L=g%vZ zax5F9mF4`$5}dnoy+|qQPH&1VQhQ%~U!>jpeY{LW@jYbL5t0b{KW{m9n}8!p?JVyY05SP#}%!wI_z|z&JP;L@GHhU!N#&{*O2QKWgr6Nz=pWDx`WkA-INGM9SATKcZbzN3Bd3~Ae zZ}My6`nKr8!X9^`%UbA0BtNp_r#5>%MdRR{CiS8ZwOU#hDRBO(bZa+Dw>IeqZ@OEn zcWw!1Q(lKmxr@;NC&fIG5f8SdEthl<%zSSKzE!nczOA0hH94Bge;N%b1Qaz@x9tj}QAH zH>_auWY6y=OUN0U~He19e}RYnf1VK2m8oAL{pZMmlti!o`s{_*?-*p6Y3o5 zwOyu%wRvco2XZdH&LkTdz0XJv+gDcCa2;>>!}1f8W=?$Z{pR-BwcK&@$(bi)+ZsP; zbB^$$&B-xW&ea=qrYnxGwLgQO_pHn6vK3}sf`VvN0BtfIQ*$a+LfAMsr)hdkQRYG> z>g`isd;NAa_3n2Pmn!us=hogyd~pYN}iC~qG@-JHLn6&MQ=OV?a>VglA6-2 zz<@FNcz~s}qzZ`Anag~pJjFIs{(AJeh+L8prfPo_JIC(7{FAdqWlef2(RWt$B_FGS zxO0uQNenFPuuDX@aSoBi6O$mB7TX56kTC?wrCNsN?MGch2&N6^1RH(^FG9t^YGC?& z11~~2UBj9HT3PefIY%$GKape0(pm5cI5+(SUAew2v(lrR33;%aWlB`^ylr9~>@yPq z3(|00My~p>h^|a$pOI5K-6?9$x>800MG;=`1`jJb*Zs(Ov&x?Gk8MxT=E0_nhT>*3 zGi5|77@$qu`PO)UGSB&malx5IzjbbHW(@j&w%m>8KK9^QsNJsZ`_OoK25iIVID*{jFQ2TU+*yBKGS)P9QC)dd3j8{xhV4>%{^=#^k zlzG;soLQDMXCm9=I*PTE{Bw~%{^82>-1{yWYyP|h=OiJ_S)8uh?A;)+M2W#3`EKw` zMP8ABZ3pY0psxs_Wek5Ub{%^!?g~Os@PL!sw0ak7r@N%N2iBbkWSx;=E?nhRDI z2-uHvBE?NGLQpWqjse`&Z@v-WAisb|zMO+&%Q@su2-*_ehb}XDdYQQLlXK&?N;#HG zT-z4l7)R@GV_kV5l-t%dY%e^N6SgcUw5DtuDA0ec5~EI`;IOyCtmW>TW5L?G*{ucd z(bXzOunK^d5jhW(Wb}3KMuxB!Ab1<)zTZB(A~QkkYi-Y9&tSVV2)xVBJw$ic{OPdg z8G^4Z#P1ROSX4vAdKB=pJx1ZT{Y~+AbljNlR@t#n!$05TxCravjqxFa&Rie4A=H^5AVa{_w0)HItc>Ke8wXa2tw=0b>ND?lj`l& zU|zC_j@f$6F=5MD^4{NcJlkE)oo`qx^ni=FY_JV>Em!7>PtHj#SfY|S|LAAk=zR?pe{qP3PJlRg>`{K?Y<>IDmixj$>|lc?(TR2k94mOPVfx^*EB+T#1bK_GT^;_ypB+T z2+G*|Vs(4P!q-FbZ!7qA@+|SbNg&^SisF*ov_>XIyw?AWxgvd^^ zwbGL^uS#JxXI(xGXUk7a-s;A=?%sr}!&OJA@`8Be#I=jdKFVMuvX9I33t*j@tl#uu zTc`JSQ1o2y?RD_`1x`p)2s7xxvf=*?e4VRt#cBjjhR3x969@_DMjyqEbt_G-5 zV5c)2nG20ml#oUF<{J|~B>-5Pg-vkQGx)%=Qy@Ih3a9V-N<}Dkc>9b{(%~*9E-4h9 z$?+SP{3c>juI=%-b2i<$s5aW8vM7D6j8=@mEhjK@pGoJ~c^wvKhX z1wSG%^$IYCr6fkQZ@fovW2leAUGz?J2k<=Xzg`+po%?!gJZ&zv;i3`MMy{U?d5 zyK@ZZky`!Vd)`F&bUnkk=U}gI6%X#^F!w6#!%4V~yaK`7#XBx1Sf-lnotzH=I96ox zS?323zkkxbY7~K-_{WyV^0~TiK^__wpydT_L`K&3Up~@?amuDF*Y*qhp2hQfpJf8j z4=VkgI)$uD21e2agPHtan|)1Op5)-qb!_d&H90Zq>aosdHpa-ih15~ajI1pN)HSba z)zWI^THJbziw`#IpEJjl6T@+seQ_|y>V3=Vhh)All$xa!DJOg;oXU@ zIJv)q1a~)@0*PQX07+&FubVAIoFTnt=d@FDZ8L%|vD$M!t{QS@atR{xQwKFS3tx{1 ze8Jlb4bEAv?eDzQ>#pSif(d-So6ld)Q4j<6oo!>m@UcqQ)4^kanY&8?Sh+!BlfVF% z5N3-e*R~kK$C&F>4;p@|l)s?_Z3G{mY|gYkafWnlzweZE{>*pUU%;M$b}-G$%L*cX z38r}EG806}CXni+End9w)(h9b6;9JB>XYw{4h=!bj+* z(y@8!1n+h9=fJx3bwVC><_1W{?g?p9S=}o#_K#>m-xBY5WJ51DHI2I+vq)LaSy|i4 zdbUJNyYkx%^z=sr<-`0);x1^zaKf>xXArXBXa|kqdqSQ>G;pg~um~w4D`0Z`*Za5~e4B7s7fMgc<&<8aN+mc?w zK$o-So!qf?2+v~($|T_F&KL0Wkl_-oO#R_B8h@T}$^pRJCkVvc>a6YL+6Gt)e)9CP zOxN}gq~*M;JqO}4IpgDwv-!iOcj5F|qxBm7LVu}Fc&rnV>yw&PcMJocS>0T(wq|4cKh=ju*|pr6#yp%%AUKn z>r->8nVjNg4(R@7b6F_I6eUVO7x--fw%;jvVBO@E5~65Y73ElJK7w;?S2|heu1`St zlhx-WGcgqc4|TqQHGMmgLAPY>%nQ)QdT!wRl-7Coi{q~Ce3WH9KeYV;H1(<}Rh*;v zuM7&n5kM3d1_M_%3=nJ!ei?F8wm@M(lH!&yaE%0fpcrJGlSvduso?58YiinhR<7+k zH+Ey3(xj$S-F#B|jX4UO)nX)GdWFZ`reNP*s@PH@O#I?5=r~rKnM4-V6*eH^(mebk z81GsDj+4mPJ!I7J%a^ zf5rx69oj*+6`5cz(w+#Wzz2M4e&@owa{Wk@#fnkcs8f8q+4BiRsD2*F4;G%#cTHR& z2$I)${hFO~PNGXsL`FlCgs~Oz&fzTRTjCw}zS=#WwVj8utY;N-eqOq_eUMM@k4I_@ zlH}(Zy8}K8F;O{Tf15g3G?2NM5V_d|Ie@hFxZ`F}kYmmySIC(}n$ zVyd98kAk|hFg`g*7IF2^hSc)N@?qXfCoBQ ztf3HB6uFFI(>C&8#lcX!#B<&~Zt6#lpXY!3zT}{1e&m=UMK<0_M7gX!HqXyZ2}{D- z#BbZ(kGbY2PEY60DC_x=t~bm{V89&IVJz6x+Y5;UV`v5EL|_PbWyL&W{V?q@(ro2b zwn%{j%ajTCn|)Rq3M;%E!}#)EVPOiJDJyuy(3deNOzvDKLy5wE)<0JF?ZCsfKSR1D z-jNB=@}es4+`#uKU{))JjZ-$|v!0uK_dAAhkjAuE4q(Lh<+3eVSZg{+0fXQxf$@4A z&}U3>vfoMh962kUDF8;&=0Y%MgE|1-T;TlnSNA~fEdR5oo;PkikCL)t&kx?U4a^1% zex*e=1z!g2GRowPw~z^9*cdUF>f9;3Z#C-ynC~f4Rx3+z> z+i;vs&`P;-G+~6L+6Tlbf(~btgu#xulV@f)J-evIqeD+ zK?^nN30S?BH$rzrPGh21Xqm1+QT=8+c#R@Vf|p3@irYy1)sQyU%-*JDGLnVu0CGuG z)}j+ZVpei)jv$OfjJJ3%Em0Cp9j z@6{|Gd(MNzpYU^UAV2#O&%hm|Yc4dl|Q$ho>7BrI%a$ z*lvTugmYqgM>N5SuW>t$K;a;f0 zOe*2;+ll}RZeBwxyGk^cVPoA+iGs82gkb0RCrZIBkkN)%ja&fTaAsPLeY@@Xpf8AB zJaA3JiUbYVe(>9V2%jChtN|`_M#iLfA}%d`JIX~dW|q`pYH_ugSX6NLz4CNZ03SwH``7weO$k=u za6TlrX`~|@5(>Yvl9nw=J%Svl+J{YSUz#GY=MB~87!?oX;VW^A2SVDxrnjPW7NL%=zlB3x=Hj;7hWmvXk7l4{rMj*0j7#eS^LJebK~xI|yztbq|Z`mZa*xZG2IZ zymZ~Xv;w&1>1Mqsi4g=`6qA*D!W^^0LU_x7NeW@zluj-5uthHBmVBANf+adJz|=== zMAX!yS;B8?q!Lbn(Crc)w2f$nHQ1AV0<3kW735LT`@GejDyh(9O|4qBV-VarGT>pf z6!L=FG~f4;@4ujr!wyf%s*<68y%wl{jNg3Cc_I zVRA@y6#~;I6w$uUAscUS;H!0a`1}%cKOzSYGIH~Mr>1#ql>`qipNRJj@qSA6R0Q14 z{bJty4f}+Xnsjx++s54`i{;UoB@=N$)k0ida}p*LSD><}6at0yjiqu?f@Km2Ppg+3Jld&*zUkhhsqfj{7lkF^z?~4g;^n>{cC1kV z9p8+?;50zXik8W*2EI>O&TDpMzYBDnvfbOy?foTVTE?=03K@ij%YbLuR3oc( z60!2(6&Z5~XI(SE^<{kf?Af70>qpcn=cldbr?%*M&%V!WbK)2xj1EE3E;8N;ZXw!u zu(&r$3JOSTtIEx{jNP=%9b>}B-~#>^57$zP|Cq!Jo)Pb7%MnBjYssIX8a1`J2JfG+43|_d!NiPL&>je>iR zUR*X+eZ(bIOYm6N2K>1F6|_LRE2< zm{;3C%j?e+%cq`&a>hUkv`?RM7ABX~<9i#wt?KflEHTCe!7m+3rq#)voIUM4#B|rj z@wxT+NV&J;Wj&ks^kU;0{}wqP-Zx}Cg-%FX$;e}2!U=G|8v{w)Sp)(Tu7){_t8vmf zlQ4Bwg{dL7l>%-S2t{?Yjf`W6%Ow?dN#$+*OKn*9LMw)b%u=7^-R%tBlVeLW+}lrW z9ssvslK#n5aFDpIxqcI<6=Vmlv4UL|S;~cJ-AKmAPoc&k3{abM%1a>r=)x+TF#Q0) z*|*dw2*eRG$Kt>VV7tI@vVGd@(v*99Q~!RwY8b#0ohW=%Kp3|-$M_Q__8ZK4c21SZ zwXF`8$WYwXwI|_26HXU1O42WcIg~WFbP_%}@ocQ9UX1^0eL?)ZYaPMMSmB%QVu;pG za$2QPSbVG}vY1sUBS?)Tr@5k&`tV5SI=X(s(wGZxl%KD}+;CyEjaSC4=e(5V-d^L9 z!xR~WCGYhkn_!_g13_wbF#t~LFTUJ{ z2e;=BA;qz0MH^JMJI7-%ph+YmH%l0C7aO@h088W&&Wa}c#xsl`RE9JS! zaR9w@L20VL9+a_XCtuja6Bpffrm%=~KMG`-gQ7^6(}rp;it7o?D4l?tCY~)WtvLZl zlIBUE{=(GDk{I`YwZ4e9pD2WXSMy^NPo?(JiJSYVOs(|sJ>?Sr z$f6s>ch}#6_JKA8ffffC+Ss2{Jy*P)+}jG2>&uIAp#<4aEvd%RNu|=gFI{X!{xN*v z)Cu^-&OQv}vY9O_dz&vz!t)$LoF?|$Q%VvW9?*iEcpw@!=yL6E&KK{zc2-t`?GdFV z%O~Pvf4o@S{iXG4idmrA+JN=qWp$!5nvSMo&mFxQWtf;X#F*dsTmw^2Z858n^$qy2 z(y~(GOvFkH_O6V)&PWWbj~~87EMVj z2CG&4ITlPp-**T=too=|^$%h~4ZHL8sMbf1%rWM!X ztIbbhpNvf>?ei0+pxf>^fVkSmfB2qY<1=T%4LR$l(sgX=+n?p;zEJ()Pi7e+TC-~a zM}vg0o*5hzojko1H=bFI6Xkaa6N7S0T`MIx-$O&WA%WOvFqXKxOlRzY|ySnK`?C#!gwjB!()e&YNUdz zEtR00U3Pj!5vocA+WND3V%g*vYYoCq!&JaEmcFT%8%Yz9%+ zXlx$B9nbYpTTjm0vCc*Y zeTwgG@Oi<)AJtF7AM=k%wJYZ&kF8UAfM=A{ioc(EEoPO};b@W?3-794l*GLMZr>x) z&EEkdd4n5F?uyHCK0hwtG4if&;ryZy&I3c#nd`--zI`~YGMIWgQ7u}+pUjH5vClLf z`Kd2bwn=wSH3o-dZ1N!1{Z_HzFI+qUlPj|sU-joCdF+Ert8o0(QZ>sB^CuOfQd-=9 z|5*Eo;H=`$@!}*Z=}NhVy_TiPxp!FlROs@Fq()jud4&{iidIs%tf)*}+wgwWm3hV< zq9NS3<$v+iuE#;hb06gFb6u@v9alYZcGRLw(ys1Z;@@BUiUjH3LW5KcY@5!T_D<~T z+)hvJeq6Y;8=L89TCe6|$8_JDZ=D>6y3!)Nzo9a*dQYz}Lv;aJxXNn=;#G3HkwJdL&s`&5MU%(#bb$VzSoD{F7=$B)0cm7aTKkB}_p zvblr&+(0p9NGEKP4Ts@ikdQCq>s9XIiBrq*+1rxTdRqg}K% zG?si*^tEBz1vXqwmCY0c^#g+KT@@o9w6%$ZhHoCdHiWW*& z_Ra6A%?r+)6ay}kmhjSbUut8M+LuNwZ`1@&pS(1x~kupCIxi@JN}b^14a zO27GV$&e+heNmr|X}&I;bqN+sSR54p>DK%4^zJ8+e_dQNicKsVT(stp6~43*Ao*_T zZ>GC9e1qQXY;*-mib`4#^FMbe5bDrQ^~dwV#E#CT)Cn_M}gb4Y~W+DfdcE5&<0)sTR*r75#3 z{W)ajlNs$}_QEjZy;FL^H|*6Gzg>=!Oy61E)b=GSdxF#f(4P z#00I7>Ar^Vd{fNw31DuPy%dBMw$*Oz%Y41=X&i+D^QKd}+>XZLBx+7yO}W083m25* zPoxz*yKZ!eDHkoSz|7jwoufKRDI`;>i}1Hs*5T?ChfnKYSf3$0Ti1c9mu~e3;-BPV zwiq$k2Eq-5>X_HPteYE^B~`d+_T}J9?QLjVpDdCxlpBO)9R-^2U+`gk`lR0#SIZc3 zMM;Gj+*ZgKFeR-#*lpit-%u;G_IB+P4>aB{!Nn&yO)8&^3uazqRY!A6nma3{%Sf#t z#z}#5>j<8Tu}G@7=gK(eZ_2px4=poBI*z!#dkB>0ST;bn`9|=M zqBK7Evcqks_YsIP?_~PCD*XB_GNkdbxu~ozHf6(_3>(2)*Z?S%CM4YYCFDvuDwYb) znU_ozzxlT(i8C&qf^0IAp%Q-6;2g)FH|`sBgUjnJ#1tGB4tClO1wifF=mudVjl*(D z6?TCV^KuJvbqhNr$Q~E*vX_ihm@hX(ZXIuM<$||OzoybGj1nFfWV7A%C#l1LP`}uK0EK4xip9i2<=p0);|9K)mviT?`huL_s`aWZJ8UF0zIvE=-lh(?} z(r76pYbku@Um0u!V-B%r7ne_Tk)(-D_&9b1A7h_myW5F&Zez{c*SWpBjZ*^Qk z4DME%==zt}pCM{W{p$w@X%OGvcsF_ndrc7%RmIify$$b^z*DjN-s(x>7--uuB`6VkZh3d3(P_E`Ik~=#on-zcFdWZq3W3$SclziAR!TKY>yPUm3_;LO2o4~Q&JQMQu+1C^1{A46+ z!RvQ6o3~2lQHK0wjB%dxON52GgourO(=Ork7pF8h5ZA|NOh_9t%7Ql1#ym5E|I6;3 z?IQr(yGP+3^R2xd)-ah{GErP#w-lw~=*$c#gjCx;I`K>~xwy)Au=7a7G8$}bnP+CF zz3~SGy}CH>z|NsQ>>f-l*3@7v=!x->qm{j_-Z|aP5@wRb5DA7~ylf(V`}`VdVGr+m zo-3{GsWk`wz+c?akAHZq11&wnTXr)tuCcvqoB3t(5)HW|6Z;Sut5f{L@i>Ls#?rL_ zs;uX8roSV&{_6cNV|VvXdv0O{pEd1VoLaxkS=l9`1eeUdLON}VZC&K7ato?3pln9D zX%F%HP+z@6J@m+qpOI1wEUEd|%cqUh90#eyKM{DhEbzLaq+R zR!LrkE|C|LS~2a`hg-3~d*pkc9=Xu8>Icm!na7BfsQnRB^>;;^mrYa66RJBLhNx>4FPw&(lNZd&HvR+V$v zhsnQ|-ex?r`>CM*Gp3#`HP2Gp{-oYnRkPEvuI8~l|9MJzF+SK(i2#N`dB2}uF%{2T zGYy|wT#acJ!z+KP(^O`sof340^CDy>hykJU2mU+!MS+m@sl_&dJ7@S%n6h^E z1UcXgU9Vf#cHkRdT#KgNKCCfqP9;8d>xl}e#Z(g;HV#dgR~1`8Hcd0SA4ssAYH2kW z)1@DpBR==9%aZ9-mIeoM_{I0PZ_Xzp)vD>G*$h_&|TmrF;B zl*W3>q*A=Up$gZ|t-!(wCCN0XLbyrI=l<6>x^TAy(p#2Iz;B;WGi>=53F15QD1!|d z?%M9I{9}?Y5|)p=LTK1fc$~59D6IcP9}R9>S+TD^(}bN{y6CD;&KGB1G7TkWjf-U$ z)MJi}0sr_vx8RjuHi^N+Il|8;7Pn)Ij7YGUyJP~r=Tq~=qSGe2`V=)vh2ZD^y$x%h zZ^mUGjzc7TMFCx3{q*#*ySv($U)v8v_`gyAq{bwImBqZTT5ovi98GO9-~QhHDqa9Y zAiHz9Vc3ftuN&+Zh_d2x%#~I!rwwhdn^nT> zIr?utXi?TT8Q+)_$7JGh?!etspcomYw3GS*zE2fJJH&EwLl{Hs+Rcy50`uAE(g_s$#H zb*C)o-QC&atRW+W!Y$XBh6m?(+#8!G)aYSc#vw2ZH#N%D&@9_=-`6)wi@p=*UOfY| z7gQ%9l&R91e&6pbR4aMm=il3g*8Tm~pTpqIlUkwdjEkp=t8Qq(B$lPE=2}1Vvpw|C z-CNbvEoh{}vU+toH??%w>RxF^E#iJ&y2oY~KunF^e82J-;(P6|6*_yzPI z=V(@WG8ZqAA(B$P#Mr5`^8;0VbrG&xR*4}mo7l6_Uwb-ocw%Eeky-{-6j=-vK~rrD za^zR5%;1^Mpt0k~b80ECS9w|6) zd$~P%m-W8hp~U+BxAP_?06!A7_79ra3QQsRc(xH6I+(!#hS-^8 zj588lZT)!sz8z?Mqa7dm>|)Gbq&;40&hiD<&Bl!R)%f<`y@9sS4<$CFJRieIjvM5m& z6kl&|J8+Axd!XBI48xo;8N0>rU^0PX#y8`kvZNAqW&VW#y%M0?`dgimpvvXUEbLYL zUci~s{me;$^HaMXxAKRr_wKKer?Fgn=TZ!Bc5KCxi6^?lGplCF7Uami`x-}wpYoBi zP(LW$*q>Zfg_9GxOBsdBk<_yHIFFe;^SdB!Hfz45kpwQoMobf)SIe~ zHCj+M#Vz9m>%aEPz_Mjb$*m`aEOpScmEb+&lp{uY&C{dh;@;aagjQ*ZOsy_X<|H2} z>Xi(>qwUbRTvKYP7A5d&bZT-=AB1bhM|)Bgmr4z^tk}E%)#_!P104pL-7=fW8Bgte zT%0s{Y2adhNrHC&P@lg*&RgBQ`N=>l^0JG$sS;r3ZEWpt37VR`O)KG59T$sZ&_`qb zb5*gxSyRgrYxy#1EzgxeT5$jgh1+B-_@7_v#P>G$U~jMHnRm;0^*@|B5i>{eGKuwV zgQHr`wx=^I>z({xYg00%orfYLziX>m;mgt6|W7F_!q3lsn+ zr4(3S`SE!;?xb4W^VLnFPb%FPUOyXWUp5^zOet#J*QY=nFF(EyovnlJ?H94Kkky9p zcSc*e9>VqAKqsc)-cxdw@{DPFzA;O)!c#DrTSC7F+5%pxx&tL8x1QLbU8DLs{(YQL zvVXGP6->skDpymUmaodqYK;chb#eTJ84l!`4le1=9ZNqCwNHYMm{fd_?#`n?YN{2x zBc}liV#~b3-?|Z^`j{>2+>n01=aqDS9mMNX4iB};LHxw#UcCR*Y8*-GlZ?Kpz-d3z zGc{lW4@pq^Fc+nf`_(eRu`Tq-PY=b z6(3$unXK|P^8nw-)GyKWfo;9`>(%Ya6ft%8iWA-^J zra1GG>8MiuA!7(9oH-dc{COFMWC&@_;+kZ+PDN_U*5=pR@Z)bZ(w4PtCf2MiKH(Q$ zN^VrJSh#71y&q@MS7jvD5e2ZzG#Nfty~~mqO!NKzia_W(+KmP zM?-tsb2?MqXf$MBVJYl>v?V}nE}ix{c-xVqCV@WL~l@V(*%mZ>LJeym)BU)tCy ze)&^l#xw~xpy2M&gbf@3Q{5!wmiykrP-r&muB3%>HEnG zH71r%O3EKU=|o&Q_e%U|%MYcib^u-=CGyr;BU<#vPAYbN5e&hgO*y*;xc9dn@gX^> zv+Q80ynO(U?}(JBK6+YAnf|VzB&FnyS8?UAAWTc zw!Ges_kQZQBqpuO&t4F^G&|b{@Z7_D@YoNxQ_G${1_ZX9yrCJB2n>j8fu{kyyK^x0 zCM(`PzB6RVs2`(mu<^`P81R~d_dOfyNElFbmXx_>?hxvxuk08=OSc(@{sj!`eJ6ZW zgXJQ@>2qm3U~g1nK;&hL1zA^f#0Z`!QfrvjHzZrylN%6KMfsC}$0Bv-`i;_|jU?rH z^tz7bLo*P)#uD|5A8rv(>rDRC6B%;=tw_0=zwxWiWG(IkozpxTQVEhzHTD)bY?CC1~ku#-rOF7JRxZd*5^-mx!+dZ-&3HS~)9Itz6oS+WR`(&=eUKbk;PY zLrL}0efK{rCS%2n3LMOOBFY8*BWX4N#Y;NYYp7E9Uom>%S1X9+%iu1I zoCM4#3Zn8E<6p!lI|~o+Op%7@l%{Xp;hKg9h@O9VkJu{X)7N}z0Zv~LCIl&$_ILkb z9o~4M#aelka_?!g%V{H7)`gRmW?nTih@vXveNlZLynxV&PFex7cj~@PeThU)vYB(j zSXy?fl`Q8MaZ&X=w!RmOrj;Zs)2T8OtBNo!k1?WNCAp(@NLCvv73#P0`rY$VR|5Fn zsB^J!eb2@+BYuydyq%x`nmP8shq`S5McclU%y*vgrWFT>fuTXP$go^h*|7!CIz}98 zH_p?e`(7)_p;Z#}5yt@Vmyu+#xC7|c_<*ur_jDYcX)vmtPjBr*$3v~S>8zUMZBvIc zQEaDF2sZ6MxQt?pR(_Dj;!&*Av++*gJ;)3m+0*8Naiyusw%BUZCM?5 zb?r<`B(p&O^LwA6`LzvVg>-K#QgQ6-7knUDtm0R@pH>T<2>#l^S=F<#V$P-5)4f}) z+W#Uo_3XE5v!5reuc6)wBBoS^LbzkF&DNEaR|~n+SL9n$`Own>sQ@Uq_Q8Pjy7obQ zV_g^iV||y5@p~{;g7p&%t8m-$x&s1dMcZW@yQP10<7@H^lT?+B$jB!*-Ci-wxo#pg zU-2t1mc@085Ty0DO7^<@@86I>+)P(}vO$!U7vrUsd-3?aJ81XTE~gA=ceXp<>$yHt zJNuUS^+rNn0Ni~I_cyAR;@@5n`&F<6JkFWabQfocU6mTNy`&~Qv#B4i?P$?4VR`md zCs*SCToNj{meg9}e{p{s^$z&C(k2yNO}!EweMDe!=VYd}b*sY$^ZC7Kx=>YPXWFNiIQ-xLbjd0cwl3 zd}_Ghnog)N=^r!8CZw)u0lE!ij8wzdN#^|inr@sns|*(&SB{C5hbL+5ms@+WYZS^z zXT~Z~_2pBT=IIBuLp5dv$KV|tL*PI%J{0#{6AXyR21=FhZ8(`FnC}zmt>sr== zr4O3$pa%7!p`qmE78A=Sv!+UYY zw6m3~6U(QbCDyjA!7ELx#g2~c64ZTPDP>W`!{^sD1oyPFV>?qq>%Axa{C)D6?mroe=lq^m=q|)u8?m4gsx3qmSTg)LX_Z=f)~jTd;uVb7Bss6`g@1)%+Gd-H`jHbNOs=t z#xAu_IA^I#FVBe#djs%Lfjsx_ZoMa(wl}k`*jtQYeeji1fm#SVk2#eRFf^}_bkmru zd)vjG?YGuyl~UZ=O)y#wI!71-ZCyj6dw{vw4cOUi0sib05DZrb6fi*TbPMkxOHtzD zcH#yBz81GHchsP|qzDzIg$vlxkXnuG!8dwAg^kjLx-tZ7 zRf$@dA|C8qd$)TCfixxmKz+n3n=JTtNb7lT_Z}Q?rZp9bA~e)4z~gun;UWX%PE!N5 zqpuy`TXz>eu;?Q=bGn{-r4|=?=gbRn;-r)D+@5Fg;@)2+z`V3xCzS~az6kcD8@0Kp)-+i_P$4@B5 zxl_w<>8uKzQC}+CTAaKJGK-s%7;4WDzWPQNz9FsVeZ3+7t1R%(oKTIwl9qGTL55z` zA}#&Hq;O|}cYR_(hdd>mBLksw$FP$dIm9GEm|q|wMKURs3A`rYDcG5ME^t0KvkYf% z+t_K!nMV1t0t_*{YC96yHd+8o06KMAtqgT^^qQr20dC0pamKbYuj{xNt{%TZBG_*h z10jBlg(UqoSt40(*xPg;imsVbJ6IxGcs_>=GI~3NlzpjN)-G-et!I;oVnN;oUdbDW zu-jgX2rDMWHPWN-Y}Xe0ZCoghm29!L!5+MpyypN2)8yebmG~jMHPYeFvrkSvbC=6u zvg(V=Q_o`<7q_$ycHyYf>-z@KEaScPQx9LV*biUr#_mzBXqB~2`DE_mW!+4{PGk#$ zWJksW76IhDIGY+kn_D;FU9(oWDwa$-QCf*r$%j+G*ko>y}8+^GQJadiSd9xOS+5YOU~?mQOA@tc#VX zDaNn04kVvDHgsWXWpR=$cJ-VJoGn3nuC%PnWWNu}{@fws!4K`|P0FolNoQAANO1nc zQ)=)Rr%fp6t!g8YYSVC2tg;jryHb{gQ%xbXaefmVjYNDNdw{-H$BDkOSl$zB1Nd)t zS`60K_Tq{Jj~koc#xxTqx=Uoex#^C|QV7&aYq3qHUR~SKn>sn#<{2LG-68Ap<}{xL z?@E&IX;x4m05Orj(yZ&)FFVN{Mz42@k!1qbS6cA<>n4`Ip6X?uEA47c^Vp2i3B29r zRIBuv-Ap}j3SkD&QpPX)b4zcN{OreqV`RaS7rM66E;Z`~p>l#?IWSFr)`SQKrNwnW zaEJ{EL5s`NePIE*F+NaTcI4(D=OeYU*Oykd9!w?_O^@lPix>UIPzG;&oqkh3mp#S!b<-yjt?wsGi5<&*HvSr_8rH-G9* zPsqf_+!|5xw*v7yU;jqp5`X`q59>M01(0%W@95fQ`6{`QVo`!i=Uo{Hstqk~By+Q^ za;Sp5_N3ZF z0?sO&y`g=0#YC;^t*mJN!i?FAYF(JvDe0LS9~>a_ZN8?oIXOslvKVcXkii6TK*Z`d z!o`YfkvL!@3(s;OyC|s%`w;0iGJg`7|2pl6rXaOZ6>8d@9?L2jYiF{MOm;1{)m~lU zV-?YFevba@v*3lRz?t-cMa#=M;3QGllq+p*TbUAKgmCwjjCBX6S_!h(GS~5M=g6TW zL-Z}KoNliO*Jl|Djinq#GgQc{jH#QjWwb{R-`x8YZkhWYl#4N$tL&&*8W-Q&_nfe< z5Y5fzIT~;#vQq&C+*CJ3K{vz$2W~*Beyc7@uTgDLZ&iF?Vg1%`(@XXde z^cT2Rb|JK-c@Y2KQyn-^irw65ArO_Um5_7&Sa3%4Z9a+Sp05mC9rn#s1pnRE+bUk# z`+_T1Bwf)eGrL^5Ndhy81V7*Xld)y>7OMaE!fkj~ez*3uU?ke#vroO!lHlqfET47; zrrAM_B*Pp}?0C$q3vL2avIWw`ovLryrR@5S` z{yB(nM$Y~?M^Hlep96bkmnvfQXn)AyAc1we2F2*{%+`8r70594nB!(kRk zWi;z}voB*b1Lsp^!j0uX#Z3osy+lyfTII9qihVx>jRPBomif32@?xv+Z5a%vGeusjvlpIV|aCCLHi=a${Tq_ zUT#s;PyQHOLw%RozvMvt+0I6Kx${kob$YUW1Ge<-=X^oVH|@0~#`OM?v%V7u`Vv6Y zw~H#KrLJuOx-mYmaPrvEY7|KS{bTL;%99;k#gEp$kpj2OeYJ z)SR|}=2XuElVGVq%}1htmU;jYWAJ=}gn!ih=I3@l1D7NBgd%HXm3nI?%R z@Iyy+1%S;Ffc>`8n`57KCtE(u3J|)wb6((ZZVq^t)lYVwXU>2%@j)WoHIv^tXQ1i| z(ry#2~mmE22Cua8egg;zjrKV-p!*tHYOI{CeRclgRz83&bd=rVrYOmXC87ke14 zy~J39b(B-m^z-V^4dNSno}@SXn@8w?qeqQ>O}KmiuV_GarjyekF0+N}Q+0yvGyj}D zR9n8#TO#h;#TC=z%eN*dEKT!Pd2*xt*Y`GtcCM}`) zHOGm13Ha(o96LLAU`^A@P*b~vxd)Y)cG29+g6wTo_7~e80*hA(Q(iRpG$n3tzT~Ky z26ZeDpJH_=NX@7292i+9t#0neb@RgYsu!O&2~E3ph0@Z5RP?rY*Jh_+d%g_M4|n@% zSMlivxXE56uA5VwWX7jq<;naGuVuW6c?%>L(SJxt3p&0FoIbBS0|Z0Y0i|3Jf>opY zA($OuZh?Y!*gA!9k;yt3=+zoc4M!Lh5n|o8! z*m&d6%-RxMc|rxQIk5tj2e2ZP>WdBg2k_UwXvf||@S4L-O=*CiSEJrp>jycdMqVs7 zDK$pZJj_dztyb9W-Ca8afZi_|zHhKUyeP4N7m2`C?wVmN9c7un-t?Myz4^7Y{Dl|& z7tOg8m(9I0IQDAO8m!v)qPz z_b!}_lP8rPh)x)gT7*m`i1ig@L8p0a&LX}dS0E@1Sr8$&6(*Ds19N){;{#pJ#YX#C zC`T>bSzT8~U2Xj$ydqE7vI*VE5$DJDaFLp4%|M%1>h2?{qi%{9UVTY;APw$4odXJ_ zgHXWCiN&auvW&ZODNmmPaepB?N3gSfN$Z>!EKMY5Ufbo0<-BsD&#@WaB6FNYSN2o6 zQb$c6@qI4cju2#vyJUH{jdi=!vkce8UR*I1Pe_1vS=+IkBJwJXD`TtH1&eG6^1Y>t ziD>aU;IX!KP=SwI=f4+Yh1v&u@R!>kpl91R37cafY|L5DYbVdTK9cnfA{oh)6N85|Au)cIktAI@f)#Q~=GRqc51CSRq z+ip2efn+`IQ>QEo+V$%GHOXjpXX$AbT5`B7PlNJYyJgoiQ7oU*OMVJYaZxcYnRf-Q znD_2v9<`;No!jxF%|G;2Spmz|nBCsq7yz`Qi=-8O=f<%M(2CYdK)vo4`*F+ix@6t$ z>VxoiD`4K#K8TUw8CbcyFST#+vPtf@mFz?Tiy*cKV`y%;AuD-;FxLrd9>tW}dV`QHJ5x@iCGY z0WOx!cWGhIV)^V|Z2d6p5D|{Jg7VB4xAv#Rj`@?vyV~duA&VvFMdlp{DfqoH6kzrqVgRJL_8pq|l8@#&I z^6Jd@W3P-Y=zz|jUxxc$?Z%O$Y6;B0bzUt_o?e!KU-3aCZ>y#7HcBA<-pgHhdB*^T zs1UJO7%6a8R`k-Dez`j3zEy7SZ5>;aZI{&@TP#R#5>ZwWUy$LqU3_GEbvXZ6C4Rjj z-QIlATP48`S@KL2SmzwK5lqkXttu@p!zFVs$F&Q8EqGZ+XMZQ|li;je;Z6X%Tld#k z*ZR5y_t5ITFahZF6s)mC>JBzbugmX0+kyvo^x|($uRGxQxq5%}#*V@i5;fIIWpndo zQI!R))|>7&UWXWjLjlU~A=36JJkMA`@@cv3>O`en{nUQizq3b7nN^vTKjWfl$>$(Q zjIcc{b+r$ucSVD@p2NiUjVkdo1n3KoFP8w_YYfLU4sh$(pdYJWZ-+z0jvu?jy*OD! zS=w;%bn^4eTyj;BU}JJ5qR1My7PSjr8OXKrMzGcj4j$k#X=lrT=#Y_t+6vzUmC0RG zRDsT1Z*Y0vO3L1!A>XV5nLcjA9QweS)$_&#IB)A~#_c;FrC)V!_Ogrk_<{2XT4L_% zNS6sDy#8wx7xLCwvYjYJX-2PMt{`_aHcwu}0Aq8hk>IEAysrkquh1WeO`#qAo^J^P|!+UymyKL<8qB1O~ zTa>)HYT48?q|1q=Ajk6CE5zOv#)XF5no%>0K6?C(c;BKA1>mgcr;YbvwQ_BPF>Z#R za9#83@vc;ibu3f6j2nM%b2qM)*7T3w?7`pxuvBwzVHw<(?te3#nY{F!@q9_GuzNX3 z2%wwNpcIyObugi+sjp{H{P3$A(A9BpIU9$9)Oysv{OL}tdSZ`hb2$H0(dwu6rOsP% zLZ!b)D{NV^PjbY7ralz*C+xYb4t;r_`{j#~2ymTEx6uh*-nzBhB0E`tRcYjZj@3=( z{>fYuo(nuykZ%)+?PB*Tzm#`@lZu5duABzMz)Iv#r_`Z9xp5s6)M0rnthlzg0vAt= z<>rwkwNjW`h~#sdzmI3yHz7Ba6F$i;qTr_C`X4N$D>t5NTlj{Sl;WyZ~n{-P2RBz*;R#G({FYSp{1{I-n>sL0-rr8 z?DzAooPlQ_+?i3@3lqm__Bop;D?~Q%c>B@5GSMUY>L>T1SGN1gPc&d=Lp3H$KC&-4 z7?6tkj?JBT^!sm0aNb9QgDz+zTuzj+AXN-HD-J!gt^~VU2K|k4{4#(1?Boc5oE|`a z%qYrPJBZB#b7RV(6;TkEhjXJVYpP&3w;PytUUPDyzHX7Rtl5Kg4mp7!Iu5XJbydlV zFK+3RN=&FIUr@IMFR3X|6dB0meY5)Qv=sIgWw=EARegUsM$Cz`CoG`Ts^{Qn(d*s2 z@PmCX;AgF`X;E$B1U6P|pFYol(<^}?d7Do1Gz3Rx0oOTjx9^^YRhaZc5jdlIZdS7r zk9G{u_k#hnqRW<4W?G6zf|Mn^T7sbZloksamlnyQ5y}=6#vmM$Wt2VAKd8YvcNi?? ze5Cp%jzcT(QS+g@B^Yt92l(&gC#Al5%Y)=F1A1U9F;*5;V)3NogZ3Oh@g$ru>11Tl zya^5X&87cGExC!cO|OdAnpR6|t_d9j9Z+wV$;n<+udJ*nt`s%pwOBY|G0vEN4rbNN z4l=JTsW)N$VB>$|#a+L00PjS*XIBdi&Z1tg0Xi7N*UhUurT|)zO6*o^eLuCQAOC!I zopjY#6cn3QOMH&T@>Ypr@q#6D7S*D%x)eQK1K>hGAuAsc?S}`Sl&g{~yakCX!6d77 zFEwN1nif<|C`DO$5uDI>)v)cPzP;t#LOotsGYobX5w_gf$r zG$V_=9%16vK_K1K#}oy9j$K{MC@_>0zHz2K&QD9?C#$>Zb63>`{dKie{=c&Q5$+Aw zUC)dN{>xF?so_*WcEq9j?D9$U;VEa0JaEj_4%O12Y9+;uz5DRLd!NTM9h<3bsMkMY z1JVYSt*VnYrX5RIe%7R8(lD@XmX2``QI~Le{PMt+lTXdMsk_vl7@+TzpD*(r=gluq z+}vILN6w1Qq5%oS1BY;-l0!ugukXS2r-T4@>AWlOqfPe!8MaEGje^Jj@>3*Jlb`BE z8IvpOgK}bo3_A6y$?5Vu^|^4)#mTau%Bt

6f$@7nMqYu0UMU}G(|Po8B%3IP{D-5tz9qN6~>NS_EJGbG%mRD&*?_RVg(^1Ly zp~=p+o=W&kOruN!%utFoJ>4Hs$Rd>(XS5#mduC~!IK3tne{M7(=MbRHd}wuGh25vz z+?Oq>IO54-#|o(x&SHRGKJ850zww8hOC3?P=C+oLKC?BPZ|VFjLW7;zmcJKGT*4$* zHuVqnVPDU_WDV^YywyBr<+6_5*29sS$NXcdcs#N5QR*G&4Zs+NRoUCR%#C`dsyep6 zXRnM!uf_3`PjaUpi*9aCZ4yM)8s1Ou>BHZgQJ2KkvjoTP-XT2S)Q{29?Q1&&fL3&x zj6?t8f8X>j6@bZ-5GBc3fmXJA0byRCkqB-Jm)w~nU}xKSU|>d)dC)E^Sy)R+5TEc% z4q&W&V??H9!nV!7kJ?OuCg%%ACB1Gu{&hg5%YdhGR{ z0H76pdgiCG0xx+F$0t^*wf#N&AmjFOfm{4z^T3EL@;A%C0 zd2jb_=|X-3TidrJua4Z&u}!@`GMOiR{_G2I=Crd%1;~~f+cx9b-B06%J-5%O+sugZpr-lDa|l{^*Z9-h@vstj1p~)7CVnU+nC| z3;Rb8&`NQM-P~%r)e`wxzsh(XBEgt;K1NC*tnBbWX!3o5;Q8uxxgEgj1)hUKOf=c0 zi7nO(hIO#=kDuo*Bm`J)maslU3wk1uomSRc@3Oru3n3D4r1J9an-+l6N6)KC06KOc z1Z^UxX@)ljU%>PNJc7G95+0>eFHwVKNWMIa5sO4m>emF4=DNFB?LvGD!sw|al` zr%(O8BxbCpbjg^qT1qnk&z^zq1eA&U1`|P0BNot#VMPWjkNpzd8Z@9=YGX2Rh&CW(a4z2pfBLBHnlbDrHRjOBei0Dz<%* z1n6Vcisq!O=QF32;`dLi!P!&F5)Xk|oaB$5Z^KImU_mST%GncB$zsnuxD((0yR~jR z20lXJBr?xqapJ%tOrMukX1HSqM!Y?WB6lyljtT?(^8+hVHC*`DJJF%C=p71MqKxff z+rr8e+S|Mzg7ZhwKS3Q%L4g>qyrS5mxBGm3|NOBjNhpBRH)TlbKX*N)+bYui@WLOkXLe^WF7J@#pieiJzQuZyy&|7m)1OTjkd+e4ol#{`>>SW}NVFld_(F z_{sFE!oKwUUnTRB;mnC}j+qsFeuo~*shZSOC`6P4=c2Y-whluM5mh|+Mx*b9k zi5h81*Ot_xw4^MUHq|G!W%X*v?*1<63hLwaQo1I%Hb%>c2JMAcoZaz{o^S(QDm7@{ z#5*^3luH%*!`sgY7Isne^+((B^LOvr$Zj=l#2QFul$>|qQmKaF@K3*zd!04!GNw_ z%APOGzgpBw`O_t3%uWf!>w5Ok8W|hj+1ny|NWW=;aum!j_ir7ukr@#&dBD1cA&t*p zo3_@#^@}u#tW()@Tc8 zLvFqGR+ZxY1-?(cT2X=Yp3bA2EH)NtU`Y2*{01NmNJX6V?X30vBIb`c%f#(|-J@y^*7234uITiqo=y0!nU z!DA|?QN^eC_2zJ}x1{Dyt2i`Yv_z4bf}~c@8lD(`WF2+##y;WzaFSE4Yt(MCa)3*A zvfRS0Tp$ewT6Vf@S^X_ceVJte_=F7MMQ&(8y6YzXn&#a-;=HS71+^VNvlKu0RhM6C z)k%ARyU&A6UNAZCl^Q>;0+6+BBYp$E8r^OAz!MqgBkBiVQ!F!LTh-#3ooZz(7d)@P z?WdhBLpbxe3NdSv=P|WDwtA_>OUdF(ag)gd9fRc{e<~xPP+7_kH@$}Yn_k9GWo-G$ zwhefrYd4x?%y=L-6ofL23=&=##mEN(sCiOyDCi;|!6BQ{;O2IVFc*k-WX97Vl1tDf^q!+bPRuxcIf+{M3whW@r;>%pGo-uv_CDYFW#rGmq{&e8(!O_`F`YB&2H> zzTf@k{0H|t1X{NYpko&OXr16n#v1G^B?W=PO8s{@i2cCOxj@d{Ll~Cgfn}~66d?lQ zdV~{emdR7+-@ow(smtBCs4A7QJWiTad_F5i|AF5N=fjT_GP5gFF}x8z>B<@z960Q; zi0pf#?XwrW9tWBfNma)?zASIIol4|Aqv`9yn$l650x(S4^1vONQm6mcC3ToNvBVDz zKfYKszS+cB*o;NjJ~9W4+N#HuRgL4Z6ZZtmEh7sIUIXTB5q7BCwg%5IxHh{UJgB%K zYBY6I7lFOYTYaA2+=~}B$196f;8U|MaGl^mExJFj_64$q0QVjM*6I9#27KafRDe%Y zv)ACq?eAO!;1qU5P+lc&`Fl3|BPEib%EyJbuy~^==nGq((&g3WH8S=*vph)gQq%}N z%{idF0Iil8Lk6OM?!pO2eEH8~h1AMtF)1s0`LwePALYWqpBlVY(18N08zGQ0iy98Z z!RqjXSR^wvj8IABLC!h8;K38_oK%~lS(>a(1~-e#J|w6$q0=zuRg8zxLe9%P-4Vavh`pn#`?N?cdlS2){S))iV*_Oh1z zJrc2Jqj@xvwV;p*yh(5Sh4gDBKQ;4Rnbxzx+<-n%rul6Kg;5Pd@Q>S;lwmGy zcTJY1ZNc9e1m+%Kd~>}1$V0{K?6vtTEm# zE&%~>>(B^D{Qzy!f_Z9c+vVFQ&r8XXA__Po;Ti{!2!)utA^=xUpyCO(2#Qwjw9D2q zvNpk8o4BKswaZ+~A&VOaURK&h$ohVA=Vruo=7I`bbW)}3C+@j&_44~7{%t`(eR4MM z$D#&9AbS7~dVK%;W4fxG>jQVL`;imDPGT#85d$b;%Nc%MoRSHMnhO zMc8(b18^_^}w;E6AW>0oow? z?eTsUi;feb#!1uNFLfpJqB%{eoQi7~{hHej02DT212`shc%`F0j*_TJyMPdwcC)6^xE6&)u; zjgzLEo@zKG<8kWCd+GlpJ}JEpjSP$7cu?i2kVnp+WHfTrD+KZ zYKhiAdMu2cO|E&snBwp4Cf&O$Owda30J8|dPBmy1&Ne(8#0;j+5NDI}HUUMc%0j@7I8CMz&f zFN;u=8NbaY{t!8PiR?1@&gJ{E*fc1T=eU61Ur4rd{)7DZ=GWTkysKu3QWl;oFA+FS z%CQGm=i@PfP|?k5vhWy1K^rn}fsMYiUKxE*a-lWxmRrzX5ZM zi5n{(k}^A622opCgr)OB9y_IGHlAtQgyw-RHi#*JWG6b33yYwU27LYCxAEVA11VTI zL+q7?wE^JnO6{pNd;&lwniLq-$Gzalw00TatQvpL%Q6ZzB(l z7)&XcT;tb4}(;~CZd zAMr9?Wdt1Vdp+F&xGQU2-^9;%L>}-FUfUV+Vf!Gg_8GRx*5BRVCBFH}zo#@k1wiBR z=xqAR+DIrBd7g}+DUEpTms@1OL!zD{$!)HS$u z9rYCj<#XP%5yVAU!b4J5E?qyFcXRV|t<-k?;rEL_n0I+rVwj@qF$@)y?PV73PPw|T zld)*EPWL#a>7O3&NV&SzTdqEP`X41LX(i-UIg4JFQGG_HE+;4#2|U5ayeD!az(Js| zMeXzT==d;&A`#A|L)zx1@B(C#GyqnP*tKnzHg7v+3u`Bw0(;R&>^)F3Q#YTYqyJxU!_bSz@u?Wn8wJU3gheiPVqwlRJqJ$R~JUH3pf3ny`K! z$rMau)QxhPyGc`p1vC)5cFwqBU5iAPLLjV5$6Wi7|J|CIF!q1nJ2{yjZH2Lo6DzPY zt*{+urYxCm%Teeug$87pqRu6na|48Zf=plG*2=b8t=i57~f@gzsc_v^HRUgyY-MRyEp1+j*5^+YkUc%E?=H#jo| z*|$2`*22lp6?Tp)PA0l*m&~+F)tGJX2G`8z+|a_U=wLE$v^C4B6~ZO#-M5-;i z;X0?tw#8h}jyCQFXV>#7L*(3QPByD$MbDk}jzp2+q+Un)KU;dtfWj5Q1hbCyJ|K{qnRl0IH3}c zzS@nB-W(hY2kzs{$dcVhzKp(}YY4cblr`Aj4w=ydf3CqVAm}q+rwIJ3~tmuVLSE6C4b*YVf&F8URdkH;5|dv{jXuZ$NZ z$)bYiOBq-9MToMx)!VMVcv&5$*NjiSib=V;)!VLOy1e1txPI{mz%58eKKFt+7=pa2 z>8xzFow9U6+!}YkjaDi0)#I+`qf@?O3*0_AP2Yo=`N^zxy*~nZ2iUg$=(t+C^c$=H z4Kb;;tRK5_%6QUP1}Rr}R#x{VADEAe<;Pjg;Fg9>pkk@_iGcCbmdKfMEb~u@0JUr> zu*GSt3Px@U6#47vZ6n_7a#~K`bX6u`ZWb>gXTI7*CrttzN4;T5+MaXCYP=old;jiU z`u5+xlIkzDde*moYeuq=3Hgfr$0l}>^BR~AbhihJM*%UEh99Hc(uDCCI9EEkdaQj1 zV$&1Zb!}VVGQ{AoZwy1{trcb;vhK}UnbvJ)JLfuAG6tIPTgkaBf6K*f@(ug{sCJzb)Rcre1yNnn~jzok96tFmjy)Xa&-W zDDXm?AxCpgsa+ayL=A~q`|kl2;hd7-5qCka|ysH zhiIavQyk2368n1gVt-HityT)06-ZAUpM#&G0n8OM>Q&9zJodrgKOW~_Ia_a#!wFc! z)saVU%QV*LGb){r7ZVd?q3~k!gb_V=KGVvFLrHHq%ge}50gplHHWB-{8;dUH@0AHr z)_^xRc9MD>WlXasOOXC;3DT85M(TOlcArQMNP=%H>~tIpOoqq3>ziyR=rTDc)%pF{ zozCUz+~xMlth{+HVHtMgzWGk2j{42C5yr(EJjk5rklxW3HufTmzPRvOoL)OmupXfh z`GIKLL94y4*Lci5P_&=@HfkX8TXYOXtUuu7r3<(pLqbXX#p zVD7lXU&}soMKjCm@Q=rTP-G;9DY|JS*R~~r10c$HnTDc0(&hH~pR|mx*KJ6}=RbGB z@JUYhZuma#S^s@+oo2b0xh0)N@i|-#bs5`fQI;GQ0!3WR(klXS;;?a1M`AbZvu_!qyp{AGL|qNkO~9M*QxT z6UA>|k(uC>P{&{|KJ(gLw7zSnXGm&!_RL9_=YPsZid|g=Yidr9) zit^7&U@qkYCdFZ-+gxz{w*6q95}{-CUqATI&Vx*LRm9p&AxeAT59+C(S%s0n+0wcleYol0c9R5Yq<}eSgouw@ zO(M@dWR|lxmx6KdBf0-O~UoFo?0t+(E~Qhr@2KQs9L8tH;Ozo8t@H1?&k znBOj>7IOLZvkG4c>%{t#6QFy&>D6Rg6bWO_=m?5IGV9+m8mYEwk_;8s$ zLyLCx+1RfINIQp7@OQeIddMY~ff)(bRm8#B+5lX}dh%clbNwRSW;n?v5{voI&bzH3 za8@*Cu3*qGj)zo;>pPt85mt3Y-;9nNWgvo=_>Ce!V+!@v=JYE!n|o-V&E2 z73n$0CLPl(F(z1d=spXSW76xl5sSyWpte2F>e<10z8GxmRxnM4c+!&Z31W#<#M)(i z_xyqW@pbk1^rdxK-J|l50^eo{2k7{j{hr%ar|h$;W&%MoEPX zfV?CHtx^*nlb>brF=a{r)8p-VW3X>kQdYCFp7YRc&|b|r>*4FxNzmU^_+DszyUe``Q|*OoP6fA-@}xuOmJ3<^j`IDDN5ss=peL5rR_mlW%RrkMG#1tzMA^LcSd*Wm!}L z92PNF@r+^JsD=@pMV2X}k&@j;ta5AICl4{^B?Q-r>-6s2n`~{;6a(Smsr9t1^aZn0hi=iZQgrZlN9XBFDty%&G;>@C>avxm$)&Ja*30_*~wA*EIZ zBjRg-8LM2x;k2M~o4ZJX)s)!)vYIPX;$2xb{;oLg8hqm9n~;Z;;Jir99+1~;fabA= ztb%{=Tx*ie{8lHGD0lD0^~nlrdC0x&Jzt)PBJ~1^yZ-JK?BCUsl2%4)3MQ%CBhII{ znJOG;0M1l&Q(VlMWmS*(n9*O^fiJUtg5(dIj;AvY`Lp zy-m39SDgeG8;7^n^<}xl2SzDdiM1QfhRdbKWd74bn{$+c-JPNmIxyVBY49>1i2TKN|l?J*Z>-ZzX-f?|A2=d|B+OpZ*|&$8JR)0ot^?2Y3AK8mxc0B~!-&Jjj9hKBFQ4M9Ks~ zUSD|@{wBq1IzjA5c^e3lc$@0m_LwCu~%^5uQ81g8B-&xs) z|94MQ*gU|Qf&6~0+u56{ZrE7&gKB@rjG-@Vi$|N|yM{pk$h@?5|aP=Wsl>v$qwWdG!w3+1p|}DrKGe?#Vz~ z+b}RoIDI_5Patp&Szs?LF77+ib|U9!Vg+ZHPr@yWuNP<3H6RZi6gZp996FK@OTCff zvsuTK%UfB}3asBMR9z;Lc=IqW?Lgyv<$To zF_V(n=e5af_qR1jLS7KapR|^F4W{^KUm^KEvHq0Ar9HJOZ@f7#QyWF_4rupUij>P+ zy+|T!UhuI>3XoO2d6>6*HA3^)s;q;u&s1NjKFiEn`LS|&e`}+YNm_t=F9`)q#-voT zX{Sb!NSP@vZW_uv?n=#)wQ1rmVzw`Dd|JqO`!wA6r%Us>v=!Z+FCI9OM^L%EZ~T{? z>YIG*(#Y~a&B!vS34xp3$FVI6bNwTIe|~)zWcQrldQZB)$OEE(wj!~X|K?*;arWZ8 z@%ct*aBj>xIGjgN(bu;=DqY@>kyq0Uc4}tRwy}szXzK#cx=*KNWC$6b3E;Q&;SpFZ zt}D1$Tv&W`)_M5Nc^Bn#X)79aLRc0ZQh-)8oJOVStzu0VU^O>l7^b!~lGdJB(;L1| zkH7f~yHJ<6R3q1QvJXL`n6Ty4w+P%eA``r0*I`g6za|6cFt99wbL@9jX_a(me+n1O zy$HilK}0CS`yEaRiQ5XBDXIrIWyGtZQ*5I@v0@^A@9Ml(vm&MVU0(o? z4Qp&DYx;9*zenrbR4m&NZQBaA!$!)ZUKJEu-^fFG^%r>6h1mISVcMu{2F;XK^KDDs zH=Nb1jI!Gb;ju#KkOQ6&)&4%Y(qAJTRi*%&{GpF_WByUxXV-&kzJPv%4eTRx;+Y* zuavRos}{T`wS*_5{WAXJ&BvtMyV*BQ-<@@1 z`>tO+P!vXKvz$-k)vU zvgc23UP!7=J!zi18Hf8P@ekscz>_0Qy31;7EeCVQ&m$c zG%z;|2h56A;xO{qjwS=tziLOe8=C!gZf)URRc=0|g%yf`#CM>}$hPSnX$>c>36VG0 z&t6<5fqBwMz&vV&IkV$qfH;NIboJOLI--U z4GrikihMe8aungJVAfONlFdw?+4Ikmfc$&!9?@b}v=WDg$5ucaXbr=ab3onG5-NaR zT@y|-2`&J`PeCXx-xMhzBSFp8V=J?lkl(dM70P19N9T+P%!kya9n)b4XhlXK+=^jb zxR#VP{m6#i%=alDDN@N_moKTrdGpH(0cQ1pZa)+W0i29Atzuve!L0HAZ>(*4 zHTmr;fOTv02um;r8OUp<4BND5J30TPDW}kxGtLng&b@dfU{AfjT#}#o0E!B z-z6>TqnS*m;>w>rsV0dt4>N7b(qRz-g@BHtZ5!J03klR}de;73-ODE@>gP6e6nTgNLzgV0(@i-JfcS85sA+?%09T9-G zWa5VEVKt0YR$0|+b`Ic|Tl*5QKHRI4O|LD+`SZ&Q1!YTjqJVdL9w?1Qu~D>k|EqXh zTGp@2@4el7z^7KRVrG~-uNPZif|mfCVGUQpy27bSy0GWh9fz}|8@oVIR@4a1&}fwh{)tX4p~R)X><-f^wo!+z`G5(1;;F$L1fvR=QcNyVz!5fO+y z7+0gYN(9<)$-A}y5PN_mkJXllxr-)X`MYM|ysPJoWG!22#3*CUqovXCm;&pcuj#}u zR(0XI^-Q@*dMKPj&C|PCp|HYW+7>M8I4{PDbIWnb(i)sC4Gi@ukZzNouZ$HQdu;#f z2~aE0-r3VUk~XI)!{i7u7bv5Q{GK3P*emK!6lX|4zG%uxBU#IqRzl1Dl{n0FL;>2; zXc*j*0_janL&^7E3ErEU4%|(tEaVvykQERwsF&X}$`XJc1+BypdO(Us%ixNXHNCZM zOJZ3!wrx&+cMWz?R-}i`uQoq@wzoa5R{Cm?fUH*jYN%U~{4Nlb6(wE<97Z7!(}D1q z0_n%)N3Bez!24iUC{q@)vW(T|w8>=&Fpu(0Tq|*iEx_TZkerd2RQC6}mzwaVw6M2t zY)@R_-5sjWynCBX3IzOgpD=1@*m26tDlAzx8S@s`Vb0=O6lf`1YJ?t>cj5?;>8~51 z$7BNvppNbwUf>vYEIn)T@tLfB;N|ay9QL^6gk&; zby*FhWt?z@O6*b#iYP0&S_1JXz?f4bbhhyk1Ll|xhR4*RCykP~?Dtj^yH?wFK@|Ir z>N?3|7L+GS9y^G4SKkRe7knj-0vRECBMy+qnxqSSzXa~?&H*$_3%e`nGm`tYwOv_L zn#7P5lTDdfDYr{7Pg=>9wPl4`$T6v$kK2!=(Bx#sq?)xdVmK;`6lkkuMBCMO(?Iee zv%kGZ^VppFl4ReUDWwSxogl5`Ig-yt3C5PxIJ9H35l4Xz1gJTwg-_J9E%mM3;hlq8 z;O|fiqDU~VEv-OpvHYlS>9$r@@$ogYFsouB4vHfVqoFM{&SRq?H6|4%t-w*F zqiR9NL|PkN0j<5Sz|kY6WvV#oQL|(UCGr-}wa7Ck_z2NT`FR{i(ONEq$Xh&$$3{#j zJB(y4nfs0b9#j3LK4XE$?w6lCj{zRL5xT#|d8_~;?dekebsdf_t;87Ou`vbEoETVJ zCU3yuCFLqp05j&9IUgCYRt$b24!>ZqO3Z4Eae ( + + + + + + +); diff --git a/src/assets/svg/QRCodeIcon.tsx b/src/assets/svg/QRCodeIcon.tsx new file mode 100644 index 000000000..eba364d75 --- /dev/null +++ b/src/assets/svg/QRCodeIcon.tsx @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import * as React from 'react'; +import Svg, {Path, SvgProps} from 'react-native-svg'; +import {rem} from 'rn-units'; + +export const QRCodeIcon = ({ + color = COLORS.primaryDark, + ...props +}: SvgProps) => ( + + + + + +); diff --git a/src/assets/svg/ShareIcon.android.tsx b/src/assets/svg/ShareIcon.android.tsx new file mode 100644 index 000000000..7ac211a11 --- /dev/null +++ b/src/assets/svg/ShareIcon.android.tsx @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import * as React from 'react'; +import Svg, {Path, SvgProps} from 'react-native-svg'; +import {rem} from 'rn-units'; + +export const ShareIcon = ({color = COLORS.primaryDark, ...props}: SvgProps) => ( + + + +); diff --git a/src/assets/svg/ShareIcon.ios.tsx b/src/assets/svg/ShareIcon.ios.tsx new file mode 100644 index 000000000..1c0b66986 --- /dev/null +++ b/src/assets/svg/ShareIcon.ios.tsx @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import * as React from 'react'; +import Svg, {Path, SvgProps} from 'react-native-svg'; +import {rem} from 'rn-units'; + +export const ShareIcon = ({color = COLORS.primaryDark, ...props}: SvgProps) => ( + + + +); diff --git a/src/components/BackButton/index.tsx b/src/components/Buttons/BackButton/index.tsx similarity index 100% rename from src/components/BackButton/index.tsx rename to src/components/Buttons/BackButton/index.tsx diff --git a/src/components/InviteButton/index.tsx b/src/components/Buttons/InviteButton/index.tsx similarity index 100% rename from src/components/InviteButton/index.tsx rename to src/components/Buttons/InviteButton/index.tsx diff --git a/src/components/PrimaryButton/index.tsx b/src/components/Buttons/PrimaryButton/index.tsx similarity index 100% rename from src/components/PrimaryButton/index.tsx rename to src/components/Buttons/PrimaryButton/index.tsx diff --git a/src/components/ResendButton/index.tsx b/src/components/Buttons/ResendButton/index.tsx similarity index 100% rename from src/components/ResendButton/index.tsx rename to src/components/Buttons/ResendButton/index.tsx diff --git a/src/components/Forms/ConfirmPhoneNumberForm/index.tsx b/src/components/Forms/ConfirmPhoneNumberForm/index.tsx index a7265e367..9c5917f1b 100644 --- a/src/components/Forms/ConfirmPhoneNumberForm/index.tsx +++ b/src/components/Forms/ConfirmPhoneNumberForm/index.tsx @@ -1,10 +1,10 @@ // SPDX-License-Identifier: ice License 1.0 +import {ResendButton} from '@components/Buttons/ResendButton'; import {ConfirmCode} from '@components/Forms/components/ConfirmCode'; import {ConfirmCodeBack} from '@components/Forms/components/ConfirmCode/components/ConfirmCodeBack'; import {useConfirmPhoneNumber} from '@components/Forms/ConfirmPhoneNumberForm/hooks/useConfirmPhoneNumber'; import {CodeInput} from '@components/Inputs/CodeInput'; -import {ResendButton} from '@components/ResendButton'; import {COLORS} from '@constants/colors'; import {useNavigation} from '@react-navigation/native'; import {t} from '@translations/i18n'; diff --git a/src/components/Forms/ModifyEmailForm/index.tsx b/src/components/Forms/ModifyEmailForm/index.tsx index ebbb7a9a3..87fdf2cb4 100644 --- a/src/components/Forms/ModifyEmailForm/index.tsx +++ b/src/components/Forms/ModifyEmailForm/index.tsx @@ -1,10 +1,10 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {UpdateAccountField} from '@components/Forms/components/UpdateAccountField'; import {Note} from '@components/Forms/ModifyEmailForm/components/Note'; import {useModifyEmail} from '@components/Forms/ModifyEmailForm/hooks/useModifyEmail'; import {EmailInput} from '@components/Inputs/EmailInput'; -import {PrimaryButton} from '@components/PrimaryButton'; import {t} from '@translations/i18n'; import React from 'react'; diff --git a/src/components/Forms/ModifyPhoneNumberForm/index.tsx b/src/components/Forms/ModifyPhoneNumberForm/index.tsx index 273de29b3..92e73eec9 100644 --- a/src/components/Forms/ModifyPhoneNumberForm/index.tsx +++ b/src/components/Forms/ModifyPhoneNumberForm/index.tsx @@ -1,9 +1,9 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {UpdateAccountField} from '@components/Forms/components/UpdateAccountField'; import {useModifyPhoneNumber} from '@components/Forms/ModifyPhoneNumberForm/hooks/useModifyPhoneNumber'; import {PhoneNumberInput} from '@components/Inputs/PhoneNumberInput'; -import {PrimaryButton} from '@components/PrimaryButton'; import {Country} from '@constants/countries'; import {useResendCountdown} from '@hooks/useResendCountdown'; import {t} from '@translations/i18n'; diff --git a/src/components/Inputs/CommonInput/index.tsx b/src/components/Inputs/CommonInput/index.tsx index 91c238543..3dbcb78ff 100644 --- a/src/components/Inputs/CommonInput/index.tsx +++ b/src/components/Inputs/CommonInput/index.tsx @@ -124,7 +124,6 @@ export const CommonInput = ({ )} - {postfix} {loading && } {(!!errorText || validated) && !loading && ( )} + {postfix} ); diff --git a/src/navigation/Main.tsx b/src/navigation/Main.tsx index 8fa3cc64e..a12889166 100644 --- a/src/navigation/Main.tsx +++ b/src/navigation/Main.tsx @@ -31,6 +31,7 @@ import {UserGrowthGraph} from '@screens/HomeFlow/UserGrowthGraph'; import {ImageView} from '@screens/ImageView'; import {InviteFriend} from '@screens/InviteFlow/InviteFriend'; import {InviteShare} from '@screens/InviteFlow/InviteShare'; +import {QRCodeShare} from '@screens/InviteFlow/QRCodeShare'; import {ActionSheet} from '@screens/Modals/ActionSheet'; import {ContextualMenu} from '@screens/Modals/ContextualMenu'; import { @@ -114,6 +115,7 @@ export type MainStackParamList = { }; InviteFriend: {contact: Contact}; InviteShare: undefined; + QRCodeShare: undefined; ContextualMenu: { coords: Coordinates; buttons: ContextualMenuButton[]; @@ -351,6 +353,7 @@ export function MainNavigator() { options={modalOptions} /> + (); @@ -112,6 +117,11 @@ export function WelcomeNavigator() { options={modalOptions} component={PopUp} /> + ); } diff --git a/src/components/AnimatedSplash/index.tsx b/src/navigation/components/AnimatedSplash/index.tsx similarity index 100% rename from src/components/AnimatedSplash/index.tsx rename to src/navigation/components/AnimatedSplash/index.tsx diff --git a/src/navigation/components/Header/components/QRCodeShareButton.tsx b/src/navigation/components/Header/components/QRCodeShareButton.tsx new file mode 100644 index 000000000..b55faa59d --- /dev/null +++ b/src/navigation/components/Header/components/QRCodeShareButton.tsx @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Touchable} from '@components/Touchable'; +import {COLORS} from '@constants/colors'; +import {SMALL_BUTTON_HIT_SLOP} from '@constants/styles'; +import {MainNavigationParams} from '@navigation/Main'; +import {useNavigation} from '@react-navigation/native'; +import {NativeStackNavigationProp} from '@react-navigation/native-stack'; +import {QRCodeIcon} from '@svg/QRCodeIcon'; +import React from 'react'; +import {StyleProp, View, ViewStyle} from 'react-native'; + +type Props = { + containerStyle?: StyleProp; + color?: string; +}; + +export const QRCodeShareButton = ({ + containerStyle, + color = COLORS.primaryDark, +}: Props = {}) => { + const navigation = + useNavigation>(); + + return ( + + navigation.navigate('QRCodeShare')} + hitSlop={SMALL_BUTTON_HIT_SLOP}> + + + + ); +}; diff --git a/src/components/InitializationError/index.tsx b/src/navigation/components/InitializationError/index.tsx similarity index 96% rename from src/components/InitializationError/index.tsx rename to src/navigation/components/InitializationError/index.tsx index fd89a3e4c..9a89747c4 100644 --- a/src/components/InitializationError/index.tsx +++ b/src/navigation/components/InitializationError/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton} from '@components/PrimaryButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {COLORS} from '@constants/colors'; import {Images} from '@images'; import {AppCommonActions} from '@store/modules/AppCommon/actions'; diff --git a/src/navigation/components/MainTabBar/components/MiningTooltip/components/PreStakingCall.tsx b/src/navigation/components/MainTabBar/components/MiningTooltip/components/PreStakingCall.tsx index bdcea133e..67d1c202a 100644 --- a/src/navigation/components/MainTabBar/components/MiningTooltip/components/PreStakingCall.tsx +++ b/src/navigation/components/MainTabBar/components/MiningTooltip/components/PreStakingCall.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton} from '@components/PrimaryButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {COLORS} from '@constants/colors'; import { STAKING_RATE_PERCENTAGES_MAX, diff --git a/src/screens/AuthFlow/ConfirmEmailLink/index.tsx b/src/screens/AuthFlow/ConfirmEmailLink/index.tsx index 5da5e3efa..7eedd33ce 100644 --- a/src/screens/AuthFlow/ConfirmEmailLink/index.tsx +++ b/src/screens/AuthFlow/ConfirmEmailLink/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {BackButton} from '@components/BackButton'; +import {BackButton} from '@components/Buttons/BackButton'; import {FullScreenLoading} from '@components/FullScreenLoading'; import {LottieView} from '@components/LottieView'; import {PrivacyTerms} from '@components/PrivacyTerms'; diff --git a/src/screens/AuthFlow/ConfirmPhone/index.tsx b/src/screens/AuthFlow/ConfirmPhone/index.tsx index 8dda8ce32..66742457f 100644 --- a/src/screens/AuthFlow/ConfirmPhone/index.tsx +++ b/src/screens/AuthFlow/ConfirmPhone/index.tsx @@ -1,11 +1,11 @@ // SPDX-License-Identifier: ice License 1.0 -import {BackButton} from '@components/BackButton'; +import {BackButton} from '@components/Buttons/BackButton'; +import {ResendButton} from '@components/Buttons/ResendButton'; import {CodeInput} from '@components/Inputs/CodeInput'; import {KeyboardAvoider} from '@components/KeyboardAvoider'; import {LottieView} from '@components/LottieView'; import {PrivacyTerms} from '@components/PrivacyTerms'; -import {ResendButton} from '@components/ResendButton'; import {useScrollEndOnKeyboardShown} from '@hooks/useScrollEndOnKeyboardShown'; import {LottieAnimations} from '@lottie'; import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; diff --git a/src/screens/AuthFlow/InvalidLink/index.tsx b/src/screens/AuthFlow/InvalidLink/index.tsx index 771e0868b..8a9b0501e 100644 --- a/src/screens/AuthFlow/InvalidLink/index.tsx +++ b/src/screens/AuthFlow/InvalidLink/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 -import {BackButton} from '@components/BackButton'; -import {PrimaryButton} from '@components/PrimaryButton'; +import {BackButton} from '@components/Buttons/BackButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; import {Header} from '@screens/AuthFlow/InvalidLink/components/Header'; import {useBackHandler} from '@screens/AuthFlow/InvalidLink/hooks/useBackHandler'; diff --git a/src/screens/AuthFlow/ResetPasswordLink/index.tsx b/src/screens/AuthFlow/ResetPasswordLink/index.tsx index a0dc3a219..b133ececb 100644 --- a/src/screens/AuthFlow/ResetPasswordLink/index.tsx +++ b/src/screens/AuthFlow/ResetPasswordLink/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {BackButton} from '@components/BackButton'; +import {BackButton} from '@components/Buttons/BackButton'; import {PrivacyTerms} from '@components/PrivacyTerms'; import {Touchable} from '@components/Touchable'; import {COLORS} from '@constants/colors'; diff --git a/src/screens/AuthFlow/SignIn/components/Header/index.tsx b/src/screens/AuthFlow/SignIn/components/Header/index.tsx index 0c4002ff3..9d0074a65 100644 --- a/src/screens/AuthFlow/SignIn/components/Header/index.tsx +++ b/src/screens/AuthFlow/SignIn/components/Header/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {BackButton} from '@components/BackButton'; +import {BackButton} from '@components/Buttons/BackButton'; import {COLORS} from '@constants/colors'; import {windowWidth} from '@constants/styles'; import {useTopOffsetStyle} from '@hooks/useTopOffsetStyle'; diff --git a/src/screens/AuthFlow/SignIn/components/SubmitButton/index.tsx b/src/screens/AuthFlow/SignIn/components/SubmitButton/index.tsx index fad39e2b6..24fab8338 100644 --- a/src/screens/AuthFlow/SignIn/components/SubmitButton/index.tsx +++ b/src/screens/AuthFlow/SignIn/components/SubmitButton/index.tsx @@ -1,6 +1,9 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton, PrimaryButtonProps} from '@components/PrimaryButton'; +import { + PrimaryButton, + PrimaryButtonProps, +} from '@components/Buttons/PrimaryButton'; import React from 'react'; import {StyleSheet} from 'react-native'; import {rem} from 'rn-units'; diff --git a/src/screens/HomeFlow/Home/components/Overview/hooks/useInviteFriendsWalkthrough.tsx b/src/screens/HomeFlow/Home/components/Overview/hooks/useInviteFriendsWalkthrough.tsx index d28baf2dd..811ecbb65 100644 --- a/src/screens/HomeFlow/Home/components/Overview/hooks/useInviteFriendsWalkthrough.tsx +++ b/src/screens/HomeFlow/Home/components/Overview/hooks/useInviteFriendsWalkthrough.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {InviteButton} from '@components/InviteButton'; +import {InviteButton} from '@components/Buttons/InviteButton'; import {SCREEN_SIDE_OFFSET, windowWidth} from '@constants/styles'; import {WalkthroughElementContainer} from '@screens/Walkthrough/components/WalkthroughElementContainer'; import {useSetWalkthroughElementData} from '@store/modules/Walkthrough/hooks/useSetWalkthroughElementData'; diff --git a/src/screens/HomeFlow/Home/components/Overview/index.tsx b/src/screens/HomeFlow/Home/components/Overview/index.tsx index 9040d63c0..ec128e1a4 100644 --- a/src/screens/HomeFlow/Home/components/Overview/index.tsx +++ b/src/screens/HomeFlow/Home/components/Overview/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {InviteButton} from '@components/Buttons/InviteButton'; import {FlipCard, FlipCardMethods} from '@components/FlipCard'; -import {InviteButton} from '@components/InviteButton'; import {SectionHeader} from '@components/SectionHeader'; import {COLORS} from '@constants/colors'; import {SCREEN_SIDE_OFFSET, windowWidth} from '@constants/styles'; diff --git a/src/screens/InviteFlow/InviteFriend/index.tsx b/src/screens/InviteFlow/InviteFriend/index.tsx index c675b8d2e..95b29c8af 100644 --- a/src/screens/InviteFlow/InviteFriend/index.tsx +++ b/src/screens/InviteFlow/InviteFriend/index.tsx @@ -1,8 +1,8 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {IceLabel} from '@components/Labels/IceLabel'; import {LinesBackground} from '@components/LinesBackground'; -import {PrimaryButton} from '@components/PrimaryButton'; import {COLORS} from '@constants/colors'; import {commonStyles, smallHeightDevice, windowWidth} from '@constants/styles'; import {useSafeAreaInsets} from '@hooks/useSafeAreaInsets'; diff --git a/src/screens/InviteFlow/InviteShare/assets/images/instagramIcon.png b/src/screens/InviteFlow/InviteShare/assets/images/instagramIcon.png deleted file mode 100644 index 945592fc86fccf2b45175aca4ec658c9537a2acc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4832 zcmV<65+Ch}P)qwjD~7KRR`aGp?=E);f-+qwQEb6Ef4G zjMNe6bZ`LKgnm%|(J-Uq2aYZ>qX;T13W^`(MMfdyYY9mkzP36CcN>g2mfIYoW}B!0B^f=atjY-GKqzFBuUpg zV6~7R0|kg~89$c!SW0#*?!i7tELJr*zE3tf)I02lTuWwkeiJ4UGXYv#nvP_P`* z8{#+Vd(DS3b~i2zY1j7Y9W$p5@D`4!v9SaA16zslxIH(2*G zlhR0rty`xTgIokq+%nJQhZBS2Rjp>*&f|_jCXYV_>_DK#WW-`vE2(dpHNZ_^w!lS< zS_jm#P6bJ3=7>$FE3t4wjAKGT*eS^3uI-|yFXWvm=)GsltrtzwShnNR-3?jS5&1x|zY{M_-*Jiol zV&31$XLp=p!O6GWI>Gl$Ht66qrY!!NLNWw}aDaL-NLBN|*wWZE+lX>s`^17i8FF_v z6JcKoACarTP7N|o{&nhAg`@lYsc6@#65e~EAqg={1q09J&m*}_n38d&@Eb^k;fyMJ$Wvv zIJ8@h(0wxVm2x2_bW&39By7~TWje_&<&nxxnz(HGpZBN*8Nde`2$vM{=vk4i%D>U# zFsvk?Av6%HyMhCEkWD|U2@M1a0#Z}TtYoz_s9*DR5rx24HWg_NM9+T>8 z9*1&G2Je-JRwVLVwkVQoHJ#lY$~HhHsSw7P~EGr6DNEsQY#7ilh!uiDwA`sR~H^nTx8|n-x*q+TGIT zvuK{lfyPRbSuJJ~ zl9ZL@M(X5_Ml5HpYeIqrsCi@vq!E^pwz+RgTiOP?)dr$d5KSSP&fRio;L&2SF>jYx zHJ23kZOn>e7hV8o{?TQ)eDnFxp0&12@{26x{P5|+F#GTmaOk#sVfc$9=6CGElslIS zgO{lgmICwYV##}IM#UB!77LXagm6W{WvFMvF5YiMch`T#c*$>d)YnF70d9 zz^i2a(>KE5+wXd1qYt?ccH3ewL zE~meRvVz_Rmx4cfEU z==nA8xl*?bQY#MSN&%V;NjwX&*A&3s3o6L*woNkNp$(ovIXKT?L|^P!s!0G^byU_x)=Ksn(VfBa@x`~K~a&KOgW zv)}nC%zk^H>KeIkqUSNn-A-Io;~cGZSKH9|B3Zpb9Ez@ThxTL#F# z^?ajSIVZn)5?B2GW<2L}*Q*ux zfAmx3d1qer2EAXCFu%{9D{K~(hGm~-#fmeI35%-58XPjH5`W^dVm(e)H5To76Rw#f zt)OMUvq_)Y9XJTHQ(sd(BP+(yOJ7|6+nb=>_*xj{RgMjxJxs^G^mP)v@Gz_0PtnNB?$$4M}Flm~GN;=t-8nKaw8kAzB1SYwg3dvBLI@i3RvSuq% zfowrw_e?VRLj`G?*lE@7Std5?*Xzp`_6^t?)~vsJsG#l2z3oR?JybMM+ zUw}`)_uuH?4ZA_IVoMFEHxdyp?|BC{XRTAc zT>GJS;lW*>lr#&xC|LAd1*7U6UA3%vdhWuCjq#1gowtQ7H&%eSKtdc$I1Ebm1@wHZ z?8giIz@ZX?tVR;DpO-kE5(~BrY{ix<9NYmo@S%^w++&Xcoj9h%GyCATaQ_E)Qpa*4 z%Zj&L45JsFua%2EzxPOVLNTJzeReg=^^yaR>>ix9ebG`>Vz6mD_EjN~VOd9%HI-R8 zxMh_Wbjp5U1JT^93#{h;Tg8L=n&!k!C*pOyPZ&;1R0Udo1SHD-Bi3huDJ2T28z0iyR|wXHX# zvS$vFrz**?wORqBuFBSIBt2U&$zYJ+mA7(-`H9uA*;^0Qgg%%Y&)214`tOdNuo3Ct zv`eI}CB#%0@_t9|N1#64u&+2hEF|Fj*X0uQwX{-qFp0q8oTt8@_^y92dz+yzDB@? z5O{Ncjk$Mc1u|wb$JMV{iODFkmZi+3Q~i z>;L0AP7+K;PJH!#SYWm-mRPiSY6eCswI8Axj(_kV{nxWd{30Sl9CP?efVvrkP)sBCHRdDJe8hP~YPlGp!tzzw4!HLI; z15dd90|%AnPIXu7syCj6i%c|KR-$Pw!A{9KY3SRCn@EmRSkz;xSWw-m#u&{WgPD*0 z3(bA~D+DjFoP6k8aNxrqfqdXuZ-rZlkyeh?=Q<#l1FKOSP`D-ZuF-S$QA8J(iD43A z;Z#jrGrF&}TjzP6Isio;mC$sEqw(-Fkk*_HBNuGe$zayf;#9_(kL<_iZvOLHYdrL!U41bjIIZ3!|4^ z8FgD^7*r&pw76x^rM83k{4{#uCRp`1?<~)I?tk}M$>J_(s~bz7Y0$01WgkT19T-{D z!4F?9xu*7D%7+5?)7sCmSf)s@DXeLg`SQ2F8%EzgQ3jR|?T7B?KZSh!c=>`!&Ic6j z2Jfvz^1f`->)CSa%QK$;|9j}U|J%z1!xWm6iF!_9ec#H|#BcQLBoEXrKf7UU?ZSZ5 zvvE{~p{N$IGN`9Nh|bLBdnKFU={xzQNyWe*txdr0D(fp)Gi+AAMgI{24 zPC$F!#Y#LcXXy?+3-gcu08UKZ4|9)jPe;Bd2mSlUByTjCJcMkhxHoA1Lxf@>D_du@ z;MJ^!N*lv4QuGC=d`pP05!!`T<_pfX_A(uL8fNdhp3}`BCvzq0>^lSG#*fM5Hd5co zXH_N#**3)uOSd@M^!}mWnj!uTA7gOQHpj}Krjs)HGyGAen<{BnZR|v|sA^zCWalgw z#hSudidBR@m-@|Gm9@sRkAyjj2|sRGe9^V)g7!I}kcK&_ThNKgau2MUSSSP31~g!R z!|(cF5f?G27qkvi>DO~bD>6F++4x{RRinyw1rSERVKuUp z&6Dp6&Z)sO9}L#eB#TE#_i>x0+uN@iK-g4EmQIsu$y!XnDJ*AtX<3egQ|nU%zX2!} zcL1UoG)9~txR!)&qKx~UlxTc|rIL7gaX^NTfvwVEe zjMBAzOp5^Gj={_jXglu?!14+5W{-XvXeG(crysFV~K%m!ZIVN6(c!C5tHJ^YREWPd&fB}*-vrG6rHDRo=Y1ia9Dy{1ZnQ-0KPmZZn~8tWHJLf%>J$NNvR{JeYP zmp?i6V&i{FfEDPu6YMx2;6Yr(4;O7y?E$L-^e;n2hkBYuHqZupT2=t{!R7+GP6By_ z(VHasOei`xl{?sd&KEwl=XAz>+5lsj{rA_6v(Ri~sl0*#jq{AIX60GUfL5CrOA`it z(0!2jA{Is)yjn`EsMimmCI?fT_D;{GbkD}Uy9Y04yuSpnSb~bGijlSe00005iKvEg1DpmEryZfHAzi;nz-~av$kRTT- z|9f{h_nbX^``i1Rd!NeZaJy#LHQP@dmK{aPbEFJARrFjH+ddxJq4fkaX@6z>t6IO0 z`>pLMXhYdpJy-d+o;$RoYG&#?a9(Z9l4~PEm!B>pn`nweRQg99$ml36O6yH9-rg+L6zDaY5nnWHfPsTPupKi_FeM+|8%W93fm*9z^b^l z`^)8HtFIgfzg?iT0;5gE4HM4_Z!##V3S!7}w1+{QTlj4l95M-|6QvAIs71UzXi!Q~ zqG`9e;wn_ugJzv_y8av5HY!+Qch(ICnzgt|y;xVr@B4EAUsIam}tl^_o#pJNlSadtU@( zpq*(G=qwS3Y)Vj|;7Rqjc~a{3cu}_93QaI}*fZQB1Ck-b=0P zn}2RicWo}1T9H*7Z1)S_|AW`bXR&?83T$3?Z1$Q_Qm^bij$T%`(oEU{heA=ElFAZ~ znh*|$*7S%W;j_lSA|wtnjc3`Wd+vgQ7U6R|AzDr`{WcXV0;<6IZ_I!0tox8El`C0$=}(Yj%u6ykQK{J6vHVBq|yfk9{3uB%DsX z5a*Z9TZ-rcxe%Fpch~X3A_hu-Y$0wEBm*YlVZBFB1f$M0O(sfbR0Et78lw?EYYLg% z@A1+ogp85n2v*DHO&5LRXTVq=wgM|;j?#Xs)>wyFl@Q5vfOMZ8Vgaj*aH^4;k;ITG zcJVJ1Ege*5tP5`dTvztj6i%fUkRm0tCE?LY4$!gHUO;hZA^NpgH{R30V~|!v_=8

y(9(jn{LssA$zUJE3j6%Gk1{3WP>K5mk)Epw0D|hOB zBra2Lv>*&rlq(Ik+MqJ*7)o>r7Mxl?D5@wzl8^X?Py}zORhINho<50vOdVViL3m_= z(DdGl;eg@r?joVh3Y-0vwc(B;8|=Jjx#HrRFTYYA!uF69c=d(XTt41<4|Axb{}vG1 z6f4qf%LQz)FBDq845{3niE4P;0{eu7!cGB~LSAEi%HXo9_u$|n$_xypR0yZ5D{!bZn{)LG7UihG*G2H*KKDmw)^=v|L}u);)5#i>Steb zsm|@K3vk&%AR8G(Wzn;yF)=<%La53@PN=>2A)@r~i+IFXnaURFQi2>9$)Lq|_pBk6 zLOn%H46j&(%N`7~HY&Zs7Ot2=r3K_>49xJ_nU)V{m|t}9fmiL92iP7^f!B;|(~5my zY-)S2I2YOwo>w3s7jWgw)l(~+4b4p`%zMNo`qzQw+`=)3Yw;ih11hbK|y|(v3NK*C^8$BxI9l>k&U+b@ER?)qXbmi0%>sq&=dwTKt*{9Fu0N% zi5nIa2RlQYtXma zGBqvrz-unN`qJ?ZZ=J+8l_Vxi!t4Hy#K~WbFH7XF@Ido`;Gf}9{;tr+WqD>8~ahu9s6LVWZP|D zsm3-p_N$&VE5h-4yHbyLVM5*Js*uW*2(l z>|uNjJ=%9`B}jARD();=h<+mbZg}cd+ZT1U4nnVe)~~!qYl*BGQ zR6tM6G}Lpe!X!R7`)(dFAiXeE>vOw+*^V7r%&=!+I=rz;SDBUwpr{EUi;+4lNDm^D z3~$c#!@`9~A%cxq8&}OTGwn&TIx@*xuGer%i~}%y=69Q8~?RYF?JOwJs?*);uCXf znOXpXS+G=or|1F_RU(y`R9(PcD5(w-yMfiJ5LgXPZMz4w+m1Kl>;_dKZ}4R!%a#%O3LJb+k&5&yyS+xjxAZ(%C){Dk{v?HrjTPpXo z&3ekj3nw1<>(74uL7!ph$Ox2FP>1q3AnAq5G{GdjYwoZ|vVvpbafB3ua-)k>vV=#Q z8w32s0nk4PnVw+g0EI|GDSem-E3B%(8Yp-WhauSou_N6>!(&NwpnVKnCuLWHrH4Sn zAe<7rxh{|$Nr!DvI`P5^(<99<9>hj9AKGk3cU}N53=jOZXaDlc#!GiNS#b|(!JDwC z4e9}hUZX5cp|;?eE?i~Y>yDum=j=>8ML_H0d;g-qvzW zO-)BSAl{N|!jLm+5GZ4!&V~m6i;6*8uT#Ifz)(CVA`cit!TGQgC~|1kEcZt5h7+k4 zdQ2~&0^7-N9LdXg#X)77(0Nlq9_asuV4*ItLFpw_nnIZ!eC9NhBskS;llY|P;ru43 zLPh0u0b2!?7WZaIou3T`A}od#)ec4}a}QVylRiaJ*L+eRO#7RMdQxT>8a54wRYTd$ zgfz3~At+`88i$N-txE`!-c3{t5qbkgbBL`^D|+Je3ZpA-3nzBX93UhpzYVeokDm91 zhbqr+(Av(2@>F^TtDzicoa%|XpvuzPLaNXd(v&^(xYvqGg$aFQi3niTnhT^bfctAk zDR&0fXU+RaCY(^Y5(uKy0j8{o4PxeCcIgJ zzM2*aPPHCNo3)UpBC+UF0)diQIg9Rus>6k9R1DUvzUs}PS*>$la|>u0=wrVD>o|8}5ey={c0GYNaUD#D zri}7VPdx06F>+u(B{(j9(G93)yWYkj(_!bz8+To`t3!+9(0WAHRB-2wN@WfpF_~JRFm5g0dO1wd zo<_S(p`h#qQG#VPpeK?yCxl#~t)vH~V-a0IO3Z}|wD0f>AXsCnR#K2kJ|t7DbX|q! z2i`Z=f`-?*;c8qah@DWf2E@Xcouk15RA8G@!h5aGXY5)TcbqFxQIRMd2WbiT3&o)l zGI(JYbgyP(Qu2r2@QH@x?hEp(2vgi49&H+$Dl(Dw!K_8KFNg zLsVJJZMWMorhoQSosbm^2<;VEFfUV-{2`fW&r&7YXzb4l=G;QbGlL`zQ$}9Kt*h9^ zDFL6w?<9@Y-6Rc}2PTRk?1|_k92t~T!2QGNM518hb=VXzbsngzG9mnM--0R8aBoKd zm>8f?Et63$T}3L==tEMIP##l>tTUjmN#2_4;8x>V=dNg(hj&c8kE~QAmDt8O*FGL% zn#8>cQy~p{F^Xie2AOnF3s`MpnR#0+Z5TI9t615#MNhr>8FI>3eu-@UmtQC=k3Cbm zO=Y@0*mrrb+{Iwpv`J=M-$-5$dgCGNSEiqL)oYe5?&a2Y9472Td zZ^I0Jg!jS{oOJXELWk2-MKY&@uyxTZq1?iAF;`WRya?w1e5~zygXgL% zf6y$DcYj-)Y*33BIE;!qLr(vW7wW0saG`uIx0Al;@$KK%ul@4&{oX%(pWJ!%pU8<% z-bL7T#k4%MVDe@9P^kyks)Iq(MmlynflJ@79aIYo@!Ev~p51$^*tshs#GT%1iE5#+ z32||yR*VDtWTnLm*{WWgrZ=SlINZkck^p*9buN8{2JLy52R-eQi)H&uze&p0E%ML3 zo%({OwSRYB{dT?c>OU1AxH1K1%hPN&U1_ya*~c^Oz;*(i6r)=6lTm&U)o{ z%eJq7rhL9_XT0LMGTU~F+_C5PVf+}7W}@wJky8w)yfu3+7K%~}a+9sM$@nBzp~UVu zQdrPEaxGbLkC_KFX8g0pFd=ZnJ;#ewu4p9oUYwMEHUnO4EK(O_uTcP~F|ILDUv+!N zD_;6}sXT6{z2w19IY{9}g}m9bXl)bEe{LSHWlPWLP^?Fz;&0T!i#>^LbB@tG8k+q}=t!ccvUQ=7K~*_yIAR#04KG-qprIb_6f=5{*o}bPB1=Uq%)>fbv7& zNX|%YW+F?vptekV!sK85?3T%Gc9dhU1 zH^{NS`dcV~85C+WPRv|vsKUB(e4ii{W4R39l{vKgPKn&?K6|g;`Act=ZQuB><@A?5 zZ>b_rf5pXe?~NapwSPL4jk#|H3-Q$f8f7$c9Kf$lrlXYQ8ujN0jj2wrtc;6@e@zJ0 zQO@;c5WY&Ri+w}Ud0SD|R)1-?LaafnE0o7ZLr`A{Hiy#dzv|t-zkc>M=BB6<>+HfQCr(cX&p-UB28S(S`@AMT;xUOGijD=^8G12jJaQk39XWLnZ7WUPmLLoh{`W96m;Yf`Ian*Fh zfLU#8RnIL=@O8kmI=448p%(vJ6wCIMOZZ#?o}jl`i#g)tyzQUWYimAN|CYHg#yDSgdcxpP}N=SKdJ1x%QxKuL`R0+Lm+vet#Dj?q{& zg*7}BHa`o6JWA!{r=BN|zxuz(&i#AkoS%6`lhv)SeuLD!aB-_ps*gFD0nhv5xjWpv zp8$aWvk%gz3)m5Pp%Uy_M9_sC($YNIdLT|AK`HTlZoZ~7)^}P-FY^6`9yK72RwYq6 zEtWP#Rwd7%RPk$@=hn`h{N+!UW!t@Pe#@xD+X#s6AqB>$NT7qIyVrU(7K`Cr)XzxCN)A!q;SOLczhopSrn{^rs?K4w&+L|dBk zpv5wS@URD0f)-R#Nm&KY+9(uhy@F%2iK16HUDP~@`J2qKSc&;uZE6liI^?2M7g*$X z?R+lFfUs)6N3Zjo5A0M}uo(ZI{MG+zonYp--yuhCct8$N%9IGQanTk)rz_rdOhy&wqS_#(q2bg7aH{??3SOw)Uwz zb>(r>czDVM=gHk~dItu^30lNcg>Rd$+W}p0Bl39~Q7N6`I?og4dFxrIAA^(EG$Qjm zGS0TjS{u0t1q~hx!B7hdxsB|2`OTtUs$6$9NG!*%FdXFuk}JpY*(l`2?f&<^ubo1r zSUinunQ&z@O;{^qJ6pc~S+eEpo~bL3J!|Q}*KYl^-v6P$le>TY4`lwSPfN5p{%3yM zr$r{LubzJ=;Z={k>#yW7-};@(a}pD& z#Q0~WaCtk+U=p6#r3M2OYnm(3GSM$oq}N4TvO0_96$2_Q97^~~>-5Tw9lF@f6RWGD znlqeGqEM@v$${!vt=aw`zGGC}v*f|HT1VY>@z=C}_r3iu^zPsI16dmtSsOb34N;7ixcAKaBwnMC&DciR?CYcTIfJ&Oe9nYUJ*PzKfW*Fdn8~Mf*p&rq z@3$~ghaSts7fT?pq<-@lKhONpSAIq%w{6e8P)>fz7t39*f3qBY&w&Pg)iaO0=YwO> z{0Va8-G3#+y+<9R)i!L0NsQ!D#0ko@`7{e=nT7F|W8?XIdTcCgGPRtQ5{n#SeLqSo zM&niRi}mOOvVgk#y{76+L*1J0O@H2!!f6SsGtI3dT%P??KlWMGORGnoeZ}|5*5`c<3u1C&^u+t#ep8E^IZ*|ov|NKo zKax-Zh2VVC6a(3)pngEc3?{m0(?L3?-q~$Mk?T3sfr%EfMiLrVTw$6~z*1XmtKK%( zOgHA{`JH=gKBWIpzD7J zgen5y@@rL-87o03ed@z_Wj3bB(TJ>yQ7g0(VAhpIoVQgcWtV;=+!bAm+ zmif9CR%zl~P3Adxaa*{yGtwk#N`rXF#+$>Zp>iPzfG(-oIp^qU-~F8%UVHq*|5uLw z<;`~VFK*UKOloOk)6OUA=AGxtW4`?onQcID&i;x2DF66fudb|>eHLSn2MT-11}BLL z+dL34P@>WnQ5}^bXQYgNnfY74_O!dPX`jf~^H)517bt?>n5(ee!-8#UVOdR+xhkLk z0~=M`mBAo_I+o-JmRT%`$=+pnA0vQa34R^lsW1MPk-46|?ixFCMDBUhTjah!cw3gu z#N~5h^<#G8;K%jwpS{bree-kmw3l8Yx&Xc7#Ic<5ecvW`{QN!%g$T%@FPqyyfe2-o zMb}tGW_aYOxTgC~Oc?amcOTXXl(Hr|f#pQsv$86F)77|L~7J zoZwnk43+U_9P7Qm_jbAM$NqbZaf{p5i!YRw$DJum`a#Z`*mMIAWPIb_wiKDUE}>QU z0EHmg7ec1wl!I~bEp+`;FHxZEM@8L{kzG-rrO2O*<>}y*jbhjl`nx zz%pg6o4@o+*PS{aYo&+(=#RvU*^4;=&ywJNVcY4b7}$i(9B)Dzn>gRoeit{;|4Ch2xE&@o-GWwGzx-~OHO7Q6;Z zF(oElEz~Bn6ELEqH{HChy_#B-t*7`h#qipoQ%m|P87k`8MLIJP7?GzLk}Mn?Cy=4@ z-l*`xdLt+7lCF3|hIt;?Ak%5D7n_YY2nL}Z#y)`2Vk6~3tvfzvF zt<%E;dLWb$Fubf{Q@6ES4$@19Y@03f!I`#SW9kY2j^6bCrMKUF{=e`UItbe0>Am%v zW$Y5cjD$q$ld}^^%p_no^Ft`MD|jPpbay3Tm@c(g$(e+14U7yLZK&?8+#@Vr8H3XTOtfT#TuF;g0 z5_9?;&kUgt>@KSaCL5_`7+G!D0+X%{7;{2lVV#UCBqXX4(1h2+G*+)ck#NV(m(>DD zVzb3UnoG1jc|Dym_xR?dWS&ek=KdHDgP|ebRiU>j3Xqv0g0^&wQZ-}T1I86XN(=TQ zINx#G(sNhNJ}2Vjl-&*xA40EN?)ZYeYsdV65P6 zMSzZpLa`{ZJz!j^$BG4WUHkaKrBXcUX-@-*2xFn)khCaUW!spkmyHxy(~OM2@Q4RU zBgmR_b&lUjwLh+EJz?qCv2Z1UE4YjOC}_cVJ12Fht2GYJxC@f-K2>OWA7|%h+&>?i z8-iRgkI9+nw!gsQeLBHQZ{keUn1gO;*FE~L?V zfBk@q@G&oW(Yp5PQVttE5W&(U3e?Lti~LQ9(4Hc6O82tKkjp!SMaE>Sl!uY@wnpi_ zi-EX7ax3W+UoIce>E2l8R;w_Ll~$J7*2{PbLBU#B=U_cdhG%hKB&tK~>%DR#u|!g? zX|>1R{pah>-2CJ(lP%AG0qS-+|N}Cdz&6*dY$^w`K zO!ah`X+sBNga9P8CQ(vSB*zgam#NRM$Gb(?mfZiYKU;eKwr}}1*>vu?nL3F$f#SUi zm<;;4X)J7?`tSbjvZmyoH(uA=4Nn?dl;$>sdoFf1daF5&iobwYtOpFEg%`TQ5aZf- zJuXHd>`{}7v@oiY(>`-`n5@Lb7az5_=kX2+y>y-f$Sk?qE2c;YuOJM_6YC^&E2H^y z@f+uXU9JXX@_q9=Zq@tW{b%dX-?CNCc=b=})^GeK&6qWTQlqtReZlkftSf(fykdapj>7};J~yj@V6IWzO&ytSs6Y|sa+wb~Gr#XQ zua=W8c!pM`Eh_QU?|ivzdEN`;@LPUcj^A>y)kkY@W@n$HCqM1!a?;bEzO)=yx4Mw( zp5Jmw*^d-wWL@^VR5R{O*}g>&7D1w zS13!oIBke`60eEOqy-AHfzPlZuk+6HRb_4L{>U>}A3Kw&lF1@1UMG=Y20l{rRBI$N z_q^`E$!S0GGfS@;l_ih)-tU)(yB&JNZ?wd|NeN3fM5DhOc2r}s2%%o7AzY1lzlki2 z5z?i_r+SmLl*oZ&8Gc?M)Vp{oZLnA_;mR}2G>8|r=N;{5P-QT780cYifzo>%Qj(HE zGAFDZ88(ngM~WoaD~W|1|Jx7Ay>EEPKdtbf+o50npK||Sz7N)JAuo_A3q)A58BtAR z)qzI-M>o@~I{DH=3==KnjD%p!102|`fDNgC52thwEM2vwaPiXIn9y@9W_)KO^N%37 zKvqk$BbGZPL~k7#5I;4;^tuf(k6+w!DM9bX{qOnn(HjrjwwJs@%UO?=&t$9fhOi{gLO4fIwcA9%bOlov}<}o=0^AbSETA zGF1OR+x^ct$ry!(&X^hO&?)}xhdgQt{jf#AUYn9D&Mg-`QO>eUi_2Cn~UEY^fwA@hqm!!xD4bSrvb(q%;FtkaLx_I?v z7<^)Ph-y146CTY>PyFQ{%d&0Tzkiifa>A09L^;kw4cS3oZcCG*@AL68GgfAtF;eVV ze8^(-WJXjcaFzYZ_7aCL_lWaY_7`ChrK`k>G*2drIMP-692mp;VJnkB2^Ai1kBD=nTeg@I*bs;H|an$p0+NF+%K_PXR)9wSG>XO6Xg_Nq!%o}BTcuUuL)J^ZKd z3J8UW{e?m?Y2feNZc2s1P!L#H^Ww#C)y}L`s5G8ODnq4)%Bu&iau#A%XCG$0k_LF9 z#J;GSL&3=LO#9W=Z75VO=LJQkr8X*jwB)y4TNCtkLYj?a=G4o7K~B2xxze=_WA^*v zyDx!2+FW8ij_Aa@kXy#ewIVT&E+VzhCw4bR6CZky%s>7Q0a%Ok0Yd%9SVXkdw!f+cK|9jxZ>TlCd$n6hx&~`5d6$21C3Y`UQ>1I7NmA z-f`n^%k1&z%jU0s{!*b;NImJI7sTS9tvjP3(ehR zGIb=`2L4(1xy?`%|LXq^644PKiP*v2&f4=k9epr=`w0URl*js}OpB6{ut(_Wj6$gs@wQvsJf!#h_|tC~+2$@# z`>s|l>Em5(&s)wg;$y({QG246notrg&>w{d;z9&(hKwL1tRaX8>~i|!WYhT<$jVnd zbFA1rPG(rVuf_YScFpr-QWZ=^dkoS81RH; zsDyUDz*Mq!0!GGZ6VF5Zu(1La;3~sipORx^vR^%tEUYPaFa!q|LJro2Oc$YHv^PI8 zaDlKVyAv?J;`>r?*3Aka3YqV(w*&zJ4niWxdk31ngN$HejmF9$w^LbRqD!_J3n8h- z2k6Y@&v(m@5L(s__P8b!x`Ydb^$W|#@jnBKK12)W609*24oY%r zLc>bB7;nkTe79=GR8gk3!fLm4AxW|)3`e{X1m_1CSNcKuNK0pa0DFZ@X?pGXcu&@1 z76x%Gzi5UV41&Q4RS9lsqrMCWuB7himq1R-5=Ez zuCQvi8X^s7-?1P`gZ_6*>3~U1B?X;``YBwbujeT_7|s#2DN$u{qvmfiMa81GF|)Ad zuwtjS8f_z+4_l*vg=^mzOAOWe{D<1|8k|crLP|thFQMPAA@e{Xky=3Vl12(EqvRI` z7g!LH6z&)faV*CZP#CrMttCr>``)BDTmR~$GrHt@kL zLJwU{a|lm#1ykV0CsLIwukmzlyP-v`E@um}zGouw(mI2ONq8kaQnL>hh3~LzVXEVg zPNs*Ngn)T3LpTW-0v2?qN*G&8O`(KI!^m9&#)v?j3+36C2|Rr&?uq5s>2=+?%8(;* zr9|wESS4~}Q-1rZ!}TmM z;SzjFg5zp2@zT1|ke~JMLXR1w$w*Sco zes(n!*mkbS^%AU;Y#Lry1z8xg0xJEX&vs0dFF7zi#vHTv^h%b6*yjOYA`#dFhB13i zQNycE$zt2QM}jszCrHsWU$FGvs4$BzKq&pqfB=!X_5Cwyp)(R%2mj{%Nr1wdG6ou! zL`OKcuoHtPOO606*t!AjGArHf^ygGwmPsI-8!0W4LB?y5b+Qb_bz zO*-xU>SotTWF~Q;#U8&iXa4iY8oJm45a=Kj%u_?q%pf6=zRDbQ9jdgBUWC#nV~TA; zIv9L--%in!eh?Dl?8&_(Wr2J?utW8hFM0oKuU)6W)2~=PG~R3vV`0E4zn5O91L7rH z;4xY*ycctfnGz70{5*JfgtMLqLC6^8K%K*c9kx5Gm-M9QceV%bQ|X9@GJOx|RZB9G zAJDG^KaoT|S*M%{LDFePNg^Y}*QmT$oY5g_cTXdD%1mru-;>Gv0yl3yzIQzF?jS6^ zM`54}j|lI8GUAy(Dn~kNC5-k((k>p6B(-o6y&fW8l3q}NlQ80>FBaYh87YMdOAZJt zeN02QI%)B2kzBuG!r4^Im90uxHj<=?H))iZ66|4A`RX9;2`Kspm*)MlV`Jr|lxt-p z1?ukAk<1KxxgKVcoB1j;JnQGVUzY;F_WgWCYSE_%#l4k+p-`k3Eexhx^wU*>U=-Rx z4z3So$=DSCo3OkryZHk^w%|s>c$fR8tRq=xH)n&Ip>&bdqe(rvOai9$;HwL6Z0w_0 z)`Yw<b9dxAiwz1G5ejOY>B*kntZPd_wrnVi3w zZpbF1>feEI5=CL1uC{XUy!Zb6m5a@+Q(*PNGS`<&$3lZeYUX9q!|ZfldPLMKd(R5=`_W^cg*=DH|O&G)- z;(CN+yvB$n~@ z5RAwtee4b&$teRUNV4x9CvEyT9b1ZE!T5;zH3=&lcl_e{fAMqI$wO6OQ=-U~9=Nc^eCJ9c|E-d3~7*ReC6DC236%Y^lBKZ!z48E*6Hz)*Xo#-UPhldb}&Ko;w zU7!@gbRR(2bd4N$mCbh1&i#81$-`A(-A>uPx;nP?qAtj1Xlcp|RcU%Cm22@1&5Wf@ zImr@0-%L`^oh5d15qhl;tR(AGdMHP&LVh5=0sz{g2cgC3%|M#Ov5;Qt-RhmSi`_l_ zr+fmed5*GgJgO9WNW;1;MTow>Z=6g1?ooNG@&MZdDzI*wcCYRq?c|jm=`dn{H=QC9 z>qmQb2~8I=34r@BSfY%`l+<;pLkJ>2S&lWifPV>p4B>bCrfr5-NBcy^Npg|rxBqD5 zEg274;O#pbUdHQst#+nC)Hj-EAX9z3NPg)2ckWpl_xkNY6hlu2k}T& zblU)@()nlSW#JfZkp45+Q<@Lk*eP7-#Zu#Bv>FX zT3{OzFsd>su>lR}QGJ4MU4WHNqh{JgpwycMe2;Fvd*?fT@k)7!+e21h-8S!D-7|Ph zJe0$9sqjZUGMCEeqAHWTuZ?UNjPX%1c|v9RnCr$#UBaYJ4y$%qx5hlHNS`y(bNxZL z&cCb+owNf8IK7)!b5mRJ>^M~ylpiToUkvN`bc`VSIm%SN?!5iK^srvP@vszFx080S zUN;xJV7%F?;K}&9zoY2lanhDl6d+d;8sVXi01}X5%+vdaRR}(W!qVU=&QO))?=ZL* zSz>cA4dVLL)@Xbai&%6~^ng{iut=3jdWbef`bgWrsjQCkc^B;5|GNG1Ft>-Tz`9j- zy2(Z*itNo1J8>dxGQebDllYr-kR>w>FhgqBGZKl`p%njJCO_WG+>(|Hts5p6|6{*=7Tag7KyJsb+Hu7wzRSjr?&#O^J6IKec2FQtpL)Y@r9=_}oVt zS3V0e$f5C^y>fiZo(D?MAL{mqDX?xwuiCMr4DzzEgO{nzc7y^NXqNiRKJ8gy^VN!G z{7st$p&1senc*2|cyrx1%v;RR5SUwYc$(~U=#avd1EUkv+=wDnZX3f`(bB!c{o5W9#c_K?71(dbf8mQ>HWJOtM#1fZzyw}4 zNc&|9z={yg2$vpZBm_pmcY+-{?=)XXZ2@bBYek@}cAa}hFVOx`W~Ty{eT34gLV+UY zkm&{qBMgr%0qu?)`F;F%!+7EK!x6c5=l*?~mnHWLzEa4c?7FoTBD(zB+X5uTi$?eOaNb$;m(>@jJ80rW6Eg+RnhJPp;_ z!IMp0AI5X;8ux#2{B-?^du89Fp|pN`)D^h69sQ{%?b1yvPZ>@OJI8@Pr3zv`*X`rq z?TmvRnb|?&(c+LF8~l~((>NF&U>%V#g@;FsN{{PcnWPD?c|;uTNtLX&m%R*x<$(6p x@!CUUe7|L8<=_Y|H=dBqt2?iIbd}a`{~vJo&aJ}n4n+U}002ovPDHLkV1oR?(mntH diff --git a/src/screens/InviteFlow/InviteShare/assets/images/instagramIcon@3x.png b/src/screens/InviteFlow/InviteShare/assets/images/instagramIcon@3x.png deleted file mode 100644 index 017f9b7cee3e2eb1ac63a0b1a42a18e91a41198a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28271 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 { translateY: slideUpValue.interpolate({ inputRange: [0, 1], - outputRange: [rem(45), 0], + outputRange: [0, -rem(45)], }), }, ], @@ -73,9 +73,9 @@ export const Copied = forwardRef( const styles = StyleSheet.create({ container: { - flex: 1, - backgroundColor: 'transparent', - alignItems: 'center', + position: 'absolute', + alignSelf: 'center', + top: 0, }, copiedContainer: { height: rem(35), diff --git a/src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareButton/index.tsx b/src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareButton/index.tsx new file mode 100644 index 000000000..e11b29ee6 --- /dev/null +++ b/src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareButton/index.tsx @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Touchable} from '@components/Touchable'; +import {font} from '@utils/styles'; +import React from 'react'; +import {Image, StyleProp, StyleSheet, Text, ViewStyle} from 'react-native'; +import {rem} from 'rn-units'; + +type Props = { + onPress: () => void; + title: string; + icon: number; + style?: StyleProp; +}; + +export const ShareButton = ({title, icon, onPress, style}: Props) => { + return ( + + + {title} + + ); +}; + +const styles = StyleSheet.create({ + icon: { + width: rem(56), + height: rem(56), + }, + buttonTitle: { + marginTop: rem(8), + ...font(11, 18, 'regular', 'secondary'), + }, +}); diff --git a/src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareCard/index.tsx b/src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareCard/index.tsx new file mode 100644 index 000000000..56a3728ae --- /dev/null +++ b/src/screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareCard/index.tsx @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import {commonStyles} from '@constants/styles'; +import {useBottomOffsetStyle} from '@navigation/hooks/useBottomOffsetStyle'; +import {ShareButton as ShareButtonComponent} from '@screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareButton'; +import React, {ReactNode} from 'react'; +import {StyleSheet, View} from 'react-native'; +import {rem} from 'rn-units'; + +export type ShareButton

= { + type: string; + title: string; + icon: number; + onPress: (p: P) => Promise; +}; + +type Props

= { + buttons: ShareButton

[]; + onButtonPress: (button: ShareButton

) => void; + children?: ReactNode; +}; + +export const ShareCard = ({buttons, onButtonPress, children}: Props

) => { + const bottomOffset = useBottomOffsetStyle(); + + return ( + + {children} + + {buttons.map(button => ( + onButtonPress(button)} + style={styles.button} + /> + ))} + + + ); +}; + +const styles = StyleSheet.create({ + shareCard: { + position: 'absolute', + left: 0, + bottom: 0, + right: 0, + }, + buttonsContainer: { + flexDirection: 'row', + flexWrap: 'wrap', + marginHorizontal: rem(12), + marginTop: rem(12), + marginBottom: rem(20), + backgroundColor: COLORS.white, + }, + button: { + width: '25%', + alignItems: 'center', + justifyContent: 'center', + marginTop: rem(24), + }, +}); diff --git a/src/screens/InviteFlow/InviteShare/components/InviteShareCard/index.tsx b/src/screens/InviteFlow/InviteShare/components/InviteShareCard/index.tsx new file mode 100644 index 000000000..df0faaa3a --- /dev/null +++ b/src/screens/InviteFlow/InviteShare/components/InviteShareCard/index.tsx @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Images} from '@images'; +import Clipboard from '@react-native-clipboard/clipboard'; +import { + Copied, + CopiedMethods, +} from '@screens/InviteFlow/InviteShare/components/Copied'; +import { + ShareButton, + ShareCard, +} from '@screens/InviteFlow/InviteShare/components/InviteShareCard/components/ShareCard'; +import {logError} from '@services/logging'; +import {shareSingle, Social} from '@services/share'; +import {usernameSelector} from '@store/modules/Account/selectors'; +import {AnalyticsEventLogger} from '@store/modules/Analytics/constants'; +import {t} from '@translations/i18n'; +import {buildUsernameLink} from '@utils/username'; +import React, {createRef} from 'react'; +import {Linking, Share as ShareMore, Vibration} from 'react-native'; +import {openComposer} from 'react-native-email-link'; +import {useSelector} from 'react-redux'; +import {isIOS} from 'rn-units'; + +const buttons: ShareButton<{url: string; message: string}>[] = [ + { + type: 'WhatsApp', + title: t('invite_share.whatsapp'), + icon: Images.share.whatsApp, + onPress: ({url, message}) => + shareSingle({url, message, social: Social.Whatsapp}), + }, + { + type: 'Telegram', + title: t('invite_share.telegram'), + icon: Images.share.telegram, + onPress: ({url, message}) => + shareSingle({message: `${message} ${url}`, social: Social.Telegram}), + }, + { + type: 'Twitter', + title: t('invite_share.twitter'), + icon: Images.share.twitter, + onPress: ({url, message}) => + shareSingle({url, message, social: Social.Twitter}), + }, + { + type: 'FB', + title: t('invite_share.fb'), + icon: Images.share.facebook, + onPress: ({url, message}) => + shareSingle({url, message, social: Social.Facebook}), + }, + { + type: 'Email', + title: t('invite_share.email'), + icon: Images.share.email, + onPress: async ({url, message}) => { + openComposer({ + subject: t('invite_share.share_subject'), + body: `${message} ${url}`, + }); + }, + }, + { + type: 'Sms', + title: t('invite_share.sms'), + icon: Images.share.sms, + onPress: ({url, message}) => { + const divider = isIOS ? '&' : '?'; + return Linking.openURL(`sms:${divider}body=${message} ${url}`); + }, + }, + { + type: 'CopyLink', + title: t('invite_share.copy_link'), + icon: Images.share.link, + onPress: async ({url}) => { + Clipboard.setString(url); + Vibration.vibrate([0, 50]); + copiedRef.current?.updateVisibleState(true); + }, + }, + { + type: 'More', + title: t('invite_share.more'), + icon: Images.share.more, + onPress: ({url}) => + ShareMore.share({ + message: `${t('invite_share.share_message')} ${url}`, + }), + }, +]; + +const copiedRef = createRef(); + +export const InviteShareCard = () => { + const username = useSelector(usernameSelector); + + const handleSocialButtonPress = (button: typeof buttons[number]) => { + AnalyticsEventLogger.trackInvite({inviteAppType: button.type}); + button + .onPress({ + message: t('invite_share.share_message'), + url: buildUsernameLink(username), + }) + .catch(logError); + }; + + return ( + + + + ); +}; diff --git a/src/screens/InviteFlow/InviteShare/components/ShareButton/index.tsx b/src/screens/InviteFlow/InviteShare/components/ShareButton/index.tsx deleted file mode 100644 index cf1f81d7f..000000000 --- a/src/screens/InviteFlow/InviteShare/components/ShareButton/index.tsx +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -import {Touchable} from '@components/Touchable'; -import {SocialType} from '@screens/InviteFlow/InviteShare/components/ShareButton/types'; -import {font} from '@utils/styles'; -import React from 'react'; -import {Image, StyleSheet, Text} from 'react-native'; -import {Social} from 'react-native-share'; -import {rem} from 'rn-units'; - -export type SocialShareButtonType = { - type: SocialType; - title: string; - icon: number; - social?: Social; -}; - -interface ShareButtonProps { - button: SocialShareButtonType; - onPress: (type: SocialType) => void; -} -export const ShareButton = ({button, onPress}: ShareButtonProps) => { - const handlePress = () => { - onPress(button.type); - }; - - return ( - - - {button.title} - - ); -}; - -const styles = StyleSheet.create({ - button: { - width: '25%', - alignItems: 'center', - justifyContent: 'center', - marginTop: rem(35), - }, - icon: { - width: rem(56), - height: rem(56), - }, - buttonTitle: { - marginTop: rem(8), - ...font(11, 18, 'regular', 'secondary'), - }, -}); diff --git a/src/screens/InviteFlow/InviteShare/components/ShareButton/types.ts b/src/screens/InviteFlow/InviteShare/components/ShareButton/types.ts deleted file mode 100644 index 10f1e5b6c..000000000 --- a/src/screens/InviteFlow/InviteShare/components/ShareButton/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -export type SocialType = - | 'Telegram' - | 'Twitter' - | 'WhatsApp' - | 'Instagram' - | 'Sms' - | 'Email' - | 'FB' - | 'CopyLink' - | 'More'; diff --git a/src/screens/InviteFlow/InviteShare/components/ShareCard/index.tsx b/src/screens/InviteFlow/InviteShare/components/ShareCard/index.tsx deleted file mode 100644 index ab0b85e2d..000000000 --- a/src/screens/InviteFlow/InviteShare/components/ShareCard/index.tsx +++ /dev/null @@ -1,228 +0,0 @@ -// SPDX-License-Identifier: ice License 1.0 - -import {LINKS} from '@constants/links'; -import {commonStyles} from '@constants/styles'; -import {useSafeAreaInsets} from '@hooks/useSafeAreaInsets'; -import Clipboard from '@react-native-clipboard/clipboard'; -import { - Copied, - CopiedMethods, -} from '@screens/InviteFlow/InviteShare/components/Copied'; -import { - ShareButton, - SocialShareButtonType, -} from '@screens/InviteFlow/InviteShare/components/ShareButton'; -import {SocialType} from '@screens/InviteFlow/InviteShare/components/ShareButton/types'; -import {logError} from '@services/logging'; -import {usernameSelector} from '@store/modules/Account/selectors'; -import {AnalyticsEventLogger} from '@store/modules/Analytics/constants'; -import {t} from '@translations/i18n'; -import {checkProp} from '@utils/guards'; -import React, {useRef} from 'react'; -import { - Linking, - Share as ShareMore, - StyleSheet, - Vibration, - View, -} from 'react-native'; -import {openComposer} from 'react-native-email-link'; -import Share, {ShareSingleOptions, Social} from 'react-native-share'; -import {useSelector} from 'react-redux'; -import {isAndroid, isIOS, rem} from 'rn-units'; - -const telegramIcon = require('../../assets/images/telegramIcon.png'); -const twitterIcon = require('../../assets/images/twitterIcon.png'); -const whatsAppIcon = require('../../assets/images/whatsAppIcon.png'); -const emailIcon = require('../../assets/images/emailIcon.png'); -const fbIcon = require('../../assets/images/newsfeedIcon.png'); -const copyIcon = require('../../assets/images/linkIcon.png'); -const moreIcon = require('../../assets/images/moreIcon.png'); -const smsIcon = require('../../assets/images/smsIcon.png'); - -const buttons: SocialShareButtonType[] = [ - { - type: 'WhatsApp', - title: t('invite_share.whatsapp'), - icon: whatsAppIcon, - }, - { - type: 'Telegram', - title: t('invite_share.telegram'), - icon: telegramIcon, - }, - { - type: 'Twitter', - title: t('invite_share.twitter'), - icon: twitterIcon, - }, - { - type: 'FB', - title: t('invite_share.fb'), - icon: fbIcon, - social: Share.Social.FACEBOOK, - }, - { - type: 'Email', - title: t('invite_share.email'), - icon: emailIcon, - }, - { - type: 'Sms', - title: t('invite_share.sms'), - icon: smsIcon, - }, - { - type: 'CopyLink', - title: t('invite_share.copy_link'), - icon: copyIcon, - }, - { - type: 'More', - title: t('invite_share.more'), - icon: moreIcon, - }, -]; - -const ShareCard = () => { - const copiedRef = useRef(null); - const {bottom: bottomInset} = useSafeAreaInsets(); - const username = useSelector(usernameSelector); - - const handleSocialButtonPress = async (type: SocialType) => { - const url = `${LINKS.MAIN}@${username}`; - const baseOptions = {message: t('invite_share.share_message'), url}; - AnalyticsEventLogger.trackInvite({inviteAppType: type}); - try { - switch (type) { - case 'More': - let moreOptions = { - message: `${t('invite_share.share_message')} ${url}`, - }; - await ShareMore.share(moreOptions); - break; - case 'CopyLink': - Clipboard.setString(url); - Vibration.vibrate([0, 50]); - copiedRef.current?.updateVisibleState(true); - break; - case 'Telegram': - let telegramOptions: ShareSingleOptions = { - social: Social.Telegram, - message: `${baseOptions.message} ${url}`, - }; - await Share.shareSingle(telegramOptions); - break; - case 'Twitter': - let twitterOptions: ShareSingleOptions = { - ...baseOptions, - social: Social.Twitter, - }; - await Share.shareSingle(twitterOptions); - break; - case 'WhatsApp': - let whatsappOptions: ShareSingleOptions = { - ...baseOptions, - social: Social.Whatsapp, - }; - await Share.shareSingle(whatsappOptions); - break; - case 'Email': - let emailOptions: ShareSingleOptions = { - ...baseOptions, - social: Social.Email, - }; - - await openComposer({ - subject: emailOptions.subject, - body: `${emailOptions.message} ${url}`, - }); - break; - case 'FB': - let fbOptions: ShareSingleOptions = { - ...baseOptions, - social: Social.Facebook, - }; - await Share.shareSingle(fbOptions); - break; - case 'Sms': - const divider = isIOS ? '&' : '?'; - - const path = `sms:${divider}body=${baseOptions.message} ${url}`; - - await Linking.openURL(path); - break; - - default: - break; - } - } catch (error) { - if (isShareProviderNotInstalled(error)) { - return; - } - logError(error); - } - }; - - return ( - - - - - {buttons.map(button => ( - - ))} - - - - ); -}; - -const isShareProviderNotInstalled = (error: unknown) => { - if ( - isAndroid && - checkProp(error, 'error') && - typeof error.error === 'string' && - error.error.includes('No Activity found to handle Intent') - ) { - return true; - } else if ( - isIOS && - checkProp(error, 'code') && - error.code === 'ECOM.RNSHARE1' - ) { - return true; - } - return false; -}; - -const styles = StyleSheet.create({ - fullCard: { - position: 'absolute', - left: 0, - bottom: 0, - right: 0, - }, - shareCard: { - position: 'absolute', - left: 0, - bottom: 0, - right: 0, - }, - buttonsContainer: { - flexDirection: 'row', - flexWrap: 'wrap', - marginHorizontal: rem(12), - }, -}); - -export default ShareCard; diff --git a/src/screens/InviteFlow/InviteShare/index.tsx b/src/screens/InviteFlow/InviteShare/index.tsx index 1f653e5af..5d57695f2 100644 --- a/src/screens/InviteFlow/InviteShare/index.tsx +++ b/src/screens/InviteFlow/InviteShare/index.tsx @@ -6,7 +6,7 @@ import {COLORS} from '@constants/colors'; import {commonStyles, windowWidth} from '@constants/styles'; import {Header} from '@navigation/components/Header'; import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; -import ShareCard from '@screens/InviteFlow/InviteShare/components/ShareCard'; +import {InviteShareCard} from '@screens/InviteFlow/InviteShare/components/InviteShareCard'; import {replaceString, t, tagRegex} from '@translations/i18n'; import {font} from '@utils/styles'; import React, {memo} from 'react'; @@ -37,7 +37,7 @@ export const InviteShare = memo(() => { )} - + ); diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/PrivacyButton/index.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/PrivacyButton/index.tsx new file mode 100644 index 000000000..2ec438dd9 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/PrivacyButton/index.tsx @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Touchable} from '@components/Touchable'; +import {COLORS} from '@constants/colors'; +import {SMALL_BUTTON_HIT_SLOP} from '@constants/styles'; +import {ClosedPrivacyIcon} from '@svg/ClosedPrivacyIcon'; +import {OpenedPrivacyIcon} from '@svg/OpenedPrivacyIcon'; +import React from 'react'; +import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'; +import {rem} from 'rn-units'; + +const SIZE = rem(24); + +type Props = { + onPress: () => void; + isClosed: boolean; + style?: StyleProp; +}; + +export const PrivacyButton = ({onPress, isClosed, style}: Props) => { + return ( + + + {isClosed ? ( + + ) : ( + + )} + + + ); +}; + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + right: 0, + bottom: -rem(6), + width: SIZE, + height: SIZE, + borderRadius: SIZE / 2, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: COLORS.foam, + }, +}); diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeEye.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeEye.tsx new file mode 100644 index 000000000..b491ea863 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeEye.tsx @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {EYE_CELLS} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/constants'; +import {QRCodeEyeIcon} from '@svg/QRCodeEyeIcon'; +import React from 'react'; +import {StyleProp, ViewStyle} from 'react-native'; + +type Props = { + size: number; + matrix: (1 | 0)[][]; + color?: string; + style?: StyleProp; +}; + +export const QRCodeEye = ({size, matrix, color, style}: Props) => { + const matrixLength = matrix.length; + const eyeSize = (size / matrixLength) * EYE_CELLS; + return ( + + ); +}; diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeField.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeField.tsx new file mode 100644 index 000000000..6d2402fb2 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeField.tsx @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {EYE_CELLS} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/constants'; +import React from 'react'; +import {Circle, Svg} from 'react-native-svg'; + +type Props = { + size: number; + matrix: (1 | 0)[][]; + color?: string; + dotSize?: number; +}; + +export const QRCodeField = ({size, matrix, color, dotSize = 2}: Props) => { + const matrixLength = matrix.length; + const cellSize = size / matrixLength; + + const circles = matrix.flatMap((row, i) => { + return row.map((column, j) => { + if (column) { + if ( + (i < EYE_CELLS && j < EYE_CELLS) || + (i >= matrixLength - EYE_CELLS && j < EYE_CELLS) || + (i < EYE_CELLS && j >= matrixLength - EYE_CELLS) + ) { + return null; + } else { + return ( + + ); + } + } + }); + }); + + return ( + + {circles} + + ); +}; diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeLogo.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeLogo.tsx new file mode 100644 index 000000000..2ac65c938 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeLogo.tsx @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {LogoIcon} from '@svg/LogoIcon'; +import React from 'react'; +import {StyleSheet, View} from 'react-native'; + +type Props = { + size: number; + matrix: (1 | 0)[][]; + color?: string; + logoSizePercentage?: number; +}; + +export const QRCodeLogo = ({ + size, + matrix, + color, + logoSizePercentage = 30, +}: Props) => { + const matrixLength = matrix.length; + const cellSize = size / matrixLength; + const approxLogoCells = Math.floor((matrixLength * logoSizePercentage) / 100); + const logoCells = + (matrixLength - approxLogoCells) % 2 === 0 + ? approxLogoCells + : approxLogoCells + 1; + const logoSize = cellSize * logoCells; + + return ( + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + alignSelf: 'center', + backgroundColor: 'white', + justifyContent: 'center', + alignItems: 'center', + }, +}); diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/constants.ts b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/constants.ts new file mode 100644 index 000000000..1cda0c61d --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/constants.ts @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: ice License 1.0 + +export const EYE_CELLS = 7; diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/index.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/index.tsx new file mode 100644 index 000000000..31dcc4412 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/index.tsx @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import {QRCodeEye} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeEye'; +import {QRCodeField} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeField'; +import {QRCodeLogo} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/components/QRCodeLogo'; +import {generateQRCodeMatrix} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/utils'; +import React from 'react'; +import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'; + +type Props = { + input: string; + size: number; + color?: string; + containerStyle?: StyleProp; +}; + +export const QRCode = ({ + input, + size, + color = COLORS.black, + containerStyle, +}: Props) => { + const matrix = generateQRCodeMatrix(input, {errorCorrectionLevel: 'H'}); + + return ( + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + justifyContent: 'center', + }, + eyeTopLeft: { + position: 'absolute', + top: 0, + left: 0, + }, + eyeTopRight: { + position: 'absolute', + top: 0, + right: 0, + transform: [{rotate: '90deg'}], + }, + eyeBottomLeft: { + position: 'absolute', + bottom: 0, + left: 0, + transform: [{rotate: '90deg'}], + }, +}); diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/utils.ts b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/utils.ts new file mode 100644 index 000000000..a8fddbe50 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode/utils.ts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: ice License 1.0 + +import QRCodeMatrix, {QRCodeOptions} from 'qrcode'; + +export const generateQRCodeMatrix = (input: string, options: QRCodeOptions) => { + const sequence: (1 | 0)[] = Array.prototype.slice.call( + QRCodeMatrix.create(input, options).modules.data, + 0, + ); + const size = Math.sqrt(sequence.length); + + const matrix = []; + while (sequence.length) { + matrix.push(sequence.splice(0, size)); + } + return matrix; +}; diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCodeAvatar/index.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCodeAvatar/index.tsx new file mode 100644 index 000000000..eaf436adb --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCodeAvatar/index.tsx @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Avatar} from '@components/Avatar/Avatar'; +import {COLORS} from '@constants/colors'; +import React from 'react'; +import {StyleSheet, View} from 'react-native'; +import {rem} from 'rn-units'; + +export const AVATAR_SIZE = rem(82); +const AVATAR_BORDER_RADIUS = rem(24); + +type Props = { + uri: string; + isShown: boolean; +}; + +export const QRCodeAvatar = ({uri, isShown}: Props) => { + return ( + + {isShown ? ( + + ) : ( + + )} + + ); +}; + +const styles = StyleSheet.create({ + container: { + position: 'absolute', + top: -AVATAR_SIZE / 2, + alignSelf: 'center', + }, + avatar: { + borderWidth: rem(3), + borderColor: COLORS.white, + }, + stub: { + width: AVATAR_SIZE, + height: AVATAR_SIZE, + borderRadius: AVATAR_BORDER_RADIUS, + backgroundColor: COLORS.foam, + }, +}); diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/index.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/index.tsx new file mode 100644 index 000000000..841cabc4f --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRCodePreview/index.tsx @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {User} from '@api/user/types'; +import {IceLabel} from '@components/Labels/IceLabel'; +import {COLORS} from '@constants/colors'; +import {windowWidth} from '@constants/styles'; +import {PrivacyButton} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/PrivacyButton'; +import {QRCode} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCode'; +import { + AVATAR_SIZE, + QRCodeAvatar, +} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview/components/QRCodeAvatar'; +import {t} from '@translations/i18n'; +import {font} from '@utils/styles'; +import {buildUsernameLink} from '@utils/username'; +import React, {forwardRef, Ref, useState} from 'react'; +import {StyleSheet, Text, View} from 'react-native'; +import {rem} from 'rn-units'; + +type Props = { + user: User; +}; + +export const QRCodePreview = forwardRef( + ({user}: Props, forwardedRef: Ref) => { + const [isAvatarShown, setIsAvatarShown] = useState(true); + return ( + + + + + @{user.username} + + + {t('qr_code.description')} + + + + + + + {/* + * PrivacyButton has to be outside of the "ref" component so + * it won't be included to the shared view shot + */} + setIsAvatarShown(s => !s)} + style={styles.privacyButton} + /> + + ); + }, +); + +const styles = StyleSheet.create({ + container: { + marginHorizontal: rem(16), + marginTop: -rem(20), + backgroundColor: 'transparent', // has to be defined for android view-shot + }, + body: { + alignItems: 'center', + marginTop: AVATAR_SIZE / 2, + backgroundColor: COLORS.white, + borderRadius: rem(16), + }, + usernameText: { + marginTop: rem(12) + AVATAR_SIZE / 2, + ...font(17, 20.4, 'semibold', 'black'), + }, + qrCode: { + marginTop: rem(26), + }, + descriptionText: { + marginTop: rem(24), + ...font(14, 16.8, 'semibold', 'black'), + }, + iceLabel: { + marginTop: rem(20), + marginBottom: rem(12), + }, + iceLabelText: { + ...font(28, 33, 'bold', 'black'), + }, + privacyButton: { + position: 'absolute', + top: AVATAR_SIZE / 2 + rem(2), + right: windowWidth / 2 - AVATAR_SIZE / 2, + }, +}); diff --git a/src/screens/InviteFlow/QRCodeShare/components/QRShareCard/index.tsx b/src/screens/InviteFlow/QRCodeShare/components/QRShareCard/index.tsx new file mode 100644 index 000000000..2e795e9fb --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/components/QRShareCard/index.tsx @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {User} from '@api/user/types'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; +import {Touchable} from '@components/Touchable'; +import {COLORS} from '@constants/colors'; +import {MIDDLE_BUTTON_HIT_SLOP} from '@constants/styles'; +import {Images} from '@images'; +import {logError} from '@services/logging'; +import {openShareDialog} from '@services/share'; +import {ShareIcon} from '@svg/ShareIcon'; +import {t} from '@translations/i18n'; +import {font} from '@utils/styles'; +import React, {RefObject} from 'react'; +import {Image, StyleSheet, View} from 'react-native'; +import {captureRef} from 'react-native-view-shot'; +import {rem} from 'rn-units'; + +type Props = { + user: User; + qrCodePreviewRef: RefObject; +}; + +export const QRShareCard = ({user, qrCodePreviewRef}: Props) => { + const onSharePress = async () => { + try { + const url = await captureRef(qrCodePreviewRef, { + fileName: `${user.username}_qr_code`, + }); + await openShareDialog({url}); + } catch (error) { + logError(error); + } + }; + + return ( + + + + + } + onPress={onSharePress} + customBackground={true} + style={styles.button} + textStyle={styles.buttonText} + /> + + ); +}; + +const styles = StyleSheet.create({ + container: { + flexGrow: 1, + justifyContent: 'center', + }, + image: { + height: rem(34), + alignSelf: 'center', + }, + button: { + backgroundColor: COLORS.white, + height: rem(48), + marginTop: rem(34), + marginHorizontal: rem(38), + }, + buttonText: { + ...font(14, 16.8, 'black', 'primaryDark'), + marginHorizontal: rem(4), + }, +}); diff --git a/src/screens/InviteFlow/QRCodeShare/index.tsx b/src/screens/InviteFlow/QRCodeShare/index.tsx new file mode 100644 index 000000000..d52711d87 --- /dev/null +++ b/src/screens/InviteFlow/QRCodeShare/index.tsx @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {LinesBackground} from '@components/LinesBackground'; +import {COLORS} from '@constants/colors'; +import {commonStyles} from '@constants/styles'; +import {Header} from '@navigation/components/Header'; +import {useBottomOffsetStyle} from '@navigation/hooks/useBottomOffsetStyle'; +import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; +import {QRCodePreview} from '@screens/InviteFlow/QRCodeShare/components/QRCodePreview'; +import {QRShareCard} from '@screens/InviteFlow/QRCodeShare/components/QRShareCard'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; +import React, {memo, useRef} from 'react'; +import {StyleSheet, View} from 'react-native'; +import {useSelector} from 'react-redux'; + +export const QRCodeShare = memo(() => { + useFocusStatusBar({style: 'light-content'}); + const bottomOffset = useBottomOffsetStyle(); + + const user = useSelector(unsafeUserSelector); + const qrCodePreviewRef = useRef(null); + + return ( + + +

+ + + + + + ); +}); + +const styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: COLORS.primaryLight, + }, +}); diff --git a/src/screens/Modals/DateSelector/index.tsx b/src/screens/Modals/DateSelector/index.tsx index 9f09ecc9d..929952432 100644 --- a/src/screens/Modals/DateSelector/index.tsx +++ b/src/screens/Modals/DateSelector/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {stopPropagation} from '@components/KeyboardDismiss'; -import {PrimaryButton} from '@components/PrimaryButton'; import {Touchable} from '@components/Touchable'; import {COLORS} from '@constants/colors'; import {MIDDLE_BUTTON_HIT_SLOP} from '@constants/styles'; diff --git a/src/screens/Modals/PopUp/components/PopUpButton/index.tsx b/src/screens/Modals/PopUp/components/PopUpButton/index.tsx index 25d991d97..ca071c2f5 100644 --- a/src/screens/Modals/PopUp/components/PopUpButton/index.tsx +++ b/src/screens/Modals/PopUp/components/PopUpButton/index.tsx @@ -1,6 +1,9 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton, PrimaryButtonProps} from '@components/PrimaryButton'; +import { + PrimaryButton, + PrimaryButtonProps, +} from '@components/Buttons/PrimaryButton'; import {COLORS} from '@constants/colors'; import {t} from '@translations/i18n'; import {font} from '@utils/styles'; diff --git a/src/screens/Modals/ProfilePrivacyEdit/step3/index.tsx b/src/screens/Modals/ProfilePrivacyEdit/step3/index.tsx index b29311cd5..2627f5553 100644 --- a/src/screens/Modals/ProfilePrivacyEdit/step3/index.tsx +++ b/src/screens/Modals/ProfilePrivacyEdit/step3/index.tsx @@ -1,6 +1,5 @@ // SPDX-License-Identifier: ice License 1.0 -import {User} from '@api/user/types'; import {COLORS} from '@constants/colors'; import {windowWidth} from '@constants/styles'; import {Images} from '@images'; @@ -9,7 +8,7 @@ import {CancelButton} from '@screens/Modals/ProfilePrivacyEdit/components/Cancel import {Description} from '@screens/Modals/ProfilePrivacyEdit/components/Description'; import {NextButton} from '@screens/Modals/ProfilePrivacyEdit/components/NextButton'; import {BadgeSummariesList} from '@screens/ProfileFlow/Profile/components/Badges/components/BadgeSummariesList'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import {AchievementsSelectors} from '@store/modules/Achievements/selectors'; import {t} from '@translations/i18n'; import React from 'react'; @@ -19,7 +18,7 @@ import {rem} from 'rn-units'; export const ProfilePrivacyEditStep3 = () => { const navigation = useNavigation(); - const authUser = useSelector(userSelector) as User; + const authUser = useSelector(unsafeUserSelector); const badgesSummary = useSelector( AchievementsSelectors.getBadgesSummary({userId: authUser.id}), ); diff --git a/src/screens/Modals/QRCodeScanner/hooks/useCameraPermissions.tsx b/src/screens/Modals/QRCodeScanner/hooks/useCameraPermissions.tsx new file mode 100644 index 000000000..98d0251a8 --- /dev/null +++ b/src/screens/Modals/QRCodeScanner/hooks/useCameraPermissions.tsx @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {PermissionsActions} from '@store/modules/Permissions/actions'; +import {isPermissionGrantedSelector} from '@store/modules/Permissions/selectors'; +import {useEffect} from 'react'; +import {useDispatch, useSelector} from 'react-redux'; + +export const useCameraPermissions = () => { + const dispatch = useDispatch(); + const permissionsGranted = useSelector(isPermissionGrantedSelector('camera')); + + useEffect(() => { + if (!permissionsGranted) { + dispatch(PermissionsActions.GET_PERMISSIONS.START.create('camera')); + } + }, [dispatch, permissionsGranted]); + + return {permissionsGranted}; +}; diff --git a/src/screens/Modals/QRCodeScanner/hooks/useDetectBarcode.tsx b/src/screens/Modals/QRCodeScanner/hooks/useDetectBarcode.tsx new file mode 100644 index 000000000..124e65eab --- /dev/null +++ b/src/screens/Modals/QRCodeScanner/hooks/useDetectBarcode.tsx @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {useRef} from 'react'; +import {runOnJS} from 'react-native-reanimated'; +import {useFrameProcessor} from 'react-native-vision-camera'; +import {Barcode, BarcodeFormat, scanBarcodes} from 'vision-camera-code-scanner'; + +export const useDetectBarcode = ({ + onDetect, +}: { + onDetect: (content: string) => void; +}) => { + const detectedRef = useRef(false); + + const onBarcodesDetect = (barcodes: Barcode[]) => { + if (barcodes.length > 0 && !detectedRef.current) { + detectedRef.current = true; + onDetect(barcodes[0].rawValue ?? ''); + } + }; + + const frameProcessor = useFrameProcessor(frame => { + 'worklet'; + const detectedBarcodes = scanBarcodes(frame, [BarcodeFormat.QR_CODE]); + runOnJS(onBarcodesDetect)(detectedBarcodes); + }, []); + + return {frameProcessor}; +}; diff --git a/src/screens/Modals/QRCodeScanner/index.tsx b/src/screens/Modals/QRCodeScanner/index.tsx new file mode 100644 index 000000000..845d1d492 --- /dev/null +++ b/src/screens/Modals/QRCodeScanner/index.tsx @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {COLORS} from '@constants/colors'; +import {commonStyles} from '@constants/styles'; +import {Header} from '@navigation/components/Header'; +import {WelcomeStackParamList} from '@navigation/Welcome'; +import {RouteProp, useNavigation, useRoute} from '@react-navigation/native'; +import {useCameraPermissions} from '@screens/Modals/QRCodeScanner/hooks/useCameraPermissions'; +import {useDetectBarcode} from '@screens/Modals/QRCodeScanner/hooks/useDetectBarcode'; +import React from 'react'; +import {StyleSheet, View} from 'react-native'; +import {Camera, useCameraDevices} from 'react-native-vision-camera'; + +export type QRCodeScannerParams = { + onDetect: (content: string) => void; +}; + +export const QRCodeScanner = () => { + const route = useRoute>(); + const navigation = useNavigation(); + const {onDetect} = route.params; + + const {frameProcessor} = useDetectBarcode({ + onDetect: content => { + onDetect(content); + navigation.goBack(); + }, + }); + + const {permissionsGranted} = useCameraPermissions(); + + const device = useCameraDevices().back; + + return ( + +
+ {device && permissionsGranted ? ( + + ) : ( + + )} + + ); +}; + +const styles = StyleSheet.create({ + stub: { + backgroundColor: COLORS.black, + }, +}); diff --git a/src/screens/Notifications/components/EmptyNotifications/index.tsx b/src/screens/Notifications/components/EmptyNotifications/index.tsx index 390e30040..c8b220e93 100644 --- a/src/screens/Notifications/components/EmptyNotifications/index.tsx +++ b/src/screens/Notifications/components/EmptyNotifications/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton} from '@components/PrimaryButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {COLORS} from '@constants/colors'; import {NotificationActions} from '@store/modules/Notifications/actions'; import {t} from '@translations/i18n'; diff --git a/src/screens/ProfileFlow/Badges/components/BadgeCard.tsx b/src/screens/ProfileFlow/Badges/components/BadgeCard.tsx index c27166420..34c6ce661 100644 --- a/src/screens/ProfileFlow/Badges/components/BadgeCard.tsx +++ b/src/screens/ProfileFlow/Badges/components/BadgeCard.tsx @@ -1,11 +1,11 @@ // SPDX-License-Identifier: ice License 1.0 import {BadgeType} from '@api/achievements/types'; -import {ImageCardCompact} from '@components/Cards/ImageCardCompact'; import {COLORS} from '@constants/colors'; import {SCREEN_SIDE_OFFSET} from '@constants/styles'; import {Images} from '@images'; import {BadgeProgress} from '@screens/ProfileFlow/Badges/components/BadgeCardProgress'; +import {ImageCardCompact} from '@screens/ProfileFlow/Badges/components/ImageCardCompact'; import {t} from '@translations/i18n'; import {formatNumber} from '@utils/numbers'; import React from 'react'; diff --git a/src/components/Cards/ImageCardCompact.tsx b/src/screens/ProfileFlow/Badges/components/ImageCardCompact.tsx similarity index 100% rename from src/components/Cards/ImageCardCompact.tsx rename to src/screens/ProfileFlow/Badges/components/ImageCardCompact.tsx diff --git a/src/screens/ProfileFlow/Badges/index.tsx b/src/screens/ProfileFlow/Badges/index.tsx index d6b19e6dd..07bcb79e0 100644 --- a/src/screens/ProfileFlow/Badges/index.tsx +++ b/src/screens/ProfileFlow/Badges/index.tsx @@ -1,8 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 import {BadgeType} from '@api/achievements/types'; -import {User} from '@api/user/types'; -import {InviteButton} from '@components/InviteButton'; +import {InviteButton} from '@components/Buttons/InviteButton'; import { SegmentedControl, SegmentedControlMethods, @@ -17,7 +16,7 @@ import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; import {ProfileTabStackParamList} from '@navigation/Main'; import {RouteProp, useRoute} from '@react-navigation/native'; import {BadgeList} from '@screens/ProfileFlow/Badges/components/BadgeList'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import {AchievementsActions} from '@store/modules/Achievements/actions'; import {AchievementsSelectors} from '@store/modules/Achievements/selectors'; import {t} from '@translations/i18n'; @@ -42,7 +41,7 @@ export const Badges = () => { const bottomOffset = useBottomTabBarOffsetStyle(); const route = useRoute>(); - const authUser = useSelector(userSelector) as User; + const authUser = useSelector(unsafeUserSelector); const isOwner = !route.params || route.params.userId === authUser.id; const userId = isOwner ? authUser.id : route.params?.userId || ''; diff --git a/src/screens/ProfileFlow/Profile/components/AvatarHeader/components/ContactsAvatarButton/index.tsx b/src/screens/ProfileFlow/Profile/components/AvatarHeader/components/ContactsAvatarButton/index.tsx new file mode 100644 index 000000000..ffa340164 --- /dev/null +++ b/src/screens/ProfileFlow/Profile/components/AvatarHeader/components/ContactsAvatarButton/index.tsx @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {ContactAvatar} from '@components/ContactAvatar'; +import {Touchable} from '@components/Touchable'; +import {MIDDLE_BUTTON_HIT_SLOP} from '@constants/styles'; +import {font} from '@utils/styles'; +import React from 'react'; +import {StyleSheet, ViewStyle} from 'react-native'; +import {Contact} from 'react-native-contacts'; +import Animated, {AnimatedStyleProp} from 'react-native-reanimated'; +import {rem} from 'rn-units'; + +const AnimatedTouchable = Animated.createAnimatedComponent(Touchable); + +type Props = { + onPress: () => void; + contacts: Contact; + containerStyle?: AnimatedStyleProp; +}; + +const SIZE = rem(30); + +export const ContactsAvatarButton = ({ + onPress, + contacts, + containerStyle, +}: Props) => { + return ( + + + + ); +}; + +const styles = StyleSheet.create({ + lettersAvatar: { + width: SIZE, + height: SIZE, + bottom: -rem(3), + right: -rem(3), + position: 'absolute', + }, + avatarText: { + ...font(13, 16, 'regular'), + }, +}); diff --git a/src/screens/ProfileFlow/Profile/components/AvatarHeader/components/EditAvatarButton/index.tsx b/src/screens/ProfileFlow/Profile/components/AvatarHeader/components/EditAvatarButton/index.tsx new file mode 100644 index 000000000..6f08733f6 --- /dev/null +++ b/src/screens/ProfileFlow/Profile/components/AvatarHeader/components/EditAvatarButton/index.tsx @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Touchable} from '@components/Touchable'; +import {COLORS} from '@constants/colors'; +import {MIDDLE_BUTTON_HIT_SLOP} from '@constants/styles'; +import {PEN_SIZE} from '@screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useAnimatedStyles'; +import {AnimatedCameraIcon} from '@svg/AnimatedCameraIcon'; +import React from 'react'; +import {ActivityIndicator, StyleSheet, ViewStyle} from 'react-native'; +import Animated, {AnimatedStyleProp} from 'react-native-reanimated'; +import {rem} from 'rn-units'; + +const AnimatedTouchable = Animated.createAnimatedComponent(Touchable); + +type Props = { + onPress: () => void; + loading?: boolean; + containerStyle?: AnimatedStyleProp; + iconStyle?: AnimatedStyleProp; +}; + +export const EditAvatarButton = ({ + onPress, + loading, + containerStyle, + iconStyle, +}: Props) => { + return ( + + {loading ? ( + + ) : ( + + )} + + ); +}; + +const styles = StyleSheet.create({ + penWrapper: { + position: 'absolute', + bottom: -rem(10), + right: -rem(10), + alignItems: 'center', + justifyContent: 'center', + width: PEN_SIZE, + height: PEN_SIZE, + borderRadius: PEN_SIZE / 2, + borderColor: COLORS.white, + backgroundColor: COLORS.white, + marginHorizontal: rem(10), + marginVertical: rem(10), + }, +}); diff --git a/src/screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useAnimatedStyles.ts b/src/screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useAnimatedStyles.ts index 3cdedca0f..d6ef6f68a 100644 --- a/src/screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useAnimatedStyles.ts +++ b/src/screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useAnimatedStyles.ts @@ -107,7 +107,7 @@ export const useAnimatedStyles = ({animatedIndex}: Params) => { () => { const opacity = interpolate( animatedIndex.value, - [0, 5], + [0, MAX_SCROLL / 2], [1, 0], Extrapolate.CLAMP, ); diff --git a/src/screens/ProfileFlow/Profile/components/AvatarHeader/index.tsx b/src/screens/ProfileFlow/Profile/components/AvatarHeader/index.tsx index aca4c0c65..b42175415 100644 --- a/src/screens/ProfileFlow/Profile/components/AvatarHeader/index.tsx +++ b/src/screens/ProfileFlow/Profile/components/AvatarHeader/index.tsx @@ -1,33 +1,26 @@ // SPDX-License-Identifier: ice License 1.0 import {User} from '@api/user/types'; -import {ActivityIndicator} from '@components/ActivityIndicator'; import {Avatar, AvatarSkeleton} from '@components/Avatar/Avatar'; -import {ContactAvatar} from '@components/ContactAvatar'; -import {Touchable} from '@components/Touchable'; import {COLORS} from '@constants/colors'; -import { - commonStyles, - MIDDLE_BUTTON_HIT_SLOP, - windowWidth, -} from '@constants/styles'; +import {commonStyles, windowWidth} from '@constants/styles'; import {useActionSheetUpdateAvatar} from '@hooks/useActionSheetUpdateAvatar'; -import {useSafeAreaInsets} from '@hooks/useSafeAreaInsets'; -import {useScrollShadow} from '@hooks/useScrollShadow'; import {useUpdateAvatar} from '@hooks/useUpdateAvatar'; import {HEADER_HEIGHT} from '@navigation/components/Header'; import {BackButton} from '@navigation/components/Header/components/BackButton'; +import {QRCodeShareButton} from '@navigation/components/Header/components/QRCodeShareButton'; import {SettingsButton} from '@navigation/components/Header/components/SettingsButton'; import {ShowPrivacyButton} from '@navigation/components/Header/components/ShowPrivacyButton'; +import {useTopOffsetStyle} from '@navigation/hooks/useTopOffsetStyle'; import {AgendaContactTooltip} from '@screens/ProfileFlow/Profile/components/AvatarHeader/components/AgendaContactTooltip'; +import {ContactsAvatarButton} from '@screens/ProfileFlow/Profile/components/AvatarHeader/components/ContactsAvatarButton'; +import {EditAvatarButton} from '@screens/ProfileFlow/Profile/components/AvatarHeader/components/EditAvatarButton'; import { AVATAR_RADIUS, - PEN_SIZE, useAnimatedStyles, } from '@screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useAnimatedStyles'; import {useUserContactDetails} from '@screens/ProfileFlow/Profile/components/AvatarHeader/hooks/useUserContactDetails'; import {usernameWithPrefixSelector} from '@store/modules/Account/selectors'; -import {AnimatedCameraIcon} from '@svg/AnimatedCameraIcon'; import {font, mirrorTransform} from '@utils/styles'; import React, {memo, useState} from 'react'; import {Image, StyleSheet, View} from 'react-native'; @@ -35,15 +28,10 @@ import Animated, {SharedValue} from 'react-native-reanimated'; import {useSelector} from 'react-redux'; import {rem} from 'rn-units'; -const AnimatedTouchable = Animated.createAnimatedComponent(Touchable); - const NOT_FOUND = require('../../assets/images/notFoundPlaceholder.png'); export const AVATAR_SIZE = rem(122); -const MIN_WIDTH_SIDE_CONTAINERS = rem(80); -const MIN_WIDTH_SMALL_SIDE_CONTAINERS = rem(40); - type Props = { user: User | null; animatedIndex: SharedValue; @@ -53,9 +41,8 @@ type Props = { export const AvatarHeader = memo( ({user, animatedIndex, isOwner, isLoading = false}: Props) => { - const {shadowStyle} = useScrollShadow({translateY: animatedIndex}); - const {top: topInset} = useSafeAreaInsets(); const username = useSelector(usernameWithPrefixSelector); + const topOffset = useTopOffsetStyle(); const uri = user?.profilePictureUrl; @@ -71,11 +58,6 @@ export const AvatarHeader = memo( const {contactDetails} = useUserContactDetails({user}); - const extraPadding = { - paddingTop: topInset, - height: HEADER_HEIGHT + topInset, - }; - const {updateAvatar, updateAvatarLoading} = useUpdateAvatar(); const {localImage, onEditPress} = useActionSheetUpdateAvatar({ @@ -84,18 +66,8 @@ export const AvatarHeader = memo( }); return ( - - - - - + + ) : ( @@ -124,34 +96,21 @@ export const AvatarHeader = memo( )} {isOwner && ( - - {updateAvatarLoading ? ( - - ) : ( - - )} - + loading={updateAvatarLoading} + containerStyle={penAnimatedStyle} + iconStyle={iconAvatarStyle} + /> + )} + {contactDetails && ( + setIsTooltipVisible(state => !state)} + contacts={contactDetails} + containerStyle={lettersAvatarStyle} + /> )} - {contactDetails && ( - setIsTooltipVisible(state => !state)}> - - - - - )} {user && ( + + + - {isOwner && user && user?.hiddenProfileElements?.length && ( - + {isOwner && user?.hiddenProfileElements?.length && ( + )} - {isOwner && user && } + {isOwner && ( + + )} + {isOwner && } - + {contactDetails && isTooltipVisible && !isOwner && ( )} @@ -181,22 +152,16 @@ export const AvatarHeader = memo( ); const styles = StyleSheet.create({ + outerContainer: { + zIndex: 1, + backgroundColor: COLORS.white, + }, container: { height: HEADER_HEIGHT, justifyContent: 'center', flexDirection: 'row', - width: windowWidth, - overflow: 'visible', - backgroundColor: COLORS.white, zIndex: 1000, - ...commonStyles.shadow, - }, - miniAvatarContainer: { - width: AVATAR_SIZE, - height: AVATAR_SIZE, - alignSelf: 'center', - bottom: 0, - position: 'absolute', + width: windowWidth, }, wrapper: { flexDirection: 'row', @@ -205,23 +170,19 @@ const styles = StyleSheet.create({ alignItems: 'center', alignSelf: 'center', }, - rightContainer: { - paddingRight: rem(16), - alignSelf: 'center', - minWidth: MIN_WIDTH_SIDE_CONTAINERS, + navigationContainer: { + position: 'absolute', flexDirection: 'row', - justifyContent: 'space-between', + alignItems: 'center', + right: rem(16), + top: 0, + bottom: 0, }, - rightSmallContainer: { - minWidth: MIN_WIDTH_SMALL_SIDE_CONTAINERS, + navigationContainerLeft: { + left: rem(16), }, - leftContainer: { - paddingLeft: rem(16), - alignSelf: 'center', - minWidth: MIN_WIDTH_SIDE_CONTAINERS, - }, - leftSmallContainer: { - minWidth: MIN_WIDTH_SMALL_SIDE_CONTAINERS, + navigationContainerRight: { + right: rem(16), }, imageContainer: { borderColor: COLORS.foam, @@ -241,35 +202,7 @@ const styles = StyleSheet.create({ justifyContent: 'center', ...mirrorTransform(), }, - touchableAvatar: { - flex: 1, - }, - avatarText: { - ...font(13, 16, 'regular'), - }, - lettersAvatar: { - width: rem(30), - height: rem(30), - bottom: -rem(3), - right: -rem(3), - position: 'absolute', - }, - penWrapper: { - position: 'absolute', - bottom: -rem(10), - right: -rem(10), - alignItems: 'center', - justifyContent: 'center', - width: PEN_SIZE, - height: PEN_SIZE, - borderRadius: PEN_SIZE / 2, - borderColor: COLORS.white, - backgroundColor: COLORS.white, - marginHorizontal: rem(10), - marginVertical: rem(10), - }, - showPrivacyButton: {marginRight: rem(16)}, - touchArea: { - zIndex: 1, + navigationButton: { + marginRight: rem(16), }, }); diff --git a/src/screens/ProfileFlow/Profile/components/Invite/index.tsx b/src/screens/ProfileFlow/Profile/components/Invite/index.tsx index f64256dc0..ee1c3aea6 100644 --- a/src/screens/ProfileFlow/Profile/components/Invite/index.tsx +++ b/src/screens/ProfileFlow/Profile/components/Invite/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {InviteButton} from '@components/InviteButton'; +import {InviteButton} from '@components/Buttons/InviteButton'; import {Touchable} from '@components/Touchable'; import {LINKS} from '@constants/links'; import {SCREEN_SIDE_OFFSET} from '@constants/styles'; diff --git a/src/screens/SettingsFlow/PersonalInformation/index.tsx b/src/screens/SettingsFlow/PersonalInformation/index.tsx index 483bf7dda..7b9fb4811 100644 --- a/src/screens/SettingsFlow/PersonalInformation/index.tsx +++ b/src/screens/SettingsFlow/PersonalInformation/index.tsx @@ -1,9 +1,8 @@ // SPDX-License-Identifier: ice License 1.0 -import {User} from '@api/user/types'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {CommonInput} from '@components/Inputs/CommonInput'; import {KeyboardAvoider} from '@components/KeyboardAvoider'; -import {PrimaryButton} from '@components/PrimaryButton'; import {UserAvatarHeader} from '@components/UserAvatarHeader'; import {COLORS} from '@constants/colors'; import {isChangePhoneNumberEnabled} from '@constants/featureFlags'; @@ -14,7 +13,7 @@ import {useFocusStatusBar} from '@navigation/hooks/useFocusStatusBar'; import {useControlHandlers} from '@screens/SettingsFlow/PersonalInformation/hooks/useControlHandlers'; import {useUpdateAccount} from '@screens/SettingsFlow/PersonalInformation/hooks/useUpdateAccount'; import {useValidateUsername} from '@screens/SettingsFlow/PersonalInformation/hooks/useValidateUsername'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import {EmailIcon} from '@svg/EmailIcon'; import {LocationIcon} from '@svg/LocationIcon'; import {PersonIcon} from '@svg/PersonIcon'; @@ -34,7 +33,7 @@ export const PersonalInformation = memo(() => { useFocusStatusBar({style: 'dark-content'}); const tabbarOffset = useBottomTabBarOffsetStyle(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const { userDraft, diff --git a/src/screens/Staking/components/Footer/index.tsx b/src/screens/Staking/components/Footer/index.tsx index 4631a60a5..74effb923 100644 --- a/src/screens/Staking/components/Footer/index.tsx +++ b/src/screens/Staking/components/Footer/index.tsx @@ -1,8 +1,8 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {CheckBox} from '@components/CheckBox'; import {IceLabel} from '@components/Labels/IceLabel'; -import {PrimaryButton} from '@components/PrimaryButton'; import {COLORS} from '@constants/colors'; import {LINKS} from '@constants/links'; import {STAKING_ALLOCATION_MAX, STAKING_YEARS_MAX} from '@constants/staking'; diff --git a/src/screens/Team/components/Contacts/components/ContactsList/hooks/useContactsListRenderItems.tsx b/src/screens/Team/components/Contacts/components/ContactsList/hooks/useContactsListRenderItems.tsx index df8f2f740..fb771e8b9 100644 --- a/src/screens/Team/components/Contacts/components/ContactsList/hooks/useContactsListRenderItems.tsx +++ b/src/screens/Team/components/Contacts/components/ContactsList/hooks/useContactsListRenderItems.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {InviteButton} from '@components/InviteButton'; +import {InviteButton} from '@components/Buttons/InviteButton'; import {ListItemSkeleton} from '@components/ListItems/ListItemSkeleton'; import {UserListItem} from '@components/ListItems/UserListItem'; import {UserListPingButton} from '@components/ListItems/UserListItem/components/UserListPingButton'; diff --git a/src/screens/Team/components/Contacts/components/ContactsPermissions/components/AllowContactsButton.tsx b/src/screens/Team/components/Contacts/components/ContactsPermissions/components/AllowContactsButton.tsx index ca83877ff..4cedc3a06 100644 --- a/src/screens/Team/components/Contacts/components/ContactsPermissions/components/AllowContactsButton.tsx +++ b/src/screens/Team/components/Contacts/components/ContactsPermissions/components/AllowContactsButton.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton} from '@components/PrimaryButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {PermissionsActions} from '@store/modules/Permissions/actions'; import {AddressBookIcon} from '@svg/AddressBookIcon'; import {t} from '@translations/i18n'; diff --git a/src/screens/Team/components/Contacts/components/ModifyPhoneNumber/hooks/useModifyPhoneNumberWalkthrough.tsx b/src/screens/Team/components/Contacts/components/ModifyPhoneNumber/hooks/useModifyPhoneNumberWalkthrough.tsx index 13fecb0a4..7744c4864 100644 --- a/src/screens/Team/components/Contacts/components/ModifyPhoneNumber/hooks/useModifyPhoneNumberWalkthrough.tsx +++ b/src/screens/Team/components/Contacts/components/ModifyPhoneNumber/hooks/useModifyPhoneNumberWalkthrough.tsx @@ -1,8 +1,8 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {UPDATE_ACCOUNT_FIELD_BUTTON_OFFSET} from '@components/Forms/components/UpdateAccountField'; import {PhoneNumberInput} from '@components/Inputs/PhoneNumberInput'; -import {PrimaryButton} from '@components/PrimaryButton'; import {SCREEN_SIDE_OFFSET} from '@constants/styles'; import {WalkthroughElementContainer} from '@screens/Walkthrough/components/WalkthroughElementContainer'; import {useSetWalkthroughElementData} from '@store/modules/Walkthrough/hooks/useSetWalkthroughElementData'; diff --git a/src/screens/Team/components/TierList/components/EmptyTier/index.tsx b/src/screens/Team/components/TierList/components/EmptyTier/index.tsx index dda1d7c65..06247ef7b 100644 --- a/src/screens/Team/components/TierList/components/EmptyTier/index.tsx +++ b/src/screens/Team/components/TierList/components/EmptyTier/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton} from '@components/PrimaryButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {COLORS} from '@constants/colors'; import {SCREEN_SIDE_OFFSET} from '@constants/styles'; import {MainStackParamList} from '@navigation/Main'; diff --git a/src/screens/Templates/FinalizeRegistrationStep/index.tsx b/src/screens/Templates/FinalizeRegistrationStep/index.tsx index a3e29cf7e..e5992c6a4 100644 --- a/src/screens/Templates/FinalizeRegistrationStep/index.tsx +++ b/src/screens/Templates/FinalizeRegistrationStep/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {BackButton} from '@components/BackButton'; +import {BackButton} from '@components/Buttons/BackButton'; import {KeyboardAvoider} from '@components/KeyboardAvoider'; import {COLORS} from '@constants/colors'; import {smallHeightDevice, windowWidth} from '@constants/styles'; diff --git a/src/screens/WelcomeFlow/ClaimUsername/hooks/useClaimUsername.ts b/src/screens/WelcomeFlow/ClaimUsername/hooks/useClaimUsername.ts index c2c3c9518..853456da2 100644 --- a/src/screens/WelcomeFlow/ClaimUsername/hooks/useClaimUsername.ts +++ b/src/screens/WelcomeFlow/ClaimUsername/hooks/useClaimUsername.ts @@ -2,7 +2,7 @@ import {User} from '@api/user/types'; import {AccountActions} from '@store/modules/Account/actions'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import { failedReasonSelector, isLoadingSelector, @@ -15,7 +15,7 @@ import {wait} from 'rn-units'; export const useClaimUsername = () => { const dispatch = useDispatch(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const validationError = useSelector( failedReasonSelector.bind(null, ValidationActions.USERNAME_VALIDATION), diff --git a/src/screens/WelcomeFlow/ClaimUsername/index.tsx b/src/screens/WelcomeFlow/ClaimUsername/index.tsx index f35638046..bdc41cb32 100644 --- a/src/screens/WelcomeFlow/ClaimUsername/index.tsx +++ b/src/screens/WelcomeFlow/ClaimUsername/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {CommonInput} from '@components/Inputs/CommonInput'; -import {PrimaryButton} from '@components/PrimaryButton'; import {COLORS} from '@constants/colors'; import {SCREEN_SIDE_OFFSET} from '@constants/styles'; import {FinalizeRegistrationStep} from '@screens/Templates/FinalizeRegistrationStep'; diff --git a/src/screens/WelcomeFlow/ConfirmEmailLink/index.tsx b/src/screens/WelcomeFlow/ConfirmEmailLink/index.tsx index ef8cfdd1c..fe5341c31 100644 --- a/src/screens/WelcomeFlow/ConfirmEmailLink/index.tsx +++ b/src/screens/WelcomeFlow/ConfirmEmailLink/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {ResendButton} from '@components/Buttons/ResendButton'; import {CodeInput} from '@components/Inputs/CodeInput'; -import {ResendButton} from '@components/ResendButton'; import {COLORS} from '@constants/colors'; import {FinalizeRegistrationStep} from '@screens/Templates/FinalizeRegistrationStep'; import {BigHeader} from '@screens/Templates/FinalizeRegistrationStep/components/BigHeader'; diff --git a/src/screens/WelcomeFlow/IceBonus/hooks/useIceBonus.ts b/src/screens/WelcomeFlow/IceBonus/hooks/useIceBonus.ts index 382911e63..74ae33532 100644 --- a/src/screens/WelcomeFlow/IceBonus/hooks/useIceBonus.ts +++ b/src/screens/WelcomeFlow/IceBonus/hooks/useIceBonus.ts @@ -2,7 +2,7 @@ import {User} from '@api/user/types'; import {AccountActions} from '@store/modules/Account/actions'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import {AnalyticsActions} from '@store/modules/Analytics/actions'; import {balanceSummarySelector} from '@store/modules/Tokenomics/selectors'; import {isLoadingSelector} from '@store/modules/UtilityProcessStatuses/selectors'; @@ -11,7 +11,7 @@ import {useDispatch, useSelector} from 'react-redux'; export const useIceBonus = () => { const dispatch = useDispatch(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const loading = useSelector( isLoadingSelector.bind(null, AccountActions.UPDATE_ACCOUNT), diff --git a/src/screens/WelcomeFlow/IceBonus/index.tsx b/src/screens/WelcomeFlow/IceBonus/index.tsx index 4f3380ebf..75f3958c9 100644 --- a/src/screens/WelcomeFlow/IceBonus/index.tsx +++ b/src/screens/WelcomeFlow/IceBonus/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {IceLabel} from '@components/Labels/IceLabel'; -import {PrimaryButton} from '@components/PrimaryButton'; import {FinalizeRegistrationStep} from '@screens/Templates/FinalizeRegistrationStep'; import {BigHeader} from '@screens/Templates/FinalizeRegistrationStep/components/BigHeader'; import {CurrentBalance} from '@screens/WelcomeFlow/IceBonus/components/CurrentBalance'; diff --git a/src/screens/WelcomeFlow/Onboarding/components/Controls/index.tsx b/src/screens/WelcomeFlow/Onboarding/components/Controls/index.tsx index 7ab571d35..7bcfbe598 100644 --- a/src/screens/WelcomeFlow/Onboarding/components/Controls/index.tsx +++ b/src/screens/WelcomeFlow/Onboarding/components/Controls/index.tsx @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PrimaryButton} from '@components/PrimaryButton'; +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {Touchable} from '@components/Touchable'; import {COLORS} from '@constants/colors'; import {smallHeightDevice} from '@constants/styles'; diff --git a/src/screens/WelcomeFlow/Onboarding/hooks/useFinishOnboarding.ts b/src/screens/WelcomeFlow/Onboarding/hooks/useFinishOnboarding.ts index e9b28bd30..7ebc4069f 100644 --- a/src/screens/WelcomeFlow/Onboarding/hooks/useFinishOnboarding.ts +++ b/src/screens/WelcomeFlow/Onboarding/hooks/useFinishOnboarding.ts @@ -1,12 +1,11 @@ // SPDX-License-Identifier: ice License 1.0 -import {User} from '@api/user/types'; import { OnboardingSlide, onboardingSlides, } from '@screens/WelcomeFlow/Onboarding/slides'; import {AccountActions} from '@store/modules/Account/actions'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import {PermissionsActions} from '@store/modules/Permissions/actions'; import {canAskPermissionSelector} from '@store/modules/Permissions/selectors'; import {UsersActions} from '@store/modules/Users/actions'; @@ -21,7 +20,7 @@ export const useFinishOnboarding = () => { const [slides, setSlides] = useState([]); const dispatch = useDispatch(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const canAskNotificationPermission = useSelector( canAskPermissionSelector('pushNotifications'), diff --git a/src/screens/WelcomeFlow/SetEmail/hooks/useSetEmail.ts b/src/screens/WelcomeFlow/SetEmail/hooks/useSetEmail.ts index 2762ea0f3..d75361dd1 100644 --- a/src/screens/WelcomeFlow/SetEmail/hooks/useSetEmail.ts +++ b/src/screens/WelcomeFlow/SetEmail/hooks/useSetEmail.ts @@ -6,7 +6,7 @@ import {useNavigation} from '@react-navigation/native'; import {NativeStackNavigationProp} from '@react-navigation/native-stack'; import {DEFAULT_DIALOG_NO_BUTTON} from '@screens/Modals/PopUp/components/PopUpButton'; import {AccountActions} from '@store/modules/Account/actions'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import { failedReasonSelector, isLoadingSelector, @@ -19,7 +19,7 @@ import {useDispatch, useSelector} from 'react-redux'; export const useSetEmail = () => { const dispatch = useDispatch(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const navigation = useNavigation>(); diff --git a/src/screens/WelcomeFlow/SetEmail/index.tsx b/src/screens/WelcomeFlow/SetEmail/index.tsx index b0351fcab..e51dd293b 100644 --- a/src/screens/WelcomeFlow/SetEmail/index.tsx +++ b/src/screens/WelcomeFlow/SetEmail/index.tsx @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {EmailInput} from '@components/Inputs/EmailInput'; -import {PrimaryButton} from '@components/PrimaryButton'; import {FinalizeRegistrationStep} from '@screens/Templates/FinalizeRegistrationStep'; import {BigHeader} from '@screens/Templates/FinalizeRegistrationStep/components/BigHeader'; import {Info} from '@screens/Templates/FinalizeRegistrationStep/components/Info'; diff --git a/src/screens/WelcomeFlow/WhoInvitedYou/components/QRCodeButton.tsx b/src/screens/WelcomeFlow/WhoInvitedYou/components/QRCodeButton.tsx new file mode 100644 index 000000000..fd60dcdea --- /dev/null +++ b/src/screens/WelcomeFlow/WhoInvitedYou/components/QRCodeButton.tsx @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {Touchable} from '@components/Touchable'; +import {COLORS} from '@constants/colors'; +import {SMALL_BUTTON_HIT_SLOP} from '@constants/styles'; +import {WelcomeStackParamList} from '@navigation/Welcome'; +import {useNavigation} from '@react-navigation/native'; +import {NativeStackNavigationProp} from '@react-navigation/native-stack'; +import {QRCodeIcon} from '@svg/QRCodeIcon'; +import {getUsernameFromUsernameLink} from '@utils/username'; +import React from 'react'; +import {Keyboard, StyleSheet} from 'react-native'; +import {rem} from 'rn-units'; + +type Props = { + onUsernameDetect: (content: string) => void; +}; + +export const QRCodeButton = ({onUsernameDetect}: Props) => { + const navigation = + useNavigation>(); + + const onButtonPress = () => { + Keyboard.dismiss(); + navigation.navigate('QRCodeScanner', {onDetect}); + }; + + const onDetect = (content: string) => { + const username = getUsernameFromUsernameLink(content); + if (username) { + onUsernameDetect(username); + } + }; + + return ( + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + marginLeft: rem(10), + }, +}); diff --git a/src/screens/WelcomeFlow/WhoInvitedYou/hooks/useWhoInvitedYou.ts b/src/screens/WelcomeFlow/WhoInvitedYou/hooks/useWhoInvitedYou.ts index 24e88cc94..0a2ac32d6 100644 --- a/src/screens/WelcomeFlow/WhoInvitedYou/hooks/useWhoInvitedYou.ts +++ b/src/screens/WelcomeFlow/WhoInvitedYou/hooks/useWhoInvitedYou.ts @@ -6,7 +6,7 @@ import {useNavigation} from '@react-navigation/native'; import {NativeStackNavigationProp} from '@react-navigation/native-stack'; import {DEFAULT_DIALOG_NO_BUTTON} from '@screens/Modals/PopUp/components/PopUpButton'; import {AccountActions} from '@store/modules/Account/actions'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import { failedReasonSelector, isLoadingSelector, @@ -23,7 +23,7 @@ export const useWhoInvitedYou = () => { const dispatch = useDispatch(); const navigation = useNavigation>(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const updateRefByUsernameError = useSelector( failedReasonSelector.bind(null, AccountActions.UPDATE_REF_BY_USERNAME), diff --git a/src/screens/WelcomeFlow/WhoInvitedYou/index.tsx b/src/screens/WelcomeFlow/WhoInvitedYou/index.tsx index 3c639a37f..68d1875f1 100644 --- a/src/screens/WelcomeFlow/WhoInvitedYou/index.tsx +++ b/src/screens/WelcomeFlow/WhoInvitedYou/index.tsx @@ -1,12 +1,13 @@ // SPDX-License-Identifier: ice License 1.0 +import {PrimaryButton} from '@components/Buttons/PrimaryButton'; import {CommonInput} from '@components/Inputs/CommonInput'; -import {PrimaryButton} from '@components/PrimaryButton'; import {COLORS} from '@constants/colors'; import {SCREEN_SIDE_OFFSET} from '@constants/styles'; import {FinalizeRegistrationStep} from '@screens/Templates/FinalizeRegistrationStep'; import {BigHeader} from '@screens/Templates/FinalizeRegistrationStep/components/BigHeader'; import {Info} from '@screens/Templates/FinalizeRegistrationStep/components/Info'; +import {QRCodeButton} from '@screens/WelcomeFlow/WhoInvitedYou/components/QRCodeButton'; import {useWhoInvitedYou} from '@screens/WelcomeFlow/WhoInvitedYou/hooks/useWhoInvitedYou'; import {ManIcon} from '@svg/ManIcon'; import {t} from '@translations/i18n'; @@ -53,6 +54,7 @@ export const WhoInvitedYou = () => { value={refUsername} errorText={error} validated={isReferralUpdated} + postfix={} style={styles.input} /> } diff --git a/src/services/auth/signin/apple.ts b/src/services/auth/signin/apple.ts index 8c28b9123..41d763d01 100644 --- a/src/services/auth/signin/apple.ts +++ b/src/services/auth/signin/apple.ts @@ -4,7 +4,7 @@ import appleAuth from '@invertase/react-native-apple-authentication'; import {SocialSignInMethod} from '@services/auth/signin/types'; import {t} from '@translations/i18n'; import {checkProp} from '@utils/guards'; -import {removeInvalidUsernameCharacters} from '@utils/string'; +import {removeInvalidUsernameCharacters} from '@utils/username'; export const startAppleSignIn: SocialSignInMethod<{ token: string; diff --git a/src/services/auth/signin/facebook.ts b/src/services/auth/signin/facebook.ts index 4136a5371..7e7fdea98 100644 --- a/src/services/auth/signin/facebook.ts +++ b/src/services/auth/signin/facebook.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: ice License 1.0 import {SocialSignInMethod} from '@services/auth/signin/types'; -import {removeInvalidUsernameCharacters} from '@utils/string'; +import {removeInvalidUsernameCharacters} from '@utils/username'; import { AccessToken, LoginManager, diff --git a/src/services/auth/signin/google.ts b/src/services/auth/signin/google.ts index 7a318862c..e52e7f17f 100644 --- a/src/services/auth/signin/google.ts +++ b/src/services/auth/signin/google.ts @@ -8,7 +8,7 @@ import { import {SocialSignInMethod} from '@services/auth/signin/types'; import {t} from '@translations/i18n'; import {checkProp} from '@utils/guards'; -import {removeInvalidUsernameCharacters} from '@utils/string'; +import {removeInvalidUsernameCharacters} from '@utils/username'; GoogleSignin.configure({ // to be able to receive idToken on Android, we need to pass webClientId diff --git a/src/services/auth/signin/twitter.ts b/src/services/auth/signin/twitter.ts index 5b15f81c3..263041e79 100644 --- a/src/services/auth/signin/twitter.ts +++ b/src/services/auth/signin/twitter.ts @@ -4,7 +4,7 @@ import {ENV} from '@constants/env'; import RNTwitterSignIn from '@react-native-twitter-signin/twitter-signin'; import {SocialSignInMethod} from '@services/auth/signin/types'; import {checkProp} from '@utils/guards'; -import {removeInvalidUsernameCharacters} from '@utils/string'; +import {removeInvalidUsernameCharacters} from '@utils/username'; RNTwitterSignIn.init( ENV.TWITTER_CONSUMER_KEY ?? '', diff --git a/src/services/share/index.ts b/src/services/share/index.ts new file mode 100644 index 000000000..78526885b --- /dev/null +++ b/src/services/share/index.ts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {logError} from '@services/logging'; +import {checkProp} from '@utils/guards'; +// eslint-disable-next-line no-restricted-imports +import Share, { + ShareOptions, + ShareSingleOptions, + Social as SocialType, +} from 'react-native-share'; +import {isAndroid, isIOS} from 'rn-units'; + +export const shareSingle = async (options: ShareSingleOptions) => { + try { + await Share.shareSingle(options); + } catch (error) { + if (isShareProviderNotInstalled(error)) { + return; + } + logError(error); + } +}; + +export const openShareDialog = async (options: ShareOptions) => { + try { + await Share.open({failOnCancel: false, ...options}); + } catch (error) { + logError(error); + } +}; + +const isShareProviderNotInstalled = (error: unknown) => { + if ( + isAndroid && + checkProp(error, 'error') && + typeof error.error === 'string' && + error.error.includes('No Activity found to handle Intent') + ) { + return true; + } else if ( + isIOS && + checkProp(error, 'code') && + error.code === 'ECOM.RNSHARE1' + ) { + return true; + } + return false; +}; + +export const Social = SocialType; diff --git a/src/store/modules/Account/hooks/useUpdateHiddenProfileElements.ts b/src/store/modules/Account/hooks/useUpdateHiddenProfileElements.ts index 69f1529c5..258eab522 100644 --- a/src/store/modules/Account/hooks/useUpdateHiddenProfileElements.ts +++ b/src/store/modules/Account/hooks/useUpdateHiddenProfileElements.ts @@ -2,13 +2,13 @@ import {HiddenProfileElement, User} from '@api/user/types'; import {AccountActions} from '@store/modules/Account/actions'; -import {userSelector} from '@store/modules/Account/selectors'; +import {unsafeUserSelector} from '@store/modules/Account/selectors'; import {isLoadingSelector} from '@store/modules/UtilityProcessStatuses/selectors'; import {useDispatch, useSelector} from 'react-redux'; export const useUpdateHiddenProfileElements = () => { const dispatch = useDispatch(); - const user = useSelector(userSelector) as User; + const user = useSelector(unsafeUserSelector); const loading = useSelector( isLoadingSelector.bind(null, AccountActions.UPDATE_ACCOUNT), diff --git a/src/store/modules/Account/selectors/index.ts b/src/store/modules/Account/selectors/index.ts index 538cd45f6..ad59566c8 100644 --- a/src/store/modules/Account/selectors/index.ts +++ b/src/store/modules/Account/selectors/index.ts @@ -23,6 +23,13 @@ export const authTokenSelector = (state: RootState) => state.account.token; export const userSelector = (state: RootState) => state.account.user; +export const unsafeUserSelector = (state: RootState) => { + if (!state.account.user) { + throw new Error('User is not set'); + } + return state.account.user; +}; + export const appLocaleSelector = (state: RootState): SupportedLocale => { const user = userSelector(state); diff --git a/src/store/modules/Analytics/constants.ts b/src/store/modules/Analytics/constants.ts index 8fb985400..58d57b63f 100644 --- a/src/store/modules/Analytics/constants.ts +++ b/src/store/modules/Analytics/constants.ts @@ -5,7 +5,6 @@ import { NotificationDeliveryChannel, NotificationDomainToggle, } from '@api/devices/types'; -import {SocialType} from '@screens/InviteFlow/InviteShare/components/ShareButton/types'; import {Attributes, trackEvent, trackScreenView} from '@services/analytics'; import {dayjs} from '@services/dayjs'; import {store} from '@store/configureStore'; @@ -55,7 +54,7 @@ export const AnalyticsEventLogger = { trackEvent: (params: {eventName: EventNamesType}) => { trackEvent(params); }, - trackInvite: ({inviteAppType}: {inviteAppType: SocialType}) => { + trackInvite: ({inviteAppType}: {inviteAppType: string}) => { trackEvent({ eventName: EVENT_NAMES.INVITE, eventProps: {App: inviteAppType}, diff --git a/src/store/modules/AppCommon/sagas/intervalUpdates.ts b/src/store/modules/AppCommon/sagas/intervalUpdates.ts index d0d7ba863..0a3ab6d22 100644 --- a/src/store/modules/AppCommon/sagas/intervalUpdates.ts +++ b/src/store/modules/AppCommon/sagas/intervalUpdates.ts @@ -1,9 +1,13 @@ // SPDX-License-Identifier: ice License 1.0 import {APP_AUTO_UPDATE_INTERVAL_SEC} from '@constants/timeouts'; -import {isAuthorizedSelector} from '@store/modules/Account/selectors'; +import { + isAuthorizedSelector, + isRegistrationCompleteSelector, +} from '@store/modules/Account/selectors'; import {AppCommonActions} from '@store/modules/AppCommon/actions'; -import {delay, put, select} from 'redux-saga/effects'; +import {waitForSelector} from '@store/utils/sagas/effects'; +import {call, delay, put, select} from 'redux-saga/effects'; export function* intervalUpdatesSaga() { const isAuthorized: ReturnType = yield select( @@ -11,6 +15,7 @@ export function* intervalUpdatesSaga() { ); if (isAuthorized) { + yield call(waitForSelector, isRegistrationCompleteSelector); while (true) { yield delay(APP_AUTO_UPDATE_INTERVAL_SEC * 1000); yield put(AppCommonActions.INTERVAL_UPDATE.STATE.create()); diff --git a/src/store/modules/Contacts/sagas/inviteContactSaga.ts b/src/store/modules/Contacts/sagas/inviteContactSaga.ts index 30b565887..a34d19a83 100644 --- a/src/store/modules/Contacts/sagas/inviteContactSaga.ts +++ b/src/store/modules/Contacts/sagas/inviteContactSaga.ts @@ -1,12 +1,12 @@ // SPDX-License-Identifier: ice License 1.0 -import {LINKS} from '@constants/links'; import {usernameSelector} from '@store/modules/Account/selectors'; import {ContactsActions} from '@store/modules/Contacts/actions'; import {t} from '@translations/i18n'; import {getContactName} from '@utils/contacts'; import {openSMS} from '@utils/device'; import {getErrorMessage, showError} from '@utils/errors'; +import {buildUsernameLink} from '@utils/username'; import {Contact, getContactById} from 'react-native-contacts'; import {call, put, SagaReturnType, select} from 'redux-saga/effects'; @@ -26,7 +26,7 @@ export function* inviteContactSaga( throw new Error('Contact has no phone numbers'); } - const url = `${LINKS.MAIN}@${username}`; + const url = buildUsernameLink(username); const text = `${t('team.contacts_list.invitation_text', { name: getContactName(contact), diff --git a/src/store/modules/Permissions/actions/index.ts b/src/store/modules/Permissions/actions/index.ts index 7e23ecd52..46e7923ae 100644 --- a/src/store/modules/Permissions/actions/index.ts +++ b/src/store/modules/Permissions/actions/index.ts @@ -1,12 +1,13 @@ // SPDX-License-Identifier: ice License 1.0 -import {PermissionType} from '@store/modules/Permissions/sagas/getPermissionsSaga'; +import {PermissionType} from '@store/modules/Permissions/reducer'; import {createAction} from '@store/utils/actions/createAction'; import {PermissionStatus} from 'react-native-permissions'; export type PermissionsType = { contacts: PermissionStatus; pushNotifications: PermissionStatus; + camera: PermissionStatus; }; const GET_PERMISSIONS = createAction('GET_PERMISSIONS', { diff --git a/src/store/modules/Permissions/reducer/index.ts b/src/store/modules/Permissions/reducer/index.ts index c1ba75dc2..049292bdc 100644 --- a/src/store/modules/Permissions/reducer/index.ts +++ b/src/store/modules/Permissions/reducer/index.ts @@ -7,8 +7,11 @@ import {PermissionStatus} from 'react-native-permissions'; export interface State { contacts: PermissionStatus | null; pushNotifications: PermissionStatus | null; + camera: PermissionStatus | null; } +export type PermissionType = keyof State; + type Actions = ReturnType< | typeof PermissionsActions.GET_PERMISSIONS.SUCCESS.create | typeof PermissionsActions.CHECK_ALL_PERMISSIONS.SUCCESS.create @@ -17,6 +20,7 @@ type Actions = ReturnType< const INITIAL_STATE: State = { contacts: null, pushNotifications: null, + camera: null, }; export function permissionsReducer( diff --git a/src/store/modules/Permissions/sagas/checkAllPermissionsSaga.ts b/src/store/modules/Permissions/sagas/checkAllPermissionsSaga.ts index 79794ae0e..63f877dd3 100644 --- a/src/store/modules/Permissions/sagas/checkAllPermissionsSaga.ts +++ b/src/store/modules/Permissions/sagas/checkAllPermissionsSaga.ts @@ -4,10 +4,7 @@ import {isAppActiveSelector} from '@store/modules/AppCommon/selectors'; import {PermissionsActions} from '@store/modules/Permissions/actions'; import {PERMISSIONS_LIST} from '@store/modules/Permissions/sagas/getPermissionsSaga'; import {getErrorMessage} from '@utils/errors'; -import Permissions, { - checkNotifications, - PermissionStatus, -} from 'react-native-permissions'; +import Permissions, {checkNotifications} from 'react-native-permissions'; import {put, SagaReturnType, select} from 'redux-saga/effects'; export function* checkAllPermissionsSaga() { @@ -15,9 +12,11 @@ export function* checkAllPermissionsSaga() { const isAppActive: boolean = yield select(isAppActiveSelector); if (isAppActive) { - const contacts: PermissionStatus = yield Permissions.check( - PERMISSIONS_LIST.contacts, - ); + const contacts: SagaReturnType = + yield Permissions.check(PERMISSIONS_LIST.contacts); + + const camera: SagaReturnType = + yield Permissions.check(PERMISSIONS_LIST.camera); const pushNotificationsResponse: SagaReturnType< typeof checkNotifications @@ -25,6 +24,7 @@ export function* checkAllPermissionsSaga() { const permissions = { contacts, + camera, pushNotifications: pushNotificationsResponse.status, }; yield put( diff --git a/src/store/modules/Permissions/sagas/getPermissionsSaga.ts b/src/store/modules/Permissions/sagas/getPermissionsSaga.ts index a3971127b..5c5d4f3d8 100644 --- a/src/store/modules/Permissions/sagas/getPermissionsSaga.ts +++ b/src/store/modules/Permissions/sagas/getPermissionsSaga.ts @@ -17,16 +17,16 @@ import {isIOS} from 'rn-units'; const actionCreator = PermissionsActions.GET_PERMISSIONS.START.create; -export type PermissionType = 'contacts' | 'pushNotifications'; - type PermissionsListType = { contacts: Permission; + camera: Permission; }; export const PERMISSIONS_LIST: PermissionsListType = { contacts: isIOS ? PERMISSIONS.IOS.CONTACTS : PERMISSIONS.ANDROID.READ_CONTACTS, + camera: isIOS ? PERMISSIONS.IOS.CAMERA : PERMISSIONS.ANDROID.CAMERA, }; export function* getPermissionsSaga(action: ReturnType) { diff --git a/src/store/modules/Permissions/selectors/index.ts b/src/store/modules/Permissions/selectors/index.ts index 215d32d13..1d64dd5ac 100644 --- a/src/store/modules/Permissions/selectors/index.ts +++ b/src/store/modules/Permissions/selectors/index.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: ice License 1.0 -import {PermissionType} from '@store/modules/Permissions/sagas/getPermissionsSaga'; +import {PermissionType} from '@store/modules/Permissions/reducer'; import {RootState} from '@store/rootReducer'; import {RESULTS} from 'react-native-permissions'; diff --git a/src/store/modules/Validation/sagas/validateRefUsernameSaga.ts b/src/store/modules/Validation/sagas/validateRefUsernameSaga.ts index 16b28ce3a..984105206 100644 --- a/src/store/modules/Validation/sagas/validateRefUsernameSaga.ts +++ b/src/store/modules/Validation/sagas/validateRefUsernameSaga.ts @@ -4,7 +4,7 @@ import {USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH} from '@constants/validations'; import {userSelector} from '@store/modules/Account/selectors'; import {ValidationActions} from '@store/modules/Validation/actions'; import {t} from '@translations/i18n'; -import {validateUsername} from '@utils/string'; +import {validateUsername} from '@utils/username'; import {put, select} from 'redux-saga/effects'; const actionCreator = ValidationActions.REF_USERNAME_VALIDATION.START.create; diff --git a/src/store/modules/Validation/sagas/validateUsernameSaga.ts b/src/store/modules/Validation/sagas/validateUsernameSaga.ts index e74ed7d96..5f0ef05d0 100644 --- a/src/store/modules/Validation/sagas/validateUsernameSaga.ts +++ b/src/store/modules/Validation/sagas/validateUsernameSaga.ts @@ -3,7 +3,7 @@ import {USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH} from '@constants/validations'; import {ValidationActions} from '@store/modules/Validation/actions'; import {t} from '@translations/i18n'; -import {validateUsername} from '@utils/string'; +import {validateUsername} from '@utils/username'; import {put} from 'redux-saga/effects'; const actionCreator = ValidationActions.USERNAME_VALIDATION.START.create; diff --git a/src/translations/locales/en.json b/src/translations/locales/en.json index 40bbf6e88..dc05b5cf9 100644 --- a/src/translations/locales/en.json +++ b/src/translations/locales/en.json @@ -466,7 +466,9 @@ "more": "More", "copied": "COPIED", "share_message": "Hi ☃️ Snowman! Join my team on ice and receive 10 ice coins when you sign-up using my referral code:", - "description": "Spread the word and invite your friends. You earn [[:ice]] for each new referral you bring." + "share_subject": "Join my team on ice", + "description": "Spread the word and invite your friends. You earn [[:ice]] for each new referral you bring.", + "share": "Share" }, "users": { "ping": "PING", @@ -865,5 +867,8 @@ "title": "Notice", "message": "Thanks for your interest in mining [[:bold]]ice![[/:bold]] We are currently fine-tuning our technology and mining isn't available at the moment. This is your chance to focus on building your team and growing your micro-community.", "message_footer": "Stay tuned for updates on our [[:twitter]]Twitter[[/:twitter]] and [[:telegram]]Telegram[[/:telegram]] channels." + }, + "qr_code": { + "description": "Scan QR code to join my team" } } diff --git a/src/translations/locales/en.json.d.ts b/src/translations/locales/en.json.d.ts index 28dd6f200..5f34b2b29 100644 --- a/src/translations/locales/en.json.d.ts +++ b/src/translations/locales/en.json.d.ts @@ -317,7 +317,9 @@ export type Translations = { 'invite_share.more': null; 'invite_share.copied': null; 'invite_share.share_message': null; + 'invite_share.share_subject': null; 'invite_share.description': null; + 'invite_share.share': null; 'users.ping': null; 'users.active': null; 'users.inactive': null; @@ -571,4 +573,5 @@ export type Translations = { 'mining_notice.title': null; 'mining_notice.message': null; 'mining_notice.message_footer': null; + 'qr_code.description': null; }; diff --git a/src/utils/string.ts b/src/utils/string.ts index 10afe6e02..2b75f62fb 100644 --- a/src/utils/string.ts +++ b/src/utils/string.ts @@ -18,13 +18,4 @@ export const stringToColor = (input: string = '') => { return colour; }; -export const removeInvalidUsernameCharacters = (input: string) => { - return input.replace(/[^a-zA-Z0-9.]/g, ''); -}; - -export const validateUsername = (username: string) => { - const validationRegex: RegExp = /^[a-zA-Z0-9.]+$/; - return validationRegex.test(username); -}; - export const extractDigits = (str: string) => str.replace(/\D/g, ''); diff --git a/src/utils/username.ts b/src/utils/username.ts new file mode 100644 index 000000000..5dc967c26 --- /dev/null +++ b/src/utils/username.ts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: ice License 1.0 + +import {LINKS} from '@constants/links'; + +export const removeInvalidUsernameCharacters = (username: string) => { + return username.replace(/[^a-zA-Z0-9.]/g, ''); +}; + +export const validateUsername = (username: string) => { + const validationRegex: RegExp = /^[a-zA-Z0-9.]+$/; + return validationRegex.test(username); +}; + +export const buildUsernameLink = (username: string) => + `${LINKS.MAIN}@${username}`; + +export const getUsernameFromUsernameLink = (usernameLink: string) => + usernameLink.match(`${LINKS.MAIN}@(.+)`)?.[1]; diff --git a/tsconfig.json b/tsconfig.json index 662913874..4d4320e67 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */, - "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */, // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ @@ -55,10 +55,14 @@ "@translations/*": ["src/translations/*"], "@utils/*": ["src/utils/*"], "@store/*": ["src/store/*"], - "@hooks/*": ["src/hooks/*"], + "@hooks/*": ["src/hooks/*"] }, + "moduleSuffixes": [".android", ".ios", ""], // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - "typeRoots": ["./types", "./node_modules/@types"] /* List of folders to include type definitions from. */, + "typeRoots": [ + "./types", + "./node_modules/@types" + ] /* List of folders to include type definitions from. */, // "types": [], /* Type declaration files to be included in compilation. */ "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, diff --git a/yarn.lock b/yarn.lock index b018420a4..e305c8d36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1995,11 +1995,6 @@ resolved "https://registry.yarnpkg.com/@types/i18n-js/-/i18n-js-3.8.3.tgz#9aac0ac81c0b5f16d864b395607442eebb382528" integrity sha512-Y20B7kgoNrchIYCfty20zQYeFFJMHdegwy9VopCEKdByp7Tlv0jtWrfoRb+3r2mIvgrwp/eMwXhhXOBYKEFkTA== -"@types/invariant@^2.2.35": - version "2.2.35" - resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be" - integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg== - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" @@ -2089,6 +2084,13 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/qrcode@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.5.0.tgz#6a98fe9a9a7b2a9a3167b6dde17eff999eabe40b" + integrity sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA== + dependencies: + "@types/node" "*" + "@types/qs@^6.9.7": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -3800,6 +3802,11 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dijkstrajs@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" + integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -3922,6 +3929,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -7655,6 +7667,11 @@ plist@^3.0.5: base64-js "^1.5.1" xmlbuilder "^15.1.1" +pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -7853,6 +7870,16 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== +qrcode@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb" + integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg== + dependencies: + dijkstrajs "^1.0.1" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" + qs@^6.10.2: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -8112,14 +8139,13 @@ react-native-rate@^1.2.12: resolved "https://registry.yarnpkg.com/react-native-rate/-/react-native-rate-1.2.12.tgz#d4307b2994f9c849b987eb65599ec467db4aee04" integrity sha512-A/z3s7Zth08aXcJnru6S4p71NG8acx2w5LhIfItwTJUbQruNJugk8WrN51dLBCSDv8W33kbS5YoUT4M9jOP5gA== -react-native-reanimated@2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.13.0.tgz#d64c1386626822d4dc22094b4efe028ff2c49cc9" - integrity sha512-yUHyYVIegWWIza4+nVyS3CSmI/Mc8kLFVHw2c6gnSHaYhYA4LeEjH/jBkoMzHk9Xd0Ra3cwtjYKAMG8OTp6JVg== +react-native-reanimated@2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-2.15.0.tgz#d795ed8a56f61cdbb3413d07d4dd43f47e161d1e" + integrity sha512-pNbcjIsqB72lsLGr7DvcXl07oovTvQUaBgP6CdkYtogmrCKUMcB+TDe2OjUNPWdzJ9JkgNIZZ1h71LM78H9HrQ== dependencies: "@babel/plugin-transform-object-assign" "^7.16.7" "@babel/preset-typescript" "^7.16.7" - "@types/invariant" "^2.2.35" invariant "^2.2.4" lodash.isequal "^4.5.0" setimmediate "^1.0.5" @@ -8190,6 +8216,16 @@ react-native-swipe-gestures@^1.0.5: resolved "https://registry.yarnpkg.com/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz#a172cb0f3e7478ccd681fd36b8bfbcdd098bde7c" integrity sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw== +react-native-view-shot@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/react-native-view-shot/-/react-native-view-shot-3.6.0.tgz#2c5febd03cb1effb9923372b29aed227c680d9fd" + integrity sha512-QUYGaIaAxQwOTydUzqGMooBwrg455cuOQgTloZ+gPO1QCUuLRdncCqrEMwKW5eUnN5U8JGMKeFRll2m6egOxtA== + +react-native-vision-camera@^2.15.4: + version "2.15.4" + resolved "https://registry.yarnpkg.com/react-native-vision-camera/-/react-native-vision-camera-2.15.4.tgz#821f0505fc8c63b87c1ae4697d2bb4f670333576" + integrity sha512-SJXSWH1pu4V3Kj4UuX/vSgOxc9d5wb5+nHqBHd+5iUtVyVLEp0F6Jbbaha7tDoU+kUBwonhlwr2o8oV6NZ7Ibg== + react-native@0.70.8: version "0.70.8" resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.70.8.tgz#aa9aae8e6291589908db74fe69e0ec1d9a9c5490" @@ -9837,6 +9873,11 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +vision-camera-code-scanner@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/vision-camera-code-scanner/-/vision-camera-code-scanner-0.2.0.tgz#8adc0694319a17f6a95f6dfacc02ab7ac29b4742" + integrity sha512-H5hVkXfbIcGdg9YlhuS8Y/xDX5e32Vo6eK5FyDQsE9AGVjlqEHMmSLHZg7BX8UUm4ADmiAZc8wzc4n8TUqGr0g== + vlq@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468"