mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React, {memo} from 'react'
2import {StyleSheet, View} from 'react-native'
3import Svg, {Circle, Line} from 'react-native-svg'
4import {AtUri} from '@atproto/api'
5import {Trans} from '@lingui/macro'
6
7import {FeedPostSlice} from '#/state/queries/post-feed'
8import {usePalette} from 'lib/hooks/usePalette'
9import {makeProfileLink} from 'lib/routes/links'
10import {Link} from '../util/Link'
11import {Text} from '../util/text/Text'
12import {FeedItem} from './FeedItem'
13
14let FeedSlice = ({
15 slice,
16 hideTopBorder,
17}: {
18 slice: FeedPostSlice
19 hideTopBorder?: boolean
20}): React.ReactNode => {
21 if (slice.isThread && slice.items.length > 3) {
22 const last = slice.items.length - 1
23 return (
24 <>
25 <FeedItem
26 key={slice.items[0]._reactKey}
27 post={slice.items[0].post}
28 record={slice.items[0].record}
29 reason={slice.items[0].reason}
30 feedContext={slice.items[0].feedContext}
31 parentAuthor={slice.items[0].parentAuthor}
32 showReplyTo={true}
33 moderation={slice.items[0].moderation}
34 isThreadParent={isThreadParentAt(slice.items, 0)}
35 isThreadChild={isThreadChildAt(slice.items, 0)}
36 hideTopBorder={hideTopBorder}
37 isParentBlocked={slice.items[0].isParentBlocked}
38 />
39 <FeedItem
40 key={slice.items[1]._reactKey}
41 post={slice.items[1].post}
42 record={slice.items[1].record}
43 reason={slice.items[1].reason}
44 feedContext={slice.items[1].feedContext}
45 parentAuthor={slice.items[1].parentAuthor}
46 showReplyTo={false}
47 moderation={slice.items[1].moderation}
48 isThreadParent={isThreadParentAt(slice.items, 1)}
49 isThreadChild={isThreadChildAt(slice.items, 1)}
50 isParentBlocked={slice.items[1].isParentBlocked}
51 />
52 <ViewFullThread slice={slice} />
53 <FeedItem
54 key={slice.items[last]._reactKey}
55 post={slice.items[last].post}
56 record={slice.items[last].record}
57 reason={slice.items[last].reason}
58 feedContext={slice.items[last].feedContext}
59 parentAuthor={slice.items[2].parentAuthor}
60 showReplyTo={false}
61 moderation={slice.items[last].moderation}
62 isThreadParent={isThreadParentAt(slice.items, last)}
63 isThreadChild={isThreadChildAt(slice.items, last)}
64 isParentBlocked={slice.items[2].isParentBlocked}
65 isThreadLastChild
66 />
67 </>
68 )
69 }
70
71 return (
72 <>
73 {slice.items.map((item, i) => (
74 <FeedItem
75 key={item._reactKey}
76 post={slice.items[i].post}
77 record={slice.items[i].record}
78 reason={slice.items[i].reason}
79 feedContext={slice.items[i].feedContext}
80 moderation={slice.items[i].moderation}
81 parentAuthor={slice.items[i].parentAuthor}
82 showReplyTo={i === 0}
83 isThreadParent={isThreadParentAt(slice.items, i)}
84 isThreadChild={isThreadChildAt(slice.items, i)}
85 isThreadLastChild={
86 isThreadChildAt(slice.items, i) && slice.items.length === i + 1
87 }
88 isParentBlocked={slice.items[i].isParentBlocked}
89 hideTopBorder={hideTopBorder && i === 0}
90 />
91 ))}
92 </>
93 )
94}
95FeedSlice = memo(FeedSlice)
96export {FeedSlice}
97
98function ViewFullThread({slice}: {slice: FeedPostSlice}) {
99 const pal = usePalette('default')
100 const itemHref = React.useMemo(() => {
101 const urip = new AtUri(slice.rootUri)
102 return makeProfileLink({did: urip.hostname, handle: ''}, 'post', urip.rkey)
103 }, [slice.rootUri])
104
105 return (
106 <Link style={[styles.viewFullThread]} href={itemHref} asAnchor noFeedback>
107 <View style={styles.viewFullThreadDots}>
108 <Svg width="4" height="40">
109 <Line
110 x1="2"
111 y1="0"
112 x2="2"
113 y2="15"
114 stroke={pal.colors.replyLine}
115 strokeWidth="2"
116 />
117 <Circle cx="2" cy="22" r="1.5" fill={pal.colors.replyLineDot} />
118 <Circle cx="2" cy="28" r="1.5" fill={pal.colors.replyLineDot} />
119 <Circle cx="2" cy="34" r="1.5" fill={pal.colors.replyLineDot} />
120 </Svg>
121 </View>
122
123 <Text type="md" style={[pal.link, {paddingTop: 18, paddingBottom: 4}]}>
124 <Trans>View full thread</Trans>
125 </Text>
126 </Link>
127 )
128}
129
130const styles = StyleSheet.create({
131 viewFullThread: {
132 flexDirection: 'row',
133 gap: 10,
134 paddingLeft: 18,
135 },
136 viewFullThreadDots: {
137 width: 52,
138 alignItems: 'center',
139 },
140})
141
142function isThreadParentAt<T>(arr: Array<T>, i: number) {
143 if (arr.length === 1) {
144 return false
145 }
146 return i < arr.length - 1
147}
148
149function isThreadChildAt<T>(arr: Array<T>, i: number) {
150 if (arr.length === 1) {
151 return false
152 }
153 return i > 0
154}