about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorTom Sherman <the.tomsherman@gmail.com>2025-02-13 01:11:13 +0000
committerGitHub <noreply@github.com>2025-02-13 01:11:13 +0000
commitd56efe250e8b83930d71793c44e6ba58cdecdaf4 (patch)
tree8cb6557b76e70c7c6b144f1694be9b1f822deb38 /src
parentdb25f95c33121da9d04a02dc2e77929a5d24a5ce (diff)
downloadvoidsky-d56efe250e8b83930d71793c44e6ba58cdecdaf4.tar.zst
Add dev mode for easy copying of at:// URIs and DIDs (#7723)
* Add dev mode for easy copying at:// URIs and DIDs

* Use storage API

* Share text instead of URL

* Cleanup persisted schema

* Change translation msg
Diffstat (limited to 'src')
-rw-r--r--src/lib/sharing.ts16
-rw-r--r--src/screens/Settings/AboutSettings.tsx11
-rw-r--r--src/state/preferences/dev-mode.ts9
-rw-r--r--src/storage/schema.ts1
-rw-r--r--src/view/com/profile/ProfileMenu.tsx37
-rw-r--r--src/view/com/util/forms/PostDropdownBtnMenuItems.tsx34
6 files changed, 106 insertions, 2 deletions
diff --git a/src/lib/sharing.ts b/src/lib/sharing.ts
index c89d2d7a6..cdad6afe5 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 92ba2c1be..4d009281d 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<CommonNavigatorParams, 'AboutSettings'>
 export function AboutSettingsScreen({}: Props) {
   const {_} = useLingui()
+  const [devModeEnabled, setDevModeEnabled] = useDevModeEnabled()
 
   return (
     <Layout.Screen>
@@ -66,6 +68,15 @@ export function AboutSettingsScreen({}: Props) {
           <SettingsList.PressableItem
             label={_(msg`Version ${appVersion}`)}
             accessibilityHint={_(msg`Copies build version to clipboard`)}
+            onLongPress={() => {
+              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 000000000..ace283895
--- /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 667b43208..0e9b1985c 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 f01fb5e17..770d17f48 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 (
     <EventStopper onKeyDown={false}>
       <Menu.Root>
@@ -308,6 +318,31 @@ let ProfileMenu = ({
               </Menu.Group>
             </>
           )}
+          {devModeEnabled ? (
+            <>
+              <Menu.Divider />
+              <Menu.Group>
+                <Menu.Item
+                  testID="profileHeaderDropdownShareATURIBtn"
+                  label={_(msg`Copy at:// URI`)}
+                  onPress={onPressShareATUri}>
+                  <Menu.ItemText>
+                    <Trans>Copy at:// URI</Trans>
+                  </Menu.ItemText>
+                  <Menu.ItemIcon icon={Share} />
+                </Menu.Item>
+                <Menu.Item
+                  testID="profileHeaderDropdownShareDIDBtn"
+                  label={_(msg`Copy DID`)}
+                  onPress={onPressShareDID}>
+                  <Menu.ItemText>
+                    <Trans>Copy DID</Trans>
+                  </Menu.ItemText>
+                  <Menu.ItemIcon icon={Share} />
+                </Menu.Item>
+              </Menu.Group>
+            </>
+          ) : null}
         </Menu.Outer>
       </Menu.Root>
 
diff --git a/src/view/com/util/forms/PostDropdownBtnMenuItems.tsx b/src/view/com/util/forms/PostDropdownBtnMenuItems.tsx
index 149bb9ad2..41f7e74a6 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 (
     <>
       <Menu.Outer>
@@ -647,6 +657,28 @@ let PostDropdownMenuItems = ({
                 </>
               )}
             </Menu.Group>
+
+            {devModeEnabled ? (
+              <>
+                <Menu.Divider />
+                <Menu.Group>
+                  <Menu.Item
+                    testID="postAtUriShareBtn"
+                    label={_(msg`Copy post at:// URI`)}
+                    onPress={onShareATURI}>
+                    <Menu.ItemText>{_(msg`Copy post at:// URI`)}</Menu.ItemText>
+                    <Menu.ItemIcon icon={Share} position="right" />
+                  </Menu.Item>
+                  <Menu.Item
+                    testID="postAuthorDIDShareBtn"
+                    label={_(msg`Copy author DID`)}
+                    onPress={onShareAuthorDID}>
+                    <Menu.ItemText>{_(msg`Copy author DID`)}</Menu.ItemText>
+                    <Menu.ItemIcon icon={Share} position="right" />
+                  </Menu.Item>
+                </Menu.Group>
+              </>
+            ) : null}
           </>
         )}
       </Menu.Outer>