From 22e1eb18c81b6f41927bc86d4726223c2634e19e Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 31 May 2024 18:43:04 +0300 Subject: [PATCH] =?UTF-8?q?[=F0=9F=90=B4]=20Record=20message=20(#4230)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * send record via link in text * re-trim text after removing link * record message * only show copy text if message + add translate * reduce padding * adjust padding * Tweak spacing * Stop clickthrough for hidden content * Update bg to show labels --------- Co-authored-by: Eric Bailey --- src/components/dms/MessageItem.tsx | 74 +++++++------ src/components/dms/MessageItemEmbed.tsx | 109 +++++++++++++++++++ src/components/dms/MessageMenu.tsx | 47 ++++++-- src/components/moderation/ContentHider.tsx | 17 +-- src/view/com/util/post-embeds/QuoteEmbed.tsx | 18 +-- src/view/com/util/post-embeds/index.tsx | 18 ++- 6 files changed, 225 insertions(+), 58 deletions(-) create mode 100644 src/components/dms/MessageItemEmbed.tsx diff --git a/src/components/dms/MessageItem.tsx b/src/components/dms/MessageItem.tsx index c5ff8109..b498ddf1 100644 --- a/src/components/dms/MessageItem.tsx +++ b/src/components/dms/MessageItem.tsx @@ -6,7 +6,11 @@ import { TextStyle, View, } from 'react-native' -import {ChatBskyConvoDefs, RichText as RichTextAPI} from '@atproto/api' +import { + AppBskyEmbedRecord, + ChatBskyConvoDefs, + RichText as RichTextAPI, +} from '@atproto/api' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -18,6 +22,7 @@ import {ActionsWrapper} from '#/components/dms/ActionsWrapper' import {InlineLinkText} from '#/components/Link' import {Text} from '#/components/Typography' import {RichText} from '../RichText' +import {MessageItemEmbed} from './MessageItemEmbed' let MessageItem = ({ item, @@ -77,37 +82,44 @@ let MessageItem = ({ return ( - - + )} + {rt.text.length > 0 && ( + - + a.py_sm, + a.my_2xs, + a.rounded_md, + { + paddingLeft: 14, + paddingRight: 14, + backgroundColor: isFromSelf + ? isPending + ? pendingColor + : t.palette.primary_500 + : t.palette.contrast_50, + borderRadius: 17, + }, + isFromSelf ? a.self_end : a.self_start, + isFromSelf + ? {borderBottomRightRadius: isLastInGroup ? 2 : 17} + : {borderBottomLeftRadius: isLastInGroup ? 2 : 17}, + ]}> + + + )} {isLastInGroup && ( diff --git a/src/components/dms/MessageItemEmbed.tsx b/src/components/dms/MessageItemEmbed.tsx new file mode 100644 index 00000000..d64563b9 --- /dev/null +++ b/src/components/dms/MessageItemEmbed.tsx @@ -0,0 +1,109 @@ +import React, {useMemo} from 'react' +import {View} from 'react-native' +import { + AppBskyEmbedRecord, + AppBskyFeedPost, + AtUri, + RichText as RichTextAPI, +} from '@atproto/api' + +import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' +import {makeProfileLink} from '#/lib/routes/links' +import {useModerationOpts} from '#/state/preferences/moderation-opts' +import {usePostQuery} from '#/state/queries/post' +import {PostEmbeds} from '#/view/com/util/post-embeds' +import {PostMeta} from '#/view/com/util/PostMeta' +import {atoms as a, useTheme} from '#/alf' +import {Link} from '#/components/Link' +import {ContentHider} from '#/components/moderation/ContentHider' +import {PostAlerts} from '#/components/moderation/PostAlerts' +import {RichText} from '#/components/RichText' + +let MessageItemEmbed = ({ + embed, +}: { + embed: AppBskyEmbedRecord.Main +}): React.ReactNode => { + const t = useTheme() + const {data: post} = usePostQuery(embed.record.uri) + + const moderationOpts = useModerationOpts() + const moderation = useMemo( + () => + moderationOpts && post ? moderatePost(post, moderationOpts) : undefined, + [moderationOpts, post], + ) + + const {rt, record} = useMemo(() => { + if ( + post && + AppBskyFeedPost.isRecord(post.record) && + AppBskyFeedPost.validateRecord(post.record).success + ) { + return { + rt: new RichTextAPI({ + text: post.record.text, + facets: post.record.facets, + }), + record: post.record, + } + } + + return {rt: undefined, record: undefined} + }, [post]) + + if (!post || !moderation || !rt || !record) { + return null + } + + const itemUrip = new AtUri(post.uri) + const itemHref = makeProfileLink(post.author, 'post', itemUrip.rkey) + + return ( + + + + + + {rt.text && ( + + + + )} + {post.embed && ( + + )} + + + + ) +} +MessageItemEmbed = React.memo(MessageItemEmbed) +export {MessageItemEmbed} diff --git a/src/components/dms/MessageMenu.tsx b/src/components/dms/MessageMenu.tsx index 21812d26..92913d1c 100644 --- a/src/components/dms/MessageMenu.tsx +++ b/src/components/dms/MessageMenu.tsx @@ -6,12 +6,16 @@ import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {richTextToString} from '#/lib/strings/rich-text-helpers' +import {getTranslatorLink} from '#/locale/helpers' +import {useLanguagePrefs} from '#/state/preferences' +import {useOpenLink} from '#/state/preferences/in-app-browser' import {isWeb} from 'platform/detection' import {useConvoActive} from 'state/messages/convo' import {useSession} from 'state/session' import * as Toast from '#/view/com/util/Toast' import {atoms as a, useTheme} from '#/alf' import {ReportDialog} from '#/components/dms/ReportDialog' +import {BubbleQuestion_Stroke2_Corner0_Rounded as Translate} from '#/components/icons/Bubble' import {DotGrid_Stroke2_Corner0_Rounded as DotsHorizontal} from '#/components/icons/DotGrid' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' @@ -35,10 +39,12 @@ export let MessageMenu = ({ const convo = useConvoActive() const deleteControl = usePromptControl() const reportControl = usePromptControl() + const langPrefs = useLanguagePrefs() + const openLink = useOpenLink() const isFromSelf = message.sender?.did === currentAccount?.did - const onCopyPostText = React.useCallback(() => { + const onCopyMessage = React.useCallback(() => { const str = richTextToString( new RichText({ text: message.text, @@ -51,6 +57,14 @@ export let MessageMenu = ({ Toast.show(_(msg`Copied to clipboard`)) }, [_, message.text, message.facets]) + const onPressTranslateMessage = React.useCallback(() => { + const translatorUrl = getTranslatorLink( + message.text, + langPrefs.primaryLanguage, + ) + openLink(translatorUrl) + }, [langPrefs.primaryLanguage, message.text, openLink]) + const onDelete = React.useCallback(() => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) convo @@ -81,16 +95,27 @@ export let MessageMenu = ({ )} - - - {_(msg`Copy message text`)} - - - - + {message.text.length > 0 && ( + <> + + + {_(msg`Translate`)} + + + + {_(msg`Copy message text`)} + + + + + + )}