From c24389df87cc8a079c447aad6a0e0b025def84f5 Mon Sep 17 00:00:00 2001 From: Ansh Nanda Date: Fri, 12 May 2023 19:46:50 -0700 Subject: custom feed embed --- src/view/com/util/post-embeds/index.tsx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'src/view/com/util/post-embeds/index.tsx') diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 2dda9069e..72158af42 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -13,6 +13,7 @@ import { AppBskyEmbedRecord, AppBskyEmbedRecordWithMedia, AppBskyFeedPost, + AppBskyFeedDefs, } from '@atproto/api' import {Link} from '../Link' import {ImageLayoutGrid} from '../images/ImageLayoutGrid' @@ -24,6 +25,7 @@ import {ExternalLinkEmbed} from './ExternalLinkEmbed' import {getYoutubeVideoId} from 'lib/strings/url-helpers' import QuoteEmbed from './QuoteEmbed' import {AutoSizedImage} from '../images/AutoSizedImage' +import AlgoItem from 'view/com/algos/AlgoItem' type Embed = | AppBskyEmbedRecord.View @@ -42,6 +44,8 @@ export function PostEmbeds({ const pal = usePalette('default') const store = useStores() + // quote post with media + // = if ( AppBskyEmbedRecordWithMedia.isView(embed) && AppBskyEmbedRecord.isViewRecord(embed.record.record) && @@ -65,6 +69,8 @@ export function PostEmbeds({ ) } + // quote post + // = if (AppBskyEmbedRecord.isView(embed)) { if ( AppBskyEmbedRecord.isViewRecord(embed.record) && @@ -87,6 +93,8 @@ export function PostEmbeds({ } } + // image embed + // = if (AppBskyEmbedImages.isView(embed)) { const {images} = embed @@ -132,10 +140,11 @@ export function PostEmbeds({ /> ) - // } } } + // external link embed + // = if (AppBskyEmbedExternal.isView(embed)) { const link = embed.external const youtubeVideoId = getYoutubeVideoId(link.uri) @@ -153,6 +162,21 @@ export function PostEmbeds({ ) } + + // custom feed embed (i.e. generator view) + // = + if ( + AppBskyEmbedRecord.isView(embed) && + AppBskyFeedDefs.isGeneratorView(embed.record) + ) { + return ( + + ) + } + return } -- cgit 1.4.1 From 047024a5ac96a5292b6a2122835673b5a034f4c3 Mon Sep 17 00:00:00 2001 From: Ansh Nanda Date: Sat, 13 May 2023 11:59:08 -0700 Subject: create algo-item model and redefine data models --- src/state/models/feeds/actor.ts | 121 ---------------------------- src/state/models/feeds/algo/actor.ts | 121 ++++++++++++++++++++++++++++ src/state/models/feeds/algo/algo-item.ts | 56 +++++++++++++ src/state/models/feeds/algo/saved.ts | 116 ++++++++++++++++++++++++++ src/state/models/feeds/bookmarked.ts | 134 ------------------------------- src/state/models/ui/profile.ts | 2 +- src/view/com/algos/AlgoItem.tsx | 93 ++++++++++++++------- src/view/com/util/post-embeds/index.tsx | 3 +- src/view/screens/Profile.tsx | 8 +- 9 files changed, 363 insertions(+), 291 deletions(-) delete mode 100644 src/state/models/feeds/actor.ts create mode 100644 src/state/models/feeds/algo/actor.ts create mode 100644 src/state/models/feeds/algo/algo-item.ts create mode 100644 src/state/models/feeds/algo/saved.ts delete mode 100644 src/state/models/feeds/bookmarked.ts (limited to 'src/view/com/util/post-embeds/index.tsx') diff --git a/src/state/models/feeds/actor.ts b/src/state/models/feeds/actor.ts deleted file mode 100644 index 08b7c2a74..000000000 --- a/src/state/models/feeds/actor.ts +++ /dev/null @@ -1,121 +0,0 @@ -import {makeAutoObservable} from 'mobx' -import { - AppBskyFeedDefs as FeedDefs, - AppBskyFeedGetActorFeeds as GetActorFeeds, -} from '@atproto/api' -import {RootStoreModel} from '../root-store' -import {bundleAsync} from 'lib/async/bundle' -import {cleanError} from 'lib/strings/errors' - -const PAGE_SIZE = 30 - -export class ActorFeedsModel { - // state - isLoading = false - isRefreshing = false - hasLoaded = false - error = '' - hasMore = true - loadMoreCursor?: string - - // data - feeds: FeedDefs.GeneratorView[] = [] - - constructor( - public rootStore: RootStoreModel, - public params: GetActorFeeds.QueryParams, - ) { - makeAutoObservable( - this, - { - rootStore: false, - }, - {autoBind: true}, - ) - } - - get hasContent() { - return this.feeds.length > 0 - } - - get hasError() { - return this.error !== '' - } - - get isEmpty() { - return this.hasLoaded && !this.hasContent - } - - // public api - // = - - async refresh() { - return this.loadMore(true) - } - - clear() { - this.isLoading = false - this.isRefreshing = false - this.hasLoaded = false - this.error = '' - this.hasMore = true - this.loadMoreCursor = undefined - this.feeds = [] - } - - loadMore = bundleAsync(async (replace: boolean = false) => { - if (!replace && !this.hasMore) { - return - } - this._xLoading(replace) - try { - const res = await this.rootStore.agent.app.bsky.feed.getActorFeeds({ - actor: this.params.actor, - limit: PAGE_SIZE, - cursor: replace ? undefined : this.loadMoreCursor, - }) - console.log('res', res.data.feeds) - if (replace) { - this._replaceAll(res) - } else { - this._appendAll(res) - } - this._xIdle() - } catch (e: any) { - this._xIdle(e) - } - }) - - // state transitions - // = - - _xLoading(isRefreshing = false) { - this.isLoading = true - this.isRefreshing = isRefreshing - this.error = '' - } - - _xIdle(err?: any) { - this.isLoading = false - this.isRefreshing = false - this.hasLoaded = true - this.error = cleanError(err) - if (err) { - this.rootStore.log.error('Failed to fetch user followers', err) - } - } - - // helper functions - // = - - _replaceAll(res: GetActorFeeds.Response) { - this.feeds = [] - this._appendAll(res) - } - - _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/feeds/algo/actor.ts b/src/state/models/feeds/algo/actor.ts new file mode 100644 index 000000000..e42df8495 --- /dev/null +++ b/src/state/models/feeds/algo/actor.ts @@ -0,0 +1,121 @@ +import {makeAutoObservable} from 'mobx' +import {AppBskyFeedGetActorFeeds as GetActorFeeds} from '@atproto/api' +import {RootStoreModel} from '../../root-store' +import {bundleAsync} from 'lib/async/bundle' +import {cleanError} from 'lib/strings/errors' +import {AlgoItemModel} from './algo-item' + +const PAGE_SIZE = 30 + +export class ActorFeedsModel { + // state + isLoading = false + isRefreshing = false + hasLoaded = false + error = '' + hasMore = true + loadMoreCursor?: string + + // data + feeds: AlgoItemModel[] = [] + + constructor( + public rootStore: RootStoreModel, + public params: GetActorFeeds.QueryParams, + ) { + makeAutoObservable( + this, + { + rootStore: false, + }, + {autoBind: true}, + ) + } + + get hasContent() { + return this.feeds.length > 0 + } + + get hasError() { + return this.error !== '' + } + + get isEmpty() { + return this.hasLoaded && !this.hasContent + } + + // public api + // = + + async refresh() { + return this.loadMore(true) + } + + clear() { + this.isLoading = false + this.isRefreshing = false + this.hasLoaded = false + this.error = '' + this.hasMore = true + this.loadMoreCursor = undefined + this.feeds = [] + } + + loadMore = bundleAsync(async (replace: boolean = false) => { + if (!replace && !this.hasMore) { + return + } + this._xLoading(replace) + try { + const res = await this.rootStore.agent.app.bsky.feed.getActorFeeds({ + actor: this.params.actor, + limit: PAGE_SIZE, + cursor: replace ? undefined : this.loadMoreCursor, + }) + console.log('res', res.data.feeds) + if (replace) { + this._replaceAll(res) + } else { + this._appendAll(res) + } + this._xIdle() + } catch (e: any) { + this._xIdle(e) + } + }) + + // state transitions + // = + + _xLoading(isRefreshing = false) { + this.isLoading = true + this.isRefreshing = isRefreshing + this.error = '' + } + + _xIdle(err?: any) { + this.isLoading = false + this.isRefreshing = false + this.hasLoaded = true + this.error = cleanError(err) + if (err) { + this.rootStore.log.error('Failed to fetch user followers', err) + } + } + + // helper functions + // = + + _replaceAll(res: GetActorFeeds.Response) { + this.feeds = [] + this._appendAll(res) + } + + _appendAll(res: GetActorFeeds.Response) { + this.loadMoreCursor = res.data.cursor + this.hasMore = !!this.loadMoreCursor + for (const f of res.data.feeds) { + this.feeds.push(new AlgoItemModel(this.rootStore, f)) + } + } +} diff --git a/src/state/models/feeds/algo/algo-item.ts b/src/state/models/feeds/algo/algo-item.ts new file mode 100644 index 000000000..555d1d56d --- /dev/null +++ b/src/state/models/feeds/algo/algo-item.ts @@ -0,0 +1,56 @@ +import {AppBskyFeedDefs} from '@atproto/api' +import {makeAutoObservable, makeObservable} from 'mobx' +import {RootStoreModel} from 'state/models/root-store' + +// algoitemmodel implemented in mobx +export class AlgoItemModel { + // data + data: AppBskyFeedDefs.GeneratorView + + constructor( + public rootStore: RootStoreModel, + view: AppBskyFeedDefs.GeneratorView, + ) { + this.data = view + makeAutoObservable( + this, + { + rootStore: false, + }, + {autoBind: true}, + ) + } + + set toggleSaved(value: boolean) { + console.log('toggleSaved', this.data.viewer) + if (this.data.viewer) { + this.data.viewer.saved = value + } + } + + async save() { + try { + // runInAction(() => { + this.toggleSaved = true + // }) + const res = await this.rootStore.agent.app.bsky.feed.saveFeed({ + feed: this.data.uri, + }) + } catch (e: any) { + this.rootStore.log.error('Failed to save feed', e) + } + } + + async unsave() { + try { + // runInAction(() => { + this.toggleSaved = false + // }) + const res = await this.rootStore.agent.app.bsky.feed.unsaveFeed({ + feed: this.data.uri, + }) + } catch (e: any) { + this.rootStore.log.error('Failed to unsanve feed', e) + } + } +} diff --git a/src/state/models/feeds/algo/saved.ts b/src/state/models/feeds/algo/saved.ts new file mode 100644 index 000000000..fabb75ae0 --- /dev/null +++ b/src/state/models/feeds/algo/saved.ts @@ -0,0 +1,116 @@ +import {makeAutoObservable} from 'mobx' +import {AppBskyFeedGetSavedFeeds as GetSavedFeeds} from '@atproto/api' +import {RootStoreModel} from '../../root-store' +import {bundleAsync} from 'lib/async/bundle' +import {cleanError} from 'lib/strings/errors' +import {AlgoItemModel} from './algo-item' + +const PAGE_SIZE = 30 + +export class SavedFeedsModel { + // state + isLoading = false + isRefreshing = false + hasLoaded = false + error = '' + hasMore = true + loadMoreCursor?: string + + // data + feeds: AlgoItemModel[] = [] + + constructor(public rootStore: RootStoreModel) { + makeAutoObservable( + this, + { + rootStore: false, + }, + {autoBind: true}, + ) + } + + get hasContent() { + return this.feeds.length > 0 + } + + get hasError() { + return this.error !== '' + } + + get isEmpty() { + return this.hasLoaded && !this.hasContent + } + + // public api + // = + + async refresh() { + return this.loadMore(true) + } + + clear() { + this.isLoading = false + this.isRefreshing = false + this.hasLoaded = false + this.error = '' + this.hasMore = true + this.loadMoreCursor = undefined + this.feeds = [] + } + + loadMore = bundleAsync(async (replace: boolean = false) => { + if (!replace && !this.hasMore) { + return + } + this._xLoading(replace) + try { + const res = await this.rootStore.agent.app.bsky.feed.getSavedFeeds({ + limit: PAGE_SIZE, + cursor: replace ? undefined : this.loadMoreCursor, + }) + if (replace) { + this._replaceAll(res) + } else { + this._appendAll(res) + } + this._xIdle() + } catch (e: any) { + this._xIdle(e) + } + }) + + // state transitions + // = + + _xLoading(isRefreshing = false) { + this.isLoading = true + this.isRefreshing = isRefreshing + this.error = '' + } + + _xIdle(err?: any) { + this.isLoading = false + this.isRefreshing = false + this.hasLoaded = true + this.error = cleanError(err) + if (err) { + this.rootStore.log.error('Failed to fetch user followers', err) + } + } + + // helper functions + // = + + _replaceAll(res: GetSavedFeeds.Response) { + this.feeds = [] + this._appendAll(res) + } + + _appendAll(res: GetSavedFeeds.Response) { + this.loadMoreCursor = res.data.cursor + this.hasMore = !!this.loadMoreCursor + for (const f of res.data.feeds) { + this.feeds.push(new AlgoItemModel(f)) + } + } +} diff --git a/src/state/models/feeds/bookmarked.ts b/src/state/models/feeds/bookmarked.ts deleted file mode 100644 index d472f0480..000000000 --- a/src/state/models/feeds/bookmarked.ts +++ /dev/null @@ -1,134 +0,0 @@ -import {makeAutoObservable} from 'mobx' -import { - AppBskyFeedGetBookmarkedFeeds as GetBookmarkedFeeds, - // AppBskyFeedBookmarkFeed as bookmarkedFeed, - // AppBskyFeedUnbookmarkFeed as unbookmarkFeed, - AppBskyFeedDefs as FeedDefs, -} from '@atproto/api' -import {RootStoreModel} from '../root-store' -import {bundleAsync} from 'lib/async/bundle' -import {cleanError} from 'lib/strings/errors' - -const PAGE_SIZE = 30 - -export class BookmarkedFeedsModel { - // state - isLoading = false - isRefreshing = false - hasLoaded = false - error = '' - hasMore = true - loadMoreCursor?: string - - // data - feeds: FeedDefs.GeneratorView[] = [] - - constructor(public rootStore: RootStoreModel) { - makeAutoObservable( - this, - { - rootStore: false, - }, - {autoBind: true}, - ) - } - - get hasContent() { - return this.feeds.length > 0 - } - - get hasError() { - return this.error !== '' - } - - get isEmpty() { - return this.hasLoaded && !this.hasContent - } - - // public api - // = - - async refresh() { - return this.loadMore(true) - } - - clear() { - this.isLoading = false - this.isRefreshing = false - this.hasLoaded = false - this.error = '' - this.hasMore = true - this.loadMoreCursor = undefined - this.feeds = [] - } - - loadMore = bundleAsync(async (replace: boolean = false) => { - if (!replace && !this.hasMore) { - return - } - this._xLoading(replace) - try { - const res = await this.rootStore.agent.app.bsky.feed.getBookmarkedFeeds({ - limit: PAGE_SIZE, - cursor: replace ? undefined : this.loadMoreCursor, - }) - if (replace) { - this._replaceAll(res) - } else { - this._appendAll(res) - } - this._xIdle() - } catch (e: any) { - this._xIdle(e) - } - }) - - async bookmark(feed: FeedDefs.GeneratorView) { - try { - await this.rootStore.agent.app.bsky.feed.bookmarkFeed({feed: feed.uri}) - } catch (e: any) { - this.rootStore.log.error('Failed to bookmark feed', e) - } - } - - async unbookmark(feed: FeedDefs.GeneratorView) { - try { - await this.rootStore.agent.app.bsky.feed.unbookmarkFeed({feed: feed.uri}) - } catch (e: any) { - this.rootStore.log.error('Failed to unbookmark feed', e) - } - } - - // state transitions - // = - - _xLoading(isRefreshing = false) { - this.isLoading = true - this.isRefreshing = isRefreshing - this.error = '' - } - - _xIdle(err?: any) { - this.isLoading = false - this.isRefreshing = false - this.hasLoaded = true - this.error = cleanError(err) - if (err) { - this.rootStore.log.error('Failed to fetch user followers', err) - } - } - - // helper functions - // = - - _replaceAll(res: GetBookmarkedFeeds.Response) { - this.feeds = [] - this._appendAll(res) - } - - _appendAll(res: GetBookmarkedFeeds.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 86199108e..855955d12 100644 --- a/src/state/models/ui/profile.ts +++ b/src/state/models/ui/profile.ts @@ -2,7 +2,7 @@ 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 {ActorFeedsModel} from '../feeds/algo/actor' import {AppBskyFeedDefs} from '@atproto/api' export enum Sections { diff --git a/src/view/com/algos/AlgoItem.tsx b/src/view/com/algos/AlgoItem.tsx index 979518f1d..987bfd68d 100644 --- a/src/view/com/algos/AlgoItem.tsx +++ b/src/view/com/algos/AlgoItem.tsx @@ -1,41 +1,62 @@ import React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} 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' +import {Button} from '../util/forms/Button' +import {observer} from 'mobx-react-lite' +import {AlgoItemModel} from 'state/models/feeds/algo/algo-item' -const AlgoItem = ({ - item, - style, -}: { - item: AppBskyFeedDefs.GeneratorView - style?: StyleProp -}) => { - const pal = usePalette('default') - return ( - - - - +const AlgoItem = observer( + ({item, style}: {item: AlgoItemModel; style?: StyleProp}) => { + const pal = usePalette('default') + return ( + + + + + + + + {item.data.displayName ?? 'Feed name'} + + + {item.data.description ?? + 'THIS IS A FEED DESCRIPTION, IT WILL TELL YOU WHAT THE FEED IS ABOUT. THIS IS A COOL FEED ABOUT COOL PEOPLE.'} + + - - - {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 */} - - ) -} + {/* TODO: this feed is like by *3* people UserAvatars and others */} + + + + + + + + Liked by 3 others + + +