Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[topics] use a screen for topics rather than search screen #7148

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
6bd0a91
Add WIP UIs for trending topics and suggested starterpacks
pfrazee Dec 4, 2024
a74b42f
Disable SPs for now
estrattonbailey Dec 11, 2024
73aaeb2
Improve explore treatment a bit, add some polish to cards
estrattonbailey Dec 11, 2024
ec32c53
Add tiny option in RightNav
estrattonbailey Dec 11, 2024
48fb1f4
Add persisted option to hide trending from sidebar
estrattonbailey Dec 11, 2024
b4bad89
Add to settings, abstract state, not updating in tab
estrattonbailey Dec 12, 2024
8372e58
Fix up hide/show toggle state, WITH broadcast hacK
estrattonbailey Dec 12, 2024
ea7b710
Clean up persisted code, add new setting
estrattonbailey Dec 12, 2024
e3574a0
Add new interstitial to Discover
estrattonbailey Dec 12, 2024
6f23591
Exploration
estrattonbailey Dec 13, 2024
04fae9a
First hack at mute words
estrattonbailey Dec 13, 2024
682dc44
Wire up interstitial and Explore page
estrattonbailey Dec 16, 2024
a59802a
Align components
estrattonbailey Dec 16, 2024
0643233
Some skeleton UI
estrattonbailey Dec 16, 2024
64e47cc
Handle service config, enablement, load states, update lex contract
estrattonbailey Dec 16, 2024
3ef6134
Centralize mute word handling
estrattonbailey Dec 16, 2024
409809a
Stale time to 30m
estrattonbailey Dec 16, 2024
6437e7b
Cache enabled value for reloads, use real data for service config
estrattonbailey Dec 16, 2024
e0ab37d
Remove broadcast hack
estrattonbailey Dec 16, 2024
2dc2443
Remove titleChild
estrattonbailey Dec 16, 2024
e182e75
Gate settings too
estrattonbailey Dec 16, 2024
8934aa1
Update package, rm langs
estrattonbailey Dec 17, 2024
a706918
Add feature gate
estrattonbailey Dec 17, 2024
8725185
Only english during beta period
estrattonbailey Dec 17, 2024
8a5fbff
Hook up real data
estrattonbailey Dec 17, 2024
1af1760
Tweak config
estrattonbailey Dec 17, 2024
4863e60
Straight passthrough links
estrattonbailey Dec 17, 2024
b534e6c
Hook up prod agent
estrattonbailey Dec 17, 2024
37a4afb
Fix no-show logic
estrattonbailey Dec 17, 2024
e84953d
Up config query to 5 min
estrattonbailey Dec 17, 2024
120b66e
Remove old file
estrattonbailey Dec 17, 2024
83cb2d0
Remove comment
estrattonbailey Dec 17, 2024
a4fd857
Remove stray flex_1
estrattonbailey Dec 17, 2024
f51366f
add topic screen
haileyok Dec 18, 2024
98cefc6
decode
haileyok Dec 18, 2024
fb8e237
fix search query
haileyok Dec 18, 2024
5755c92
Merge remote-tracking branch 'origin/explore-page-trending-and-starte…
haileyok Dec 18, 2024
9055ce9
decode
haileyok Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ import {LanguageSettingsScreen} from './screens/Settings/LanguageSettings'
import {PrivacyAndSecuritySettingsScreen} from './screens/Settings/PrivacyAndSecuritySettings'
import {SettingsScreen} from './screens/Settings/Settings'
import {ThreadPreferencesScreen} from './screens/Settings/ThreadPreferences'
import TopicScreen from './screens/Topic'

const navigationRef = createNavigationContainerRef<AllNavigatorParams>()

