Use the RichText facets when copying post text (#2481)
* feat: serialize rich text to string * feat: wire richTextToString to copy post textzio/stable
parent
f7b01c3542
commit
0b2daa787c
|
@ -0,0 +1,29 @@
|
||||||
|
import {AppBskyRichtextFacet, RichText} from '@atproto/api'
|
||||||
|
import {linkRequiresWarning} from './url-helpers'
|
||||||
|
|
||||||
|
export function richTextToString(rt: RichText): string {
|
||||||
|
const {text, facets} = rt
|
||||||
|
|
||||||
|
if (!facets?.length) {
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = ''
|
||||||
|
|
||||||
|
for (const segment of rt.segments()) {
|
||||||
|
const link = segment.link
|
||||||
|
|
||||||
|
if (link && AppBskyRichtextFacet.validateLink(link).success) {
|
||||||
|
const href = link.uri
|
||||||
|
const text = segment.text
|
||||||
|
|
||||||
|
const requiresWarning = linkRequiresWarning(href, text)
|
||||||
|
|
||||||
|
result += !requiresWarning ? href : `[${text}](${href})`
|
||||||
|
} else {
|
||||||
|
result += segment.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -336,6 +336,7 @@ let PostThreadItemLoaded = ({
|
||||||
postCid={post.cid}
|
postCid={post.cid}
|
||||||
postUri={post.uri}
|
postUri={post.uri}
|
||||||
record={record}
|
record={record}
|
||||||
|
richText={richText}
|
||||||
showAppealLabelItem={
|
showAppealLabelItem={
|
||||||
post.author.did === currentAccount?.did && isModeratedPost
|
post.author.did === currentAccount?.did && isModeratedPost
|
||||||
}
|
}
|
||||||
|
@ -439,6 +440,7 @@ let PostThreadItemLoaded = ({
|
||||||
big
|
big
|
||||||
post={post}
|
post={post}
|
||||||
record={record}
|
record={record}
|
||||||
|
richText={richText}
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
@ -587,6 +589,7 @@ let PostThreadItemLoaded = ({
|
||||||
<PostCtrls
|
<PostCtrls
|
||||||
post={post}
|
post={post}
|
||||||
record={record}
|
record={record}
|
||||||
|
richText={richText}
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -213,7 +213,12 @@ function PostInner({
|
||||||
</ContentHider>
|
</ContentHider>
|
||||||
) : null}
|
) : null}
|
||||||
</ContentHider>
|
</ContentHider>
|
||||||
<PostCtrls post={post} record={record} onPressReply={onPressReply} />
|
<PostCtrls
|
||||||
|
post={post}
|
||||||
|
record={record}
|
||||||
|
richText={richText}
|
||||||
|
onPressReply={onPressReply}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -304,6 +304,7 @@ let FeedItemInner = ({
|
||||||
<PostCtrls
|
<PostCtrls
|
||||||
post={post}
|
post={post}
|
||||||
record={record}
|
record={record}
|
||||||
|
richText={richText}
|
||||||
onPressReply={onPressReply}
|
onPressReply={onPressReply}
|
||||||
showAppealLabelItem={
|
showAppealLabelItem={
|
||||||
post.author.did === currentAccount?.did && isModeratedPost
|
post.author.did === currentAccount?.did && isModeratedPost
|
||||||
|
|
|
@ -2,7 +2,12 @@ import React, {memo} from 'react'
|
||||||
import {Linking, StyleProp, View, ViewStyle} from 'react-native'
|
import {Linking, StyleProp, View, ViewStyle} from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {AppBskyActorDefs, AppBskyFeedPost, AtUri} from '@atproto/api'
|
import {
|
||||||
|
AppBskyActorDefs,
|
||||||
|
AppBskyFeedPost,
|
||||||
|
AtUri,
|
||||||
|
RichText as RichTextAPI,
|
||||||
|
} from '@atproto/api'
|
||||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
|
@ -24,6 +29,7 @@ import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
|
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||||
|
|
||||||
let PostDropdownBtn = ({
|
let PostDropdownBtn = ({
|
||||||
testID,
|
testID,
|
||||||
|
@ -31,6 +37,7 @@ let PostDropdownBtn = ({
|
||||||
postCid,
|
postCid,
|
||||||
postUri,
|
postUri,
|
||||||
record,
|
record,
|
||||||
|
richText,
|
||||||
style,
|
style,
|
||||||
showAppealLabelItem,
|
showAppealLabelItem,
|
||||||
}: {
|
}: {
|
||||||
|
@ -39,6 +46,7 @@ let PostDropdownBtn = ({
|
||||||
postCid: string
|
postCid: string
|
||||||
postUri: string
|
postUri: string
|
||||||
record: AppBskyFeedPost.Record
|
record: AppBskyFeedPost.Record
|
||||||
|
richText: RichTextAPI
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
showAppealLabelItem?: boolean
|
showAppealLabelItem?: boolean
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
|
@ -96,9 +104,11 @@ let PostDropdownBtn = ({
|
||||||
}, [rootUri, toggleThreadMute, _])
|
}, [rootUri, toggleThreadMute, _])
|
||||||
|
|
||||||
const onCopyPostText = React.useCallback(() => {
|
const onCopyPostText = React.useCallback(() => {
|
||||||
Clipboard.setString(record?.text || '')
|
const str = richTextToString(richText)
|
||||||
|
|
||||||
|
Clipboard.setString(str)
|
||||||
Toast.show(_(msg`Copied to clipboard`))
|
Toast.show(_(msg`Copied to clipboard`))
|
||||||
}, [record, _])
|
}, [_, richText])
|
||||||
|
|
||||||
const onOpenTranslate = React.useCallback(() => {
|
const onOpenTranslate = React.useCallback(() => {
|
||||||
Linking.openURL(translatorUrl)
|
Linking.openURL(translatorUrl)
|
||||||
|
|
|
@ -6,7 +6,11 @@ import {
|
||||||
View,
|
View,
|
||||||
ViewStyle,
|
ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import {AppBskyFeedDefs, AppBskyFeedPost} from '@atproto/api'
|
import {
|
||||||
|
AppBskyFeedDefs,
|
||||||
|
AppBskyFeedPost,
|
||||||
|
RichText as RichTextAPI,
|
||||||
|
} from '@atproto/api'
|
||||||
import {Text} from '../text/Text'
|
import {Text} from '../text/Text'
|
||||||
import {PostDropdownBtn} from '../forms/PostDropdownBtn'
|
import {PostDropdownBtn} from '../forms/PostDropdownBtn'
|
||||||
import {HeartIcon, HeartIconSolid, CommentBottomArrow} from 'lib/icons'
|
import {HeartIcon, HeartIconSolid, CommentBottomArrow} from 'lib/icons'
|
||||||
|
@ -33,6 +37,7 @@ let PostCtrls = ({
|
||||||
big,
|
big,
|
||||||
post,
|
post,
|
||||||
record,
|
record,
|
||||||
|
richText,
|
||||||
showAppealLabelItem,
|
showAppealLabelItem,
|
||||||
style,
|
style,
|
||||||
onPressReply,
|
onPressReply,
|
||||||
|
@ -40,6 +45,7 @@ let PostCtrls = ({
|
||||||
big?: boolean
|
big?: boolean
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>
|
post: Shadow<AppBskyFeedDefs.PostView>
|
||||||
record: AppBskyFeedPost.Record
|
record: AppBskyFeedPost.Record
|
||||||
|
richText: RichTextAPI
|
||||||
showAppealLabelItem?: boolean
|
showAppealLabelItem?: boolean
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
onPressReply: () => void
|
onPressReply: () => void
|
||||||
|
@ -212,6 +218,7 @@ let PostCtrls = ({
|
||||||
postCid={post.cid}
|
postCid={post.cid}
|
||||||
postUri={post.uri}
|
postUri={post.uri}
|
||||||
record={record}
|
record={record}
|
||||||
|
richText={richText}
|
||||||
showAppealLabelItem={showAppealLabelItem}
|
showAppealLabelItem={showAppealLabelItem}
|
||||||
style={styles.ctrlPad}
|
style={styles.ctrlPad}
|
||||||
/>
|
/>
|
||||||
|
|
Loading…
Reference in New Issue