PWI improvements (#3489)

* Enable home and feeds on the PWI

* Add global SigninDialog to drive useRequireAuth()

* Tweak desktop styles

* Make the logo in leftnav PWI a clickable home link

* Add label

* Improve dialog on web

* Fix query key

* Go to home after signout from settings screen

* Filter out feeds from the discover listing for logged out users which are known to break without auth

* Update profile header follow/subscribe to give signin prompt

* Show profile feeds tabs on pwi

* Add language selector to account creation footer and pwi left nav desktop

---------

Co-authored-by: dan <dan.abramov@gmail.com>
This commit is contained in:
Paul Frazee 2024-04-12 14:13:13 -07:00 committed by GitHub
parent 44039c68d6
commit ec5c4929c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 519 additions and 478 deletions

View file

@ -1,52 +1,53 @@
import React from 'react'
import {
ActivityIndicator,
StyleSheet,
View,
type FlatList,
Pressable,
StyleSheet,
View,
} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {FontAwesomeIconStyle} from '@fortawesome/react-native-fontawesome'
import {ViewHeader} from 'view/com/util/ViewHeader'
import {FAB} from 'view/com/util/fab/FAB'
import {Link} from 'view/com/util/Link'
import {NativeStackScreenProps, FeedsTabNavigatorParams} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons'
import {s} from 'lib/styles'
import {atoms as a, useTheme} from '#/alf'
import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
import {UserAvatar} from 'view/com/util/UserAvatar'
import {
LoadingPlaceholder,
FeedFeedLoadingPlaceholder,
} from 'view/com/util/LoadingPlaceholder'
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
import debounce from 'lodash.debounce'
import {Text} from 'view/com/util/text/Text'
import {List} from 'view/com/util/List'
import {useFocusEffect} from '@react-navigation/native'
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
import {Trans, msg} from '@lingui/macro'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useSetMinimalShellMode} from '#/state/shell'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {useFocusEffect} from '@react-navigation/native'
import debounce from 'lodash.debounce'
import {isNative, isWeb} from '#/platform/detection'
import {
getAvatarTypeFromUri,
useFeedSourceInfoQuery,
useGetPopularFeedsQuery,
useSearchPopularFeedsMutation,
getAvatarTypeFromUri,
} from '#/state/queries/feed'
import {cleanError} from 'lib/strings/errors'
import {useComposerControls} from '#/state/shell/composer'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {useSession} from '#/state/session'
import {isNative, isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell'
import {useComposerControls} from '#/state/shell/composer'
import {HITSLOP_10} from 'lib/constants'
import {usePalette} from 'lib/hooks/usePalette'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {CogIcon, ComposeIcon2, MagnifyingGlassIcon2} from 'lib/icons'
import {FeedsTabNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {cleanError} from 'lib/strings/errors'
import {s} from 'lib/styles'
import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard'
import {ErrorMessage} from 'view/com/util/error/ErrorMessage'
import {FAB} from 'view/com/util/fab/FAB'
import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
import {Link} from 'view/com/util/Link'
import {List} from 'view/com/util/List'
import {
FeedFeedLoadingPlaceholder,
LoadingPlaceholder,
} from 'view/com/util/LoadingPlaceholder'
import {Text} from 'view/com/util/text/Text'
import {UserAvatar} from 'view/com/util/UserAvatar'
import {ViewHeader} from 'view/com/util/ViewHeader'
import {atoms as a, useTheme} from '#/alf'
import {IconCircle} from '#/components/IconCircle'
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
@ -100,6 +101,22 @@ type FlatlistSlice =
key: string
}
// HACK
// the protocol doesn't yet tell us which feeds are personalized
// this list is used to filter out feed recommendations from logged out users
// for the ones we know need it
// -prf
const KNOWN_AUTHED_ONLY_FEEDS = [
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/with-friends', // popular with friends, by bsky.app
'at://did:plc:tenurhgjptubkk5zf5qhi3og/app.bsky.feed.generator/mutuals', // mutuals, by skyfeed
'at://did:plc:tenurhgjptubkk5zf5qhi3og/app.bsky.feed.generator/only-posts', // only posts, by skyfeed
'at://did:plc:wzsilnxf24ehtmmc3gssy5bu/app.bsky.feed.generator/mentions', // mentions, by flicknow
'at://did:plc:q6gjnaw2blty4crticxkmujt/app.bsky.feed.generator/bangers', // my bangers, by jaz
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/mutuals', // mutuals, by bluesky
'at://did:plc:q6gjnaw2blty4crticxkmujt/app.bsky.feed.generator/my-followers', // followers, by jaz
'at://did:plc:vpkhqolt662uhesyj6nxm7ys/app.bsky.feed.generator/followpics', // the gram, by why
]
export function FeedsScreen(_props: Props) {
const pal = usePalette('default')
const {openComposer} = useComposerControls()
@ -299,7 +316,15 @@ export function FeedsScreen(_props: Props) {
for (const page of popularFeeds.pages || []) {
slices = slices.concat(
page.feeds
.filter(feed => !preferences?.feeds?.saved.includes(feed.uri))
.filter(feed => {
if (
!hasSession &&
KNOWN_AUTHED_ONLY_FEEDS.includes(feed.uri)
) {
return false
}
return !preferences?.feeds?.saved.includes(feed.uri)
})
.map(feed => ({
key: `popularFeed:${feed.uri}`,
type: 'popularFeed',

View file

@ -2,6 +2,7 @@ import React from 'react'
import {ActivityIndicator, AppState, StyleSheet, View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
import {PROD_DEFAULT_FEED} from '#/lib/constants'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
import {useSetTitle} from '#/lib/hooks/useSetTitle'
import {logEvent, LogEvents, useGate} from '#/lib/statsig/statsig'
@ -19,7 +20,6 @@ import {Pager, PagerRef, RenderTabBarFnProps} from 'view/com/pager/Pager'
import {CustomFeedEmptyState} from 'view/com/posts/CustomFeedEmptyState'
import {FollowingEmptyState} from 'view/com/posts/FollowingEmptyState'
import {FollowingEndOfFeed} from 'view/com/posts/FollowingEndOfFeed'
import {HomeLoggedOutCTA} from '../com/auth/HomeLoggedOutCTA'
import {HomeHeader} from '../com/home/HomeHeader'
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home'>
@ -231,7 +231,12 @@ function HomeScreenReady({
onPageSelected={onPageSelected}
onPageScrollStateChanged={onPageScrollStateChanged}
renderTabBar={renderTabBar}>
<HomeLoggedOutCTA />
<FeedPage
testID="customFeedPage"
isPageFocused
feed={`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`}
renderEmptyState={renderCustomFeedEmptyState}
/>
</Pager>
)
}

View file

@ -184,8 +184,7 @@ function ProfileScreenLoaded({
const showRepliesTab = hasSession
const showMediaTab = !hasLabeler
const showLikesTab = isMe
const showFeedsTab =
hasSession && (isMe || (profile.associated?.feedgens || 0) > 0)
const showFeedsTab = isMe || (profile.associated?.feedgens || 0) > 0
const showListsTab =
hasSession && (isMe || (profile.associated?.lists || 0) > 0)

View file

@ -71,6 +71,7 @@ import {UserAvatar} from 'view/com/util/UserAvatar'
import {ScrollView} from 'view/com/util/Views'
import {useDialogControl} from '#/components/Dialog'
import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
import {navigate, resetToTab} from '#/Navigation'
import {ExportCarDialog} from './ExportCarDialog'
function SettingsAccountCard({account}: {account: SessionAccount}) {
@ -104,7 +105,14 @@ function SettingsAccountCard({account}: {account: SessionAccount}) {
<TouchableOpacity
testID="signOutBtn"
onPress={() => {
logout('Settings')
if (isNative) {
logout('Settings')
resetToTab('HomeTab')
} else {
navigate('Home').then(() => {
logout('Settings')
})
}
}}
accessibilityRole="button"
accessibilityLabel={_(msg`Sign out`)}