diff --git a/src/state/models/feeds/actor.ts b/src/state/models/feeds/actor.ts index e660d4eb..08b7c2a7 100644 --- a/src/state/models/feeds/actor.ts +++ b/src/state/models/feeds/actor.ts @@ -1,9 +1,7 @@ import {makeAutoObservable} from 'mobx' import { - AppBskyFeedGetBookmarkedFeeds as GetBookmarkedFeeds, - // AppBskyFeedBookmarkFeed as bookmarkedFeed, - // AppBskyFeedUnbookmarkFeed as unbookmarkFeed, AppBskyFeedDefs as FeedDefs, + AppBskyFeedGetActorFeeds as GetActorFeeds, } from '@atproto/api' import {RootStoreModel} from '../root-store' import {bundleAsync} from 'lib/async/bundle' @@ -23,7 +21,10 @@ export class ActorFeedsModel { // data feeds: FeedDefs.GeneratorView[] = [] - constructor(public rootStore: RootStoreModel) { + constructor( + public rootStore: RootStoreModel, + public params: GetActorFeeds.QueryParams, + ) { makeAutoObservable( this, { @@ -69,10 +70,11 @@ export class ActorFeedsModel { this._xLoading(replace) try { 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, cursor: replace ? undefined : this.loadMoreCursor, }) + console.log('res', res.data.feeds) if (replace) { this._replaceAll(res) } else { @@ -106,12 +108,12 @@ export class ActorFeedsModel { // helper functions // = - _replaceAll(res: GetBookmarkedFeeds.Response) { + _replaceAll(res: GetActorFeeds.Response) { this.feeds = [] this._appendAll(res) } - _appendAll(res: GetBookmarkedFeeds.Response) { + _appendAll(res: GetActorFeeds.Response) { this.loadMoreCursor = res.data.cursor this.hasMore = !!this.loadMoreCursor this.feeds = this.feeds.concat(res.data.feeds) diff --git a/src/state/models/ui/profile.ts b/src/state/models/ui/profile.ts index d06a196f..86199108 100644 --- a/src/state/models/ui/profile.ts +++ b/src/state/models/ui/profile.ts @@ -2,13 +2,20 @@ import {makeAutoObservable} from 'mobx' import {RootStoreModel} from '../root-store' import {ProfileModel} from '../content/profile' import {PostsFeedModel} from '../feeds/posts' +import {ActorFeedsModel} from '../feeds/actor' +import {AppBskyFeedDefs} from '@atproto/api' export enum Sections { Posts = 'Posts', 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 { user: string @@ -22,6 +29,7 @@ export class ProfileUiModel { // data profile: ProfileModel feed: PostsFeedModel + algos: ActorFeedsModel // ui state selectedViewIndex = 0 @@ -43,15 +51,19 @@ export class ProfileUiModel { actor: params.user, limit: 10, }) + this.algos = new ActorFeedsModel(rootStore, {actor: params.user}) } - get currentView(): PostsFeedModel { + get currentView(): PostsFeedModel | ActorFeedsModel { if ( this.selectedView === Sections.Posts || this.selectedView === Sections.PostsWithReplies ) { return this.feed } + if (this.selectedView === Sections.CustomAlgorithms) { + return this.algos + } throw new Error(`Invalid selector value: ${this.selectedViewIndex}`) } @@ -71,12 +83,17 @@ export class ProfileUiModel { get selectedView() { return this.selectorItems[this.selectedViewIndex] } + isGeneratorView(v: any) { + return AppBskyFeedDefs.isGeneratorView(v) + } get uiItems() { let arr: any[] = [] + // if loading, return loading item to show loading spinner if (this.isInitialLoading) { arr = arr.concat([ProfileUiModel.LOADING_ITEM]) } else if (this.currentView.hasError) { + // if error, return error item to show error message arr = arr.concat([ { _reactKey: '__error__', @@ -84,12 +101,16 @@ export class ProfileUiModel { }, ]) } else { + // not loading, no error, show content if ( this.selectedView === Sections.Posts || - this.selectedView === Sections.PostsWithReplies + this.selectedView === Sections.PostsWithReplies || + this.selectedView === Sections.CustomAlgorithms ) { 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 } else { arr = this.feed.slices.slice() @@ -101,6 +122,7 @@ export class ProfileUiModel { arr = arr.concat([ProfileUiModel.EMPTY_ITEM]) } } else { + // fallback, add empty item, to show empty message arr = arr.concat([ProfileUiModel.EMPTY_ITEM]) } } diff --git a/src/view/com/algos/AlgoItem.tsx b/src/view/com/algos/AlgoItem.tsx new file mode 100644 index 00000000..57a1428e --- /dev/null +++ b/src/view/com/algos/AlgoItem.tsx @@ -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 ( + + + + + + + + {item.displayName ?? 'Feed name'} + + + {item.description ?? + 'THIS IS A FEED DESCRIPTION, IT WILL TELL YOU WHAT THE FEED IS ABOUT. THIS IS A COOL FEED ABOUT COOL PEOPLE.'} + + + + + {/* TODO: this feed is like by *3* people UserAvatars and others */} + + ) +} + +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', + }, +}) diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index 5fb21255..b88caf1f 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -21,6 +21,8 @@ import {FAB} from '../com/util/fab/FAB' import {s, colors} from 'lib/styles' import {useAnalytics} from 'lib/analytics' import {ComposeIcon2} from 'lib/icons' +import {AppBskyFeedDefs} from '@atproto/api' +import AlgoItem from 'view/com/algos/AlgoItem' type Props = NativeStackScreenProps export const ProfileScreen = withAuthRequired( @@ -152,15 +154,14 @@ export const ProfileScreen = withAuthRequired( ) } else if (item instanceof PostsFeedSliceModel) { return + } 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 } return }, - [ - onPressTryAgain, - uiState.profile.did, - uiState.feed.isBlocking, - uiState.feed.isBlockedBy, - ], + [onPressTryAgain, uiState], ) return (