Expand Down Expand Up @@ -376,6 +377,11 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
getComponent={() => HashtagScreen}
options={{title: title(msg`Hashtag`)}}
/>
<Stack.Screen
name="Topic"
getComponent={() => TopicScreen}
options={{title: title(msg`Topic`)}}
/>
<Stack.Screen
name="MessagesConversation"
getComponent={() => MessagesConversationScreen}
Expand Down
3 changes: 3 additions & 0 deletions src/lib/routes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type CommonNavigatorParams = {
AppIconSettings: undefined
Search: {q?: string}
Hashtag: {tag: string; author?: string}
Topic: {topic: string}
MessagesConversation: {conversation: string; embed?: string}
MessagesSettings: undefined
NotificationSettings: undefined
Expand Down Expand Up @@ -92,6 +93,7 @@ export type FlatNavigatorParams = CommonNavigatorParams & {
Feeds: undefined
Notifications: undefined
Hashtag: {tag: string; author?: string}
Topic: {topic: string}
Messages: {pushToConversation?: string; animation?: 'push' | 'pop'}
}

Expand All @@ -105,6 +107,7 @@ export type AllNavigatorParams = CommonNavigatorParams & {
Notifications: undefined
MyProfileTab: undefined
Hashtag: {tag: string; author?: string}
Topic: {topic: string}
MessagesTab: undefined
Messages: {animation?: 'push' | 'pop'}
Start: {name: string; rkey: string}
Expand Down
1 change: 1 addition & 0 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const router = new Router({
CopyrightPolicy: '/support/copyright',
// hashtags
Hashtag: '/hashtag/:tag',
Topic: '/topic/:topic',
// DMs
Messages: '/messages',
MessagesSettings: '/messages/settings',
Expand Down
204 changes: 204 additions & 0 deletions src/screens/Topic.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import React from 'react'
import {ListRenderItemInfo, View} from 'react-native'
import {PostView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'

import {HITSLOP_10} from '#/lib/constants'
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
import {CommonNavigatorParams} from '#/lib/routes/types'
import {shareUrl} from '#/lib/sharing'
import {cleanError} from '#/lib/strings/errors'
import {enforceLen} from '#/lib/strings/helpers'
import {useSearchPostsQuery} from '#/state/queries/search-posts'
import {useSetMinimalShellMode} from '#/state/shell'
import {Pager} from '#/view/com/pager/Pager'
import {TabBar} from '#/view/com/pager/TabBar'
import {Post} from '#/view/com/post/Post'
import {List} from '#/view/com/util/List'
import {atoms as a, web} from '#/alf'
import {Button, ButtonIcon} from '#/components/Button'
import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox'
import * as Layout from '#/components/Layout'
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'

const renderItem = ({item}: ListRenderItemInfo<PostView>) => {
return <Post post={item} />
}

const keyExtractor = (item: PostView, index: number) => {
return `${item.uri}-${index}`
}

export default function TopicScreen({
route,
}: NativeStackScreenProps<CommonNavigatorParams, 'Topic'>) {
const {topic} = route.params
const {_} = useLingui()

const headerTitle = React.useMemo(() => {
return enforceLen(decodeURIComponent(topic), 24, true, 'middle')
}, [topic])

const onShare = React.useCallback(() => {
const url = new URL('https://bsky.app')
url.pathname = `/topic/${topic}`
shareUrl(url.toString())
}, [topic])

const [activeTab, setActiveTab] = React.useState(0)
const setMinimalShellMode = useSetMinimalShellMode()

useFocusEffect(
React.useCallback(() => {
setMinimalShellMode(false)
}, [setMinimalShellMode]),
)

const onPageSelected = React.useCallback(
(index: number) => {
setMinimalShellMode(false)
setActiveTab(index)
},
[setMinimalShellMode],
)

const sections = React.useMemo(() => {
return [
{
title: _(msg`Top`),
component: (
<TopicScreenTab topic={topic} sort="top" active={activeTab === 0} />
),
},
{
title: _(msg`Latest`),
component: (
<TopicScreenTab
topic={topic}
sort="latest"
active={activeTab === 1}
/>
),
},
]
}, [_, topic, activeTab])

return (
<Layout.Screen>
<Layout.Header.Outer noBottomBorder>
<Layout.Header.BackButton />
<Layout.Header.Content>
<Layout.Header.TitleText>{headerTitle}</Layout.Header.TitleText>
</Layout.Header.Content>
<Layout.Header.Slot>
<Button
label={_(msg`Share`)}
size="small"
variant="ghost"
color="primary"
shape="round"
onPress={onShare}
hitSlop={HITSLOP_10}
style={[{right: -3}]}>
<ButtonIcon icon={Share} size="md" />
</Button>
</Layout.Header.Slot>
</Layout.Header.Outer>
<Pager
onPageSelected={onPageSelected}
renderTabBar={props => (
<Layout.Center style={[a.z_10, web([a.sticky, {top: 0}])]}>
<TabBar items={sections.map(section => section.title)} {...props} />
</Layout.Center>
)}
initialPage={0}>
{sections.map((section, i) => (
<View key={i}>{section.component}</View>
))}
</Pager>
</Layout.Screen>
)
}

function TopicScreenTab({
topic,
sort,
active,
}: {
topic: string
sort: 'top' | 'latest'
active: boolean
}) {
const {_} = useLingui()
const initialNumToRender = useInitialNumToRender()
const [isPTR, setIsPTR] = React.useState(false)

const {
data,
isFetched,
isFetchingNextPage,
isLoading,
isError,
error,
refetch,
fetchNextPage,
hasNextPage,
} = useSearchPostsQuery({
query: decodeURIComponent(topic),
sort,
enabled: active,
})

const posts = React.useMemo(() => {
return data?.pages.flatMap(page => page.posts) || []
}, [data])

const onRefresh = React.useCallback(async () => {
setIsPTR(true)
await refetch()
setIsPTR(false)
}, [refetch])

const onEndReached = React.useCallback(() => {
if (isFetchingNextPage || !hasNextPage || error) return
fetchNextPage()
}, [isFetchingNextPage, hasNextPage, error, fetchNextPage])

return (
<>
{posts.length < 1 ? (
<ListMaybePlaceholder
isLoading={isLoading || !isFetched}
isError={isError}
onRetry={refetch}
emptyType="results"
emptyMessage={_(msg`We couldn't find any results for that topic.`)}
/>
) : (
<List
data={posts}
renderItem={renderItem}
keyExtractor={keyExtractor}
refreshing={isPTR}
onRefresh={onRefresh}
onEndReached={onEndReached}
onEndReachedThreshold={4}
// @ts-ignore web only -prf
desktopFixedHeight
ListFooterComponent={
<ListFooter
isFetchingNextPage={isFetchingNextPage}
error={cleanError(error)}
onRetry={fetchNextPage}
/>
}
initialNumToRender={initialNumToRender}
windowSize={11}
/>
)}
</>
)
}
Loading