Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

(optional) In app browser (#2490)

* add expo web browser + modal

* add in app browser option to settings

* don't show toggle on web

* Tweak browser-choice UIs

---------

Co-authored-by: Samuel Newman <mozzius@protonmail.com>

authored by

Paul Frazee
Samuel Newman
and committed by
GitHub
998ee299 b147f7ae

+299 -22
+1 -1
package.json
··· 113 113 "expo-system-ui": "~2.9.2", 114 114 "expo-task-manager": "~11.7.0", 115 115 "expo-updates": "~0.24.5", 116 + "expo-web-browser": "^12.5.0", 116 117 "fast-text-encoding": "^1.0.6", 117 118 "history": "^5.3.0", 118 119 "js-sha256": "^0.9.0", ··· 148 149 "react-native-get-random-values": "~1.8.0", 149 150 "react-native-haptic-feedback": "^1.14.0", 150 151 "react-native-image-crop-picker": "^0.38.1", 151 - "react-native-inappbrowser-reborn": "^3.6.3", 152 152 "react-native-ios-context-menu": "^1.15.3", 153 153 "react-native-linear-gradient": "^2.6.2", 154 154 "react-native-pager-view": "6.2.2",
+6
src/state/modals/index.tsx
··· 187 187 onAccept: () => void 188 188 } 189 189 190 + export interface InAppBrowserConsentModal { 191 + name: 'in-app-browser-consent' 192 + href: string 193 + } 194 + 190 195 export type Modal = 191 196 // Account 192 197 | AddAppPasswordModal ··· 231 236 | ConfirmModal 232 237 | LinkWarningModal 233 238 | EmbedConsentModal 239 + | InAppBrowserConsentModal 234 240 235 241 const ModalContext = React.createContext<{ 236 242 isModalActive: boolean
+2
src/state/persisted/schema.ts
··· 53 53 step: z.string(), 54 54 }), 55 55 hiddenPosts: z.array(z.string()).optional(), // should move to server 56 + useInAppBrowser: z.boolean().optional(), 56 57 }) 57 58 export type Schema = z.infer<typeof schema> 58 59 ··· 84 85 step: 'Home', 85 86 }, 86 87 hiddenPosts: [], 88 + useInAppBrowser: undefined, 87 89 }
+79
src/state/preferences/in-app-browser.tsx
··· 1 + import React from 'react' 2 + import * as persisted from '#/state/persisted' 3 + import {Linking} from 'react-native' 4 + import * as WebBrowser from 'expo-web-browser' 5 + import {isNative} from '#/platform/detection' 6 + import {useModalControls} from '../modals' 7 + 8 + type StateContext = persisted.Schema['useInAppBrowser'] 9 + type SetContext = (v: persisted.Schema['useInAppBrowser']) => void 10 + 11 + const stateContext = React.createContext<StateContext>( 12 + persisted.defaults.useInAppBrowser, 13 + ) 14 + const setContext = React.createContext<SetContext>( 15 + (_: persisted.Schema['useInAppBrowser']) => {}, 16 + ) 17 + 18 + export function Provider({children}: React.PropsWithChildren<{}>) { 19 + const [state, setState] = React.useState(persisted.get('useInAppBrowser')) 20 + 21 + const setStateWrapped = React.useCallback( 22 + (inAppBrowser: persisted.Schema['useInAppBrowser']) => { 23 + setState(inAppBrowser) 24 + persisted.write('useInAppBrowser', inAppBrowser) 25 + }, 26 + [setState], 27 + ) 28 + 29 + React.useEffect(() => { 30 + return persisted.onUpdate(() => { 31 + setState(persisted.get('useInAppBrowser')) 32 + }) 33 + }, [setStateWrapped]) 34 + 35 + return ( 36 + <stateContext.Provider value={state}> 37 + <setContext.Provider value={setStateWrapped}> 38 + {children} 39 + </setContext.Provider> 40 + </stateContext.Provider> 41 + ) 42 + } 43 + 44 + export function useInAppBrowser() { 45 + return React.useContext(stateContext) 46 + } 47 + 48 + export function useSetInAppBrowser() { 49 + return React.useContext(setContext) 50 + } 51 + 52 + export function useOpenLink() { 53 + const {openModal} = useModalControls() 54 + const enabled = useInAppBrowser() 55 + 56 + const openLink = React.useCallback( 57 + (url: string, override?: boolean) => { 58 + if (isNative && !url.startsWith('mailto:')) { 59 + if (override === undefined && enabled === undefined) { 60 + openModal({ 61 + name: 'in-app-browser-consent', 62 + href: url, 63 + }) 64 + return 65 + } else if (override ?? enabled) { 66 + WebBrowser.openBrowserAsync(url, { 67 + presentationStyle: 68 + WebBrowser.WebBrowserPresentationStyle.FULL_SCREEN, 69 + }) 70 + return 71 + } 72 + } 73 + Linking.openURL(url) 74 + }, 75 + [enabled, openModal], 76 + ) 77 + 78 + return openLink 79 + }
+4 -1
src/state/preferences/index.tsx
··· 3 3 import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required' 4 4 import {Provider as HiddenPostsProvider} from '../preferences/hidden-posts' 5 5 import {Provider as ExternalEmbedsProvider} from './external-embeds-prefs' 6 + import {Provider as InAppBrowserProvider} from './in-app-browser' 6 7 7 8 export {useLanguagePrefs, useLanguagePrefsApi} from './languages' 8 9 export { ··· 20 21 <LanguagesProvider> 21 22 <AltTextRequiredProvider> 22 23 <ExternalEmbedsProvider> 23 - <HiddenPostsProvider>{children}</HiddenPostsProvider> 24 + <HiddenPostsProvider> 25 + <InAppBrowserProvider>{children}</InAppBrowserProvider> 26 + </HiddenPostsProvider> 24 27 </ExternalEmbedsProvider> 25 28 </AltTextRequiredProvider> 26 29 </LanguagesProvider>
+102
src/view/com/modals/InAppBrowserConsent.tsx
··· 1 + import React from 'react' 2 + import {StyleSheet, View} from 'react-native' 3 + 4 + import {s} from 'lib/styles' 5 + import {Text} from '../util/text/Text' 6 + import {Button} from '../util/forms/Button' 7 + import {ScrollView} from './util' 8 + import {usePalette} from 'lib/hooks/usePalette' 9 + 10 + import {msg, Trans} from '@lingui/macro' 11 + import {useLingui} from '@lingui/react' 12 + import {useModalControls} from '#/state/modals' 13 + import { 14 + useOpenLink, 15 + useSetInAppBrowser, 16 + } from '#/state/preferences/in-app-browser' 17 + 18 + export const snapPoints = [350] 19 + 20 + export function Component({href}: {href: string}) { 21 + const pal = usePalette('default') 22 + const {closeModal} = useModalControls() 23 + const {_} = useLingui() 24 + const setInAppBrowser = useSetInAppBrowser() 25 + const openLink = useOpenLink() 26 + 27 + const onUseIAB = React.useCallback(() => { 28 + setInAppBrowser(true) 29 + closeModal() 30 + openLink(href, true) 31 + }, [closeModal, setInAppBrowser, href, openLink]) 32 + 33 + const onUseLinking = React.useCallback(() => { 34 + setInAppBrowser(false) 35 + closeModal() 36 + openLink(href, false) 37 + }, [closeModal, setInAppBrowser, href, openLink]) 38 + 39 + return ( 40 + <ScrollView 41 + testID="inAppBrowserConsentModal" 42 + style={[s.flex1, pal.view, {paddingHorizontal: 20, paddingTop: 10}]}> 43 + <Text style={[pal.text, styles.title]}> 44 + <Trans>How should we open this link?</Trans> 45 + </Text> 46 + <Text style={pal.text}> 47 + <Trans> 48 + Your choice will be saved, but can be changed later in settings. 49 + </Trans> 50 + </Text> 51 + <View style={[styles.btnContainer]}> 52 + <Button 53 + testID="confirmBtn" 54 + type="inverted" 55 + onPress={onUseIAB} 56 + accessibilityLabel={_(msg`Use in-app browser`)} 57 + accessibilityHint="" 58 + label={_(msg`Use in-app browser`)} 59 + labelContainerStyle={{justifyContent: 'center', padding: 8}} 60 + labelStyle={[s.f18]} 61 + /> 62 + <Button 63 + testID="confirmBtn" 64 + type="inverted" 65 + onPress={onUseLinking} 66 + accessibilityLabel={_(msg`Use my default browser`)} 67 + accessibilityHint="" 68 + label={_(msg`Use my default browser`)} 69 + labelContainerStyle={{justifyContent: 'center', padding: 8}} 70 + labelStyle={[s.f18]} 71 + /> 72 + <Button 73 + testID="cancelBtn" 74 + type="default" 75 + onPress={() => { 76 + closeModal() 77 + }} 78 + accessibilityLabel={_(msg`Cancel`)} 79 + accessibilityHint="" 80 + label="Cancel" 81 + labelContainerStyle={{justifyContent: 'center', padding: 8}} 82 + labelStyle={[s.f18]} 83 + /> 84 + </View> 85 + </ScrollView> 86 + ) 87 + } 88 + 89 + const styles = StyleSheet.create({ 90 + title: { 91 + textAlign: 'center', 92 + fontWeight: 'bold', 93 + fontSize: 24, 94 + marginBottom: 12, 95 + }, 96 + btnContainer: { 97 + marginTop: 20, 98 + flexDirection: 'column', 99 + justifyContent: 'center', 100 + rowGap: 10, 101 + }, 102 + })
+4 -2
src/view/com/modals/LinkWarning.tsx
··· 1 1 import React from 'react' 2 - import {Linking, SafeAreaView, StyleSheet, View} from 'react-native' 2 + import {SafeAreaView, StyleSheet, View} from 'react-native' 3 3 import {ScrollView} from './util' 4 4 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 5 5 import {Text} from '../util/text/Text' ··· 12 12 import {Trans, msg} from '@lingui/macro' 13 13 import {useLingui} from '@lingui/react' 14 14 import {useModalControls} from '#/state/modals' 15 + import {useOpenLink} from '#/state/preferences/in-app-browser' 15 16 16 17 export const snapPoints = ['50%'] 17 18 ··· 21 22 const {isMobile} = useWebMediaQueries() 22 23 const {_} = useLingui() 23 24 const potentiallyMisleading = isPossiblyAUrl(text) 25 + const openLink = useOpenLink() 24 26 25 27 const onPressVisit = () => { 26 28 closeModal() 27 - Linking.openURL(href) 29 + openLink(href) 28 30 } 29 31 30 32 return (
+4
src/view/com/modals/Modal.tsx
··· 39 39 import * as SwitchAccountModal from './SwitchAccount' 40 40 import * as LinkWarningModal from './LinkWarning' 41 41 import * as EmbedConsentModal from './EmbedConsent' 42 + import * as InAppBrowserConsentModal from './InAppBrowserConsent' 42 43 43 44 const DEFAULT_SNAPPOINTS = ['90%'] 44 45 const HANDLE_HEIGHT = 24 ··· 180 181 } else if (activeModal?.name === 'embed-consent') { 181 182 snapPoints = EmbedConsentModal.snapPoints 182 183 element = <EmbedConsentModal.Component {...activeModal} /> 184 + } else if (activeModal?.name === 'in-app-browser-consent') { 185 + snapPoints = InAppBrowserConsentModal.snapPoints 186 + element = <InAppBrowserConsentModal.Component {...activeModal} /> 183 187 } else { 184 188 return null 185 189 }
+9 -3
src/view/com/util/Link.tsx
··· 1 1 import React, {ComponentProps, memo, useMemo} from 'react' 2 2 import { 3 - Linking, 4 3 GestureResponderEvent, 5 4 Platform, 6 5 StyleProp, ··· 31 30 import {PressableWithHover} from './PressableWithHover' 32 31 import FixedTouchableHighlight from '../pager/FixedTouchableHighlight' 33 32 import {useModalControls} from '#/state/modals' 33 + import {useOpenLink} from '#/state/preferences/in-app-browser' 34 34 35 35 type Event = 36 36 | React.MouseEvent<HTMLAnchorElement, MouseEvent> ··· 65 65 const {closeModal} = useModalControls() 66 66 const navigation = useNavigation<NavigationProp>() 67 67 const anchorHref = asAnchor ? sanitizeUrl(href) : undefined 68 + const openLink = useOpenLink() 68 69 69 70 const onPress = React.useCallback( 70 71 (e?: Event) => { ··· 74 75 navigation, 75 76 sanitizeUrl(href), 76 77 navigationAction, 78 + openLink, 77 79 e, 78 80 ) 79 81 } 80 82 }, 81 - [closeModal, navigation, navigationAction, href], 83 + [closeModal, navigation, navigationAction, href, openLink], 82 84 ) 83 85 84 86 if (noFeedback) { ··· 172 174 const {...props} = useLinkProps({to: sanitizeUrl(href)}) 173 175 const navigation = useNavigation<NavigationProp>() 174 176 const {openModal, closeModal} = useModalControls() 177 + const openLink = useOpenLink() 175 178 176 179 if (warnOnMismatchingLabel && typeof text !== 'string') { 177 180 console.error('Unable to detect mismatching label') ··· 200 203 navigation, 201 204 sanitizeUrl(href), 202 205 navigationAction, 206 + openLink, 203 207 e, 204 208 ) 205 209 }, ··· 212 216 text, 213 217 warnOnMismatchingLabel, 214 218 navigationAction, 219 + openLink, 215 220 ], 216 221 ) 217 222 const hrefAttrs = useMemo(() => { ··· 317 322 navigation: NavigationProp, 318 323 href: string, 319 324 navigationAction: 'push' | 'replace' | 'navigate' = 'push', 325 + openLink: (href: string) => void, 320 326 e?: Event, 321 327 ) { 322 328 let shouldHandle = false ··· 345 351 if (shouldHandle) { 346 352 href = convertBskyAppUrlIfNeeded(href) 347 353 if (newTab || href.startsWith('http') || href.startsWith('mailto')) { 348 - Linking.openURL(href) 354 + openLink(href) 349 355 } else { 350 356 closeModal() // close any active modals 351 357
+18
src/view/screens/Settings.tsx
··· 70 70 import {useQueryClient} from '@tanstack/react-query' 71 71 import {useLoggedOutViewControls} from '#/state/shell/logged-out' 72 72 import {useCloseAllActiveElements} from '#/state/util' 73 + import { 74 + useInAppBrowser, 75 + useSetInAppBrowser, 76 + } from '#/state/preferences/in-app-browser' 77 + import {isNative} from '#/platform/detection' 73 78 74 79 function SettingsAccountCard({account}: {account: SessionAccount}) { 75 80 const pal = usePalette('default') ··· 146 151 const setMinimalShellMode = useSetMinimalShellMode() 147 152 const requireAltTextEnabled = useRequireAltTextEnabled() 148 153 const setRequireAltTextEnabled = useSetRequireAltTextEnabled() 154 + const inAppBrowserPref = useInAppBrowser() 155 + const setUseInAppBrowser = useSetInAppBrowser() 149 156 const onboardingDispatch = useOnboardingDispatch() 150 157 const navigation = useNavigation<NavigationProp>() 151 158 const {isMobile} = useWebMediaQueries() ··· 658 665 <Trans>Change handle</Trans> 659 666 </Text> 660 667 </TouchableOpacity> 668 + {isNative && ( 669 + <View style={[pal.view, styles.toggleCard]}> 670 + <ToggleButton 671 + type="default-light" 672 + label={_(msg`Open links with in-app browser`)} 673 + labelType="lg" 674 + isSelected={inAppBrowserPref ?? false} 675 + onPress={() => setUseInAppBrowser(!inAppBrowserPref)} 676 + /> 677 + </View> 678 + )} 661 679 <View style={styles.spacer20} /> 662 680 <Text type="xl-bold" style={[pal.text, styles.heading]}> 663 681 <Trans>Danger Zone</Trans>
+70 -15
yarn.lock
··· 9583 9583 resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" 9584 9584 integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== 9585 9585 9586 + compare-urls@^2.0.0: 9587 + version "2.0.0" 9588 + resolved "https://registry.yarnpkg.com/compare-urls/-/compare-urls-2.0.0.tgz#9b378c4abd43980a8700fffec9afb85de4df9075" 9589 + integrity sha512-eCJcWn2OYFEIqbm70ta7LQowJOOZZqq1a2YbbFCFI1uwSvj+TWMwXVn7vPR1ceFNcAIt5RSTDbwdlX82gYLTkA== 9590 + dependencies: 9591 + normalize-url "^2.0.1" 9592 + 9586 9593 component-type@^1.2.1: 9587 9594 version "1.2.1" 9588 9595 resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" ··· 10136 10143 resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" 10137 10144 integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== 10138 10145 10139 - decode-uri-component@^0.2.2: 10146 + decode-uri-component@^0.2.0, decode-uri-component@^0.2.2: 10140 10147 version "0.2.2" 10141 10148 resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" 10142 10149 integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== ··· 11687 11694 fbemitter "^3.0.0" 11688 11695 resolve-from "^5.0.0" 11689 11696 11697 + expo-web-browser@^12.5.0: 11698 + version "12.5.0" 11699 + resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-12.5.0.tgz#69949c50ef0ef8d2889435ed9e595206cfbcf68b" 11700 + integrity sha512-3uDzP19DqcEicLOB4ZH6pGWzxlCQ8mLHSmWMmfXEBhZjooUkHUrysbzkNvQQa24ijy3uoUybX4jW0xPss594kA== 11701 + dependencies: 11702 + compare-urls "^2.0.0" 11703 + url "^0.11.0" 11704 + 11690 11705 expo@^50.0.0-preview.7: 11691 11706 version "50.0.0-preview.7" 11692 11707 resolved "https://registry.yarnpkg.com/expo/-/expo-50.0.0-preview.7.tgz#d4ac7a9aad0a5e9f03a31b8794e186a1af741edc" ··· 13340 13355 version "3.0.3" 13341 13356 resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 13342 13357 integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 13358 + 13359 + is-plain-obj@^1.0.0: 13360 + version "1.1.0" 13361 + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" 13362 + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== 13343 13363 13344 13364 is-plain-obj@^2.1.0: 13345 13365 version "2.1.0" ··· 16139 16159 resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" 16140 16160 integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== 16141 16161 16162 + normalize-url@^2.0.1: 16163 + version "2.0.1" 16164 + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" 16165 + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== 16166 + dependencies: 16167 + prepend-http "^2.0.0" 16168 + query-string "^5.0.1" 16169 + sort-keys "^2.0.0" 16170 + 16142 16171 normalize-url@^6.0.1: 16143 16172 version "6.1.0" 16144 16173 resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" ··· 16407 16436 define-lazy-prop "^2.0.0" 16408 16437 is-docker "^2.1.1" 16409 16438 is-wsl "^2.2.0" 16410 - 16411 - opencollective-postinstall@^2.0.3: 16412 - version "2.0.3" 16413 - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" 16414 - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== 16415 16439 16416 16440 optionator@^0.9.3: 16417 16441 version "0.9.3" ··· 17572 17596 resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" 17573 17597 integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== 17574 17598 17599 + prepend-http@^2.0.0: 17600 + version "2.0.0" 17601 + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" 17602 + integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== 17603 + 17575 17604 prettier-linter-helpers@^1.0.0: 17576 17605 version "1.0.0" 17577 17606 resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" ··· 17906 17935 end-of-stream "^1.1.0" 17907 17936 once "^1.3.1" 17908 17937 17938 + punycode@^1.4.1: 17939 + version "1.4.1" 17940 + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 17941 + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== 17942 + 17909 17943 punycode@^2.1.0, punycode@^2.1.1: 17910 17944 version "2.3.0" 17911 17945 resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" ··· 17933 17967 dependencies: 17934 17968 side-channel "^1.0.4" 17935 17969 17936 - qs@^6.5.1: 17970 + qs@^6.11.2, qs@^6.5.1: 17937 17971 version "6.11.2" 17938 17972 resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" 17939 17973 integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== 17940 17974 dependencies: 17941 17975 side-channel "^1.0.4" 17976 + 17977 + query-string@^5.0.1: 17978 + version "5.1.1" 17979 + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" 17980 + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== 17981 + dependencies: 17982 + decode-uri-component "^0.2.0" 17983 + object-assign "^4.1.0" 17984 + strict-uri-encode "^1.0.0" 17942 17985 17943 17986 query-string@^7.1.3: 17944 17987 version "7.1.3" ··· 18178 18221 resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.38.1.tgz#5973b4a8b55835b987e6be2064de411e849ac005" 18179 18222 integrity sha512-cF5UQnWplzHCeiCO+aiGS/0VomWaLmFf3nSsgTMPfY+8+99h8N/eHQvVdSF7RsGw50B8394wGeGyqHjjp8YRWw== 18180 18223 18181 - react-native-inappbrowser-reborn@^3.6.3: 18182 - version "3.7.0" 18183 - resolved "https://registry.yarnpkg.com/react-native-inappbrowser-reborn/-/react-native-inappbrowser-reborn-3.7.0.tgz#849a43c3c7da22b65147649fe596836bcb494083" 18184 - integrity sha512-Ia53jYNtFcbNaX5W3QfOmN25I7bcvuDiQmSY5zABXjy4+WI20bPc9ua09li55F8yDCjv3C99jX6vKms68mBV7g== 18185 - dependencies: 18186 - invariant "^2.2.4" 18187 - opencollective-postinstall "^2.0.3" 18188 - 18189 18224 react-native-ios-context-menu@^1.15.3: 18190 18225 version "1.15.3" 18191 18226 resolved "https://registry.yarnpkg.com/react-native-ios-context-menu/-/react-native-ios-context-menu-1.15.3.tgz#c02e6a7af2df8c08d0b3e1c8f3395484b3c9c760" ··· 19454 19489 dependencies: 19455 19490 atomic-sleep "^1.0.0" 19456 19491 19492 + sort-keys@^2.0.0: 19493 + version "2.0.0" 19494 + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" 19495 + integrity sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg== 19496 + dependencies: 19497 + is-plain-obj "^1.0.0" 19498 + 19457 19499 source-list-map@^2.0.0, source-list-map@^2.0.1: 19458 19500 version "2.0.1" 19459 19501 resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" ··· 19679 19721 fast-fifo "^1.1.0" 19680 19722 queue-tick "^1.0.1" 19681 19723 19724 + strict-uri-encode@^1.0.0: 19725 + version "1.1.0" 19726 + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" 19727 + integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== 19728 + 19682 19729 strict-uri-encode@^2.0.0: 19683 19730 version "2.0.0" 19684 19731 resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" ··· 20757 20804 dependencies: 20758 20805 querystringify "^2.1.1" 20759 20806 requires-port "^1.0.0" 20807 + 20808 + url@^0.11.0: 20809 + version "0.11.3" 20810 + resolved "https://registry.yarnpkg.com/url/-/url-0.11.3.tgz#6f495f4b935de40ce4a0a52faee8954244f3d3ad" 20811 + integrity sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw== 20812 + dependencies: 20813 + punycode "^1.4.1" 20814 + qs "^6.11.2" 20760 20815 20761 20816 use-callback-ref@^1.3.0: 20762 20817 version "1.3.0"