diff options
Diffstat (limited to 'src/view/com')
-rw-r--r-- | src/view/com/composer/Composer.tsx | 34 | ||||
-rw-r--r-- | src/view/com/feeds/ProfileFeedgens.tsx | 105 | ||||
-rw-r--r-- | src/view/com/lists/ProfileLists.tsx | 32 | ||||
-rw-r--r-- | src/view/com/profile/ProfileCard.tsx | 1 | ||||
-rw-r--r-- | src/view/com/util/post-ctrls/PostCtrls.tsx | 29 |
5 files changed, 125 insertions, 76 deletions
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 80bce5351..9e2f77d4d 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -24,12 +24,18 @@ import Animated, { } from 'react-native-reanimated' import {useSafeAreaInsets} from 'react-native-safe-area-context' import {LinearGradient} from 'expo-linear-gradient' +import { + AppBskyFeedDefs, + AppBskyFeedGetPostThread, + BskyAgent, +} from '@atproto/api' import {RichText} from '@atproto/api' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {observer} from 'mobx-react-lite' +import {until} from '#/lib/async/until' import { createGIFDescription, parseAltFromGIFDescription, @@ -299,6 +305,17 @@ export const ComposePost = observer(function ComposePost({ langs: toPostLanguages(langPrefs.postLanguage), }) ).uri + try { + await whenAppViewReady(agent, postUri, res => { + const thread = res.data.thread + return AppBskyFeedDefs.isThreadViewPost(thread) + }) + } catch (waitErr: any) { + logger.error(waitErr, { + message: `Waiting for app view failed`, + }) + // Keep going because the post *was* published. + } } catch (e: any) { logger.error(e, { message: `Composer: create post failed`, @@ -756,6 +773,23 @@ function useKeyboardVerticalOffset() { return top + 10 } +async function whenAppViewReady( + agent: BskyAgent, + uri: string, + fn: (res: AppBskyFeedGetPostThread.Response) => boolean, +) { + await until( + 5, // 5 tries + 1e3, // 1s delay between tries + fn, + () => + agent.app.bsky.feed.getPostThread({ + uri, + depth: 0, + }), + ) +} + const styles = StyleSheet.create({ topbarInner: { flexDirection: 'row', diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx index 197f35e4d..ec1a55e22 100644 --- a/src/view/com/feeds/ProfileFeedgens.tsx +++ b/src/view/com/feeds/ProfileFeedgens.tsx @@ -3,7 +3,6 @@ import { findNodeHandle, ListRenderItemInfo, StyleProp, - StyleSheet, View, ViewStyle, } from 'react-native' @@ -12,18 +11,17 @@ import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' import {cleanError} from '#/lib/strings/errors' -import {useTheme} from '#/lib/ThemeContext' import {logger} from '#/logger' import {isNative, isWeb} from '#/platform/detection' -import {hydrateFeedGenerator} from '#/state/queries/feed' import {usePreferencesQuery} from '#/state/queries/preferences' import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {EmptyState} from 'view/com/util/EmptyState' +import {atoms as a, useTheme} from '#/alf' +import * as FeedCard from '#/components/FeedCard' import {ErrorMessage} from '../util/error/ErrorMessage' import {List, ListRef} from '../util/List' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' -import {FeedSourceCardLoaded} from './FeedSourceCard' const LOADING = {_reactKey: '__loading__'} const EMPTY = {_reactKey: '__empty__'} @@ -52,7 +50,7 @@ export const ProfileFeedgens = React.forwardRef< ref, ) { const {_} = useLingui() - const theme = useTheme() + const t = useTheme() const [isPTRing, setIsPTRing] = React.useState(false) const opts = React.useMemo(() => ({enabled}), [enabled]) const { @@ -79,10 +77,9 @@ export const ProfileFeedgens = React.forwardRef< items = items.concat([EMPTY]) } else if (data?.pages) { for (const page of data?.pages) { - items = items.concat(page.feeds.map(feed => hydrateFeedGenerator(feed))) + items = items.concat(page.feeds) } - } - if (isError && !isEmpty) { + } else if (isError && !isEmpty) { items = items.concat([LOAD_MORE_ERROR_ITEM]) } return items @@ -132,48 +129,46 @@ export const ProfileFeedgens = React.forwardRef< // rendering // = - const renderItemInner = React.useCallback( - ({item, index}: ListRenderItemInfo<any>) => { - if (item === EMPTY) { - return ( - <EmptyState - icon="hashtag" - message={_(msg`You have no feeds.`)} - testID="listsEmpty" - /> - ) - } else if (item === ERROR_ITEM) { - return ( - <ErrorMessage message={cleanError(error)} onPressTryAgain={refetch} /> - ) - } else if (item === LOAD_MORE_ERROR_ITEM) { - return ( - <LoadMoreRetryBtn - label={_( - msg`There was an issue fetching your lists. Tap here to try again.`, - )} - onPress={onPressRetryLoadMore} - /> - ) - } else if (item === LOADING) { - return <FeedLoadingPlaceholder /> - } - if (preferences) { - return ( - <FeedSourceCardLoaded - feedUri={item.uri} - feed={item} - preferences={preferences} - style={styles.item} - showLikes - hideTopBorder={index === 0 && !isWeb} - /> - ) - } - return null - }, - [error, refetch, onPressRetryLoadMore, preferences, _], - ) + const renderItem = ({item, index}: ListRenderItemInfo<any>) => { + if (item === EMPTY) { + return ( + <EmptyState + icon="hashtag" + message={_(msg`You have no feeds.`)} + testID="listsEmpty" + /> + ) + } else if (item === ERROR_ITEM) { + return ( + <ErrorMessage message={cleanError(error)} onPressTryAgain={refetch} /> + ) + } else if (item === LOAD_MORE_ERROR_ITEM) { + return ( + <LoadMoreRetryBtn + label={_( + msg`There was an issue fetching your lists. Tap here to try again.`, + )} + onPress={onPressRetryLoadMore} + /> + ) + } else if (item === LOADING) { + return <FeedLoadingPlaceholder /> + } + if (preferences) { + return ( + <View + style={[ + (index !== 0 || isWeb) && a.border_t, + t.atoms.border_contrast_low, + a.px_lg, + a.py_lg, + ]}> + <FeedCard.Default type="feed" view={item} /> + </View> + ) + } + return null + } React.useEffect(() => { if (enabled && scrollElRef.current) { @@ -189,12 +184,12 @@ export const ProfileFeedgens = React.forwardRef< ref={scrollElRef} data={items} keyExtractor={(item: any) => item._reactKey || item.uri} - renderItem={renderItemInner} + renderItem={renderItem} refreshing={isPTRing} onRefresh={onRefresh} headerOffset={headerOffset} contentContainerStyle={isNative && {paddingBottom: headerOffset + 100}} - indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} + indicatorStyle={t.name === 'light' ? 'black' : 'white'} removeClippedSubviews={true} // @ts-ignore our .web version only -prf desktopFixedHeight @@ -203,9 +198,3 @@ export const ProfileFeedgens = React.forwardRef< </View> ) }) - -const styles = StyleSheet.create({ - item: { - paddingHorizontal: 18, - }, -}) diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx index e7fdfe4bd..62c944efc 100644 --- a/src/view/com/lists/ProfileLists.tsx +++ b/src/view/com/lists/ProfileLists.tsx @@ -3,7 +3,6 @@ import { findNodeHandle, ListRenderItemInfo, StyleProp, - StyleSheet, View, ViewStyle, } from 'react-native' @@ -12,17 +11,17 @@ import {useLingui} from '@lingui/react' import {useQueryClient} from '@tanstack/react-query' import {cleanError} from '#/lib/strings/errors' -import {useTheme} from '#/lib/ThemeContext' import {logger} from '#/logger' import {isNative, isWeb} from '#/platform/detection' import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists' import {useAnalytics} from 'lib/analytics/analytics' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {EmptyState} from 'view/com/util/EmptyState' +import {atoms as a, useTheme} from '#/alf' +import * as FeedCard from '#/components/FeedCard' import {ErrorMessage} from '../util/error/ErrorMessage' import {List, ListRef} from '../util/List' import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn' -import {ListCard} from './ListCard' const LOADING = {_reactKey: '__loading__'} const EMPTY = {_reactKey: '__empty__'} @@ -48,7 +47,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( {did, scrollElRef, headerOffset, enabled, style, testID, setScrollViewTag}, ref, ) { - const theme = useTheme() + const t = useTheme() const {track} = useAnalytics() const {_} = useLingui() const [isPTRing, setIsPTRing] = React.useState(false) @@ -166,15 +165,18 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( return <FeedLoadingPlaceholder /> } return ( - <ListCard - list={item} - testID={`list-${item.name}`} - style={styles.item} - noBorder={index === 0 && !isWeb} - /> + <View + style={[ + (index !== 0 || isWeb) && a.border_t, + t.atoms.border_contrast_low, + a.px_lg, + a.py_lg, + ]}> + <FeedCard.Default type="list" view={item} /> + </View> ) }, - [error, refetch, onPressRetryLoadMore, _], + [error, refetch, onPressRetryLoadMore, _, t.atoms.border_contrast_low], ) React.useEffect(() => { @@ -198,7 +200,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( contentContainerStyle={ isNative && {paddingBottom: headerOffset + 100} } - indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} + indicatorStyle={t.name === 'light' ? 'black' : 'white'} removeClippedSubviews={true} // @ts-ignore our .web version only -prf desktopFixedHeight @@ -208,9 +210,3 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>( ) }, ) - -const styles = StyleSheet.create({ - item: { - paddingHorizontal: 18, - }, -}) diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index 2b0790002..a3cd5ca1b 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -328,6 +328,7 @@ const styles = StyleSheet.create({ borderRadius: 4, paddingHorizontal: 6, paddingVertical: 2, + justifyContent: 'center', }, btn: { paddingVertical: 7, diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx index 472ce4043..231808bf2 100644 --- a/src/view/com/util/post-ctrls/PostCtrls.tsx +++ b/src/view/com/util/post-ctrls/PostCtrls.tsx @@ -6,6 +6,7 @@ import { View, type ViewStyle, } from 'react-native' +import * as Clipboard from 'expo-clipboard' import { AppBskyFeedDefs, AppBskyFeedPost, @@ -19,6 +20,7 @@ import {POST_CTRL_HITSLOP} from '#/lib/constants' import {useHaptics} from '#/lib/haptics' import {makeProfileLink} from '#/lib/routes/links' import {shareUrl} from '#/lib/sharing' +import {useGate} from '#/lib/statsig/statsig' import {toShareUrl} from '#/lib/strings/url-helpers' import {s} from '#/lib/styles' import {Shadow} from '#/state/cache/types' @@ -41,6 +43,7 @@ import * as Prompt from '#/components/Prompt' import {PostDropdownBtn} from '../forms/PostDropdownBtn' import {formatCount} from '../numeric/format' import {Text} from '../text/Text' +import * as Toast from '../Toast' import {RepostButton} from './RepostButton' let PostCtrls = ({ @@ -75,6 +78,7 @@ let PostCtrls = ({ const loggedOutWarningPromptControl = useDialogControl() const {sendInteraction} = useFeedFeedbackContext() const playHaptic = useHaptics() + const gate = useGate() const shouldShowLoggedOutWarning = React.useMemo(() => { return ( @@ -329,6 +333,31 @@ let PostCtrls = ({ timestamp={post.indexedAt} /> </View> + {gate('debug_show_feedcontext') && feedContext && ( + <Pressable + accessible={false} + style={{ + position: 'absolute', + top: 0, + bottom: 0, + right: 0, + display: 'flex', + justifyContent: 'center', + }} + onPress={e => { + e.stopPropagation() + Clipboard.setStringAsync(feedContext) + Toast.show(_(msg`Copied to clipboard`)) + }}> + <Text + style={{ + color: t.palette.contrast_400, + fontSize: 7, + }}> + {feedContext} + </Text> + </Pressable> + )} </View> ) } |