diff options
Diffstat (limited to 'src/view/com/auth/onboarding')
-rw-r--r-- | src/view/com/auth/onboarding/RecommendedFeeds.tsx | 120 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/RecommendedFeedsItem.tsx | 55 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/RecommendedFollows.tsx | 184 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/RecommendedFollowsItem.tsx | 114 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/WelcomeDesktop.tsx | 7 | ||||
-rw-r--r-- | src/view/com/auth/onboarding/WelcomeMobile.tsx | 37 |
6 files changed, 313 insertions, 204 deletions
diff --git a/src/view/com/auth/onboarding/RecommendedFeeds.tsx b/src/view/com/auth/onboarding/RecommendedFeeds.tsx index 400b836d0..d3318bffd 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' @@ -10,76 +9,55 @@ import {Button} from 'view/com/util/forms/Button' import {RecommendedFeedsItem} from './RecommendedFeedsItem' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {usePalette} from 'lib/hooks/usePalette' -import {useQuery} from '@tanstack/react-query' -import {useStores} from 'state/index' -import {FeedSourceModel} from 'state/models/content/feed-source' import {ErrorMessage} from 'view/com/util/error/ErrorMessage' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useSuggestedFeedsQuery} from '#/state/queries/suggested-feeds' type Props = { next: () => void } -export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ - next, -}: Props) { - const store = useStores() +export function RecommendedFeeds({next}: Props) { const pal = usePalette('default') + const {_} = useLingui() const {isTabletOrMobile} = useWebMediaQueries() - const {isLoading, data: recommendedFeeds} = useQuery({ - staleTime: Infinity, // fixed list rn, never refetch - queryKey: ['onboarding', 'recommended_feeds'], - async queryFn() { - try { - const { - data: {feeds}, - success, - } = await store.agent.app.bsky.feed.getSuggestedFeeds() + const {isLoading, data} = useSuggestedFeedsQuery() - if (!success) { - return [] - } - - return (feeds.length ? feeds : []).map(feed => { - const model = new FeedSourceModel(store, feed.uri) - model.hydrateFeedGenerator(feed) - return model - }) - } catch (e) { - return [] - } - }, - }) - - const hasFeeds = recommendedFeeds && recommendedFeeds.length + const hasFeeds = data && data.pages[0].feeds.length const title = ( <> - <Text - style={[ - pal.textLight, - tdStyles.title1, - isTabletOrMobile && tdStyles.title1Small, - ]}> - Choose your - </Text> - <Text - style={[ - pal.link, - tdStyles.title2, - isTabletOrMobile && tdStyles.title2Small, - ]}> - Recommended - </Text> - <Text - style={[ - pal.link, - tdStyles.title2, - isTabletOrMobile && tdStyles.title2Small, - ]}> - Feeds - </Text> + <Trans> + <Text + style={[ + pal.textLight, + tdStyles.title1, + isTabletOrMobile && tdStyles.title1Small, + ]}> + Choose your + </Text> + <Text + style={[ + pal.link, + tdStyles.title2, + isTabletOrMobile && tdStyles.title2Small, + ]}> + Recommended + </Text> + <Text + style={[ + pal.link, + tdStyles.title2, + isTabletOrMobile && tdStyles.title2Small, + ]}> + Feeds + </Text> + </Trans> <Text type="2xl-medium" style={[pal.textLight, tdStyles.description]}> - Feeds are created by users to curate content. Choose some feeds that you - find interesting. + <Trans> + Feeds are created by users to curate content. Choose some feeds that + you find interesting. + </Trans> </Text> <View style={{ @@ -98,7 +76,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ <Text type="2xl-medium" style={{color: '#fff', position: 'relative', top: -1}}> - Next + <Trans>Next</Trans> </Text> <FontAwesomeIcon icon="angle-right" color="#fff" size={14} /> </View> @@ -118,7 +96,7 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ contentStyle={{paddingHorizontal: 0}}> {hasFeeds ? ( <FlatList - data={recommendedFeeds} + data={data.pages[0].feeds} renderItem={({item}) => <RecommendedFeedsItem item={item} />} keyExtractor={item => item.uri} style={{flex: 1}} @@ -128,25 +106,27 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ <ActivityIndicator size="large" /> </View> ) : ( - <ErrorMessage message="Failed to load recommended feeds" /> + <ErrorMessage message={_(msg`Failed to load recommended feeds`)} /> )} </TitleColumnLayout> </TabletOrDesktop> <Mobile> <View style={[mStyles.container]} testID="recommendedFeedsOnboarding"> <ViewHeader - title="Recommended Feeds" + title={_(msg`Recommended Feeds`)} showBackButton={false} showOnDesktop /> <Text type="lg-medium" style={[pal.text, mStyles.header]}> - Check out some recommended feeds. Tap + to add them to your list of - pinned feeds. + <Trans> + Check out some recommended feeds. Tap + to add them to your list + of pinned feeds. + </Trans> </Text> {hasFeeds ? ( <FlatList - data={recommendedFeeds} + data={data.pages[0].feeds} renderItem={({item}) => <RecommendedFeedsItem item={item} />} keyExtractor={item => item.uri} style={{flex: 1}} @@ -157,13 +137,15 @@ export const RecommendedFeeds = observer(function RecommendedFeedsImpl({ </View> ) : ( <View style={{flex: 1}}> - <ErrorMessage message="Failed to load recommended feeds" /> + <ErrorMessage + message={_(msg`Failed to load recommended feeds`)} + /> </View> )} <Button onPress={next} - label="Continue" + label={_(msg`Continue`)} testID="continueBtn" style={mStyles.button} labelStyle={mStyles.buttonText} @@ -172,7 +154,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 bee23c953..7417e5b06 100644 --- a/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx +++ b/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx @@ -1,7 +1,7 @@ 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' import {RichText} from 'view/com/util/text/RichText' import {Button} from 'view/com/util/forms/Button' @@ -11,33 +11,58 @@ import {HeartIcon} from 'lib/icons' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {sanitizeHandle} from 'lib/strings/handles' -import {FeedSourceModel} from 'state/models/content/feed-source' +import { + usePreferencesQuery, + usePinFeedMutation, + useRemoveFeedMutation, +} from '#/state/queries/preferences' +import {logger} from '#/logger' -export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({ +export function RecommendedFeedsItem({ item, }: { - item: FeedSourceModel + item: AppBskyFeedDefs.GeneratorView }) { const {isMobile} = useWebMediaQueries() const pal = usePalette('default') - if (!item) return null + const {data: preferences} = usePreferencesQuery() + const { + mutateAsync: pinFeed, + variables: pinnedFeed, + reset: resetPinFeed, + } = usePinFeedMutation() + const { + mutateAsync: removeFeed, + variables: removedFeed, + reset: resetRemoveFeed, + } = useRemoveFeedMutation() + + if (!item || !preferences) return null + + const isPinned = + !removedFeed?.uri && + (pinnedFeed?.uri || preferences.feeds.saved.includes(item.uri)) + const onToggle = async () => { - if (item.isSaved) { + if (isPinned) { try { - await item.unsave() + await removeFeed({uri: item.uri}) + resetRemoveFeed() } catch (e) { Toast.show('There was an issue contacting your server') - console.error('Failed to unsave feed', {e}) + logger.error('Failed to unsave feed', {error: e}) } } else { try { - await item.pin() + await pinFeed({uri: item.uri}) + resetPinFeed() } catch (e) { Toast.show('There was an issue contacting your server') - console.error('Failed to pin feed', {e}) + logger.error('Failed to pin feed', {error: e}) } } } + return ( <View testID={`feed-${item.displayName}`}> <View @@ -66,10 +91,10 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({ </Text> <Text style={[pal.textLight, {marginBottom: 8}]} numberOfLines={1}> - by {sanitizeHandle(item.creatorHandle, '@')} + by {sanitizeHandle(item.creator.handle, '@')} </Text> - {item.descriptionRT ? ( + {item.description ? ( <RichText type="xl" style={[ @@ -80,7 +105,7 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({ marginBottom: 18, }, ]} - richText={item.descriptionRT} + richText={new BskRichText({text: item.description || ''})} numberOfLines={6} /> ) : null} @@ -97,7 +122,7 @@ export const RecommendedFeedsItem = observer(function RecommendedFeedsItemImpl({ paddingRight: 2, gap: 6, }}> - {item.isSaved ? ( + {isPinned ? ( <> <FontAwesomeIcon icon="check" @@ -138,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 f2710d2ac..372bbec6a 100644 --- a/src/view/com/auth/onboarding/RecommendedFollows.tsx +++ b/src/view/com/auth/onboarding/RecommendedFollows.tsx @@ -1,7 +1,7 @@ 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' import {Text} from 'view/com/util/text/Text' import {ViewHeader} from 'view/com/util/ViewHeader' @@ -9,59 +9,62 @@ import {TitleColumnLayout} from 'view/com/util/layouts/TitleColumnLayout' import {Button} from 'view/com/util/forms/Button' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {usePalette} from 'lib/hooks/usePalette' -import {useStores} from 'state/index' import {RecommendedFollowsItem} from './RecommendedFollowsItem' +import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows' +import {useGetSuggestedFollowersByActor} from '#/state/queries/suggested-follows' +import {useModerationOpts} from '#/state/queries/preferences' +import {logger} from '#/logger' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' type Props = { next: () => void } -export const RecommendedFollows = observer(function RecommendedFollowsImpl({ - next, -}: Props) { - const store = useStores() +export function RecommendedFollows({next}: Props) { const pal = usePalette('default') + const {_} = useLingui() const {isTabletOrMobile} = useWebMediaQueries() - - React.useEffect(() => { - // Load suggested actors if not already loaded - // prefetch should happen in the onboarding model - if ( - !store.onboarding.suggestedActors.hasLoaded || - store.onboarding.suggestedActors.isEmpty - ) { - store.onboarding.suggestedActors.loadMore(true) - } - }, [store]) + const {data: suggestedFollows} = useSuggestedFollowsQuery() + const getSuggestedFollowsByActor = useGetSuggestedFollowersByActor() + const [additionalSuggestions, setAdditionalSuggestions] = React.useState<{ + [did: string]: AppBskyActorDefs.ProfileView[] + }>({}) + const existingDids = React.useRef<string[]>([]) + const moderationOpts = useModerationOpts() const title = ( <> - <Text - style={[ - pal.textLight, - tdStyles.title1, - isTabletOrMobile && tdStyles.title1Small, - ]}> - Follow some - </Text> - <Text - style={[ - pal.link, - tdStyles.title2, - isTabletOrMobile && tdStyles.title2Small, - ]}> - Recommended - </Text> - <Text - style={[ - pal.link, - tdStyles.title2, - isTabletOrMobile && tdStyles.title2Small, - ]}> - Users - </Text> + <Trans> + <Text + style={[ + pal.textLight, + tdStyles.title1, + isTabletOrMobile && tdStyles.title1Small, + ]}> + Follow some + </Text> + <Text + style={[ + pal.link, + tdStyles.title2, + isTabletOrMobile && tdStyles.title2Small, + ]}> + Recommended + </Text> + <Text + style={[ + pal.link, + tdStyles.title2, + isTabletOrMobile && tdStyles.title2Small, + ]}> + Users + </Text> + </Trans> <Text type="2xl-medium" style={[pal.textLight, tdStyles.description]}> - Follow some users to get started. We can recommend you more users based - on who you find interesting. + <Trans> + Follow some users to get started. We can recommend you more users + based on who you find interesting. + </Trans> </Text> <View style={{ @@ -80,7 +83,7 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({ <Text type="2xl-medium" style={{color: '#fff', position: 'relative', top: -1}}> - Done + <Trans>Done</Trans> </Text> <FontAwesomeIcon icon="angle-right" color="#fff" size={14} /> </View> @@ -89,6 +92,59 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({ </> ) + const suggestions = React.useMemo(() => { + if (!suggestedFollows) return [] + + const additional = Object.entries(additionalSuggestions) + const items = suggestedFollows.pages.flatMap(page => page.actors) + + outer: while (additional.length) { + const additionalAccount = additional.shift() + + if (!additionalAccount) break + + const [followedUser, relatedAccounts] = additionalAccount + + for (let i = 0; i < items.length; i++) { + if (items[i].did === followedUser) { + items.splice(i + 1, 0, ...relatedAccounts) + continue outer + } + } + } + + existingDids.current = items.map(i => i.did) + + return items + }, [suggestedFollows, additionalSuggestions]) + + const onFollowStateChange = React.useCallback( + async ({following, did}: {following: boolean; did: string}) => { + if (following) { + try { + const {suggestions: results} = await getSuggestedFollowsByActor(did) + + if (results.length) { + const deduped = results.filter( + r => !existingDids.current.find(did => did === r.did), + ) + setAdditionalSuggestions(s => ({ + ...s, + [did]: deduped.slice(0, 3), + })) + } + } catch (e) { + logger.error('RecommendedFollows: failed to get suggestions', { + error: e, + }) + } + } + + // not handling the unfollow case + }, + [existingDids, getSuggestedFollowsByActor, setAdditionalSuggestions], + ) + return ( <> <TabletOrDesktop> @@ -98,15 +154,19 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({ horizontal titleStyle={isTabletOrMobile ? undefined : {minWidth: 470}} contentStyle={{paddingHorizontal: 0}}> - {store.onboarding.suggestedActors.isLoading ? ( + {!suggestedFollows || !moderationOpts ? ( <ActivityIndicator size="large" /> ) : ( <FlatList - data={store.onboarding.suggestedActors.suggestions} - renderItem={({item, index}) => ( - <RecommendedFollowsItem item={item} index={index} /> + data={suggestions} + renderItem={({item}) => ( + <RecommendedFollowsItem + profile={item} + onFollowStateChange={onFollowStateChange} + moderation={moderateProfile(item, moderationOpts)} + /> )} - keyExtractor={(item, index) => item.did + index.toString()} + keyExtractor={item => item.did} style={{flex: 1}} /> )} @@ -117,30 +177,36 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({ <View style={[mStyles.container]} testID="recommendedFollowsOnboarding"> <View> <ViewHeader - title="Recommended Follows" + title={_(msg`Recommended Users`)} showBackButton={false} showOnDesktop /> <Text type="lg-medium" style={[pal.text, mStyles.header]}> - Check out some recommended users. Follow them to see similar - users. + <Trans> + Check out some recommended users. Follow them to see similar + users. + </Trans> </Text> </View> - {store.onboarding.suggestedActors.isLoading ? ( + {!suggestedFollows || !moderationOpts ? ( <ActivityIndicator size="large" /> ) : ( <FlatList - data={store.onboarding.suggestedActors.suggestions} - renderItem={({item, index}) => ( - <RecommendedFollowsItem item={item} index={index} /> + data={suggestions} + renderItem={({item}) => ( + <RecommendedFollowsItem + profile={item} + onFollowStateChange={onFollowStateChange} + moderation={moderateProfile(item, moderationOpts)} + /> )} - keyExtractor={(item, index) => item.did + index.toString()} + keyExtractor={item => item.did} style={{flex: 1}} /> )} <Button onPress={next} - label="Continue" + label={_(msg`Continue`)} testID="continueBtn" style={mStyles.button} labelStyle={mStyles.buttonText} @@ -149,7 +215,7 @@ export const RecommendedFollows = observer(function RecommendedFollowsImpl({ </Mobile> </> ) -}) +} const tdStyles = StyleSheet.create({ container: { diff --git a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx index 2b26918d0..93c515f38 100644 --- a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx +++ b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx @@ -1,11 +1,8 @@ -import React, {useMemo} from 'react' +import React from 'react' import {View, StyleSheet, ActivityIndicator} from 'react-native' -import {AppBskyActorDefs, moderateProfile} from '@atproto/api' -import {observer} from 'mobx-react-lite' -import {useStores} from 'state/index' -import {FollowButton} from 'view/com/profile/FollowButton' +import {ProfileModeration, AppBskyActorDefs} from '@atproto/api' +import {Button} from '#/view/com/util/forms/Button' import {usePalette} from 'lib/hooks/usePalette' -import {SuggestedActor} from 'state/models/discovery/suggested-actors' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {s} from 'lib/styles' @@ -14,26 +11,32 @@ import {Text} from 'view/com/util/text/Text' import Animated, {FadeInRight} from 'react-native-reanimated' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useAnalytics} from 'lib/analytics/analytics' +import {Trans} from '@lingui/macro' +import {Shadow, useProfileShadow} from '#/state/cache/profile-shadow' +import {useProfileFollowMutationQueue} from '#/state/queries/profile' +import {logger} from '#/logger' type Props = { - item: SuggestedActor - index: number + profile: AppBskyActorDefs.ProfileViewBasic + moderation: ProfileModeration + onFollowStateChange: (props: { + did: string + following: boolean + }) => Promise<void> } -export const RecommendedFollowsItem: React.FC<Props> = ({item, index}) => { + +export function RecommendedFollowsItem({ + profile, + moderation, + onFollowStateChange, +}: React.PropsWithChildren<Props>) { const pal = usePalette('default') - const store = useStores() const {isMobile} = useWebMediaQueries() - const delay = useMemo(() => { - return ( - 50 * - (Math.abs(store.onboarding.suggestedActors.lastInsertedAtIndex - index) % - 5) - ) - }, [index, store.onboarding.suggestedActors.lastInsertedAtIndex]) + const shadowedProfile = useProfileShadow(profile) return ( <Animated.View - entering={FadeInRight.delay(delay).springify()} + entering={FadeInRight} style={[ styles.cardContainer, pal.view, @@ -43,24 +46,62 @@ export const RecommendedFollowsItem: React.FC<Props> = ({item, index}) => { borderRightWidth: isMobile ? undefined : 1, }, ]}> - <ProfileCard key={item.did} profile={item} index={index} /> + <ProfileCard + key={profile.did} + profile={shadowedProfile} + onFollowStateChange={onFollowStateChange} + moderation={moderation} + /> </Animated.View> ) } -export const ProfileCard = observer(function ProfileCardImpl({ +export function ProfileCard({ profile, - index, + onFollowStateChange, + moderation, }: { - profile: AppBskyActorDefs.ProfileViewBasic - index: number + profile: Shadow<AppBskyActorDefs.ProfileViewBasic> + moderation: ProfileModeration + onFollowStateChange: (props: { + did: string + following: boolean + }) => Promise<void> }) { const {track} = useAnalytics() - const store = useStores() const pal = usePalette('default') - const moderation = moderateProfile(profile, store.preferences.moderationOpts) const [addingMoreSuggestions, setAddingMoreSuggestions] = React.useState(false) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) + + const onToggleFollow = React.useCallback(async () => { + try { + if (profile.viewer?.following) { + await queueUnfollow() + } else { + setAddingMoreSuggestions(true) + await queueFollow() + await onFollowStateChange({did: profile.did, following: true}) + setAddingMoreSuggestions(false) + track('Onboarding:SuggestedFollowFollowed') + } + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('RecommendedFollows: failed to toggle following', { + error: e, + }) + } + } finally { + setAddingMoreSuggestions(false) + } + }, [ + profile, + queueFollow, + queueUnfollow, + setAddingMoreSuggestions, + track, + onFollowStateChange, + ]) return ( <View style={styles.card}> @@ -88,20 +129,11 @@ export const ProfileCard = observer(function ProfileCardImpl({ </Text> </View> - <FollowButton - profile={profile} + <Button + type={profile.viewer?.following ? 'default' : 'inverted'} labelStyle={styles.followButton} - onToggleFollow={async isFollow => { - if (isFollow) { - setAddingMoreSuggestions(true) - await store.onboarding.suggestedActors.insertSuggestionsByActor( - profile.did, - index, - ) - setAddingMoreSuggestions(false) - track('Onboarding:SuggestedFollowFollowed') - } - }} + onPress={onToggleFollow} + label={profile.viewer?.following ? 'Unfollow' : 'Follow'} /> </View> {profile.description ? ( @@ -114,12 +146,14 @@ export const ProfileCard = observer(function ProfileCardImpl({ {addingMoreSuggestions ? ( <View style={styles.addingMoreContainer}> <ActivityIndicator size="small" color={pal.colors.text} /> - <Text style={[pal.text]}>Finding similar accounts...</Text> + <Text style={[pal.text]}> + <Trans>Finding similar accounts...</Trans> + </Text> </View> ) : null} </View> ) -}) +} const styles = StyleSheet.create({ cardContainer: { 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 1f0a64370..5de1a7817 100644 --- a/src/view/com/auth/onboarding/WelcomeMobile.tsx +++ b/src/view/com/auth/onboarding/WelcomeMobile.tsx @@ -5,18 +5,15 @@ 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' type Props = { next: () => void skip: () => void } -export const WelcomeMobile = observer(function WelcomeMobileImpl({ - next, - skip, -}: Props) { +export function WelcomeMobile({next, skip}: Props) { const pal = usePalette('default') return ( @@ -32,7 +29,9 @@ export const WelcomeMobile = observer(function WelcomeMobileImpl({ accessibilityRole="button" style={[s.flexRow, s.alignCenter]} onPress={skip}> - <Text style={[pal.link]}>Skip</Text> + <Text style={[pal.link]}> + <Trans>Skip</Trans> + </Text> <FontAwesomeIcon icon={'chevron-right'} size={14} @@ -44,18 +43,22 @@ export const WelcomeMobile = observer(function WelcomeMobileImpl({ /> <View> <Text style={[pal.text, styles.title]}> - Welcome to{' '} - <Text style={[pal.text, pal.link, styles.title]}>Bluesky</Text> + <Trans> + Welcome to{' '} + <Text style={[pal.text, pal.link, styles.title]}>Bluesky</Text> + </Trans> </Text> <View style={styles.spacer} /> <View style={[styles.row]}> <FontAwesomeIcon icon={'globe'} size={36} color={pal.colors.link} /> <View style={[styles.rowText]}> <Text type="lg-bold" style={[pal.text]}> - Bluesky is public. + <Trans>Bluesky is public.</Trans> </Text> <Text type="lg-thin" style={[pal.text, s.pt2]}> - Your posts, likes, and blocks are public. Mutes are private. + <Trans> + Your posts, likes, and blocks are public. Mutes are private. + </Trans> </Text> </View> </View> @@ -63,10 +66,10 @@ export const WelcomeMobile = observer(function WelcomeMobileImpl({ <FontAwesomeIcon icon={'at'} size={36} color={pal.colors.link} /> <View style={[styles.rowText]}> <Text type="lg-bold" style={[pal.text]}> - Bluesky is open. + <Trans>Bluesky is open.</Trans> </Text> <Text type="lg-thin" style={[pal.text, s.pt2]}> - Never lose access to your followers and data. + <Trans>Never lose access to your followers and data.</Trans> </Text> </View> </View> @@ -74,11 +77,13 @@ export const WelcomeMobile = observer(function WelcomeMobileImpl({ <FontAwesomeIcon icon={'gear'} size={36} color={pal.colors.link} /> <View style={[styles.rowText]}> <Text type="lg-bold" style={[pal.text]}> - Bluesky is flexible. + <Trans>Bluesky is flexible.</Trans> </Text> <Text type="lg-thin" style={[pal.text, s.pt2]}> - Choose the algorithms that power your experience with custom - feeds. + <Trans> + Choose the algorithms that power your experience with custom + feeds. + </Trans> </Text> </View> </View> @@ -93,7 +98,7 @@ export const WelcomeMobile = observer(function WelcomeMobileImpl({ /> </View> ) -}) +} const styles = StyleSheet.create({ container: { |