This commit is contained in:
Eric Bailey
2024-04-17 20:27:49 -05:00
parent 38ce57acf1
commit 6f35e50dbf
10 changed files with 91 additions and 80 deletions
@@ -5,7 +5,7 @@ import {useLingui} from '@lingui/react'
import {DialogOuterProps} from '#/components/Dialog' import {DialogOuterProps} from '#/components/Dialog'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
export function HomeAlgoNoticeDialog({ export function PrimaryAlgoNoticeDialog({
control, control,
}: { }: {
control: DialogOuterProps['control'] control: DialogOuterProps['control']
@@ -13,9 +13,9 @@ export function HomeAlgoNoticeDialog({
const {_} = useLingui() const {_} = useLingui()
return ( return (
<Prompt.Outer control={control}> <Prompt.Outer control={control}>
<Prompt.TitleText>Your home algorithm</Prompt.TitleText> <Prompt.TitleText>Your primary algorithm</Prompt.TitleText>
<Prompt.DescriptionText> <Prompt.DescriptionText>
This feed is set as your home algorithm, which is used as your home This feed is set as your primary algorithm, which is used as your home
screen when you open the app. screen when you open the app.
</Prompt.DescriptionText> </Prompt.DescriptionText>
<Prompt.Actions> <Prompt.Actions>
+17 -13
View File
@@ -238,13 +238,13 @@ const DISCOVER_FEED_STUB: FeedSourceInfo = {
likeCount: 0, likeCount: 0,
likeUri: '', likeUri: '',
} }
const HOME_ALGO_FEED_STUB: FeedSourceInfo = { const PRIMARY_ALGO_STUB: FeedSourceInfo = {
type: 'feed', type: 'feed',
displayName: 'Home', displayName: 'For You',
uri: 'home-algo', uri: 'primary-algo',
route: { route: {
href: '/', href: '/',
name: 'Home', name: 'For You',
params: {}, params: {},
}, },
cid: '', cid: '',
@@ -261,18 +261,18 @@ const pinnedFeedInfosQueryKeyRoot = 'pinnedFeedsInfos'
export function usePinnedFeedsInfos() { export function usePinnedFeedsInfos() {
const {hasSession} = useSession() const {hasSession} = useSession()
const {data: preferences, isLoading: isLoadingPrefs} = usePreferencesQuery() const {data: preferences, isLoading: isLoadingPrefs} = usePreferencesQuery()
const isHomeAlgoExperimentEnabled = useGate( const isPrimaryAlgoExperimentEnabled = useGate(
'reduced_onboarding_and_home_algo', 'reduced_onboarding_and_home_algo',
) )
const pinnedUris = (preferences?.feeds?.pinned ?? []).filter(f => { const pinnedUris = (preferences?.feeds?.pinned ?? []).filter(f => {
if ( if (
isHomeAlgoExperimentEnabled && isPrimaryAlgoExperimentEnabled &&
hasSession && hasSession &&
preferences?.homeAlgo && preferences?.primaryAlgorithm &&
preferences?.homeAlgo?.enabled preferences?.primaryAlgorithm?.enabled
) { ) {
// remove duplicate feed // remove duplicate feed
return f !== preferences?.homeAlgo.uri return f !== preferences?.primaryAlgorithm.uri
} }
return true return true
}) })
@@ -323,11 +323,15 @@ export function usePinnedFeedsInfos() {
// The returned result will have the original order. // The returned result will have the original order.
let result = [hasSession ? HOME_FEED_STUB : DISCOVER_FEED_STUB] let result = [hasSession ? HOME_FEED_STUB : DISCOVER_FEED_STUB]
if (isHomeAlgoExperimentEnabled && hasSession && preferences?.homeAlgo) { if (
const {enabled, uri} = preferences.homeAlgo isPrimaryAlgoExperimentEnabled &&
// ONLY add the home algo if we have a URI set hasSession &&
preferences?.primaryAlgorithm
) {
const {enabled, uri} = preferences.primaryAlgorithm
// ONLY add the primary algo if we have a URI set
if (enabled && uri) { if (enabled && uri) {
result = [HOME_ALGO_FEED_STUB, HOME_FEED_STUB] result = [PRIMARY_ALGO_STUB, HOME_FEED_STUB]
} }
} }
+1 -1
View File
@@ -44,7 +44,7 @@ type AuthorFilter =
type FeedUri = string type FeedUri = string
type ListUri = string type ListUri = string
export type FeedDescriptor = export type FeedDescriptor =
| 'home-algo' | 'primary-algo'
| 'home' | 'home'
| 'following' | 'following'
| `author|${ActorDid}|${AuthorFilter}` | `author|${ActorDid}|${AuthorFilter}`
+1 -1
View File
@@ -45,5 +45,5 @@ export const DEFAULT_LOGGED_OUT_PREFERENCES: UsePreferencesQueryResponse = {
threadViewPrefs: DEFAULT_THREAD_VIEW_PREFS, threadViewPrefs: DEFAULT_THREAD_VIEW_PREFS,
userAge: 13, // TODO(pwi) userAge: 13, // TODO(pwi)
interests: {tags: []}, interests: {tags: []},
homeAlgo: {enabled: undefined}, primaryAlgorithm: {enabled: undefined},
} }
+3 -4
View File
@@ -3,7 +3,6 @@ import {
AppBskyActorDefs, AppBskyActorDefs,
BSKY_LABELER_DID, BSKY_LABELER_DID,
BskyFeedViewPreference, BskyFeedViewPreference,
BskyHomeAlgoPreference,
LabelPreference, LabelPreference,
ModerationOpts, ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
@@ -347,12 +346,12 @@ export function useRemoveMutedWordMutation() {
}) })
} }
export function useSetHomeAlgoMutation() { export function useSetPrimaryAlgorithmMutation() {
const queryClient = useQueryClient() const queryClient = useQueryClient()
return useMutation({ return useMutation({
mutationFn: async (pref: BskyHomeAlgoPreference) => { mutationFn: async (pref: AppBskyActorDefs.PrimaryAlgoPref) => {
await getAgent().setHomeAlgoPref(pref) await getAgent().setPrimaryAlgorithm(pref)
// triggers a refetch // triggers a refetch
await queryClient.invalidateQueries({ await queryClient.invalidateQueries({
queryKey: preferencesQueryKey, queryKey: preferencesQueryKey,
+14 -12
View File
@@ -25,8 +25,8 @@ import * as Toast from 'view/com/util/Toast'
import {useTheme} from '#/alf' import {useTheme} from '#/alf'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {HomeAlgoNoticeDialog} from '#/components/HomeAlgoNoticeDialog'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {PrimaryAlgoNoticeDialog} from '#/components/PrimaryAlgoNoticeDialog'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import {RichText} from '#/components/RichText' import {RichText} from '#/components/RichText'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
@@ -93,10 +93,10 @@ export function FeedSourceCardLoaded({
const {_} = useLingui() const {_} = useLingui()
const removePromptControl = Prompt.usePromptControl() const removePromptControl = Prompt.usePromptControl()
const navigation = useNavigationDeduped() const navigation = useNavigationDeduped()
const isHomeAlgoExperimentEnabled = useGate( const isPrimaryAlgoExperimentEnabled = useGate(
'reduced_onboarding_and_home_algo', 'reduced_onboarding_and_home_algo',
) )
const homeAlgoDialogControl = Prompt.usePromptControl() const primaryAlgoDialogControl = Prompt.usePromptControl()
const {isPending: isSavePending, mutateAsync: saveFeed} = const {isPending: isSavePending, mutateAsync: saveFeed} =
useSaveFeedMutation() useSaveFeedMutation()
@@ -196,10 +196,10 @@ export function FeedSourceCardLoaded({
) )
const showFeedSaveButton = showSaveBtn && feed.type === 'feed' const showFeedSaveButton = showSaveBtn && feed.type === 'feed'
const isHomeAlgo = const isPrimaryAlgo =
preferences.homeAlgo?.enabled && preferences.primaryAlgorithm?.enabled &&
preferences.homeAlgo?.uri && preferences.primaryAlgorithm?.uri &&
preferences.homeAlgo.uri === feed.uri preferences.primaryAlgorithm.uri === feed.uri
return ( return (
<> <>
@@ -239,17 +239,19 @@ export function FeedSourceCardLoaded({
</View> </View>
{showFeedSaveButton && {showFeedSaveButton &&
(isHomeAlgoExperimentEnabled && isHomeAlgo ? ( (isPrimaryAlgoExperimentEnabled && isPrimaryAlgo ? (
<Button <Button
variant="solid" variant="solid"
color="secondary" color="secondary"
size="small" size="small"
label={_(msg`This feed is already set as your home algorithm.`)} label={_(
msg`This feed is already set as your primary algorithm.`,
)}
onPress={() => { onPress={() => {
homeAlgoDialogControl.open() primaryAlgoDialogControl.open()
}}> }}>
<ButtonIcon icon={Check} position="left" /> <ButtonIcon icon={Check} position="left" />
<ButtonText>Home Algo</ButtonText> <ButtonText>Primary Algorithm</ButtonText>
</Button> </Button>
) : ( ) : (
<View style={[s.justifyCenter]}> <View style={[s.justifyCenter]}>
@@ -313,7 +315,7 @@ export function FeedSourceCardLoaded({
confirmButtonColor="negative" confirmButtonColor="negative"
/> />
<HomeAlgoNoticeDialog control={homeAlgoDialogControl} /> <PrimaryAlgoNoticeDialog control={primaryAlgoDialogControl} />
</> </>
) )
} }
+1 -1
View File
@@ -25,7 +25,7 @@ export function HomeHeader(
const hasPinnedCustom = React.useMemo<boolean>(() => { const hasPinnedCustom = React.useMemo<boolean>(() => {
if (!hasSession) return false if (!hasSession) return false
return feeds.some( return feeds.some(
tab => !['home', 'home-algo', 'following'].includes(tab.uri), tab => !['home', 'primary-algo', 'following'].includes(tab.uri),
) )
}, [feeds, hasSession]) }, [feeds, hasSession])
+14 -10
View File
@@ -54,7 +54,7 @@ function HomeScreenReady({
pinnedFeedInfos: FeedSourceInfo[] pinnedFeedInfos: FeedSourceInfo[]
}) { }) {
useOTAUpdates() useOTAUpdates()
const isHomeAlgoExperimentEnabled = useGate( const isPrimaryAlgoExperimentEnabled = useGate(
'reduced_onboarding_and_home_algo', 'reduced_onboarding_and_home_algo',
) )
@@ -65,18 +65,18 @@ function HomeScreenReady({
feeds.push(`feedgen|${uri}`) feeds.push(`feedgen|${uri}`)
} else if (uri.includes('app.bsky.graph.list')) { } else if (uri.includes('app.bsky.graph.list')) {
feeds.push(`list|${uri}`) feeds.push(`list|${uri}`)
} else if (uri === 'home-algo') { } else if (uri === 'primary-algo') {
if ( if (
isHomeAlgoExperimentEnabled && isPrimaryAlgoExperimentEnabled &&
preferences.homeAlgo.enabled && preferences.primaryAlgorithm.enabled &&
preferences.homeAlgo.uri preferences.primaryAlgorithm.uri
) { ) {
feeds.push(`feedgen|${preferences.homeAlgo.uri}`) feeds.push(`feedgen|${preferences.primaryAlgorithm.uri}`)
} else { } else {
// should never happen - esb // should never happen - esb
logger.error(`home-algo feed expected, but no URI found`, { logger.error(`primary-algo feed expected, but no URI found`, {
isHomeAlgoExperimentEnabled, isPrimaryAlgoExperimentEnabled,
homeAlgo: preferences.homeAlgo, primaryAlgorithm: preferences.primaryAlgorithm,
}) })
feeds.push(`feedgen|${DISCOVER_FEED_URI}`) feeds.push(`feedgen|${DISCOVER_FEED_URI}`)
} }
@@ -87,7 +87,11 @@ function HomeScreenReady({
} }
} }
return feeds return feeds
}, [pinnedFeedInfos, isHomeAlgoExperimentEnabled, preferences.homeAlgo]) }, [
pinnedFeedInfos,
isPrimaryAlgoExperimentEnabled,
preferences.primaryAlgorithm,
])
const rawSelectedFeed = useSelectedFeed() const rawSelectedFeed = useSelectedFeed()
const setSelectedFeed = useSetSelectedFeed() const setSelectedFeed = useSetSelectedFeed()
+35 -33
View File
@@ -21,7 +21,7 @@ import {
UsePreferencesQueryResponse, UsePreferencesQueryResponse,
useRemoveFeedMutation, useRemoveFeedMutation,
useSaveFeedMutation, useSaveFeedMutation,
useSetHomeAlgoMutation, useSetPrimaryAlgorithmMutation,
useUnpinFeedMutation, useUnpinFeedMutation,
} from '#/state/queries/preferences' } from '#/state/queries/preferences'
import {useResolveUriQuery} from '#/state/queries/resolve-uri' import {useResolveUriQuery} from '#/state/queries/resolve-uri'
@@ -56,7 +56,6 @@ import {CenteredView} from 'view/com/util/Views'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button as NewButton, ButtonIcon, ButtonText} from '#/components/Button' import {Button as NewButton, ButtonIcon, ButtonText} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {HomeAlgoNoticeDialog} from '#/components/HomeAlgoNoticeDialog'
import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox' import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox'
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo'
@@ -70,6 +69,7 @@ import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import * as Menu from '#/components/Menu' import * as Menu from '#/components/Menu'
import {PrimaryAlgoNoticeDialog} from '#/components/PrimaryAlgoNoticeDialog'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
import {RichText} from '#/components/RichText' import {RichText} from '#/components/RichText'
@@ -168,10 +168,10 @@ export function ProfileFeedScreenInner({
const playHaptic = useHaptics() const playHaptic = useHaptics()
const feedSectionRef = React.useRef<SectionRef>(null) const feedSectionRef = React.useRef<SectionRef>(null)
const isScreenFocused = useIsFocused() const isScreenFocused = useIsFocused()
const isHomeAlgoExperimentEnabled = useGate( const isPrimaryAlgoExperimentEnabled = useGate(
'reduced_onboarding_and_home_algo', 'reduced_onboarding_and_home_algo',
) )
const homeAlgoDialogControl = useDialogControl() const primaryAlgoDialogControl = useDialogControl()
const { const {
mutateAsync: saveFeed, mutateAsync: saveFeed,
@@ -198,10 +198,10 @@ export function ProfileFeedScreenInner({
isPending: isUnpinPending, isPending: isUnpinPending,
} = useUnpinFeedMutation() } = useUnpinFeedMutation()
const { const {
mutateAsync: setHomeAlgo, mutateAsync: setPrimaryAlgo,
variables: homeAlgoVariables, variables: primaryAlgoVariables,
isPending: isSetHomeAlgoPending, isPending: isSetPrimaryAlgoPending,
} = useSetHomeAlgoMutation() } = useSetPrimaryAlgorithmMutation()
const isSaved = const isSaved =
!removedFeed && !removedFeed &&
@@ -209,11 +209,11 @@ export function ProfileFeedScreenInner({
const isPinned = const isPinned =
!unpinnedFeed && !unpinnedFeed &&
(!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri)) (!!pinnedFeed || preferences.feeds.pinned.includes(feedInfo.uri))
const isHomeAlgo = const isPrimaryAlgo =
(preferences.homeAlgo?.enabled && (preferences.primaryAlgorithm?.enabled &&
preferences.homeAlgo?.uri && preferences.primaryAlgorithm?.uri &&
preferences.homeAlgo.uri === feedInfo.uri) || preferences.primaryAlgorithm.uri === feedInfo.uri) ||
(homeAlgoVariables?.enabled && homeAlgoVariables.uri === feedInfo.uri) (primaryAlgoVariables?.enabled && primaryAlgoVariables.uri === feedInfo.uri)
useSetTitle(feedInfo?.displayName) useSetTitle(feedInfo?.displayName)
@@ -278,15 +278,17 @@ export function ProfileFeedScreenInner({
_, _,
]) ])
const onSetHomeAlgo = React.useCallback(async () => { const onSetPrimaryAlgo = React.useCallback(async () => {
try { try {
playHaptic() playHaptic()
await setHomeAlgo({enabled: true, uri: feedInfo.uri}) await setPrimaryAlgo({enabled: true, uri: feedInfo.uri})
} catch (e: any) { } catch (e: any) {
Toast.show(_(msg`There was an issue contacting the server`)) Toast.show(_(msg`There was an issue contacting the server`))
logger.error('ProfileFeed: failed to set home algo', {message: e.message}) logger.error('ProfileFeed: failed to set primary algo', {
message: e.message,
})
} }
}, [setHomeAlgo, feedInfo, _, playHaptic]) }, [setPrimaryAlgo, feedInfo, _, playHaptic])
const onPressShare = React.useCallback(() => { const onPressShare = React.useCallback(() => {
const url = toShareUrl(feedInfo.route.href) const url = toShareUrl(feedInfo.route.href)
@@ -325,19 +327,19 @@ export function ProfileFeedScreenInner({
<View style={[a.flex_row, a.align_center, a.gap_sm]}> <View style={[a.flex_row, a.align_center, a.gap_sm]}>
{feedInfo && {feedInfo &&
hasSession && hasSession &&
(isHomeAlgoExperimentEnabled && isHomeAlgo ? ( (isPrimaryAlgoExperimentEnabled && isPrimaryAlgo ? (
<NewButton <NewButton
variant="solid" variant="solid"
color="secondary" color="secondary"
size="small" size="small"
label={_( label={_(
msg`This feed is already set as your home algorithm.`, msg`This feed is already set as your primary algorithm.`,
)} )}
onPress={() => { onPress={() => {
homeAlgoDialogControl.open() primaryAlgoDialogControl.open()
}}> }}>
<ButtonIcon icon={Check} position="left" /> <ButtonIcon icon={Check} position="left" />
<ButtonText>Home Algo</ButtonText> <ButtonText>Primary Algorithm</ButtonText>
</NewButton> </NewButton>
) : ( ) : (
<NewButton <NewButton
@@ -386,7 +388,7 @@ export function ProfileFeedScreenInner({
<Menu.Group> <Menu.Group>
{hasSession && ( {hasSession && (
<> <>
{!isHomeAlgo && ( {!isPrimaryAlgo && (
<> <>
<Menu.Item <Menu.Item
disabled={isSavePending || isRemovePending} disabled={isSavePending || isRemovePending}
@@ -409,12 +411,12 @@ export function ProfileFeedScreenInner({
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item
disabled={isSetHomeAlgoPending} disabled={isSetPrimaryAlgoPending}
testID="feedHeaderDropdownSetHomeAlgoBtn" testID="feedHeaderDropdownSetPrimaryAlgoBtn"
label={_(msg`Set as home algorithm`)} label={_(msg`Set as primary algorithm`)}
onPress={onSetHomeAlgo}> onPress={onSetPrimaryAlgo}>
<Menu.ItemText> <Menu.ItemText>
{_(msg`Set as home algorithm`)} {_(msg`Set as primary algorithm`)}
</Menu.ItemText> </Menu.ItemText>
<Menu.ItemIcon icon={Home} position="right" /> <Menu.ItemIcon icon={Home} position="right" />
</Menu.Item> </Menu.Item>
@@ -449,7 +451,7 @@ export function ProfileFeedScreenInner({
feedInfo={feedInfo} feedInfo={feedInfo}
/> />
<HomeAlgoNoticeDialog control={homeAlgoDialogControl} /> <PrimaryAlgoNoticeDialog control={primaryAlgoDialogControl} />
</> </>
) )
}, [ }, [
@@ -468,11 +470,11 @@ export function ProfileFeedScreenInner({
onPressReport, onPressReport,
onPressShare, onPressShare,
t, t,
isHomeAlgoExperimentEnabled, isPrimaryAlgoExperimentEnabled,
isHomeAlgo, isPrimaryAlgo,
homeAlgoDialogControl, primaryAlgoDialogControl,
onSetHomeAlgo, onSetPrimaryAlgo,
isSetHomeAlgoPending, isSetPrimaryAlgoPending,
]) ])
return ( return (
+2 -2
View File
@@ -36,8 +36,8 @@ export function DesktopFeeds() {
let feed: FeedDescriptor let feed: FeedDescriptor
if (uri === 'home') { if (uri === 'home') {
feed = 'home' feed = 'home'
} else if (uri === 'home-algo') { } else if (uri === 'primary-algo') {
feed = 'home-algo' feed = 'primary-algo'
} else if (uri.includes('app.bsky.feed.generator')) { } else if (uri.includes('app.bsky.feed.generator')) {
feed = `feedgen|${uri}` feed = `feedgen|${uri}`
} else if (uri.includes('app.bsky.graph.list')) { } else if (uri.includes('app.bsky.graph.list')) {