show algos by user on profile

zio/stable
Ansh Nanda 2023-05-12 19:32:39 -07:00
parent fa4af20764
commit 760b5309e0
4 changed files with 99 additions and 17 deletions

View File

@ -1,9 +1,7 @@
import {makeAutoObservable} from 'mobx' import {makeAutoObservable} from 'mobx'
import { import {
AppBskyFeedGetBookmarkedFeeds as GetBookmarkedFeeds,
// AppBskyFeedBookmarkFeed as bookmarkedFeed,
// AppBskyFeedUnbookmarkFeed as unbookmarkFeed,
AppBskyFeedDefs as FeedDefs, AppBskyFeedDefs as FeedDefs,
AppBskyFeedGetActorFeeds as GetActorFeeds,
} from '@atproto/api' } from '@atproto/api'
import {RootStoreModel} from '../root-store' import {RootStoreModel} from '../root-store'
import {bundleAsync} from 'lib/async/bundle' import {bundleAsync} from 'lib/async/bundle'
@ -23,7 +21,10 @@ export class ActorFeedsModel {
// data // data
feeds: FeedDefs.GeneratorView[] = [] feeds: FeedDefs.GeneratorView[] = []
constructor(public rootStore: RootStoreModel) { constructor(
public rootStore: RootStoreModel,
public params: GetActorFeeds.QueryParams,
) {
makeAutoObservable( makeAutoObservable(
this, this,
{ {
@ -69,10 +70,11 @@ export class ActorFeedsModel {
this._xLoading(replace) this._xLoading(replace)
try { try {
const res = await this.rootStore.agent.app.bsky.feed.getActorFeeds({ const res = await this.rootStore.agent.app.bsky.feed.getActorFeeds({
actor: 'did:plc:dpny6d4qwwxu5b6dp3qob5ok', // TODO: take this as input param actor: this.params.actor,
limit: PAGE_SIZE, limit: PAGE_SIZE,
cursor: replace ? undefined : this.loadMoreCursor, cursor: replace ? undefined : this.loadMoreCursor,
}) })
console.log('res', res.data.feeds)
if (replace) { if (replace) {
this._replaceAll(res) this._replaceAll(res)
} else { } else {
@ -106,12 +108,12 @@ export class ActorFeedsModel {
// helper functions // helper functions
// = // =
_replaceAll(res: GetBookmarkedFeeds.Response) { _replaceAll(res: GetActorFeeds.Response) {
this.feeds = [] this.feeds = []
this._appendAll(res) this._appendAll(res)
} }
_appendAll(res: GetBookmarkedFeeds.Response) { _appendAll(res: GetActorFeeds.Response) {
this.loadMoreCursor = res.data.cursor this.loadMoreCursor = res.data.cursor
this.hasMore = !!this.loadMoreCursor this.hasMore = !!this.loadMoreCursor
this.feeds = this.feeds.concat(res.data.feeds) this.feeds = this.feeds.concat(res.data.feeds)

View File

@ -2,13 +2,20 @@ import {makeAutoObservable} from 'mobx'
import {RootStoreModel} from '../root-store' import {RootStoreModel} from '../root-store'
import {ProfileModel} from '../content/profile' import {ProfileModel} from '../content/profile'
import {PostsFeedModel} from '../feeds/posts' import {PostsFeedModel} from '../feeds/posts'
import {ActorFeedsModel} from '../feeds/actor'
import {AppBskyFeedDefs} from '@atproto/api'
export enum Sections { export enum Sections {
Posts = 'Posts', Posts = 'Posts',
PostsWithReplies = 'Posts & replies', PostsWithReplies = 'Posts & replies',
CustomAlgorithms = 'Algos',
} }
const USER_SELECTOR_ITEMS = [Sections.Posts, Sections.PostsWithReplies] const USER_SELECTOR_ITEMS = [
Sections.Posts,
Sections.PostsWithReplies,
Sections.CustomAlgorithms,
]
export interface ProfileUiParams { export interface ProfileUiParams {
user: string user: string
@ -22,6 +29,7 @@ export class ProfileUiModel {
// data // data
profile: ProfileModel profile: ProfileModel
feed: PostsFeedModel feed: PostsFeedModel
algos: ActorFeedsModel
// ui state // ui state
selectedViewIndex = 0 selectedViewIndex = 0
@ -43,15 +51,19 @@ export class ProfileUiModel {
actor: params.user, actor: params.user,
limit: 10, limit: 10,
}) })
this.algos = new ActorFeedsModel(rootStore, {actor: params.user})
} }
get currentView(): PostsFeedModel { get currentView(): PostsFeedModel | ActorFeedsModel {
if ( if (
this.selectedView === Sections.Posts || this.selectedView === Sections.Posts ||
this.selectedView === Sections.PostsWithReplies this.selectedView === Sections.PostsWithReplies
) { ) {
return this.feed return this.feed
} }
if (this.selectedView === Sections.CustomAlgorithms) {
return this.algos
}
throw new Error(`Invalid selector value: ${this.selectedViewIndex}`) throw new Error(`Invalid selector value: ${this.selectedViewIndex}`)
} }
@ -71,12 +83,17 @@ export class ProfileUiModel {
get selectedView() { get selectedView() {
return this.selectorItems[this.selectedViewIndex] return this.selectorItems[this.selectedViewIndex]
} }
isGeneratorView(v: any) {
return AppBskyFeedDefs.isGeneratorView(v)
}
get uiItems() { get uiItems() {
let arr: any[] = [] let arr: any[] = []
// if loading, return loading item to show loading spinner
if (this.isInitialLoading) { if (this.isInitialLoading) {
arr = arr.concat([ProfileUiModel.LOADING_ITEM]) arr = arr.concat([ProfileUiModel.LOADING_ITEM])
} else if (this.currentView.hasError) { } else if (this.currentView.hasError) {
// if error, return error item to show error message
arr = arr.concat([ arr = arr.concat([
{ {
_reactKey: '__error__', _reactKey: '__error__',
@ -84,12 +101,16 @@ export class ProfileUiModel {
}, },
]) ])
} else { } else {
// not loading, no error, show content
if ( if (
this.selectedView === Sections.Posts || this.selectedView === Sections.Posts ||
this.selectedView === Sections.PostsWithReplies this.selectedView === Sections.PostsWithReplies ||
this.selectedView === Sections.CustomAlgorithms
) { ) {
if (this.feed.hasContent) { if (this.feed.hasContent) {
if (this.selectedView === Sections.Posts) { if (this.selectedView === Sections.CustomAlgorithms) {
arr = this.algos.feeds
} else if (this.selectedView === Sections.Posts) {
arr = this.feed.nonReplyFeed arr = this.feed.nonReplyFeed
} else { } else {
arr = this.feed.slices.slice() arr = this.feed.slices.slice()
@ -101,6 +122,7 @@ export class ProfileUiModel {
arr = arr.concat([ProfileUiModel.EMPTY_ITEM]) arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
} }
} else { } else {
// fallback, add empty item, to show empty message
arr = arr.concat([ProfileUiModel.EMPTY_ITEM]) arr = arr.concat([ProfileUiModel.EMPTY_ITEM])
} }
} }

View File

@ -0,0 +1,57 @@
import React from 'react'
import {StyleSheet, View} from 'react-native'
import {Text} from '../util/text/Text'
import {AppBskyFeedDefs} from '@atproto/api'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {UserAvatar} from '../util/UserAvatar'
const AlgoItem = ({item}: {item: AppBskyFeedDefs.GeneratorView}) => {
const pal = usePalette('default')
return (
<View style={[styles.container]} key={item.uri}>
<View style={[styles.headerContainer]}>
<View style={[s.mr20]}>
<UserAvatar size={56} avatar={item.avatar} />
</View>
<View style={[styles.headerTextContainer]}>
<Text style={[pal.text, s.bold]}>
{item.displayName ?? 'Feed name'}
</Text>
<Text style={[pal.textLight, styles.description]}>
{item.description ??
'THIS IS A FEED DESCRIPTION, IT WILL TELL YOU WHAT THE FEED IS ABOUT. THIS IS A COOL FEED ABOUT COOL PEOPLE.'}
</Text>
</View>
</View>
{/* TODO: this feed is like by *3* people UserAvatars and others */}
</View>
)
}
export default AlgoItem
const styles = StyleSheet.create({
container: {
paddingHorizontal: 18,
paddingVertical: 20,
flexDirection: 'column',
columnGap: 36,
flex: 1,
borderTopWidth: 1,
borderTopColor: '#E5E5E5',
},
headerContainer: {
flexDirection: 'row',
},
headerTextContainer: {
flexDirection: 'column',
columnGap: 4,
flex: 1,
},
description: {
flex: 1,
flexWrap: 'wrap',
},
})

View File

@ -21,6 +21,8 @@ import {FAB} from '../com/util/fab/FAB'
import {s, colors} from 'lib/styles' import {s, colors} from 'lib/styles'
import {useAnalytics} from 'lib/analytics' import {useAnalytics} from 'lib/analytics'
import {ComposeIcon2} from 'lib/icons' import {ComposeIcon2} from 'lib/icons'
import {AppBskyFeedDefs} from '@atproto/api'
import AlgoItem from 'view/com/algos/AlgoItem'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
export const ProfileScreen = withAuthRequired( export const ProfileScreen = withAuthRequired(
@ -152,15 +154,14 @@ export const ProfileScreen = withAuthRequired(
) )
} else if (item instanceof PostsFeedSliceModel) { } else if (item instanceof PostsFeedSliceModel) {
return <FeedSlice slice={item} ignoreMuteFor={uiState.profile.did} /> return <FeedSlice slice={item} ignoreMuteFor={uiState.profile.did} />
} else if (item.creator) {
// TODO: this is a hack to see if it is a custom feed. fix it to something more robust
const typedItem = item as AppBskyFeedDefs.GeneratorView
return <AlgoItem item={typedItem} />
} }
return <View /> return <View />
}, },
[ [onPressTryAgain, uiState],
onPressTryAgain,
uiState.profile.did,
uiState.feed.isBlocking,
uiState.feed.isBlockedBy,
],
) )
return ( return (