diff --git a/src/screens/Settings/DeerSettings.tsx b/src/screens/Settings/DeerSettings.tsx
index 423fb8614..f62494c29 100644
--- a/src/screens/Settings/DeerSettings.tsx
+++ b/src/screens/Settings/DeerSettings.tsx
@@ -23,6 +23,10 @@ import {
useDirectFetchRecords,
useSetDirectFetchRecords,
} from '#/state/preferences/direct-fetch-records'
+import {
+ useNoAppLabelers,
+ useSetNoAppLabelers,
+} from '#/state/preferences/no-app-labelers'
import {TextInput} from '#/view/com/modals/util'
import * as SettingsList from '#/screens/Settings/components/SettingsList'
import {atoms as a} from '#/alf'
@@ -35,6 +39,7 @@ import {Eye_Stroke2_Corner0_Rounded as VisibilityIcon} from '#/components/icons/
import {Earth_Stroke2_Corner2_Rounded as GlobeIcon} from '#/components/icons/Globe'
import {Lab_Stroke2_Corner0_Rounded as BeakerIcon} from '#/components/icons/Lab'
import {PaintRoller_Stroke2_Corner2_Rounded as PaintRollerIcon} from '#/components/icons/PaintRoller'
+import {RaisingHand4Finger_Stroke2_Corner0_Rounded as RaisingHandIcon} from '#/components/icons/RaisingHand'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography'
@@ -117,6 +122,9 @@ export function DeerSettingsScreen({}: Props) {
const directFetchRecords = useDirectFetchRecords()
const setDirectFetchRecords = useSetDirectFetchRecords()
+ const noAppLabelers = useNoAppLabelers()
+ const setNoAppLabelers = useSetNoAppLabelers()
+
const location = useGeolocation()
const setLocationControl = Dialog.useDialogControl()
@@ -176,7 +184,8 @@ export function DeerSettingsScreen({}: Props) {
style={[a.w_full]}>
- Fetch records directly from PDS to see through quote blocks
+ Fetch records directly from PDS to see contents of blocked and
+ detatched quotes
@@ -214,12 +223,46 @@ export function DeerSettingsScreen({}: Props) {
- Geolocation country code informs required regional labelers and
- currency behavior.
+ Geolocation country code informs required regional app labelers
+ and currency behavior.
+
+
+
+ Labelers
+
+ setNoAppLabelers(value)}
+ style={[a.w_full]}>
+
+ Do not declare any default app labelers
+
+
+
+
+ Restart app after changing this setting.
+
+
+
+ Some appviews will default to using an app labeler if you have
+ no labelers, so consider subscribing to at least one labeler.
+
+
+
+
+ App labelers are mandatory top-level labelers that can perform
+ "takedowns". This setting does not influence geolocation based
+ labelers.
+
+
+
+
diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts
index 519488e5a..aa7977413 100644
--- a/src/state/persisted/schema.ts
+++ b/src/state/persisted/schema.ts
@@ -128,7 +128,7 @@ const schema = z.object({
goLinksEnabled: z.boolean().optional(),
constellationEnabled: z.boolean().optional(),
directFetchRecords: z.boolean().optional(),
- unfollowConfirm: z.boolean().optional(),
+ noAppLabelers: z.boolean().optional(),
/** @deprecated */
mutedThreads: z.array(z.string()),
@@ -186,7 +186,7 @@ export const defaults: Schema = {
goLinksEnabled: true,
constellationEnabled: false,
directFetchRecords: false,
- unfollowConfirm: false,
+ noAppLabelers: false,
}
export function tryParse(rawData: string): Schema | undefined {
diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx
index 132561dd8..fca56292e 100644
--- a/src/state/preferences/index.tsx
+++ b/src/state/preferences/index.tsx
@@ -12,6 +12,7 @@ import {Provider as InAppBrowserProvider} from './in-app-browser'
import {Provider as KawaiiProvider} from './kawaii'
import {Provider as LanguagesProvider} from './languages'
import {Provider as LargeAltBadgeProvider} from './large-alt-badge'
+import {Provider as NoAppLabelersProvider} from './no-app-labelers'
import {Provider as SubtitlesProvider} from './subtitles'
import {Provider as TrendingSettingsProvider} from './trending'
import {Provider as UsedStarterPacksProvider} from './used-starter-packs'
@@ -37,29 +38,31 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
-
-
-
-
-
-
-
-
-
-
-
- {children}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/state/preferences/no-app-labelers.tsx b/src/state/preferences/no-app-labelers.tsx
new file mode 100644
index 000000000..c8ca8bd0d
--- /dev/null
+++ b/src/state/preferences/no-app-labelers.tsx
@@ -0,0 +1,51 @@
+import React from 'react'
+
+import * as persisted from '#/state/persisted'
+
+type StateContext = persisted.Schema['noAppLabelers']
+type SetContext = (v: persisted.Schema['noAppLabelers']) => void
+
+const stateContext = React.createContext(
+ persisted.defaults.noAppLabelers,
+)
+const setContext = React.createContext(
+ (_: persisted.Schema['noAppLabelers']) => {},
+)
+
+export function Provider({children}: React.PropsWithChildren<{}>) {
+ const [state, setState] = React.useState(persisted.get('noAppLabelers'))
+
+ const setStateWrapped = React.useCallback(
+ (noAppLabelers: persisted.Schema['noAppLabelers']) => {
+ setState(noAppLabelers)
+ persisted.write('noAppLabelers', noAppLabelers)
+ },
+ [setState],
+ )
+
+ React.useEffect(() => {
+ return persisted.onUpdate('noAppLabelers', nextNoAppLabelers => {
+ setState(nextNoAppLabelers)
+ })
+ }, [setStateWrapped])
+
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export function useNoAppLabelers() {
+ return React.useContext(stateContext)
+}
+
+export function useSetNoAppLabelers() {
+ return React.useContext(setContext)
+}
+
+export function getNoAppLabelers() {
+ return persisted.get('noAppLabelers') || persisted.defaults.noAppLabelers!
+}
diff --git a/src/state/session/moderation.ts b/src/state/session/moderation.ts
index 01684fe0b..693281998 100644
--- a/src/state/session/moderation.ts
+++ b/src/state/session/moderation.ts
@@ -1,9 +1,10 @@
import {BSKY_LABELER_DID, BskyAgent} from '@atproto/api'
import {IS_TEST_USER} from '#/lib/constants'
+import {getNoAppLabelers} from '../preferences/no-app-labelers'
import {configureAdditionalModerationAuthorities} from './additional-moderation-authorities'
import {readLabelers} from './agent-config'
-import {SessionAccount} from './types'
+import {type SessionAccount} from './types'
export function configureModerationForGuest() {
// This global mutation is *only* OK because this code is only relevant for testing.
@@ -38,7 +39,9 @@ export async function configureModerationForAccount(
}
function switchToBskyAppLabeler() {
- BskyAgent.configure({appLabelers: [BSKY_LABELER_DID]})
+ BskyAgent.configure({
+ appLabelers: getNoAppLabelers() ? [] : [BSKY_LABELER_DID],
+ })
}
async function trySwitchToTestAppLabeler(agent: BskyAgent) {