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
This commit is contained in:
@@ -25,3 +25,19 @@ export async function shareUrl(url: string) {
|
|||||||
Toast.show(t`Copied to clipboard`, 'clipboard-check')
|
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')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {NativeStackScreenProps} from '@react-navigation/native-stack'
|
|||||||
import {appVersion, BUNDLE_DATE, bundleInfo} from '#/lib/app-info'
|
import {appVersion, BUNDLE_DATE, bundleInfo} from '#/lib/app-info'
|
||||||
import {STATUS_PAGE_URL} from '#/lib/constants'
|
import {STATUS_PAGE_URL} from '#/lib/constants'
|
||||||
import {CommonNavigatorParams} from '#/lib/routes/types'
|
import {CommonNavigatorParams} from '#/lib/routes/types'
|
||||||
|
import {useDevModeEnabled} from '#/state/preferences/dev-mode'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
import * as SettingsList from '#/screens/Settings/components/SettingsList'
|
import * as SettingsList from '#/screens/Settings/components/SettingsList'
|
||||||
import {CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon} from '#/components/icons/CodeLines'
|
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'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AboutSettings'>
|
||||||
export function AboutSettingsScreen({}: Props) {
|
export function AboutSettingsScreen({}: Props) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
const [devModeEnabled, setDevModeEnabled] = useDevModeEnabled()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout.Screen>
|
<Layout.Screen>
|
||||||
@@ -66,6 +68,15 @@ export function AboutSettingsScreen({}: Props) {
|
|||||||
<SettingsList.PressableItem
|
<SettingsList.PressableItem
|
||||||
label={_(msg`Version ${appVersion}`)}
|
label={_(msg`Version ${appVersion}`)}
|
||||||
accessibilityHint={_(msg`Copies build version to clipboard`)}
|
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={() => {
|
onPress={() => {
|
||||||
setStringAsync(
|
setStringAsync(
|
||||||
`Build version: ${appVersion}; Bundle info: ${bundleInfo}; Bundle date: ${BUNDLE_DATE}; Platform: ${Platform.OS}; Platform version: ${Platform.Version}`,
|
`Build version: ${appVersion}; Bundle info: ${bundleInfo}; Bundle date: ${BUNDLE_DATE}; Platform: ${Platform.OS}; Platform version: ${Platform.Version}`,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import {device, useStorage} from '#/storage'
|
||||||
|
|
||||||
|
export function useDevModeEnabled() {
|
||||||
|
const [devModeEnabled = false, setDevModeEnabled] = useStorage(device, [
|
||||||
|
'devMode',
|
||||||
|
])
|
||||||
|
|
||||||
|
return [devModeEnabled, setDevModeEnabled] as const
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ export type Device = {
|
|||||||
countryCode: string | undefined
|
countryCode: string | undefined
|
||||||
}
|
}
|
||||||
trendingBetaEnabled: boolean
|
trendingBetaEnabled: boolean
|
||||||
|
devMode: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Account = {
|
export type Account = {
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ import {useQueryClient} from '@tanstack/react-query'
|
|||||||
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
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 {toShareUrl} from '#/lib/strings/url-helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {Shadow} from '#/state/cache/types'
|
import {Shadow} from '#/state/cache/types'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
|
import {useDevModeEnabled} from '#/state/preferences/dev-mode'
|
||||||
import {
|
import {
|
||||||
RQKEY as profileQueryKey,
|
RQKEY as profileQueryKey,
|
||||||
useProfileBlockMutationQueue,
|
useProfileBlockMutationQueue,
|
||||||
@@ -52,6 +53,7 @@ let ProfileMenu = ({
|
|||||||
const isBlocked = profile.viewer?.blocking || profile.viewer?.blockedBy
|
const isBlocked = profile.viewer?.blocking || profile.viewer?.blockedBy
|
||||||
const isFollowingBlockedAccount = isFollowing && isBlocked
|
const isFollowingBlockedAccount = isFollowing && isBlocked
|
||||||
const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked
|
const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked
|
||||||
|
const [devModeEnabled] = useDevModeEnabled()
|
||||||
|
|
||||||
const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile)
|
const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile)
|
||||||
const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
|
const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile)
|
||||||
@@ -167,6 +169,14 @@ let ProfileMenu = ({
|
|||||||
reportDialogControl.open()
|
reportDialogControl.open()
|
||||||
}, [reportDialogControl])
|
}, [reportDialogControl])
|
||||||
|
|
||||||
|
const onPressShareATUri = React.useCallback(() => {
|
||||||
|
shareText(`at://${profile.did}`)
|
||||||
|
}, [profile.did])
|
||||||
|
|
||||||
|
const onPressShareDID = React.useCallback(() => {
|
||||||
|
shareText(profile.did)
|
||||||
|
}, [profile.did])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EventStopper onKeyDown={false}>
|
<EventStopper onKeyDown={false}>
|
||||||
<Menu.Root>
|
<Menu.Root>
|
||||||
@@ -308,6 +318,31 @@ let ProfileMenu = ({
|
|||||||
</Menu.Group>
|
</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.Outer>
|
||||||
</Menu.Root>
|
</Menu.Root>
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {useOpenLink} from '#/lib/hooks/useOpenLink'
|
|||||||
import {getCurrentRoute} from '#/lib/routes/helpers'
|
import {getCurrentRoute} from '#/lib/routes/helpers'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
|
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 {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
import {richTextToString} from '#/lib/strings/rich-text-helpers'
|
||||||
import {toShareUrl} from '#/lib/strings/url-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 {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences'
|
import {useHiddenPosts, useHiddenPostsApi} from '#/state/preferences'
|
||||||
|
import {useDevModeEnabled} from '#/state/preferences/dev-mode'
|
||||||
import {usePinnedPostMutation} from '#/state/queries/pinned-post'
|
import {usePinnedPostMutation} from '#/state/queries/pinned-post'
|
||||||
import {
|
import {
|
||||||
usePostDeleteMutation,
|
usePostDeleteMutation,
|
||||||
@@ -122,6 +123,7 @@ let PostDropdownMenuItems = ({
|
|||||||
const hideReplyConfirmControl = useDialogControl()
|
const hideReplyConfirmControl = useDialogControl()
|
||||||
const {mutateAsync: toggleReplyVisibility} =
|
const {mutateAsync: toggleReplyVisibility} =
|
||||||
useToggleReplyVisibilityMutation()
|
useToggleReplyVisibilityMutation()
|
||||||
|
const [devModeEnabled] = useDevModeEnabled()
|
||||||
|
|
||||||
const postUri = post.uri
|
const postUri = post.uri
|
||||||
const postCid = post.cid
|
const postCid = post.cid
|
||||||
@@ -366,6 +368,14 @@ let PostDropdownMenuItems = ({
|
|||||||
}
|
}
|
||||||
}, [_, queueBlock])
|
}, [_, queueBlock])
|
||||||
|
|
||||||
|
const onShareATURI = useCallback(() => {
|
||||||
|
shareText(postUri)
|
||||||
|
}, [postUri])
|
||||||
|
|
||||||
|
const onShareAuthorDID = useCallback(() => {
|
||||||
|
shareText(postAuthor.did)
|
||||||
|
}, [postAuthor.did])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Menu.Outer>
|
<Menu.Outer>
|
||||||
@@ -647,6 +657,28 @@ let PostDropdownMenuItems = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Menu.Group>
|
</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>
|
</Menu.Outer>
|
||||||
|
|||||||
Reference in New Issue
Block a user