Merge branch 'main' into starter-packs
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import React from 'react'
|
||||
import {View} from 'react-native'
|
||||
import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
|
||||
import {msg, plural, Trans} from '@lingui/macro'
|
||||
import {msg, Plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Link} from '#/components/Link'
|
||||
import {Link, LinkProps} from '#/components/Link'
|
||||
import {Text} from '#/components/Typography'
|
||||
|
||||
const AVI_SIZE = 30
|
||||
@@ -29,9 +29,11 @@ export function shouldShowKnownFollowers(
|
||||
export function KnownFollowers({
|
||||
profile,
|
||||
moderationOpts,
|
||||
onLinkPress,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
moderationOpts: ModerationOpts
|
||||
onLinkPress?: LinkProps['onPress']
|
||||
}) {
|
||||
const cache = React.useRef<Map<string, AppBskyActorDefs.KnownFollowers>>(
|
||||
new Map(),
|
||||
@@ -56,6 +58,7 @@ export function KnownFollowers({
|
||||
profile={profile}
|
||||
cachedKnownFollowers={cachedKnownFollowers}
|
||||
moderationOpts={moderationOpts}
|
||||
onLinkPress={onLinkPress}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -67,10 +70,12 @@ function KnownFollowersInner({
|
||||
profile,
|
||||
moderationOpts,
|
||||
cachedKnownFollowers,
|
||||
onLinkPress,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||
moderationOpts: ModerationOpts
|
||||
cachedKnownFollowers: AppBskyActorDefs.KnownFollowers
|
||||
onLinkPress?: LinkProps['onPress']
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
@@ -82,15 +87,6 @@ function KnownFollowersInner({
|
||||
t.atoms.text_contrast_medium,
|
||||
]
|
||||
|
||||
// list of users, minus blocks
|
||||
const returnedCount = cachedKnownFollowers.followers.length
|
||||
// db count, includes blocks
|
||||
const fullCount = cachedKnownFollowers.count
|
||||
// knownFollowers can return up to 5 users, but will exclude blocks
|
||||
// therefore, if we have less 5 users, use whichever count is lower
|
||||
const count =
|
||||
returnedCount < 5 ? Math.min(fullCount, returnedCount) : fullCount
|
||||
|
||||
const slice = cachedKnownFollowers.followers.slice(0, 3).map(f => {
|
||||
const moderation = moderateProfile(f, moderationOpts)
|
||||
return {
|
||||
@@ -104,12 +100,14 @@ function KnownFollowersInner({
|
||||
moderation,
|
||||
}
|
||||
})
|
||||
const count = cachedKnownFollowers.count - Math.min(slice.length, 2)
|
||||
|
||||
return (
|
||||
<Link
|
||||
label={_(
|
||||
msg`Press to view followers of this account that you also follow`,
|
||||
)}
|
||||
onPress={onLinkPress}
|
||||
to={makeProfileLink(profile, 'known-followers')}
|
||||
style={[
|
||||
a.flex_1,
|
||||
@@ -166,31 +164,37 @@ function KnownFollowersInner({
|
||||
},
|
||||
]}
|
||||
numberOfLines={2}>
|
||||
<Trans>Followed by</Trans>{' '}
|
||||
{count > 2 ? (
|
||||
<>
|
||||
{slice.slice(0, 2).map(({profile: prof}, i) => (
|
||||
<Text key={prof.did} style={textStyle}>
|
||||
{prof.displayName}
|
||||
{i === 0 && ', '}
|
||||
</Text>
|
||||
))}
|
||||
{', '}
|
||||
{plural(count - 2, {
|
||||
one: 'and # other',
|
||||
other: 'and # others',
|
||||
})}
|
||||
</>
|
||||
) : count === 2 ? (
|
||||
slice.map(({profile: prof}, i) => (
|
||||
<Text key={prof.did} style={textStyle}>
|
||||
{prof.displayName} {i === 0 ? _(msg`and`) + ' ' : ''}
|
||||
<Trans>
|
||||
Followed by{' '}
|
||||
<Text key={slice[0].profile.did} style={textStyle}>
|
||||
{slice[0].profile.displayName}
|
||||
</Text>
|
||||
))
|
||||
,{' '}
|
||||
<Text key={slice[1].profile.did} style={textStyle}>
|
||||
{slice[1].profile.displayName}
|
||||
</Text>
|
||||
, and{' '}
|
||||
<Plural value={count - 2} one="# other" other="# others" />
|
||||
</Trans>
|
||||
) : count === 2 ? (
|
||||
<Trans>
|
||||
Followed by{' '}
|
||||
<Text key={slice[0].profile.did} style={textStyle}>
|
||||
{slice[0].profile.displayName}
|
||||
</Text>{' '}
|
||||
and{' '}
|
||||
<Text key={slice[1].profile.did} style={textStyle}>
|
||||
{slice[1].profile.displayName}
|
||||
</Text>
|
||||
</Trans>
|
||||
) : (
|
||||
<Text key={slice[0].profile.did} style={textStyle}>
|
||||
{slice[0].profile.displayName}
|
||||
</Text>
|
||||
<Trans>
|
||||
Followed by{' '}
|
||||
<Text key={slice[0].profile.did} style={textStyle}>
|
||||
{slice[0].profile.displayName}
|
||||
</Text>
|
||||
</Trans>
|
||||
)}
|
||||
</Text>
|
||||
</>
|
||||
|
||||
@@ -5,6 +5,7 @@ import {flip, offset, shift, size, useFloating} from '@floating-ui/react-dom'
|
||||
import {msg, plural} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {getModerationCauseKey} from '#/lib/moderation'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
@@ -22,11 +23,16 @@ import {useFollowMethods} from '#/components/hooks/useFollowMethods'
|
||||
import {useRichText} from '#/components/hooks/useRichText'
|
||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||
import {
|
||||
KnownFollowers,
|
||||
shouldShowKnownFollowers,
|
||||
} from '#/components/KnownFollowers'
|
||||
import {InlineLinkText, Link} from '#/components/Link'
|
||||
import {Loader} from '#/components/Loader'
|
||||
import {Portal} from '#/components/Portal'
|
||||
import {RichText} from '#/components/RichText'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {ProfileLabel} from '../moderation/ProfileHeaderAlerts'
|
||||
import {ProfileHoverCardProps} from './types'
|
||||
|
||||
const floatingMiddlewares = [
|
||||
@@ -370,7 +376,10 @@ function Inner({
|
||||
profile: profileShadow,
|
||||
logContext: 'ProfileHoverCard',
|
||||
})
|
||||
const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
|
||||
const isBlockedUser =
|
||||
profile.viewer?.blocking ||
|
||||
profile.viewer?.blockedBy ||
|
||||
profile.viewer?.blockingByList
|
||||
const following = formatCount(profile.followsCount || 0)
|
||||
const followers = formatCount(profile.followersCount || 0)
|
||||
const pluralizedFollowers = plural(profile.followersCount || 0, {
|
||||
@@ -401,29 +410,41 @@ function Inner({
|
||||
/>
|
||||
</Link>
|
||||
|
||||
{!isMe && (
|
||||
<Button
|
||||
size="small"
|
||||
color={profileShadow.viewer?.following ? 'secondary' : 'primary'}
|
||||
variant="solid"
|
||||
label={
|
||||
profileShadow.viewer?.following
|
||||
? _(msg`Following`)
|
||||
: _(msg`Follow`)
|
||||
}
|
||||
style={[a.rounded_full]}
|
||||
onPress={profileShadow.viewer?.following ? unfollow : follow}>
|
||||
<ButtonIcon
|
||||
position="left"
|
||||
icon={profileShadow.viewer?.following ? Check : Plus}
|
||||
/>
|
||||
<ButtonText>
|
||||
{profileShadow.viewer?.following
|
||||
? _(msg`Following`)
|
||||
: _(msg`Follow`)}
|
||||
</ButtonText>
|
||||
</Button>
|
||||
)}
|
||||
{!isMe &&
|
||||
(isBlockedUser ? (
|
||||
<Link
|
||||
to={profileURL}
|
||||
label={_(msg`View blocked user's profile`)}
|
||||
onPress={hide}
|
||||
size="small"
|
||||
color="secondary"
|
||||
variant="solid"
|
||||
style={[a.rounded_full]}>
|
||||
<ButtonText>{_(msg`View profile`)}</ButtonText>
|
||||
</Link>
|
||||
) : (
|
||||
<Button
|
||||
size="small"
|
||||
color={profileShadow.viewer?.following ? 'secondary' : 'primary'}
|
||||
variant="solid"
|
||||
label={
|
||||
profileShadow.viewer?.following
|
||||
? _(msg`Following`)
|
||||
: _(msg`Follow`)
|
||||
}
|
||||
style={[a.rounded_full]}
|
||||
onPress={profileShadow.viewer?.following ? unfollow : follow}>
|
||||
<ButtonIcon
|
||||
position="left"
|
||||
icon={profileShadow.viewer?.following ? Check : Plus}
|
||||
/>
|
||||
<ButtonText>
|
||||
{profileShadow.viewer?.following
|
||||
? _(msg`Following`)
|
||||
: _(msg`Follow`)}
|
||||
</ButtonText>
|
||||
</Button>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<Link to={profileURL} label={_(msg`View profile`)} onPress={hide}>
|
||||
@@ -439,7 +460,19 @@ function Inner({
|
||||
</View>
|
||||
</Link>
|
||||
|
||||
{!blockHide && (
|
||||
{isBlockedUser && (
|
||||
<View style={[a.flex_row, a.flex_wrap, a.gap_xs]}>
|
||||
{moderation.ui('profileView').alerts.map(cause => (
|
||||
<ProfileLabel
|
||||
key={getModerationCauseKey(cause)}
|
||||
cause={cause}
|
||||
disableDetailsDialog
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
|
||||
{!isBlockedUser && (
|
||||
<>
|
||||
<View style={[a.flex_row, a.flex_wrap, a.gap_md, a.pt_xs]}>
|
||||
<InlineLinkText
|
||||
@@ -473,6 +506,17 @@ function Inner({
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
|
||||
{!isMe &&
|
||||
shouldShowKnownFollowers(profile.viewer?.knownFollowers) && (
|
||||
<View style={[a.flex_row, a.align_center, a.gap_sm, a.pt_md]}>
|
||||
<KnownFollowers
|
||||
profile={profile}
|
||||
moderationOpts={moderationOpts}
|
||||
onLinkPress={hide}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -43,7 +43,13 @@ export function ProfileHeaderAlerts({
|
||||
)
|
||||
}
|
||||
|
||||
function ProfileLabel({cause}: {cause: ModerationCause}) {
|
||||
export function ProfileLabel({
|
||||
cause,
|
||||
disableDetailsDialog,
|
||||
}: {
|
||||
cause: ModerationCause
|
||||
disableDetailsDialog?: boolean
|
||||
}) {
|
||||
const t = useTheme()
|
||||
const control = useModerationDetailsDialogControl()
|
||||
const desc = useModerationCauseDescription(cause)
|
||||
@@ -51,6 +57,7 @@ function ProfileLabel({cause}: {cause: ModerationCause}) {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
disabled={disableDetailsDialog}
|
||||
label={desc.name}
|
||||
onPress={() => {
|
||||
control.open()
|
||||
@@ -87,7 +94,9 @@ function ProfileLabel({cause}: {cause: ModerationCause}) {
|
||||
)}
|
||||
</Button>
|
||||
|
||||
<ModerationDetailsDialog control={control} modcause={cause} />
|
||||
{!disableDetailsDialog && (
|
||||
<ModerationDetailsDialog control={control} modcause={cause} />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ type StatsigUser = {
|
||||
bundleDate: number
|
||||
refSrc: string
|
||||
refUrl: string
|
||||
referrer: string
|
||||
referrerHostname: string
|
||||
appLanguage: string
|
||||
contentLanguages: string[]
|
||||
}
|
||||
@@ -33,12 +35,29 @@ type StatsigUser = {
|
||||
|
||||
let refSrc = ''
|
||||
let refUrl = ''
|
||||
let referrer = ''
|
||||
let referrerHostname = ''
|
||||
if (isWeb && typeof window !== 'undefined') {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
refSrc = params.get('ref_src') ?? ''
|
||||
refUrl = decodeURIComponent(params.get('ref_url') ?? '')
|
||||
}
|
||||
|
||||
if (
|
||||
isWeb &&
|
||||
typeof document !== 'undefined' &&
|
||||
document != null &&
|
||||
document.referrer
|
||||
) {
|
||||
try {
|
||||
const url = new URL(document.referrer)
|
||||
if (url.hostname !== 'bsky.app') {
|
||||
referrer = document.referrer
|
||||
referrerHostname = url.hostname
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
export type {LogEvents}
|
||||
|
||||
function createStatsigOptions(prefetchUsers: StatsigUser[]) {
|
||||
@@ -198,6 +217,8 @@ function toStatsigUser(did: string | undefined): StatsigUser {
|
||||
custom: {
|
||||
refSrc,
|
||||
refUrl,
|
||||
referrer,
|
||||
referrerHostname,
|
||||
platform: Platform.OS as 'ios' | 'android' | 'web',
|
||||
bundleIdentifier: BUNDLE_IDENTIFIER,
|
||||
bundleDate: BUNDLE_DATE,
|
||||
|
||||
@@ -75,6 +75,10 @@ let ProfileHeaderStandard = ({
|
||||
const [_queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
|
||||
const unblockPromptControl = Prompt.usePromptControl()
|
||||
const requireAuth = useRequireAuth()
|
||||
const isBlockedUser =
|
||||
profile.viewer?.blocking ||
|
||||
profile.viewer?.blockedBy ||
|
||||
profile.viewer?.blockingByList
|
||||
|
||||
const onPressEditProfile = React.useCallback(() => {
|
||||
track('ProfileHeader:EditProfileButtonClicked')
|
||||
@@ -257,7 +261,7 @@ let ProfileHeaderStandard = ({
|
||||
<ProfileHeaderDisplayName profile={profile} moderation={moderation} />
|
||||
<ProfileHeaderHandle profile={profile} />
|
||||
</View>
|
||||
{!isPlaceholderProfile && (
|
||||
{!isPlaceholderProfile && !isBlockedUser && (
|
||||
<>
|
||||
<ProfileHeaderMetrics profile={profile} />
|
||||
{descriptionRT && !moderation.ui('profileView').blur ? (
|
||||
@@ -274,6 +278,7 @@ let ProfileHeaderStandard = ({
|
||||
) : undefined}
|
||||
|
||||
{!isMe &&
|
||||
!isBlockedUser &&
|
||||
shouldShowKnownFollowers(profile.viewer?.knownFollowers) && (
|
||||
<View style={[a.flex_row, a.align_center, a.gap_sm, a.pt_md]}>
|
||||
<KnownFollowers
|
||||
|
||||
@@ -94,6 +94,7 @@ export function usePrefetchProfileQuery() {
|
||||
const prefetchProfileQuery = useCallback(
|
||||
async (did: string) => {
|
||||
await queryClient.prefetchQuery({
|
||||
staleTime: STALE.SECONDS.THIRTY,
|
||||
queryKey: RQKEY(did),
|
||||
queryFn: async () => {
|
||||
const res = await agent.getProfile({actor: did || ''})
|
||||
|
||||
@@ -415,12 +415,14 @@ export const ComposePost = observer(function ComposePost({
|
||||
bottomBarAnimatedStyle,
|
||||
} = useAnimatedBorders()
|
||||
|
||||
const keyboardVerticalOffset = useKeyboardVerticalOffset()
|
||||
|
||||
return (
|
||||
<KeyboardAvoidingView
|
||||
testID="composePostView"
|
||||
behavior={isIOS ? 'padding' : 'height'}
|
||||
keyboardVerticalOffset={isIOS ? 70 : 0}
|
||||
style={[a.flex_1]}>
|
||||
keyboardVerticalOffset={keyboardVerticalOffset}
|
||||
style={a.flex_1}>
|
||||
<View style={[a.flex_1, viewStyles]} aria-modal accessibilityViewIsModal>
|
||||
<Animated.View style={topBarAnimatedStyle}>
|
||||
<View style={styles.topbarInner}>
|
||||
@@ -741,6 +743,19 @@ function useAnimatedBorders() {
|
||||
}
|
||||
}
|
||||
|
||||
function useKeyboardVerticalOffset() {
|
||||
const {top} = useSafeAreaInsets()
|
||||
|
||||
// Android etc
|
||||
if (!isIOS) return 0
|
||||
|
||||
// iPhone SE
|
||||
if (top === 20) return 40
|
||||
|
||||
// all other iPhones
|
||||
return top + 10
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
topbarInner: {
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -150,16 +150,27 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
||||
attributes: {
|
||||
class: modeClass,
|
||||
},
|
||||
handlePaste: (_, event) => {
|
||||
const items = event.clipboardData?.items
|
||||
handlePaste: (view, event) => {
|
||||
const clipboardData = event.clipboardData
|
||||
|
||||
if (items === undefined) {
|
||||
return
|
||||
if (clipboardData) {
|
||||
if (clipboardData.types.includes('text/html')) {
|
||||
// Rich-text formatting is pasted, try retrieving plain text
|
||||
const text = clipboardData.getData('text/plain')
|
||||
|
||||
// `pasteText` will invoke this handler again, but `clipboardData` will be null.
|
||||
view.pasteText(text)
|
||||
|
||||
// Return `true` to prevent ProseMirror's default paste behavior.
|
||||
return true
|
||||
} else {
|
||||
// Otherwise, try retrieving images from the clipboard
|
||||
|
||||
getImageFromUri(clipboardData.items, (uri: string) => {
|
||||
textInputWebEmitter.emit('photo-pasted', uri)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
getImageFromUri(items, (uri: string) => {
|
||||
textInputWebEmitter.emit('photo-pasted', uri)
|
||||
})
|
||||
},
|
||||
handleKeyDown: (_, event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.code === 'Enter') {
|
||||
|
||||
@@ -71,8 +71,11 @@ let ProfileMenu = ({
|
||||
const loggedOutWarningPromptControl = Prompt.usePromptControl()
|
||||
|
||||
const showLoggedOutWarning = React.useMemo(() => {
|
||||
return !!profile.labels?.find(label => label.val === '!no-unauthenticated')
|
||||
}, [profile.labels])
|
||||
return (
|
||||
profile.did !== currentAccount?.did &&
|
||||
!!profile.labels?.find(label => label.val === '!no-unauthenticated')
|
||||
)
|
||||
}, [currentAccount, profile])
|
||||
|
||||
const invalidateProfileQuery = React.useCallback(() => {
|
||||
queryClient.invalidateQueries({
|
||||
|
||||
@@ -11,6 +11,7 @@ import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {niceDate} from 'lib/strings/time'
|
||||
import {TypographyVariant} from 'lib/ThemeContext'
|
||||
import {isAndroid, isWeb} from 'platform/detection'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||
import {TextLinkOnWebOnly} from './Link'
|
||||
import {Text} from './text/Text'
|
||||
@@ -39,9 +40,13 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||
const prefetchProfileQuery = usePrefetchProfileQuery()
|
||||
|
||||
const profileLink = makeProfileLink(opts.author)
|
||||
const onPointerEnter = isWeb
|
||||
? () => prefetchProfileQuery(opts.author.did)
|
||||
: undefined
|
||||
const prefetchedProfile = React.useRef(false)
|
||||
const onPointerMove = React.useCallback(() => {
|
||||
if (!prefetchedProfile.current) {
|
||||
prefetchedProfile.current = true
|
||||
prefetchProfileQuery(opts.author.did)
|
||||
}
|
||||
}, [opts.author.did, prefetchProfileQuery])
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const onOpenAuthor = opts.onOpenAuthor
|
||||
@@ -66,37 +71,39 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||
</View>
|
||||
)}
|
||||
<ProfileHoverCard inline did={opts.author.did}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[styles.maxWidth, pal.textLight, opts.displayNameStyle]}>
|
||||
<TextLinkOnWebOnly
|
||||
type={opts.displayNameType || 'lg-bold'}
|
||||
style={[pal.text]}
|
||||
lineHeight={1.2}
|
||||
disableMismatchWarning
|
||||
text={
|
||||
<>
|
||||
{sanitizeDisplayName(
|
||||
displayName,
|
||||
opts.moderation?.ui('displayName'),
|
||||
)}
|
||||
</>
|
||||
}
|
||||
href={profileLink}
|
||||
onBeforePress={onBeforePressAuthor}
|
||||
onPointerEnter={onPointerEnter}
|
||||
/>
|
||||
<TextLinkOnWebOnly
|
||||
type="md"
|
||||
disableMismatchWarning
|
||||
style={[pal.textLight, {flexShrink: 4}]}
|
||||
text={'\xa0' + sanitizeHandle(handle, '@')}
|
||||
href={profileLink}
|
||||
onBeforePress={onBeforePressAuthor}
|
||||
onPointerEnter={onPointerEnter}
|
||||
anchorNoUnderline
|
||||
/>
|
||||
</Text>
|
||||
<View
|
||||
onPointerMove={isWeb ? onPointerMove : undefined}
|
||||
style={[a.flex_1]}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={[styles.maxWidth, pal.textLight, opts.displayNameStyle]}>
|
||||
<TextLinkOnWebOnly
|
||||
type={opts.displayNameType || 'lg-bold'}
|
||||
style={[pal.text]}
|
||||
lineHeight={1.2}
|
||||
disableMismatchWarning
|
||||
text={
|
||||
<>
|
||||
{sanitizeDisplayName(
|
||||
displayName,
|
||||
opts.moderation?.ui('displayName'),
|
||||
)}
|
||||
</>
|
||||
}
|
||||
href={profileLink}
|
||||
onBeforePress={onBeforePressAuthor}
|
||||
/>
|
||||
<TextLinkOnWebOnly
|
||||
type="md"
|
||||
disableMismatchWarning
|
||||
style={[pal.textLight, {flexShrink: 4}]}
|
||||
text={'\xa0' + sanitizeHandle(handle, '@')}
|
||||
href={profileLink}
|
||||
onBeforePress={onBeforePressAuthor}
|
||||
anchorNoUnderline
|
||||
/>
|
||||
</Text>
|
||||
</View>
|
||||
</ProfileHoverCard>
|
||||
{!isAndroid && (
|
||||
<Text
|
||||
|
||||
@@ -196,6 +196,9 @@ let PostDropdownBtn = ({
|
||||
)
|
||||
}, [postAuthor])
|
||||
|
||||
const showLoggedOutWarning =
|
||||
postAuthor.did !== currentAccount?.did && hideInPWI
|
||||
|
||||
const onSharePost = React.useCallback(() => {
|
||||
const url = toShareUrl(href)
|
||||
shareUrl(url)
|
||||
@@ -296,7 +299,7 @@ let PostDropdownBtn = ({
|
||||
testID="postDropdownShareBtn"
|
||||
label={isWeb ? _(msg`Copy link to post`) : _(msg`Share`)}
|
||||
onPress={() => {
|
||||
if (hideInPWI) {
|
||||
if (showLoggedOutWarning) {
|
||||
loggedOutWarningPromptControl.open()
|
||||
} else {
|
||||
onSharePost()
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
usePostLikeMutationQueue,
|
||||
usePostRepostMutationQueue,
|
||||
} from '#/state/queries/post'
|
||||
import {useRequireAuth} from '#/state/session'
|
||||
import {useRequireAuth, useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
@@ -64,6 +64,7 @@ let PostCtrls = ({
|
||||
const t = useTheme()
|
||||
const {_} = useLingui()
|
||||
const {openComposer} = useComposerControls()
|
||||
const {currentAccount} = useSession()
|
||||
const [queueLike, queueUnlike] = usePostLikeMutationQueue(post, logContext)
|
||||
const [queueRepost, queueUnrepost] = usePostRepostMutationQueue(
|
||||
post,
|
||||
@@ -75,10 +76,11 @@ let PostCtrls = ({
|
||||
const playHaptic = useHaptics()
|
||||
|
||||
const shouldShowLoggedOutWarning = React.useMemo(() => {
|
||||
return !!post.author.labels?.find(
|
||||
label => label.val === '!no-unauthenticated',
|
||||
return (
|
||||
post.author.did !== currentAccount?.did &&
|
||||
!!post.author.labels?.find(label => label.val === '!no-unauthenticated')
|
||||
)
|
||||
}, [post])
|
||||
}, [currentAccount, post])
|
||||
|
||||
const defaultCtrlColor = React.useMemo(
|
||||
() => ({
|
||||
|
||||
Reference in New Issue
Block a user