EnHANCE
This commit is contained in:
@@ -1,73 +1,69 @@
|
|||||||
import {
|
import {createContext, useCallback, useContext, useId, useState} from 'react'
|
||||||
createContext,
|
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
useId,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react'
|
|
||||||
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
import {type AppBskyFeedDefs, AtUri} from '@atproto/api'
|
||||||
|
|
||||||
import {Logger} from '#/logger'
|
import {Logger} from '#/logger'
|
||||||
import {type FeedDescriptor} from '#/state/queries/post-feed'
|
import {type FeedDescriptor} from '#/state/queries/post-feed'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Separate logger for better debugging
|
||||||
|
*/
|
||||||
const logger = Logger.create(Logger.Context.PostSource)
|
const logger = Logger.create(Logger.Context.PostSource)
|
||||||
|
|
||||||
/**
|
export type PostSource = {
|
||||||
* For passing the source of the post (i.e. the original post, from the feed) to the threadview,
|
|
||||||
* without using query params. Deliberately unstable to avoid using query params, use for FeedFeedback
|
|
||||||
* and other ephemeral non-critical systems.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export type Source = {
|
|
||||||
post: AppBskyFeedDefs.FeedViewPost
|
post: AppBskyFeedDefs.FeedViewPost
|
||||||
feed?: FeedDescriptor
|
feed?: FeedDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
const SetUnstablePostSourceContext = createContext<
|
const SetUnstablePostSourceContext = createContext<
|
||||||
(uri: string, source: Source) => void
|
(key: string, source: PostSource) => void
|
||||||
>(() => {})
|
>(() => {})
|
||||||
const ConsumeUnstablePostSourceContext = createContext<
|
const ConsumeUnstablePostSourceContext = createContext<
|
||||||
(uri: string, id: string) => Source | undefined
|
(key: string, id: string) => PostSource | undefined
|
||||||
>(() => undefined)
|
>(() => undefined)
|
||||||
|
|
||||||
const persistentSourcesRef = new Map<string, Source>(new Map())
|
/**
|
||||||
|
* A cache of sources that will be consumed by the post thread view. This is
|
||||||
|
* cleaned up any time a source is consumed.
|
||||||
|
*/
|
||||||
|
const transientSourcesRef = new Map<string, PostSource>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache of sources that have been consumed by the post thread view. This is
|
||||||
|
* not cleaned up, but because we use a new ID for each post thread view that
|
||||||
|
* consumes a source, this is never reused unless a user navigates back to a
|
||||||
|
* post thread view that has not been dropped from memory.
|
||||||
|
*/
|
||||||
|
const consumedSourcesRef = new Map<string, PostSource>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For passing the source of the post (i.e. the original post, from the feed)
|
||||||
|
* to the threadview, without using query params. Deliberately unstable to
|
||||||
|
* avoid using query params, use for FeedFeedback and other ephemeral
|
||||||
|
* non-critical systems.
|
||||||
|
*/
|
||||||
export function Provider({children}: {children: React.ReactNode}) {
|
export function Provider({children}: {children: React.ReactNode}) {
|
||||||
const sourcesRef = useRef<Map<string, Source>>(new Map())
|
const setUnstablePostSource = useCallback(
|
||||||
|
(key: string, source: PostSource) => {
|
||||||
const setUnstablePostSource = useCallback((uri: string, source: Source) => {
|
assertValid(
|
||||||
if (__DEV__) {
|
key,
|
||||||
const urip = new AtUri(uri)
|
`setUnstablePostSource key should be a URI containing a handle, received ${key} — use buildPostSourceKey`,
|
||||||
if (urip.host.startsWith('did:')) {
|
|
||||||
throw new Error(
|
|
||||||
`URI passed to setUnstablePostSource should contain a handle — use buildPostSourceUri`,
|
|
||||||
)
|
)
|
||||||
}
|
logger.debug('set', {key, source})
|
||||||
}
|
transientSourcesRef.set(key, source)
|
||||||
|
},
|
||||||
logger.debug('set', {uri, source})
|
[],
|
||||||
sourcesRef.current.set(uri, source)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const consumeUnstablePostSource = useCallback((uri: string, id: string) => {
|
|
||||||
if (__DEV__) {
|
|
||||||
const urip = new AtUri(uri)
|
|
||||||
if (urip.host.startsWith('did:')) {
|
|
||||||
throw new Error(
|
|
||||||
`URI passed to consumeUnstablePostSource should contain a handle — use buildPostSourceUri`,
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = persistentSourcesRef.get(id) || sourcesRef.current.get(uri)
|
|
||||||
|
|
||||||
|
const consumeUnstablePostSource = useCallback((key: string, id: string) => {
|
||||||
|
assertValid(
|
||||||
|
key,
|
||||||
|
`consumeUnstablePostSource key should be a URI containing a handle, received ${key} — use buildPostSourceKey`,
|
||||||
|
)
|
||||||
|
const source = consumedSourcesRef.get(id) || transientSourcesRef.get(key)
|
||||||
if (source) {
|
if (source) {
|
||||||
logger.debug('consume', {uri, source})
|
logger.debug('consume', {key, source})
|
||||||
sourcesRef.current.delete(uri)
|
transientSourcesRef.delete(key)
|
||||||
persistentSourcesRef.set(id, source)
|
consumedSourcesRef.set(id, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
return source
|
return source
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -89,15 +85,28 @@ export function useSetUnstablePostSource() {
|
|||||||
* DANGER - This hook is unstable and should only be used for FeedFeedback
|
* DANGER - This hook is unstable and should only be used for FeedFeedback
|
||||||
* and other ephemeral non-critical systems. Does not change when the URI changes.
|
* and other ephemeral non-critical systems. Does not change when the URI changes.
|
||||||
*/
|
*/
|
||||||
export function useUnstablePostSource(uri: string) {
|
export function useUnstablePostSource(key: string) {
|
||||||
const id = useId()
|
const id = useId()
|
||||||
const consume = useContext(ConsumeUnstablePostSourceContext)
|
const consume = useContext(ConsumeUnstablePostSourceContext)
|
||||||
const [source] = useState(() => consume(uri, id))
|
const [source] = useState(() => consume(key, id))
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildPostSourceUri(uri: string, handle: string) {
|
/**
|
||||||
const urip = new AtUri(uri)
|
* Builds a post source key. This (atm) is a URI where the `host` is the post
|
||||||
|
* author's handle, not DID.
|
||||||
|
*/
|
||||||
|
export function buildPostSourceKey(key: string, handle: string) {
|
||||||
|
const urip = new AtUri(key)
|
||||||
urip.host = handle
|
urip.host = handle
|
||||||
return urip.toString()
|
return urip.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assertValid(key: string, message: string) {
|
||||||
|
if (__DEV__) {
|
||||||
|
const urip = new AtUri(key)
|
||||||
|
if (urip.host.startsWith('did:')) {
|
||||||
|
throw new Error(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import {useLanguagePrefs} from '#/state/preferences'
|
|||||||
import {type ThreadPost} from '#/state/queries/post-thread'
|
import {type ThreadPost} from '#/state/queries/post-thread'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {type Source} from '#/state/unstable-post-source'
|
import {type PostSource} from '#/state/unstable-post-source'
|
||||||
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
|
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
|
||||||
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
|
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
|
||||||
import {Link, TextLink} from '#/view/com/util/Link'
|
import {Link, TextLink} from '#/view/com/util/Link'
|
||||||
@@ -105,7 +105,7 @@ export function PostThreadItem({
|
|||||||
onPostReply: (postUri: string | undefined) => void
|
onPostReply: (postUri: string | undefined) => void
|
||||||
hideTopBorder?: boolean
|
hideTopBorder?: boolean
|
||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
anchorPostSource?: Source
|
anchorPostSource?: PostSource
|
||||||
}) {
|
}) {
|
||||||
const postShadowed = usePostShadow(post)
|
const postShadowed = usePostShadow(post)
|
||||||
const richText = useMemo(
|
const richText = useMemo(
|
||||||
@@ -206,7 +206,7 @@ let PostThreadItemLoaded = ({
|
|||||||
onPostReply: (postUri: string | undefined) => void
|
onPostReply: (postUri: string | undefined) => void
|
||||||
hideTopBorder?: boolean
|
hideTopBorder?: boolean
|
||||||
threadgateRecord?: AppBskyFeedThreadgate.Record
|
threadgateRecord?: AppBskyFeedThreadgate.Record
|
||||||
anchorPostSource?: Source
|
anchorPostSource?: PostSource
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {currentAccount, hasSession} = useSession()
|
const {currentAccount, hasSession} = useSession()
|
||||||
const feedFeedback = useFeedFeedback(anchorPostSource?.feed, hasSession)
|
const feedFeedback = useFeedFeedback(anchorPostSource?.feed, hasSession)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ import {unstableCacheProfileView} from '#/state/queries/profile'
|
|||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import {
|
import {
|
||||||
buildPostSourceUri,
|
buildPostSourceKey,
|
||||||
useSetUnstablePostSource,
|
useSetUnstablePostSource,
|
||||||
} from '#/state/unstable-post-source'
|
} from '#/state/unstable-post-source'
|
||||||
import {FeedNameText} from '#/view/com/util/FeedInfoText'
|
import {FeedNameText} from '#/view/com/util/FeedInfoText'
|
||||||
@@ -235,7 +235,7 @@ let FeedItemInner = ({
|
|||||||
reqId,
|
reqId,
|
||||||
})
|
})
|
||||||
unstableCacheProfileView(queryClient, post.author)
|
unstableCacheProfileView(queryClient, post.author)
|
||||||
unstableSetPostSource(buildPostSourceUri(post.uri, post.author.handle), {
|
unstableSetPostSource(buildPostSourceKey(post.uri, post.author.handle), {
|
||||||
feed: feedDescriptor,
|
feed: feedDescriptor,
|
||||||
post: {
|
post: {
|
||||||
post,
|
post,
|
||||||
|
|||||||
Reference in New Issue
Block a user