From 257686f3603e800e355850a23b3a4011e5558aeb Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 25 May 2023 20:02:37 -0500 Subject: Add feeds tab --- src/view/com/posts/MultiFeed.tsx | 230 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 src/view/com/posts/MultiFeed.tsx (limited to 'src/view/com/posts/MultiFeed.tsx') diff --git a/src/view/com/posts/MultiFeed.tsx b/src/view/com/posts/MultiFeed.tsx new file mode 100644 index 000000000..4911c9e2c --- /dev/null +++ b/src/view/com/posts/MultiFeed.tsx @@ -0,0 +1,230 @@ +import React, {MutableRefObject} from 'react' +import {observer} from 'mobx-react-lite' +import { + ActivityIndicator, + RefreshControl, + StyleProp, + StyleSheet, + View, + ViewStyle, +} from 'react-native' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {FlatList} from '../util/Views' +import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder' +import {ErrorMessage} from '../util/error/ErrorMessage' +import {PostsMultiFeedModel, MultiFeedItem} from 'state/models/feeds/multi-feed' +import {FeedSlice} from './FeedSlice' +import {Text} from '../util/text/Text' +import {Link} from '../util/Link' +import {UserAvatar} from '../util/UserAvatar' +import {OnScrollCb} from 'lib/hooks/useOnMainScroll' +import {s} from 'lib/styles' +import {useAnalytics} from 'lib/analytics' +import {usePalette} from 'lib/hooks/usePalette' +import {useTheme} from 'lib/ThemeContext' + +export const MultiFeed = observer(function Feed({ + multifeed, + style, + showPostFollowBtn, + scrollElRef, + onScroll, + scrollEventThrottle, + testID, + headerOffset = 0, + extraData, +}: { + multifeed: PostsMultiFeedModel + style?: StyleProp + showPostFollowBtn?: boolean + scrollElRef?: MutableRefObject | null> + onPressTryAgain?: () => void + onScroll?: OnScrollCb + scrollEventThrottle?: number + renderEmptyState?: () => JSX.Element + testID?: string + headerOffset?: number + extraData?: any +}) { + const pal = usePalette('default') + const palInverted = usePalette('inverted') + const theme = useTheme() + const {track} = useAnalytics() + const [isRefreshing, setIsRefreshing] = React.useState(false) + + // events + // = + + const onRefresh = React.useCallback(async () => { + track('MultiFeed:onRefresh') + setIsRefreshing(true) + try { + await multifeed.refresh() + } catch (err) { + multifeed.rootStore.log.error('Failed to refresh posts feed', err) + } + setIsRefreshing(false) + }, [multifeed, track, setIsRefreshing]) + + const onEndReached = React.useCallback(async () => { + track('MultiFeed:onEndReached') + try { + await multifeed.loadMore() + } catch (err) { + multifeed.rootStore.log.error('Failed to load more posts', err) + } + }, [multifeed, track]) + + // rendering + // = + + const renderItem = React.useCallback( + ({item}: {item: MultiFeedItem}) => { + if (item.type === 'header') { + return + } else if (item.type === 'feed-header') { + return ( + + + + {item.title} + + + ) + } else if (item.type === 'feed-slice') { + return ( + + ) + } else if (item.type === 'feed-loading') { + return + } else if (item.type === 'feed-error') { + return + } else if (item.type === 'feed-footer') { + return ( + + + See more from {item.title} + + + + ) + } else if (item.type === 'footer') { + return ( + + + + Discover new feeds + + + ) + } + return null + }, + [showPostFollowBtn, pal, palInverted], + ) + + const FeedFooter = React.useCallback( + () => + multifeed.isLoading && !isRefreshing ? ( + + + + ) : ( + + ), + [multifeed.isLoading, isRefreshing, pal], + ) + + return ( + + {multifeed.items.length > 0 && ( + item._reactKey} + renderItem={renderItem} + ListFooterComponent={FeedFooter} + refreshControl={ + + } + contentContainerStyle={s.contentContainer} + style={[{paddingTop: headerOffset}, pal.viewLight, styles.container]} + onScroll={onScroll} + scrollEventThrottle={scrollEventThrottle} + indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} + onEndReached={onEndReached} + onEndReachedThreshold={0.6} + removeClippedSubviews={true} + contentOffset={{x: 0, y: headerOffset * -1}} + extraData={extraData} + // @ts-ignore our .web version only -prf + desktopFixedHeight + /> + )} + + ) +}) + +const styles = StyleSheet.create({ + container: { + height: '100%', + }, + header: { + borderTopWidth: 1, + marginBottom: 4, + }, + feedHeader: { + flexDirection: 'row', + gap: 8, + alignItems: 'center', + paddingHorizontal: 16, + paddingBottom: 8, + marginTop: 12, + }, + feedHeaderTitle: { + fontWeight: 'bold', + }, + feedFooter: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingHorizontal: 16, + paddingVertical: 16, + marginBottom: 12, + borderTopWidth: 1, + borderBottomWidth: 1, + }, + footerLink: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + borderRadius: 8, + paddingHorizontal: 14, + paddingVertical: 12, + marginHorizontal: 8, + marginBottom: 8, + gap: 8, + }, + loadMore: { + paddingTop: 10, + }, +}) -- cgit 1.4.1 From 651f3abc1ff0913347ed7bfb824f8e280f87a850 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 25 May 2023 20:19:49 -0500 Subject: Tune up custom feed uis on web --- src/view/com/pager/TabBar.tsx | 5 +++-- src/view/com/posts/MultiFeed.tsx | 29 ++++++++++++++++++++++++++++- src/view/shell/desktop/LeftNav.tsx | 18 +++++++++--------- 3 files changed, 40 insertions(+), 12 deletions(-) (limited to 'src/view/com/posts/MultiFeed.tsx') diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx index 70500db2c..422d986a7 100644 --- a/src/view/com/pager/TabBar.tsx +++ b/src/view/com/pager/TabBar.tsx @@ -92,7 +92,7 @@ export function TabBar({ hoverStyle={pal.viewLight} onPress={() => onPressItem(i)}> {item} @@ -112,7 +112,7 @@ const styles = isDesktopWeb width: 598, }, contentContainer: { - columnGap: 14, + columnGap: 8, marginLeft: 14, paddingRight: 14, backgroundColor: 'transparent', @@ -120,6 +120,7 @@ const styles = isDesktopWeb item: { paddingTop: 14, paddingBottom: 12, + paddingHorizontal: 10, borderBottomWidth: 3, borderBottomColor: 'transparent', }, diff --git a/src/view/com/posts/MultiFeed.tsx b/src/view/com/posts/MultiFeed.tsx index 4911c9e2c..75c57c446 100644 --- a/src/view/com/posts/MultiFeed.tsx +++ b/src/view/com/posts/MultiFeed.tsx @@ -22,6 +22,8 @@ import {s} from 'lib/styles' import {useAnalytics} from 'lib/analytics' import {usePalette} from 'lib/hooks/usePalette' import {useTheme} from 'lib/ThemeContext' +import {isDesktopWeb} from 'platform/detection' +import {CogIcon} from 'lib/icons' export const MultiFeed = observer(function Feed({ multifeed, @@ -81,6 +83,18 @@ export const MultiFeed = observer(function Feed({ const renderItem = React.useCallback( ({item}: {item: MultiFeedItem}) => { if (item.type === 'header') { + if (isDesktopWeb) { + return ( + + + My Feeds + + + + + + ) + } return } else if (item.type === 'feed-header') { return ( @@ -167,7 +181,11 @@ export const MultiFeed = observer(function Feed({ /> } contentContainerStyle={s.contentContainer} - style={[{paddingTop: headerOffset}, pal.viewLight, styles.container]} + style={[ + {paddingTop: headerOffset}, + isDesktopWeb ? pal.view : pal.viewLight, + styles.container, + ]} onScroll={onScroll} scrollEventThrottle={scrollEventThrottle} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} @@ -192,6 +210,15 @@ const styles = StyleSheet.create({ borderTopWidth: 1, marginBottom: 4, }, + headerDesktop: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + borderBottomWidth: 1, + marginBottom: 4, + paddingHorizontal: 16, + paddingVertical: 8, + }, feedHeader: { flexDirection: 'row', gap: 8, diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index 3b14d7e99..ce232a730 100644 --- a/src/view/shell/desktop/LeftNav.tsx +++ b/src/view/shell/desktop/LeftNav.tsx @@ -197,15 +197,6 @@ export const DesktopLeftNav = observer(function DesktopLeftNav() { } label="Search" /> - } - iconFilled={ - - } - label="Notifications" - /> + } + iconFilled={ + + } + label="Notifications" + /> Date: Thu, 25 May 2023 20:44:37 -0500 Subject: UI tune ups --- src/view/com/pager/FeedsTabBarMobile.tsx | 10 +++++++--- src/view/com/posts/MultiFeed.tsx | 21 +++++---------------- 2 files changed, 12 insertions(+), 19 deletions(-) (limited to 'src/view/com/posts/MultiFeed.tsx') diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx index 0d71b2b98..9c7138815 100644 --- a/src/view/com/pager/FeedsTabBarMobile.tsx +++ b/src/view/com/pager/FeedsTabBarMobile.tsx @@ -6,6 +6,7 @@ import {RenderTabBarFnProps} from 'view/com/pager/Pager' import {useStores} from 'state/index' import {usePalette} from 'lib/hooks/usePalette' import {useAnimatedValue} from 'lib/hooks/useAnimatedValue' +import {useColorSchemeStyle} from 'lib/hooks/useColorSchemeStyle' import {Link} from '../util/Link' import {Text} from '../util/text/Text' import {CogIcon} from 'lib/icons' @@ -32,6 +33,8 @@ export const FeedsTabBar = observer( transform: [{translateY: Animated.multiply(interp, -100)}], } + const brandBlue = useColorSchemeStyle(s.brandBlue, s.blue3) + const onPressAvi = React.useCallback(() => { store.shell.openDrawer() }, [store]) @@ -59,9 +62,7 @@ export const FeedsTabBar = observer( /> - - Bluesky - + Bluesky - - + + + Discover new feeds @@ -146,7 +139,7 @@ export const MultiFeed = observer(function Feed({ } return null }, - [showPostFollowBtn, pal, palInverted], + [showPostFollowBtn, pal], ) const FeedFooter = React.useCallback( @@ -181,11 +174,7 @@ export const MultiFeed = observer(function Feed({ /> } contentContainerStyle={s.contentContainer} - style={[ - {paddingTop: headerOffset}, - isDesktopWeb ? pal.view : pal.viewLight, - styles.container, - ]} + style={[{paddingTop: headerOffset}, pal.view, styles.container]} onScroll={onScroll} scrollEventThrottle={scrollEventThrottle} indicatorStyle={theme.colorScheme === 'dark' ? 'white' : 'black'} -- cgit 1.4.1