Verification (#8226)
* WIP * Alignment with icon * Add create/remove prompts * Fill out check dialog a bit * Reorg * Handle was verified state * Add warning to edit profile * Add warning to handle dialog * Decent alignment in posts on all platforms * Refactor alignment for posts, chatlist, hover card * Disable on profile * Convo header * Compute simple verification state * Add other icon, rename, integrate * Swap in simple state for profile edits * Clean up utility hooks * Add verifications UI to dialog * Add edu nux * Revert change * Fix wrapping of check on profile * Rename * Fix gap under PostMeta * Update check dialogs * Handle takendown verifiers in check dialog * alf composer reply to * Refactor verification state * Add create/remove mutations, non-functional for now * Fix up post-rebase * Add check to first author noty * Do cache updates after mutations * DRY up hook, add to profile updates too * Add to drawer * Update account list * Adapt to new types * Hook up mutations * Use profile shadow in feeds * Add to settings * Shadow currentAccountProfile * Add invalid state to verifications * Fix alignment and overflow in Settings and Drawer * Re-integrate post rebase * Remove debug code * Update copy * Add unverified notification support * Remove link * Make sure dialog closes * Update URL * Add settings screen * Integrate new setting into verification states * Add metrics, bump package, fix bad import * NUX fixes * Update copy * Fixes * Update types * fix search autocomplete * fix lint * add display name warning to new dialog * update default prefs * Add parsing support for notifications * Bump pkg * Tweak noty styles * Adjust check alignment * Tweak check alignment * Fix badge for verifier * Modify copy --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com> Co-authored-by: Paul Frazee <pfrazee@gmail.com>
This commit is contained in:
@@ -49,7 +49,7 @@ import {Post} from '#/view/com/post/Post'
|
||||
import {formatCount} from '#/view/com/util/numeric/format'
|
||||
import {TimeElapsed} from '#/view/com/util/TimeElapsed'
|
||||
import {PreviewableUserAvatar, UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {atoms as a, platform, useTheme} from '#/alf'
|
||||
import {Button, ButtonText} from '#/components/Button'
|
||||
import {
|
||||
ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon,
|
||||
@@ -59,12 +59,15 @@ import {Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled} from '#/compon
|
||||
import {PersonPlus_Filled_Stroke2_Corner0_Rounded as PersonPlusIcon} from '#/components/icons/Person'
|
||||
import {Repost_Stroke2_Corner2_Rounded as RepostIcon} from '#/components/icons/Repost'
|
||||
import {StarterPack} from '#/components/icons/StarterPack'
|
||||
import {VerifiedCheck} from '#/components/icons/VerifiedCheck'
|
||||
import {InlineLinkText, Link} from '#/components/Link'
|
||||
import * as MediaPreview from '#/components/MediaPreview'
|
||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||
import {Notification as StarterPackCard} from '#/components/StarterPack/StarterPackCard'
|
||||
import {SubtleWebHover} from '#/components/SubtleWebHover'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
import * as bsky from '#/types/bsky'
|
||||
|
||||
const MAX_AUTHORS = 5
|
||||
@@ -145,6 +148,9 @@ let NotificationFeedItem = ({
|
||||
|
||||
const niceTimestamp = niceDate(i18n, item.notification.indexedAt)
|
||||
const firstAuthor = authors[0]
|
||||
const firstAuthorVerification = useSimpleVerificationState({
|
||||
profile: firstAuthor.profile,
|
||||
})
|
||||
const firstAuthorName = sanitizeDisplayName(
|
||||
firstAuthor.profile.displayName || firstAuthor.profile.handle,
|
||||
)
|
||||
@@ -186,6 +192,24 @@ let NotificationFeedItem = ({
|
||||
emoji
|
||||
label={_(msg`Go to ${firstAuthorName}'s profile`)}>
|
||||
{forceLTR(firstAuthorName)}
|
||||
{firstAuthorVerification.showBadge && (
|
||||
<View
|
||||
style={[
|
||||
a.relative,
|
||||
{
|
||||
paddingTop: platform({android: 2}),
|
||||
marginBottom: platform({ios: -7}),
|
||||
top: platform({web: 1}),
|
||||
paddingLeft: 3,
|
||||
paddingRight: 2,
|
||||
},
|
||||
]}>
|
||||
<VerificationCheck
|
||||
width={14}
|
||||
verifier={firstAuthorVerification.role === 'verifier'}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</InlineLinkText>
|
||||
)
|
||||
const additionalAuthorsCount = authors.length - 1
|
||||
@@ -366,6 +390,60 @@ let NotificationFeedItem = ({
|
||||
<StarterPack width={30} gradient="sky" />
|
||||
</View>
|
||||
)
|
||||
// @ts-ignore TODO
|
||||
} else if (item.type === 'verified') {
|
||||
a11yLabel = hasMultipleAuthors
|
||||
? _(
|
||||
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||
one: `${formattedAuthorsCount} other`,
|
||||
other: `${formattedAuthorsCount} others`,
|
||||
})} verified you`,
|
||||
)
|
||||
: _(msg`${firstAuthorName} verified you`)
|
||||
notificationContent = hasMultipleAuthors ? (
|
||||
<Trans>
|
||||
{firstAuthorLink} and{' '}
|
||||
<Text style={[pal.text, s.bold]}>
|
||||
<Plural
|
||||
value={additionalAuthorsCount}
|
||||
one={`${formattedAuthorsCount} other`}
|
||||
other={`${formattedAuthorsCount} others`}
|
||||
/>
|
||||
</Text>{' '}
|
||||
verified you
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>{firstAuthorLink} verified you</Trans>
|
||||
)
|
||||
icon = <VerifiedCheck size="xl" />
|
||||
// @ts-ignore TODO
|
||||
} else if (item.type === 'unverified') {
|
||||
a11yLabel = hasMultipleAuthors
|
||||
? _(
|
||||
msg`${firstAuthorName} and ${plural(additionalAuthorsCount, {
|
||||
one: `${formattedAuthorsCount} other`,
|
||||
other: `${formattedAuthorsCount} others`,
|
||||
})} removed their verifications from your account`,
|
||||
)
|
||||
: _(msg`${firstAuthorName} removed their verification from your account`)
|
||||
notificationContent = hasMultipleAuthors ? (
|
||||
<Trans>
|
||||
{firstAuthorLink} and{' '}
|
||||
<Text style={[pal.text, s.bold]}>
|
||||
<Plural
|
||||
value={additionalAuthorsCount}
|
||||
one={`${formattedAuthorsCount} other`}
|
||||
other={`${formattedAuthorsCount} others`}
|
||||
/>
|
||||
</Text>{' '}
|
||||
removed their verifications from your account
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>
|
||||
{firstAuthorLink} removed their verification from your account
|
||||
</Trans>
|
||||
)
|
||||
icon = <VerifiedCheck size="xl" fill={t.palette.contrast_500} />
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
@@ -447,7 +525,6 @@ let NotificationFeedItem = ({
|
||||
style={[
|
||||
a.flex_row,
|
||||
a.flex_wrap,
|
||||
a.pb_2xs,
|
||||
{paddingTop: 6},
|
||||
a.self_start,
|
||||
a.text_md,
|
||||
@@ -475,7 +552,9 @@ let NotificationFeedItem = ({
|
||||
</Text>
|
||||
</ExpandListPressable>
|
||||
{item.type === 'post-like' || item.type === 'repost' ? (
|
||||
<AdditionalPostText post={item.subject} />
|
||||
<View style={[a.pt_2xs]}>
|
||||
<AdditionalPostText post={item.subject} />
|
||||
</View>
|
||||
) : null}
|
||||
{item.type === 'feedgen-like' && item.subjectUri ? (
|
||||
<FeedSourceCard
|
||||
@@ -672,8 +751,6 @@ function ExpandedAuthorsList({
|
||||
visible: boolean
|
||||
authors: Author[]
|
||||
}) {
|
||||
const {_} = useLingui()
|
||||
const t = useTheme()
|
||||
const heightInterp = useAnimatedValue(visible ? 1 : 0)
|
||||
const targetHeight =
|
||||
authors.length * (EXPANDED_AUTHOR_EL_HEIGHT + 10) /*10=margin*/
|
||||
@@ -692,59 +769,78 @@ function ExpandedAuthorsList({
|
||||
<Animated.View style={[a.overflow_hidden, heightStyle]}>
|
||||
{visible &&
|
||||
authors.map(author => (
|
||||
<Link
|
||||
key={author.profile.did}
|
||||
label={author.profile.displayName || author.profile.handle}
|
||||
accessibilityHint={_(msg`Opens this profile`)}
|
||||
to={makeProfileLink({
|
||||
did: author.profile.did,
|
||||
handle: author.profile.handle,
|
||||
})}
|
||||
style={styles.expandedAuthor}>
|
||||
<View style={[a.mr_sm]}>
|
||||
<ProfileHoverCard did={author.profile.did}>
|
||||
<UserAvatar
|
||||
size={35}
|
||||
avatar={author.profile.avatar}
|
||||
moderation={author.moderation.ui('avatar')}
|
||||
type={author.profile.associated?.labeler ? 'labeler' : 'user'}
|
||||
/>
|
||||
</ProfileHoverCard>
|
||||
</View>
|
||||
<View style={[a.flex_1]}>
|
||||
<View style={[a.flex_row, a.align_end]}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
emoji
|
||||
style={[
|
||||
a.text_md,
|
||||
a.font_bold,
|
||||
a.leading_tight,
|
||||
{maxWidth: '70%'},
|
||||
]}>
|
||||
{sanitizeDisplayName(
|
||||
author.profile.displayName || author.profile.handle,
|
||||
)}
|
||||
</Text>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
a.pl_xs,
|
||||
a.text_md,
|
||||
a.leading_tight,
|
||||
a.flex_shrink,
|
||||
t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{sanitizeHandle(author.profile.handle, '@')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Link>
|
||||
<ExpandedAuthorCard key={author.profile.did} author={author} />
|
||||
))}
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
|
||||
function ExpandedAuthorCard({author}: {author: Author}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const verification = useSimpleVerificationState({
|
||||
profile: author.profile,
|
||||
})
|
||||
return (
|
||||
<Link
|
||||
key={author.profile.did}
|
||||
label={author.profile.displayName || author.profile.handle}
|
||||
accessibilityHint={_(msg`Opens this profile`)}
|
||||
to={makeProfileLink({
|
||||
did: author.profile.did,
|
||||
handle: author.profile.handle,
|
||||
})}
|
||||
style={styles.expandedAuthor}>
|
||||
<View style={[a.mr_sm]}>
|
||||
<ProfileHoverCard did={author.profile.did}>
|
||||
<UserAvatar
|
||||
size={35}
|
||||
avatar={author.profile.avatar}
|
||||
moderation={author.moderation.ui('avatar')}
|
||||
type={author.profile.associated?.labeler ? 'labeler' : 'user'}
|
||||
/>
|
||||
</ProfileHoverCard>
|
||||
</View>
|
||||
<View style={[a.flex_1]}>
|
||||
<View style={[a.flex_row, a.align_end]}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
emoji
|
||||
style={[
|
||||
a.text_md,
|
||||
a.font_bold,
|
||||
a.leading_tight,
|
||||
{maxWidth: '70%'},
|
||||
]}>
|
||||
{sanitizeDisplayName(
|
||||
author.profile.displayName || author.profile.handle,
|
||||
)}
|
||||
</Text>
|
||||
{verification.showBadge && (
|
||||
<View style={[a.pl_xs, a.self_center]}>
|
||||
<VerificationCheck
|
||||
width={14}
|
||||
verifier={verification.role === 'verifier'}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
a.pl_xs,
|
||||
a.text_md,
|
||||
a.leading_tight,
|
||||
a.flex_shrink,
|
||||
t.atoms.text_contrast_medium,
|
||||
]}>
|
||||
{sanitizeHandle(author.profile.handle, '@')}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
|
||||
const t = useTheme()
|
||||
if (
|
||||
@@ -761,7 +857,7 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
|
||||
{text?.length > 0 && (
|
||||
<Text
|
||||
emoji
|
||||
style={[a.text_md, a.leading_snug, t.atoms.text_contrast_medium]}>
|
||||
style={[a.text_sm, a.leading_snug, t.atoms.text_contrast_medium]}>
|
||||
{text}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user