diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/state/models/feeds/algo/actor.ts (renamed from src/state/models/feeds/actor.ts) | 14 | ||||
-rw-r--r-- | src/state/models/feeds/algo/algo-item.ts | 56 | ||||
-rw-r--r-- | src/state/models/feeds/algo/saved.ts (renamed from src/state/models/feeds/bookmarked.ts) | 40 | ||||
-rw-r--r-- | src/state/models/ui/profile.ts | 2 | ||||
-rw-r--r-- | src/view/com/algos/AlgoItem.tsx | 93 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/index.tsx | 3 | ||||
-rw-r--r-- | src/view/screens/Profile.tsx | 8 |
7 files changed, 144 insertions, 72 deletions
diff --git a/src/state/models/feeds/actor.ts b/src/state/models/feeds/algo/actor.ts index 08b7c2a74..e42df8495 100644 --- a/src/state/models/feeds/actor.ts +++ b/src/state/models/feeds/algo/actor.ts @@ -1,11 +1,9 @@ import {makeAutoObservable} from 'mobx' -import { - AppBskyFeedDefs as FeedDefs, - AppBskyFeedGetActorFeeds as GetActorFeeds, -} from '@atproto/api' -import {RootStoreModel} from '../root-store' +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 @@ -19,7 +17,7 @@ export class ActorFeedsModel { loadMoreCursor?: string // data - feeds: FeedDefs.GeneratorView[] = [] + feeds: AlgoItemModel[] = [] constructor( public rootStore: RootStoreModel, @@ -116,6 +114,8 @@ export class ActorFeedsModel { _appendAll(res: GetActorFeeds.Response) { this.loadMoreCursor = res.data.cursor this.hasMore = !!this.loadMoreCursor - this.feeds = this.feeds.concat(res.data.feeds) + 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/bookmarked.ts b/src/state/models/feeds/algo/saved.ts index d472f0480..fabb75ae0 100644 --- a/src/state/models/feeds/bookmarked.ts +++ b/src/state/models/feeds/algo/saved.ts @@ -1,17 +1,13 @@ 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 {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 BookmarkedFeedsModel { +export class SavedFeedsModel { // state isLoading = false isRefreshing = false @@ -21,7 +17,7 @@ export class BookmarkedFeedsModel { loadMoreCursor?: string // data - feeds: FeedDefs.GeneratorView[] = [] + feeds: AlgoItemModel[] = [] constructor(public rootStore: RootStoreModel) { makeAutoObservable( @@ -68,7 +64,7 @@ export class BookmarkedFeedsModel { } this._xLoading(replace) try { - const res = await this.rootStore.agent.app.bsky.feed.getBookmarkedFeeds({ + const res = await this.rootStore.agent.app.bsky.feed.getSavedFeeds({ limit: PAGE_SIZE, cursor: replace ? undefined : this.loadMoreCursor, }) @@ -83,22 +79,6 @@ export class BookmarkedFeedsModel { } }) - 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 // = @@ -121,14 +101,16 @@ export class BookmarkedFeedsModel { // helper functions // = - _replaceAll(res: GetBookmarkedFeeds.Response) { + _replaceAll(res: GetSavedFeeds.Response) { this.feeds = [] this._appendAll(res) } - _appendAll(res: GetBookmarkedFeeds.Response) { + _appendAll(res: GetSavedFeeds.Response) { this.loadMoreCursor = res.data.cursor this.hasMore = !!this.loadMoreCursor - this.feeds = this.feeds.concat(res.data.feeds) + for (const f of res.data.feeds) { + this.feeds.push(new AlgoItemModel(f)) + } } } 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<ViewStyle> -}) => { - const pal = usePalette('default') - return ( - <View style={[styles.container, style]} key={item.uri}> - <View style={[styles.headerContainer]}> - <View style={[s.mr20]}> - <UserAvatar size={56} avatar={item.avatar} /> +const AlgoItem = observer( + ({item, style}: {item: AlgoItemModel; style?: StyleProp<ViewStyle>}) => { + const pal = usePalette('default') + return ( + <View style={[styles.container, style]} key={item.data.uri}> + <View style={[styles.headerContainer]}> + <View style={[s.mr10]}> + <UserAvatar size={36} avatar={item.data.avatar} /> + </View> + <View style={[styles.headerTextContainer]}> + <Text style={[pal.text, s.bold]}> + {item.data.displayName ?? 'Feed name'} + </Text> + <Text style={[pal.textLight, styles.description]}> + {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.'} + </Text> + </View> </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> - ) -} + {/* TODO: this feed is like by *3* people UserAvatars and others */} + <View style={styles.bottomContainer}> + <View style={styles.likedByContainer}> + <View style={styles.likedByAvatars}> + <UserAvatar size={24} avatar={item.data.avatar} /> + <UserAvatar size={24} avatar={item.data.avatar} /> + <UserAvatar size={24} avatar={item.data.avatar} /> + </View> + <Text style={[pal.text, pal.textLight]}>Liked by 3 others</Text> + </View> + <View> + <Button + type="inverted" + onPress={() => { + if (item.data.viewer?.saved) { + item.unsave() + } else { + item.save() + } + }} + label={item.data.viewer?.saved ? 'Unsave' : 'Save'} + /> + </View> + </View> + </View> + ) + }, +) export default AlgoItem const styles = StyleSheet.create({ @@ -43,10 +64,10 @@ const styles = StyleSheet.create({ paddingHorizontal: 18, paddingVertical: 20, flexDirection: 'column', - columnGap: 36, flex: 1, borderTopWidth: 1, borderTopColor: '#E5E5E5', + gap: 18, }, headerContainer: { flexDirection: 'row', @@ -60,4 +81,18 @@ const styles = StyleSheet.create({ flex: 1, flexWrap: 'wrap', }, + bottomContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + }, + likedByContainer: { + flexDirection: 'row', + alignItems: 'center', + gap: 2, + }, + likedByAvatars: { + flexDirection: 'row', + gap: -12, + }, }) diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 72158af42..3eb2720c0 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -26,6 +26,7 @@ import {getYoutubeVideoId} from 'lib/strings/url-helpers' import QuoteEmbed from './QuoteEmbed' import {AutoSizedImage} from '../images/AutoSizedImage' import AlgoItem from 'view/com/algos/AlgoItem' +import {AlgoItemModel} from 'state/models/feeds/algo/algo-item' type Embed = | AppBskyEmbedRecord.View @@ -171,7 +172,7 @@ export function PostEmbeds({ ) { return ( <AlgoItem - item={embed.record} + item={new AlgoItemModel(store, embed.record)} style={[pal.view, pal.border, styles.extOuter]} /> ) diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index b88caf1f8..68aa97b66 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -21,8 +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' +import {AlgoItemModel} from 'state/models/feeds/algo/algo-item' type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'> export const ProfileScreen = withAuthRequired( @@ -154,10 +154,8 @@ export const ProfileScreen = withAuthRequired( ) } else if (item instanceof PostsFeedSliceModel) { 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} /> + } else if (item instanceof AlgoItemModel) { + return <AlgoItem item={item} /> } return <View /> }, |