diff options
Diffstat (limited to 'src/view/com/util/forms/PostDropdownBtn2.tsx')
-rw-r--r-- | src/view/com/util/forms/PostDropdownBtn2.tsx | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/view/com/util/forms/PostDropdownBtn2.tsx b/src/view/com/util/forms/PostDropdownBtn2.tsx new file mode 100644 index 000000000..c457e0a46 --- /dev/null +++ b/src/view/com/util/forms/PostDropdownBtn2.tsx @@ -0,0 +1,210 @@ +import React from 'react' +import {Linking, StyleProp, View, ViewStyle} from 'react-native' +import Clipboard from '@react-native-clipboard/clipboard' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {AppBskyFeedDefs, AppBskyFeedPost, AtUri} from '@atproto/api' +import {toShareUrl} from 'lib/strings/url-helpers' +import {useTheme} from 'lib/ThemeContext' +import {shareUrl} from 'lib/sharing' +import { + NativeDropdown, + DropdownItem as NativeDropdownItem, +} from './NativeDropdown' +import * as Toast from '../Toast' +import {EventStopper} from '../EventStopper' +import {useModalControls} from '#/state/modals' +import {makeProfileLink} from '#/lib/routes/links' +import {getTranslatorLink} from '#/locale/helpers' +import {useStores} from '#/state' +import {usePostDeleteMutation} from '#/state/queries/post' +import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads' +import {useLanguagePrefs} from '#/state/preferences' +import {logger} from '#/logger' + +export function PostDropdownBtn({ + testID, + post, + record, + style, +}: { + testID: string + post: AppBskyFeedDefs.PostView + record: AppBskyFeedPost.Record + style?: StyleProp<ViewStyle> +}) { + const store = useStores() + const theme = useTheme() + const defaultCtrlColor = theme.palette.default.postCtrl + const {openModal} = useModalControls() + const langPrefs = useLanguagePrefs() + const mutedThreads = useMutedThreads() + const toggleThreadMute = useToggleThreadMute() + const postDeleteMutation = usePostDeleteMutation() + + const rootUri = record.reply?.root?.uri || post.uri + const isThreadMuted = mutedThreads.includes(rootUri) + const isAuthor = post.author.did === store.me.did + const href = React.useMemo(() => { + const urip = new AtUri(post.uri) + return makeProfileLink(post.author, 'post', urip.rkey) + }, [post.uri, post.author]) + + const translatorUrl = getTranslatorLink( + record.text, + langPrefs.primaryLanguage, + ) + + const onDeletePost = React.useCallback(() => { + postDeleteMutation.mutateAsync({uri: post.uri}).then( + () => { + Toast.show('Post deleted') + }, + e => { + logger.error('Failed to delete post', {error: e}) + Toast.show('Failed to delete post, please try again') + }, + ) + }, [post, postDeleteMutation]) + + const onToggleThreadMute = React.useCallback(() => { + try { + const muted = toggleThreadMute(rootUri) + if (muted) { + Toast.show('You will no longer receive notifications for this thread') + } else { + Toast.show('You will now receive notifications for this thread') + } + } catch (e) { + logger.error('Failed to toggle thread mute', {error: e}) + } + }, [rootUri, toggleThreadMute]) + + const onCopyPostText = React.useCallback(() => { + Clipboard.setString(record?.text || '') + Toast.show('Copied to clipboard') + }, [record]) + + const onOpenTranslate = React.useCallback(() => { + Linking.openURL(translatorUrl) + }, [translatorUrl]) + + const dropdownItems: NativeDropdownItem[] = [ + { + label: 'Translate', + onPress() { + onOpenTranslate() + }, + testID: 'postDropdownTranslateBtn', + icon: { + ios: { + name: 'character.book.closed', + }, + android: 'ic_menu_sort_alphabetically', + web: 'language', + }, + }, + { + label: 'Copy post text', + onPress() { + onCopyPostText() + }, + testID: 'postDropdownCopyTextBtn', + icon: { + ios: { + name: 'doc.on.doc', + }, + android: 'ic_menu_edit', + web: ['far', 'paste'], + }, + }, + { + label: 'Share', + onPress() { + const url = toShareUrl(href) + shareUrl(url) + }, + testID: 'postDropdownShareBtn', + icon: { + ios: { + name: 'square.and.arrow.up', + }, + android: 'ic_menu_share', + web: 'share', + }, + }, + { + label: 'separator', + }, + { + label: isThreadMuted ? 'Unmute thread' : 'Mute thread', + onPress() { + onToggleThreadMute() + }, + testID: 'postDropdownMuteThreadBtn', + icon: { + ios: { + name: 'speaker.slash', + }, + android: 'ic_lock_silent_mode', + web: 'comment-slash', + }, + }, + { + label: 'separator', + }, + !isAuthor && { + label: 'Report post', + onPress() { + openModal({ + name: 'report', + uri: post.uri, + cid: post.cid, + }) + }, + testID: 'postDropdownReportBtn', + icon: { + ios: { + name: 'exclamationmark.triangle', + }, + android: 'ic_menu_report_image', + web: 'circle-exclamation', + }, + }, + isAuthor && { + label: 'separator', + }, + isAuthor && { + label: 'Delete post', + onPress() { + openModal({ + name: 'confirm', + title: 'Delete this post?', + message: 'Are you sure? This can not be undone.', + onPressConfirm: onDeletePost, + }) + }, + testID: 'postDropdownDeleteBtn', + icon: { + ios: { + name: 'trash', + }, + android: 'ic_menu_delete', + web: ['far', 'trash-can'], + }, + }, + ].filter(Boolean) as NativeDropdownItem[] + + return ( + <EventStopper> + <NativeDropdown + testID={testID} + items={dropdownItems} + accessibilityLabel="More post options" + accessibilityHint=""> + <View style={style}> + <FontAwesomeIcon icon="ellipsis" size={20} color={defaultCtrlColor} /> + </View> + </NativeDropdown> + </EventStopper> + ) +} |