diff --git a/src/lib/sharing.ts b/src/lib/sharing.ts index c89d2d7a6a..cdad6afe50 100644 --- a/src/lib/sharing.ts +++ b/src/lib/sharing.ts @@ -25,3 +25,19 @@ export async function shareUrl(url: string) { Toast.show(t`Copied to clipboard`, 'clipboard-check') } } + +/** + * This function shares a text using the native Share API if available, or copies it to the clipboard + * and displays a toast message if not (mostly on web) + * + * @param {string} text - A string representing the text that needs to be shared or copied to the + * clipboard. + */ +export async function shareText(text: string) { + if (isAndroid || isIOS) { + await Share.share({message: text}) + } else { + await setStringAsync(text) + Toast.show(t`Copied to clipboard`, 'clipboard-check') + } +} diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx index 92ba2c1beb..4d009281de 100644 --- a/src/screens/Settings/AboutSettings.tsx +++ b/src/screens/Settings/AboutSettings.tsx @@ -7,6 +7,7 @@ import {NativeStackScreenProps} from '@react-navigation/native-stack' import {appVersion, BUNDLE_DATE, bundleInfo} from '#/lib/app-info' import {STATUS_PAGE_URL} from '#/lib/constants' import {CommonNavigatorParams} from '#/lib/routes/types' +import {useDevModeEnabled} from '#/state/preferences/dev-mode' import * as Toast from '#/view/com/util/Toast' import * as SettingsList from '#/screens/Settings/components/SettingsList' import {CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon} from '#/components/icons/CodeLines' @@ -18,6 +19,7 @@ import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps export function AboutSettingsScreen({}: Props) { const {_} = useLingui() + const [devModeEnabled, setDevModeEnabled] = useDevModeEnabled() return ( @@ -66,6 +68,15 @@ export function AboutSettingsScreen({}: Props) { { + const newDevModeEnabled = !devModeEnabled + setDevModeEnabled(newDevModeEnabled) + Toast.show( + newDevModeEnabled + ? _(msg`Developer mode enabled`) + : _(msg`Developer mode disabled`), + ) + }} onPress={() => { setStringAsync( `Build version: ${appVersion}; Bundle info: ${bundleInfo}; Bundle date: ${BUNDLE_DATE}; Platform: ${Platform.OS}; Platform version: ${Platform.Version}`, diff --git a/src/state/preferences/dev-mode.ts b/src/state/preferences/dev-mode.ts new file mode 100644 index 0000000000..ace2838959 --- /dev/null +++ b/src/state/preferences/dev-mode.ts @@ -0,0 +1,9 @@ +import {device, useStorage} from '#/storage' + +export function useDevModeEnabled() { + const [devModeEnabled = false, setDevModeEnabled] = useStorage(device, [ + 'devMode', + ]) + + return [devModeEnabled, setDevModeEnabled] as const +} diff --git a/src/storage/schema.ts b/src/storage/schema.ts index 667b432082..0e9b1985cb 100644 --- a/src/storage/schema.ts +++ b/src/storage/schema.ts @@ -9,6 +9,7 @@ export type Device = { countryCode: string | undefined } trendingBetaEnabled: boolean + devMode: boolean } export type Account = { diff --git a/src/view/com/profile/ProfileMenu.tsx b/src/view/com/profile/ProfileMenu.tsx index f01fb5e172..770d17f48c 100644 --- a/src/view/com/profile/ProfileMenu.tsx +++ b/src/view/com/profile/ProfileMenu.tsx @@ -6,11 +6,12 @@ import {useQueryClient} from '@tanstack/react-query' import {HITSLOP_20} from '#/lib/constants' import {makeProfileLink} from '#/lib/routes/links' -import {shareUrl} from '#/lib/sharing' +import {shareText, shareUrl} from '#/lib/sharing' import {toShareUrl} from '#/lib/strings/url-helpers' import {logger} from '#/logger' import {Shadow} from '#/state/cache/types' import {useModalControls} from '#/state/modals' +import {useDevModeEnabled} from '#/state/preferences/dev-mode' import { RQKEY as profileQueryKey, useProfileBlockMutationQueue, @@ -52,6 +53,7 @@ let ProfileMenu = ({ const isBlocked = profile.viewer?.blocking || profile.viewer?.blockedBy const isFollowingBlockedAccount = isFollowing && isBlocked const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked + const [devModeEnabled] = useDevModeEnabled() const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile) const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile) @@ -167,6 +169,14 @@ let ProfileMenu = ({ reportDialogControl.open() }, [reportDialogControl]) + const onPressShareATUri = React.useCallback(() => { + shareText(`at://${profile.did}`) + }, [profile.did]) + + const onPressShareDID = React.useCallback(() => { + shareText(profile.did) + }, [profile.did]) + return ( @@ -308,6 +318,31 @@ let ProfileMenu = ({ )} + {devModeEnabled ? ( + <> + + + + + Copy at:// URI + + + + + + Copy DID + + + + + + ) : null} diff --git a/src/view/com/util/forms/PostDropdownBtnMenuItems.tsx b/src/view/com/util/forms/PostDropdownBtnMenuItems.tsx index 149bb9ad2f..41f7e74a69 100644 --- a/src/view/com/util/forms/PostDropdownBtnMenuItems.tsx +++ b/src/view/com/util/forms/PostDropdownBtnMenuItems.tsx @@ -21,7 +21,7 @@ import {useOpenLink} from '#/lib/hooks/useOpenLink' import {getCurrentRoute} from '#/lib/routes/helpers' import {makeProfileLink} from '#/lib/routes/links' import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types' -import {shareUrl} from '#/lib/sharing' +import {shareText, shareUrl} from '#/lib/sharing' import {logEvent} from '#/lib/statsig/statsig' import {richTextToString} from '#/lib/strings/rich-text-helpers' import {toShareUrl} from '#/lib/strings/url-helpers' @@ -33,6 +33,7 @@ import {useProfileShadow} from '#/state/cache/profile-shadow' import {useFeedFeedbackContext} from '#/state/feed-feedback' import {useLanguagePrefs} from '#/state/preferences' import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences' +import {useDevModeEnabled} from '#/state/preferences/dev-mode' import {usePinnedPostMutation} from '#/state/queries/pinned-post' import { usePostDeleteMutation, @@ -122,6 +123,7 @@ let PostDropdownMenuItems = ({ const hideReplyConfirmControl = useDialogControl() const {mutateAsync: toggleReplyVisibility} = useToggleReplyVisibilityMutation() + const [devModeEnabled] = useDevModeEnabled() const postUri = post.uri const postCid = post.cid @@ -366,6 +368,14 @@ let PostDropdownMenuItems = ({ } }, [_, queueBlock]) + const onShareATURI = useCallback(() => { + shareText(postUri) + }, [postUri]) + + const onShareAuthorDID = useCallback(() => { + shareText(postAuthor.did) + }, [postAuthor.did]) + return ( <> @@ -647,6 +657,28 @@ let PostDropdownMenuItems = ({ )} + + {devModeEnabled ? ( + <> + + + + {_(msg`Copy post at:// URI`)} + + + + {_(msg`Copy author DID`)} + + + + + ) : null} )}