Add the ability to navigate to posts within a thread

zio/stable
Paul Frazee 2022-07-21 13:07:24 -05:00
parent 139c9deb75
commit 28dbc5f5e6
7 changed files with 46 additions and 20 deletions

View File

@ -15,7 +15,7 @@
"dependencies": {
"@adxp/auth": "*",
"@adxp/common": "*",
"@adxp/mock-api": "git+ssh://git@github.com:bluesky-social/adx-mock-api.git#3714722a09503caad6e3aba7f9e9027994d07bdb",
"@adxp/mock-api": "git+ssh://git@github.com:bluesky-social/adx-mock-api.git#464712517e8f42b307622aa625bf2b2e11ad763e",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",

View File

@ -24,6 +24,7 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
| bsky.PostThreadView.RecordEmbed
| bsky.PostThreadView.ExternalEmbed
| bsky.PostThreadView.UnknownEmbed
parent?: PostThreadViewPostModel
replyCount: number = 0
replies?: PostThreadViewPostModel[]
repostCount: number = 0
@ -34,11 +35,25 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
makeAutoObservable(this)
this._reactKey = reactKey
if (v) {
Object.assign(this, _omit(v, 'replies')) // copy everything but the replies
Object.assign(this, _omit(v, 'parent', 'replies')) // copy everything but the replies and the parent
}
}
setReplies(keyGen: Generator<string>, v: bsky.PostThreadView.Post) {
assignTreeModels(keyGen: Generator<string>, v: bsky.PostThreadView.Post) {
// parents
if (v.parent) {
// TODO: validate .record
const parentModel = new PostThreadViewPostModel(
keyGen.next().value,
v.parent,
)
parentModel._depth = this._depth - 1
if (v.parent.parent) {
parentModel.assignTreeModels(keyGen, v.parent)
}
this.parent = parentModel
}
// replies
if (v.replies) {
const replies = []
for (const item of v.replies) {
@ -46,7 +61,7 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
const itemModel = new PostThreadViewPostModel(keyGen.next().value, item)
itemModel._depth = this._depth + 1
if (item.replies) {
itemModel.setReplies(keyGen, item)
itemModel.assignTreeModels(keyGen, item)
}
replies.push(itemModel)
}
@ -161,7 +176,7 @@ export class PostThreadViewModel implements bsky.PostThreadView.Response {
const keyGen = reactKeyGenerator()
const thread = new PostThreadViewPostModel(keyGen.next().value, res.thread)
thread._isHighlightedPost = true
thread.setReplies(keyGen, res.thread)
thread.assignTreeModels(keyGen, res.thread)
this.thread = thread
}
}

View File

@ -78,6 +78,9 @@ export const PostThread = observer(function PostThread({
function* flattenThread(
post: PostThreadViewPostModel,
): Generator<PostThreadViewPostModel, void> {
if (post.parent) {
yield* flattenThread(post.parent)
}
yield post
if (post.replies?.length) {
for (const reply of post.replies) {

View File

@ -8,7 +8,7 @@ import {
TouchableOpacity,
View,
} from 'react-native'
import {bsky} from '@adxp/mock-api'
import {bsky, AdxUri} from '@adxp/mock-api'
import moment from 'moment'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {OnNavigateContent} from '../../routes/types'
@ -31,7 +31,8 @@ function iter<T>(n: number, fn: (i: number) => T): Array<T> {
}
export const PostThreadItem = observer(function PostThreadItem({
item, // onNavigateContent,
item,
onNavigateContent,
}: {
item: PostThreadViewPostModel
onNavigateContent: OnNavigateContent
@ -39,12 +40,16 @@ export const PostThreadItem = observer(function PostThreadItem({
const record = item.record as unknown as bsky.Post.Record
const hasEngagement = item.likeCount || item.repostCount
const onPressOuter = () => {
// TODO onNavigateContent
const urip = new AdxUri(item.uri)
onNavigateContent('PostThread', {
name: item.author.name,
recordKey: urip.recordKey,
})
}
return (
<TouchableOpacity style={styles.outer} onPress={onPressOuter}>
<View style={styles.layout}>
{iter(item._depth, () => (
{iter(Math.abs(item._depth), () => (
<View style={styles.replyBar} />
))}
<View style={styles.layoutAvi}>
@ -143,7 +148,7 @@ const styles = StyleSheet.create({
},
replyBar: {
width: 5,
backgroundColor: '#d4f0ff',
backgroundColor: 'gray',
marginRight: 2,
},
layoutAvi: {

View File

@ -54,20 +54,24 @@ const tabBarScreenOptions = ({
route: RouteProp<ParamListBase, string>
}) => ({
headerShown: false,
tabBarIcon: (_state: {focused: boolean; color: string; size: number}) => {
tabBarIcon: (state: {focused: boolean; color: string; size: number}) => {
switch (route.name) {
case 'Home':
return <FontAwesomeIcon icon="house" />
return <FontAwesomeIcon icon="house" style={{color: state.color}} />
case 'Search':
return <FontAwesomeIcon icon="magnifying-glass" />
return (
<FontAwesomeIcon
icon="magnifying-glass"
style={{color: state.color}}
/>
)
case 'Notifications':
return <FontAwesomeIcon icon="bell" />
return <FontAwesomeIcon icon="bell" style={{color: state.color}} />
case 'Menu':
return <FontAwesomeIcon icon="bars" />
return <FontAwesomeIcon icon="bars" style={{color: state.color}} />
default:
return <FontAwesomeIcon icon="bars" />
return <FontAwesomeIcon icon="bars" style={{color: state.color}} />
}
// return <Text>{route.name?.[0] || ''}</Text>
},
})

View File

@ -8,7 +8,6 @@ Paul's todo list
- Thread view
- Mock API support fetch on thread that's not root
- Header (back btn, highlight)
- Navigate on post press
- View likes list
- View reposts list
- Reply control

View File

@ -55,9 +55,9 @@
ucans "0.9.0-alpha3"
uint8arrays "^3.0.0"
"@adxp/mock-api@git+ssh://git@github.com:bluesky-social/adx-mock-api.git#3714722a09503caad6e3aba7f9e9027994d07bdb":
"@adxp/mock-api@git+ssh://git@github.com:bluesky-social/adx-mock-api.git#464712517e8f42b307622aa625bf2b2e11ad763e":
version "0.0.1"
resolved "git+ssh://git@github.com:bluesky-social/adx-mock-api.git#3714722a09503caad6e3aba7f9e9027994d07bdb"
resolved "git+ssh://git@github.com:bluesky-social/adx-mock-api.git#464712517e8f42b307622aa625bf2b2e11ad763e"
dependencies:
ajv "^8.11.0"
ajv-formats "^2.1.1"