diff options
Diffstat (limited to 'src/view/screens')
-rw-r--r-- | src/view/screens/Feeds.tsx | 737 | ||||
-rw-r--r-- | src/view/screens/Home.tsx | 63 | ||||
-rw-r--r-- | src/view/screens/PostLikedBy.tsx | 37 | ||||
-rw-r--r-- | src/view/screens/PostRepostedBy.tsx | 37 | ||||
-rw-r--r-- | src/view/screens/PostThread.tsx | 145 | ||||
-rw-r--r-- | src/view/screens/Profile.tsx | 131 | ||||
-rw-r--r-- | src/view/screens/ProfileFeed.tsx | 3 | ||||
-rw-r--r-- | src/view/screens/ProfileFeedLikedBy.tsx | 37 | ||||
-rw-r--r-- | src/view/screens/ProfileFollowers.tsx | 35 | ||||
-rw-r--r-- | src/view/screens/ProfileFollows.tsx | 35 | ||||
-rw-r--r-- | src/view/screens/SavedFeeds.tsx | 16 |
11 files changed, 669 insertions, 607 deletions
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx index 5d62125ce..301c87d14 100644 --- a/src/view/screens/Feeds.tsx +++ b/src/view/screens/Feeds.tsx @@ -87,426 +87,429 @@ type FlatlistSlice = key: string } -export const FeedsScreen = withAuthRequired(function FeedsScreenImpl( - _props: Props, -) { - const pal = usePalette('default') - const {openComposer} = useComposerControls() - const {isMobile, isTabletOrDesktop} = useWebMediaQueries() - const [query, setQuery] = React.useState('') - const [isPTR, setIsPTR] = React.useState(false) - const { - data: preferences, - isLoading: isPreferencesLoading, - error: preferencesError, - } = usePreferencesQuery() - const { - data: popularFeeds, - isFetching: isPopularFeedsFetching, - error: popularFeedsError, - refetch: refetchPopularFeeds, - fetchNextPage: fetchNextPopularFeedsPage, - isFetchingNextPage: isPopularFeedsFetchingNextPage, - hasNextPage: hasNextPopularFeedsPage, - } = useGetPopularFeedsQuery() - const {_} = useLingui() - const setMinimalShellMode = useSetMinimalShellMode() - const { - data: searchResults, - mutate: search, - reset: resetSearch, - isPending: isSearchPending, - error: searchError, - } = useSearchPopularFeedsMutation() +export const FeedsScreen = withAuthRequired( + function FeedsScreenImpl(_props: Props) { + const pal = usePalette('default') + const {openComposer} = useComposerControls() + const {isMobile, isTabletOrDesktop} = useWebMediaQueries() + const [query, setQuery] = React.useState('') + const [isPTR, setIsPTR] = React.useState(false) + const { + data: preferences, + isLoading: isPreferencesLoading, + error: preferencesError, + } = usePreferencesQuery() + const { + data: popularFeeds, + isFetching: isPopularFeedsFetching, + error: popularFeedsError, + refetch: refetchPopularFeeds, + fetchNextPage: fetchNextPopularFeedsPage, + isFetchingNextPage: isPopularFeedsFetchingNextPage, + hasNextPage: hasNextPopularFeedsPage, + } = useGetPopularFeedsQuery() + const {_} = useLingui() + const setMinimalShellMode = useSetMinimalShellMode() + const { + data: searchResults, + mutate: search, + reset: resetSearch, + isPending: isSearchPending, + error: searchError, + } = useSearchPopularFeedsMutation() - /** - * A search query is present. We may not have search results yet. - */ - const isUserSearching = query.length > 1 - const debouncedSearch = React.useMemo( - () => debounce(q => search(q), 500), // debounce for 500ms - [search], - ) - const onPressCompose = React.useCallback(() => { - openComposer({}) - }, [openComposer]) - const onChangeQuery = React.useCallback( - (text: string) => { - setQuery(text) - if (text.length > 1) { - debouncedSearch(text) - } else { - refetchPopularFeeds() - resetSearch() - } - }, - [setQuery, refetchPopularFeeds, debouncedSearch, resetSearch], - ) - const onPressCancelSearch = React.useCallback(() => { - setQuery('') - refetchPopularFeeds() - resetSearch() - }, [refetchPopularFeeds, setQuery, resetSearch]) - const onSubmitQuery = React.useCallback(() => { - debouncedSearch(query) - }, [query, debouncedSearch]) - const onPullToRefresh = React.useCallback(async () => { - setIsPTR(true) - await refetchPopularFeeds() - setIsPTR(false) - }, [setIsPTR, refetchPopularFeeds]) - const onEndReached = React.useCallback(() => { - if ( - isPopularFeedsFetching || - isUserSearching || - !hasNextPopularFeedsPage || - popularFeedsError + /** + * A search query is present. We may not have search results yet. + */ + const isUserSearching = query.length > 1 + const debouncedSearch = React.useMemo( + () => debounce(q => search(q), 500), // debounce for 500ms + [search], ) - return - fetchNextPopularFeedsPage() - }, [ - isPopularFeedsFetching, - isUserSearching, - popularFeedsError, - hasNextPopularFeedsPage, - fetchNextPopularFeedsPage, - ]) - - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + const onPressCompose = React.useCallback(() => { + openComposer({}) + }, [openComposer]) + const onChangeQuery = React.useCallback( + (text: string) => { + setQuery(text) + if (text.length > 1) { + debouncedSearch(text) + } else { + refetchPopularFeeds() + resetSearch() + } + }, + [setQuery, refetchPopularFeeds, debouncedSearch, resetSearch], + ) + const onPressCancelSearch = React.useCallback(() => { + setQuery('') + refetchPopularFeeds() + resetSearch() + }, [refetchPopularFeeds, setQuery, resetSearch]) + const onSubmitQuery = React.useCallback(() => { + debouncedSearch(query) + }, [query, debouncedSearch]) + const onPullToRefresh = React.useCallback(async () => { + setIsPTR(true) + await refetchPopularFeeds() + setIsPTR(false) + }, [setIsPTR, refetchPopularFeeds]) + const onEndReached = React.useCallback(() => { + if ( + isPopularFeedsFetching || + isUserSearching || + !hasNextPopularFeedsPage || + popularFeedsError + ) + return + fetchNextPopularFeedsPage() + }, [ + isPopularFeedsFetching, + isUserSearching, + popularFeedsError, + hasNextPopularFeedsPage, + fetchNextPopularFeedsPage, + ]) - const items = React.useMemo(() => { - let slices: FlatlistSlice[] = [] + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - slices.push({ - key: 'savedFeedsHeader', - type: 'savedFeedsHeader', - }) + const items = React.useMemo(() => { + let slices: FlatlistSlice[] = [] - if (preferencesError) { slices.push({ - key: 'savedFeedsError', - type: 'error', - error: cleanError(preferencesError.toString()), + key: 'savedFeedsHeader', + type: 'savedFeedsHeader', }) - } else { - if (isPreferencesLoading || !preferences?.feeds?.saved) { + + if (preferencesError) { slices.push({ - key: 'savedFeedsLoading', - type: 'savedFeedsLoading', - // pendingItems: this.rootStore.preferences.savedFeeds.length || 3, + key: 'savedFeedsError', + type: 'error', + error: cleanError(preferencesError.toString()), }) } else { - if (preferences?.feeds?.saved.length === 0) { + if (isPreferencesLoading || !preferences?.feeds?.saved) { slices.push({ - key: 'savedFeedNoResults', - type: 'savedFeedNoResults', + key: 'savedFeedsLoading', + type: 'savedFeedsLoading', + // pendingItems: this.rootStore.preferences.savedFeeds.length || 3, }) } else { - const {saved, pinned} = preferences.feeds - - slices = slices.concat( - pinned.map(uri => ({ - key: `savedFeed:${uri}`, - type: 'savedFeed', - feedUri: uri, - })), - ) + if (preferences?.feeds?.saved.length === 0) { + slices.push({ + key: 'savedFeedNoResults', + type: 'savedFeedNoResults', + }) + } else { + const {saved, pinned} = preferences.feeds - slices = slices.concat( - saved - .filter(uri => !pinned.includes(uri)) - .map(uri => ({ + slices = slices.concat( + pinned.map(uri => ({ key: `savedFeed:${uri}`, type: 'savedFeed', feedUri: uri, })), - ) + ) + + slices = slices.concat( + saved + .filter(uri => !pinned.includes(uri)) + .map(uri => ({ + key: `savedFeed:${uri}`, + type: 'savedFeed', + feedUri: uri, + })), + ) + } } } - } - - slices.push({ - key: 'popularFeedsHeader', - type: 'popularFeedsHeader', - }) - if (popularFeedsError || searchError) { slices.push({ - key: 'popularFeedsError', - type: 'error', - error: cleanError( - popularFeedsError?.toString() ?? searchError?.toString() ?? '', - ), + key: 'popularFeedsHeader', + type: 'popularFeedsHeader', }) - } else { - if (isUserSearching) { - if (isSearchPending || !searchResults) { - slices.push({ - key: 'popularFeedsLoading', - type: 'popularFeedsLoading', - }) - } else { - if (!searchResults || searchResults?.length === 0) { + + if (popularFeedsError || searchError) { + slices.push({ + key: 'popularFeedsError', + type: 'error', + error: cleanError( + popularFeedsError?.toString() ?? searchError?.toString() ?? '', + ), + }) + } else { + if (isUserSearching) { + if (isSearchPending || !searchResults) { slices.push({ - key: 'popularFeedsNoResults', - type: 'popularFeedsNoResults', + key: 'popularFeedsLoading', + type: 'popularFeedsLoading', }) } else { - slices = slices.concat( - searchResults.map(feed => ({ - key: `popularFeed:${feed.uri}`, - type: 'popularFeed', - feedUri: feed.uri, - })), - ) + if (!searchResults || searchResults?.length === 0) { + slices.push({ + key: 'popularFeedsNoResults', + type: 'popularFeedsNoResults', + }) + } else { + slices = slices.concat( + searchResults.map(feed => ({ + key: `popularFeed:${feed.uri}`, + type: 'popularFeed', + feedUri: feed.uri, + })), + ) + } } - } - } else { - if (isPopularFeedsFetching && !popularFeeds?.pages) { - slices.push({ - key: 'popularFeedsLoading', - type: 'popularFeedsLoading', - }) } else { - if ( - !popularFeeds?.pages || - popularFeeds?.pages[0]?.feeds?.length === 0 - ) { + if (isPopularFeedsFetching && !popularFeeds?.pages) { slices.push({ - key: 'popularFeedsNoResults', - type: 'popularFeedsNoResults', + key: 'popularFeedsLoading', + type: 'popularFeedsLoading', }) } else { - for (const page of popularFeeds.pages || []) { - slices = slices.concat( - page.feeds - .filter(feed => !preferences?.feeds?.saved.includes(feed.uri)) - .map(feed => ({ - key: `popularFeed:${feed.uri}`, - type: 'popularFeed', - feedUri: feed.uri, - })), - ) - } - - if (isPopularFeedsFetchingNextPage) { + if ( + !popularFeeds?.pages || + popularFeeds?.pages[0]?.feeds?.length === 0 + ) { slices.push({ - key: 'popularFeedsLoadingMore', - type: 'popularFeedsLoadingMore', + key: 'popularFeedsNoResults', + type: 'popularFeedsNoResults', }) + } else { + for (const page of popularFeeds.pages || []) { + slices = slices.concat( + page.feeds + .filter( + feed => !preferences?.feeds?.saved.includes(feed.uri), + ) + .map(feed => ({ + key: `popularFeed:${feed.uri}`, + type: 'popularFeed', + feedUri: feed.uri, + })), + ) + } + + if (isPopularFeedsFetchingNextPage) { + slices.push({ + key: 'popularFeedsLoadingMore', + type: 'popularFeedsLoadingMore', + }) + } } } } } - } - return slices - }, [ - preferences, - isPreferencesLoading, - preferencesError, - popularFeeds, - isPopularFeedsFetching, - popularFeedsError, - isPopularFeedsFetchingNextPage, - searchResults, - isSearchPending, - searchError, - isUserSearching, - ]) + return slices + }, [ + preferences, + isPreferencesLoading, + preferencesError, + popularFeeds, + isPopularFeedsFetching, + popularFeedsError, + isPopularFeedsFetchingNextPage, + searchResults, + isSearchPending, + searchError, + isUserSearching, + ]) - const renderHeaderBtn = React.useCallback(() => { - return ( - <Link - href="/settings/saved-feeds" - hitSlop={10} - accessibilityRole="button" - accessibilityLabel={_(msg`Edit Saved Feeds`)} - accessibilityHint="Opens screen to edit Saved Feeds"> - <CogIcon size={22} strokeWidth={2} style={pal.textLight} /> - </Link> - ) - }, [pal, _]) + const renderHeaderBtn = React.useCallback(() => { + return ( + <Link + href="/settings/saved-feeds" + hitSlop={10} + accessibilityRole="button" + accessibilityLabel={_(msg`Edit Saved Feeds`)} + accessibilityHint="Opens screen to edit Saved Feeds"> + <CogIcon size={22} strokeWidth={2} style={pal.textLight} /> + </Link> + ) + }, [pal, _]) - const renderItem = React.useCallback( - ({item}: {item: FlatlistSlice}) => { - if (item.type === 'error') { - return <ErrorMessage message={item.error} /> - } else if ( - item.type === 'popularFeedsLoadingMore' || - item.type === 'savedFeedsLoading' - ) { - return ( - <View style={s.p10}> - <ActivityIndicator /> - </View> - ) - } else if (item.type === 'savedFeedsHeader') { - if (!isMobile) { + const renderItem = React.useCallback( + ({item}: {item: FlatlistSlice}) => { + if (item.type === 'error') { + return <ErrorMessage message={item.error} /> + } else if ( + item.type === 'popularFeedsLoadingMore' || + item.type === 'savedFeedsLoading' + ) { return ( - <View - style={[ - pal.view, - styles.header, - pal.border, - { - borderBottomWidth: 1, - }, - ]}> - <Text type="title-lg" style={[pal.text, s.bold]}> - <Trans>My Feeds</Trans> - </Text> - <Link - href="/settings/saved-feeds" - accessibilityLabel={_(msg`Edit My Feeds`)} - accessibilityHint=""> - <CogIcon strokeWidth={1.5} style={pal.icon} size={28} /> - </Link> + <View style={s.p10}> + <ActivityIndicator /> </View> ) - } - return <View /> - } else if (item.type === 'savedFeedNoResults') { - return ( - <View - style={{ - paddingHorizontal: 16, - paddingTop: 10, - }}> - <Text type="lg" style={pal.textLight}> - <Trans>You don't have any saved feeds!</Trans> - </Text> - </View> - ) - } else if (item.type === 'savedFeed') { - return <SavedFeed feedUri={item.feedUri} /> - } else if (item.type === 'popularFeedsHeader') { - return ( - <> + } else if (item.type === 'savedFeedsHeader') { + if (!isMobile) { + return ( + <View + style={[ + pal.view, + styles.header, + pal.border, + { + borderBottomWidth: 1, + }, + ]}> + <Text type="title-lg" style={[pal.text, s.bold]}> + <Trans>My Feeds</Trans> + </Text> + <Link + href="/settings/saved-feeds" + accessibilityLabel={_(msg`Edit My Feeds`)} + accessibilityHint=""> + <CogIcon strokeWidth={1.5} style={pal.icon} size={28} /> + </Link> + </View> + ) + } + return <View /> + } else if (item.type === 'savedFeedNoResults') { + return ( <View - style={[ - pal.view, - styles.header, - { - marginTop: 16, - paddingLeft: isMobile ? 12 : undefined, - paddingRight: 10, - paddingBottom: isMobile ? 6 : undefined, - }, - ]}> - <Text type="title-lg" style={[pal.text, s.bold]}> - <Trans>Discover new feeds</Trans> + style={{ + paddingHorizontal: 16, + paddingTop: 10, + }}> + <Text type="lg" style={pal.textLight}> + <Trans>You don't have any saved feeds!</Trans> </Text> + </View> + ) + } else if (item.type === 'savedFeed') { + return <SavedFeed feedUri={item.feedUri} /> + } else if (item.type === 'popularFeedsHeader') { + return ( + <> + <View + style={[ + pal.view, + styles.header, + { + marginTop: 16, + paddingLeft: isMobile ? 12 : undefined, + paddingRight: 10, + paddingBottom: isMobile ? 6 : undefined, + }, + ]}> + <Text type="title-lg" style={[pal.text, s.bold]}> + <Trans>Discover new feeds</Trans> + </Text> + + {!isMobile && ( + <SearchInput + query={query} + onChangeQuery={onChangeQuery} + onPressCancelSearch={onPressCancelSearch} + onSubmitQuery={onSubmitQuery} + style={{flex: 1, maxWidth: 250}} + /> + )} + </View> - {!isMobile && ( - <SearchInput - query={query} - onChangeQuery={onChangeQuery} - onPressCancelSearch={onPressCancelSearch} - onSubmitQuery={onSubmitQuery} - style={{flex: 1, maxWidth: 250}} - /> + {isMobile && ( + <View style={{paddingHorizontal: 8, paddingBottom: 10}}> + <SearchInput + query={query} + onChangeQuery={onChangeQuery} + onPressCancelSearch={onPressCancelSearch} + onSubmitQuery={onSubmitQuery} + /> + </View> )} + </> + ) + } else if (item.type === 'popularFeedsLoading') { + return <FeedFeedLoadingPlaceholder /> + } else if (item.type === 'popularFeed') { + return ( + <FeedSourceCard + feedUri={item.feedUri} + showSaveBtn + showDescription + showLikes + /> + ) + } else if (item.type === 'popularFeedsNoResults') { + return ( + <View + style={{ + paddingHorizontal: 16, + paddingTop: 10, + paddingBottom: '150%', + }}> + <Text type="lg" style={pal.textLight}> + <Trans>No results found for "{query}"</Trans> + </Text> </View> + ) + } + return null + }, + [ + _, + isMobile, + pal, + query, + onChangeQuery, + onPressCancelSearch, + onSubmitQuery, + ], + ) - {isMobile && ( - <View style={{paddingHorizontal: 8, paddingBottom: 10}}> - <SearchInput - query={query} - onChangeQuery={onChangeQuery} - onPressCancelSearch={onPressCancelSearch} - onSubmitQuery={onSubmitQuery} - /> - </View> - )} - </> - ) - } else if (item.type === 'popularFeedsLoading') { - return <FeedFeedLoadingPlaceholder /> - } else if (item.type === 'popularFeed') { - return ( - <FeedSourceCard - feedUri={item.feedUri} - showSaveBtn - showDescription - showLikes + return ( + <View style={[pal.view, styles.container]}> + {isMobile && ( + <ViewHeader + title={_(msg`Feeds`)} + canGoBack={false} + renderButton={renderHeaderBtn} + showBorder /> - ) - } else if (item.type === 'popularFeedsNoResults') { - return ( - <View - style={{ - paddingHorizontal: 16, - paddingTop: 10, - paddingBottom: '150%', - }}> - <Text type="lg" style={pal.textLight}> - <Trans>No results found for "{query}"</Trans> - </Text> - </View> - ) - } - return null - }, - [ - _, - isMobile, - pal, - query, - onChangeQuery, - onPressCancelSearch, - onSubmitQuery, - ], - ) + )} - return ( - <View style={[pal.view, styles.container]}> - {isMobile && ( - <ViewHeader - title={_(msg`Feeds`)} - canGoBack={false} - renderButton={renderHeaderBtn} - showBorder - /> - )} - - {preferences ? <View /> : <ActivityIndicator />} + {preferences ? <View /> : <ActivityIndicator />} - <FlatList - style={[!isTabletOrDesktop && s.flex1, styles.list]} - data={items} - keyExtractor={item => item.key} - contentContainerStyle={styles.contentContainer} - renderItem={renderItem} - refreshControl={ - <RefreshControl - refreshing={isPTR} - onRefresh={isUserSearching ? undefined : onPullToRefresh} - tintColor={pal.colors.text} - titleColor={pal.colors.text} - /> - } - initialNumToRender={10} - onEndReached={onEndReached} - // @ts-ignore our .web version only -prf - desktopFixedHeight - /> + <FlatList + style={[!isTabletOrDesktop && s.flex1, styles.list]} + data={items} + keyExtractor={item => item.key} + contentContainerStyle={styles.contentContainer} + renderItem={renderItem} + refreshControl={ + <RefreshControl + refreshing={isPTR} + onRefresh={isUserSearching ? undefined : onPullToRefresh} + tintColor={pal.colors.text} + titleColor={pal.colors.text} + /> + } + initialNumToRender={10} + onEndReached={onEndReached} + // @ts-ignore our .web version only -prf + desktopFixedHeight + /> - <FAB - testID="composeFAB" - onPress={onPressCompose} - icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />} - accessibilityRole="button" - accessibilityLabel={_(msg`New post`)} - accessibilityHint="" - /> - </View> - ) -}) + <FAB + testID="composeFAB" + onPress={onPressCompose} + icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />} + accessibilityRole="button" + accessibilityLabel={_(msg`New post`)} + accessibilityHint="" + /> + </View> + ) + }, + {isPublic: true}, +) function SavedFeed({feedUri}: {feedUri: string}) { const pal = usePalette('default') diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 18a0cbc15..8df945cd2 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -14,22 +14,56 @@ import {useSetMinimalShellMode, useSetDrawerSwipeDisabled} from '#/state/shell' import {usePreferencesQuery} from '#/state/queries/preferences' import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types' import {emitSoftReset} from '#/state/events' +import {useSession} from '#/state/session' type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'> -export const HomeScreen = withAuthRequired(function HomeScreenImpl( - props: Props, -) { - const {data: preferences} = usePreferencesQuery() - if (preferences) { - return <HomeScreenReady {...props} preferences={preferences} /> - } else { - return ( - <View style={styles.loading}> - <ActivityIndicator size="large" /> - </View> - ) - } -}) +export const HomeScreen = withAuthRequired( + function HomeScreenImpl(props: Props) { + const {hasSession} = useSession() + const {data: preferences} = usePreferencesQuery() + + if (!hasSession) { + return <HomeScreenPublic /> + } + + if (preferences) { + return <HomeScreenReady {...props} preferences={preferences} /> + } else { + return ( + <View style={styles.loading}> + <ActivityIndicator size="large" /> + </View> + ) + } + }, + { + isPublic: true, + }, +) + +function HomeScreenPublic() { + const setMinimalShellMode = useSetMinimalShellMode() + const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() + + const renderCustomFeedEmptyState = React.useCallback(() => { + return <CustomFeedEmptyState /> + }, []) + + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + setDrawerSwipeDisabled(false) + }, [setDrawerSwipeDisabled, setMinimalShellMode]), + ) + + return ( + <FeedPage + isPageFocused + feed={`feedgen|at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot`} + renderEmptyState={renderCustomFeedEmptyState} + /> + ) +} function HomeScreenReady({ preferences, @@ -83,6 +117,7 @@ function HomeScreenReady({ emitSoftReset() }, []) + // TODO(pwi) may need this in public view const onPageScrollStateChanged = React.useCallback( (state: 'idle' | 'dragging' | 'settling') => { if (state === 'dragging') { diff --git a/src/view/screens/PostLikedBy.tsx b/src/view/screens/PostLikedBy.tsx index ab7bbcefe..2209310d0 100644 --- a/src/view/screens/PostLikedBy.tsx +++ b/src/view/screens/PostLikedBy.tsx @@ -11,22 +11,25 @@ import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'> -export const PostLikedByScreen = withAuthRequired(({route}: Props) => { - const setMinimalShellMode = useSetMinimalShellMode() - const {name, rkey} = route.params - const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) - const {_} = useLingui() +export const PostLikedByScreen = withAuthRequired( + ({route}: Props) => { + const setMinimalShellMode = useSetMinimalShellMode() + const {name, rkey} = route.params + const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) + const {_} = useLingui() - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - return ( - <View> - <ViewHeader title={_(msg`Liked by`)} /> - <PostLikedByComponent uri={uri} /> - </View> - ) -}) + return ( + <View> + <ViewHeader title={_(msg`Liked by`)} /> + <PostLikedByComponent uri={uri} /> + </View> + ) + }, + {isPublic: true}, +) diff --git a/src/view/screens/PostRepostedBy.tsx b/src/view/screens/PostRepostedBy.tsx index eabbc4a4e..5b3b5f8fa 100644 --- a/src/view/screens/PostRepostedBy.tsx +++ b/src/view/screens/PostRepostedBy.tsx @@ -11,22 +11,25 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'> -export const PostRepostedByScreen = withAuthRequired(({route}: Props) => { - const {name, rkey} = route.params - const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) - const setMinimalShellMode = useSetMinimalShellMode() - const {_} = useLingui() +export const PostRepostedByScreen = withAuthRequired( + ({route}: Props) => { + const {name, rkey} = route.params + const uri = makeRecordUri(name, 'app.bsky.feed.post', rkey) + const setMinimalShellMode = useSetMinimalShellMode() + const {_} = useLingui() - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - return ( - <View> - <ViewHeader title={_(msg`Reposted by`)} /> - <PostRepostedByComponent uri={uri} /> - </View> - ) -}) + return ( + <View> + <ViewHeader title={_(msg`Reposted by`)} /> + <PostRepostedByComponent uri={uri} /> + </View> + ) + }, + {isPublic: true}, +) diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index 0476e182b..11574e283 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -27,84 +27,85 @@ import {CenteredView} from '../com/util/Views' import {useComposerControls} from '#/state/shell/composer' type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'> -export const PostThreadScreen = withAuthRequired(function PostThreadScreenImpl({ - route, -}: Props) { - const queryClient = useQueryClient() - const {_} = useLingui() - 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 {_} = useLingui() + 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]), - ) - - const onPressReply = React.useCallback(() => { - if (!resolvedUri) { - return - } - const thread = queryClient.getQueryData<ThreadNode>( - POST_THREAD_RQKEY(resolvedUri.uri), + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), ) - 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={_(msg`Post`)} />} - <View style={s.flex1}> - {uriError ? ( - <CenteredView> - <ErrorMessage message={String(uriError)} /> - </CenteredView> - ) : ( - <PostThreadComponent - uri={resolvedUri?.uri} - onPressReply={onPressReply} - /> + return ( + <View style={s.hContentRegion}> + {isMobile && <ViewHeader title={_(msg`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> - {isMobile && ( - <Animated.View - style={[ - styles.prompt, - fabMinimalShellTransform, - { - bottom: clamp(safeAreaInsets.bottom, 15, 30), - }, - ]}> - <ComposePrompt onPressCompose={onPressReply} /> - </Animated.View> - )} - </View> - ) -}) + ) + }, + {isPublic: true}, +) const styles = StyleSheet.create({ prompt: { diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 88b11b114..5411bc044 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -43,82 +43,85 @@ interface SectionRef { } type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'> -export const ProfileScreen = withAuthRequired(function ProfileScreenImpl({ - route, -}: Props) { - const {currentAccount} = useSession() - const name = - route.params.name === 'me' ? currentAccount?.did : route.params.name - const moderationOpts = useModerationOpts() - const { - data: resolvedDid, - error: resolveError, - refetch: refetchDid, - isFetching: isFetchingDid, - } = useResolveDidQuery(name) - const { - data: profile, - dataUpdatedAt, - error: profileError, - refetch: refetchProfile, - isFetching: isFetchingProfile, - } = useProfileQuery({ - did: resolvedDid?.did, - }) +export const ProfileScreen = withAuthRequired( + function ProfileScreenImpl({route}: Props) { + const {currentAccount} = useSession() + const name = + route.params.name === 'me' ? currentAccount?.did : route.params.name + const moderationOpts = useModerationOpts() + const { + data: resolvedDid, + error: resolveError, + refetch: refetchDid, + isFetching: isFetchingDid, + } = useResolveDidQuery(name) + const { + data: profile, + dataUpdatedAt, + error: profileError, + refetch: refetchProfile, + isFetching: isFetchingProfile, + } = useProfileQuery({ + did: resolvedDid?.did, + }) - const onPressTryAgain = React.useCallback(() => { - if (resolveError) { - refetchDid() - } else { - refetchProfile() - } - }, [resolveError, refetchDid, refetchProfile]) + const onPressTryAgain = React.useCallback(() => { + if (resolveError) { + refetchDid() + } else { + refetchProfile() + } + }, [resolveError, refetchDid, refetchProfile]) - if (isFetchingDid || isFetchingProfile || !moderationOpts) { - return ( - <CenteredView> - <ProfileHeader - profile={null} - moderation={null} - isProfilePreview={true} + if (isFetchingDid || isFetchingProfile || !moderationOpts) { + return ( + <CenteredView> + <ProfileHeader + profile={null} + moderation={null} + isProfilePreview={true} + /> + </CenteredView> + ) + } + if (resolveError || profileError) { + return ( + <CenteredView> + <ErrorScreen + testID="profileErrorScreen" + title="Oops!" + message={cleanError(resolveError || profileError)} + onPressTryAgain={onPressTryAgain} + /> + </CenteredView> + ) + } + if (profile && moderationOpts) { + return ( + <ProfileScreenLoaded + profile={profile} + dataUpdatedAt={dataUpdatedAt} + moderationOpts={moderationOpts} + hideBackButton={!!route.params.hideBackButton} /> - </CenteredView> - ) - } - if (resolveError || profileError) { + ) + } + // should never happen return ( <CenteredView> <ErrorScreen testID="profileErrorScreen" title="Oops!" - message={cleanError(resolveError || profileError)} + message="Something went wrong and we're not sure what." onPressTryAgain={onPressTryAgain} /> </CenteredView> ) - } - if (profile && moderationOpts) { - return ( - <ProfileScreenLoaded - profile={profile} - dataUpdatedAt={dataUpdatedAt} - moderationOpts={moderationOpts} - hideBackButton={!!route.params.hideBackButton} - /> - ) - } - // should never happen - return ( - <CenteredView> - <ErrorScreen - testID="profileErrorScreen" - title="Oops!" - message="Something went wrong and we're not sure what." - onPressTryAgain={onPressTryAgain} - /> - </CenteredView> - ) -}) + }, + { + isPublic: true, + }, +) function ProfileScreenLoaded({ profile: profileUnshadowed, diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx index 3974d3a11..2cdcdb3b5 100644 --- a/src/view/screens/ProfileFeed.tsx +++ b/src/view/screens/ProfileFeed.tsx @@ -129,6 +129,9 @@ export const ProfileFeedScreen = withAuthRequired( </CenteredView> ) }, + { + isPublic: true, + }, ) function ProfileFeedScreenIntermediate({feedUri}: {feedUri: string}) { diff --git a/src/view/screens/ProfileFeedLikedBy.tsx b/src/view/screens/ProfileFeedLikedBy.tsx index c8466360e..6399c8a0b 100644 --- a/src/view/screens/ProfileFeedLikedBy.tsx +++ b/src/view/screens/ProfileFeedLikedBy.tsx @@ -11,22 +11,25 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'> -export const ProfileFeedLikedByScreen = withAuthRequired(({route}: Props) => { - const setMinimalShellMode = useSetMinimalShellMode() - const {name, rkey} = route.params - const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey) - const {_} = useLingui() +export const ProfileFeedLikedByScreen = withAuthRequired( + ({route}: Props) => { + const setMinimalShellMode = useSetMinimalShellMode() + const {name, rkey} = route.params + const uri = makeRecordUri(name, 'app.bsky.feed.generator', rkey) + const {_} = useLingui() - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - return ( - <View> - <ViewHeader title={_(msg`Liked by`)} /> - <PostLikedByComponent uri={uri} /> - </View> - ) -}) + return ( + <View> + <ViewHeader title={_(msg`Liked by`)} /> + <PostLikedByComponent uri={uri} /> + </View> + ) + }, + {isPublic: true}, +) diff --git a/src/view/screens/ProfileFollowers.tsx b/src/view/screens/ProfileFollowers.tsx index 13e69541a..71c0e4a9c 100644 --- a/src/view/screens/ProfileFollowers.tsx +++ b/src/view/screens/ProfileFollowers.tsx @@ -10,21 +10,24 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'> -export const ProfileFollowersScreen = withAuthRequired(({route}: Props) => { - const {name} = route.params - const setMinimalShellMode = useSetMinimalShellMode() - const {_} = useLingui() +export const ProfileFollowersScreen = withAuthRequired( + ({route}: Props) => { + const {name} = route.params + const setMinimalShellMode = useSetMinimalShellMode() + const {_} = useLingui() - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - return ( - <View> - <ViewHeader title={_(msg`Followers`)} /> - <ProfileFollowersComponent name={name} /> - </View> - ) -}) + return ( + <View> + <ViewHeader title={_(msg`Followers`)} /> + <ProfileFollowersComponent name={name} /> + </View> + ) + }, + {isPublic: true}, +) diff --git a/src/view/screens/ProfileFollows.tsx b/src/view/screens/ProfileFollows.tsx index 07d6eaa78..bb3f2040f 100644 --- a/src/view/screens/ProfileFollows.tsx +++ b/src/view/screens/ProfileFollows.tsx @@ -10,21 +10,24 @@ import {useLingui} from '@lingui/react' import {msg} from '@lingui/macro' type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'> -export const ProfileFollowsScreen = withAuthRequired(({route}: Props) => { - const {name} = route.params - const setMinimalShellMode = useSetMinimalShellMode() - const {_} = useLingui() +export const ProfileFollowsScreen = withAuthRequired( + ({route}: Props) => { + const {name} = route.params + const setMinimalShellMode = useSetMinimalShellMode() + const {_} = useLingui() - useFocusEffect( - React.useCallback(() => { - setMinimalShellMode(false) - }, [setMinimalShellMode]), - ) + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) - return ( - <View> - <ViewHeader title={_(msg`Following`)} /> - <ProfileFollowsComponent name={name} /> - </View> - ) -}) + return ( + <View> + <ViewHeader title={_(msg`Following`)} /> + <ProfileFollowsComponent name={name} /> + </View> + ) + }, + {isPublic: true}, +) diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx index 4928b6745..4c13a2be1 100644 --- a/src/view/screens/SavedFeeds.tsx +++ b/src/view/screens/SavedFeeds.tsx @@ -33,7 +33,7 @@ import { usePinFeedMutation, useUnpinFeedMutation, useSetSaveFeedsMutation, - usePreferencesQueryKey, + preferencesQueryKey, UsePreferencesQueryResponse, } from '#/state/queries/preferences' @@ -182,9 +182,10 @@ function ListItem({ const onPressUp = React.useCallback(async () => { if (!isPinned) return - const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>( - usePreferencesQueryKey, - )?.feeds + const feeds = + queryClient.getQueryData<UsePreferencesQueryResponse>( + preferencesQueryKey, + )?.feeds const pinned = feeds?.pinned ?? [] const index = pinned.indexOf(feedUri) @@ -206,9 +207,10 @@ function ListItem({ const onPressDown = React.useCallback(async () => { if (!isPinned) return - const feeds = queryClient.getQueryData<UsePreferencesQueryResponse>( - usePreferencesQueryKey, - )?.feeds + const feeds = + queryClient.getQueryData<UsePreferencesQueryResponse>( + preferencesQueryKey, + )?.feeds const pinned = feeds?.pinned ?? [] const index = pinned.indexOf(feedUri) |