Basically working read more

This commit is contained in:
Eric Bailey
2025-05-27 11:28:01 -05:00
parent 2497099d81
commit 37cd3840a4
3 changed files with 149 additions and 97 deletions
+39 -23
View File
@@ -38,49 +38,65 @@ export function flatten(
}) })
} }
const maybeParent = const deepestParent =
parentsWithUnhydratedReplies[parentsWithUnhydratedReplies.length - 1] parentsWithUnhydratedReplies[parentsWithUnhydratedReplies.length - 1]
if (maybeParent) { if (deepestParent) {
// next item is a sibling or an aunt/uncle // next item is a sibling or an aunt/uncle
if (item.depth <= maybeParent.depth) { if (item.depth <= deepestParent.depth) {
for (let pi = parentsWithUnhydratedReplies.length - 1; pi >= 0; pi--) {
const parent = parentsWithUnhydratedReplies[pi]
if (item.depth <= parent.depth) {
flattened.splice( flattened.splice(
i, i + 1 + (pi - parentsWithUnhydratedReplies.length),
0, 0,
views.readMore({ views.readMore({
item, item,
parent: maybeParent, parent: parent,
}), }),
) )
parentsWithUnhydratedReplies.pop() parentsWithUnhydratedReplies.pop()
i++ // skip over the read more item i++
} else if (i === flattened.length - 1) { } else {
// last iteration might have a parent
flattened.push(
views.readMore({
item,
parent: maybeParent,
}),
)
break break
} }
} }
}
}
/*
* Lastly, insert next read more if necessary
*/
if (item.value.moreReplies > 0) { if (item.value.moreReplies > 0) {
// last iteration might have its own read more parentsWithUnhydratedReplies.push(item)
if (i === flattened.length - 1) { }
flattened.push(
const isLastIteration = i === flattened.length - 1
if (isLastIteration) {
const deepestParent =
parentsWithUnhydratedReplies[parentsWithUnhydratedReplies.length - 1]
i++
if (deepestParent) {
// next item is a sibling or an aunt/uncle
if (deepestParent.depth <= item.depth) {
for (let pi = parentsWithUnhydratedReplies.length - 1; pi >= 0; pi--) {
const parent = parentsWithUnhydratedReplies[pi]
if (parent.depth <= item.depth) {
flattened.splice(
i + 1 + (pi - parentsWithUnhydratedReplies.length),
0,
views.readMore({ views.readMore({
item, item,
parent: item, parent: parent,
}), }),
) )
break parentsWithUnhydratedReplies.pop()
i++
} else { } else {
parentsWithUnhydratedReplies.push(item) break
}
}
}
} }
} }
} }
+1 -1
View File
@@ -95,7 +95,7 @@ export function threadPost({
ui: { ui: {
isAnchor: depth === 0, isAnchor: depth === 0,
showParentReplyLine: !!oneUp && oneUp.depth !== 0 && oneUp.depth < depth, showParentReplyLine: !!oneUp && oneUp.depth !== 0 && oneUp.depth < depth,
showChildReplyLine: !!oneDown && depth !== 0 && oneDown.depth > depth, showChildReplyLine: (value.post.replyCount || 0) > 0,
}, },
} }
} }
+96 -60
View File
@@ -1,6 +1,6 @@
import {useCallback, useMemo, useRef, useState} from 'react' import {useCallback, useMemo, useRef, useState} from 'react'
import {useWindowDimensions, View} from 'react-native' import {useWindowDimensions, View} from 'react-native'
import {msg, Trans} from '@lingui/macro' import {msg, Trans, Plural} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
@@ -22,6 +22,7 @@ import {
HiddenReplyKind, HiddenReplyKind,
type Slice, type Slice,
usePostThread, usePostThread,
PostThreadParams,
} from '#/state/queries/usePostThread' } from '#/state/queries/usePostThread'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {type OnPostSuccessData} from '#/state/shell/composer' import {type OnPostSuccessData} from '#/state/shell/composer'
@@ -261,65 +262,7 @@ export function Inner({uri}: {uri: string | undefined}) {
) )
} else if (item.type === 'readMore') { } else if (item.type === 'readMore') {
return ( return (
<View style={[a.flex_row, a.px_sm]}> <ReadMore item={item} view={treeViewEnabled ? 'tree' : 'linear'} />
{Array.from(Array(item.indent - 1)).map((_, n: number) => (
<View
key={`${item.key}-padding-${n}`}
style={[
a.ml_sm,
t.atoms.border_contrast_low,
{
borderLeftWidth: 2,
paddingLeft: a.pl_sm.paddingLeft - 2, // minus border
},
]}
/>
))}
<View style={[a.ml_sm]}>
<View
style={[
t.atoms.border_contrast_low,
{
borderLeftWidth: 2,
borderBottomWidth: 2,
borderBottomLeftRadius: a.rounded_sm.borderRadius,
height: 12,
width: a.pl_sm.paddingLeft * 2,
},
]}
/>
</View>
<Link
label={_(msg`Read more replies`)}
to={makeProfileLink(
{
did: item.nextAnchorUri.host,
handle: item.nextAnchor.value.post.author.handle,
},
'post',
item.nextAnchorUri.rkey,
)}
style={[a.pt_2xs, a.pb_sm, a.gap_xs]}>
{({hovered, pressed}) => {
return (
<>
<CirclePlus
fill={t.atoms.text_contrast_high.color}
width={18}
/>
<Text
style={[
a.text_sm,
t.atoms.text_contrast_medium,
(hovered || pressed) && a.underline,
]}>
Read {item.replyCount} more replies ({item.key})
</Text>
</>
)
}}
</Link>
</View>
) )
} else if (item.type === 'threadPostBlocked') { } else if (item.type === 'threadPostBlocked') {
return ( return (
@@ -556,3 +499,96 @@ function ThreadMenu({
const keyExtractor = (item: Slice) => { const keyExtractor = (item: Slice) => {
return item.key return item.key
} }
function ReadMore({
item,
view,
}: {
item: Extract<Slice, {type: 'readMore'}>
view: PostThreadParams['view']
}) {
const t = useTheme()
const {_} = useLingui()
const isTreeView = view === 'tree'
const indentCount = item.indent - 1
const treeIndents = isTreeView ? (
Array.from(Array(indentCount)).map((_, n: number) => (
<View
key={`${item.key}-padding-${n}`}
style={[
a.ml_sm,
t.atoms.border_contrast_low,
{
borderLeftWidth: 2,
paddingLeft: a.pl_sm.paddingLeft - 2, // minus border
},
]}
/>
))
) : indentCount > 0 ? (
<View
style={[
// avi width minus border, divided by 2
{width: (42 - 2) / 2}
]}
/>
) : null
return (
<View style={[a.flex_row, a.px_sm]}>
{treeIndents}
<View style={[a.ml_sm]}>
<View
style={[
t.atoms.border_contrast_low,
{
borderLeftWidth: 2,
borderBottomWidth: 2,
borderBottomLeftRadius: a.rounded_sm.borderRadius,
height: 12,
width: isTreeView ? a.pl_sm.paddingLeft * 2 : (42 / 2 + 10),
},
]}
/>
</View>
<Link
label={_(msg`Read more replies`)}
to={makeProfileLink(
{
did: item.nextAnchorUri.host,
handle: item.nextAnchor.value.post.author.handle,
},
'post',
item.nextAnchorUri.rkey,
)}
style={[a.pt_2xs, a.pb_sm, a.gap_xs]}>
{({hovered, pressed}) => {
return (
<>
<CirclePlus
fill={t.atoms.text_contrast_high.color}
width={18}
/>
<Text
style={[
a.text_sm,
t.atoms.text_contrast_medium,
(hovered || pressed) && a.underline,
]}>
<Trans>
Read {item.replyCount} more{' '}
<Plural
one="reply"
other="replies"
value={item.replyCount}
/>
</Trans>
</Text>
</>
)
}}
</Link>
</View>
)
}