custom feed screen

zio/stable
Ansh Nanda 2023-05-15 10:42:23 -07:00
parent 61ea37ff81
commit 5010861160
7 changed files with 119 additions and 10 deletions

View File

@ -53,6 +53,7 @@ import {MutedAccounts} from 'view/screens/MutedAccounts'
import {BlockedAccounts} from 'view/screens/BlockedAccounts'
import {getRoutingInstrumentation} from 'lib/sentry'
import {SavedFeeds} from './view/screens/SavedFeeds'
import {CustomFeed} from './view/screens/CustomFeed'
const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
@ -93,6 +94,7 @@ function commonScreens(Stack: typeof HomeTab) {
<Stack.Screen name="CopyrightPolicy" component={CopyrightPolicyScreen} />
<Stack.Screen name="AppPasswords" component={AppPasswords} />
<Stack.Screen name="SavedFeeds" component={SavedFeeds} />
<Stack.Screen name="CustomFeed" component={CustomFeed} />
<Stack.Screen name="MutedAccounts" component={MutedAccounts} />
<Stack.Screen name="BlockedAccounts" component={BlockedAccounts} />
</>

View File

@ -21,6 +21,7 @@ export type CommonNavigatorParams = {
CopyrightPolicy: undefined
AppPasswords: undefined
SavedFeeds: undefined
CustomFeed: {name: string; rkey: string}
MutedAccounts: undefined
BlockedAccounts: undefined
}

View File

@ -15,6 +15,7 @@ export const router = new Router({
Log: '/sys/log',
AppPasswords: '/settings/app-passwords',
SavedFeeds: '/settings/saved-feeds',
CustomFeed: '/profile/:name/feed/:rkey',
MutedAccounts: '/settings/muted-accounts',
BlockedAccounts: '/settings/blocked-accounts',
Support: '/support',

View File

@ -29,6 +29,10 @@ export class AlgoItemModel {
}
}
get getUri() {
return this.data.uri
}
// public apis
// =
async save() {
@ -52,4 +56,20 @@ export class AlgoItemModel {
this.rootStore.log.error('Failed to unsanve feed', e)
}
}
// async getFeedSkeleton() {
// const res = await this.rootStore.agent.app.bsky.feed.getFeedSkeleton({
// feed: this.data.uri,
// })
// const skeleton = res.data.feed
// console.log('skeleton', skeleton)
// return skeleton
// }
// async getFeed() {
// const feed = await this.rootStore.agent.app.bsky.feed.getFeed({
// feed: this.data.uri,
// })
// console.log('feed', feed)
// return feed
// }
}

View File

@ -4,6 +4,7 @@ import {
AppBskyFeedDefs,
AppBskyFeedPost,
AppBskyFeedGetAuthorFeed as GetAuthorFeed,
AppBskyFeedGetFeed as GetCustomFeed,
RichText,
jsonToLex,
} from '@atproto/api'
@ -305,8 +306,11 @@ export class PostsFeedModel {
constructor(
public rootStore: RootStoreModel,
public feedType: 'home' | 'author' | 'suggested' | 'goodstuff',
params: GetTimeline.QueryParams | GetAuthorFeed.QueryParams,
public feedType: 'home' | 'author' | 'suggested' | 'goodstuff' | 'custom',
params:
| GetTimeline.QueryParams
| GetAuthorFeed.QueryParams
| GetCustomFeed.QueryParams,
) {
makeAutoObservable(
this,
@ -595,13 +599,15 @@ export class PostsFeedModel {
// helper functions
// =
async _replaceAll(res: GetTimeline.Response | GetAuthorFeed.Response) {
async _replaceAll(
res: GetTimeline.Response | GetAuthorFeed.Response | GetCustomFeed.Response,
) {
this.pollCursor = res.data.feed[0]?.post.uri
return this._appendAll(res, true)
}
async _appendAll(
res: GetTimeline.Response | GetAuthorFeed.Response,
res: GetTimeline.Response | GetAuthorFeed.Response | GetCustomFeed.Response,
replace = false,
) {
this.loadMoreCursor = res.data.cursor
@ -640,7 +646,9 @@ export class PostsFeedModel {
})
}
_updateAll(res: GetTimeline.Response | GetAuthorFeed.Response) {
_updateAll(
res: GetTimeline.Response | GetAuthorFeed.Response | GetCustomFeed.Response,
) {
for (const item of res.data.feed) {
const existingSlice = this.slices.find(slice =>
slice.containsUri(item.post.uri),
@ -657,8 +665,13 @@ export class PostsFeedModel {
}
protected async _getFeed(
params: GetTimeline.QueryParams | GetAuthorFeed.QueryParams = {},
): Promise<GetTimeline.Response | GetAuthorFeed.Response> {
params:
| GetTimeline.QueryParams
| GetAuthorFeed.QueryParams
| GetCustomFeed.QueryParams,
): Promise<
GetTimeline.Response | GetAuthorFeed.Response | GetCustomFeed.Response
> {
params = Object.assign({}, this.params, params)
if (this.feedType === 'suggested') {
const responses = await getMultipleAuthorsPosts(
@ -680,6 +693,10 @@ export class PostsFeedModel {
}
} else if (this.feedType === 'home') {
return this.rootStore.agent.getTimeline(params as GetTimeline.QueryParams)
} else if (this.feedType === 'custom') {
return this.rootStore.agent.app.bsky.feed.getFeed(
params as GetCustomFeed.QueryParams,
)
} else if (this.feedType === 'goodstuff') {
const res = await getGoodStuff(
this.rootStore.session.currentSession?.accessJwt || '',

View File

@ -1,5 +1,11 @@
import React from 'react'
import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
import {
StyleProp,
StyleSheet,
View,
ViewStyle,
TouchableOpacity,
} from 'react-native'
import {Text} from '../util/text/Text'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
@ -7,13 +13,25 @@ import {UserAvatar} from '../util/UserAvatar'
import {Button} from '../util/forms/Button'
import {observer} from 'mobx-react-lite'
import {AlgoItemModel} from 'state/models/feeds/algo/algo-item'
import {useNavigation} from '@react-navigation/native'
import {NavigationProp} from 'lib/routes/types'
const AlgoItem = observer(
({item, style}: {item: AlgoItemModel; style?: StyleProp<ViewStyle>}) => {
const pal = usePalette('default')
const navigation = useNavigation<NavigationProp>()
return (
<View style={[styles.container, style]} key={item.data.uri}>
<TouchableOpacity
accessibilityRole="button"
style={[styles.container, style]}
onPress={() => {
navigation.navigate('CustomFeed', {
name: item.data.creator.did,
rkey: item.data.uri,
})
}}
key={item.data.uri}>
<View style={[styles.headerContainer]}>
<View style={[s.mr10]}>
<UserAvatar size={36} avatar={item.data.avatar} />
@ -54,7 +72,7 @@ const AlgoItem = observer(
/>
</View>
</View>
</View>
</TouchableOpacity>
)
},
)

View File

@ -0,0 +1,50 @@
import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {CommonNavigatorParams} from 'lib/routes/types'
import {observer} from 'mobx-react-lite'
import React, {useEffect, useMemo, useRef} from 'react'
import {FlatList, StyleSheet, View} from 'react-native'
import {useStores} from 'state/index'
import {AlgoItemModel} from 'state/models/feeds/algo/algo-item'
import {PostsFeedModel} from 'state/models/feeds/posts'
import {withAuthRequired} from 'view/com/auth/withAuthRequired'
import {Feed} from 'view/com/posts/Feed'
import {ViewHeader} from 'view/com/util/ViewHeader'
import {Text} from 'view/com/util/text/Text'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'CustomFeed'>
export const CustomFeed = withAuthRequired(
observer(({route}: Props) => {
const rootStore = useStores()
const scrollElRef = useRef<FlatList>(null)
const {rkey, name} = route.params
const algoFeed: PostsFeedModel = useMemo(() => {
const feed = new PostsFeedModel(rootStore, 'custom', {
feed: rkey,
})
feed.setup()
return feed
}, [rkey, rootStore])
return (
<View style={[styles.container]}>
<ViewHeader title={'Custom Feed'} showOnDesktop />
<Feed
scrollElRef={scrollElRef}
testID={'test-feed'}
key="default"
feed={algoFeed}
/>
</View>
)
}),
)
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
},
})