diff --git a/src/components/BotAccountInfoDialog.tsx b/src/components/BotAccountInfoDialog.tsx
index 8ca56f282c..36dde27e38 100644
--- a/src/components/BotAccountInfoDialog.tsx
+++ b/src/components/BotAccountInfoDialog.tsx
@@ -1,9 +1,9 @@
-import {View} from 'react-native'
+import {Modal, Pressable, View} from 'react-native'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
-import {atoms as a, useTheme} from '#/alf'
+import {atoms as a, useTheme, web} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {Robot_Filled_Corner2_Rounded as RobotIcon} from '#/components/icons/Robot'
@@ -12,58 +12,132 @@ import {navigate} from '#/Navigation'
export function BotAccountInfoDialog({
control,
- isMe,
}: {
control: Dialog.DialogControlProps
- isMe?: boolean
}) {
return (
-
+
)
}
-function BotAccountInfoDialogInner({
- control,
- isMe,
+export function BotAccountOwnAlert({
+ visible,
+ onClose,
}: {
- control: Dialog.DialogControlProps
- isMe?: boolean
+ visible: boolean
+ onClose: (cb?: () => void) => void
}) {
const {_} = useLingui()
const t = useTheme()
return (
-
-
-
-
-
-
- {isMe ? (
+ onClose()}
+ accessibilityLabel={_(msg`Automated account`)}
+ accessibilityViewIsModal>
+ onClose()}
+ style={[
+ a.flex_1,
+ a.justify_center,
+ a.align_center,
+ a.px_xl,
+ {backgroundColor: 'rgba(0,0,0,0.5)'},
+ ]}>
+ e.stopPropagation()}
+ style={[
+ t.atoms.bg,
+ a.w_full,
+ {borderRadius: 48},
+ a.p_2xl,
+ {maxWidth: 280},
+ ]}>
+
+
+
+
+
+
+
+ You have marked this account as automated. You can remove it at
+ any time from your account settings.
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export function BotAccountOwnAlertWeb({
+ control,
+}: {
+ control: Dialog.DialogControlProps
+}) {
+ const {_} = useLingui()
+ const t = useTheme()
+
+ return (
+
+
+
+
+
+
+
You have marked this account as automated. You can remove it at
any time from your account settings.
- ) : (
-
- This account has been marked as automated by its owner
-
- )}
-
-
- {isMe && (
+
+
- )}
+
+
+
+
+ )
+}
+
+function BotAccountInfoDialogInner({
+ control,
+}: {
+ control: Dialog.DialogControlProps
+}) {
+ const {_} = useLingui()
+ const t = useTheme()
+
+ return (
+
+
+
+
+
+
+ This account has been marked as automated by its owner
+
+
diff --git a/src/components/BotBadge.tsx b/src/components/BotBadge.tsx
index 41ef567688..0b9e3b4b2a 100644
--- a/src/components/BotBadge.tsx
+++ b/src/components/BotBadge.tsx
@@ -1,15 +1,21 @@
+import {useState} from 'react'
import {View} from 'react-native'
import {type ComAtprotoLabelDefs} from '@atproto/api'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
+import {useAnalytics} from '#/analytics'
+import {IS_NATIVE} from '#/env'
import {isBotAccount} from '#/lib/bots'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
-import {BotAccountInfoDialog} from '#/components/BotAccountInfoDialog'
+import {
+ BotAccountInfoDialog,
+ BotAccountOwnAlert,
+ BotAccountOwnAlertWeb,
+} from '#/components/BotAccountInfoDialog'
import {Button} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog'
import {Robot_Filled_Corner2_Rounded as RobotIcon} from '#/components/icons/Robot'
-import {useAnalytics} from '#/analytics'
export function BotBadge({
profile,
@@ -47,6 +53,7 @@ export function BotBadgeButton({
const {_} = useLingui()
const {gtPhone} = useBreakpoints()
const control = useDialogControl()
+ const [alertVisible, setAlertVisible] = useState(false)
if (!isBotAccount(profile)) {
return null
@@ -59,6 +66,8 @@ export function BotBadgeButton({
dimensions = 14
}
+ const useNativeAlert = isMe && IS_NATIVE
+
return (
<>
-
+ {useNativeAlert ? (
+ {
+ setAlertVisible(false)
+ cb?.()
+ }}
+ />
+ ) : isMe ? (
+
+ ) : (
+
+ )}
>
)
}
diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx
index 54906e33d5..0e489c5aac 100644
--- a/src/components/ProfileCard.tsx
+++ b/src/components/ProfileCard.tsx
@@ -273,7 +273,14 @@ function InlineNameAndHandle({
/>
)}
-
+
+
+
)}
-
+
+
+
)
}
diff --git a/src/screens/Settings/AutomationLabelSettings.tsx b/src/screens/Settings/AutomationLabelSettings.tsx
index 89ec0ac273..4874f845dc 100644
--- a/src/screens/Settings/AutomationLabelSettings.tsx
+++ b/src/screens/Settings/AutomationLabelSettings.tsx
@@ -1,6 +1,7 @@
import React from 'react'
import {View} from 'react-native'
import {type $Typed, ComAtprotoLabelDefs} from '@atproto/api'
+import {useQueryClient} from '@tanstack/react-query'
import {msg} from '@lingui/core/macro'
import {useLingui} from '@lingui/react'
import {Trans} from '@lingui/react/macro'
@@ -8,6 +9,8 @@ import {type NativeStackScreenProps} from '@react-navigation/native-stack'
import {useAnalytics} from '#/analytics'
import {type CommonNavigatorParams} from '#/lib/routes/types'
+import {RQKEY_ROOT as POST_FEED_RQKEY_ROOT} from '#/state/queries/post-feed'
+import {postThreadQueryKeyRoot} from '#/state/queries/usePostThread/types'
import {
useProfileQuery,
useProfileUpdateMutation,
@@ -32,6 +35,7 @@ export function AutomationLabelSettingsScreen({}: Props) {
const t = useTheme()
const ax = useAnalytics()
const {_} = useLingui()
+ const queryClient = useQueryClient()
const {currentAccount} = useSession()
const {data: profile} = useProfileQuery({did: currentAccount?.did})
const updateProfile = useProfileUpdateMutation()
@@ -48,41 +52,50 @@ export function AutomationLabelSettingsScreen({}: Props) {
}
let wasAdded = false
ax.metric('bot:label:toggle', {state: isBotLabeled ? 'remove' : 'add'})
- updateProfile.mutate({
- profile,
- updates: existing => {
- const labels: $Typed = bsky.validate(
- existing.labels,
- ComAtprotoLabelDefs.validateSelfLabels,
- )
- ? existing.labels
- : {
- $type: 'com.atproto.label.defs#selfLabels',
- values: [],
- }
+ updateProfile.mutate(
+ {
+ profile,
+ updates: existing => {
+ const labels: $Typed =
+ bsky.validate(
+ existing.labels,
+ ComAtprotoLabelDefs.validateSelfLabels,
+ )
+ ? existing.labels
+ : {
+ $type: 'com.atproto.label.defs#selfLabels',
+ values: [],
+ }
- const hasLabel = labels.values.some(l => l.val === 'bot')
- if (hasLabel) {
- wasAdded = false
- labels.values = labels.values.filter(l => l.val !== 'bot')
- } else {
- wasAdded = true
- labels.values.push({val: 'bot'})
- }
+ const hasLabel = labels.values.some(l => l.val === 'bot')
+ if (hasLabel) {
+ wasAdded = false
+ labels.values = labels.values.filter(l => l.val !== 'bot')
+ } else {
+ wasAdded = true
+ labels.values.push({val: 'bot'})
+ }
- if (labels.values.length === 0) {
- delete existing.labels
- } else {
- existing.labels = labels
- }
+ if (labels.values.length === 0) {
+ delete existing.labels
+ } else {
+ existing.labels = labels
+ }
- return existing
+ return existing
+ },
+ checkCommitted: res => {
+ const exists = !!res.data.labels?.some(l => l.val === 'bot')
+ return exists === wasAdded
+ },
},
- checkCommitted: res => {
- const exists = !!res.data.labels?.some(l => l.val === 'bot')
- return exists === wasAdded
+ {
+ onSuccess() {
+ queryClient.invalidateQueries({queryKey: [POST_FEED_RQKEY_ROOT]})
+ queryClient.invalidateQueries({queryKey: [postThreadQueryKeyRoot]})
+ },
},
- })
+ )
}, [updateProfile, profile])
return (