diff options
Diffstat (limited to 'src/view/com')
48 files changed, 252 insertions, 189 deletions
diff --git a/src/view/com/auth/create/Step2.tsx b/src/view/com/auth/create/Step2.tsx index 60e197564..b2054150b 100644 --- a/src/view/com/auth/create/Step2.tsx +++ b/src/view/com/auth/create/Step2.tsx @@ -10,8 +10,8 @@ import {usePalette} from 'lib/hooks/usePalette' import {TextInput} from '../util/TextInput' import {Policies} from './Policies' import {ErrorMessage} from 'view/com/util/error/ErrorMessage' -import {useStores} from 'state/index' import {isWeb} from 'platform/detection' +import {useModalControls} from '#/state/modals' /** STEP 2: Your account * @field Invite code or waitlist @@ -28,11 +28,11 @@ export const Step2 = observer(function Step2Impl({ model: CreateAccountModel }) { const pal = usePalette('default') - const store = useStores() + const {openModal} = useModalControls() const onPressWaitlist = React.useCallback(() => { - store.shell.openModal({name: 'waitlist'}) - }, [store]) + openModal({name: 'waitlist'}) + }, [openModal]) return ( <View> diff --git a/src/view/com/auth/login/Login.tsx b/src/view/com/auth/login/Login.tsx index acc05b6ca..24a657c66 100644 --- a/src/view/com/auth/login/Login.tsx +++ b/src/view/com/auth/login/Login.tsx @@ -31,6 +31,7 @@ import {useTheme} from 'lib/ThemeContext' import {cleanError} from 'lib/strings/errors' import {isWeb} from 'platform/detection' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' enum Forms { Login, @@ -303,9 +304,10 @@ const LoginForm = ({ const [identifier, setIdentifier] = useState<string>(initialHandle) const [password, setPassword] = useState<string>('') const passwordInputRef = useRef<TextInput>(null) + const {openModal} = useModalControls() const onPressSelectService = () => { - store.shell.openModal({ + openModal({ name: 'server-input', initialService: serviceUrl, onSelect: setServiceUrl, @@ -528,7 +530,6 @@ const LoginForm = ({ } const ForgotPasswordForm = ({ - store, error, serviceUrl, serviceDescription, @@ -551,13 +552,14 @@ const ForgotPasswordForm = ({ const [isProcessing, setIsProcessing] = useState<boolean>(false) const [email, setEmail] = useState<string>('') const {screen} = useAnalytics() + const {openModal} = useModalControls() useEffect(() => { screen('Signin:ForgotPassword') }, [screen]) const onPressSelectService = () => { - store.shell.openModal({ + openModal({ name: 'server-input', initialService: serviceUrl, onSelect: setServiceUrl, diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 632e72fde..68f706828 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -49,6 +49,7 @@ import {LabelsBtn} from './labels/LabelsBtn' import {SelectLangBtn} from './select-language/SelectLangBtn' import {EmojiPickerButton} from './text-input/web/EmojiPicker.web' import {insertMentionAt} from 'lib/strings/mention-manip' +import {useModals, useModalControls} from '#/state/modals' import {useRequireAltTextEnabled} from '#/state/preferences' import { useLanguagePrefs, @@ -64,6 +65,8 @@ export const ComposePost = observer(function ComposePost({ quote: initQuote, mention: initMention, }: Props) { + const {activeModals} = useModals() + const {openModal, closeModal} = useModalControls() const {track} = useAnalytics() const pal = usePalette('default') const {isDesktop, isMobile} = useWebMediaQueries() @@ -118,18 +121,18 @@ export const ComposePost = observer(function ComposePost({ const onPressCancel = useCallback(() => { if (graphemeLength > 0 || !gallery.isEmpty) { - if (store.shell.activeModals.some(modal => modal.name === 'confirm')) { - store.shell.closeModal() + if (activeModals.some(modal => modal.name === 'confirm')) { + closeModal() } if (Keyboard) { Keyboard.dismiss() } - store.shell.openModal({ + openModal({ name: 'confirm', title: 'Discard draft', onPressConfirm: onClose, onPressCancel: () => { - store.shell.closeModal() + closeModal() }, message: "Are you sure you'd like to discard this draft?", confirmBtnText: 'Discard', @@ -138,7 +141,7 @@ export const ComposePost = observer(function ComposePost({ } else { onClose() } - }, [store, onClose, graphemeLength, gallery]) + }, [openModal, closeModal, activeModals, onClose, graphemeLength, gallery]) // android back button useEffect(() => { if (!isAndroid) { diff --git a/src/view/com/composer/labels/LabelsBtn.tsx b/src/view/com/composer/labels/LabelsBtn.tsx index 96908d47f..4b6ad81c7 100644 --- a/src/view/com/composer/labels/LabelsBtn.tsx +++ b/src/view/com/composer/labels/LabelsBtn.tsx @@ -3,11 +3,11 @@ import {Keyboard, StyleSheet} from 'react-native' import {observer} from 'mobx-react-lite' import {Button} from 'view/com/util/forms/Button' import {usePalette} from 'lib/hooks/usePalette' -import {useStores} from 'state/index' import {ShieldExclamation} from 'lib/icons' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome' import {isNative} from 'platform/detection' +import {useModalControls} from '#/state/modals' export const LabelsBtn = observer(function LabelsBtn({ labels, @@ -19,7 +19,7 @@ export const LabelsBtn = observer(function LabelsBtn({ onChange: (v: string[]) => void }) { const pal = usePalette('default') - const store = useStores() + const {openModal} = useModalControls() return ( <Button @@ -34,7 +34,7 @@ export const LabelsBtn = observer(function LabelsBtn({ Keyboard.dismiss() } } - store.shell.openModal({name: 'self-label', labels, hasMedia, onChange}) + openModal({name: 'self-label', labels, hasMedia, onChange}) }}> <ShieldExclamation style={pal.link} size={26} /> {labels.length > 0 ? ( diff --git a/src/view/com/composer/photos/Gallery.tsx b/src/view/com/composer/photos/Gallery.tsx index fcd99842a..069a05475 100644 --- a/src/view/com/composer/photos/Gallery.tsx +++ b/src/view/com/composer/photos/Gallery.tsx @@ -7,11 +7,11 @@ import {s, colors} from 'lib/styles' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {Image} from 'expo-image' import {Text} from 'view/com/util/text/Text' -import {openAltTextModal} from 'lib/media/alt-text' import {Dimensions} from 'lib/media/types' -import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useModalControls} from '#/state/modals' +import {isNative} from 'platform/detection' const IMAGE_GAP = 8 @@ -47,9 +47,9 @@ const GalleryInner = observer(function GalleryImpl({ gallery, containerInfo, }: GalleryInnerProps) { - const store = useStores() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() + const {openModal} = useModalControls() let side: number @@ -117,7 +117,10 @@ const GalleryInner = observer(function GalleryImpl({ accessibilityHint="" onPress={() => { Keyboard.dismiss() - openAltTextModal(store, image) + openModal({ + name: 'alt-text-image', + image, + }) }} style={[styles.altTextControl, altTextControlStyle]}> <Text style={styles.altTextControlLabel} accessible={false}> @@ -137,7 +140,17 @@ const GalleryInner = observer(function GalleryImpl({ accessibilityRole="button" accessibilityLabel="Edit image" accessibilityHint="" - onPress={() => gallery.edit(image)} + onPress={() => { + if (isNative) { + gallery.crop(image) + } else { + openModal({ + name: 'edit-image', + image, + gallery, + }) + } + }} style={styles.imageControl}> <FontAwesomeIcon icon="pen" @@ -165,7 +178,10 @@ const GalleryInner = observer(function GalleryImpl({ accessibilityHint="" onPress={() => { Keyboard.dismiss() - openAltTextModal(store, image) + openModal({ + name: 'alt-text-image', + image, + }) }} style={styles.altTextHiddenRegion} /> diff --git a/src/view/com/composer/select-language/SelectLangBtn.tsx b/src/view/com/composer/select-language/SelectLangBtn.tsx index 646542387..6c45f3384 100644 --- a/src/view/com/composer/select-language/SelectLangBtn.tsx +++ b/src/view/com/composer/select-language/SelectLangBtn.tsx @@ -12,9 +12,9 @@ import { DropdownItemButton, } from 'view/com/util/forms/DropdownButton' import {usePalette} from 'lib/hooks/usePalette' -import {useStores} from 'state/index' import {isNative} from 'platform/detection' import {codeToLanguageName} from '../../../../locale/helpers' +import {useModalControls} from '#/state/modals' import { useLanguagePrefs, useSetLanguagePrefs, @@ -24,7 +24,7 @@ import { export const SelectLangBtn = observer(function SelectLangBtn() { const pal = usePalette('default') - const store = useStores() + const {openModal} = useModalControls() const langPrefs = useLanguagePrefs() const setLangPrefs = useSetLanguagePrefs() @@ -34,8 +34,8 @@ export const SelectLangBtn = observer(function SelectLangBtn() { Keyboard.dismiss() } } - store.shell.openModal({name: 'post-languages-settings'}) - }, [store]) + openModal({name: 'post-languages-settings'}) + }, [openModal]) const postLanguagesPref = toPostLanguages(langPrefs.postLanguage) const items: DropdownItem[] = useMemo(() => { diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx index 2c4335dc1..63af52619 100644 --- a/src/view/com/feeds/FeedSourceCard.tsx +++ b/src/view/com/feeds/FeedSourceCard.tsx @@ -10,12 +10,12 @@ import {observer} from 'mobx-react-lite' import {FeedSourceModel} from 'state/models/content/feed-source' import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' -import {useStores} from 'state/index' import {pluralize} from 'lib/strings/helpers' import {AtUri} from '@atproto/api' import * as Toast from 'view/com/util/Toast' import {sanitizeHandle} from 'lib/strings/handles' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' export const FeedSourceCard = observer(function FeedSourceCardImpl({ item, @@ -30,13 +30,13 @@ export const FeedSourceCard = observer(function FeedSourceCardImpl({ showDescription?: boolean showLikes?: boolean }) { - const store = useStores() const pal = usePalette('default') const navigation = useNavigation<NavigationProp>() + const {openModal} = useModalControls() const onToggleSaved = React.useCallback(async () => { if (item.isSaved) { - store.shell.openModal({ + openModal({ name: 'confirm', title: 'Remove from my feeds', message: `Remove ${item.displayName} from my feeds?`, @@ -59,7 +59,7 @@ export const FeedSourceCard = observer(function FeedSourceCardImpl({ logger.error('Failed to save feed', {error: e}) } } - }, [store, item]) + }, [openModal, item]) return ( <Pressable diff --git a/src/view/com/lists/ListItems.tsx b/src/view/com/lists/ListItems.tsx index 192cdd9d3..3658e5522 100644 --- a/src/view/com/lists/ListItems.tsx +++ b/src/view/com/lists/ListItems.tsx @@ -17,11 +17,11 @@ import {Button} from '../util/forms/Button' import {ListModel} from 'state/models/content/list' import {useAnalytics} from 'lib/analytics/analytics' import {usePalette} from 'lib/hooks/usePalette' -import {useStores} from 'state/index' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {s} from 'lib/styles' import {OnScrollCb} from 'lib/hooks/useOnMainScroll' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' const LOADING_ITEM = {_reactKey: '__loading__'} const EMPTY_ITEM = {_reactKey: '__empty__'} @@ -54,10 +54,10 @@ export const ListItems = observer(function ListItemsImpl({ desktopFixedHeightOffset?: number }) { const pal = usePalette('default') - const store = useStores() const {track} = useAnalytics() const [isRefreshing, setIsRefreshing] = React.useState(false) const {isMobile} = useWebMediaQueries() + const {openModal} = useModalControls() const data = React.useMemo(() => { let items: any[] = [] @@ -115,7 +115,7 @@ export const ListItems = observer(function ListItemsImpl({ const onPressEditMembership = React.useCallback( (profile: AppBskyActorDefs.ProfileViewBasic) => { - store.shell.openModal({ + openModal({ name: 'user-add-remove-lists', subject: profile.did, displayName: profile.displayName || profile.handle, @@ -131,7 +131,7 @@ export const ListItems = observer(function ListItemsImpl({ }, }) }, - [store, list], + [openModal, list], ) // rendering diff --git a/src/view/com/modals/AddAppPasswords.tsx b/src/view/com/modals/AddAppPasswords.tsx index 29763620f..621c61b90 100644 --- a/src/view/com/modals/AddAppPasswords.tsx +++ b/src/view/com/modals/AddAppPasswords.tsx @@ -13,6 +13,7 @@ import { import Clipboard from '@react-native-clipboard/clipboard' import * as Toast from '../util/Toast' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' export const snapPoints = ['70%'] @@ -54,6 +55,7 @@ const shadesOfBlue: string[] = [ export function Component({}: {}) { const pal = usePalette('default') const store = useStores() + const {closeModal} = useModalControls() const [name, setName] = useState( shadesOfBlue[Math.floor(Math.random() * shadesOfBlue.length)], ) @@ -69,8 +71,8 @@ export function Component({}: {}) { }, [appPassword]) const onDone = React.useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) const createAppPassword = async () => { // if name is all whitespace, we don't allow it diff --git a/src/view/com/modals/AltImage.tsx b/src/view/com/modals/AltImage.tsx index c084e84a3..9c377a121 100644 --- a/src/view/com/modals/AltImage.tsx +++ b/src/view/com/modals/AltImage.tsx @@ -17,9 +17,9 @@ import {MAX_ALT_TEXT} from 'lib/constants' import {useTheme} from 'lib/ThemeContext' import {Text} from '../util/text/Text' import LinearGradient from 'react-native-linear-gradient' -import {useStores} from 'state/index' import {isAndroid, isWeb} from 'platform/detection' import {ImageModel} from 'state/models/media/image' +import {useModalControls} from '#/state/modals' export const snapPoints = ['fullscreen'] @@ -29,10 +29,10 @@ interface Props { export function Component({image}: Props) { const pal = usePalette('default') - const store = useStores() const theme = useTheme() const [altText, setAltText] = useState(image.altText) const windim = useWindowDimensions() + const {closeModal} = useModalControls() const imageStyles = useMemo<ImageStyle>(() => { const maxWidth = isWeb ? 450 : windim.width @@ -53,11 +53,11 @@ export function Component({image}: Props) { const onPressSave = useCallback(() => { image.setAltText(altText) - store.shell.closeModal() - }, [store, image, altText]) + closeModal() + }, [closeModal, image, altText]) const onPressCancel = () => { - store.shell.closeModal() + closeModal() } return ( diff --git a/src/view/com/modals/BirthDateSettings.tsx b/src/view/com/modals/BirthDateSettings.tsx index 6927ba8d2..7b0778f83 100644 --- a/src/view/com/modals/BirthDateSettings.tsx +++ b/src/view/com/modals/BirthDateSettings.tsx @@ -15,12 +15,14 @@ import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {cleanError} from 'lib/strings/errors' +import {useModalControls} from '#/state/modals' export const snapPoints = ['50%'] export const Component = observer(function Component({}: {}) { const pal = usePalette('default') const store = useStores() + const {closeModal} = useModalControls() const [date, setDate] = useState<Date>( store.preferences.birthDate || new Date(), ) @@ -33,7 +35,7 @@ export const Component = observer(function Component({}: {}) { setIsProcessing(true) try { await store.preferences.setBirthDate(date) - store.shell.closeModal() + closeModal() } catch (e) { setError(cleanError(String(e))) } finally { diff --git a/src/view/com/modals/ChangeEmail.tsx b/src/view/com/modals/ChangeEmail.tsx index 012570556..ec37aeede 100644 --- a/src/view/com/modals/ChangeEmail.tsx +++ b/src/view/com/modals/ChangeEmail.tsx @@ -12,6 +12,7 @@ import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {cleanError} from 'lib/strings/errors' +import {useModalControls} from '#/state/modals' enum Stages { InputEmail, @@ -32,6 +33,7 @@ export const Component = observer(function Component({}: {}) { const [isProcessing, setIsProcessing] = useState<boolean>(false) const [error, setError] = useState<string>('') const {isMobile} = useWebMediaQueries() + const {openModal, closeModal} = useModalControls() const onRequestChange = async () => { if (email === store.session.currentSession?.email) { @@ -90,8 +92,8 @@ export const Component = observer(function Component({}: {}) { } const onVerify = async () => { - store.shell.closeModal() - store.shell.openModal({name: 'verify-email'}) + closeModal() + openModal({name: 'verify-email'}) } return ( @@ -207,7 +209,7 @@ export const Component = observer(function Component({}: {}) { <Button testID="cancelBtn" type="default" - onPress={() => store.shell.closeModal()} + onPress={() => closeModal()} accessibilityLabel="Cancel" accessibilityHint="" label="Cancel" diff --git a/src/view/com/modals/ChangeHandle.tsx b/src/view/com/modals/ChangeHandle.tsx index c54c1c043..6184cb3b7 100644 --- a/src/view/com/modals/ChangeHandle.tsx +++ b/src/view/com/modals/ChangeHandle.tsx @@ -22,6 +22,7 @@ import {useTheme} from 'lib/ThemeContext' import {useAnalytics} from 'lib/analytics/analytics' import {cleanError} from 'lib/strings/errors' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' export const snapPoints = ['100%'] @@ -30,6 +31,7 @@ export function Component({onChanged}: {onChanged: () => void}) { const [error, setError] = useState<string>('') const pal = usePalette('default') const {track} = useAnalytics() + const {closeModal} = useModalControls() const [isProcessing, setProcessing] = useState<boolean>(false) const [retryDescribeTrigger, setRetryDescribeTrigger] = React.useState<any>( @@ -85,8 +87,8 @@ export function Component({onChanged}: {onChanged: () => void}) { // events // = const onPressCancel = React.useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) const onPressRetryConnect = React.useCallback( () => setRetryDescribeTrigger({}), [setRetryDescribeTrigger], @@ -110,7 +112,7 @@ export function Component({onChanged}: {onChanged: () => void}) { await store.agent.updateHandle({ handle: newHandle, }) - store.shell.closeModal() + closeModal() onChanged() } catch (err: any) { setError(cleanError(err)) @@ -127,6 +129,7 @@ export function Component({onChanged}: {onChanged: () => void}) { isCustom, onChanged, track, + closeModal, ]) // rendering diff --git a/src/view/com/modals/Confirm.tsx b/src/view/com/modals/Confirm.tsx index c1324b1cb..6b942057b 100644 --- a/src/view/com/modals/Confirm.tsx +++ b/src/view/com/modals/Confirm.tsx @@ -6,13 +6,13 @@ import { View, } from 'react-native' import {Text} from '../util/text/Text' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {ErrorMessage} from '../util/error/ErrorMessage' import {cleanError} from 'lib/strings/errors' import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' -import type {ConfirmModal} from 'state/models/ui/shell' +import type {ConfirmModal} from '#/state/modals' +import {useModalControls} from '#/state/modals' export const snapPoints = ['50%'] @@ -26,7 +26,7 @@ export function Component({ cancelBtnText, }: ConfirmModal) { const pal = usePalette('default') - const store = useStores() + const {closeModal} = useModalControls() const [isProcessing, setIsProcessing] = useState<boolean>(false) const [error, setError] = useState<string>('') const onPress = async () => { @@ -34,7 +34,7 @@ export function Component({ setIsProcessing(true) try { await onPressConfirm() - store.shell.closeModal() + closeModal() return } catch (e: any) { setError(cleanError(e)) diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx index 9075d0272..0891a6473 100644 --- a/src/view/com/modals/ContentFilteringSettings.tsx +++ b/src/view/com/modals/ContentFilteringSettings.tsx @@ -16,6 +16,7 @@ import {isIOS} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import * as Toast from '../util/Toast' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' export const snapPoints = ['90%'] @@ -24,14 +25,15 @@ export const Component = observer( const store = useStores() const {isMobile} = useWebMediaQueries() const pal = usePalette('default') + const {closeModal} = useModalControls() React.useEffect(() => { store.preferences.sync() }, [store]) const onPressDone = React.useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) return ( <View testID="contentFilteringModal" style={[pal.view, styles.container]}> @@ -89,8 +91,9 @@ const AdultContentEnabledPref = observer( function AdultContentEnabledPrefImpl() { const store = useStores() const pal = usePalette('default') + const {openModal} = useModalControls() - const onSetAge = () => store.shell.openModal({name: 'birth-date-settings'}) + const onSetAge = () => openModal({name: 'birth-date-settings'}) const onToggleAdultContent = async () => { if (isIOS) { diff --git a/src/view/com/modals/CreateOrEditList.tsx b/src/view/com/modals/CreateOrEditList.tsx index 1ea12695f..cdad37770 100644 --- a/src/view/com/modals/CreateOrEditList.tsx +++ b/src/view/com/modals/CreateOrEditList.tsx @@ -24,6 +24,7 @@ import {useTheme} from 'lib/ThemeContext' import {useAnalytics} from 'lib/analytics/analytics' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {cleanError, isNetworkError} from 'lib/strings/errors' +import {useModalControls} from '#/state/modals' const MAX_NAME = 64 // todo const MAX_DESCRIPTION = 300 // todo @@ -40,6 +41,7 @@ export function Component({ list?: ListModel }) { const store = useStores() + const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() const [error, setError] = useState<string>('') const pal = usePalette('default') @@ -67,8 +69,8 @@ export function Component({ const [newAvatar, setNewAvatar] = useState<RNImage | undefined | null>() const onPressCancel = useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) const onSelectNewAvatar = useCallback( async (img: RNImage | null) => { @@ -123,7 +125,7 @@ export function Component({ Toast.show(`${purposeLabel} list created`) onSave?.(res.uri) } - store.shell.closeModal() + closeModal() } catch (e: any) { if (isNetworkError(e)) { setError( @@ -141,6 +143,7 @@ export function Component({ error, onSave, store, + closeModal, activePurpose, isCurateList, purposeLabel, diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx index 50a4cd603..9a8a8b4b0 100644 --- a/src/view/com/modals/DeleteAccount.tsx +++ b/src/view/com/modals/DeleteAccount.tsx @@ -17,6 +17,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {ErrorMessage} from '../util/error/ErrorMessage' import {cleanError} from 'lib/strings/errors' import {resetToTab} from '../../../Navigation' +import {useModalControls} from '#/state/modals' export const snapPoints = ['60%'] @@ -24,6 +25,7 @@ export function Component({}: {}) { const pal = usePalette('default') const theme = useTheme() const store = useStores() + const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false) const [confirmCode, setConfirmCode] = React.useState<string>('') @@ -55,14 +57,14 @@ export function Component({}: {}) { Toast.show('Your account has been deleted') resetToTab('HomeTab') store.session.clear() - store.shell.closeModal() + closeModal() } catch (e: any) { setError(cleanError(e)) } setIsProcessing(false) } const onCancel = () => { - store.shell.closeModal() + closeModal() } return ( <View style={[styles.container, pal.view]}> diff --git a/src/view/com/modals/EditImage.tsx b/src/view/com/modals/EditImage.tsx index dcb6668c7..a2a458f4c 100644 --- a/src/view/com/modals/EditImage.tsx +++ b/src/view/com/modals/EditImage.tsx @@ -6,7 +6,6 @@ import {gradients, s} from 'lib/styles' import {useTheme} from 'lib/ThemeContext' import {Text} from '../util/text/Text' import LinearGradient from 'react-native-linear-gradient' -import {useStores} from 'state/index' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import ImageEditor, {Position} from 'react-avatar-editor' import {TextInput} from './util' @@ -19,6 +18,7 @@ import {Slider} from '@miblanchard/react-native-slider' import {MaterialIcons} from '@expo/vector-icons' import {observer} from 'mobx-react-lite' import {getKeys} from 'lib/type-assertions' +import {useModalControls} from '#/state/modals' export const snapPoints = ['80%'] @@ -52,9 +52,9 @@ export const Component = observer(function EditImageImpl({ }: Props) { const pal = usePalette('default') const theme = useTheme() - const store = useStores() const windowDimensions = useWindowDimensions() const {isMobile} = useWebMediaQueries() + const {closeModal} = useModalControls() const { aspectRatio, @@ -128,8 +128,8 @@ export const Component = observer(function EditImageImpl({ }, [image]) const onCloseModal = useCallback(() => { - store.shell.closeModal() - }, [store.shell]) + closeModal() + }, [closeModal]) const onPressCancel = useCallback(async () => { await gallery.previous(image) diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx index dfd5305f5..f08bb2326 100644 --- a/src/view/com/modals/EditProfile.tsx +++ b/src/view/com/modals/EditProfile.tsx @@ -13,7 +13,6 @@ import LinearGradient from 'react-native-linear-gradient' import {Image as RNImage} from 'react-native-image-crop-picker' import {Text} from '../util/text/Text' import {ErrorMessage} from '../util/error/ErrorMessage' -import {useStores} from 'state/index' import {ProfileModel} from 'state/models/content/profile' import {s, colors, gradients} from 'lib/styles' import {enforceLen} from 'lib/strings/helpers' @@ -27,6 +26,7 @@ import {useAnalytics} from 'lib/analytics/analytics' import {cleanError, isNetworkError} from 'lib/strings/errors' import Animated, {FadeOut} from 'react-native-reanimated' import {isWeb} from 'platform/detection' +import {useModalControls} from '#/state/modals' const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity) @@ -40,11 +40,11 @@ export function Component({ profileView: ProfileModel onUpdate?: () => void }) { - const store = useStores() const [error, setError] = useState<string>('') const pal = usePalette('default') const theme = useTheme() const {track} = useAnalytics() + const {closeModal} = useModalControls() const [isProcessing, setProcessing] = useState<boolean>(false) const [displayName, setDisplayName] = useState<string>( @@ -66,7 +66,7 @@ export function Component({ RNImage | undefined | null >() const onPressCancel = () => { - store.shell.closeModal() + closeModal() } const onSelectNewAvatar = useCallback( async (img: RNImage | null) => { @@ -123,7 +123,7 @@ export function Component({ ) Toast.show('Profile updated') onUpdate?.() - store.shell.closeModal() + closeModal() } catch (e: any) { if (isNetworkError(e)) { setError( @@ -141,7 +141,7 @@ export function Component({ error, profileView, onUpdate, - store, + closeModal, displayName, description, newUserAvatar, diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx index a8aa164c3..227b25275 100644 --- a/src/view/com/modals/InviteCodes.tsx +++ b/src/view/com/modals/InviteCodes.tsx @@ -15,6 +15,7 @@ import {ScrollView} from './util' import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useModalControls} from '#/state/modals' import {useInvitesState, useInvitesAPI} from '#/state/invites' import {UserInfoText} from '../util/UserInfoText' import {makeProfileLink} from '#/lib/routes/links' @@ -25,11 +26,12 @@ export const snapPoints = ['70%'] export function Component({}: {}) { const pal = usePalette('default') const store = useStores() + const {closeModal} = useModalControls() const {isTabletOrDesktop} = useWebMediaQueries() const onClose = React.useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) if (store.me.invites.length === 0) { return ( diff --git a/src/view/com/modals/LinkWarning.tsx b/src/view/com/modals/LinkWarning.tsx index 67a156af4..751c69b3f 100644 --- a/src/view/com/modals/LinkWarning.tsx +++ b/src/view/com/modals/LinkWarning.tsx @@ -5,12 +5,12 @@ import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Text} from '../util/text/Text' import {Button} from '../util/forms/Button' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {isPossiblyAUrl, splitApexDomain} from 'lib/strings/url-helpers' +import {useModalControls} from '#/state/modals' export const snapPoints = ['50%'] @@ -22,12 +22,12 @@ export const Component = observer(function Component({ href: string }) { const pal = usePalette('default') - const store = useStores() + const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() const potentiallyMisleading = isPossiblyAUrl(text) const onPressVisit = () => { - store.shell.closeModal() + closeModal() Linking.openURL(href) } @@ -83,7 +83,7 @@ export const Component = observer(function Component({ <Button testID="cancelBtn" type="default" - onPress={() => store.shell.closeModal()} + onPress={() => closeModal()} accessibilityLabel="Cancel" accessibilityHint="" label="Cancel" diff --git a/src/view/com/modals/ListAddUser.tsx b/src/view/com/modals/ListAddUser.tsx index a04e2d186..8864ebc78 100644 --- a/src/view/com/modals/ListAddUser.tsx +++ b/src/view/com/modals/ListAddUser.tsx @@ -26,6 +26,7 @@ import {cleanError} from 'lib/strings/errors' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {HITSLOP_20} from '#/lib/constants' +import {useModalControls} from '#/state/modals' export const snapPoints = ['90%'] @@ -38,6 +39,7 @@ export const Component = observer(function Component({ }) { const pal = usePalette('default') const store = useStores() + const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() const [query, setQuery] = useState('') const autocompleteView = useMemo<UserAutocompleteModel>( @@ -146,7 +148,7 @@ export const Component = observer(function Component({ <Button testID="doneBtn" type="default" - onPress={() => store.shell.closeModal()} + onPress={() => closeModal()} accessibilityLabel="Done" accessibilityHint="" label="Done" diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 5aaa09e87..c1999c5d6 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -3,13 +3,13 @@ import {StyleSheet} from 'react-native' import {SafeAreaView, useSafeAreaInsets} from 'react-native-safe-area-context' import {observer} from 'mobx-react-lite' import BottomSheet from '@gorhom/bottom-sheet' -import {useStores} from 'state/index' import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' import {usePalette} from 'lib/hooks/usePalette' import {timeout} from 'lib/async/timeout' import {navigate} from '../../../Navigation' import once from 'lodash.once' +import {useModals, useModalControls} from '#/state/modals' import * as ConfirmModal from './Confirm' import * as EditProfileModal from './EditProfile' import * as ProfilePreviewModal from './ProfilePreview' @@ -41,17 +41,17 @@ const DEFAULT_SNAPPOINTS = ['90%'] const HANDLE_HEIGHT = 24 export const ModalsContainer = observer(function ModalsContainer() { - const store = useStores() + const {isModalActive, activeModals} = useModals() + const {closeModal} = useModalControls() const bottomSheetRef = useRef<BottomSheet>(null) const pal = usePalette('default') const safeAreaInsets = useSafeAreaInsets() - const activeModal = - store.shell.activeModals[store.shell.activeModals.length - 1] + const activeModal = activeModals[activeModals.length - 1] const navigateOnce = once(navigate) - const onBottomSheetAnimate = (fromIndex: number, toIndex: number) => { + const onBottomSheetAnimate = (_fromIndex: number, toIndex: number) => { if (activeModal?.name === 'profile-preview' && toIndex === 1) { // begin loading the profile screen behind the scenes navigateOnce('Profile', {name: activeModal.did}) @@ -59,7 +59,7 @@ export const ModalsContainer = observer(function ModalsContainer() { } const onBottomSheetChange = async (snapPoint: number) => { if (snapPoint === -1) { - store.shell.closeModal() + closeModal() } else if (activeModal?.name === 'profile-preview' && snapPoint === 1) { await navigateOnce('Profile', {name: activeModal.did}) // There is no particular callback for when the view has actually been presented. @@ -67,21 +67,21 @@ export const ModalsContainer = observer(function ModalsContainer() { // It's acceptable because the data is already being fetched + it usually takes longer anyway. // TODO: Figure out why avatar/cover don't always show instantly from cache. await timeout(200) - store.shell.closeModal() + closeModal() } } const onClose = () => { bottomSheetRef.current?.close() - store.shell.closeModal() + closeModal() } useEffect(() => { - if (store.shell.isModalActive) { + if (isModalActive) { bottomSheetRef.current?.expand() } else { bottomSheetRef.current?.close() } - }, [store.shell.isModalActive, bottomSheetRef, activeModal?.name]) + }, [isModalActive, bottomSheetRef, activeModal?.name]) let needsSafeTopInset = false let snapPoints: (string | number)[] = DEFAULT_SNAPPOINTS @@ -184,12 +184,12 @@ export const ModalsContainer = observer(function ModalsContainer() { snapPoints={snapPoints} topInset={topInset} handleHeight={HANDLE_HEIGHT} - index={store.shell.isModalActive ? 0 : -1} + index={isModalActive ? 0 : -1} enablePanDownToClose android_keyboardInputMode="adjustResize" keyboardBlurBehavior="restore" backdropComponent={ - store.shell.isModalActive ? createCustomBackdrop(onClose) : undefined + isModalActive ? createCustomBackdrop(onClose) : undefined } handleIndicatorStyle={{backgroundColor: pal.text.color}} handleStyle={[styles.handle, pal.view]} diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx index ede845378..65c4ee444 100644 --- a/src/view/com/modals/Modal.web.tsx +++ b/src/view/com/modals/Modal.web.tsx @@ -1,11 +1,11 @@ import React from 'react' import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native' import {observer} from 'mobx-react-lite' -import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import type {Modal as ModalIface} from 'state/models/ui/shell' +import type {Modal as ModalIface} from '#/state/modals' +import {useModals, useModalControls} from '#/state/modals' import * as ConfirmModal from './Confirm' import * as EditProfileModal from './EditProfile' import * as ProfilePreviewModal from './ProfilePreview' @@ -34,15 +34,15 @@ import * as ChangeEmailModal from './ChangeEmail' import * as LinkWarningModal from './LinkWarning' export const ModalsContainer = observer(function ModalsContainer() { - const store = useStores() + const {isModalActive, activeModals} = useModals() - if (!store.shell.isModalActive) { + if (!isModalActive) { return null } return ( <> - {store.shell.activeModals.map((modal, i) => ( + {activeModals.map((modal, i) => ( <Modal key={`modal-${i}`} modal={modal} /> ))} </> @@ -50,11 +50,12 @@ export const ModalsContainer = observer(function ModalsContainer() { }) function Modal({modal}: {modal: ModalIface}) { - const store = useStores() + const {isModalActive} = useModals() + const {closeModal} = useModalControls() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() - if (!store.shell.isModalActive) { + if (!isModalActive) { return null } @@ -62,7 +63,7 @@ function Modal({modal}: {modal: ModalIface}) { if (modal.name === 'crop-image' || modal.name === 'edit-image') { return // dont close on mask presses during crop } - store.shell.closeModal() + closeModal() } const onInnerPress = () => { // TODO: can we use prevent default? diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx index c01312d69..35ddfe2a1 100644 --- a/src/view/com/modals/ModerationDetails.tsx +++ b/src/view/com/modals/ModerationDetails.tsx @@ -1,7 +1,6 @@ import React from 'react' import {StyleSheet, View} from 'react-native' import {ModerationUI} from '@atproto/api' -import {useStores} from 'state/index' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {s} from 'lib/styles' import {Text} from '../util/text/Text' @@ -10,6 +9,7 @@ import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {listUriToHref} from 'lib/strings/url-helpers' import {Button} from '../util/forms/Button' +import {useModalControls} from '#/state/modals' export const snapPoints = [300] @@ -20,7 +20,7 @@ export function Component({ context: 'account' | 'content' moderation: ModerationUI }) { - const store = useStores() + const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() const pal = usePalette('default') @@ -99,10 +99,7 @@ export function Component({ {description} </Text> <View style={s.flex1} /> - <Button - type="primary" - style={styles.btn} - onPress={() => store.shell.closeModal()}> + <Button type="primary" style={styles.btn} onPress={() => closeModal()}> <Text type="button-lg" style={[pal.textLight, s.textCenter, s.white]}> Okay </Text> diff --git a/src/view/com/modals/Repost.tsx b/src/view/com/modals/Repost.tsx index b1862ecbd..13728b62b 100644 --- a/src/view/com/modals/Repost.tsx +++ b/src/view/com/modals/Repost.tsx @@ -1,12 +1,12 @@ import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' -import {useStores} from 'state/index' import {s, colors, gradients} from 'lib/styles' import {Text} from '../util/text/Text' import {usePalette} from 'lib/hooks/usePalette' import {RepostIcon} from 'lib/icons' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {useModalControls} from '#/state/modals' export const snapPoints = [250] @@ -20,10 +20,10 @@ export function Component({ isReposted: boolean // TODO: Add author into component }) { - const store = useStores() const pal = usePalette('default') + const {closeModal} = useModalControls() const onPress = async () => { - store.shell.closeModal() + closeModal() } return ( diff --git a/src/view/com/modals/SelfLabel.tsx b/src/view/com/modals/SelfLabel.tsx index 820f2895b..242b6a38a 100644 --- a/src/view/com/modals/SelfLabel.tsx +++ b/src/view/com/modals/SelfLabel.tsx @@ -2,7 +2,6 @@ import React, {useState} from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {observer} from 'mobx-react-lite' import {Text} from '../util/text/Text' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -10,6 +9,7 @@ import {isWeb} from 'platform/detection' import {Button} from '../util/forms/Button' import {SelectableBtn} from '../util/forms/SelectableBtn' import {ScrollView} from 'view/com/modals/util' +import {useModalControls} from '#/state/modals' const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn'] @@ -25,7 +25,7 @@ export const Component = observer(function Component({ onChange: (labels: string[]) => void }) { const pal = usePalette('default') - const store = useStores() + const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() const [selected, setSelected] = useState(labels) @@ -143,7 +143,7 @@ export const Component = observer(function Component({ <TouchableOpacity testID="confirmBtn" onPress={() => { - store.shell.closeModal() + closeModal() }} style={styles.btn} accessibilityRole="button" diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx index 13b21fe22..0f8db30b6 100644 --- a/src/view/com/modals/ServerInput.tsx +++ b/src/view/com/modals/ServerInput.tsx @@ -6,26 +6,26 @@ import { } from '@fortawesome/react-native-fontawesome' import {ScrollView, TextInput} from './util' import {Text} from '../util/text/Text' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' import {LOCAL_DEV_SERVICE, STAGING_SERVICE, PROD_SERVICE} from 'state/index' import {LOGIN_INCLUDE_DEV_SERVERS} from 'lib/build-flags' +import {useModalControls} from '#/state/modals' export const snapPoints = ['80%'] export function Component({onSelect}: {onSelect: (url: string) => void}) { const theme = useTheme() const pal = usePalette('default') - const store = useStores() const [customUrl, setCustomUrl] = useState<string>('') + const {closeModal} = useModalControls() const doSelect = (url: string) => { if (!url.startsWith('http://') && !url.startsWith('https://')) { url = `https://${url}` } - store.shell.closeModal() + closeModal() onSelect(url) } diff --git a/src/view/com/modals/UserAddRemoveLists.tsx b/src/view/com/modals/UserAddRemoveLists.tsx index aeec2e87f..f86e88439 100644 --- a/src/view/com/modals/UserAddRemoveLists.tsx +++ b/src/view/com/modals/UserAddRemoveLists.tsx @@ -21,6 +21,7 @@ import {usePalette} from 'lib/hooks/usePalette' import {isWeb, isAndroid} from 'platform/detection' import isEqual from 'lodash.isequal' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' export const snapPoints = ['fullscreen'] @@ -36,6 +37,7 @@ export const Component = observer(function UserAddRemoveListsImpl({ onRemove?: (listUri: string) => void }) { const store = useStores() + const {closeModal} = useModalControls() const pal = usePalette('default') const palPrimary = usePalette('primary') const palInverted = usePalette('inverted') @@ -69,8 +71,8 @@ export const Component = observer(function UserAddRemoveListsImpl({ }, [memberships, listsList, store, setSelected, setMembershipsLoaded]) const onPressCancel = useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) const onPressSave = useCallback(async () => { let changes @@ -87,8 +89,8 @@ export const Component = observer(function UserAddRemoveListsImpl({ for (const uri of changes.removed) { onRemove?.(uri) } - store.shell.closeModal() - }, [store, selected, memberships, onAdd, onRemove]) + closeModal() + }, [closeModal, selected, memberships, onAdd, onRemove]) const onToggleSelected = useCallback( (uri: string) => { diff --git a/src/view/com/modals/VerifyEmail.tsx b/src/view/com/modals/VerifyEmail.tsx index 9fe8811b0..3adaffb14 100644 --- a/src/view/com/modals/VerifyEmail.tsx +++ b/src/view/com/modals/VerifyEmail.tsx @@ -20,6 +20,7 @@ import {usePalette} from 'lib/hooks/usePalette' import {isWeb} from 'platform/detection' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {cleanError} from 'lib/strings/errors' +import {useModalControls} from '#/state/modals' export const snapPoints = ['90%'] @@ -43,6 +44,7 @@ export const Component = observer(function Component({ const [isProcessing, setIsProcessing] = useState<boolean>(false) const [error, setError] = useState<string>('') const {isMobile} = useWebMediaQueries() + const {openModal, closeModal} = useModalControls() const onSendEmail = async () => { setError('') @@ -67,7 +69,7 @@ export const Component = observer(function Component({ }) store.session.updateLocalAccountData({emailConfirmed: true}) Toast.show('Email verified') - store.shell.closeModal() + closeModal() } catch (e) { setError(cleanError(String(e))) } finally { @@ -76,8 +78,8 @@ export const Component = observer(function Component({ } const onEmailIncorrect = () => { - store.shell.closeModal() - store.shell.openModal({name: 'change-email'}) + closeModal() + openModal({name: 'change-email'}) } return ( @@ -224,7 +226,7 @@ export const Component = observer(function Component({ <Button testID="cancelBtn" type="default" - onPress={() => store.shell.closeModal()} + onPress={() => closeModal()} accessibilityLabel={ stage === Stages.Reminder ? 'Not right now' : 'Cancel' } diff --git a/src/view/com/modals/Waitlist.tsx b/src/view/com/modals/Waitlist.tsx index 0fb371fe4..219bdc583 100644 --- a/src/view/com/modals/Waitlist.tsx +++ b/src/view/com/modals/Waitlist.tsx @@ -12,19 +12,19 @@ import { } from '@fortawesome/react-native-fontawesome' import LinearGradient from 'react-native-linear-gradient' import {Text} from '../util/text/Text' -import {useStores} from 'state/index' import {s, gradients} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' import {ErrorMessage} from '../util/error/ErrorMessage' import {cleanError} from 'lib/strings/errors' +import {useModalControls} from '#/state/modals' export const snapPoints = ['80%'] export function Component({}: {}) { const pal = usePalette('default') const theme = useTheme() - const store = useStores() + const {closeModal} = useModalControls() const [email, setEmail] = React.useState<string>('') const [isEmailSent, setIsEmailSent] = React.useState<boolean>(false) const [isProcessing, setIsProcessing] = React.useState<boolean>(false) @@ -54,7 +54,7 @@ export function Component({}: {}) { setIsProcessing(false) } const onCancel = () => { - store.shell.closeModal() + closeModal() } return ( diff --git a/src/view/com/modals/crop-image/CropImage.web.tsx b/src/view/com/modals/crop-image/CropImage.web.tsx index 8e35201d1..c88d002a9 100644 --- a/src/view/com/modals/crop-image/CropImage.web.tsx +++ b/src/view/com/modals/crop-image/CropImage.web.tsx @@ -7,10 +7,10 @@ import {Text} from 'view/com/util/text/Text' import {Dimensions} from 'lib/media/types' import {getDataUriSize} from 'lib/media/util' import {s, gradients} from 'lib/styles' -import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {SquareIcon, RectWideIcon, RectTallIcon} from 'lib/icons' import {Image as RNImage} from 'react-native-image-crop-picker' +import {useModalControls} from '#/state/modals' enum AspectRatio { Square = 'square', @@ -33,7 +33,7 @@ export function Component({ uri: string onSelect: (img?: RNImage) => void }) { - const store = useStores() + const {closeModal} = useModalControls() const pal = usePalette('default') const [as, setAs] = React.useState<AspectRatio>(AspectRatio.Square) const [scale, setScale] = React.useState<number>(1) @@ -43,7 +43,7 @@ export function Component({ const onPressCancel = () => { onSelect(undefined) - store.shell.closeModal() + closeModal() } const onPressDone = () => { const canvas = editorRef.current?.getImageScaledToCanvas() @@ -59,7 +59,7 @@ export function Component({ } else { onSelect(undefined) } - store.shell.closeModal() + closeModal() } let cropperStyle diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx index 659245616..d37d51e47 100644 --- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx @@ -1,7 +1,6 @@ import React from 'react' import {StyleSheet, View} from 'react-native' import {ScrollView} from '../util' -import {useStores} from 'state/index' import {Text} from '../../util/text/Text' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -9,6 +8,7 @@ import {deviceLocales} from 'platform/detection' import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' import {LanguageToggle} from './LanguageToggle' import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' +import {useModalControls} from '#/state/modals' import { useLanguagePrefs, useSetLanguagePrefs, @@ -18,14 +18,14 @@ import { export const snapPoints = ['100%'] export function Component({}: {}) { - const store = useStores() + const {closeModal} = useModalControls() const langPrefs = useLanguagePrefs() const setLangPrefs = useSetLanguagePrefs() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const onPressDone = React.useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) const languages = React.useMemo(() => { const langs = LANGUAGES.filter( diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx index 435fb9e1a..4a39da752 100644 --- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx @@ -2,7 +2,6 @@ import React from 'react' import {StyleSheet, View} from 'react-native' import {observer} from 'mobx-react-lite' import {ScrollView} from '../util' -import {useStores} from 'state/index' import {Text} from '../../util/text/Text' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -10,6 +9,7 @@ import {deviceLocales} from 'platform/detection' import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' import {ToggleButton} from 'view/com/util/forms/ToggleButton' +import {useModalControls} from '#/state/modals' import { useLanguagePrefs, useSetLanguagePrefs, @@ -20,14 +20,14 @@ import { export const snapPoints = ['100%'] export const Component = observer(function PostLanguagesSettingsImpl() { - const store = useStores() + const {closeModal} = useModalControls() const langPrefs = useLanguagePrefs() const setLangPrefs = useSetLanguagePrefs() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const onPressDone = React.useCallback(() => { - store.shell.closeModal() - }, [store]) + closeModal() + }, [closeModal]) const languages = React.useMemo(() => { const langs = LANGUAGES.filter( diff --git a/src/view/com/modals/report/Modal.tsx b/src/view/com/modals/report/Modal.tsx index 98aa2d471..8dc3f53f7 100644 --- a/src/view/com/modals/report/Modal.tsx +++ b/src/view/com/modals/report/Modal.tsx @@ -14,6 +14,7 @@ import {SendReportButton} from './SendReportButton' import {InputIssueDetails} from './InputIssueDetails' import {ReportReasonOptions} from './ReasonOptions' import {CollectionId} from './types' +import {useModalControls} from '#/state/modals' const DMCA_LINK = 'https://blueskyweb.xyz/support/copyright' @@ -37,6 +38,7 @@ type ReportComponentProps = export function Component(content: ReportComponentProps) { const store = useStores() + const {closeModal} = useModalControls() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const [isProcessing, setIsProcessing] = useState(false) @@ -60,7 +62,7 @@ export function Component(content: ReportComponentProps) { try { if (issue === '__copyright__') { Linking.openURL(DMCA_LINK) - store.shell.closeModal() + closeModal() return } const $type = !isAccountReport @@ -76,7 +78,7 @@ export function Component(content: ReportComponentProps) { }) Toast.show("Thank you for your report! We'll look into it promptly.") - store.shell.closeModal() + closeModal() return } catch (e: any) { setError(cleanError(e)) diff --git a/src/view/com/posts/FeedErrorMessage.tsx b/src/view/com/posts/FeedErrorMessage.tsx index 9e75d9507..84e438fcd 100644 --- a/src/view/com/posts/FeedErrorMessage.tsx +++ b/src/view/com/posts/FeedErrorMessage.tsx @@ -11,6 +11,7 @@ import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' import {useStores} from 'state/index' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' const MESSAGES = { [KnownError.Unknown]: '', @@ -57,13 +58,14 @@ function FeedgenErrorMessage({ const msg = MESSAGES[knownError] const uri = (feed.params as GetCustomFeed.QueryParams).feed const [ownerDid] = safeParseFeedgenUri(uri) + const {openModal, closeModal} = useModalControls() const onViewProfile = React.useCallback(() => { navigation.navigate('Profile', {name: ownerDid}) }, [navigation, ownerDid]) const onRemoveFeed = React.useCallback(async () => { - store.shell.openModal({ + openModal({ name: 'confirm', title: 'Remove feed', message: 'Remove this feed from your saved feeds?', @@ -78,10 +80,10 @@ function FeedgenErrorMessage({ } }, onPressCancel() { - store.shell.closeModal() + closeModal() }, }) - }, [store, uri]) + }, [store, openModal, closeModal, uri]) return ( <View diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx index 1a1d38e4b..1ee209785 100644 --- a/src/view/com/profile/ProfileHeader.tsx +++ b/src/view/com/profile/ProfileHeader.tsx @@ -40,6 +40,7 @@ import {makeProfileLink} from 'lib/routes/links' import {Link} from '../util/Link' import {ProfileHeaderSuggestedFollows} from './ProfileHeaderSuggestedFollows' import {logger} from '#/logger' +import {useModalControls} from '#/state/modals' interface Props { view: ProfileModel @@ -113,6 +114,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ const pal = usePalette('default') const palInverted = usePalette('inverted') const store = useStores() + const {openModal} = useModalControls() const navigation = useNavigation<NavigationProp>() const {track} = useAnalytics() const invalidHandle = isInvalidHandle(view.handle) @@ -157,12 +159,12 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ const onPressEditProfile = React.useCallback(() => { track('ProfileHeader:EditProfileButtonClicked') - store.shell.openModal({ + openModal({ name: 'edit-profile', profileView: view, onUpdate: onRefreshAll, }) - }, [track, store, view, onRefreshAll]) + }, [track, openModal, view, onRefreshAll]) const trackPress = React.useCallback( (f: 'Followers' | 'Follows') => { @@ -181,12 +183,12 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ const onPressAddRemoveLists = React.useCallback(() => { track('ProfileHeader:AddToListsButtonClicked') - store.shell.openModal({ + openModal({ name: 'user-add-remove-lists', subject: view.did, displayName: view.displayName || view.handle, }) - }, [track, view, store]) + }, [track, view, openModal]) const onPressMuteAccount = React.useCallback(async () => { track('ProfileHeader:MuteAccountButtonClicked') @@ -212,7 +214,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ const onPressBlockAccount = React.useCallback(async () => { track('ProfileHeader:BlockAccountButtonClicked') - store.shell.openModal({ + openModal({ name: 'confirm', title: 'Block Account', message: @@ -228,11 +230,11 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ } }, }) - }, [track, view, store, onRefreshAll]) + }, [track, view, openModal, onRefreshAll]) const onPressUnblockAccount = React.useCallback(async () => { track('ProfileHeader:UnblockAccountButtonClicked') - store.shell.openModal({ + openModal({ name: 'confirm', title: 'Unblock Account', message: @@ -248,15 +250,15 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({ } }, }) - }, [track, view, store, onRefreshAll]) + }, [track, view, openModal, onRefreshAll]) const onPressReportAccount = React.useCallback(() => { track('ProfileHeader:ReportAccountButtonClicked') - store.shell.openModal({ + openModal({ name: 'report', did: view.did, }) - }, [track, store, view]) + }, [track, openModal, view]) const isMe = React.useMemo( () => store.me.did === view.did, diff --git a/src/view/com/testing/TestCtrls.e2e.tsx b/src/view/com/testing/TestCtrls.e2e.tsx index db9b6b4bf..2f36609e9 100644 --- a/src/view/com/testing/TestCtrls.e2e.tsx +++ b/src/view/com/testing/TestCtrls.e2e.tsx @@ -2,6 +2,7 @@ import React from 'react' import {Pressable, View} from 'react-native' import {useStores} from 'state/index' import {navigate} from '../../../Navigation' +import {useModalControls} from '#/state/modals' /** * This utility component is only included in the test simulator @@ -13,6 +14,7 @@ const BTN = {height: 1, width: 1, backgroundColor: 'red'} export function TestCtrls() { const store = useStores() + const {openModal} = useModalControls() const onPressSignInAlice = async () => { await store.session.login({ service: 'http://localhost:3000', @@ -85,7 +87,7 @@ export function TestCtrls() { /> <Pressable testID="e2eOpenInviteCodesModal" - onPress={() => store.shell.openModal({name: 'invite-codes'})} + onPress={() => openModal({name: 'invite-codes'})} accessibilityRole="button" style={BTN} /> diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index 1777f6659..074ab2329 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -21,7 +21,6 @@ import {Text} from './text/Text' import {TypographyVariant} from 'lib/ThemeContext' import {NavigationProp} from 'lib/routes/types' import {router} from '../../../routes' -import {useStores, RootStoreModel} from 'state/index' import { convertBskyAppUrlIfNeeded, isExternalUrl, @@ -31,6 +30,7 @@ import {isAndroid, isWeb} from 'platform/detection' import {sanitizeUrl} from '@braintree/sanitize-url' import {PressableWithHover} from './PressableWithHover' import FixedTouchableHighlight from '../pager/FixedTouchableHighlight' +import {useModalControls} from '#/state/modals' type Event = | React.MouseEvent<HTMLAnchorElement, MouseEvent> @@ -60,17 +60,17 @@ export const Link = memo(function Link({ anchorNoUnderline, ...props }: Props) { - const store = useStores() + const {closeModal} = useModalControls() const navigation = useNavigation<NavigationProp>() const anchorHref = asAnchor ? sanitizeUrl(href) : undefined const onPress = React.useCallback( (e?: Event) => { if (typeof href === 'string') { - return onPressInner(store, navigation, sanitizeUrl(href), e) + return onPressInner(closeModal, navigation, sanitizeUrl(href), e) } }, - [store, navigation, href], + [closeModal, navigation, href], ) if (noFeedback) { @@ -160,8 +160,8 @@ export const TextLink = memo(function TextLink({ warnOnMismatchingLabel?: boolean } & TextProps) { const {...props} = useLinkProps({to: sanitizeUrl(href)}) - const store = useStores() const navigation = useNavigation<NavigationProp>() + const {openModal, closeModal} = useModalControls() if (warnOnMismatchingLabel && typeof text !== 'string') { console.error('Unable to detect mismatching label') @@ -174,7 +174,7 @@ export const TextLink = memo(function TextLink({ linkRequiresWarning(href, typeof text === 'string' ? text : '') if (requiresWarning) { e?.preventDefault?.() - store.shell.openModal({ + openModal({ name: 'link-warning', text: typeof text === 'string' ? text : '', href, @@ -185,9 +185,17 @@ export const TextLink = memo(function TextLink({ // @ts-ignore function signature differs by platform -prf return onPress() } - return onPressInner(store, navigation, sanitizeUrl(href), e) + return onPressInner(closeModal, navigation, sanitizeUrl(href), e) }, - [onPress, store, navigation, href, text, warnOnMismatchingLabel], + [ + onPress, + closeModal, + openModal, + navigation, + href, + text, + warnOnMismatchingLabel, + ], ) const hrefAttrs = useMemo(() => { const isExternal = isExternalUrl(href) @@ -285,7 +293,7 @@ export const TextLinkOnWebOnly = memo(function DesktopWebTextLink({ // needed customizations // -prf function onPressInner( - store: RootStoreModel, + closeModal = () => {}, navigation: NavigationProp, href: string, e?: Event, @@ -318,7 +326,7 @@ function onPressInner( if (newTab || href.startsWith('http') || href.startsWith('mailto')) { Linking.openURL(href) } else { - store.shell.closeModal() // close any active modals + closeModal() // close any active modals // @ts-ignore we're not able to type check on this one -prf navigation.dispatch(StackActions.push(...router.matchPath(href))) diff --git a/src/view/com/util/UserPreviewLink.tsx b/src/view/com/util/UserPreviewLink.tsx index f43f9e80b..9c5efe55e 100644 --- a/src/view/com/util/UserPreviewLink.tsx +++ b/src/view/com/util/UserPreviewLink.tsx @@ -1,9 +1,9 @@ import React from 'react' import {Pressable, StyleProp, ViewStyle} from 'react-native' -import {useStores} from 'state/index' import {Link} from './Link' import {isWeb} from 'platform/detection' import {makeProfileLink} from 'lib/routes/links' +import {useModalControls} from '#/state/modals' interface UserPreviewLinkProps { did: string @@ -13,7 +13,7 @@ interface UserPreviewLinkProps { export function UserPreviewLink( props: React.PropsWithChildren<UserPreviewLinkProps>, ) { - const store = useStores() + const {openModal} = useModalControls() if (isWeb) { return ( @@ -29,7 +29,7 @@ export function UserPreviewLink( return ( <Pressable onPress={() => - store.shell.openModal({ + openModal({ name: 'profile-preview', did: props.did, }) diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx index 1fffa3123..45abed647 100644 --- a/src/view/com/util/forms/PostDropdownBtn.tsx +++ b/src/view/com/util/forms/PostDropdownBtn.tsx @@ -2,7 +2,6 @@ import React from 'react' import {StyleProp, View, ViewStyle} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {toShareUrl} from 'lib/strings/url-helpers' -import {useStores} from 'state/index' import {useTheme} from 'lib/ThemeContext' import {shareUrl} from 'lib/sharing' import { @@ -10,6 +9,7 @@ import { DropdownItem as NativeDropdownItem, } from './NativeDropdown' import {EventStopper} from '../EventStopper' +import {useModalControls} from '#/state/modals' export function PostDropdownBtn({ testID, @@ -37,9 +37,9 @@ export function PostDropdownBtn({ onDeletePost: () => void style?: StyleProp<ViewStyle> }) { - const store = useStores() const theme = useTheme() const defaultCtrlColor = theme.palette.default.postCtrl + const {openModal} = useModalControls() const dropdownItems: NativeDropdownItem[] = [ { @@ -108,7 +108,7 @@ export function PostDropdownBtn({ !isAuthor && { label: 'Report post', onPress() { - store.shell.openModal({ + openModal({ name: 'report', uri: itemUri, cid: itemCid, @@ -129,7 +129,7 @@ export function PostDropdownBtn({ isAuthor && { label: 'Delete post', onPress() { - store.shell.openModal({ + openModal({ name: 'confirm', title: 'Delete this post?', message: 'Are you sure? This can not be undone.', diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx index 4f917844a..b6fe0dd8c 100644 --- a/src/view/com/util/moderation/ContentHider.tsx +++ b/src/view/com/util/moderation/ContentHider.tsx @@ -6,7 +6,7 @@ import {ModerationUI} from '@atproto/api' import {Text} from '../text/Text' import {ShieldExclamation} from 'lib/icons' import {describeModerationCause} from 'lib/moderation' -import {useStores} from 'state/index' +import {useModalControls} from '#/state/modals' export function ContentHider({ testID, @@ -22,10 +22,10 @@ export function ContentHider({ style?: StyleProp<ViewStyle> childContainerStyle?: StyleProp<ViewStyle> }>) { - const store = useStores() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const [override, setOverride] = React.useState(false) + const {openModal} = useModalControls() if (!moderation.blur || (ignoreMute && moderation.cause?.type === 'muted')) { return ( @@ -43,7 +43,7 @@ export function ContentHider({ if (!moderation.noOverride) { setOverride(v => !v) } else { - store.shell.openModal({ + openModal({ name: 'moderation-details', context: 'content', moderation, @@ -62,7 +62,7 @@ export function ContentHider({ ]}> <Pressable onPress={() => { - store.shell.openModal({ + openModal({ name: 'moderation-details', context: 'content', moderation, diff --git a/src/view/com/util/moderation/PostAlerts.tsx b/src/view/com/util/moderation/PostAlerts.tsx index 0dba367fc..2c9a71859 100644 --- a/src/view/com/util/moderation/PostAlerts.tsx +++ b/src/view/com/util/moderation/PostAlerts.tsx @@ -5,7 +5,7 @@ import {Text} from '../text/Text' import {usePalette} from 'lib/hooks/usePalette' import {ShieldExclamation} from 'lib/icons' import {describeModerationCause} from 'lib/moderation' -import {useStores} from 'state/index' +import {useModalControls} from '#/state/modals' export function PostAlerts({ moderation, @@ -15,8 +15,8 @@ export function PostAlerts({ includeMute?: boolean style?: StyleProp<ViewStyle> }) { - const store = useStores() const pal = usePalette('default') + const {openModal} = useModalControls() const shouldAlert = !!moderation.cause && moderation.alert if (!shouldAlert) { @@ -27,7 +27,7 @@ export function PostAlerts({ return ( <Pressable onPress={() => { - store.shell.openModal({ + openModal({ name: 'moderation-details', context: 'content', moderation, diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/view/com/util/moderation/PostHider.tsx index d224286b0..a9ccf2ebd 100644 --- a/src/view/com/util/moderation/PostHider.tsx +++ b/src/view/com/util/moderation/PostHider.tsx @@ -8,7 +8,7 @@ import {Text} from '../text/Text' import {addStyle} from 'lib/styles' import {describeModerationCause} from 'lib/moderation' import {ShieldExclamation} from 'lib/icons' -import {useStores} from 'state/index' +import {useModalControls} from '#/state/modals' interface Props extends ComponentProps<typeof Link> { // testID?: string @@ -25,10 +25,10 @@ export function PostHider({ children, ...props }: Props) { - const store = useStores() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const [override, setOverride] = React.useState(false) + const {openModal} = useModalControls() if (!moderation.blur) { return ( @@ -63,7 +63,7 @@ export function PostHider({ ]}> <Pressable onPress={() => { - store.shell.openModal({ + openModal({ name: 'moderation-details', context: 'content', moderation, diff --git a/src/view/com/util/moderation/ProfileHeaderAlerts.tsx b/src/view/com/util/moderation/ProfileHeaderAlerts.tsx index 6b7f4e7ec..d2406e7ae 100644 --- a/src/view/com/util/moderation/ProfileHeaderAlerts.tsx +++ b/src/view/com/util/moderation/ProfileHeaderAlerts.tsx @@ -8,7 +8,7 @@ import { describeModerationCause, getProfileModerationCauses, } from 'lib/moderation' -import {useStores} from 'state/index' +import {useModalControls} from '#/state/modals' export function ProfileHeaderAlerts({ moderation, @@ -17,8 +17,8 @@ export function ProfileHeaderAlerts({ moderation: ProfileModeration style?: StyleProp<ViewStyle> }) { - const store = useStores() const pal = usePalette('default') + const {openModal} = useModalControls() const causes = getProfileModerationCauses(moderation) if (!causes.length) { @@ -34,7 +34,7 @@ export function ProfileHeaderAlerts({ testID="profileHeaderAlert" key={desc.name} onPress={() => { - store.shell.openModal({ + openModal({ name: 'moderation-details', context: 'content', moderation: {cause}, diff --git a/src/view/com/util/moderation/ScreenHider.tsx b/src/view/com/util/moderation/ScreenHider.tsx index 0224b9fee..c3d23b84d 100644 --- a/src/view/com/util/moderation/ScreenHider.tsx +++ b/src/view/com/util/moderation/ScreenHider.tsx @@ -18,7 +18,7 @@ import {NavigationProp} from 'lib/routes/types' import {Text} from '../text/Text' import {Button} from '../forms/Button' import {describeModerationCause} from 'lib/moderation' -import {useStores} from 'state/index' +import {useModalControls} from '#/state/modals' export function ScreenHider({ testID, @@ -34,12 +34,12 @@ export function ScreenHider({ style?: StyleProp<ViewStyle> containerStyle?: StyleProp<ViewStyle> }>) { - const store = useStores() const pal = usePalette('default') const palInverted = usePalette('inverted') const [override, setOverride] = React.useState(false) const navigation = useNavigation<NavigationProp>() const {isMobile} = useWebMediaQueries() + const {openModal} = useModalControls() if (!moderation.blur || override) { return ( @@ -72,7 +72,7 @@ export function ScreenHider({ .{' '} <TouchableWithoutFeedback onPress={() => { - store.shell.openModal({ + openModal({ name: 'moderation-details', context: 'account', moderation, diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx index 5769a478b..7bcea0e79 100644 --- a/src/view/com/util/post-ctrls/PostCtrls.tsx +++ b/src/view/com/util/post-ctrls/PostCtrls.tsx @@ -16,6 +16,7 @@ import {useStores} from 'state/index' import {RepostButton} from './RepostButton' import {Haptics} from 'lib/haptics' import {HITSLOP_10, HITSLOP_20} from 'lib/constants' +import {useModalControls} from '#/state/modals' interface PostCtrlsOpts { itemUri: string @@ -51,6 +52,7 @@ interface PostCtrlsOpts { export function PostCtrls(opts: PostCtrlsOpts) { const store = useStores() const theme = useTheme() + const {closeModal} = useModalControls() const defaultCtrlColor = React.useMemo( () => ({ color: theme.palette.default.postCtrl, @@ -58,17 +60,17 @@ export function PostCtrls(opts: PostCtrlsOpts) { [theme], ) as StyleProp<ViewStyle> const onRepost = useCallback(() => { - store.shell.closeModal() + closeModal() if (!opts.isReposted) { Haptics.default() opts.onPressToggleRepost().catch(_e => undefined) } else { opts.onPressToggleRepost().catch(_e => undefined) } - }, [opts, store.shell]) + }, [opts, closeModal]) const onQuote = useCallback(() => { - store.shell.closeModal() + closeModal() store.shell.openComposer({ quote: { uri: opts.itemUri, @@ -86,6 +88,7 @@ export function PostCtrls(opts: PostCtrlsOpts) { opts.itemUri, opts.text, store.shell, + closeModal, ]) const onPressToggleLikeWrapper = async () => { diff --git a/src/view/com/util/post-ctrls/RepostButton.tsx b/src/view/com/util/post-ctrls/RepostButton.tsx index 9c4ed8e5d..0a7637252 100644 --- a/src/view/com/util/post-ctrls/RepostButton.tsx +++ b/src/view/com/util/post-ctrls/RepostButton.tsx @@ -5,8 +5,8 @@ import {s, colors} from 'lib/styles' import {useTheme} from 'lib/ThemeContext' import {Text} from '../text/Text' import {pluralize} from 'lib/strings/helpers' -import {useStores} from 'state/index' import {HITSLOP_10, HITSLOP_20} from 'lib/constants' +import {useModalControls} from '#/state/modals' interface Props { isReposted: boolean @@ -23,8 +23,8 @@ export const RepostButton = ({ onRepost, onQuote, }: Props) => { - const store = useStores() const theme = useTheme() + const {openModal} = useModalControls() const defaultControlColor = React.useMemo( () => ({ @@ -34,13 +34,13 @@ export const RepostButton = ({ ) const onPressToggleRepostWrapper = useCallback(() => { - store.shell.openModal({ + openModal({ name: 'repost', onRepost: onRepost, onQuote: onQuote, isReposted, }) - }, [onRepost, onQuote, isReposted, store.shell]) + }, [onRepost, onQuote, isReposted, openModal]) return ( <TouchableOpacity |