Compare commits

...

4 Commits

Author SHA1 Message Date
Dan Abramov ee02082f7c Drop the top border for highlighted post 2024-01-25 20:27:19 +00:00
Dan Abramov 23eca50aa7 Revert unnecessary change 2024-01-25 20:15:29 +00:00
Dan Abramov 05336665ed Fix bottom border/spinner jank 2024-01-25 20:05:28 +00:00
Dan Abramov b1d7080d5e Dejank parent thread spinner 2024-01-25 19:54:43 +00:00
3 changed files with 36 additions and 47 deletions
+23 -38
View File
@@ -45,10 +45,9 @@ import {isAndroid, isNative} from '#/platform/detection'
import {logger} from '#/logger'
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
const MAINTAIN_VISIBLE_CONTENT_POSITION = {minIndexForVisible: 2}
const MAINTAIN_VISIBLE_CONTENT_POSITION = {minIndexForVisible: 1}
const TOP_COMPONENT = {_reactKey: '__top_component__'}
const PARENT_SPINNER = {_reactKey: '__parent_spinner__'}
const REPLY_PROMPT = {_reactKey: '__reply__'}
const DELETED = {_reactKey: '__deleted__'}
const BLOCKED = {_reactKey: '__blocked__'}
@@ -59,11 +58,9 @@ const BOTTOM_COMPONENT = {_reactKey: '__bottom_component__'}
type YieldedItem =
| ThreadPost
| typeof TOP_COMPONENT
| typeof PARENT_SPINNER
| typeof REPLY_PROMPT
| typeof DELETED
| typeof BLOCKED
| typeof PARENT_SPINNER
export function PostThread({
uri,
@@ -152,7 +149,7 @@ function PostThreadLoaded({
const {hasSession} = useSession()
const {_} = useLingui()
const pal = usePalette('default')
const {isTablet, isDesktop, isTabletOrMobile} = useWebMediaQueries()
const {isDesktop, isTabletOrMobile} = useWebMediaQueries()
const ref = useRef<ListMethods>(null)
const highlightedPostRef = useRef<View | null>(null)
const needsScrollAdjustment = useRef<boolean>(
@@ -168,13 +165,11 @@ function PostThreadLoaded({
// construct content
const posts = React.useMemo(() => {
let arr = [TOP_COMPONENT].concat(
Array.from(
flattenThreadSkeleton(
sortThread(thread, threadViewPrefs),
hasSession,
treeView,
),
let arr = Array.from(
flattenThreadSkeleton(
sortThread(thread, threadViewPrefs),
hasSession,
treeView,
),
)
if (arr.length > maxVisible) {
@@ -215,15 +210,9 @@ function PostThreadLoaded({
// wait for loading to finish
if (thread.type === 'post' && !!thread.parent) {
function onMeasure(pageY: number) {
let spinnerHeight = 0
if (isDesktop) {
spinnerHeight = 40
} else if (isTabletOrMobile) {
spinnerHeight = 82
}
ref.current?.scrollToOffset({
animated: false,
offset: pageY - spinnerHeight,
offset: pageY,
})
}
if (isNative) {
@@ -242,7 +231,7 @@ function PostThreadLoaded({
}
needsScrollAdjustment.current = false
}
}, [thread, isDesktop, isTabletOrMobile])
}, [thread])
const onPTR = React.useCallback(async () => {
setIsPTRing(true)
@@ -257,17 +246,11 @@ function PostThreadLoaded({
const renderItem = React.useCallback(
({item, index}: {item: YieldedItem; index: number}) => {
if (item === TOP_COMPONENT) {
return isTablet ? (
return isTabletOrMobile ? (
<ViewHeader
title={_(msg({message: `Post`, context: 'description'}))}
/>
) : null
} else if (item === PARENT_SPINNER) {
return (
<View style={styles.parentSpinner}>
<ActivityIndicator />
</View>
)
} else if (item === REPLY_PROMPT && hasSession) {
return (
<View>
@@ -318,7 +301,7 @@ function PostThreadLoaded({
// @ts-ignore web-only
style={{
// Leave enough space below that the scroll doesn't jump
height: isNative ? 400 : '100vh',
height: isNative ? 600 : '100vh',
borderTopWidth: 1,
borderColor: pal.colors.border,
}}
@@ -326,7 +309,7 @@ function PostThreadLoaded({
)
} else if (item === CHILD_SPINNER) {
return (
<View style={styles.childSpinner}>
<View style={[pal.border, styles.childSpinner]}>
<ActivityIndicator />
</View>
)
@@ -361,8 +344,8 @@ function PostThreadLoaded({
},
[
hasSession,
isTablet,
isDesktop,
isTabletOrMobile,
onPressReply,
pal.border,
pal.viewLight,
@@ -507,12 +490,15 @@ function* flattenThreadSkeleton(
node: ThreadNode,
hasSession: boolean,
treeView: boolean,
isTraversingReplies: boolean = false,
): Generator<YieldedItem, void> {
if (node.type === 'post') {
if (node.parent) {
yield* flattenThreadSkeleton(node.parent, hasSession, treeView)
} else if (node.ctx.isParentLoading) {
yield PARENT_SPINNER
if (!node.ctx.isParentLoading) {
if (node.parent) {
yield* flattenThreadSkeleton(node.parent, hasSession, treeView, false)
} else if (!isTraversingReplies) {
yield TOP_COMPONENT
}
}
if (!hasSession && node.ctx.depth > 0 && hasPwiOptOut(node)) {
return
@@ -523,7 +509,7 @@ function* flattenThreadSkeleton(
}
if (node.replies?.length) {
for (const reply of node.replies) {
yield* flattenThreadSkeleton(reply, hasSession, treeView)
yield* flattenThreadSkeleton(reply, hasSession, treeView, true)
if (!treeView && !node.ctx.isHighlightedPost) {
break
}
@@ -567,10 +553,9 @@ const styles = StyleSheet.create({
paddingHorizontal: 18,
paddingVertical: 18,
},
parentSpinner: {
paddingVertical: 10,
},
childSpinner: {
borderTopWidth: 1,
paddingTop: 40,
paddingBottom: 200,
},
})
+13 -2
View File
@@ -250,7 +250,13 @@ let PostThreadItemLoaded = ({
<View
testID={`postThreadItem-by-${post.author.handle}`}
style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]}
style={[
styles.outer,
styles.outerHighlighted,
pal.border,
pal.view,
rootUri === post.uri && styles.outerHighlightedRoot,
]}
accessible={false}>
<PostSandboxWarning />
<View style={styles.layout}>
@@ -726,10 +732,15 @@ const useStyles = () => {
paddingLeft: 8,
},
outerHighlighted: {
paddingTop: 16,
borderTopWidth: 0,
paddingTop: 4,
paddingLeft: 8,
paddingRight: 8,
},
outerHighlightedRoot: {
borderTopWidth: 1,
paddingTop: 16,
},
noTopBorder: {
borderTopWidth: 0,
},
-7
View File
@@ -5,7 +5,6 @@ import {useFocusEffect} from '@react-navigation/native'
import {useQueryClient} from '@tanstack/react-query'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {makeRecordUri} from 'lib/strings/url-helpers'
import {ViewHeader} from '../com/util/ViewHeader'
import {PostThread as PostThreadComponent} from '../com/post-thread/PostThread'
import {ComposePrompt} from 'view/com/composer/Prompt'
import {s} from 'lib/styles'
@@ -18,8 +17,6 @@ import {clamp} from 'lodash'
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
import {useSetMinimalShellMode} from '#/state/shell'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
import {useResolveUriQuery} from '#/state/queries/resolve-uri'
import {ErrorMessage} from '../com/util/error/ErrorMessage'
import {CenteredView} from '../com/util/Views'
@@ -30,7 +27,6 @@ import {isWeb} from '#/platform/detection'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
export function PostThreadScreen({route}: Props) {
const queryClient = useQueryClient()
const {_} = useLingui()
const {hasSession} = useSession()
const {fabMinimalShellTransform} = useMinimalShellMode()
const setMinimalShellMode = useSetMinimalShellMode()
@@ -79,9 +75,6 @@ export function PostThreadScreen({route}: Props) {
return (
<View style={s.hContentRegion}>
{isMobile && (
<ViewHeader title={_(msg({message: 'Post', context: 'description'}))} />
)}
<View style={s.flex1}>
{uriError ? (
<CenteredView>