about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-11-14 12:10:39 -0800
committerGitHub <noreply@github.com>2023-11-14 12:10:39 -0800
commit8e4a3ad5b6c5abac57559f5711261b9868eb0cd1 (patch)
treedaef1dca0312ae135a05cbdad209154ffe80b7c3
parent00f8c8b06d2f789c38c5c3416ec195072bbfd450 (diff)
downloadvoidsky-8e4a3ad5b6c5abac57559f5711261b9868eb0cd1.tar.zst
Add Shadow type (#1900)
-rw-r--r--src/state/cache/post-shadow.ts17
-rw-r--r--src/state/cache/profile-shadow.ts25
-rw-r--r--src/state/cache/types.ts1
-rw-r--r--src/view/com/auth/onboarding/RecommendedFollowsItem.tsx11
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx4
-rw-r--r--src/view/com/post/Post.tsx4
-rw-r--r--src/view/com/posts/FeedItem.tsx4
-rw-r--r--src/view/com/profile/ProfileHeader.tsx3
-rw-r--r--src/view/com/util/forms/PostDropdownBtn.tsx3
-rw-r--r--src/view/com/util/post-ctrls/PostCtrls.tsx3
10 files changed, 54 insertions, 21 deletions
diff --git a/src/state/cache/post-shadow.ts b/src/state/cache/post-shadow.ts
index c06ed60c4..c49097700 100644
--- a/src/state/cache/post-shadow.ts
+++ b/src/state/cache/post-shadow.ts
@@ -1,6 +1,8 @@
 import {useEffect, useState, useCallback, useRef} from 'react'
 import EventEmitter from 'eventemitter3'
 import {AppBskyFeedDefs} from '@atproto/api'
+import {Shadow} from './types'
+export type {Shadow} from './types'
 
 const emitter = new EventEmitter()
 
@@ -22,7 +24,7 @@ interface CacheEntry {
 export function usePostShadow(
   post: AppBskyFeedDefs.PostView,
   ifAfterTS: number,
-): AppBskyFeedDefs.PostView | typeof POST_TOMBSTONE {
+): Shadow<AppBskyFeedDefs.PostView> | typeof POST_TOMBSTONE {
   const [state, setState] = useState<CacheEntry>({
     ts: Date.now(),
     value: fromPost(post),
@@ -53,13 +55,21 @@ export function usePostShadow(
     firstRun.current = false
   }, [post])
 
-  return state.ts > ifAfterTS ? mergeShadow(post, state.value) : post
+  return state.ts > ifAfterTS
+    ? mergeShadow(post, state.value)
+    : {...post, isShadowed: true}
 }
 
 export function updatePostShadow(uri: string, value: Partial<PostShadow>) {
   emitter.emit(uri, value)
 }
 
+export function isPostShadowed(
+  v: AppBskyFeedDefs.PostView | Shadow<AppBskyFeedDefs.PostView>,
+): v is Shadow<AppBskyFeedDefs.PostView> {
+  return 'isShadowed' in v && !!v.isShadowed
+}
+
 function fromPost(post: AppBskyFeedDefs.PostView): PostShadow {
   return {
     likeUri: post.viewer?.like,
@@ -73,7 +83,7 @@ function fromPost(post: AppBskyFeedDefs.PostView): PostShadow {
 function mergeShadow(
   post: AppBskyFeedDefs.PostView,
   shadow: PostShadow,
-): AppBskyFeedDefs.PostView | typeof POST_TOMBSTONE {
+): Shadow<AppBskyFeedDefs.PostView> | typeof POST_TOMBSTONE {
   if (shadow.isDeleted) {
     return POST_TOMBSTONE
   }
@@ -86,5 +96,6 @@ function mergeShadow(
       like: shadow.likeUri,
       repost: shadow.repostUri,
     },
+    isShadowed: true,
   }
 }
diff --git a/src/state/cache/profile-shadow.ts b/src/state/cache/profile-shadow.ts
index a1cf59954..59f79634d 100644
--- a/src/state/cache/profile-shadow.ts
+++ b/src/state/cache/profile-shadow.ts
@@ -1,6 +1,8 @@
 import {useEffect, useState, useCallback, useRef} from 'react'
 import EventEmitter from 'eventemitter3'
 import {AppBskyActorDefs} from '@atproto/api'
+import {Shadow} from './types'
+export type {Shadow} from './types'
 
 const emitter = new EventEmitter()
 
@@ -20,10 +22,10 @@ type ProfileView =
   | AppBskyActorDefs.ProfileViewBasic
   | AppBskyActorDefs.ProfileViewDetailed
 
-export function useProfileShadow<T extends ProfileView>(
-  profile: T,
+export function useProfileShadow(
+  profile: ProfileView,
   ifAfterTS: number,
-): T {
+): Shadow<ProfileView> {
   const [state, setState] = useState<CacheEntry>({
     ts: Date.now(),
     value: fromProfile(profile),
@@ -54,7 +56,9 @@ export function useProfileShadow<T extends ProfileView>(
     firstRun.current = false
   }, [profile])
 
-  return state.ts > ifAfterTS ? mergeShadow(profile, state.value) : profile
+  return state.ts > ifAfterTS
+    ? mergeShadow(profile, state.value)
+    : {...profile, isShadowed: true}
 }
 
 export function updateProfileShadow(
@@ -64,6 +68,12 @@ export function updateProfileShadow(
   emitter.emit(uri, value)
 }
 
+export function isProfileShadowed<T extends ProfileView>(
+  v: T | Shadow<T>,
+): v is Shadow<T> {
+  return 'isShadowed' in v && !!v.isShadowed
+}
+
 function fromProfile(profile: ProfileView): ProfileShadow {
   return {
     followingUri: profile.viewer?.following,
@@ -72,10 +82,10 @@ function fromProfile(profile: ProfileView): ProfileShadow {
   }
 }
 
-function mergeShadow<T extends ProfileView>(
-  profile: T,
+function mergeShadow(
+  profile: ProfileView,
   shadow: ProfileShadow,
-): T {
+): Shadow<ProfileView> {
   return {
     ...profile,
     viewer: {
@@ -84,5 +94,6 @@ function mergeShadow<T extends ProfileView>(
       muted: shadow.muted,
       blocking: shadow.blockingUri,
     },
+    isShadowed: true,
   }
 }
diff --git a/src/state/cache/types.ts b/src/state/cache/types.ts
new file mode 100644
index 000000000..8bfcc867c
--- /dev/null
+++ b/src/state/cache/types.ts
@@ -0,0 +1 @@
+export type Shadow<T> = T & {isShadowed: true}
diff --git a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx
index f52b31213..144cc6cd4 100644
--- a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx
+++ b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx
@@ -13,7 +13,7 @@ import Animated, {FadeInRight} from 'react-native-reanimated'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {useAnalytics} from 'lib/analytics/analytics'
 import {Trans} from '@lingui/macro'
-import {useProfileShadow} from '#/state/cache/profile-shadow'
+import {Shadow, useProfileShadow} from '#/state/cache/profile-shadow'
 import {
   useProfileFollowMutation,
   useProfileUnfollowMutation,
@@ -66,7 +66,14 @@ export function ProfileCard({
   profile,
   onFollowStateChange,
   moderation,
-}: Omit<Props, 'dataUpdatedAt'>) {
+}: {
+  profile: Shadow<SuggestedActor>
+  moderation: ProfileModeration
+  onFollowStateChange: (props: {
+    did: string
+    following: boolean
+  }) => Promise<void>
+}) {
   const {track} = useAnalytics()
   const pal = usePalette('default')
   const [addingMoreSuggestions, setAddingMoreSuggestions] =
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index c81b762c3..0e2fb7080 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -37,9 +37,9 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {MAX_POST_LINES} from 'lib/constants'
 import {Trans} from '@lingui/macro'
 import {useLanguagePrefs} from '#/state/preferences'
-import {usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 import {useComposerControls} from '#/state/shell/composer'
 import {useModerationOpts} from '#/state/queries/preferences'
+import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 
 export function PostThreadItem({
   post,
@@ -132,7 +132,7 @@ function PostThreadItemLoaded({
   hasPrecedingItem,
   onPostReply,
 }: {
-  post: AppBskyFeedDefs.PostView
+  post: Shadow<AppBskyFeedDefs.PostView>
   record: AppBskyFeedPost.Record
   richText: RichTextAPI
   moderation: PostModeration
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index 09edbe12f..a2a0e62e6 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -25,8 +25,8 @@ import {makeProfileLink} from 'lib/routes/links'
 import {MAX_POST_LINES} from 'lib/constants'
 import {countLines} from 'lib/strings/helpers'
 import {useModerationOpts} from '#/state/queries/preferences'
-import {usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 import {useComposerControls} from '#/state/shell/composer'
+import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 
 export function Post({
   post,
@@ -89,7 +89,7 @@ function PostInner({
   showReplyLine,
   style,
 }: {
-  post: AppBskyFeedDefs.PostView
+  post: Shadow<AppBskyFeedDefs.PostView>
   record: AppBskyFeedPost.Record
   richText: RichTextAPI
   moderation: PostModeration
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 31981cc54..5bc173f00 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -32,8 +32,8 @@ import {makeProfileLink} from 'lib/routes/links'
 import {isEmbedByEmbedder} from 'lib/embeds'
 import {MAX_POST_LINES} from 'lib/constants'
 import {countLines} from 'lib/strings/helpers'
-import {usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 import {useComposerControls} from '#/state/shell/composer'
+import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 
 export function FeedItem({
   post,
@@ -93,7 +93,7 @@ function FeedItemInner({
   isThreadLastChild,
   isThreadParent,
 }: {
-  post: AppBskyFeedDefs.PostView
+  post: Shadow<AppBskyFeedDefs.PostView>
   record: AppBskyFeedPost.Record
   reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined
   richText: RichTextAPI
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index a228891a4..92d51ac70 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -54,9 +54,10 @@ import {shareUrl} from 'lib/sharing'
 import {s, colors} from 'lib/styles'
 import {logger} from '#/logger'
 import {useSession} from '#/state/session'
+import {Shadow} from '#/state/cache/types'
 
 interface Props {
-  profile: AppBskyActorDefs.ProfileViewDetailed
+  profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
   moderation: ProfileModeration
   hideBackButton?: boolean
   isProfilePreview?: boolean
diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx
index c457e0a46..dfaa77c1c 100644
--- a/src/view/com/util/forms/PostDropdownBtn.tsx
+++ b/src/view/com/util/forms/PostDropdownBtn.tsx
@@ -20,6 +20,7 @@ import {usePostDeleteMutation} from '#/state/queries/post'
 import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
 import {useLanguagePrefs} from '#/state/preferences'
 import {logger} from '#/logger'
+import {Shadow} from '#/state/cache/types'
 
 export function PostDropdownBtn({
   testID,
@@ -28,7 +29,7 @@ export function PostDropdownBtn({
   style,
 }: {
   testID: string
-  post: AppBskyFeedDefs.PostView
+  post: Shadow<AppBskyFeedDefs.PostView>
   record: AppBskyFeedPost.Record
   style?: StyleProp<ViewStyle>
 }) {
diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx
index 7e95bde87..120aecf45 100644
--- a/src/view/com/util/post-ctrls/PostCtrls.tsx
+++ b/src/view/com/util/post-ctrls/PostCtrls.tsx
@@ -24,6 +24,7 @@ import {
   usePostUnrepostMutation,
 } from '#/state/queries/post'
 import {useComposerControls} from '#/state/shell/composer'
+import {Shadow} from '#/state/cache/types'
 
 export function PostCtrls({
   big,
@@ -33,7 +34,7 @@ export function PostCtrls({
   onPressReply,
 }: {
   big?: boolean
-  post: AppBskyFeedDefs.PostView
+  post: Shadow<AppBskyFeedDefs.PostView>
   record: AppBskyFeedPost.Record
   style?: StyleProp<ViewStyle>
   onPressReply: () => void