diff options
Diffstat (limited to 'src/view')
61 files changed, 982 insertions, 1102 deletions
diff --git a/src/view/com/auth/LoggedOut.tsx b/src/view/com/auth/LoggedOut.tsx index 0d8172964..3505e86af 100644 --- a/src/view/com/auth/LoggedOut.tsx +++ b/src/view/com/auth/LoggedOut.tsx @@ -1,6 +1,5 @@ import React from 'react' import {SafeAreaView} from 'react-native' -import {observer} from 'mobx-react-lite' import {Login} from 'view/com/auth/login/Login' import {CreateAccount} from 'view/com/auth/create/CreateAccount' import {ErrorBoundary} from 'view/com/util/ErrorBoundary' @@ -16,7 +15,7 @@ enum ScreenState { S_CreateAccount, } -export const LoggedOut = observer(function LoggedOutImpl() { +export function LoggedOut() { const pal = usePalette('default') const setMinimalShellMode = useSetMinimalShellMode() const {screen} = useAnalytics() @@ -58,4 +57,4 @@ export const LoggedOut = observer(function LoggedOutImpl() { </ErrorBoundary> </SafeAreaView> ) -}) +} diff --git a/src/view/com/auth/Onboarding.tsx b/src/view/com/auth/Onboarding.tsx index 994f4c149..3a17eb4f8 100644 --- a/src/view/com/auth/Onboarding.tsx +++ b/src/view/com/auth/Onboarding.tsx @@ -1,6 +1,5 @@ import React from 'react' import {SafeAreaView} from 'react-native' -import {observer} from 'mobx-react-lite' import {ErrorBoundary} from 'view/com/util/ErrorBoundary' import {s} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' @@ -10,7 +9,7 @@ import {RecommendedFollows} from './onboarding/RecommendedFollows' import {useSetMinimalShellMode} from '#/state/shell/minimal-mode' import {useOnboardingState, useOnboardingDispatch} from '#/state/shell' -export const Onboarding = observer(function OnboardingImpl() { +export function Onboarding() { const pal = usePalette('default') const setMinimalShellMode = useSetMinimalShellMode() const onboardingState = useOnboardingState() @@ -38,4 +37,4 @@ export const Onboarding = observer(function OnboardingImpl() { </ErrorBoundary> </SafeAreaView> ) -}) +} diff --git a/src/view/com/auth/create/Policies.tsx b/src/view/com/auth/create/Policies.tsx index 7d10f32fc..a52f07531 100644 --- a/src/view/com/auth/create/Policies.tsx +++ b/src/view/com/auth/create/Policies.tsx @@ -4,12 +4,14 @@ import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' +import {ComAtprotoServerDescribeServer} from '@atproto/api' import {TextLink} from '../../util/Link' import {Text} from '../../util/text/Text' import {s, colors} from 'lib/styles' -import {ServiceDescription} from 'state/models/session' import {usePalette} from 'lib/hooks/usePalette' +type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema + export const Policies = ({ serviceDescription, needsGuardian, diff --git a/src/view/com/auth/create/Step1.tsx b/src/view/com/auth/create/Step1.tsx index ab47b411f..c9d19e868 100644 --- a/src/view/com/auth/create/Step1.tsx +++ b/src/view/com/auth/create/Step1.tsx @@ -13,7 +13,7 @@ import {ErrorMessage} from 'view/com/util/error/ErrorMessage' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {LOCAL_DEV_SERVICE, STAGING_SERVICE, PROD_SERVICE} from 'state/index' +import {LOCAL_DEV_SERVICE, STAGING_SERVICE, PROD_SERVICE} from 'lib/constants' import {LOGIN_INCLUDE_DEV_SERVERS} from 'lib/build-flags' /** STEP 1: Your hosting provider diff --git a/src/view/com/auth/login/ForgotPasswordForm.tsx b/src/view/com/auth/login/ForgotPasswordForm.tsx index a794665c9..215c393d9 100644 --- a/src/view/com/auth/login/ForgotPasswordForm.tsx +++ b/src/view/com/auth/login/ForgotPasswordForm.tsx @@ -9,13 +9,13 @@ import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' +import {ComAtprotoServerDescribeServer} from '@atproto/api' import * as EmailValidator from 'email-validator' import {BskyAgent} from '@atproto/api' import {useAnalytics} from 'lib/analytics/analytics' import {Text} from '../../util/text/Text' import {s} from 'lib/styles' import {toNiceDomain} from 'lib/strings/url-helpers' -import {ServiceDescription} from 'state/models/session' import {isNetworkError} from 'lib/strings/errors' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' @@ -26,6 +26,8 @@ import {useLingui} from '@lingui/react' import {styles} from './styles' import {useModalControls} from '#/state/modals' +type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema + export const ForgotPasswordForm = ({ error, serviceUrl, diff --git a/src/view/com/auth/login/Login.tsx b/src/view/com/auth/login/Login.tsx index 27d08812c..a2f924f95 100644 --- a/src/view/com/auth/login/Login.tsx +++ b/src/view/com/auth/login/Login.tsx @@ -2,8 +2,7 @@ import React, {useState, useEffect} from 'react' import {KeyboardAvoidingView} from 'react-native' import {useAnalytics} from 'lib/analytics/analytics' import {LoggedOutLayout} from 'view/com/util/layouts/LoggedOutLayout' -import {useStores, DEFAULT_SERVICE} from 'state/index' -import {ServiceDescription} from 'state/models/session' +import {DEFAULT_SERVICE} from '#/lib/constants' import {usePalette} from 'lib/hooks/usePalette' import {logger} from '#/logger' import {ChooseAccountForm} from './ChooseAccountForm' @@ -14,6 +13,7 @@ import {PasswordUpdatedForm} from './PasswordUpdatedForm' import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' import {useSession, SessionAccount} from '#/state/session' +import {useServiceQuery} from '#/state/queries/service' enum Forms { Login, @@ -25,20 +25,20 @@ enum Forms { export const Login = ({onPressBack}: {onPressBack: () => void}) => { const pal = usePalette('default') - const store = useStores() const {accounts} = useSession() const {track} = useAnalytics() const {_} = useLingui() const [error, setError] = useState<string>('') - const [retryDescribeTrigger, setRetryDescribeTrigger] = useState<any>({}) const [serviceUrl, setServiceUrl] = useState<string>(DEFAULT_SERVICE) - const [serviceDescription, setServiceDescription] = useState< - ServiceDescription | undefined - >(undefined) const [initialHandle, setInitialHandle] = useState<string>('') const [currentForm, setCurrentForm] = useState<Forms>( accounts.length ? Forms.ChooseAccount : Forms.Login, ) + const { + data: serviceDescription, + error: serviceError, + refetch: refetchService, + } = useServiceQuery(serviceUrl) const onSelectAccount = (account?: SessionAccount) => { if (account?.service) { @@ -54,35 +54,21 @@ export const Login = ({onPressBack}: {onPressBack: () => void}) => { } useEffect(() => { - let aborted = false - setError('') - store.session.describeService(serviceUrl).then( - desc => { - if (aborted) { - return - } - setServiceDescription(desc) - }, - err => { - if (aborted) { - return - } - logger.warn(`Failed to fetch service description for ${serviceUrl}`, { - error: err, - }) - setError( - _( - msg`Unable to contact your service. Please check your Internet connection.`, - ), - ) - }, - ) - return () => { - aborted = true + if (serviceError) { + setError( + _( + msg`Unable to contact your service. Please check your Internet connection.`, + ), + ) + logger.warn(`Failed to fetch service description for ${serviceUrl}`, { + error: String(serviceError), + }) + } else { + setError('') } - }, [store.session, serviceUrl, retryDescribeTrigger, _]) + }, [serviceError, serviceUrl, _]) - const onPressRetryConnect = () => setRetryDescribeTrigger({}) + const onPressRetryConnect = () => refetchService() const onPressForgotPassword = () => { track('Signin:PressedForgotPassword') setCurrentForm(Forms.ForgotPassword) diff --git a/src/view/com/auth/login/LoginForm.tsx b/src/view/com/auth/login/LoginForm.tsx index be3a95131..365f2e253 100644 --- a/src/view/com/auth/login/LoginForm.tsx +++ b/src/view/com/auth/login/LoginForm.tsx @@ -10,12 +10,12 @@ import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' +import {ComAtprotoServerDescribeServer} from '@atproto/api' import {useAnalytics} from 'lib/analytics/analytics' import {Text} from '../../util/text/Text' import {s} from 'lib/styles' import {createFullHandle} from 'lib/strings/handles' import {toNiceDomain} from 'lib/strings/url-helpers' -import {ServiceDescription} from 'state/models/session' import {isNetworkError} from 'lib/strings/errors' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' @@ -27,6 +27,8 @@ import {styles} from './styles' import {useLingui} from '@lingui/react' import {useModalControls} from '#/state/modals' +type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema + export const LoginForm = ({ error, serviceUrl, diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.tsx index d134dae9f..941671bf8 100644 --- a/src/view/com/auth/onboarding/RecommendedFeeds.tsx +++ b/src/view/com/auth/onboarding/RecommendedFeeds.tsx @@ -1,6 +1,5 @@ import React from 'react' import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {TabletOrDesktop, Mobile} from 'view/com/util/layouts/Breakpoints' import {Text} from 'view/com/util/text/Text' @@ -16,9 +15,7 @@ import {useSuggestedFeedsQuery} from '#/state/queries/suggested-feeds' type Props = { next: () => void } -export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ - next, -}: Props) { +export function RecommendedFeeds({next}: Props) { const pal = usePalette('default') const {isTabletOrMobile} = useWebMediaQueries() const {isLoading, data} = useSuggestedFeedsQuery() @@ -146,7 +143,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ </Mobile> </> ) -}) +} const tdStyles = StyleSheet.create({ container: { diff --git a/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx b/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx index 2eaf3cf2d..7417e5b06 100644 --- a/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx +++ b/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx @@ -1,6 +1,5 @@ import React from 'react' import {View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {AppBskyFeedDefs, RichText as BskRichText} from '@atproto/api' import {Text} from 'view/com/util/text/Text' @@ -19,7 +18,7 @@ import { } from '#/state/queries/preferences' import {logger} from '#/logger' -export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({ +export function RecommendedFeedsItem({ item, }: { item: AppBskyFeedDefs.GeneratorView @@ -164,4 +163,4 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({ </View> </View> ) -}) +} diff --git a/src/view/com/auth/onboarding/RecommendedFollows.tsx b/src/view/com/auth/onboarding/RecommendedFollows.tsx index aa528cbd8..c327a7168 100644 --- a/src/view/com/auth/onboarding/RecommendedFollows.tsx +++ b/src/view/com/auth/onboarding/RecommendedFollows.tsx @@ -1,6 +1,5 @@ import React from 'react' import {ActivityIndicator, FlatList, StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {AppBskyActorDefs, moderateProfile} from '@atproto/api' import {TabletOrDesktop, Mobile} from 'view/com/util/layouts/Breakpoints' @@ -19,9 +18,7 @@ import {logger} from '#/logger' type Props = { next: () => void } -export const RecommendedFollows = observer(function RecommendedFollowsImpl({ - next, -}: Props) { +export function RecommendedFollows({next}: Props) { const pal = usePalette('default') const {isTabletOrMobile} = useWebMediaQueries() const {data: suggestedFollows, dataUpdatedAt} = useSuggestedFollowsQuery() @@ -211,7 +208,7 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({ </Mobile> </> ) -}) +} const tdStyles = StyleSheet.create({ container: { diff --git a/src/view/com/auth/onboarding/WelcomeDesktop.tsx b/src/view/com/auth/onboarding/WelcomeDesktop.tsx index c066e9bd5..1a30c17f9 100644 --- a/src/view/com/auth/onboarding/WelcomeDesktop.tsx +++ b/src/view/com/auth/onboarding/WelcomeDesktop.tsx @@ -7,16 +7,13 @@ import {usePalette} from 'lib/hooks/usePalette' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {TitleColumnLayout} from 'view/com/util/layouts/TitleColumnLayout' import {Button} from 'view/com/util/forms/Button' -import {observer} from 'mobx-react-lite' type Props = { next: () => void skip: () => void } -export const WelcomeDesktop = observer(function WelcomeDesktopImpl({ - next, -}: Props) { +export function WelcomeDesktop({next}: Props) { const pal = usePalette('default') const horizontal = useMediaQuery({minWidth: 1300}) const title = ( @@ -105,7 +102,7 @@ export const WelcomeDesktop = observer(function WelcomeDesktopImpl({ </View> </TitleColumnLayout> ) -}) +} const styles = StyleSheet.create({ row: { diff --git a/src/view/com/auth/onboarding/WelcomeMobile.tsx b/src/view/com/auth/onboarding/WelcomeMobile.tsx index ef70a1fe3..2717bff3f 100644 --- a/src/view/com/auth/onboarding/WelcomeMobile.tsx +++ b/src/view/com/auth/onboarding/WelcomeMobile.tsx @@ -5,7 +5,6 @@ import {s} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Button} from 'view/com/util/forms/Button' -import {observer} from 'mobx-react-lite' import {ViewHeader} from 'view/com/util/ViewHeader' import {Trans} from '@lingui/macro' @@ -14,10 +13,7 @@ type Props = { skip: () => void } -export const WelcomeMobile = observer(function WelcomeMobileImpl({ - next, - skip, -}: Props) { +export function WelcomeMobile({next, skip}: Props) { const pal = usePalette('default') return ( @@ -102,7 +98,7 @@ export const WelcomeMobile = observer(function WelcomeMobileImpl({ /> </View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/auth/withAuthRequired.tsx b/src/view/com/auth/withAuthRequired.tsx index 4b8b31d6c..5fd89a8bd 100644 --- a/src/view/com/auth/withAuthRequired.tsx +++ b/src/view/com/auth/withAuthRequired.tsx @@ -5,7 +5,6 @@ import { StyleSheet, TouchableOpacity, } from 'react-native' -import {observer} from 'mobx-react-lite' import {CenteredView} from '../util/Views' import {LoggedOut} from './LoggedOut' import {Onboarding} from './Onboarding' @@ -18,7 +17,7 @@ import {useSession} from '#/state/session' export const withAuthRequired = <P extends object>( Component: React.ComponentType<P>, ): React.FC<P> => - observer(function AuthRequired(props: P) { + function AuthRequired(props: P) { const {isInitialLoad, hasSession} = useSession() const onboardingState = useOnboardingState() if (isInitialLoad) { @@ -31,7 +30,7 @@ export const withAuthRequired = <P extends object>( return <Onboarding /> } return <Component {...props} /> - }) + } function Loading() { const pal = usePalette('default') diff --git a/src/view/com/composer/labels/LabelsBtn.tsx b/src/view/com/composer/labels/LabelsBtn.tsx index 7d90774f2..a10684691 100644 --- a/src/view/com/composer/labels/LabelsBtn.tsx +++ b/src/view/com/composer/labels/LabelsBtn.tsx @@ -1,6 +1,5 @@ import React from 'react' 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 {ShieldExclamation} from 'lib/icons' @@ -11,7 +10,7 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' import {useModalControls} from '#/state/modals' -export const LabelsBtn = observer(function LabelsBtn({ +export function LabelsBtn({ labels, hasMedia, onChange, @@ -49,7 +48,7 @@ export const LabelsBtn = observer(function LabelsBtn({ ) : null} </Button> ) -}) +} const styles = StyleSheet.create({ button: { diff --git a/src/view/com/composer/select-language/SelectLangBtn.tsx b/src/view/com/composer/select-language/SelectLangBtn.tsx index 7ea63ed62..78b1e9ba2 100644 --- a/src/view/com/composer/select-language/SelectLangBtn.tsx +++ b/src/view/com/composer/select-language/SelectLangBtn.tsx @@ -1,6 +1,5 @@ import React, {useCallback, useMemo} from 'react' import {StyleSheet, Keyboard} from 'react-native' -import {observer} from 'mobx-react-lite' import { FontAwesomeIcon, FontAwesomeIconStyle, @@ -24,7 +23,7 @@ import { import {t, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -export const SelectLangBtn = observer(function SelectLangBtn() { +export function SelectLangBtn() { const pal = usePalette('default') const {_} = useLingui() const {openModal} = useModalControls() @@ -117,7 +116,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() { )} </DropdownButton> ) -}) +} const styles = StyleSheet.create({ button: { diff --git a/src/view/com/composer/text-input/mobile/Autocomplete.tsx b/src/view/com/composer/text-input/mobile/Autocomplete.tsx index bb54a2042..c400aa48d 100644 --- a/src/view/com/composer/text-input/mobile/Autocomplete.tsx +++ b/src/view/com/composer/text-input/mobile/Autocomplete.tsx @@ -1,6 +1,5 @@ import React, {useEffect, useRef} from 'react' import {Animated, TouchableOpacity, StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' import {usePalette} from 'lib/hooks/usePalette' import {Text} from 'view/com/util/text/Text' @@ -10,7 +9,7 @@ import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' import {Trans} from '@lingui/macro' import {AppBskyActorDefs} from '@atproto/api' -export const Autocomplete = observer(function AutocompleteImpl({ +export function Autocomplete({ prefix, onSelect, }: { @@ -103,7 +102,7 @@ export const Autocomplete = observer(function AutocompleteImpl({ ) : null} </Animated.View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/composer/useExternalLinkFetch.ts b/src/view/com/composer/useExternalLinkFetch.ts index 0c96e4727..af6042306 100644 --- a/src/view/com/composer/useExternalLinkFetch.ts +++ b/src/view/com/composer/useExternalLinkFetch.ts @@ -1,5 +1,4 @@ import {useState, useEffect} from 'react' -import {useStores} from 'state/index' import {ImageModel} from 'state/models/media/image' import * as apilib from 'lib/api/index' import {getLinkMeta} from 'lib/link-meta/link-meta' @@ -17,6 +16,7 @@ import { import {ComposerOpts} from 'state/shell/composer' import {POST_IMG_MAX} from 'lib/constants' import {logger} from '#/logger' +import {useSession} from '#/state/session' import {useGetPost} from '#/state/queries/post' export function useExternalLinkFetch({ @@ -24,7 +24,7 @@ export function useExternalLinkFetch({ }: { setQuote: (opts: ComposerOpts['quote']) => void }) { - const store = useStores() + const {agent} = useSession() const [extLink, setExtLink] = useState<apilib.ExternalEmbedDraft | undefined>( undefined, ) @@ -56,7 +56,7 @@ export function useExternalLinkFetch({ }, ) } else if (isBskyCustomFeedUrl(extLink.uri)) { - getFeedAsEmbed(store, extLink.uri).then( + getFeedAsEmbed(agent, extLink.uri).then( ({embed, meta}) => { if (aborted) { return @@ -74,7 +74,7 @@ export function useExternalLinkFetch({ }, ) } else if (isBskyListUrl(extLink.uri)) { - getListAsEmbed(store, extLink.uri).then( + getListAsEmbed(agent, extLink.uri).then( ({embed, meta}) => { if (aborted) { return @@ -92,7 +92,7 @@ export function useExternalLinkFetch({ }, ) } else { - getLinkMeta(store, extLink.uri).then(meta => { + getLinkMeta(agent, extLink.uri).then(meta => { if (aborted) { return } @@ -134,7 +134,7 @@ export function useExternalLinkFetch({ }) } return cleanup - }, [store, extLink, setQuote, getPost]) + }, [agent, extLink, setQuote, getPost]) return {extLink, setExtLink} } diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx index 7c7ad0616..ea740ec91 100644 --- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx +++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.android.tsx @@ -315,7 +315,6 @@ const ImageItem = ({ <GestureDetector gesture={composedGesture}> <AnimatedImage contentFit="contain" - // NOTE: Don't pass imageSrc={imageSrc} or MobX will break. source={{uri: imageSrc.uri}} style={[styles.image, animatedStyle]} accessibilityLabel={imageSrc.alt} diff --git a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx index f73f355ac..2b0b0b149 100644 --- a/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx +++ b/src/view/com/lightbox/ImageViewing/components/ImageItem/ImageItem.ios.tsx @@ -139,7 +139,6 @@ const ImageItem = ({imageSrc, onTap, onZoom, onRequestClose}: Props) => { {(!loaded || !imageDimensions) && <ImageLoading />} <AnimatedImage contentFit="contain" - // NOTE: Don't pass imageSrc={imageSrc} or MobX will break. source={{uri: imageSrc.uri}} style={[styles.image, animatedStyle]} accessibilityLabel={imageSrc.alt} diff --git a/src/view/com/modals/BirthDateSettings.tsx b/src/view/com/modals/BirthDateSettings.tsx index 9996c5641..c78f06ed4 100644 --- a/src/view/com/modals/BirthDateSettings.tsx +++ b/src/view/com/modals/BirthDateSettings.tsx @@ -5,7 +5,6 @@ import { TouchableOpacity, View, } from 'react-native' -import {observer} from 'mobx-react-lite' import {Text} from '../util/text/Text' import {DateInput} from '../util/forms/DateInput' import {ErrorMessage} from '../util/error/ErrorMessage' @@ -103,7 +102,7 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) { ) } -export const Component = observer(function Component({}: {}) { +export function Component({}: {}) { const {data: preferences} = usePreferencesQuery() return !preferences ? ( @@ -111,7 +110,7 @@ export const Component = observer(function Component({}: {}) { ) : ( <Inner preferences={preferences} /> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/modals/ChangeEmail.tsx b/src/view/com/modals/ChangeEmail.tsx index 6f7a92102..829188b51 100644 --- a/src/view/com/modals/ChangeEmail.tsx +++ b/src/view/com/modals/ChangeEmail.tsx @@ -1,7 +1,6 @@ import React, {useState} from 'react' import {ActivityIndicator, SafeAreaView, StyleSheet, View} from 'react-native' import {ScrollView, TextInput} from './util' -import {observer} from 'mobx-react-lite' import {Text} from '../util/text/Text' import {Button} from '../util/forms/Button' import {ErrorMessage} from '../util/error/ErrorMessage' @@ -24,7 +23,7 @@ enum Stages { export const snapPoints = ['90%'] -export const Component = observer(function Component({}: {}) { +export function Component() { const pal = usePalette('default') const {agent, currentAccount} = useSession() const {updateCurrentAccount} = useSessionApi() @@ -226,7 +225,7 @@ export const Component = observer(function Component({}: {}) { </ScrollView> </SafeAreaView> ) -}) +} const styles = StyleSheet.create({ titleSection: { diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx index 8dc3311fc..8b42e1b1d 100644 --- a/src/view/com/modals/ContentFilteringSettings.tsx +++ b/src/view/com/modals/ContentFilteringSettings.tsx @@ -2,7 +2,6 @@ import React from 'react' import {LabelPreference} from '@atproto/api' import {StyleSheet, Pressable, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' -import {observer} from 'mobx-react-lite' import {ScrollView} from './util' import {s, colors, gradients} from 'lib/styles' import {Text} from '../util/text/Text' @@ -28,82 +27,80 @@ import { export const snapPoints = ['90%'] -export const Component = observer( - function ContentFilteringSettingsImpl({}: {}) { - const {isMobile} = useWebMediaQueries() - const pal = usePalette('default') - const {_} = useLingui() - const {closeModal} = useModalControls() - const {data: preferences} = usePreferencesQuery() +export function Component({}: {}) { + const {isMobile} = useWebMediaQueries() + const pal = usePalette('default') + const {_} = useLingui() + const {closeModal} = useModalControls() + const {data: preferences} = usePreferencesQuery() - const onPressDone = React.useCallback(() => { - closeModal() - }, [closeModal]) + const onPressDone = React.useCallback(() => { + closeModal() + }, [closeModal]) - return ( - <View testID="contentFilteringModal" style={[pal.view, styles.container]}> - <Text style={[pal.text, styles.title]}> - <Trans>Content Filtering</Trans> - </Text> + return ( + <View testID="contentFilteringModal" style={[pal.view, styles.container]}> + <Text style={[pal.text, styles.title]}> + <Trans>Content Filtering</Trans> + </Text> - <ScrollView style={styles.scrollContainer}> - <AdultContentEnabledPref /> - <ContentLabelPref - preferences={preferences} - labelGroup="nsfw" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref - preferences={preferences} - labelGroup="nudity" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref - preferences={preferences} - labelGroup="suggestive" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref - preferences={preferences} - labelGroup="gore" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref preferences={preferences} labelGroup="hate" /> - <ContentLabelPref preferences={preferences} labelGroup="spam" /> - <ContentLabelPref - preferences={preferences} - labelGroup="impersonation" - /> - <View style={{height: isMobile ? 60 : 0}} /> - </ScrollView> + <ScrollView style={styles.scrollContainer}> + <AdultContentEnabledPref /> + <ContentLabelPref + preferences={preferences} + labelGroup="nsfw" + disabled={!preferences?.adultContentEnabled} + /> + <ContentLabelPref + preferences={preferences} + labelGroup="nudity" + disabled={!preferences?.adultContentEnabled} + /> + <ContentLabelPref + preferences={preferences} + labelGroup="suggestive" + disabled={!preferences?.adultContentEnabled} + /> + <ContentLabelPref + preferences={preferences} + labelGroup="gore" + disabled={!preferences?.adultContentEnabled} + /> + <ContentLabelPref preferences={preferences} labelGroup="hate" /> + <ContentLabelPref preferences={preferences} labelGroup="spam" /> + <ContentLabelPref + preferences={preferences} + labelGroup="impersonation" + /> + <View style={{height: isMobile ? 60 : 0}} /> + </ScrollView> - <View - style={[ - styles.btnContainer, - isMobile && styles.btnContainerMobile, - pal.borderDark, - ]}> - <Pressable - testID="sendReportBtn" - onPress={onPressDone} - accessibilityRole="button" - accessibilityLabel={_(msg`Done`)} - accessibilityHint=""> - <LinearGradient - colors={[gradients.blueLight.start, gradients.blueLight.end]} - start={{x: 0, y: 0}} - end={{x: 1, y: 1}} - style={[styles.btn]}> - <Text style={[s.white, s.bold, s.f18]}> - <Trans>Done</Trans> - </Text> - </LinearGradient> - </Pressable> - </View> + <View + style={[ + styles.btnContainer, + isMobile && styles.btnContainerMobile, + pal.borderDark, + ]}> + <Pressable + testID="sendReportBtn" + onPress={onPressDone} + accessibilityRole="button" + accessibilityLabel={_(msg`Done`)} + accessibilityHint=""> + <LinearGradient + colors={[gradients.blueLight.start, gradients.blueLight.end]} + start={{x: 0, y: 0}} + end={{x: 1, y: 1}} + style={[styles.btn]}> + <Text style={[s.white, s.bold, s.f18]}> + <Trans>Done</Trans> + </Text> + </LinearGradient> + </Pressable> </View> - ) - }, -) + </View> + ) +} function AdultContentEnabledPref() { const pal = usePalette('default') @@ -171,7 +168,7 @@ function AdultContentEnabledPref() { } // TODO: Refactor this component to pass labels down to each tab -const ContentLabelPref = observer(function ContentLabelPrefImpl({ +function ContentLabelPref({ preferences, labelGroup, disabled, @@ -217,7 +214,7 @@ const ContentLabelPref = observer(function ContentLabelPrefImpl({ )} </View> ) -}) +} interface SelectGroupProps { current: LabelPreference diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx index 973c7c3a7..82a826aca 100644 --- a/src/view/com/modals/InviteCodes.tsx +++ b/src/view/com/modals/InviteCodes.tsx @@ -5,7 +5,6 @@ import { View, ActivityIndicator, } from 'react-native' -import {observer} from 'mobx-react-lite' import {ComAtprotoServerDefs} from '@atproto/api' import { FontAwesomeIcon, @@ -129,7 +128,7 @@ export function Inner({invites}: {invites: InviteCodesQueryResponse}) { ) } -const InviteCode = observer(function InviteCodeImpl({ +function InviteCode({ testID, invite, used, @@ -211,7 +210,7 @@ const InviteCode = observer(function InviteCodeImpl({ ) : null} </View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/modals/LinkWarning.tsx b/src/view/com/modals/LinkWarning.tsx index cb86387a0..c63bc2a87 100644 --- a/src/view/com/modals/LinkWarning.tsx +++ b/src/view/com/modals/LinkWarning.tsx @@ -1,7 +1,6 @@ import React from 'react' import {Linking, SafeAreaView, StyleSheet, View} from 'react-native' import {ScrollView} from './util' -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' @@ -16,13 +15,7 @@ import {useModalControls} from '#/state/modals' export const snapPoints = ['50%'] -export const Component = observer(function Component({ - text, - href, -}: { - text: string - href: string -}) { +export function Component({text, href}: {text: string; href: string}) { const pal = usePalette('default') const {closeModal} = useModalControls() const {isMobile} = useWebMediaQueries() @@ -97,7 +90,7 @@ export const Component = observer(function Component({ </ScrollView> </SafeAreaView> ) -}) +} function LinkBox({href}: {href: string}) { const pal = usePalette('default') diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 38c8bc7ba..d834db40b 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -1,7 +1,6 @@ import React, {useRef, useEffect} from 'react' 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 {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' import {usePalette} from 'lib/hooks/usePalette' @@ -40,7 +39,7 @@ import * as LinkWarningModal from './LinkWarning' const DEFAULT_SNAPPOINTS = ['90%'] const HANDLE_HEIGHT = 24 -export const ModalsContainer = observer(function ModalsContainer() { +export function ModalsContainer() { const {isModalActive, activeModals} = useModals() const {closeModal} = useModalControls() const bottomSheetRef = useRef<BottomSheet>(null) @@ -198,7 +197,7 @@ export const ModalsContainer = observer(function ModalsContainer() { {element} </BottomSheet> ) -}) +} const styles = StyleSheet.create({ handle: { diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx index 28f6c36c9..74aa7b1a9 100644 --- a/src/view/com/modals/Modal.web.tsx +++ b/src/view/com/modals/Modal.web.tsx @@ -1,6 +1,5 @@ import React from 'react' import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import type {Modal as ModalIface} from '#/state/modals' @@ -33,7 +32,7 @@ import * as VerifyEmailModal from './VerifyEmail' import * as ChangeEmailModal from './ChangeEmail' import * as LinkWarningModal from './LinkWarning' -export const ModalsContainer = observer(function ModalsContainer() { +export function ModalsContainer() { const {isModalActive, activeModals} = useModals() if (!isModalActive) { @@ -47,7 +46,7 @@ export const ModalsContainer = observer(function ModalsContainer() { ))} </> ) -}) +} function Modal({modal}: {modal: ModalIface}) { const {isModalActive} = useModals() diff --git a/src/view/com/modals/SelfLabel.tsx b/src/view/com/modals/SelfLabel.tsx index f8b64085d..092dd2d32 100644 --- a/src/view/com/modals/SelfLabel.tsx +++ b/src/view/com/modals/SelfLabel.tsx @@ -1,6 +1,5 @@ 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 {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' @@ -17,7 +16,7 @@ const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn'] export const snapPoints = ['50%'] -export const Component = observer(function Component({ +export function Component({ labels, hasMedia, onChange, @@ -161,7 +160,7 @@ export const Component = observer(function Component({ </View> </View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx index 09a460315..b30293859 100644 --- a/src/view/com/modals/ServerInput.tsx +++ b/src/view/com/modals/ServerInput.tsx @@ -9,7 +9,7 @@ import {Text} from '../util/text/Text' 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 {LOCAL_DEV_SERVICE, STAGING_SERVICE, PROD_SERVICE} from 'lib/constants' import {LOGIN_INCLUDE_DEV_SERVERS} from 'lib/build-flags' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' diff --git a/src/view/com/modals/VerifyEmail.tsx b/src/view/com/modals/VerifyEmail.tsx index 106e05b87..e7a4537c5 100644 --- a/src/view/com/modals/VerifyEmail.tsx +++ b/src/view/com/modals/VerifyEmail.tsx @@ -8,7 +8,6 @@ import { } from 'react-native' import {Svg, Circle, Path} from 'react-native-svg' import {ScrollView, TextInput} from './util' -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' @@ -32,11 +31,7 @@ enum Stages { ConfirmCode, } -export const Component = observer(function Component({ - showReminder, -}: { - showReminder?: boolean -}) { +export function Component({showReminder}: {showReminder?: boolean}) { const pal = usePalette('default') const {agent, currentAccount} = useSession() const {updateCurrentAccount} = useSessionApi() @@ -244,7 +239,7 @@ export const Component = observer(function Component({ </ScrollView> </SafeAreaView> ) -}) +} function ReminderIllustration() { const pal = usePalette('default') diff --git a/src/view/com/modals/lang-settings/LanguageToggle.tsx b/src/view/com/modals/lang-settings/LanguageToggle.tsx index 86e38a4d2..45b100f20 100644 --- a/src/view/com/modals/lang-settings/LanguageToggle.tsx +++ b/src/view/com/modals/lang-settings/LanguageToggle.tsx @@ -1,11 +1,10 @@ import React from 'react' import {StyleSheet} from 'react-native' import {usePalette} from 'lib/hooks/usePalette' -import {observer} from 'mobx-react-lite' import {ToggleButton} from 'view/com/util/forms/ToggleButton' import {useLanguagePrefs, toPostLanguages} from '#/state/preferences/languages' -export const LanguageToggle = observer(function LanguageToggleImpl({ +export function LanguageToggle({ code2, name, onPress, @@ -39,7 +38,7 @@ export const LanguageToggle = observer(function LanguageToggleImpl({ style={[pal.border, styles.languageToggle, isDisabled && styles.dimmed]} /> ) -}) +} const styles = StyleSheet.create({ languageToggle: { diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx index 7fcb24d58..05cfb8115 100644 --- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx @@ -1,6 +1,5 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {ScrollView} from '../util' import {Text} from '../../util/text/Text' import {usePalette} from 'lib/hooks/usePalette' @@ -19,7 +18,7 @@ import { export const snapPoints = ['100%'] -export const Component = observer(function PostLanguagesSettingsImpl() { +export function Component() { const {closeModal} = useModalControls() const langPrefs = useLanguagePrefs() const setLangPrefs = useLanguagePrefsApi() @@ -111,7 +110,7 @@ export const Component = observer(function PostLanguagesSettingsImpl() { <ConfirmLanguagesButton onPress={onPressDone} /> </View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/modals/report/Modal.tsx b/src/view/com/modals/report/Modal.tsx index 5183bdc10..06075547f 100644 --- a/src/view/com/modals/report/Modal.tsx +++ b/src/view/com/modals/report/Modal.tsx @@ -2,7 +2,6 @@ import React, {useState, useMemo} from 'react' import {Linking, StyleSheet, TouchableOpacity, View} from 'react-native' import {ScrollView} from 'react-native-gesture-handler' import {AtUri} 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' @@ -17,6 +16,7 @@ import {CollectionId} from './types' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useModalControls} from '#/state/modals' +import {useSession} from '#/state/session' const DMCA_LINK = 'https://blueskyweb.xyz/support/copyright' @@ -39,7 +39,7 @@ type ReportComponentProps = } export function Component(content: ReportComponentProps) { - const store = useStores() + const {agent} = useSession() const {closeModal} = useModalControls() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() @@ -70,7 +70,7 @@ export function Component(content: ReportComponentProps) { const $type = !isAccountReport ? 'com.atproto.repo.strongRef' : 'com.atproto.admin.defs#repoRef' - await store.agent.createModerationReport({ + await agent.createModerationReport({ reasonType: issue, subject: { $type, diff --git a/src/view/com/pager/FeedsTabBar.web.tsx b/src/view/com/pager/FeedsTabBar.web.tsx index b48690a66..298372893 100644 --- a/src/view/com/pager/FeedsTabBar.web.tsx +++ b/src/view/com/pager/FeedsTabBar.web.tsx @@ -1,7 +1,6 @@ import React from 'react' import {StyleSheet} from 'react-native' import Animated from 'react-native-reanimated' -import {observer} from 'mobx-react-lite' import {TabBar} from 'view/com/pager/TabBar' import {RenderTabBarFnProps} from 'view/com/pager/Pager' import {usePalette} from 'lib/hooks/usePalette' @@ -11,7 +10,7 @@ import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' import {useShellLayout} from '#/state/shell/shell-layout' import {usePinnedFeedsInfos} from '#/state/queries/feed' -export const FeedsTabBar = observer(function FeedsTabBarImpl( +export function FeedsTabBar( props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, ) { const {isMobile, isTablet} = useWebMediaQueries() @@ -22,9 +21,9 @@ export const FeedsTabBar = observer(function FeedsTabBarImpl( } else { return null } -}) +} -const FeedsTabBarTablet = observer(function FeedsTabBarTabletImpl( +function FeedsTabBarTablet( props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, ) { const feeds = usePinnedFeedsInfos() @@ -48,7 +47,7 @@ const FeedsTabBarTablet = observer(function FeedsTabBarTabletImpl( /> </Animated.View> ) -}) +} const styles = StyleSheet.create({ tabBar: { diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx index de985fb7c..e0c0be1ef 100644 --- a/src/view/com/pager/FeedsTabBarMobile.tsx +++ b/src/view/com/pager/FeedsTabBarMobile.tsx @@ -1,6 +1,5 @@ import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {TabBar} from 'view/com/pager/TabBar' import {RenderTabBarFnProps} from 'view/com/pager/Pager' import {usePalette} from 'lib/hooks/usePalette' @@ -20,7 +19,7 @@ import {useShellLayout} from '#/state/shell/shell-layout' import {useSession} from '#/state/session' import {usePinnedFeedsInfos} from '#/state/queries/feed' -export const FeedsTabBar = observer(function FeedsTabBarImpl( +export function FeedsTabBar( props: RenderTabBarFnProps & {testID?: string; onPressSelected: () => void}, ) { const pal = usePalette('default') @@ -88,7 +87,7 @@ export const FeedsTabBar = observer(function FeedsTabBarImpl( /> </Animated.View> ) -}) +} const styles = StyleSheet.create({ tabBar: { diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx index fad9f9b4e..99ee38536 100644 --- a/src/view/com/posts/FeedSlice.tsx +++ b/src/view/com/posts/FeedSlice.tsx @@ -1,6 +1,5 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FeedPostSlice} from '#/state/queries/post-feed' import {AtUri, moderatePost, ModerationOpts} from '@atproto/api' import {Link} from '../util/Link' @@ -10,7 +9,7 @@ import {FeedItem} from './FeedItem' import {usePalette} from 'lib/hooks/usePalette' import {makeProfileLink} from 'lib/routes/links' -export const FeedSlice = observer(function FeedSliceImpl({ +export function FeedSlice({ slice, dataUpdatedAt, ignoreFilterFor, @@ -94,7 +93,7 @@ export const FeedSlice = observer(function FeedSliceImpl({ ))} </> ) -}) +} function ViewFullThread({slice}: {slice: FeedPostSlice}) { const pal = usePalette('default') diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index 2f359018f..cd9855456 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -1,6 +1,5 @@ import * as React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' -import {observer} from 'mobx-react-lite' import { AppBskyActorDefs, moderateProfile, @@ -152,7 +151,7 @@ function ProfileCardPills({ ) } -const FollowersList = observer(function FollowersListImpl({ +function FollowersList({ followers, }: { followers?: AppBskyActorDefs.ProfileView[] | undefined @@ -196,7 +195,7 @@ const FollowersList = observer(function FollowersListImpl({ ))} </View> ) -}) +} export function ProfileCardWithFollowBtn({ profile, diff --git a/src/view/com/profile/ProfileSubpageHeader.tsx b/src/view/com/profile/ProfileSubpageHeader.tsx index ef128e877..0e245f0f4 100644 --- a/src/view/com/profile/ProfileSubpageHeader.tsx +++ b/src/view/com/profile/ProfileSubpageHeader.tsx @@ -1,6 +1,5 @@ import React from 'react' import {Pressable, StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {useNavigation} from '@react-navigation/native' import {usePalette} from 'lib/hooks/usePalette' @@ -12,7 +11,6 @@ import {LoadingPlaceholder} from '../util/LoadingPlaceholder' import {CenteredView} from '../util/Views' import {sanitizeHandle} from 'lib/strings/handles' import {makeProfileLink} from 'lib/routes/links' -import {useStores} from 'state/index' import {NavigationProp} from 'lib/routes/types' import {BACK_HITSLOP} from 'lib/constants' import {isNative} from 'platform/detection' @@ -22,7 +20,7 @@ import {msg} from '@lingui/macro' import {useSetDrawerOpen} from '#/state/shell' import {emitSoftReset} from '#/state/events' -export const ProfileSubpageHeader = observer(function HeaderImpl({ +export function ProfileSubpageHeader({ isLoading, href, title, @@ -45,7 +43,6 @@ export const ProfileSubpageHeader = observer(function HeaderImpl({ | undefined avatarType: UserAvatarType }>) { - const store = useStores() const setDrawerOpen = useSetDrawerOpen() const navigation = useNavigation<NavigationProp>() const {_} = useLingui() @@ -183,7 +180,7 @@ export const ProfileSubpageHeader = observer(function HeaderImpl({ </View> </CenteredView> ) -}) +} const styles = StyleSheet.create({ backBtn: { diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index c5e438f8d..fa5f12f6b 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -6,7 +6,6 @@ import {niceDate} from 'lib/strings/time' import {usePalette} from 'lib/hooks/usePalette' import {TypographyVariant} from 'lib/ThemeContext' import {UserAvatar} from './UserAvatar' -import {observer} from 'mobx-react-lite' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {isAndroid} from 'platform/detection' @@ -30,7 +29,7 @@ interface PostMetaOpts { style?: StyleProp<ViewStyle> } -export const PostMeta = observer(function PostMetaImpl(opts: PostMetaOpts) { +export function PostMeta(opts: PostMetaOpts) { const pal = usePalette('default') const displayName = opts.author.displayName || opts.author.handle const handle = opts.author.handle @@ -92,7 +91,7 @@ export const PostMeta = observer(function PostMetaImpl(opts: PostMetaOpts) { </TimeElapsed> </View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/util/SimpleViewHeader.tsx b/src/view/com/util/SimpleViewHeader.tsx index c871d9404..e86e37565 100644 --- a/src/view/com/util/SimpleViewHeader.tsx +++ b/src/view/com/util/SimpleViewHeader.tsx @@ -1,5 +1,4 @@ import React from 'react' -import {observer} from 'mobx-react-lite' import { StyleProp, StyleSheet, @@ -18,7 +17,7 @@ import {useSetDrawerOpen} from '#/state/shell' const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} -export const SimpleViewHeader = observer(function SimpleViewHeaderImpl({ +export function SimpleViewHeader({ showBackButton = true, style, children, @@ -76,7 +75,7 @@ export const SimpleViewHeader = observer(function SimpleViewHeaderImpl({ {children} </Container> ) -}) +} const styles = StyleSheet.create({ header: { diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx index adf2e4f08..082cae59c 100644 --- a/src/view/com/util/ViewHeader.tsx +++ b/src/view/com/util/ViewHeader.tsx @@ -1,5 +1,4 @@ import React from 'react' -import {observer} from 'mobx-react-lite' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {useNavigation} from '@react-navigation/native' @@ -15,7 +14,7 @@ import {useSetDrawerOpen} from '#/state/shell' const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20} -export const ViewHeader = observer(function ViewHeaderImpl({ +export function ViewHeader({ title, canGoBack, showBackButton = true, @@ -108,7 +107,7 @@ export const ViewHeader = observer(function ViewHeaderImpl({ </Container> ) } -}) +} function DesktopWebHeader({ title, @@ -140,7 +139,7 @@ function DesktopWebHeader({ ) } -const Container = observer(function ContainerImpl({ +function Container({ children, hideOnScroll, showBorder, @@ -178,7 +177,7 @@ const Container = observer(function ContainerImpl({ {children} </Animated.View> ) -}) +} const styles = StyleSheet.create({ header: { diff --git a/src/view/com/util/fab/FABInner.tsx b/src/view/com/util/fab/FABInner.tsx index 5b1d5d888..9787d92fb 100644 --- a/src/view/com/util/fab/FABInner.tsx +++ b/src/view/com/util/fab/FABInner.tsx @@ -1,5 +1,4 @@ import React, {ComponentProps} from 'react' -import {observer} from 'mobx-react-lite' import {StyleSheet, TouchableWithoutFeedback} from 'react-native' import LinearGradient from 'react-native-linear-gradient' import {gradients} from 'lib/styles' @@ -15,11 +14,7 @@ export interface FABProps icon: JSX.Element } -export const FABInner = observer(function FABInnerImpl({ - testID, - icon, - ...props -}: FABProps) { +export function FABInner({testID, icon, ...props}: FABProps) { const insets = useSafeAreaInsets() const {isMobile, isTablet} = useWebMediaQueries() const {fabMinimalShellTransform} = useMinimalShellMode() @@ -55,7 +50,7 @@ export const FABInner = observer(function FABInnerImpl({ </Animated.View> </TouchableWithoutFeedback> ) -}) +} const styles = StyleSheet.create({ sizeRegular: { diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx index 6cbcddc32..b5b6c1b52 100644 --- a/src/view/com/util/images/AutoSizedImage.tsx +++ b/src/view/com/util/images/AutoSizedImage.tsx @@ -2,8 +2,8 @@ import React from 'react' import {StyleProp, StyleSheet, Pressable, View, ViewStyle} from 'react-native' import {Image} from 'expo-image' import {clamp} from 'lib/numbers' -import {useStores} from 'state/index' import {Dimensions} from 'lib/media/types' +import * as imageSizes from 'lib/media/image-sizes' const MIN_ASPECT_RATIO = 0.33 // 1/3 const MAX_ASPECT_RATIO = 5 // 5/1 @@ -29,9 +29,8 @@ export function AutoSizedImage({ style, children = null, }: Props) { - const store = useStores() const [dim, setDim] = React.useState<Dimensions | undefined>( - dimensionsHint || store.imageSizes.get(uri), + dimensionsHint || imageSizes.get(uri), ) const [aspectRatio, setAspectRatio] = React.useState<number>( dim ? calc(dim) : 1, @@ -41,14 +40,14 @@ export function AutoSizedImage({ if (dim) { return } - store.imageSizes.fetch(uri).then(newDim => { + imageSizes.fetch(uri).then(newDim => { if (aborted) { return } setDim(newDim) setAspectRatio(calc(newDim)) }) - }, [dim, setDim, setAspectRatio, store, uri]) + }, [dim, setDim, setAspectRatio, uri]) if (onPress || onLongPress || onPressIn) { return ( diff --git a/src/view/com/util/load-latest/LoadLatestBtn.tsx b/src/view/com/util/load-latest/LoadLatestBtn.tsx index f9a9387bb..970d3a73a 100644 --- a/src/view/com/util/load-latest/LoadLatestBtn.tsx +++ b/src/view/com/util/load-latest/LoadLatestBtn.tsx @@ -1,6 +1,5 @@ import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' @@ -12,7 +11,7 @@ const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity) import {isWeb} from 'platform/detection' -export const LoadLatestBtn = observer(function LoadLatestBtnImpl({ +export function LoadLatestBtn({ onPress, label, showIndicator, @@ -44,7 +43,7 @@ export const LoadLatestBtn = observer(function LoadLatestBtnImpl({ {showIndicator && <View style={[styles.indicator, pal.borderDark]} />} </AnimatedTouchableOpacity> ) -}) +} const styles = StyleSheet.create({ loadLatest: { diff --git a/src/view/com/util/post-embeds/ListEmbed.tsx b/src/view/com/util/post-embeds/ListEmbed.tsx index dbf350039..fc5ad270f 100644 --- a/src/view/com/util/post-embeds/ListEmbed.tsx +++ b/src/view/com/util/post-embeds/ListEmbed.tsx @@ -1,12 +1,11 @@ import React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {usePalette} from 'lib/hooks/usePalette' -import {observer} from 'mobx-react-lite' import {ListCard} from 'view/com/lists/ListCard' import {AppBskyGraphDefs} from '@atproto/api' import {s} from 'lib/styles' -export const ListEmbed = observer(function ListEmbedImpl({ +export function ListEmbed({ item, style, }: { @@ -20,7 +19,7 @@ export const ListEmbed = observer(function ListEmbedImpl({ <ListCard list={item} style={[style, styles.card]} /> </View> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 8c80b0fd5..50db7e81f 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -1,6 +1,5 @@ import React from 'react' import {useFocusEffect} from '@react-navigation/native' -import {observer} from 'mobx-react-lite' import {NativeStackScreenProps, HomeTabNavigatorParams} from 'lib/routes/types' import {FeedDescriptor, FeedParams} from '#/state/queries/post-feed' import {withAuthRequired} from 'view/com/auth/withAuthRequired' @@ -15,130 +14,126 @@ import {usePreferencesQuery} from '#/state/queries/preferences' import {emitSoftReset} from '#/state/events' type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'> -export const HomeScreen = withAuthRequired( - observer(function HomeScreenImpl({}: Props) { - const setMinimalShellMode = useSetMinimalShellMode() - const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() - const pagerRef = React.useRef<PagerRef>(null) - const [selectedPage, setSelectedPage] = React.useState(0) - const [customFeeds, setCustomFeeds] = React.useState<FeedDescriptor[]>([]) - const {data: preferences} = usePreferencesQuery() - - React.useEffect(() => { - if (!preferences?.feeds?.pinned) return - - const pinned = preferences.feeds.pinned - - const feeds: FeedDescriptor[] = [] - - for (const uri of pinned) { - if (uri.includes('app.bsky.feed.generator')) { - feeds.push(`feedgen|${uri}`) - } else if (uri.includes('app.bsky.graph.list')) { - feeds.push(`list|${uri}`) - } +export const HomeScreen = withAuthRequired(function HomeScreenImpl({}: Props) { + const setMinimalShellMode = useSetMinimalShellMode() + const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() + const pagerRef = React.useRef<PagerRef>(null) + const [selectedPage, setSelectedPage] = React.useState(0) + const [customFeeds, setCustomFeeds] = React.useState<FeedDescriptor[]>([]) + const {data: preferences} = usePreferencesQuery() + + React.useEffect(() => { + if (!preferences?.feeds?.pinned) return + + const pinned = preferences.feeds.pinned + + const feeds: FeedDescriptor[] = [] + + for (const uri of pinned) { + if (uri.includes('app.bsky.feed.generator')) { + feeds.push(`feedgen|${uri}`) + } else if (uri.includes('app.bsky.graph.list')) { + feeds.push(`list|${uri}`) } + } - setCustomFeeds(feeds) + setCustomFeeds(feeds) - pagerRef.current?.setPage(0) - }, [preferences?.feeds?.pinned, setCustomFeeds, pagerRef]) + pagerRef.current?.setPage(0) + }, [preferences?.feeds?.pinned, setCustomFeeds, pagerRef]) - const homeFeedParams = React.useMemo<FeedParams>(() => { - if (!preferences) return {} + const homeFeedParams = React.useMemo<FeedParams>(() => { + if (!preferences) return {} - return { - mergeFeedEnabled: Boolean( - preferences.feedViewPrefs.lab_mergeFeedEnabled, - ), - mergeFeedSources: preferences.feeds.saved, - } - }, [preferences]) + return { + mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled), + mergeFeedSources: preferences.feeds.saved, + } + }, [preferences]) - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - setDrawerSwipeDisabled(selectedPage > 0) - return () => { - setDrawerSwipeDisabled(false) - } - }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]), - ) - - const onPageSelected = React.useCallback( - (index: number) => { + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + setDrawerSwipeDisabled(selectedPage > 0) + return () => { + setDrawerSwipeDisabled(false) + } + }, [setDrawerSwipeDisabled, selectedPage, setMinimalShellMode]), + ) + + const onPageSelected = React.useCallback( + (index: number) => { + setMinimalShellMode(false) + setSelectedPage(index) + setDrawerSwipeDisabled(index > 0) + }, + [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode], + ) + + const onPressSelected = React.useCallback(() => { + emitSoftReset() + }, []) + + const onPageScrollStateChanged = React.useCallback( + (state: 'idle' | 'dragging' | 'settling') => { + if (state === 'dragging') { setMinimalShellMode(false) - setSelectedPage(index) - setDrawerSwipeDisabled(index > 0) - }, - [setDrawerSwipeDisabled, setSelectedPage, setMinimalShellMode], - ) - - const onPressSelected = React.useCallback(() => { - emitSoftReset() - }, []) - - const onPageScrollStateChanged = React.useCallback( - (state: 'idle' | 'dragging' | 'settling') => { - if (state === 'dragging') { - setMinimalShellMode(false) - } - }, - [setMinimalShellMode], - ) - - const renderTabBar = React.useCallback( - (props: RenderTabBarFnProps) => { + } + }, + [setMinimalShellMode], + ) + + const renderTabBar = React.useCallback( + (props: RenderTabBarFnProps) => { + return ( + <FeedsTabBar + key="FEEDS_TAB_BAR" + selectedPage={props.selectedPage} + onSelect={props.onSelect} + testID="homeScreenFeedTabs" + onPressSelected={onPressSelected} + /> + ) + }, + [onPressSelected], + ) + + const renderFollowingEmptyState = React.useCallback(() => { + return <FollowingEmptyState /> + }, []) + + const renderCustomFeedEmptyState = React.useCallback(() => { + return <CustomFeedEmptyState /> + }, []) + + return ( + <Pager + ref={pagerRef} + testID="homeScreen" + onPageSelected={onPageSelected} + onPageScrollStateChanged={onPageScrollStateChanged} + renderTabBar={renderTabBar} + tabBarPosition="top"> + <FeedPage + key="1" + testID="followingFeedPage" + isPageFocused={selectedPage === 0} + feed="home" + feedParams={homeFeedParams} + renderEmptyState={renderFollowingEmptyState} + renderEndOfFeed={FollowingEndOfFeed} + /> + {customFeeds.map((f, index) => { return ( - <FeedsTabBar - key="FEEDS_TAB_BAR" - selectedPage={props.selectedPage} - onSelect={props.onSelect} - testID="homeScreenFeedTabs" - onPressSelected={onPressSelected} + <FeedPage + key={f} + testID="customFeedPage" + isPageFocused={selectedPage === 1 + index} + feed={f} + renderEmptyState={renderCustomFeedEmptyState} /> ) - }, - [onPressSelected], - ) - - const renderFollowingEmptyState = React.useCallback(() => { - return <FollowingEmptyState /> - }, []) - - const renderCustomFeedEmptyState = React.useCallback(() => { - return <CustomFeedEmptyState /> - }, []) - - return ( - <Pager - ref={pagerRef} - testID="homeScreen" - onPageSelected={onPageSelected} - onPageScrollStateChanged={onPageScrollStateChanged} - renderTabBar={renderTabBar} - tabBarPosition="top"> - <FeedPage - key="1" - testID="followingFeedPage" - isPageFocused={selectedPage === 0} - feed="home" - feedParams={homeFeedParams} - renderEmptyState={renderFollowingEmptyState} - renderEndOfFeed={FollowingEndOfFeed} - /> - {customFeeds.map((f, index) => { - return ( - <FeedPage - key={f} - testID="customFeedPage" - isPageFocused={selectedPage === 1 + index} - feed={f} - renderEmptyState={renderCustomFeedEmptyState} - /> - ) - })} - </Pager> - ) - }), -) + })} + </Pager> + ) +}) diff --git a/src/view/screens/LanguageSettings.tsx b/src/view/screens/LanguageSettings.tsx index 677451526..649daea0e 100644 --- a/src/view/screens/LanguageSettings.tsx +++ b/src/view/screens/LanguageSettings.tsx @@ -1,6 +1,5 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {Text} from '../com/util/text/Text' import {s} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' @@ -23,9 +22,7 @@ import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences' type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'> -export const LanguageSettingsScreen = observer(function LanguageSettingsImpl( - _: Props, -) { +export function LanguageSettingsScreen(_: Props) { const pal = usePalette('default') const langPrefs = useLanguagePrefs() const setLangPrefs = useLanguagePrefsApi() @@ -192,7 +189,7 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl( </View> </CenteredView> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/screens/Log.tsx b/src/view/screens/Log.tsx index 69c07edae..8680b851b 100644 --- a/src/view/screens/Log.tsx +++ b/src/view/screens/Log.tsx @@ -1,7 +1,6 @@ import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {useFocusEffect} from '@react-navigation/native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {ScrollView} from '../com/util/Views' @@ -15,7 +14,7 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' import {useSetMinimalShellMode} from '#/state/shell' -export const LogScreen = observer(function Log({}: NativeStackScreenProps< +export function LogScreen({}: NativeStackScreenProps< CommonNavigatorParams, 'Log' >) { @@ -88,7 +87,7 @@ export const LogScreen = observer(function Log({}: NativeStackScreenProps< </ScrollView> </View> ) -}) +} const styles = StyleSheet.create({ entry: { diff --git a/src/view/screens/Moderation.tsx b/src/view/screens/Moderation.tsx index eb952c068..37eecf22d 100644 --- a/src/view/screens/Moderation.tsx +++ b/src/view/screens/Moderation.tsx @@ -5,7 +5,6 @@ import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' -import {observer} from 'mobx-react-lite' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {s} from 'lib/styles' @@ -21,7 +20,7 @@ import {useModalControls} from '#/state/modals' type Props = NativeStackScreenProps<CommonNavigatorParams, 'Moderation'> export const ModerationScreen = withAuthRequired( - observer(function Moderation({}: Props) { + function Moderation({}: Props) { const pal = usePalette('default') const setMinimalShellMode = useSetMinimalShellMode() const {screen, track} = useAnalytics() @@ -111,7 +110,7 @@ export const ModerationScreen = withAuthRequired( </Link> </CenteredView> ) - }), + }, ) const styles = StyleSheet.create({ diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index 752f78dce..844a96d11 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -3,7 +3,6 @@ import {StyleSheet, View} from 'react-native' import Animated from 'react-native-reanimated' import {useFocusEffect} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' -import {observer} from 'mobx-react-lite' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {makeRecordUri} from 'lib/strings/url-helpers' import {withAuthRequired} from 'view/com/auth/withAuthRequired' @@ -26,83 +25,83 @@ import {CenteredView} from '../com/util/Views' import {useComposerControls} from '#/state/shell/composer' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'> -export const PostThreadScreen = withAuthRequired( - observer(function PostThreadScreenImpl({route}: Props) { - const queryClient = useQueryClient() - const {fabMinimalShellTransform} = useMinimalShellMode() - const setMinimalShellMode = useSetMinimalShellMode() - const {openComposer} = useComposerControls() - const safeAreaInsets = useSafeAreaInsets() - const {name, rkey} = route.params - const {isMobile} = useWebMediaQueries() - const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) - const {data: resolvedUri, error: uriError} = useResolveUriQuery(uri) +export const PostThreadScreen = withAuthRequired(function PostThreadScreenImpl({ + route, +}: Props) { + const queryClient = useQueryClient() + const {fabMinimalShellTransform} = useMinimalShellMode() + const setMinimalShellMode = useSetMinimalShellMode() + const {openComposer} = useComposerControls() + const safeAreaInsets = useSafeAreaInsets() + const {name, rkey} = route.params + const {isMobile} = useWebMediaQueries() + const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) + const {data: resolvedUri, error: uriError} = useResolveUriQuery(uri) - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - const onPressReply = React.useCallback(() => { - if (!resolvedUri) { - return - } - const thread = queryClient.getQueryData<ThreadNode>( - POST_THREAD_RQKEY(resolvedUri.uri), - ) - if (thread?.type !== 'post') { - return - } - openComposer({ - replyTo: { - uri: thread.post.uri, - cid: thread.post.cid, - text: thread.record.text, - author: { - handle: thread.post.author.handle, - displayName: thread.post.author.displayName, - avatar: thread.post.author.avatar, - }, + const onPressReply = React.useCallback(() => { + if (!resolvedUri) { + return + } + const thread = queryClient.getQueryData<ThreadNode>( + POST_THREAD_RQKEY(resolvedUri.uri), + ) + if (thread?.type !== 'post') { + return + } + openComposer({ + replyTo: { + uri: thread.post.uri, + cid: thread.post.cid, + text: thread.record.text, + author: { + handle: thread.post.author.handle, + displayName: thread.post.author.displayName, + avatar: thread.post.author.avatar, }, - onPost: () => - queryClient.invalidateQueries({ - queryKey: POST_THREAD_RQKEY(resolvedUri.uri || ''), - }), - }) - }, [openComposer, queryClient, resolvedUri]) + }, + onPost: () => + queryClient.invalidateQueries({ + queryKey: POST_THREAD_RQKEY(resolvedUri.uri || ''), + }), + }) + }, [openComposer, queryClient, resolvedUri]) - return ( - <View style={s.hContentRegion}> - {isMobile && <ViewHeader title="Post" />} - <View style={s.flex1}> - {uriError ? ( - <CenteredView> - <ErrorMessage message={String(uriError)} /> - </CenteredView> - ) : ( - <PostThreadComponent - uri={resolvedUri?.uri} - onPressReply={onPressReply} - /> - )} - </View> - {isMobile && ( - <Animated.View - style={[ - styles.prompt, - fabMinimalShellTransform, - { - bottom: clamp(safeAreaInsets.bottom, 15, 30), - }, - ]}> - <ComposePrompt onPressCompose={onPressReply} /> - </Animated.View> + return ( + <View style={s.hContentRegion}> + {isMobile && <ViewHeader title="Post" />} + <View style={s.flex1}> + {uriError ? ( + <CenteredView> + <ErrorMessage message={String(uriError)} /> + </CenteredView> + ) : ( + <PostThreadComponent + uri={resolvedUri?.uri} + onPressReply={onPressReply} + /> )} </View> - ) - }), -) + {isMobile && ( + <Animated.View + style={[ + styles.prompt, + fabMinimalShellTransform, + { + bottom: clamp(safeAreaInsets.bottom, 15, 30), + }, + ]}> + <ComposePrompt onPressCompose={onPressReply} /> + </Animated.View> + )} + </View> + ) +}) const styles = StyleSheet.create({ prompt: { diff --git a/src/view/screens/PreferencesHomeFeed.tsx b/src/view/screens/PreferencesHomeFeed.tsx index 7b240ded0..2fd0eff37 100644 --- a/src/view/screens/PreferencesHomeFeed.tsx +++ b/src/view/screens/PreferencesHomeFeed.tsx @@ -1,6 +1,5 @@ import React, {useState} from 'react' import {ScrollView, StyleSheet, TouchableOpacity, View} from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Slider} from '@miblanchard/react-native-slider' import {Text} from '../com/util/text/Text' @@ -72,9 +71,7 @@ type Props = NativeStackScreenProps< CommonNavigatorParams, 'PreferencesHomeFeed' > -export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ - navigation, -}: Props) { +export function PreferencesHomeFeed({navigation}: Props) { const pal = usePalette('default') const {_} = useLingui() const {isTabletOrDesktop} = useWebMediaQueries() @@ -308,7 +305,7 @@ export const PreferencesHomeFeed = observer(function PreferencesHomeFeedImpl({ </View> </CenteredView> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/screens/PreferencesThreads.tsx b/src/view/screens/PreferencesThreads.tsx index 2386f6445..7bd87b712 100644 --- a/src/view/screens/PreferencesThreads.tsx +++ b/src/view/screens/PreferencesThreads.tsx @@ -6,7 +6,6 @@ import { TouchableOpacity, View, } from 'react-native' -import {observer} from 'mobx-react-lite' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Text} from '../com/util/text/Text' import {s, colors} from 'lib/styles' @@ -25,9 +24,7 @@ import { } from '#/state/queries/preferences' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PreferencesThreads'> -export const PreferencesThreads = observer(function PreferencesThreadsImpl({ - navigation, -}: Props) { +export function PreferencesThreads({navigation}: Props) { const pal = usePalette('default') const {_} = useLingui() const {isTabletOrDesktop} = useWebMediaQueries() @@ -162,7 +159,7 @@ export const PreferencesThreads = observer(function PreferencesThreadsImpl({ </View> </CenteredView> ) -}) +} const styles = StyleSheet.create({ container: { diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx index f62790be6..62f5f1b36 100644 --- a/src/view/screens/ProfileFeed.tsx +++ b/src/view/screens/ProfileFeed.tsx @@ -15,7 +15,6 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {CommonNavigatorParams} from 'lib/routes/types' import {makeRecordUri} from 'lib/strings/url-helpers' import {colors, s} from 'lib/styles' -import {observer} from 'mobx-react-lite' import {FeedDescriptor} from '#/state/queries/post-feed' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' @@ -71,7 +70,7 @@ interface SectionRef { type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeed'> export const ProfileFeedScreen = withAuthRequired( - observer(function ProfileFeedScreenImpl(props: Props) { + function ProfileFeedScreenImpl(props: Props) { const {rkey, name: handleOrDid} = props.route.params const pal = usePalette('default') @@ -129,7 +128,7 @@ export const ProfileFeedScreen = withAuthRequired( </View> </CenteredView> ) - }), + }, ) function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) { @@ -154,7 +153,7 @@ function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) { ) } -export const ProfileFeedScreenInner = function ProfileFeedScreenInnerImpl({ +export function ProfileFeedScreenInner({ preferences, feedInfo, }: { @@ -485,7 +484,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( }, ) -const AboutSection = observer(function AboutPageImpl({ +function AboutSection({ feedOwnerDid, feedRkey, feedInfo, @@ -606,7 +605,7 @@ const AboutSection = observer(function AboutPageImpl({ </View> </ScrollView> ) -}) +} const styles = StyleSheet.create({ btn: { diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx index c7abcf090..e3e50ca24 100644 --- a/src/view/screens/SavedFeeds.tsx +++ b/src/view/screens/SavedFeeds.tsx @@ -14,7 +14,6 @@ import {track} from '#/lib/analytics/analytics' import {useAnalytics} from 'lib/analytics/analytics' import {usePalette} from 'lib/hooks/usePalette' import {CommonNavigatorParams} from 'lib/routes/types' -import {observer} from 'mobx-react-lite' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import {ViewHeader} from 'view/com/util/ViewHeader' @@ -146,7 +145,7 @@ export const SavedFeeds = withAuthRequired(function SavedFeedsImpl({}: Props) { ) }) -const ListItem = observer(function ListItemImpl({ +function ListItem({ feedUri, isPinned, }: { @@ -269,7 +268,7 @@ const ListItem = observer(function ListItemImpl({ </TouchableOpacity> </Pressable> ) -}) +} const styles = StyleSheet.create({ desktopContainer: { diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx index 3f7ef146a..916fd2a53 100644 --- a/src/view/screens/Settings.tsx +++ b/src/view/screens/Settings.tsx @@ -19,11 +19,9 @@ import { FontAwesomeIcon, FontAwesomeIconStyle, } from '@fortawesome/react-native-fontawesome' -import {observer} from 'mobx-react-lite' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {withAuthRequired} from 'view/com/auth/withAuthRequired' import * as AppInfo from 'lib/app-info' -import {useStores} from 'state/index' import {s, colors} from 'lib/styles' import {ScrollView} from '../com/util/Views' import {ViewHeader} from '../com/util/ViewHeader' @@ -45,7 +43,7 @@ import {formatCount} from 'view/com/util/numeric/format' import Clipboard from '@react-native-clipboard/clipboard' import {makeProfileLink} from 'lib/routes/links' import {AccountDropdownBtn} from 'view/com/util/AccountDropdownBtn' -import {logger} from '#/logger' +import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile' import {useModalControls} from '#/state/modals' import { useSetMinimalShellMode, @@ -69,6 +67,7 @@ import {useDebugHeaderSetting} from 'lib/api/debug-appview-proxy-header' import {STATUS_PAGE_URL} from 'lib/constants' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' +import {useQueryClient} from '@tanstack/react-query' function SettingsAccountCard({account}: {account: SessionAccount}) { const pal = usePalette('default') @@ -135,630 +134,620 @@ function SettingsAccountCard({account}: {account: SessionAccount}) { } type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'> -export const SettingsScreen = withAuthRequired( - observer(function Settings({}: Props) { - const colorMode = useColorMode() - const setColorMode = useSetColorMode() - const pal = usePalette('default') - const store = useStores() - const {_} = useLingui() - const setMinimalShellMode = useSetMinimalShellMode() - const requireAltTextEnabled = useRequireAltTextEnabled() - const setRequireAltTextEnabled = useSetRequireAltTextEnabled() - const onboardingDispatch = useOnboardingDispatch() - const navigation = useNavigation<NavigationProp>() - const {isMobile} = useWebMediaQueries() - const {screen, track} = useAnalytics() - const [debugHeaderEnabled, toggleDebugHeader] = useDebugHeaderSetting( - store.agent, - ) - const {openModal} = useModalControls() - const {isSwitchingAccounts, accounts, currentAccount} = useSession() - const {clearCurrentAccount} = useSessionApi() - const {mutate: clearPreferences} = useClearPreferencesMutation() - const {data: invites} = useInviteCodesQuery() - const invitesAvailable = invites?.available?.length ?? 0 - - const primaryBg = useCustomPalette<ViewStyle>({ - light: {backgroundColor: colors.blue0}, - dark: {backgroundColor: colors.blue6}, - }) - const primaryText = useCustomPalette<TextStyle>({ - light: {color: colors.blue3}, - dark: {color: colors.blue2}, - }) +export const SettingsScreen = withAuthRequired(function Settings({}: Props) { + const queryClient = useQueryClient() + const colorMode = useColorMode() + const setColorMode = useSetColorMode() + const pal = usePalette('default') + const {_} = useLingui() + const setMinimalShellMode = useSetMinimalShellMode() + const requireAltTextEnabled = useRequireAltTextEnabled() + const setRequireAltTextEnabled = useSetRequireAltTextEnabled() + const onboardingDispatch = useOnboardingDispatch() + const navigation = useNavigation<NavigationProp>() + const {isMobile} = useWebMediaQueries() + const {screen, track} = useAnalytics() + const {openModal} = useModalControls() + const {isSwitchingAccounts, accounts, currentAccount, agent} = useSession() + const {clearCurrentAccount} = useSessionApi() + const [debugHeaderEnabled, toggleDebugHeader] = useDebugHeaderSetting(agent) + const {mutate: clearPreferences} = useClearPreferencesMutation() + const {data: invites} = useInviteCodesQuery() + const invitesAvailable = invites?.available?.length ?? 0 + + const primaryBg = useCustomPalette<ViewStyle>({ + light: {backgroundColor: colors.blue0}, + dark: {backgroundColor: colors.blue6}, + }) + const primaryText = useCustomPalette<TextStyle>({ + light: {color: colors.blue3}, + dark: {color: colors.blue2}, + }) + + const dangerBg = useCustomPalette<ViewStyle>({ + light: {backgroundColor: colors.red1}, + dark: {backgroundColor: colors.red7}, + }) + const dangerText = useCustomPalette<TextStyle>({ + light: {color: colors.red4}, + dark: {color: colors.red2}, + }) + + useFocusEffect( + React.useCallback(() => { + screen('Settings') + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), + ) - const dangerBg = useCustomPalette<ViewStyle>({ - light: {backgroundColor: colors.red1}, - dark: {backgroundColor: colors.red7}, - }) - const dangerText = useCustomPalette<TextStyle>({ - light: {color: colors.red4}, - dark: {color: colors.red2}, + const onPressAddAccount = React.useCallback(() => { + track('Settings:AddAccountButtonClicked') + navigation.navigate('HomeTab') + navigation.dispatch(StackActions.popToTop()) + clearCurrentAccount() + }, [track, navigation, clearCurrentAccount]) + + const onPressChangeHandle = React.useCallback(() => { + track('Settings:ChangeHandleButtonClicked') + openModal({ + name: 'change-handle', + onChanged() { + if (currentAccount) { + // refresh my profile + queryClient.invalidateQueries({ + queryKey: RQKEY_PROFILE(currentAccount.did), + }) + } + }, }) + }, [track, queryClient, openModal, currentAccount]) - useFocusEffect( - React.useCallback(() => { - screen('Settings') - setMinimalShellMode(false) - }, [screen, setMinimalShellMode]), - ) + const onPressInviteCodes = React.useCallback(() => { + track('Settings:InvitecodesButtonClicked') + openModal({name: 'invite-codes'}) + }, [track, openModal]) + + const onPressLanguageSettings = React.useCallback(() => { + navigation.navigate('LanguageSettings') + }, [navigation]) - const onPressAddAccount = React.useCallback(() => { - track('Settings:AddAccountButtonClicked') - navigation.navigate('HomeTab') - navigation.dispatch(StackActions.popToTop()) - clearCurrentAccount() - }, [track, navigation, clearCurrentAccount]) - - const onPressChangeHandle = React.useCallback(() => { - track('Settings:ChangeHandleButtonClicked') - openModal({ - name: 'change-handle', - onChanged() { - store.session.reloadFromServer().then( - () => { - Toast.show('Your handle has been updated') - }, - err => { - logger.error('Failed to reload from server after handle update', { - error: err, - }) - }, - ) - }, - }) - }, [track, store, openModal]) - - const onPressInviteCodes = React.useCallback(() => { - track('Settings:InvitecodesButtonClicked') - openModal({name: 'invite-codes'}) - }, [track, openModal]) - - const onPressLanguageSettings = React.useCallback(() => { - navigation.navigate('LanguageSettings') - }, [navigation]) - - const onPressDeleteAccount = React.useCallback(() => { - openModal({name: 'delete-account'}) - }, [openModal]) - - const onPressResetPreferences = React.useCallback(async () => { - clearPreferences() - }, [clearPreferences]) - - const onPressResetOnboarding = React.useCallback(async () => { - onboardingDispatch({type: 'start'}) - Toast.show('Onboarding reset') - }, [onboardingDispatch]) - - const onPressBuildInfo = React.useCallback(() => { - Clipboard.setString( - `Build version: ${AppInfo.appVersion}; Platform: ${Platform.OS}`, - ) - Toast.show('Copied build version to clipboard') - }, []) - - const openHomeFeedPreferences = React.useCallback(() => { - navigation.navigate('PreferencesHomeFeed') - }, [navigation]) - - const openThreadsPreferences = React.useCallback(() => { - navigation.navigate('PreferencesThreads') - }, [navigation]) - - const onPressAppPasswords = React.useCallback(() => { - navigation.navigate('AppPasswords') - }, [navigation]) - - const onPressSystemLog = React.useCallback(() => { - navigation.navigate('Log') - }, [navigation]) - - const onPressStorybook = React.useCallback(() => { - navigation.navigate('Debug') - }, [navigation]) - - const onPressSavedFeeds = React.useCallback(() => { - navigation.navigate('SavedFeeds') - }, [navigation]) - - const onPressStatusPage = React.useCallback(() => { - Linking.openURL(STATUS_PAGE_URL) - }, []) - - return ( - <View style={[s.hContentRegion]} testID="settingsScreen"> - <ViewHeader title="Settings" /> - <ScrollView - style={[s.hContentRegion]} - contentContainerStyle={isMobile && pal.viewLight} - scrollIndicatorInsets={{right: 1}}> - <View style={styles.spacer20} /> - {currentAccount ? ( - <> - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Account</Trans> + const onPressDeleteAccount = React.useCallback(() => { + openModal({name: 'delete-account'}) + }, [openModal]) + + const onPressResetPreferences = React.useCallback(async () => { + clearPreferences() + }, [clearPreferences]) + + const onPressResetOnboarding = React.useCallback(async () => { + onboardingDispatch({type: 'start'}) + Toast.show('Onboarding reset') + }, [onboardingDispatch]) + + const onPressBuildInfo = React.useCallback(() => { + Clipboard.setString( + `Build version: ${AppInfo.appVersion}; Platform: ${Platform.OS}`, + ) + Toast.show('Copied build version to clipboard') + }, []) + + const openHomeFeedPreferences = React.useCallback(() => { + navigation.navigate('PreferencesHomeFeed') + }, [navigation]) + + const openThreadsPreferences = React.useCallback(() => { + navigation.navigate('PreferencesThreads') + }, [navigation]) + + const onPressAppPasswords = React.useCallback(() => { + navigation.navigate('AppPasswords') + }, [navigation]) + + const onPressSystemLog = React.useCallback(() => { + navigation.navigate('Log') + }, [navigation]) + + const onPressStorybook = React.useCallback(() => { + navigation.navigate('Debug') + }, [navigation]) + + const onPressSavedFeeds = React.useCallback(() => { + navigation.navigate('SavedFeeds') + }, [navigation]) + + const onPressStatusPage = React.useCallback(() => { + Linking.openURL(STATUS_PAGE_URL) + }, []) + + return ( + <View style={[s.hContentRegion]} testID="settingsScreen"> + <ViewHeader title="Settings" /> + <ScrollView + style={[s.hContentRegion]} + contentContainerStyle={isMobile && pal.viewLight} + scrollIndicatorInsets={{right: 1}}> + <View style={styles.spacer20} /> + {currentAccount ? ( + <> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Account</Trans> + </Text> + <View style={[styles.infoLine]}> + <Text type="lg-medium" style={pal.text}> + Email:{' '} </Text> - <View style={[styles.infoLine]}> - <Text type="lg-medium" style={pal.text}> - Email:{' '} - </Text> - {currentAccount.emailConfirmed && ( - <> - <FontAwesomeIcon - icon="check" - size={10} - style={{color: colors.green3, marginRight: 2}} - /> - </> - )} - <Text type="lg" style={pal.text}> - {currentAccount.email}{' '} + {currentAccount.emailConfirmed && ( + <> + <FontAwesomeIcon + icon="check" + size={10} + style={{color: colors.green3, marginRight: 2}} + /> + </> + )} + <Text type="lg" style={pal.text}> + {currentAccount.email}{' '} + </Text> + <Link onPress={() => openModal({name: 'change-email'})}> + <Text type="lg" style={pal.link}> + <Trans>Change</Trans> </Text> - <Link onPress={() => openModal({name: 'change-email'})}> - <Text type="lg" style={pal.link}> - <Trans>Change</Trans> - </Text> - </Link> - </View> - <View style={[styles.infoLine]}> - <Text type="lg-medium" style={pal.text}> - <Trans>Birthday:</Trans>{' '} + </Link> + </View> + <View style={[styles.infoLine]}> + <Text type="lg-medium" style={pal.text}> + <Trans>Birthday:</Trans>{' '} + </Text> + <Link onPress={() => openModal({name: 'birth-date-settings'})}> + <Text type="lg" style={pal.link}> + <Trans>Show</Trans> </Text> - <Link onPress={() => openModal({name: 'birth-date-settings'})}> - <Text type="lg" style={pal.link}> - <Trans>Show</Trans> - </Text> - </Link> - </View> - <View style={styles.spacer20} /> - - {!currentAccount.emailConfirmed && <EmailConfirmationNotice />} - </> - ) : null} - <View style={[s.flexRow, styles.heading]}> - <Text type="xl-bold" style={pal.text}> - <Trans>Signed in as</Trans> - </Text> - <View style={s.flex1} /> + </Link> + </View> + <View style={styles.spacer20} /> + + {!currentAccount.emailConfirmed && <EmailConfirmationNotice />} + </> + ) : null} + <View style={[s.flexRow, styles.heading]}> + <Text type="xl-bold" style={pal.text}> + <Trans>Signed in as</Trans> + </Text> + <View style={s.flex1} /> + </View> + + {isSwitchingAccounts ? ( + <View style={[pal.view, styles.linkCard]}> + <ActivityIndicator /> </View> + ) : ( + <SettingsAccountCard account={currentAccount!} /> + )} - {isSwitchingAccounts ? ( - <View style={[pal.view, styles.linkCard]}> - <ActivityIndicator /> - </View> - ) : ( - <SettingsAccountCard account={currentAccount!} /> - )} + {accounts + .filter(a => a.did !== currentAccount?.did) + .map(account => ( + <SettingsAccountCard key={account.did} account={account} /> + ))} - {accounts - .filter(a => a.did !== currentAccount?.did) - .map(account => ( - <SettingsAccountCard key={account.did} account={account} /> - ))} + <TouchableOpacity + testID="switchToNewAccountBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={isSwitchingAccounts ? undefined : onPressAddAccount} + accessibilityRole="button" + accessibilityLabel={_(msg`Add account`)} + accessibilityHint="Create a new Bluesky account"> + <View style={[styles.iconContainer, pal.btn]}> + <FontAwesomeIcon + icon="plus" + style={pal.text as FontAwesomeIconStyle} + /> + </View> + <Text type="lg" style={pal.text}> + <Trans>Add account</Trans> + </Text> + </TouchableOpacity> - <TouchableOpacity - testID="switchToNewAccountBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={isSwitchingAccounts ? undefined : onPressAddAccount} - accessibilityRole="button" - accessibilityLabel={_(msg`Add account`)} - accessibilityHint="Create a new Bluesky account"> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="plus" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Add account</Trans> - </Text> - </TouchableOpacity> + <View style={styles.spacer20} /> - <View style={styles.spacer20} /> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Invite a Friend</Trans> + </Text> - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Invite a Friend</Trans> + <TouchableOpacity + testID="inviteFriendBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={isSwitchingAccounts ? undefined : onPressInviteCodes} + accessibilityRole="button" + accessibilityLabel={_(msg`Invite`)} + accessibilityHint="Opens invite code list"> + <View + style={[ + styles.iconContainer, + invitesAvailable > 0 ? primaryBg : pal.btn, + ]}> + <FontAwesomeIcon + icon="ticket" + style={ + (invitesAvailable > 0 + ? primaryText + : pal.text) as FontAwesomeIconStyle + } + /> + </View> + <Text type="lg" style={invitesAvailable > 0 ? pal.link : pal.text}> + {formatCount(invitesAvailable)} invite{' '} + {pluralize(invitesAvailable, 'code')} available </Text> + </TouchableOpacity> - <TouchableOpacity - testID="inviteFriendBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={isSwitchingAccounts ? undefined : onPressInviteCodes} - accessibilityRole="button" - accessibilityLabel={_(msg`Invite`)} - accessibilityHint="Opens invite code list"> - <View - style={[ - styles.iconContainer, - invitesAvailable > 0 ? primaryBg : pal.btn, - ]}> - <FontAwesomeIcon - icon="ticket" - style={ - (invitesAvailable > 0 - ? primaryText - : pal.text) as FontAwesomeIconStyle - } - /> - </View> - <Text type="lg" style={invitesAvailable > 0 ? pal.link : pal.text}> - {formatCount(invitesAvailable)} invite{' '} - {pluralize(invitesAvailable, 'code')} available - </Text> - </TouchableOpacity> + <View style={styles.spacer20} /> - <View style={styles.spacer20} /> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Accessibility</Trans> + </Text> + <View style={[pal.view, styles.toggleCard]}> + <ToggleButton + type="default-light" + label="Require alt text before posting" + labelType="lg" + isSelected={requireAltTextEnabled} + onPress={() => setRequireAltTextEnabled(!requireAltTextEnabled)} + /> + </View> - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Accessibility</Trans> - </Text> - <View style={[pal.view, styles.toggleCard]}> - <ToggleButton - type="default-light" - label="Require alt text before posting" - labelType="lg" - isSelected={requireAltTextEnabled} - onPress={() => setRequireAltTextEnabled(!requireAltTextEnabled)} + <View style={styles.spacer20} /> + + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Appearance</Trans> + </Text> + <View> + <View style={[styles.linkCard, pal.view, styles.selectableBtns]}> + <SelectableBtn + selected={colorMode === 'system'} + label="System" + left + onSelect={() => setColorMode('system')} + accessibilityHint="Set color theme to system setting" + /> + <SelectableBtn + selected={colorMode === 'light'} + label="Light" + onSelect={() => setColorMode('light')} + accessibilityHint="Set color theme to light" + /> + <SelectableBtn + selected={colorMode === 'dark'} + label="Dark" + right + onSelect={() => setColorMode('dark')} + accessibilityHint="Set color theme to dark" /> </View> + </View> + <View style={styles.spacer20} /> - <View style={styles.spacer20} /> - - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Appearance</Trans> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Basics</Trans> + </Text> + <TouchableOpacity + testID="preferencesHomeFeedButton" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={openHomeFeedPreferences} + accessibilityRole="button" + accessibilityHint="" + accessibilityLabel={_(msg`Opens the home feed preferences`)}> + <View style={[styles.iconContainer, pal.btn]}> + <FontAwesomeIcon + icon="sliders" + style={pal.text as FontAwesomeIconStyle} + /> + </View> + <Text type="lg" style={pal.text}> + <Trans>Home Feed Preferences</Trans> </Text> - <View> - <View style={[styles.linkCard, pal.view, styles.selectableBtns]}> - <SelectableBtn - selected={colorMode === 'system'} - label="System" - left - onSelect={() => setColorMode('system')} - accessibilityHint="Set color theme to system setting" - /> - <SelectableBtn - selected={colorMode === 'light'} - label="Light" - onSelect={() => setColorMode('light')} - accessibilityHint="Set color theme to light" - /> - <SelectableBtn - selected={colorMode === 'dark'} - label="Dark" - right - onSelect={() => setColorMode('dark')} - accessibilityHint="Set color theme to dark" - /> - </View> + </TouchableOpacity> + <TouchableOpacity + testID="preferencesThreadsButton" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={openThreadsPreferences} + accessibilityRole="button" + accessibilityHint="" + accessibilityLabel={_(msg`Opens the threads preferences`)}> + <View style={[styles.iconContainer, pal.btn]}> + <FontAwesomeIcon + icon={['far', 'comments']} + style={pal.text as FontAwesomeIconStyle} + size={18} + /> </View> - <View style={styles.spacer20} /> - - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Basics</Trans> + <Text type="lg" style={pal.text}> + <Trans>Thread Preferences</Trans> </Text> - <TouchableOpacity - testID="preferencesHomeFeedButton" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={openHomeFeedPreferences} - accessibilityRole="button" - accessibilityHint="" - accessibilityLabel={_(msg`Opens the home feed preferences`)}> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="sliders" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Home Feed Preferences</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - testID="preferencesThreadsButton" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={openThreadsPreferences} - accessibilityRole="button" - accessibilityHint="" - accessibilityLabel={_(msg`Opens the threads preferences`)}> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon={['far', 'comments']} - style={pal.text as FontAwesomeIconStyle} - size={18} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Thread Preferences</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - testID="savedFeedsBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - accessibilityHint="My Saved Feeds" - accessibilityLabel={_(msg`Opens screen with all saved feeds`)} - onPress={onPressSavedFeeds}> - <View style={[styles.iconContainer, pal.btn]}> - <HashtagIcon style={pal.text} size={18} strokeWidth={3} /> - </View> - <Text type="lg" style={pal.text}> - <Trans>My Saved Feeds</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - testID="languageSettingsBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={isSwitchingAccounts ? undefined : onPressLanguageSettings} - accessibilityRole="button" - accessibilityHint="Language settings" - accessibilityLabel={_(msg`Opens configurable language settings`)}> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="language" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Languages</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - testID="moderationBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={ - isSwitchingAccounts - ? undefined - : () => navigation.navigate('Moderation') - } - accessibilityRole="button" - accessibilityHint="" - accessibilityLabel={_(msg`Opens moderation settings`)}> - <View style={[styles.iconContainer, pal.btn]}> - <HandIcon style={pal.text} size={18} strokeWidth={6} /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Moderation</Trans> - </Text> - </TouchableOpacity> - <View style={styles.spacer20} /> - - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Advanced</Trans> + </TouchableOpacity> + <TouchableOpacity + testID="savedFeedsBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + accessibilityHint="My Saved Feeds" + accessibilityLabel={_(msg`Opens screen with all saved feeds`)} + onPress={onPressSavedFeeds}> + <View style={[styles.iconContainer, pal.btn]}> + <HashtagIcon style={pal.text} size={18} strokeWidth={3} /> + </View> + <Text type="lg" style={pal.text}> + <Trans>My Saved Feeds</Trans> </Text> - <TouchableOpacity - testID="appPasswordBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={onPressAppPasswords} - accessibilityRole="button" - accessibilityHint="Open app password settings" - accessibilityLabel={_(msg`Opens the app password settings page`)}> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="lock" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>App passwords</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - testID="changeHandleBtn" - style={[ - styles.linkCard, - pal.view, - isSwitchingAccounts && styles.dimmed, - ]} - onPress={isSwitchingAccounts ? undefined : onPressChangeHandle} - accessibilityRole="button" - accessibilityLabel={_(msg`Change handle`)} - accessibilityHint="Choose a new Bluesky username or create"> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="at" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text} numberOfLines={1}> - <Trans>Change handle</Trans> - </Text> - </TouchableOpacity> - <View style={styles.spacer20} /> - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Danger Zone</Trans> + </TouchableOpacity> + <TouchableOpacity + testID="languageSettingsBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={isSwitchingAccounts ? undefined : onPressLanguageSettings} + accessibilityRole="button" + accessibilityHint="Language settings" + accessibilityLabel={_(msg`Opens configurable language settings`)}> + <View style={[styles.iconContainer, pal.btn]}> + <FontAwesomeIcon + icon="language" + style={pal.text as FontAwesomeIconStyle} + /> + </View> + <Text type="lg" style={pal.text}> + <Trans>Languages</Trans> </Text> - <TouchableOpacity - style={[pal.view, styles.linkCard]} - onPress={onPressDeleteAccount} - accessible={true} - accessibilityRole="button" - accessibilityLabel={_(msg`Delete account`)} - accessibilityHint="Opens modal for account deletion confirmation. Requires email code."> - <View style={[styles.iconContainer, dangerBg]}> - <FontAwesomeIcon - icon={['far', 'trash-can']} - style={dangerText as FontAwesomeIconStyle} - size={18} - /> - </View> - <Text type="lg" style={dangerText}> - <Trans>Delete my account…</Trans> - </Text> - </TouchableOpacity> - <View style={styles.spacer20} /> - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Developer Tools</Trans> + </TouchableOpacity> + <TouchableOpacity + testID="moderationBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={ + isSwitchingAccounts + ? undefined + : () => navigation.navigate('Moderation') + } + accessibilityRole="button" + accessibilityHint="" + accessibilityLabel={_(msg`Opens moderation settings`)}> + <View style={[styles.iconContainer, pal.btn]}> + <HandIcon style={pal.text} size={18} strokeWidth={6} /> + </View> + <Text type="lg" style={pal.text}> + <Trans>Moderation</Trans> </Text> - <TouchableOpacity - style={[pal.view, styles.linkCardNoIcon]} - onPress={onPressSystemLog} - accessibilityRole="button" - accessibilityHint="Open system log" - accessibilityLabel={_(msg`Opens the system log page`)}> - <Text type="lg" style={pal.text}> - <Trans>System log</Trans> - </Text> - </TouchableOpacity> - {__DEV__ ? ( - <ToggleButton - type="default-light" - label="Experiment: Use AppView Proxy" - isSelected={debugHeaderEnabled} - onPress={toggleDebugHeader} + </TouchableOpacity> + <View style={styles.spacer20} /> + + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Advanced</Trans> + </Text> + <TouchableOpacity + testID="appPasswordBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={onPressAppPasswords} + accessibilityRole="button" + accessibilityHint="Open app password settings" + accessibilityLabel={_(msg`Opens the app password settings page`)}> + <View style={[styles.iconContainer, pal.btn]}> + <FontAwesomeIcon + icon="lock" + style={pal.text as FontAwesomeIconStyle} /> - ) : null} - {__DEV__ ? ( - <> - <TouchableOpacity - style={[pal.view, styles.linkCardNoIcon]} - onPress={onPressStorybook} - accessibilityRole="button" - accessibilityHint="Open storybook page" - accessibilityLabel={_(msg`Opens the storybook page`)}> - <Text type="lg" style={pal.text}> - <Trans>Storybook</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - style={[pal.view, styles.linkCardNoIcon]} - onPress={onPressResetPreferences} - accessibilityRole="button" - accessibilityHint="Reset preferences" - accessibilityLabel={_(msg`Resets the preferences state`)}> - <Text type="lg" style={pal.text}> - <Trans>Reset preferences state</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - style={[pal.view, styles.linkCardNoIcon]} - onPress={onPressResetOnboarding} - accessibilityRole="button" - accessibilityHint="Reset onboarding" - accessibilityLabel={_(msg`Resets the onboarding state`)}> - <Text type="lg" style={pal.text}> - <Trans>Reset onboarding state</Trans> - </Text> - </TouchableOpacity> - </> - ) : null} - <View style={[styles.footer]}> + </View> + <Text type="lg" style={pal.text}> + <Trans>App passwords</Trans> + </Text> + </TouchableOpacity> + <TouchableOpacity + testID="changeHandleBtn" + style={[ + styles.linkCard, + pal.view, + isSwitchingAccounts && styles.dimmed, + ]} + onPress={isSwitchingAccounts ? undefined : onPressChangeHandle} + accessibilityRole="button" + accessibilityLabel={_(msg`Change handle`)} + accessibilityHint="Choose a new Bluesky username or create"> + <View style={[styles.iconContainer, pal.btn]}> + <FontAwesomeIcon + icon="at" + style={pal.text as FontAwesomeIconStyle} + /> + </View> + <Text type="lg" style={pal.text} numberOfLines={1}> + <Trans>Change handle</Trans> + </Text> + </TouchableOpacity> + <View style={styles.spacer20} /> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Danger Zone</Trans> + </Text> + <TouchableOpacity + style={[pal.view, styles.linkCard]} + onPress={onPressDeleteAccount} + accessible={true} + accessibilityRole="button" + accessibilityLabel={_(msg`Delete account`)} + accessibilityHint="Opens modal for account deletion confirmation. Requires email code."> + <View style={[styles.iconContainer, dangerBg]}> + <FontAwesomeIcon + icon={['far', 'trash-can']} + style={dangerText as FontAwesomeIconStyle} + size={18} + /> + </View> + <Text type="lg" style={dangerText}> + <Trans>Delete my account…</Trans> + </Text> + </TouchableOpacity> + <View style={styles.spacer20} /> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Developer Tools</Trans> + </Text> + <TouchableOpacity + style={[pal.view, styles.linkCardNoIcon]} + onPress={onPressSystemLog} + accessibilityRole="button" + accessibilityHint="Open system log" + accessibilityLabel={_(msg`Opens the system log page`)}> + <Text type="lg" style={pal.text}> + <Trans>System log</Trans> + </Text> + </TouchableOpacity> + {__DEV__ ? ( + <ToggleButton + type="default-light" + label="Experiment: Use AppView Proxy" + isSelected={debugHeaderEnabled} + onPress={toggleDebugHeader} + /> + ) : null} + {__DEV__ ? ( + <> <TouchableOpacity + style={[pal.view, styles.linkCardNoIcon]} + onPress={onPressStorybook} accessibilityRole="button" - onPress={onPressBuildInfo}> - <Text type="sm" style={[styles.buildInfo, pal.textLight]}> - <Trans> - Build version {AppInfo.appVersion} {AppInfo.updateChannel} - </Trans> + accessibilityHint="Open storybook page" + accessibilityLabel={_(msg`Opens the storybook page`)}> + <Text type="lg" style={pal.text}> + <Trans>Storybook</Trans> </Text> </TouchableOpacity> - <Text type="sm" style={[pal.textLight]}> - · - </Text> <TouchableOpacity + style={[pal.view, styles.linkCardNoIcon]} + onPress={onPressResetPreferences} accessibilityRole="button" - onPress={onPressStatusPage}> - <Text type="sm" style={[styles.buildInfo, pal.textLight]}> - <Trans>Status page</Trans> + accessibilityHint="Reset preferences" + accessibilityLabel={_(msg`Resets the preferences state`)}> + <Text type="lg" style={pal.text}> + <Trans>Reset preferences state</Trans> </Text> </TouchableOpacity> - </View> - <View style={s.footerSpacer} /> - </ScrollView> - </View> - ) - }), -) - -const EmailConfirmationNotice = observer( - function EmailConfirmationNoticeImpl() { - const pal = usePalette('default') - const palInverted = usePalette('inverted') - const {_} = useLingui() - const {isMobile} = useWebMediaQueries() - const {openModal} = useModalControls() - - return ( - <View style={{marginBottom: 20}}> - <Text type="xl-bold" style={[pal.text, styles.heading]}> - <Trans>Verify email</Trans> - </Text> - <View - style={[ - { - paddingVertical: isMobile ? 12 : 0, - paddingHorizontal: 18, - }, - pal.view, - ]}> - <View style={{flexDirection: 'row', marginBottom: 8}}> - <Pressable - style={[ - palInverted.view, - { - flexDirection: 'row', - gap: 6, - borderRadius: 6, - paddingHorizontal: 12, - paddingVertical: 10, - alignItems: 'center', - }, - isMobile && {flex: 1}, - ]} + <TouchableOpacity + style={[pal.view, styles.linkCardNoIcon]} + onPress={onPressResetOnboarding} accessibilityRole="button" - accessibilityLabel={_(msg`Verify my email`)} - accessibilityHint="" - onPress={() => openModal({name: 'verify-email'})}> - <FontAwesomeIcon - icon="envelope" - color={palInverted.colors.text} - size={16} - /> - <Text type="button" style={palInverted.text}> - <Trans>Verify My Email</Trans> + accessibilityHint="Reset onboarding" + accessibilityLabel={_(msg`Resets the onboarding state`)}> + <Text type="lg" style={pal.text}> + <Trans>Reset onboarding state</Trans> </Text> - </Pressable> - </View> - <Text style={pal.textLight}> - <Trans>Protect your account by verifying your email.</Trans> + </TouchableOpacity> + </> + ) : null} + <View style={[styles.footer]}> + <TouchableOpacity + accessibilityRole="button" + onPress={onPressBuildInfo}> + <Text type="sm" style={[styles.buildInfo, pal.textLight]}> + <Trans> + Build version {AppInfo.appVersion} {AppInfo.updateChannel} + </Trans> + </Text> + </TouchableOpacity> + <Text type="sm" style={[pal.textLight]}> + · </Text> + <TouchableOpacity + accessibilityRole="button" + onPress={onPressStatusPage}> + <Text type="sm" style={[styles.buildInfo, pal.textLight]}> + <Trans>Status page</Trans> + </Text> + </TouchableOpacity> </View> + <View style={s.footerSpacer} /> + </ScrollView> + </View> + ) +}) + +function EmailConfirmationNotice() { + const pal = usePalette('default') + const palInverted = usePalette('inverted') + const {_} = useLingui() + const {isMobile} = useWebMediaQueries() + const {openModal} = useModalControls() + + return ( + <View style={{marginBottom: 20}}> + <Text type="xl-bold" style={[pal.text, styles.heading]}> + <Trans>Verify email</Trans> + </Text> + <View + style={[ + { + paddingVertical: isMobile ? 12 : 0, + paddingHorizontal: 18, + }, + pal.view, + ]}> + <View style={{flexDirection: 'row', marginBottom: 8}}> + <Pressable + style={[ + palInverted.view, + { + flexDirection: 'row', + gap: 6, + borderRadius: 6, + paddingHorizontal: 12, + paddingVertical: 10, + alignItems: 'center', + }, + isMobile && {flex: 1}, + ]} + accessibilityRole="button" + accessibilityLabel={_(msg`Verify my email`)} + accessibilityHint="" + onPress={() => openModal({name: 'verify-email'})}> + <FontAwesomeIcon + icon="envelope" + color={palInverted.colors.text} + size={16} + /> + <Text type="button" style={palInverted.text}> + <Trans>Verify My Email</Trans> + </Text> + </Pressable> + </View> + <Text style={pal.textLight}> + <Trans>Protect your account by verifying your email.</Trans> + </Text> </View> - ) - }, -) + </View> + ) +} const styles = StyleSheet.create({ dimmed: { diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx index 1ee359be0..a67a105bb 100644 --- a/src/view/shell/Drawer.tsx +++ b/src/view/shell/Drawer.tsx @@ -10,7 +10,6 @@ import { ViewStyle, } from 'react-native' import {useNavigation, StackActions} from '@react-navigation/native' -import {observer} from 'mobx-react-lite' import { FontAwesomeIcon, FontAwesomeIconStyle, @@ -101,7 +100,7 @@ export function DrawerProfileCard({ ) } -export const DrawerContent = observer(function DrawerContentImpl() { +export function DrawerContent() { const theme = useTheme() const pal = usePalette('default') const {_} = useLingui() @@ -404,7 +403,7 @@ export const DrawerContent = observer(function DrawerContentImpl() { </SafeAreaView> </View> ) -}) +} interface MenuItemProps extends ComponentProps<typeof TouchableOpacity> { icon: JSX.Element @@ -458,11 +457,7 @@ function MenuItem({ ) } -const InviteCodes = observer(function InviteCodesImpl({ - style, -}: { - style?: StyleProp<ViewStyle> -}) { +function InviteCodes({style}: {style?: StyleProp<ViewStyle>}) { const {track} = useAnalytics() const setDrawerOpen = useSetDrawerOpen() const pal = usePalette('default') @@ -502,7 +497,7 @@ const InviteCodes = observer(function InviteCodesImpl({ </Text> </TouchableOpacity> ) -}) +} const styles = StyleSheet.create({ view: { diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx index a1502d2e9..ed800679d 100644 --- a/src/view/shell/bottom-bar/BottomBar.tsx +++ b/src/view/shell/bottom-bar/BottomBar.tsx @@ -4,7 +4,6 @@ import Animated from 'react-native-reanimated' import {StackActions} from '@react-navigation/native' import {BottomTabBarProps} from '@react-navigation/bottom-tabs' import {useSafeAreaInsets} from 'react-native-safe-area-context' -import {observer} from 'mobx-react-lite' import {Text} from 'view/com/util/text/Text' import {useAnalytics} from 'lib/analytics/analytics' import {clamp} from 'lib/numbers' @@ -34,9 +33,7 @@ import {useProfileQuery} from '#/state/queries/profile' type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds' -export const BottomBar = observer(function BottomBarImpl({ - navigation, -}: BottomTabBarProps) { +export function BottomBar({navigation}: BottomTabBarProps) { const {openModal} = useModalControls() const {currentAccount} = useSession() const pal = usePalette('default') @@ -231,7 +228,7 @@ export const BottomBar = observer(function BottomBarImpl({ /> </Animated.View> ) -}) +} interface BtnProps extends Pick< diff --git a/src/view/shell/bottom-bar/BottomBarWeb.tsx b/src/view/shell/bottom-bar/BottomBarWeb.tsx index d58580502..32fa1943a 100644 --- a/src/view/shell/bottom-bar/BottomBarWeb.tsx +++ b/src/view/shell/bottom-bar/BottomBarWeb.tsx @@ -1,5 +1,4 @@ import React from 'react' -import {observer} from 'mobx-react-lite' import {usePalette} from 'lib/hooks/usePalette' import {useNavigationState} from '@react-navigation/native' import Animated from 'react-native-reanimated' @@ -24,7 +23,7 @@ import {makeProfileLink} from 'lib/routes/links' import {CommonNavigatorParams} from 'lib/routes/types' import {useSession} from '#/state/session' -export const BottomBarWeb = observer(function BottomBarWebImpl() { +export function BottomBarWeb() { const {currentAccount} = useSession() const pal = usePalette('default') const safeAreaInsets = useSafeAreaInsets() @@ -111,7 +110,7 @@ export const BottomBarWeb = observer(function BottomBarWebImpl() { </NavItem> </Animated.View> ) -}) +} const NavItem: React.FC<{ children: (props: {isActive: boolean}) => React.ReactChild diff --git a/src/view/shell/desktop/Feeds.tsx b/src/view/shell/desktop/Feeds.tsx index 9cb10517e..dc5e311f4 100644 --- a/src/view/shell/desktop/Feeds.tsx +++ b/src/view/shell/desktop/Feeds.tsx @@ -1,13 +1,12 @@ import React from 'react' import {View, StyleSheet} from 'react-native' import {useNavigationState} from '@react-navigation/native' -import {observer} from 'mobx-react-lite' import {usePalette} from 'lib/hooks/usePalette' import {TextLink} from 'view/com/util/Link' import {getCurrentRoute} from 'lib/routes/helpers' import {usePinnedFeedsInfos} from '#/state/queries/feed' -export const DesktopFeeds = observer(function DesktopFeeds() { +export function DesktopFeeds() { const pal = usePalette('default') const feeds = usePinnedFeedsInfos() @@ -54,7 +53,7 @@ export const DesktopFeeds = observer(function DesktopFeeds() { </View> </View> ) -}) +} function FeedItem({ title, diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index 3ec68872e..841a49d38 100644 --- a/src/view/shell/desktop/LeftNav.tsx +++ b/src/view/shell/desktop/LeftNav.tsx @@ -1,5 +1,4 @@ import React from 'react' -import {observer} from 'mobx-react-lite' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {PressableWithHover} from 'view/com/util/PressableWithHover' import { @@ -47,7 +46,7 @@ import {useComposerControls} from '#/state/shell/composer' import {useFetchHandle} from '#/state/queries/handle' import {emitSoftReset} from '#/state/events' -const ProfileCard = observer(function ProfileCardImpl() { +function ProfileCard() { const {currentAccount} = useSession() const {isLoading, data: profile} = useProfileQuery({did: currentAccount!.did}) const {isDesktop} = useWebMediaQueries() @@ -73,7 +72,7 @@ const ProfileCard = observer(function ProfileCardImpl() { /> </View> ) -}) +} function BackBtn() { const {isTablet} = useWebMediaQueries() @@ -117,13 +116,7 @@ interface NavItemProps { iconFilled: JSX.Element label: string } -const NavItem = observer(function NavItemImpl({ - count, - href, - icon, - iconFilled, - label, -}: NavItemProps) { +function NavItem({count, href, icon, iconFilled, label}: NavItemProps) { const pal = usePalette('default') const {currentAccount} = useSession() const {isDesktop, isTablet} = useWebMediaQueries() @@ -192,7 +185,7 @@ const NavItem = observer(function NavItemImpl({ )} </PressableWithHover> ) -}) +} function ComposeBtn() { const {currentAccount} = useSession() @@ -264,7 +257,7 @@ function ComposeBtn() { ) } -export const DesktopLeftNav = observer(function DesktopLeftNav() { +export function DesktopLeftNav() { const {currentAccount} = useSession() const pal = usePalette('default') const {isDesktop, isTablet} = useWebMediaQueries() @@ -422,7 +415,7 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() { <ComposeBtn /> </View> ) -}) +} const styles = StyleSheet.create({ leftNav: { diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx index 9e17cdcd9..3b94c12ef 100644 --- a/src/view/shell/desktop/RightNav.tsx +++ b/src/view/shell/desktop/RightNav.tsx @@ -1,5 +1,4 @@ import React from 'react' -import {observer} from 'mobx-react-lite' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {usePalette} from 'lib/hooks/usePalette' @@ -16,7 +15,7 @@ import {useModalControls} from '#/state/modals' import {useSession} from '#/state/session' import {useInviteCodesQuery} from '#/state/queries/invites' -export const DesktopRightNav = observer(function DesktopRightNavImpl() { +export function DesktopRightNav() { const pal = usePalette('default') const palError = usePalette('error') const {isSandbox, hasSession, currentAccount} = useSession() @@ -80,9 +79,9 @@ export const DesktopRightNav = observer(function DesktopRightNavImpl() { <InviteCodes /> </View> ) -}) +} -const InviteCodes = observer(function InviteCodesImpl() { +function InviteCodes() { const pal = usePalette('default') const {openModal} = useModalControls() const {data: invites} = useInviteCodesQuery() @@ -118,7 +117,7 @@ const InviteCodes = observer(function InviteCodesImpl() { </Text> </TouchableOpacity> ) -}) +} const styles = StyleSheet.create({ rightNav: { diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index c0eed0787..09f8ba983 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -1,5 +1,4 @@ import React, {useEffect} from 'react' -import {observer} from 'mobx-react-lite' import {View, StyleSheet, TouchableOpacity} from 'react-native' import {DesktopLeftNav} from './desktop/LeftNav' import {DesktopRightNav} from './desktop/RightNav' @@ -76,7 +75,7 @@ function ShellInner() { ) } -export const Shell: React.FC = observer(function ShellImpl() { +export const Shell: React.FC = function ShellImpl() { const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark) return ( <View style={[s.hContentRegion, pageBg]}> @@ -85,7 +84,7 @@ export const Shell: React.FC = observer(function ShellImpl() { </RoutesContainer> </View> ) -}) +} const styles = StyleSheet.create({ bgLight: { |