From 6471e809aa28f0319bde4aa1f362679e3723d298 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Tue, 12 Nov 2024 21:02:41 +0000 Subject: [PATCH] Add backdated post indicator (#6156) * add backdate indicator * pill style * add indexedAt * update indicator - new copy, date in pill * complete alf migration * accidentally committed the missing indexedAt *again*! * copy tweak --- .../calendarClock_stroke2_corner0_rounded.svg | 1 + src/components/icons/CalendarClock.tsx | 5 + src/view/com/post-thread/PostThreadItem.tsx | 233 +++++++++++++----- 3 files changed, 171 insertions(+), 68 deletions(-) create mode 100644 assets/icons/calendarClock_stroke2_corner0_rounded.svg create mode 100644 src/components/icons/CalendarClock.tsx diff --git a/assets/icons/calendarClock_stroke2_corner0_rounded.svg b/assets/icons/calendarClock_stroke2_corner0_rounded.svg new file mode 100644 index 0000000000..e6535e0861 --- /dev/null +++ b/assets/icons/calendarClock_stroke2_corner0_rounded.svg @@ -0,0 +1 @@ + diff --git a/src/components/icons/CalendarClock.tsx b/src/components/icons/CalendarClock.tsx new file mode 100644 index 0000000000..52ba8094e0 --- /dev/null +++ b/src/components/icons/CalendarClock.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const CalendarClock_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M15.439 3.148a1 1 0 0 1 .41.645l.568 3.22a7 7 0 1 1-6.174 10.97L4.32 19.027a1 1 0 0 1-1.159-.811L1.078 6.398a1 1 0 0 1 .81-1.158l12.803-2.258a1 1 0 0 1 .748.166ZM9.325 16.114A7 7 0 0 1 9 14c0-1.56.51-3 1.372-4.164l-6.456 1.139 1.041 5.909 4.368-.77ZM3.568 9.005l10.833-1.91-.347-1.97L3.22 7.036l.347 1.97ZM16 9a5 5 0 1 0 0 10 5 5 0 0 0 0-10Zm0 2a1 1 0 0 1 1 1v1.586l1.374 1.374a1 1 0 0 1-1.414 1.414l-1.667-1.667A1 1 0 0 1 15 14v-2a1 1 0 0 1 1-1Z', +}) diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 5044f9621a..9edca4335d 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -1,5 +1,5 @@ import React, {memo, useMemo} from 'react' -import {StyleSheet, View} from 'react-native' +import {StyleSheet, Text as RNText, View} from 'react-native' import { AppBskyFeedDefs, AppBskyFeedPost, @@ -8,7 +8,6 @@ import { ModerationDecision, RichText as RichTextAPI, } from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {msg, Plural, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -21,6 +20,7 @@ import {sanitizeHandle} from '#/lib/strings/handles' import {countLines} from '#/lib/strings/helpers' import {niceDate} from '#/lib/strings/time' import {s} from '#/lib/styles' +import {getTranslatorLink, isPostInLanguage} from '#/locale/helpers' import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow' import {useLanguagePrefs} from '#/state/preferences' import {ThreadPost} from '#/state/queries/post-thread' @@ -28,26 +28,30 @@ import {useSession} from '#/state/session' import {useComposerControls} from '#/state/shell/composer' import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn' +import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' +import {Link, TextLink} from '#/view/com/util/Link' +import {formatCount} from '#/view/com/util/numeric/format' +import {PostCtrls} from '#/view/com/util/post-ctrls/PostCtrls' +import {PostEmbeds, PostEmbedViewContext} from '#/view/com/util/post-embeds' +import {PostMeta} from '#/view/com/util/PostMeta' +import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useTheme} from '#/alf' +import {colors} from '#/components/Admonition' +import {Button} from '#/components/Button' +import {CalendarClock_Stroke2_Corner0_Rounded as CalendarClockIcon} from '#/components/icons/CalendarClock' +import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron' +import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' import {InlineLinkText} from '#/components/Link' +import {ContentHider} from '#/components/moderation/ContentHider' +import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe' +import {PostAlerts} from '#/components/moderation/PostAlerts' +import {PostHider} from '#/components/moderation/PostHider' import {AppModerationCause} from '#/components/Pills' +import * as Prompt from '#/components/Prompt' import {RichText} from '#/components/RichText' import {SubtleWebHover} from '#/components/SubtleWebHover' -import {Text as NewText} from '#/components/Typography' -import {ContentHider} from '../../../components/moderation/ContentHider' -import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' -import {PostAlerts} from '../../../components/moderation/PostAlerts' -import {PostHider} from '../../../components/moderation/PostHider' -import {WhoCanReply} from '../../../components/WhoCanReply' -import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {Link, TextLink} from '../util/Link' -import {formatCount} from '../util/numeric/format' -import {PostCtrls} from '../util/post-ctrls/PostCtrls' -import {PostEmbeds, PostEmbedViewContext} from '../util/post-embeds' -import {PostMeta} from '../util/PostMeta' -import {Text} from '../util/text/Text' -import {PreviewableUserAvatar} from '../util/UserAvatar' +import {Text} from '#/components/Typography' +import {WhoCanReply} from '#/components/WhoCanReply' export function PostThreadItem({ post, @@ -125,19 +129,20 @@ export function PostThreadItem({ } function PostThreadItemDeleted({hideTopBorder}: {hideTopBorder?: boolean}) { - const pal = usePalette('default') + const t = useTheme() return ( - - + + This post has been deleted. @@ -308,7 +313,7 @@ let PostThreadItemLoaded = ({ /> - @@ -317,10 +322,10 @@ let PostThreadItemLoaded = ({ sanitizeHandle(post.author.handle), moderation.ui('displayName'), )} - + - {sanitizeHandle(post.author.handle, '@')} - + {currentAccount?.did !== post.author.did && ( @@ -393,48 +398,48 @@ let PostThreadItemLoaded = ({ ]}> {post.repostCount != null && post.repostCount !== 0 ? ( - - + {formatCount(i18n, post.repostCount)} - {' '} + {' '} - + ) : null} {post.quoteCount != null && post.quoteCount !== 0 && !post.viewer?.embeddingDisabled ? ( - - + {formatCount(i18n, post.quoteCount)} - {' '} + {' '} - + ) : null} {post.likeCount != null && post.likeCount !== 0 ? ( - - + {formatCount(i18n, post.likeCount)} - {' '} + {' '} - + ) : null} @@ -617,13 +622,13 @@ let PostThreadItemLoaded = ({ href={postHref} title={itemTitle} noFeedback> - + More - ) : undefined} @@ -732,32 +737,124 @@ function ExpandedPostDetails({ }, [openLink, translatorUrl]) return ( - - - {niceDate(i18n, post.indexedAt)} - - {isRootPost && ( - - )} - {needsTranslation && ( - <> - - · - + + + + + {niceDate(i18n, post.indexedAt)} + + {isRootPost && ( + + )} + {needsTranslation && ( + <> + + · + - - Translate - - - )} + + Translate + + + )} + ) } +function BackdatedPostIndicator({post}: {post: AppBskyFeedDefs.PostView}) { + const t = useTheme() + const {_, i18n} = useLingui() + const control = Prompt.usePromptControl() + + const indexedAt = new Date(post.indexedAt) + const createdAt = AppBskyFeedPost.isRecord(post.record) + ? new Date(post.record.createdAt) + : new Date(post.indexedAt) + + // backdated if createdAt is 24 hours or more before indexedAt + const isBackdated = + indexedAt.getTime() - createdAt.getTime() > 24 * 60 * 60 * 1000 + + if (!isBackdated) return null + + const orange = t.name === 'light' ? colors.warning.dark : colors.warning.light + + return ( + <> + + + + + Archived post + + + + This post claims to have been created on{' '} + {niceDate(i18n, createdAt)}, + but was first seen by Bluesky on{' '} + {niceDate(i18n, indexedAt)}. + + + + + Bluesky cannot confirm the authenticity of the claimed date. + + + + {}} /> + + + + ) +} + function getThreadAuthor( post: AppBskyFeedDefs.PostView, record: AppBskyFeedPost.Record,