Fix home feed positioning (closes #189) (#195)

* Fix home feed positioning for floating header

* Fix positioning of errors in home feed

* Fix lint
This commit is contained in:
Paul Frazee
2023-02-14 15:33:36 -06:00
committed by GitHub
parent 6f98bf8aa5
commit 7d162c8101
2 changed files with 26 additions and 24 deletions
+16 -17
View File
@@ -17,8 +17,8 @@ import {OnScrollCb} from '../../lib/hooks/useOnMainScroll'
import {s} from '../../lib/styles' import {s} from '../../lib/styles'
import {useAnalytics} from '@segment/analytics-react-native' import {useAnalytics} from '@segment/analytics-react-native'
const HEADER_SPACER_ITEM = {_reactKey: '__spacer__'}
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
const ERROR_FEED_ITEM = {_reactKey: '__error__'}
export const Feed = observer(function Feed({ export const Feed = observer(function Feed({
feed, feed,
@@ -27,7 +27,7 @@ export const Feed = observer(function Feed({
onPressTryAgain, onPressTryAgain,
onScroll, onScroll,
testID, testID,
headerSpacer, headerOffset = 0,
}: { }: {
feed: FeedModel feed: FeedModel
style?: StyleProp<ViewStyle> style?: StyleProp<ViewStyle>
@@ -35,7 +35,7 @@ export const Feed = observer(function Feed({
onPressTryAgain?: () => void onPressTryAgain?: () => void
onScroll?: OnScrollCb onScroll?: OnScrollCb
testID?: string testID?: string
headerSpacer?: boolean headerOffset?: number
}) { }) {
const {screen, track} = useAnalytics() const {screen, track} = useAnalytics()
@@ -56,12 +56,12 @@ export const Feed = observer(function Feed({
style={styles.emptyState} style={styles.emptyState}
/> />
) )
} else if (item === ERROR_FEED_ITEM) {
return (
<ErrorMessage message={feed.error} onPressTryAgain={onPressTryAgain} />
)
} }
if (item === HEADER_SPACER_ITEM) { return <FeedItem item={item} />
return <View style={styles.headerSpacer} />
} else {
return <FeedItem item={item} />
}
} }
const onRefresh = () => { const onRefresh = () => {
track('Feed:onRefresh') track('Feed:onRefresh')
@@ -77,13 +77,13 @@ export const Feed = observer(function Feed({
.loadMore() .loadMore()
.catch(err => feed.rootStore.log.error('Failed to load more posts', err)) .catch(err => feed.rootStore.log.error('Failed to load more posts', err))
} }
let data = [] let data: any[] = []
if (headerSpacer) { if (feed.hasError) {
data.push(HEADER_SPACER_ITEM) data = data.concat([ERROR_FEED_ITEM])
} }
if (feed.hasLoaded) { if (feed.hasLoaded) {
if (feed.isEmpty) { if (feed.isEmpty) {
data.push(EMPTY_FEED_ITEM) data = data.concat([EMPTY_FEED_ITEM])
} else { } else {
data = data.concat(feed.feed) data = data.concat(feed.feed)
} }
@@ -99,10 +99,7 @@ export const Feed = observer(function Feed({
return ( return (
<View testID={testID} style={style}> <View testID={testID} style={style}>
{feed.isLoading && !data && <PostFeedLoadingPlaceholder />} {feed.isLoading && !data && <PostFeedLoadingPlaceholder />}
{feed.hasError && ( {data && (
<ErrorMessage message={feed.error} onPressTryAgain={onPressTryAgain} />
)}
{feed.hasLoaded && data && (
<FlatList <FlatList
ref={scrollElRef} ref={scrollElRef}
data={data} data={data}
@@ -115,6 +112,9 @@ export const Feed = observer(function Feed({
onRefresh={onRefresh} onRefresh={onRefresh}
onEndReached={onEndReached} onEndReached={onEndReached}
removeClippedSubviews={true} removeClippedSubviews={true}
contentInset={{top: headerOffset}}
contentOffset={{x: 0, y: headerOffset * -1}}
progressViewOffset={headerOffset}
/> />
)} )}
</View> </View>
@@ -122,7 +122,6 @@ export const Feed = observer(function Feed({
}) })
const styles = StyleSheet.create({ const styles = StyleSheet.create({
headerSpacer: {height: 42},
feedFooter: {paddingTop: 20}, feedFooter: {paddingTop: 20},
emptyState: {paddingVertical: 40}, emptyState: {paddingVertical: 40},
}) })
+10 -7
View File
@@ -15,6 +15,7 @@ import {useOnMainScroll} from '../lib/hooks/useOnMainScroll'
import {clamp} from 'lodash' import {clamp} from 'lodash'
import {useAnalytics} from '@segment/analytics-react-native' import {useAnalytics} from '@segment/analytics-react-native'
const HEADER_HEIGHT = 42
const HITSLOP = {left: 20, top: 20, right: 20, bottom: 20} const HITSLOP = {left: 20, top: 20, right: 20, bottom: 20}
export const Home = observer(function Home({navIdx, visible}: ScreenParams) { export const Home = observer(function Home({navIdx, visible}: ScreenParams) {
@@ -42,12 +43,14 @@ export const Home = observer(function Home({navIdx, visible}: ScreenParams) {
[appState, visible, store], [appState, visible, store],
) )
const onSoftReset = () => { const scrollToTop = React.useCallback(() => {
scrollElRef.current?.scrollToOffset({offset: 0}) // NOTE: the feed is offset by the height of the collapsing header,
} // so we scroll to the negative of that height -prf
scrollElRef.current?.scrollToOffset({offset: -HEADER_HEIGHT})
}, [scrollElRef])
useEffect(() => { useEffect(() => {
const softResetSub = store.onScreenSoftReset(onSoftReset) const softResetSub = store.onScreenSoftReset(scrollToTop)
const feedCleanup = store.me.mainFeed.registerListeners() const feedCleanup = store.me.mainFeed.registerListeners()
const pollInterval = setInterval(() => doPoll(), 15e3) const pollInterval = setInterval(() => doPoll(), 15e3)
const cleanup = () => { const cleanup = () => {
@@ -72,7 +75,7 @@ export const Home = observer(function Home({navIdx, visible}: ScreenParams) {
store.me.mainFeed.setup() store.me.mainFeed.setup()
} }
return cleanup return cleanup
}, [visible, store, store.me.mainFeed, navIdx, doPoll, wasVisible]) }, [visible, store, store.me.mainFeed, navIdx, doPoll, wasVisible, scrollToTop])
const onPressCompose = (imagesOpen?: boolean) => { const onPressCompose = (imagesOpen?: boolean) => {
track('Home:ComposeButtonPressed') track('Home:ComposeButtonPressed')
@@ -83,7 +86,7 @@ export const Home = observer(function Home({navIdx, visible}: ScreenParams) {
} }
const onPressLoadLatest = () => { const onPressLoadLatest = () => {
store.me.mainFeed.refresh() store.me.mainFeed.refresh()
scrollElRef?.current?.scrollToOffset({offset: 0}) scrollToTop()
} }
return ( return (
@@ -96,7 +99,7 @@ export const Home = observer(function Home({navIdx, visible}: ScreenParams) {
style={s.h100pct} style={s.h100pct}
onPressTryAgain={onPressTryAgain} onPressTryAgain={onPressTryAgain}
onScroll={onMainScroll} onScroll={onMainScroll}
headerSpacer headerOffset={HEADER_HEIGHT}
/> />
<ViewHeader title="Bluesky" canGoBack={false} hideOnScroll /> <ViewHeader title="Bluesky" canGoBack={false} hideOnScroll />
{store.me.mainFeed.hasNewLatest && !store.me.mainFeed.isRefreshing ? ( {store.me.mainFeed.hasNewLatest && !store.me.mainFeed.isRefreshing ? (