Handle no pinned feeds
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import {Insets, Platform} from 'react-native'
|
import {Insets, Platform} from 'react-native'
|
||||||
|
import {AppBskyActorDefs} from '@atproto/api'
|
||||||
|
import {TID} from '@atproto/common-web'
|
||||||
|
|
||||||
export const LOCAL_DEV_SERVICE =
|
export const LOCAL_DEV_SERVICE =
|
||||||
Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583'
|
Platform.OS === 'android' ? 'http://10.0.2.2:2583' : 'http://localhost:2583'
|
||||||
@@ -92,3 +94,18 @@ export const BSKY_FEED_OWNER_DIDS = [
|
|||||||
|
|
||||||
export const DISCOVER_FEED_URI =
|
export const DISCOVER_FEED_URI =
|
||||||
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot'
|
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot'
|
||||||
|
|
||||||
|
export const RECOMMENDED_SAVED_FEEDS: AppBskyActorDefs.SavedFeed[] = [
|
||||||
|
{
|
||||||
|
id: TID.nextStr(),
|
||||||
|
type: 'feed',
|
||||||
|
value: DISCOVER_FEED_URI,
|
||||||
|
pinned: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: TID.nextStr(),
|
||||||
|
type: 'timeline',
|
||||||
|
value: 'home',
|
||||||
|
pinned: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {useWindowDimensions, View} from 'react-native'
|
||||||
|
import {msg, Trans} from '@lingui/macro'
|
||||||
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {RECOMMENDED_SAVED_FEEDS} from '#/lib/constants'
|
||||||
|
import {useSetSaveFeedsMutation} from '#/state/queries/preferences'
|
||||||
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
|
import {CenteredView} from '#/view/com/util/Views'
|
||||||
|
import {atoms as a} from '#/alf'
|
||||||
|
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||||
|
import {ListSparkle_Stroke2_Corner0_Rounded as ListSparkle} from '#/components/icons/ListSparkle'
|
||||||
|
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||||
|
import {Link} from '#/components/Link'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
|
export function useHeaderOffset() {
|
||||||
|
const {isDesktop, isTablet} = useWebMediaQueries()
|
||||||
|
const {fontScale} = useWindowDimensions()
|
||||||
|
if (isDesktop || isTablet) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
const navBarHeight = 42
|
||||||
|
const tabBarPad = 10 + 10 + 3 // padding + border
|
||||||
|
const normalLineHeight = 1.2
|
||||||
|
const tabBarText = 16 * normalLineHeight * fontScale
|
||||||
|
return navBarHeight + tabBarPad + tabBarText
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NoFeedsPinned() {
|
||||||
|
const {_} = useLingui()
|
||||||
|
const headerOffset = useHeaderOffset()
|
||||||
|
const {isPending, mutateAsync: setSavedFeeds} = useSetSaveFeedsMutation()
|
||||||
|
|
||||||
|
const addRecommendedFeeds = React.useCallback(async () => {
|
||||||
|
await setSavedFeeds(RECOMMENDED_SAVED_FEEDS)
|
||||||
|
}, [setSavedFeeds])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CenteredView sideBorders style={[a.h_full_vh]}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.align_center,
|
||||||
|
a.h_full_vh,
|
||||||
|
a.py_3xl,
|
||||||
|
a.px_xl,
|
||||||
|
{
|
||||||
|
paddingTop: headerOffset + a.py_3xl.paddingTop,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<View style={[a.align_center, a.gap_sm, a.pb_xl]}>
|
||||||
|
<Text style={[a.text_xl, a.font_bold]}>
|
||||||
|
<Trans>Whoops!</Trans>
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
style={[a.text_md, a.text_center, a.leading_snug, {maxWidth: 340}]}>
|
||||||
|
<Trans>
|
||||||
|
Looks like you unpinned all your feeds. But don't worry, you can
|
||||||
|
add some below 😄
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={[a.flex_row, a.gap_md, a.justify_center, a.flex_wrap]}>
|
||||||
|
<Button
|
||||||
|
disabled={isPending}
|
||||||
|
label={_(msg`Apply default recommended feeds`)}
|
||||||
|
size="medium"
|
||||||
|
variant="solid"
|
||||||
|
color="primary"
|
||||||
|
onPress={addRecommendedFeeds}>
|
||||||
|
<ButtonIcon icon={Plus} position="left" />
|
||||||
|
<ButtonText>{_(msg`Add recommended feeds`)}</ButtonText>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
label={_(msg`Browse other feeds`)}
|
||||||
|
to="/feeds"
|
||||||
|
size="medium"
|
||||||
|
variant="solid"
|
||||||
|
color="secondary">
|
||||||
|
<ButtonIcon icon={ListSparkle} position="left" />
|
||||||
|
<ButtonText>{_(msg`Browse other feeds`)}</ButtonText>
|
||||||
|
</Link>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</CenteredView>
|
||||||
|
)
|
||||||
|
}
|
||||||
+43
-33
@@ -21,6 +21,7 @@ import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
|
|||||||
import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
|
import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
|
||||||
import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
|
import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
|
||||||
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
|
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
|
||||||
|
import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
|
||||||
import {HomeHeader} from '../com/home/HomeHeader'
|
import {HomeHeader} from '../com/home/HomeHeader'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
|
||||||
@@ -110,12 +111,14 @@ function HomeScreenReady({
|
|||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useNonReactiveCallback(() => {
|
useNonReactiveCallback(() => {
|
||||||
logEvent('home:feedDisplayed', {
|
if (selectedFeed) {
|
||||||
index: selectedIndex,
|
logEvent('home:feedDisplayed', {
|
||||||
feedType: selectedFeed.split('|')[0],
|
index: selectedIndex,
|
||||||
feedUrl: selectedFeed,
|
feedType: selectedFeed.split('|')[0],
|
||||||
reason: 'focus',
|
feedUrl: selectedFeed,
|
||||||
})
|
reason: 'focus',
|
||||||
|
})
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -147,12 +150,15 @@ function HomeScreenReady({
|
|||||||
const onPageSelecting = React.useCallback(
|
const onPageSelecting = React.useCallback(
|
||||||
(index: number, reason: LogEvents['home:feedDisplayed']['reason']) => {
|
(index: number, reason: LogEvents['home:feedDisplayed']['reason']) => {
|
||||||
const feed = allFeeds[index]
|
const feed = allFeeds[index]
|
||||||
logEvent('home:feedDisplayed', {
|
|
||||||
index,
|
if (feed) {
|
||||||
feedType: feed.split('|')[0],
|
logEvent('home:feedDisplayed', {
|
||||||
feedUrl: feed,
|
index,
|
||||||
reason,
|
feedType: feed.split('|')[0],
|
||||||
})
|
feedUrl: feed,
|
||||||
|
reason,
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[allFeeds],
|
[allFeeds],
|
||||||
)
|
)
|
||||||
@@ -212,35 +218,39 @@ function HomeScreenReady({
|
|||||||
onPageSelected={onPageSelected}
|
onPageSelected={onPageSelected}
|
||||||
onPageScrollStateChanged={onPageScrollStateChanged}
|
onPageScrollStateChanged={onPageScrollStateChanged}
|
||||||
renderTabBar={renderTabBar}>
|
renderTabBar={renderTabBar}>
|
||||||
{allFeeds.map(feed => {
|
{allFeeds.length ? (
|
||||||
if (feed === 'home' || feed === 'following') {
|
allFeeds.map(feed => {
|
||||||
|
if (feed === 'home' || feed === 'following') {
|
||||||
|
return (
|
||||||
|
<FeedPage
|
||||||
|
key={feed}
|
||||||
|
testID="followingFeedPage"
|
||||||
|
isPageFocused={selectedFeed === feed}
|
||||||
|
feed={feed}
|
||||||
|
feedParams={homeFeedParams}
|
||||||
|
renderEmptyState={renderFollowingEmptyState}
|
||||||
|
renderEndOfFeed={FollowingEndOfFeed}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const savedFeedConfig = preferences.savedFeeds.find(f => {
|
||||||
|
return feed.includes(f.value)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FeedPage
|
<FeedPage
|
||||||
key={feed}
|
key={feed}
|
||||||
testID="followingFeedPage"
|
testID="customFeedPage"
|
||||||
isPageFocused={selectedFeed === feed}
|
isPageFocused={selectedFeed === feed}
|
||||||
feed={feed}
|
feed={feed}
|
||||||
feedParams={homeFeedParams}
|
renderEmptyState={renderCustomFeedEmptyState}
|
||||||
renderEmptyState={renderFollowingEmptyState}
|
savedFeedConfig={savedFeedConfig}
|
||||||
renderEndOfFeed={FollowingEndOfFeed}
|
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
const savedFeedConfig = preferences.savedFeeds.find(f => {
|
|
||||||
return feed.includes(f.value)
|
|
||||||
})
|
})
|
||||||
|
) : (
|
||||||
return (
|
<NoFeedsPinned />
|
||||||
<FeedPage
|
)}
|
||||||
key={feed}
|
|
||||||
testID="customFeedPage"
|
|
||||||
isPageFocused={selectedFeed === feed}
|
|
||||||
feed={feed}
|
|
||||||
renderEmptyState={renderCustomFeedEmptyState}
|
|
||||||
savedFeedConfig={savedFeedConfig}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
|
||||||
</Pager>
|
</Pager>
|
||||||
) : (
|
) : (
|
||||||
<Pager
|
<Pager
|
||||||
|
|||||||
Reference in New Issue
Block a user