From c712cbbfe27cca5db5d87abd8d7fd3b749492fcc Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 20 Jul 2022 15:00:37 -0500 Subject: Add WIP post-thread view --- src/state/models/feed-view.ts | 11 +- src/state/models/post-thread-view.ts | 153 ++++++++++++++++++++++ src/state/models/root-store.ts | 7 ++ src/view/com/Feed.tsx | 33 ----- src/view/com/FeedItem.tsx | 172 ------------------------- src/view/com/feed/Feed.tsx | 45 +++++++ src/view/com/feed/FeedItem.tsx | 189 ++++++++++++++++++++++++++++ src/view/com/post-thread/PostThread.tsx | 88 +++++++++++++ src/view/com/post-thread/PostThreadItem.tsx | 176 ++++++++++++++++++++++++++ src/view/routes/index.tsx | 11 +- src/view/routes/types.ts | 3 + src/view/screens/Home.tsx | 13 +- src/view/screens/Profile.tsx | 16 --- src/view/screens/content/PostThread.tsx | 27 ++++ src/view/screens/content/Profile.tsx | 16 +++ 15 files changed, 725 insertions(+), 235 deletions(-) create mode 100644 src/state/models/post-thread-view.ts delete mode 100644 src/view/com/Feed.tsx delete mode 100644 src/view/com/FeedItem.tsx create mode 100644 src/view/com/feed/Feed.tsx create mode 100644 src/view/com/feed/FeedItem.tsx create mode 100644 src/view/com/post-thread/PostThread.tsx create mode 100644 src/view/com/post-thread/PostThreadItem.tsx delete mode 100644 src/view/screens/Profile.tsx create mode 100644 src/view/screens/content/PostThread.tsx create mode 100644 src/view/screens/content/Profile.tsx (limited to 'src') diff --git a/src/state/models/feed-view.ts b/src/state/models/feed-view.ts index 4b915a766..51379b5cc 100644 --- a/src/state/models/feed-view.ts +++ b/src/state/models/feed-view.ts @@ -1,9 +1,9 @@ -import {makeAutoObservable, runInAction} from 'mobx' +import {makeAutoObservable} from 'mobx' import {bsky} from '@adxp/mock-api' import {RootStoreModel} from './root-store' export class FeedViewItemModel implements bsky.FeedView.FeedItem { - key: string = '' + _reactKey: string = '' uri: string = '' author: bsky.FeedView.User = {did: '', name: '', displayName: ''} repostedBy?: bsky.FeedView.User @@ -17,9 +17,9 @@ export class FeedViewItemModel implements bsky.FeedView.FeedItem { likeCount: number = 0 indexedAt: string = '' - constructor(key: string, v: bsky.FeedView.FeedItem) { + constructor(reactKey: string, v: bsky.FeedView.FeedItem) { makeAutoObservable(this) - this.key = key + this._reactKey = reactKey Object.assign(this, v) } } @@ -115,7 +115,6 @@ export class FeedViewModel implements bsky.FeedView.Response { // = private async _initialLoad() { - console.log('_initialLoad()') this._xLoading() await new Promise(r => setTimeout(r, 1e3)) // DEBUG try { @@ -131,7 +130,6 @@ export class FeedViewModel implements bsky.FeedView.Response { } private async _loadMore() { - console.log('_loadMore()') this._xLoading() await new Promise(r => setTimeout(r, 1e3)) // DEBUG try { @@ -150,7 +148,6 @@ export class FeedViewModel implements bsky.FeedView.Response { } private async _refresh() { - console.log('_refresh()') this._xLoading(true) // TODO: refetch and update items await new Promise(r => setTimeout(r, 1e3)) // DEBUG diff --git a/src/state/models/post-thread-view.ts b/src/state/models/post-thread-view.ts new file mode 100644 index 000000000..e2e0f7462 --- /dev/null +++ b/src/state/models/post-thread-view.ts @@ -0,0 +1,153 @@ +import {makeAutoObservable, runInAction} from 'mobx' +import {bsky, AdxUri} from '@adxp/mock-api' +import _omit from 'lodash.omit' +import {RootStoreModel} from './root-store' + +export class PostThreadViewPostModel implements bsky.PostThreadView.Post { + _reactKey: string = '' + uri: string = '' + author: bsky.PostThreadView.User = {did: '', name: '', displayName: ''} + record: Record = {} + embed?: + | bsky.PostThreadView.RecordEmbed + | bsky.PostThreadView.ExternalEmbed + | bsky.PostThreadView.UnknownEmbed + replyCount: number = 0 + replies?: PostThreadViewPostModel[] + repostCount: number = 0 + likeCount: number = 0 + indexedAt: string = '' + + constructor(reactKey: string, v?: bsky.PostThreadView.Post) { + makeAutoObservable(this) + this._reactKey = reactKey + if (v) { + Object.assign(this, _omit(v, 'replies')) // copy everything but the replies + } + } + + setReplies(v: bsky.PostThreadView.Post) { + if (v.replies) { + const replies = [] + let counter = 0 + for (const item of v.replies) { + // TODO: validate .record + const itemModel = new PostThreadViewPostModel(`item-${counter++}`, item) + if (item.replies) { + itemModel.setReplies(item) + } + replies.push(itemModel) + } + this.replies = replies + } + } +} +const UNLOADED_THREAD = new PostThreadViewPostModel('') + +export class PostThreadViewModel implements bsky.PostThreadView.Response { + isLoading = false + isRefreshing = false + hasLoaded = false + error = '' + resolvedUri = '' + params: bsky.PostThreadView.Params + thread: PostThreadViewPostModel = UNLOADED_THREAD + + constructor( + public rootStore: RootStoreModel, + params: bsky.PostThreadView.Params, + ) { + makeAutoObservable( + this, + { + rootStore: false, + params: false, + }, + {autoBind: true}, + ) + this.params = params + } + + get hasContent() { + return this.thread !== UNLOADED_THREAD + } + + get hasError() { + return this.error !== '' + } + + // public api + // = + + async setup() { + if (!this.resolvedUri) { + await this._resolveUri() + } + if (this.hasContent) { + await this._refresh() + } else { + await this._initialLoad() + } + } + + async refresh() { + await this._refresh() + } + + // state transitions + // = + + private _xLoading(isRefreshing = false) { + this.isLoading = true + this.isRefreshing = isRefreshing + this.error = '' + } + + private _xIdle(err: string = '') { + this.isLoading = false + this.isRefreshing = false + this.hasLoaded = true + this.error = err + } + + // loader functions + // = + + private async _resolveUri() { + const urip = new AdxUri(this.params.uri) + if (!urip.host.startsWith('did:')) { + urip.host = await this.rootStore.resolveName(urip.host) + } + runInAction(() => { + this.resolvedUri = urip.toString() + }) + } + + private async _initialLoad() { + this._xLoading() + try { + const res = (await this.rootStore.api.mainPds.view( + 'blueskyweb.xyz:PostThreadView', + Object.assign({}, this.params, {uri: this.resolvedUri}), + )) as bsky.PostThreadView.Response + this._replaceAll(res) + this._xIdle() + } catch (e: any) { + this._xIdle(`Failed to load thread: ${e.toString()}`) + } + } + + private async _refresh() { + this._xLoading(true) + // TODO: refetch and update items + await new Promise(r => setTimeout(r, 1e3)) // DEBUG + this._xIdle() + } + + private _replaceAll(res: bsky.PostThreadView.Response) { + // TODO: validate .record + const thread = new PostThreadViewPostModel('item-0', res.thread) + thread.setReplies(res.thread) + this.thread = thread + } +} diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts index a5d356066..7391a82bd 100644 --- a/src/state/models/root-store.ts +++ b/src/state/models/root-store.ts @@ -18,11 +18,18 @@ export class RootStoreModel { constructor(public api: AdxClient) { makeAutoObservable(this, { api: false, + resolveName: false, serialize: false, hydrate: false, }) } + async resolveName(didOrName: string) { + const userDb = this.api.mockDb.getUser(didOrName) + if (!userDb) throw new Error(`User not found: ${didOrName}`) + return userDb.did + } + serialize(): unknown { return { session: this.session.serialize(), diff --git a/src/view/com/Feed.tsx b/src/view/com/Feed.tsx deleted file mode 100644 index 507f0edde..000000000 --- a/src/view/com/Feed.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react' -import {observer, Observer} from 'mobx-react-lite' -import {Text, View, FlatList} from 'react-native' -import {FeedViewModel, FeedViewItemModel} from '../../state/models/feed-view' -import {FeedItem} from './FeedItem' - -export const Feed = observer(function Feed({feed}: {feed: FeedViewModel}) { - const renderItem = ({item}: {item: FeedViewItemModel}) => ( - {() => } - ) - const onRefresh = () => { - feed.refresh().catch(err => console.error('Failed to refresh', err)) - } - const onEndReached = () => { - feed.loadMore().catch(err => console.error('Failed to load more', err)) - } - return ( - - {feed.isLoading && !feed.isRefreshing && Loading...} - {feed.hasError && {feed.error}} - {feed.hasContent && ( - - )} - {feed.isEmpty && This feed is empty!} - - ) -}) diff --git a/src/view/com/FeedItem.tsx b/src/view/com/FeedItem.tsx deleted file mode 100644 index 262104bf3..000000000 --- a/src/view/com/FeedItem.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import React from 'react' -import {observer} from 'mobx-react-lite' -import {Text, Image, ImageSourcePropType, StyleSheet, View} from 'react-native' -import {bsky} from '@adxp/mock-api' -import moment from 'moment' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {FeedViewItemModel} from '../../state/models/feed-view' - -const IMAGES: Record = { - 'alice.com': require('../../assets/alice.jpg'), - 'bob.com': require('../../assets/bob.jpg'), - 'carla.com': require('../../assets/carla.jpg'), -} - -export const FeedItem = observer(function FeedItem({ - item, -}: { - item: FeedViewItemModel -}) { - const record = item.record as unknown as bsky.Post.Record - return ( - - {item.repostedBy && ( - - - - Reposted by {item.repostedBy.displayName} - - - )} - - - - - - - - {item.author.displayName} - - - @{item.author.name} - - - · {moment(item.indexedAt).fromNow(true)} - - - {record.text} - - - - {item.replyCount} - - - - {item.repostCount} - - - - {item.likeCount} - - - - - - - - - ) -}) - -const styles = StyleSheet.create({ - outer: { - borderTopWidth: 1, - borderTopColor: '#e8e8e8', - backgroundColor: '#fff', - padding: 10, - }, - repostedBy: { - flexDirection: 'row', - paddingLeft: 70, - }, - repostedByIcon: { - marginRight: 2, - color: 'gray', - }, - repostedByText: { - color: 'gray', - fontWeight: 'bold', - fontSize: 13, - }, - layout: { - flexDirection: 'row', - }, - layoutAvi: { - width: 70, - }, - avi: { - width: 60, - height: 60, - borderRadius: 30, - resizeMode: 'cover', - }, - layoutContent: { - flex: 1, - }, - meta: { - flexDirection: 'row', - paddingTop: 2, - paddingBottom: 4, - }, - metaItem: { - paddingRight: 5, - }, - metaDisplayName: { - fontSize: 15, - fontWeight: 'bold', - }, - metaName: { - fontSize: 14, - color: 'gray', - }, - metaDate: { - fontSize: 14, - color: 'gray', - }, - postText: { - fontSize: 15, - paddingBottom: 5, - }, - ctrls: { - flexDirection: 'row', - }, - ctrl: { - flexDirection: 'row', - alignItems: 'center', - flex: 1, - paddingLeft: 4, - paddingRight: 4, - }, - ctrlReplyIcon: { - marginRight: 5, - color: 'gray', - }, - ctrlRepostIcon: { - marginRight: 5, - color: 'gray', - }, - ctrlLikeIcon: { - marginRight: 5, - color: 'gray', - }, - ctrlShareIcon: { - marginRight: 5, - color: 'gray', - }, -}) diff --git a/src/view/com/feed/Feed.tsx b/src/view/com/feed/Feed.tsx new file mode 100644 index 000000000..fe9d350d1 --- /dev/null +++ b/src/view/com/feed/Feed.tsx @@ -0,0 +1,45 @@ +import React from 'react' +import {observer} from 'mobx-react-lite' +import {Text, View, FlatList} from 'react-native' +import {OnNavigateContent} from '../../routes/types' +import {FeedViewModel, FeedViewItemModel} from '../../../state/models/feed-view' +import {FeedItem} from './FeedItem' + +export const Feed = observer(function Feed({ + feed, + onNavigateContent, +}: { + feed: FeedViewModel + onNavigateContent: OnNavigateContent +}) { + // TODO optimize renderItem or FeedItem, we're getting this notice from RN: -prf + // VirtualizedList: You have a large list that is slow to update - make sure your + // renderItem function renders components that follow React performance best practices + // like PureComponent, shouldComponentUpdate, etc + const renderItem = ({item}: {item: FeedViewItemModel}) => ( + + ) + const onRefresh = () => { + feed.refresh().catch(err => console.error('Failed to refresh', err)) + } + const onEndReached = () => { + feed.loadMore().catch(err => console.error('Failed to load more', err)) + } + return ( + + {feed.isLoading && !feed.isRefreshing && Loading...} + {feed.hasError && {feed.error}} + {feed.hasContent && ( + item._reactKey} + renderItem={renderItem} + refreshing={feed.isRefreshing} + onRefresh={onRefresh} + onEndReached={onEndReached} + /> + )} + {feed.isEmpty && This feed is empty!} + + ) +}) diff --git a/src/view/com/feed/FeedItem.tsx b/src/view/com/feed/FeedItem.tsx new file mode 100644 index 000000000..7a57326f6 --- /dev/null +++ b/src/view/com/feed/FeedItem.tsx @@ -0,0 +1,189 @@ +import React from 'react' +import {observer} from 'mobx-react-lite' +import { + Image, + ImageSourcePropType, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native' +import {bsky, AdxUri} from '@adxp/mock-api' +import moment from 'moment' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {OnNavigateContent} from '../../routes/types' +import {FeedViewItemModel} from '../../../state/models/feed-view' + +const IMAGES: Record = { + 'alice.com': require('../../assets/alice.jpg'), + 'bob.com': require('../../assets/bob.jpg'), + 'carla.com': require('../../assets/carla.jpg'), +} + +export const FeedItem = observer(function FeedItem({ + item, + onNavigateContent, +}: { + item: FeedViewItemModel + onNavigateContent: OnNavigateContent +}) { + const record = item.record as unknown as bsky.Post.Record + const onPressOuter = () => { + const urip = new AdxUri(item.uri) + onNavigateContent('PostThread', { + name: item.author.name, + recordKey: urip.recordKey, + }) + } + return ( + + {item.repostedBy && ( + + + + Reposted by {item.repostedBy.displayName} + + + )} + + + + + + + + {item.author.displayName} + + + @{item.author.name} + + + · {moment(item.indexedAt).fromNow(true)} + + + {record.text} + + + + {item.replyCount} + + + + {item.repostCount} + + + + {item.likeCount} + + + + + + + + + ) +}) + +const styles = StyleSheet.create({ + outer: { + borderTopWidth: 1, + borderTopColor: '#e8e8e8', + backgroundColor: '#fff', + padding: 10, + }, + repostedBy: { + flexDirection: 'row', + paddingLeft: 70, + }, + repostedByIcon: { + marginRight: 2, + color: 'gray', + }, + repostedByText: { + color: 'gray', + fontWeight: 'bold', + fontSize: 13, + }, + layout: { + flexDirection: 'row', + }, + layoutAvi: { + width: 70, + }, + avi: { + width: 60, + height: 60, + borderRadius: 30, + resizeMode: 'cover', + }, + layoutContent: { + flex: 1, + }, + meta: { + flexDirection: 'row', + paddingTop: 2, + paddingBottom: 4, + }, + metaItem: { + paddingRight: 5, + }, + metaDisplayName: { + fontSize: 15, + fontWeight: 'bold', + }, + metaName: { + fontSize: 14, + color: 'gray', + }, + metaDate: { + fontSize: 14, + color: 'gray', + }, + postText: { + fontSize: 15, + paddingBottom: 5, + }, + ctrls: { + flexDirection: 'row', + }, + ctrl: { + flexDirection: 'row', + alignItems: 'center', + flex: 1, + paddingLeft: 4, + paddingRight: 4, + }, + ctrlReplyIcon: { + marginRight: 5, + color: 'gray', + }, + ctrlRepostIcon: { + marginRight: 5, + color: 'gray', + }, + ctrlLikeIcon: { + marginRight: 5, + color: 'gray', + }, + ctrlShareIcon: { + marginRight: 5, + color: 'gray', + }, +}) diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx new file mode 100644 index 000000000..bc6642e07 --- /dev/null +++ b/src/view/com/post-thread/PostThread.tsx @@ -0,0 +1,88 @@ +import React, {useState, useEffect} from 'react' +import {observer} from 'mobx-react-lite' +import {ActivityIndicator, FlatList, Text, View} from 'react-native' +import {OnNavigateContent} from '../../routes/types' +import { + PostThreadViewModel, + PostThreadViewPostModel, +} from '../../../state/models/post-thread-view' +import {useStores} from '../../../state' +import {PostThreadItem} from './PostThreadItem' + +export const PostThread = observer(function PostThread({ + uri, + onNavigateContent, +}: { + uri: string + onNavigateContent: OnNavigateContent +}) { + const store = useStores() + const [view, setView] = useState() + + useEffect(() => { + if (view?.params.uri === uri) { + console.log('Post thread doing nothing') + return // no change needed? or trigger refresh? + } + console.log('Fetching post thread', uri) + const newView = new PostThreadViewModel(store, {uri}) + setView(newView) + newView.setup().catch(err => console.error('Failed to fetch thread', err)) + }, [uri, view?.params.uri, store]) + + // not yet setup + if ( + !view || + (view.isLoading && !view.isRefreshing) || + view.params.uri !== uri + ) { + return ( + + + + ) + } + + // error + if (view.hasError) { + return ( + + {view.error} + + ) + } + + // rendering + const posts = Array.from(flattenThread(view.thread)) + const renderItem = ({item}: {item: PostThreadViewPostModel}) => ( + + ) + const onRefresh = () => { + view.refresh().catch(err => console.error('Failed to refresh', err)) + } + return ( + + {view.isRefreshing && } + {view.hasContent && ( + item._reactKey} + renderItem={renderItem} + refreshing={view.isRefreshing} + onRefresh={onRefresh} + /> + )} + + ) +}) + +function* flattenThread( + post: PostThreadViewPostModel, +): Generator { + yield post + if (post.replies?.length) { + for (const reply of post.replies) { + yield* flattenThread(reply) + } + } +} diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx new file mode 100644 index 000000000..33857f48a --- /dev/null +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -0,0 +1,176 @@ +import React from 'react' +import {observer} from 'mobx-react-lite' +import { + Image, + ImageSourcePropType, + StyleSheet, + Text, + TouchableOpacity, + View, +} from 'react-native' +import {bsky} from '@adxp/mock-api' +import moment from 'moment' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {OnNavigateContent} from '../../routes/types' +import {PostThreadViewPostModel} from '../../../state/models/post-thread-view' + +const IMAGES: Record = { + 'alice.com': require('../../assets/alice.jpg'), + 'bob.com': require('../../assets/bob.jpg'), + 'carla.com': require('../../assets/carla.jpg'), +} + +export const PostThreadItem = observer(function PostThreadItem({ + item, // onNavigateContent, +}: { + item: PostThreadViewPostModel + onNavigateContent: OnNavigateContent +}) { + const record = item.record as unknown as bsky.Post.Record + const onPressOuter = () => { + // TODO onNavigateContent + } + return ( + + + + + + + + + {item.author.displayName} + + + @{item.author.name} + + + · {moment(item.indexedAt).fromNow(true)} + + + {record.text} + + + + {item.replyCount} + + + + {item.repostCount} + + + + {item.likeCount} + + + + + + + + + ) +}) + +const styles = StyleSheet.create({ + outer: { + borderTopWidth: 1, + borderTopColor: '#e8e8e8', + backgroundColor: '#fff', + padding: 10, + }, + repostedBy: { + flexDirection: 'row', + paddingLeft: 70, + }, + repostedByIcon: { + marginRight: 2, + color: 'gray', + }, + repostedByText: { + color: 'gray', + fontWeight: 'bold', + fontSize: 13, + }, + layout: { + flexDirection: 'row', + }, + layoutAvi: { + width: 70, + }, + avi: { + width: 60, + height: 60, + borderRadius: 30, + resizeMode: 'cover', + }, + layoutContent: { + flex: 1, + }, + meta: { + flexDirection: 'row', + paddingTop: 2, + paddingBottom: 4, + }, + metaItem: { + paddingRight: 5, + }, + metaDisplayName: { + fontSize: 15, + fontWeight: 'bold', + }, + metaName: { + fontSize: 14, + color: 'gray', + }, + metaDate: { + fontSize: 14, + color: 'gray', + }, + postText: { + fontSize: 15, + paddingBottom: 5, + }, + ctrls: { + flexDirection: 'row', + }, + ctrl: { + flexDirection: 'row', + alignItems: 'center', + flex: 1, + paddingLeft: 4, + paddingRight: 4, + }, + ctrlReplyIcon: { + marginRight: 5, + color: 'gray', + }, + ctrlRepostIcon: { + marginRight: 5, + color: 'gray', + }, + ctrlLikeIcon: { + marginRight: 5, + color: 'gray', + }, + ctrlShareIcon: { + marginRight: 5, + color: 'gray', + }, +}) diff --git a/src/view/routes/index.tsx b/src/view/routes/index.tsx index 6351dea6a..2d47a0470 100644 --- a/src/view/routes/index.tsx +++ b/src/view/routes/index.tsx @@ -16,7 +16,8 @@ import {Home} from '../screens/Home' import {Search} from '../screens/Search' import {Notifications} from '../screens/Notifications' import {Menu} from '../screens/Menu' -import {Profile} from '../screens/Profile' +import {Profile} from '../screens/content/Profile' +import {PostThread} from '../screens/content/PostThread' import {Login} from '../screens/Login' import {Signup} from '../screens/Signup' import {NotFound} from '../screens/NotFound' @@ -32,6 +33,7 @@ const linking: LinkingOptions = { screens: { Home: '', Profile: 'profile/:name', + PostThread: 'profile/:name/post/:recordKey', Search: 'search', Notifications: 'notifications', Menu: 'menu', @@ -42,7 +44,7 @@ const linking: LinkingOptions = { }, } -export const RootTabs = createBottomTabNavigator() +export const RootTabs = createBottomTabNavigator() export const PrimaryStack = createNativeStackNavigator() const tabBarScreenOptions = ({ @@ -92,6 +94,11 @@ export const Root = observer(() => { component={Profile} options={HIDE_TAB} /> + ) : ( <> diff --git a/src/view/routes/types.ts b/src/view/routes/types.ts index d92594bbe..bca6f196a 100644 --- a/src/view/routes/types.ts +++ b/src/view/routes/types.ts @@ -6,6 +6,7 @@ export type RootTabsParamList = { Notifications: undefined Menu: undefined Profile: {name: string} + PostThread: {name: string; recordKey: string} Login: undefined Signup: undefined NotFound: undefined @@ -13,6 +14,8 @@ export type RootTabsParamList = { export type RootTabsScreenProps = StackScreenProps +export type OnNavigateContent = (screen: string, params: Record): void + /* NOTE this is leftover from a nested nav implementation diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx index 6685eb794..4a3e41a75 100644 --- a/src/view/screens/Home.tsx +++ b/src/view/screens/Home.tsx @@ -1,20 +1,23 @@ import React, {useEffect} from 'react' -import {Text, View} from 'react-native' +import {View} from 'react-native' import {Shell} from '../shell' -import {Feed} from '../com/Feed' -// import type {RootTabsScreenProps} from '../routes/types' +import {Feed} from '../com/feed/Feed' +import type {RootTabsScreenProps} from '../routes/types' import {useStores} from '../../state' -export function Home(/*{navigation}: RootTabsScreenProps<'Home'>*/) { +export function Home({navigation}: RootTabsScreenProps<'Home'>) { const store = useStores() useEffect(() => { console.log('Fetching home feed') store.homeFeed.setup() }, [store.homeFeed]) + const onNavigateContent = (screen: string, props: Record) => { + navigation.navigate(screen, props) + } return ( - + ) diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx deleted file mode 100644 index 2c93f4bf9..000000000 --- a/src/view/screens/Profile.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' -import {Shell} from '../shell' -import {View, Text} from 'react-native' -import type {RootTabsScreenProps} from '../routes/types' - -export const Profile = ({route}: RootTabsScreenProps<'Profile'>) => { - return ( - - - - {route.params?.name}'s profile - - - - ) -} diff --git a/src/view/screens/content/PostThread.tsx b/src/view/screens/content/PostThread.tsx new file mode 100644 index 000000000..5b8fa951c --- /dev/null +++ b/src/view/screens/content/PostThread.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import {AdxUri} from '@adxp/mock-api' +import {Shell} from '../../shell' +import type {RootTabsScreenProps} from '../../routes/types' +import {PostThread as PostThreadComponent} from '../../com/post-thread/PostThread' + +export const PostThread = ({ + navigation, + route, +}: RootTabsScreenProps<'PostThread'>) => { + const {name, recordKey} = route.params + + const urip = new AdxUri(`adx://todo/`) + urip.host = name + urip.collection = 'blueskyweb.xyz:Posts' + urip.recordKey = recordKey + const uri = urip.toString() + + const onNavigateContent = (screen: string, props: Record) => { + navigation.navigate(screen, props) + } + return ( + + + + ) +} diff --git a/src/view/screens/content/Profile.tsx b/src/view/screens/content/Profile.tsx new file mode 100644 index 000000000..cfbf840f3 --- /dev/null +++ b/src/view/screens/content/Profile.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import {Shell} from '../../shell' +import {View, Text} from 'react-native' +import type {RootTabsScreenProps} from '../../routes/types' + +export const Profile = ({route}: RootTabsScreenProps<'Profile'>) => { + return ( + + + + {route.params?.name}'s profile + + + + ) +} -- cgit 1.4.1