about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorSamuel Newman <mozzius@protonmail.com>2024-11-08 22:42:18 +0000
committerGitHub <noreply@github.com>2024-11-08 22:42:18 +0000
commit5da3f29498fda9ab1181df19a718e37099cb2cf6 (patch)
tree4989300fe333edc3ad1c12c7b0d03e6ff5112ee3 /src
parente8a03058bb993bda993e78d24877884d39666d63 (diff)
downloadvoidsky-5da3f29498fda9ab1181df19a718e37099cb2cf6.tar.zst
[Settings] Ungate, and remove old settings (#6144)
* move export car dialog

* move disableemail2fadialog

* delete old settings screens

* fix type error

* Update Navigation.tsx

* Delete AccountDropdownBtn.tsx

* remove old change handle modal

* delete add app paswords

* forgot to actually delete the change handle modal
Diffstat (limited to 'src')
-rw-r--r--src/Navigation.tsx22
-rw-r--r--src/lib/hooks/useCustomPalette.ts14
-rw-r--r--src/screens/Moderation/index.tsx131
-rw-r--r--src/screens/Settings/AccountSettings.tsx2
-rw-r--r--src/screens/Settings/components/DisableEmail2FADialog.tsx (renamed from src/view/screens/Settings/DisableEmail2FADialog.tsx)0
-rw-r--r--src/screens/Settings/components/Email2FAToggle.tsx2
-rw-r--r--src/screens/Settings/components/ExportCarDialog.tsx (renamed from src/view/screens/Settings/ExportCarDialog.tsx)0
-rw-r--r--src/state/modals/index.tsx11
-rw-r--r--src/view/com/modals/AddAppPasswords.tsx307
-rw-r--r--src/view/com/modals/ChangeHandle.tsx614
-rw-r--r--src/view/com/modals/Modal.tsx8
-rw-r--r--src/view/com/modals/Modal.web.tsx6
-rw-r--r--src/view/com/util/AccountDropdownBtn.tsx66
-rw-r--r--src/view/com/util/List.web.tsx4
-rw-r--r--src/view/screens/AccessibilitySettings.tsx157
-rw-r--r--src/view/screens/AppPasswords.tsx375
-rw-r--r--src/view/screens/LanguageSettings.tsx336
-rw-r--r--src/view/screens/PreferencesExternalEmbeds.tsx147
-rw-r--r--src/view/screens/PreferencesFollowingFeed.tsx249
-rw-r--r--src/view/screens/PreferencesThreads.tsx198
-rw-r--r--src/view/screens/Settings/Email2FAToggle.tsx58
-rw-r--r--src/view/screens/Settings/index.tsx1077
22 files changed, 16 insertions, 3768 deletions
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index efe4b8c29..0ab4bb613 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -40,14 +40,11 @@ import {
   shouldRequestEmailConfirmation,
   snoozeEmailConfirmationPrompt,
 } from '#/state/shell/reminders'
-import {AccessibilitySettingsScreen} from '#/view/screens/AccessibilitySettings'
-import {AppPasswords} from '#/view/screens/AppPasswords'
 import {CommunityGuidelinesScreen} from '#/view/screens/CommunityGuidelines'
 import {CopyrightPolicyScreen} from '#/view/screens/CopyrightPolicy'
 import {DebugModScreen} from '#/view/screens/DebugMod'
 import {FeedsScreen} from '#/view/screens/Feeds'
 import {HomeScreen} from '#/view/screens/Home'
-import {LanguageSettingsScreen} from '#/view/screens/LanguageSettings'
 import {ListsScreen} from '#/view/screens/Lists'
 import {LogScreen} from '#/view/screens/Log'
 import {ModerationBlockedAccounts} from '#/view/screens/ModerationBlockedAccounts'
@@ -56,9 +53,6 @@ import {ModerationMutedAccounts} from '#/view/screens/ModerationMutedAccounts'
 import {NotFoundScreen} from '#/view/screens/NotFound'
 import {NotificationsScreen} from '#/view/screens/Notifications'
 import {PostThreadScreen} from '#/view/screens/PostThread'
-import {PreferencesExternalEmbeds} from '#/view/screens/PreferencesExternalEmbeds'
-import {PreferencesFollowingFeed} from '#/view/screens/PreferencesFollowingFeed'
-import {PreferencesThreads} from '#/view/screens/PreferencesThreads'
 import {PrivacyPolicyScreen} from '#/view/screens/PrivacyPolicy'
 import {ProfileScreen} from '#/view/screens/Profile'
 import {ProfileFeedScreen} from '#/view/screens/ProfileFeed'
@@ -68,7 +62,6 @@ import {ProfileFollowsScreen} from '#/view/screens/ProfileFollows'
 import {ProfileListScreen} from '#/view/screens/ProfileList'
 import {SavedFeeds} from '#/view/screens/SavedFeeds'
 import {SearchScreen} from '#/view/screens/Search'
-import {SettingsScreen} from '#/view/screens/Settings'
 import {Storybook} from '#/view/screens/Storybook'
 import {SupportScreen} from '#/view/screens/Support'
 import {TermsOfServiceScreen} from '#/view/screens/TermsOfService'
@@ -96,9 +89,16 @@ import {useTheme} from '#/alf'
 import {router} from '#/routes'
 import {Referrer} from '../modules/expo-bluesky-swiss-army'
 import {AboutSettingsScreen} from './screens/Settings/AboutSettings'
+import {AccessibilitySettingsScreen} from './screens/Settings/AccessibilitySettings'
 import {AccountSettingsScreen} from './screens/Settings/AccountSettings'
+import {AppPasswordsScreen} from './screens/Settings/AppPasswords'
 import {ContentAndMediaSettingsScreen} from './screens/Settings/ContentAndMediaSettings'
+import {ExternalMediaPreferencesScreen} from './screens/Settings/ExternalMediaPreferences'
+import {FollowingFeedPreferencesScreen} from './screens/Settings/FollowingFeedPreferences'
+import {LanguageSettingsScreen} from './screens/Settings/LanguageSettings'
 import {PrivacyAndSecuritySettingsScreen} from './screens/Settings/PrivacyAndSecuritySettings'
+import {SettingsScreen} from './screens/Settings/Settings'
+import {ThreadPreferencesScreen} from './screens/Settings/ThreadPreferences'
 
 const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
 
@@ -285,7 +285,7 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
       />
       <Stack.Screen
         name="AppPasswords"
-        getComponent={() => AppPasswords}
+        getComponent={() => AppPasswordsScreen}
         options={{title: title(msg`App Passwords`), requireAuth: true}}
       />
       <Stack.Screen
@@ -295,7 +295,7 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
       />
       <Stack.Screen
         name="PreferencesFollowingFeed"
-        getComponent={() => PreferencesFollowingFeed}
+        getComponent={() => FollowingFeedPreferencesScreen}
         options={{
           title: title(msg`Following Feed Preferences`),
           requireAuth: true,
@@ -303,12 +303,12 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
       />
       <Stack.Screen
         name="PreferencesThreads"
-        getComponent={() => PreferencesThreads}
+        getComponent={() => ThreadPreferencesScreen}
         options={{title: title(msg`Threads Preferences`), requireAuth: true}}
       />
       <Stack.Screen
         name="PreferencesExternalEmbeds"
-        getComponent={() => PreferencesExternalEmbeds}
+        getComponent={() => ExternalMediaPreferencesScreen}
         options={{
           title: title(msg`External Media Preferences`),
           requireAuth: true,
diff --git a/src/lib/hooks/useCustomPalette.ts b/src/lib/hooks/useCustomPalette.ts
deleted file mode 100644
index 5691ea79b..000000000
--- a/src/lib/hooks/useCustomPalette.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react'
-
-import {choose} from '#/lib/functions'
-import {useTheme} from '#/lib/ThemeContext'
-
-export function useCustomPalette<T>({light, dark}: {light: T; dark: T}) {
-  const theme = useTheme()
-  return React.useMemo(() => {
-    return choose<T, Record<string, T>>(theme.colorScheme, {
-      dark,
-      light,
-    })
-  }, [theme.colorScheme, dark, light])
-}
diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx
index d5a2daffd..5f340cd56 100644
--- a/src/screens/Moderation/index.tsx
+++ b/src/screens/Moderation/index.tsx
@@ -1,13 +1,11 @@
 import React from 'react'
 import {Linking, View} from 'react-native'
 import {useSafeAreaFrame} from 'react-native-safe-area-context'
-import {ComAtprotoLabelDefs} from '@atproto/api'
 import {LABELS} from '@atproto/api'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useFocusEffect} from '@react-navigation/native'
 
-import {IS_INTERNAL} from '#/lib/app-info'
 import {getLabelingServiceTitle} from '#/lib/moderation'
 import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
 import {logger} from '#/logger'
@@ -18,11 +16,6 @@ import {
   UsePreferencesQueryResponse,
   usePreferencesSetAdultContentMutation,
 } from '#/state/queries/preferences'
-import {
-  useProfileQuery,
-  useProfileUpdateMutation,
-} from '#/state/queries/profile'
-import {useSession} from '#/state/session'
 import {isNonConfigurableModerationAuthority} from '#/state/session/additional-moderation-authorities'
 import {useSetMinimalShellMode} from '#/state/shell'
 import {ViewHeader} from '#/view/com/util/ViewHeader'
@@ -469,131 +462,7 @@ export function ModerationScreenInner({
           })}
         </View>
       )}
-
-      {!IS_INTERNAL && (
-        <>
-          <Text
-            style={[
-              a.text_md,
-              a.font_bold,
-              a.pt_2xl,
-              a.pb_md,
-              t.atoms.text_contrast_high,
-            ]}>
-            <Trans>Logged-out visibility</Trans>
-          </Text>
-
-          <PwiOptOut />
-        </>
-      )}
-
       <View style={{height: 200}} />
     </ScrollView>
   )
 }
-
-function PwiOptOut() {
-  const t = useTheme()
-  const {_} = useLingui()
-  const {currentAccount} = useSession()
-  const {data: profile} = useProfileQuery({did: currentAccount?.did})
-  const updateProfile = useProfileUpdateMutation()
-
-  const isOptedOut =
-    profile?.labels?.some(l => l.val === '!no-unauthenticated') || false
-  const canToggle = profile && !updateProfile.isPending
-
-  const onToggleOptOut = React.useCallback(() => {
-    if (!profile) {
-      return
-    }
-    let wasAdded = false
-    updateProfile.mutate({
-      profile,
-      updates: existing => {
-        // create labels attr if needed
-        existing.labels = ComAtprotoLabelDefs.isSelfLabels(existing.labels)
-          ? existing.labels
-          : {
-              $type: 'com.atproto.label.defs#selfLabels',
-              values: [],
-            }
-
-        // toggle the label
-        const hasLabel = existing.labels.values.some(
-          l => l.val === '!no-unauthenticated',
-        )
-        if (hasLabel) {
-          wasAdded = false
-          existing.labels.values = existing.labels.values.filter(
-            l => l.val !== '!no-unauthenticated',
-          )
-        } else {
-          wasAdded = true
-          existing.labels.values.push({val: '!no-unauthenticated'})
-        }
-
-        // delete if no longer needed
-        if (existing.labels.values.length === 0) {
-          delete existing.labels
-        }
-        return existing
-      },
-      checkCommitted: res => {
-        const exists = !!res.data.labels?.some(
-          l => l.val === '!no-unauthenticated',
-        )
-        return exists === wasAdded
-      },
-    })
-  }, [updateProfile, profile])
-
-  return (
-    <View style={[a.pt_sm]}>
-      <View style={[a.flex_row, a.align_center, a.justify_between, a.gap_lg]}>
-        <Toggle.Item
-          disabled={!canToggle}
-          value={isOptedOut}
-          onChange={onToggleOptOut}
-          name="logged_out_visibility"
-          style={a.flex_1}
-          label={_(
-            msg`Discourage apps from showing my account to logged-out users`,
-          )}>
-          <Toggle.Switch />
-          <Toggle.LabelText style={[a.text_md, a.flex_1]}>
-            <Trans>
-              Discourage apps from showing my account to logged-out users
-            </Trans>
-          </Toggle.LabelText>
-        </Toggle.Item>
-
-        {updateProfile.isPending && <Loader />}
-      </View>
-
-      <View style={[a.pt_md, a.gap_md, {paddingLeft: 38}]}>
-        <Text style={[a.leading_snug, t.atoms.text_contrast_high]}>
-          <Trans>
-            Bluesky will not show your profile and posts to logged-out users.
-            Other apps may not honor this request. This does not make your
-            account private.
-          </Trans>
-        </Text>
-        <Text style={[a.font_bold, a.leading_snug, t.atoms.text_contrast_high]}>
-          <Trans>
-            Note: Bluesky is an open and public network. This setting only
-            limits the visibility of your content on the Bluesky app and
-            website, and other apps may not respect this setting. Your content
-            may still be shown to logged-out users by other apps and websites.
-          </Trans>
-        </Text>
-
-        <InlineLinkText
-          label={_(msg`Learn more about what is public on Bluesky.`)}
-          to="https://blueskyweb.zendesk.com/hc/en-us/articles/15835264007693-Data-Privacy">
-          <Trans>Learn more about what is public on Bluesky.</Trans>
-        </InlineLinkText>
-      </View>
-    </View>
-  )
-}
diff --git a/src/screens/Settings/AccountSettings.tsx b/src/screens/Settings/AccountSettings.tsx
index f34810a68..35c5f3aa0 100644
--- a/src/screens/Settings/AccountSettings.tsx
+++ b/src/screens/Settings/AccountSettings.tsx
@@ -6,7 +6,6 @@ import {NativeStackScreenProps} from '@react-navigation/native-stack'
 import {CommonNavigatorParams} from '#/lib/routes/types'
 import {useModalControls} from '#/state/modals'
 import {useSession} from '#/state/session'
-import {ExportCarDialog} from '#/view/screens/Settings/ExportCarDialog'
 import * as SettingsList from '#/screens/Settings/components/SettingsList'
 import {atoms as a, useTheme} from '#/alf'
 import {useDialogControl} from '#/components/Dialog'
@@ -24,6 +23,7 @@ import {Verified_Stroke2_Corner2_Rounded as VerifiedIcon} from '#/components/ico
 import * as Layout from '#/components/Layout'
 import {ChangeHandleDialog} from './components/ChangeHandleDialog'
 import {DeactivateAccountDialog} from './components/DeactivateAccountDialog'
+import {ExportCarDialog} from './components/ExportCarDialog'
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'AccountSettings'>
 export function AccountSettingsScreen({}: Props) {
diff --git a/src/view/screens/Settings/DisableEmail2FADialog.tsx b/src/screens/Settings/components/DisableEmail2FADialog.tsx
index 1378759b0..1378759b0 100644
--- a/src/view/screens/Settings/DisableEmail2FADialog.tsx
+++ b/src/screens/Settings/components/DisableEmail2FADialog.tsx
diff --git a/src/screens/Settings/components/Email2FAToggle.tsx b/src/screens/Settings/components/Email2FAToggle.tsx
index 85ae89dea..a74f9fce7 100644
--- a/src/screens/Settings/components/Email2FAToggle.tsx
+++ b/src/screens/Settings/components/Email2FAToggle.tsx
@@ -4,9 +4,9 @@ import {useLingui} from '@lingui/react'
 
 import {useModalControls} from '#/state/modals'
 import {useAgent, useSession} from '#/state/session'
-import {DisableEmail2FADialog} from '#/view/screens/Settings/DisableEmail2FADialog'
 import {useDialogControl} from '#/components/Dialog'
 import * as Prompt from '#/components/Prompt'
+import {DisableEmail2FADialog} from './DisableEmail2FADialog'
 import * as SettingsList from './SettingsList'
 
 export function Email2FAToggle() {
diff --git a/src/view/screens/Settings/ExportCarDialog.tsx b/src/screens/Settings/components/ExportCarDialog.tsx
index 2de3895d3..2de3895d3 100644
--- a/src/view/screens/Settings/ExportCarDialog.tsx
+++ b/src/screens/Settings/components/ExportCarDialog.tsx
diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx
index 78f476d52..483de99e4 100644
--- a/src/state/modals/index.tsx
+++ b/src/state/modals/index.tsx
@@ -48,11 +48,6 @@ export interface DeleteAccountModal {
   name: 'delete-account'
 }
 
-export interface ChangeHandleModal {
-  name: 'change-handle'
-  onChanged: () => void
-}
-
 export interface WaitlistModal {
   name: 'waitlist'
 }
@@ -61,10 +56,6 @@ export interface InviteCodesModal {
   name: 'invite-codes'
 }
 
-export interface AddAppPasswordModal {
-  name: 'add-app-password'
-}
-
 export interface ContentLanguagesSettingsModal {
   name: 'content-languages-settings'
 }
@@ -101,8 +92,6 @@ export interface InAppBrowserConsentModal {
 
 export type Modal =
   // Account
-  | AddAppPasswordModal
-  | ChangeHandleModal
   | DeleteAccountModal
   | VerifyEmailModal
   | ChangeEmailModal
diff --git a/src/view/com/modals/AddAppPasswords.tsx b/src/view/com/modals/AddAppPasswords.tsx
deleted file mode 100644
index f7991f59b..000000000
--- a/src/view/com/modals/AddAppPasswords.tsx
+++ /dev/null
@@ -1,307 +0,0 @@
-import React, {useState} from 'react'
-import {StyleSheet, TextInput, TouchableOpacity, View} from 'react-native'
-import {setStringAsync} from 'expo-clipboard'
-import {
-  FontAwesomeIcon,
-  FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {usePalette} from '#/lib/hooks/usePalette'
-import {s} from '#/lib/styles'
-import {logger} from '#/logger'
-import {isNative} from '#/platform/detection'
-import {useModalControls} from '#/state/modals'
-import {
-  useAppPasswordCreateMutation,
-  useAppPasswordsQuery,
-} from '#/state/queries/app-passwords'
-import {Button} from '#/view/com/util/forms/Button'
-import {Text} from '#/view/com/util/text/Text'
-import * as Toast from '#/view/com/util/Toast'
-import {atoms as a} from '#/alf'
-import * as Toggle from '#/components/forms/Toggle'
-
-export const snapPoints = ['90%']
-
-const shadesOfBlue: string[] = [
-  'AliceBlue',
-  'Aqua',
-  'Aquamarine',
-  'Azure',
-  'BabyBlue',
-  'Blue',
-  'BlueViolet',
-  'CadetBlue',
-  'CornflowerBlue',
-  'Cyan',
-  'DarkBlue',
-  'DarkCyan',
-  'DarkSlateBlue',
-  'DeepSkyBlue',
-  'DodgerBlue',
-  'ElectricBlue',
-  'LightBlue',
-  'LightCyan',
-  'LightSkyBlue',
-  'LightSteelBlue',
-  'MediumAquaMarine',
-  'MediumBlue',
-  'MediumSlateBlue',
-  'MidnightBlue',
-  'Navy',
-  'PowderBlue',
-  'RoyalBlue',
-  'SkyBlue',
-  'SlateBlue',
-  'SteelBlue',
-  'Teal',
-  'Turquoise',
-]
-
-export function Component({}: {}) {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const {closeModal} = useModalControls()
-  const {data: passwords} = useAppPasswordsQuery()
-  const {mutateAsync: mutateAppPassword, isPending} =
-    useAppPasswordCreateMutation()
-  const [name, setName] = useState(
-    shadesOfBlue[Math.floor(Math.random() * shadesOfBlue.length)],
-  )
-  const [appPassword, setAppPassword] = useState<string>()
-  const [wasCopied, setWasCopied] = useState(false)
-  const [privileged, setPrivileged] = useState(false)
-
-  const onCopy = React.useCallback(() => {
-    if (appPassword) {
-      setStringAsync(appPassword)
-      Toast.show(_(msg`Copied to clipboard`), 'clipboard-check')
-      setWasCopied(true)
-    }
-  }, [appPassword, _])
-
-  const onDone = React.useCallback(() => {
-    closeModal()
-  }, [closeModal])
-
-  const createAppPassword = async () => {
-    // if name is all whitespace, we don't allow it
-    if (!name || !name.trim()) {
-      Toast.show(
-        _(
-          msg`Please enter a name for your app password. All spaces is not allowed.`,
-        ),
-        'xmark',
-      )
-      return
-    }
-    // if name is too short (under 4 chars), we don't allow it
-    if (name.length < 4) {
-      Toast.show(
-        _(msg`App Password names must be at least 4 characters long.`),
-        'xmark',
-      )
-      return
-    }
-
-    if (passwords?.find(p => p.name === name)) {
-      Toast.show(_(msg`This name is already in use`), 'xmark')
-      return
-    }
-
-    try {
-      const newPassword = await mutateAppPassword({name, privileged})
-      if (newPassword) {
-        setAppPassword(newPassword.password)
-      } else {
-        Toast.show(_(msg`Failed to create app password.`), 'xmark')
-        // TODO: better error handling (?)
-      }
-    } catch (e) {
-      Toast.show(_(msg`Failed to create app password.`), 'xmark')
-      logger.error('Failed to create app password', {message: e})
-    }
-  }
-
-  const _onChangeText = (text: string) => {
-    // sanitize input
-    // we only all alphanumeric characters, spaces, dashes, and underscores
-    // if the user enters anything else, we ignore it and shake the input container
-    // also, it cannot start with a space
-    if (text.match(/^[a-zA-Z0-9-_ ]*$/)) {
-      setName(text)
-    } else {
-      Toast.show(
-        _(
-          msg`App Password names can only contain letters, numbers, spaces, dashes, and underscores.`,
-        ),
-        'xmark',
-      )
-    }
-  }
-
-  return (
-    <View style={[styles.container, pal.view]} testID="addAppPasswordsModal">
-      {!appPassword ? (
-        <>
-          <View>
-            <Text type="lg" style={[pal.text]}>
-              <Trans>
-                Please enter a unique name for this App Password or use our
-                randomly generated one.
-              </Trans>
-            </Text>
-            <View style={[pal.btn, styles.textInputWrapper]}>
-              <TextInput
-                style={[styles.input, pal.text]}
-                onChangeText={_onChangeText}
-                value={name}
-                placeholder={_(msg`Enter a name for this App Password`)}
-                placeholderTextColor={pal.colors.textLight}
-                autoCorrect={false}
-                autoComplete="off"
-                autoCapitalize="none"
-                autoFocus={true}
-                maxLength={32}
-                selectTextOnFocus={true}
-                blurOnSubmit={true}
-                editable={!isPending}
-                returnKeyType="done"
-                onSubmitEditing={createAppPassword}
-                accessible={true}
-                accessibilityLabel={_(msg`Name`)}
-                accessibilityHint={_(msg`Input name for app password`)}
-              />
-            </View>
-          </View>
-          <Text type="xs" style={[pal.textLight, s.mb10, s.mt2]}>
-            <Trans>
-              Can only contain letters, numbers, spaces, dashes, and
-              underscores. Must be at least 4 characters long, but no more than
-              32 characters long.
-            </Trans>
-          </Text>
-          <Toggle.Item
-            type="checkbox"
-            label={_(msg`Allow access to your direct messages`)}
-            value={privileged}
-            onChange={val => setPrivileged(val)}
-            name="privileged"
-            style={a.my_md}>
-            <Toggle.Checkbox />
-            <Toggle.LabelText>
-              <Trans>Allow access to your direct messages</Trans>
-            </Toggle.LabelText>
-          </Toggle.Item>
-        </>
-      ) : (
-        <>
-          <View>
-            <Text type="lg" style={[pal.text]}>
-              <Text type="lg-bold" style={[pal.text, s.mr5]}>
-                <Trans>Here is your app password.</Trans>
-              </Text>
-              <Trans>
-                Use this to sign into the other app along with your handle.
-              </Trans>
-            </Text>
-            <TouchableOpacity
-              style={[pal.border, styles.passwordContainer, pal.btn]}
-              onPress={onCopy}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Copy`)}
-              accessibilityHint={_(msg`Copies app password`)}>
-              <Text type="2xl-bold" style={[pal.text]}>
-                {appPassword}
-              </Text>
-              {wasCopied ? (
-                <Text style={[pal.textLight]}>
-                  <Trans>Copied</Trans>
-                </Text>
-              ) : (
-                <FontAwesomeIcon
-                  icon={['far', 'clone']}
-                  style={pal.text as FontAwesomeIconStyle}
-                  size={18}
-                />
-              )}
-            </TouchableOpacity>
-          </View>
-          <Text type="lg" style={[pal.textLight, s.mb10]}>
-            <Trans>
-              For security reasons, you won't be able to view this again. If you
-              lose this password, you'll need to generate a new one.
-            </Trans>
-          </Text>
-        </>
-      )}
-      <View style={styles.btnContainer}>
-        <Button
-          type="primary"
-          label={!appPassword ? _(msg`Create App Password`) : _(msg`Done`)}
-          style={styles.btn}
-          labelStyle={styles.btnLabel}
-          onPress={!appPassword ? createAppPassword : onDone}
-        />
-      </View>
-    </View>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-    paddingBottom: isNative ? 50 : 0,
-    paddingHorizontal: 16,
-  },
-  textInputWrapper: {
-    borderRadius: 8,
-    flexDirection: 'row',
-    alignItems: 'center',
-    marginTop: 16,
-    marginBottom: 8,
-  },
-  input: {
-    flex: 1,
-    width: '100%',
-    paddingVertical: 10,
-    paddingHorizontal: 8,
-    fontSize: 17,
-    letterSpacing: 0.25,
-    fontWeight: '400',
-    borderRadius: 10,
-  },
-  passwordContainer: {
-    flexDirection: 'row',
-    justifyContent: 'space-between',
-    paddingVertical: 8,
-    paddingHorizontal: 16,
-    alignItems: 'center',
-    borderRadius: 10,
-    marginTop: 16,
-    marginBottom: 12,
-  },
-  btnContainer: {
-    flexDirection: 'row',
-    justifyContent: 'center',
-    marginTop: 12,
-  },
-  btn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    borderRadius: 32,
-    paddingHorizontal: 60,
-    paddingVertical: 14,
-  },
-  btnLabel: {
-    fontSize: 18,
-  },
-  groupContent: {
-    borderTopWidth: 1,
-    flexDirection: 'row',
-    alignItems: 'center',
-  },
-})
diff --git a/src/view/com/modals/ChangeHandle.tsx b/src/view/com/modals/ChangeHandle.tsx
deleted file mode 100644
index 2181a94aa..000000000
--- a/src/view/com/modals/ChangeHandle.tsx
+++ /dev/null
@@ -1,614 +0,0 @@
-import React, {useState} from 'react'
-import {
-  ActivityIndicator,
-  StyleSheet,
-  TouchableOpacity,
-  View,
-} from 'react-native'
-import {setStringAsync} from 'expo-clipboard'
-import {ComAtprotoServerDescribeServer} from '@atproto/api'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {usePalette} from '#/lib/hooks/usePalette'
-import {cleanError} from '#/lib/strings/errors'
-import {createFullHandle, makeValidHandle} from '#/lib/strings/handles'
-import {s} from '#/lib/styles'
-import {useTheme} from '#/lib/ThemeContext'
-import {logger} from '#/logger'
-import {useModalControls} from '#/state/modals'
-import {useFetchDid, useUpdateHandleMutation} from '#/state/queries/handle'
-import {useServiceQuery} from '#/state/queries/service'
-import {SessionAccount, useAgent, useSession} from '#/state/session'
-import {ErrorMessage} from '../util/error/ErrorMessage'
-import {Button} from '../util/forms/Button'
-import {SelectableBtn} from '../util/forms/SelectableBtn'
-import {Text} from '../util/text/Text'
-import * as Toast from '../util/Toast'
-import {ScrollView, TextInput} from './util'
-
-export const snapPoints = ['100%']
-
-export type Props = {onChanged: () => void}
-
-export function Component(props: Props) {
-  const {currentAccount} = useSession()
-  const agent = useAgent()
-  const {
-    isLoading,
-    data: serviceInfo,
-    error: serviceInfoError,
-  } = useServiceQuery(agent.service.toString())
-
-  return isLoading || !currentAccount ? (
-    <View style={{padding: 18}}>
-      <ActivityIndicator />
-    </View>
-  ) : serviceInfoError || !serviceInfo ? (
-    <ErrorMessage message={cleanError(serviceInfoError)} />
-  ) : (
-    <Inner
-      {...props}
-      currentAccount={currentAccount}
-      serviceInfo={serviceInfo}
-    />
-  )
-}
-
-export function Inner({
-  currentAccount,
-  serviceInfo,
-  onChanged,
-}: Props & {
-  currentAccount: SessionAccount
-  serviceInfo: ComAtprotoServerDescribeServer.OutputSchema
-}) {
-  const {_} = useLingui()
-  const pal = usePalette('default')
-  const {closeModal} = useModalControls()
-  const {mutateAsync: updateHandle, isPending: isUpdateHandlePending} =
-    useUpdateHandleMutation()
-  const agent = useAgent()
-
-  const [error, setError] = useState<string>('')
-
-  const [isCustom, setCustom] = React.useState<boolean>(false)
-  const [handle, setHandle] = React.useState<string>('')
-  const [canSave, setCanSave] = React.useState<boolean>(false)
-
-  const userDomain = serviceInfo.availableUserDomains?.[0]
-
-  // events
-  // =
-  const onPressCancel = React.useCallback(() => {
-    closeModal()
-  }, [closeModal])
-  const onToggleCustom = React.useCallback(() => {
-    // toggle between a provided domain vs a custom one
-    setHandle('')
-    setCanSave(false)
-    setCustom(!isCustom)
-  }, [setCustom, isCustom])
-  const onPressSave = React.useCallback(async () => {
-    if (!userDomain) {
-      logger.error(`ChangeHandle: userDomain is undefined`, {
-        service: serviceInfo,
-      })
-      setError(`The service you've selected has no domains configured.`)
-      return
-    }
-
-    try {
-      const newHandle = isCustom ? handle : createFullHandle(handle, userDomain)
-      logger.debug(`Updating handle to ${newHandle}`)
-      await updateHandle({
-        handle: newHandle,
-      })
-      await agent.resumeSession(agent.session!)
-      closeModal()
-      onChanged()
-    } catch (err: any) {
-      setError(cleanError(err))
-      logger.error('Failed to update handle', {handle, message: err})
-    } finally {
-    }
-  }, [
-    setError,
-    handle,
-    userDomain,
-    isCustom,
-    onChanged,
-    closeModal,
-    updateHandle,
-    serviceInfo,
-    agent,
-  ])
-
-  // rendering
-  // =
-  return (
-    <View style={[s.flex1, pal.view]}>
-      <View style={[styles.title, pal.border]}>
-        <View style={styles.titleLeft}>
-          <TouchableOpacity
-            onPress={onPressCancel}
-            accessibilityRole="button"
-            accessibilityLabel={_(msg`Cancel change handle`)}
-            accessibilityHint={_(msg`Exits handle change process`)}
-            onAccessibilityEscape={onPressCancel}>
-            <Text type="lg" style={pal.textLight}>
-              <Trans>Cancel</Trans>
-            </Text>
-          </TouchableOpacity>
-        </View>
-        <Text
-          type="2xl-bold"
-          style={[styles.titleMiddle, pal.text]}
-          numberOfLines={1}>
-          <Trans>Change Handle</Trans>
-        </Text>
-        <View style={styles.titleRight}>
-          {isUpdateHandlePending ? (
-            <ActivityIndicator />
-          ) : canSave ? (
-            <TouchableOpacity
-              onPress={onPressSave}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Save handle change`)}
-              accessibilityHint={_(msg`Saves handle change to ${handle}`)}>
-              <Text type="2xl-medium" style={pal.link}>
-                <Trans>Save</Trans>
-              </Text>
-            </TouchableOpacity>
-          ) : undefined}
-        </View>
-      </View>
-      <ScrollView style={styles.inner}>
-        {error !== '' && (
-          <View style={styles.errorContainer}>
-            <ErrorMessage message={error} />
-          </View>
-        )}
-
-        {isCustom ? (
-          <CustomHandleForm
-            currentAccount={currentAccount}
-            handle={handle}
-            isProcessing={isUpdateHandlePending}
-            canSave={canSave}
-            onToggleCustom={onToggleCustom}
-            setHandle={setHandle}
-            setCanSave={setCanSave}
-            onPressSave={onPressSave}
-          />
-        ) : (
-          <ProvidedHandleForm
-            handle={handle}
-            userDomain={userDomain}
-            isProcessing={isUpdateHandlePending}
-            onToggleCustom={onToggleCustom}
-            setHandle={setHandle}
-            setCanSave={setCanSave}
-          />
-        )}
-      </ScrollView>
-    </View>
-  )
-}
-
-/**
- * The form for using a domain allocated by the PDS
- */
-function ProvidedHandleForm({
-  userDomain,
-  handle,
-  isProcessing,
-  setHandle,
-  onToggleCustom,
-  setCanSave,
-}: {
-  userDomain: string
-  handle: string
-  isProcessing: boolean
-  setHandle: (v: string) => void
-  onToggleCustom: () => void
-  setCanSave: (v: boolean) => void
-}) {
-  const pal = usePalette('default')
-  const theme = useTheme()
-  const {_} = useLingui()
-
-  // events
-  // =
-  const onChangeHandle = React.useCallback(
-    (v: string) => {
-      const newHandle = makeValidHandle(v)
-      setHandle(newHandle)
-      setCanSave(newHandle.length > 0)
-    },
-    [setHandle, setCanSave],
-  )
-
-  // rendering
-  // =
-  return (
-    <>
-      <View style={[pal.btn, styles.textInputWrapper]}>
-        <FontAwesomeIcon
-          icon="at"
-          style={[pal.textLight, styles.textInputIcon]}
-        />
-        <TextInput
-          testID="setHandleInput"
-          style={[pal.text, styles.textInput]}
-          placeholder={_(msg`e.g. alice`)}
-          placeholderTextColor={pal.colors.textLight}
-          autoCapitalize="none"
-          keyboardAppearance={theme.colorScheme}
-          value={handle}
-          onChangeText={onChangeHandle}
-          editable={!isProcessing}
-          accessible={true}
-          accessibilityLabel={_(msg`Handle`)}
-          accessibilityHint={_(msg`Sets Bluesky username`)}
-        />
-      </View>
-      <Text type="md" style={[pal.textLight, s.pl10, s.pt10]}>
-        <Trans>
-          Your full handle will be{' '}
-          <Text type="md-bold" style={pal.textLight}>
-            @{createFullHandle(handle, userDomain)}
-          </Text>
-        </Trans>
-      </Text>
-      <TouchableOpacity
-        onPress={onToggleCustom}
-        accessibilityRole="button"
-        accessibilityLabel={_(msg`Hosting provider`)}
-        accessibilityHint={_(msg`Opens modal for using custom domain`)}>
-        <Text type="md-medium" style={[pal.link, s.pl10, s.pt5]}>
-          <Trans>I have my own domain</Trans>
-        </Text>
-      </TouchableOpacity>
-    </>
-  )
-}
-
-/**
- * The form for using a custom domain
- */
-function CustomHandleForm({
-  currentAccount,
-  handle,
-  canSave,
-  isProcessing,
-  setHandle,
-  onToggleCustom,
-  onPressSave,
-  setCanSave,
-}: {
-  currentAccount: SessionAccount
-  handle: string
-  canSave: boolean
-  isProcessing: boolean
-  setHandle: (v: string) => void
-  onToggleCustom: () => void
-  onPressSave: () => void
-  setCanSave: (v: boolean) => void
-}) {
-  const pal = usePalette('default')
-  const palSecondary = usePalette('secondary')
-  const palError = usePalette('error')
-  const theme = useTheme()
-  const {_} = useLingui()
-  const [isVerifying, setIsVerifying] = React.useState(false)
-  const [error, setError] = React.useState<string>('')
-  const [isDNSForm, setDNSForm] = React.useState<boolean>(true)
-  const fetchDid = useFetchDid()
-  // events
-  // =
-  const onPressCopy = React.useCallback(() => {
-    setStringAsync(isDNSForm ? `did=${currentAccount.did}` : currentAccount.did)
-    Toast.show(_(msg`Copied to clipboard`), 'clipboard-check')
-  }, [currentAccount, isDNSForm, _])
-  const onChangeHandle = React.useCallback(
-    (v: string) => {
-      setHandle(v)
-      setCanSave(false)
-    },
-    [setHandle, setCanSave],
-  )
-  const onPressVerify = React.useCallback(async () => {
-    if (canSave) {
-      onPressSave()
-    }
-    try {
-      setIsVerifying(true)
-      setError('')
-      const did = await fetchDid(handle)
-      if (did === currentAccount.did) {
-        setCanSave(true)
-      } else {
-        setError(`Incorrect DID returned (got ${did})`)
-      }
-    } catch (err: any) {
-      setError(cleanError(err))
-      logger.error('Failed to verify domain', {handle, error: err})
-    } finally {
-      setIsVerifying(false)
-    }
-  }, [
-    handle,
-    currentAccount,
-    setIsVerifying,
-    setCanSave,
-    setError,
-    canSave,
-    onPressSave,
-    fetchDid,
-  ])
-
-  // rendering
-  // =
-  return (
-    <>
-      <Text type="md" style={[pal.text, s.pb5, s.pl5]} nativeID="customDomain">
-        <Trans>Enter the domain you want to use</Trans>
-      </Text>
-      <View style={[pal.btn, styles.textInputWrapper]}>
-        <FontAwesomeIcon
-          icon="at"
-          style={[pal.textLight, styles.textInputIcon]}
-        />
-        <TextInput
-          testID="setHandleInput"
-          style={[pal.text, styles.textInput]}
-          placeholder={_(msg`e.g. alice.com`)}
-          placeholderTextColor={pal.colors.textLight}
-          autoCapitalize="none"
-          keyboardAppearance={theme.colorScheme}
-          value={handle}
-          onChangeText={onChangeHandle}
-          editable={!isProcessing}
-          accessibilityLabelledBy="customDomain"
-          accessibilityLabel={_(msg`Custom domain`)}
-          accessibilityHint={_(msg`Input your preferred hosting provider`)}
-        />
-      </View>
-      <View style={styles.spacer} />
-
-      <View style={[styles.selectableBtns]}>
-        <SelectableBtn
-          selected={isDNSForm}
-          label={_(msg`DNS Panel`)}
-          left
-          onSelect={() => setDNSForm(true)}
-          accessibilityHint={_(msg`Use the DNS panel`)}
-          style={s.flex1}
-        />
-        <SelectableBtn
-          selected={!isDNSForm}
-          label={_(msg`No DNS Panel`)}
-          right
-          onSelect={() => setDNSForm(false)}
-          accessibilityHint={_(msg`Use a file on your server`)}
-          style={s.flex1}
-        />
-      </View>
-      <View style={styles.spacer} />
-      {isDNSForm ? (
-        <>
-          <Text type="md" style={[pal.text, s.pb5, s.pl5]}>
-            <Trans>Add the following DNS record to your domain:</Trans>
-          </Text>
-          <View style={[styles.dnsTable, pal.btn]}>
-            <Text type="md-medium" style={[styles.dnsLabel, pal.text]}>
-              <Trans>Host:</Trans>
-            </Text>
-            <View style={[styles.dnsValue]}>
-              <Text type="mono" style={[styles.monoText, pal.text]}>
-                _atproto
-              </Text>
-            </View>
-            <Text type="md-medium" style={[styles.dnsLabel, pal.text]}>
-              <Trans>Type:</Trans>
-            </Text>
-            <View style={[styles.dnsValue]}>
-              <Text type="mono" style={[styles.monoText, pal.text]}>
-                TXT
-              </Text>
-            </View>
-            <Text type="md-medium" style={[styles.dnsLabel, pal.text]}>
-              <Trans>Value:</Trans>
-            </Text>
-            <View style={[styles.dnsValue]}>
-              <Text type="mono" style={[styles.monoText, pal.text]}>
-                did={currentAccount.did}
-              </Text>
-            </View>
-          </View>
-          <Text type="md" style={[pal.text, s.pt20, s.pl5]}>
-            <Trans>This should create a domain record at:</Trans>
-          </Text>
-          <Text type="mono" style={[styles.monoText, pal.text, s.pt5, s.pl5]}>
-            _atproto.{handle}
-          </Text>
-        </>
-      ) : (
-        <>
-          <Text type="md" style={[pal.text, s.pb5, s.pl5]}>
-            <Trans>Upload a text file to:</Trans>
-          </Text>
-          <View style={[styles.valueContainer, pal.btn]}>
-            <View style={[styles.dnsValue]}>
-              <Text type="mono" style={[styles.monoText, pal.text]}>
-                https://{handle}/.well-known/atproto-did
-              </Text>
-            </View>
-          </View>
-          <View style={styles.spacer} />
-          <Text type="md" style={[pal.text, s.pb5, s.pl5]}>
-            <Trans>That contains the following:</Trans>
-          </Text>
-          <View style={[styles.valueContainer, pal.btn]}>
-            <View style={[styles.dnsValue]}>
-              <Text type="mono" style={[styles.monoText, pal.text]}>
-                {currentAccount.did}
-              </Text>
-            </View>
-          </View>
-        </>
-      )}
-
-      <View style={styles.spacer} />
-      <Button type="default" style={[s.p20, s.mb10]} onPress={onPressCopy}>
-        <Text type="xl" style={[pal.link, s.textCenter]}>
-          <Trans>
-            Copy {isDNSForm ? _(msg`Domain Value`) : _(msg`File Contents`)}
-          </Trans>
-        </Text>
-      </Button>
-      {canSave === true && (
-        <View style={[styles.message, palSecondary.view]}>
-          <Text type="md-medium" style={palSecondary.text}>
-            <Trans>Domain verified!</Trans>
-          </Text>
-        </View>
-      )}
-      {error ? (
-        <View style={[styles.message, palError.view]}>
-          <Text type="md-medium" style={palError.text}>
-            {error}
-          </Text>
-        </View>
-      ) : null}
-      <Button
-        type="primary"
-        style={[s.p20, isVerifying && styles.dimmed]}
-        onPress={onPressVerify}>
-        {isVerifying ? (
-          <ActivityIndicator color="white" />
-        ) : (
-          <Text type="xl-medium" style={[s.white, s.textCenter]}>
-            {canSave
-              ? _(msg`Update to ${handle}`)
-              : isDNSForm
-              ? _(msg`Verify DNS Record`)
-              : _(msg`Verify Text File`)}
-          </Text>
-        )}
-      </Button>
-      <View style={styles.spacer} />
-      <TouchableOpacity
-        onPress={onToggleCustom}
-        accessibilityLabel={_(msg`Use default provider`)}
-        accessibilityHint={_(msg`Use bsky.social as hosting provider`)}>
-        <Text type="md-medium" style={[pal.link, s.pl10, s.pt5]}>
-          <Trans>Nevermind, create a handle for me</Trans>
-        </Text>
-      </TouchableOpacity>
-    </>
-  )
-}
-
-const styles = StyleSheet.create({
-  inner: {
-    padding: 14,
-  },
-  footer: {
-    padding: 14,
-  },
-  spacer: {
-    height: 20,
-  },
-  dimmed: {
-    opacity: 0.7,
-  },
-
-  selectableBtns: {
-    flexDirection: 'row',
-  },
-
-  title: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingTop: 25,
-    paddingHorizontal: 20,
-    paddingBottom: 15,
-    borderBottomWidth: 1,
-  },
-  titleLeft: {
-    width: 80,
-  },
-  titleRight: {
-    width: 80,
-    flexDirection: 'row',
-    justifyContent: 'flex-end',
-  },
-  titleMiddle: {
-    flex: 1,
-    textAlign: 'center',
-    fontSize: 21,
-  },
-
-  textInputWrapper: {
-    borderRadius: 8,
-    flexDirection: 'row',
-    alignItems: 'center',
-  },
-  textInputIcon: {
-    marginLeft: 12,
-  },
-  textInput: {
-    flex: 1,
-    width: '100%',
-    paddingVertical: 10,
-    paddingHorizontal: 8,
-    fontSize: 17,
-    letterSpacing: 0.25,
-    fontWeight: '400',
-    borderRadius: 10,
-  },
-
-  valueContainer: {
-    borderRadius: 4,
-    paddingVertical: 16,
-  },
-
-  dnsTable: {
-    borderRadius: 4,
-    paddingTop: 2,
-    paddingBottom: 16,
-  },
-  dnsLabel: {
-    paddingHorizontal: 14,
-    paddingTop: 10,
-  },
-  dnsValue: {
-    paddingHorizontal: 14,
-    borderRadius: 4,
-  },
-  monoText: {
-    fontSize: 18,
-    lineHeight: 20,
-  },
-
-  message: {
-    paddingHorizontal: 12,
-    paddingVertical: 10,
-    borderRadius: 8,
-    marginBottom: 10,
-  },
-
-  btn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    width: '100%',
-    borderRadius: 32,
-    padding: 10,
-    marginBottom: 10,
-  },
-  errorContainer: {marginBottom: 10},
-})
diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx
index becb39ff3..78f4a0117 100644
--- a/src/view/com/modals/Modal.tsx
+++ b/src/view/com/modals/Modal.tsx
@@ -7,9 +7,7 @@ import {usePalette} from '#/lib/hooks/usePalette'
 import {useModalControls, useModals} from '#/state/modals'
 import {FullWindowOverlay} from '#/components/FullWindowOverlay'
 import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
-import * as AddAppPassword from './AddAppPasswords'
 import * as ChangeEmailModal from './ChangeEmail'
-import * as ChangeHandleModal from './ChangeHandle'
 import * as ChangePasswordModal from './ChangePassword'
 import * as CreateOrEditListModal from './CreateOrEditList'
 import * as DeleteAccountModal from './DeleteAccount'
@@ -69,15 +67,9 @@ export function ModalsContainer() {
   } else if (activeModal?.name === 'delete-account') {
     snapPoints = DeleteAccountModal.snapPoints
     element = <DeleteAccountModal.Component />
-  } else if (activeModal?.name === 'change-handle') {
-    snapPoints = ChangeHandleModal.snapPoints
-    element = <ChangeHandleModal.Component {...activeModal} />
   } else if (activeModal?.name === 'invite-codes') {
     snapPoints = InviteCodesModal.snapPoints
     element = <InviteCodesModal.Component />
-  } else if (activeModal?.name === 'add-app-password') {
-    snapPoints = AddAppPassword.snapPoints
-    element = <AddAppPassword.Component />
   } else if (activeModal?.name === 'content-languages-settings') {
     snapPoints = ContentLanguagesSettingsModal.snapPoints
     element = <ContentLanguagesSettingsModal.Component />
diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx
index 46ced58d9..e9d9c01dd 100644
--- a/src/view/com/modals/Modal.web.tsx
+++ b/src/view/com/modals/Modal.web.tsx
@@ -7,9 +7,7 @@ import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import type {Modal as ModalIface} from '#/state/modals'
 import {useModalControls, useModals} from '#/state/modals'
-import * as AddAppPassword from './AddAppPasswords'
 import * as ChangeEmailModal from './ChangeEmail'
-import * as ChangeHandleModal from './ChangeHandle'
 import * as ChangePasswordModal from './ChangePassword'
 import * as CreateOrEditListModal from './CreateOrEditList'
 import * as CropImageModal from './CropImage.web'
@@ -74,12 +72,8 @@ function Modal({modal}: {modal: ModalIface}) {
     element = <CropImageModal.Component {...modal} />
   } else if (modal.name === 'delete-account') {
     element = <DeleteAccountModal.Component />
-  } else if (modal.name === 'change-handle') {
-    element = <ChangeHandleModal.Component {...modal} />
   } else if (modal.name === 'invite-codes') {
     element = <InviteCodesModal.Component />
-  } else if (modal.name === 'add-app-password') {
-    element = <AddAppPassword.Component />
   } else if (modal.name === 'content-languages-settings') {
     element = <ContentLanguagesSettingsModal.Component />
   } else if (modal.name === 'post-languages-settings') {
diff --git a/src/view/com/util/AccountDropdownBtn.tsx b/src/view/com/util/AccountDropdownBtn.tsx
deleted file mode 100644
index e7985bccf..000000000
--- a/src/view/com/util/AccountDropdownBtn.tsx
+++ /dev/null
@@ -1,66 +0,0 @@
-import React from 'react'
-import {Pressable} from 'react-native'
-import {
-  FontAwesomeIcon,
-  FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {usePalette} from '#/lib/hooks/usePalette'
-import {s} from '#/lib/styles'
-import {SessionAccount, useSessionApi} from '#/state/session'
-import {useDialogControl} from '#/components/Dialog'
-import * as Prompt from '#/components/Prompt'
-import * as Toast from '../../com/util/Toast'
-import {DropdownItem, NativeDropdown} from './forms/NativeDropdown'
-
-export function AccountDropdownBtn({account}: {account: SessionAccount}) {
-  const pal = usePalette('default')
-  const {removeAccount} = useSessionApi()
-  const removePromptControl = useDialogControl()
-  const {_} = useLingui()
-
-  const items: DropdownItem[] = [
-    {
-      label: _(msg`Remove account`),
-      onPress: removePromptControl.open,
-      icon: {
-        ios: {
-          name: 'trash',
-        },
-        android: 'ic_delete',
-        web: ['far', 'trash-can'],
-      },
-    },
-  ]
-  return (
-    <>
-      <Pressable accessibilityRole="button" style={s.pl10}>
-        <NativeDropdown
-          testID="accountSettingsDropdownBtn"
-          items={items}
-          accessibilityLabel={_(msg`Account options`)}
-          accessibilityHint="">
-          <FontAwesomeIcon
-            icon="ellipsis-h"
-            style={pal.textLight as FontAwesomeIconStyle}
-          />
-        </NativeDropdown>
-      </Pressable>
-      <Prompt.Basic
-        control={removePromptControl}
-        title={_(msg`Remove from quick access?`)}
-        description={_(
-          msg`This will remove @${account.handle} from the quick access list.`,
-        )}
-        onConfirm={() => {
-          removeAccount(account)
-          Toast.show(_(msg`Account removed from quick access`))
-        }}
-        confirmButtonCta={_(msg`Remove`)}
-        confirmButtonColor="negative"
-      />
-    </>
-  )
-}
diff --git a/src/view/com/util/List.web.tsx b/src/view/com/util/List.web.tsx
index 59a79b531..5ddc4ea8a 100644
--- a/src/view/com/util/List.web.tsx
+++ b/src/view/com/util/List.web.tsx
@@ -448,7 +448,9 @@ let Row = function RowImpl<ItemT>({
   onItemSeen: ((item: any) => void) | undefined
 }): React.ReactNode {
   const rowRef = React.useRef(null)
-  const intersectionTimeout = React.useRef<NodeJS.Timer | undefined>(undefined)
+  const intersectionTimeout = React.useRef<
+    ReturnType<typeof setTimeout> | undefined
+  >(undefined)
 
   const handleIntersection = useNonReactiveCallback(
     (entries: IntersectionObserverEntry[]) => {
diff --git a/src/view/screens/AccessibilitySettings.tsx b/src/view/screens/AccessibilitySettings.tsx
deleted file mode 100644
index 4dd5aa97b..000000000
--- a/src/view/screens/AccessibilitySettings.tsx
+++ /dev/null
@@ -1,157 +0,0 @@
-import React from 'react'
-import {StyleSheet, View} from 'react-native'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useFocusEffect} from '@react-navigation/native'
-
-import {IS_INTERNAL} from '#/lib/app-info'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
-import {s} from '#/lib/styles'
-import {isNative} from '#/platform/detection'
-import {
-  useAutoplayDisabled,
-  useHapticsDisabled,
-  useRequireAltTextEnabled,
-  useSetAutoplayDisabled,
-  useSetHapticsDisabled,
-  useSetRequireAltTextEnabled,
-} from '#/state/preferences'
-import {
-  useLargeAltBadgeEnabled,
-  useSetLargeAltBadgeEnabled,
-} from '#/state/preferences/large-alt-badge'
-import {useSetMinimalShellMode} from '#/state/shell'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
-import {Text} from '#/view/com/util/text/Text'
-import {ScrollView} from '#/view/com/util/Views'
-import {AccessibilitySettingsScreen as NewAccessibilitySettingsScreen} from '#/screens/Settings/AccessibilitySettings'
-import {atoms as a} from '#/alf'
-import * as Layout from '#/components/Layout'
-
-type Props = NativeStackScreenProps<
-  CommonNavigatorParams,
-  'AccessibilitySettings'
->
-export function AccessibilitySettingsScreen(props: Props) {
-  return IS_INTERNAL ? (
-    <NewAccessibilitySettingsScreen {...props} />
-  ) : (
-    <LegacyAccessibilitySettingsScreen {...props} />
-  )
-}
-
-function LegacyAccessibilitySettingsScreen({}: Props) {
-  const pal = usePalette('default')
-  const setMinimalShellMode = useSetMinimalShellMode()
-  const {isMobile, isTabletOrMobile} = useWebMediaQueries()
-  const {_} = useLingui()
-
-  const requireAltTextEnabled = useRequireAltTextEnabled()
-  const setRequireAltTextEnabled = useSetRequireAltTextEnabled()
-  const autoplayDisabled = useAutoplayDisabled()
-  const setAutoplayDisabled = useSetAutoplayDisabled()
-  const hapticsDisabled = useHapticsDisabled()
-  const setHapticsDisabled = useSetHapticsDisabled()
-  const largeAltBadgeEnabled = useLargeAltBadgeEnabled()
-  const setLargeAltBadgeEnabled = useSetLargeAltBadgeEnabled()
-
-  useFocusEffect(
-    React.useCallback(() => {
-      setMinimalShellMode(false)
-    }, [setMinimalShellMode]),
-  )
-
-  return (
-    <Layout.Screen testID="accessibilitySettingsScreen">
-      <SimpleViewHeader
-        showBackButton={isTabletOrMobile}
-        style={[
-          pal.border,
-          a.border_b,
-          !isMobile && {
-            borderLeftWidth: StyleSheet.hairlineWidth,
-            borderRightWidth: StyleSheet.hairlineWidth,
-          },
-        ]}>
-        <View style={a.flex_1}>
-          <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}>
-            <Trans>Accessibility Settings</Trans>
-          </Text>
-        </View>
-      </SimpleViewHeader>
-      <ScrollView
-        // @ts-ignore web only -prf
-        dataSet={{'stable-gutters': 1}}
-        style={s.flex1}
-        contentContainerStyle={[
-          s.flex1,
-          {paddingBottom: 100},
-          isMobile && pal.viewLight,
-        ]}>
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Alt text</Trans>
-        </Text>
-        <View style={[pal.view, styles.toggleCard]}>
-          <ToggleButton
-            type="default-light"
-            label={_(msg`Require alt text before posting`)}
-            labelType="lg"
-            isSelected={requireAltTextEnabled}
-            onPress={() => setRequireAltTextEnabled(!requireAltTextEnabled)}
-          />
-          <ToggleButton
-            type="default-light"
-            label={_(msg`Display larger alt text badges`)}
-            labelType="lg"
-            isSelected={!!largeAltBadgeEnabled}
-            onPress={() => setLargeAltBadgeEnabled(!largeAltBadgeEnabled)}
-          />
-        </View>
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Media</Trans>
-        </Text>
-        <View style={[pal.view, styles.toggleCard]}>
-          <ToggleButton
-            type="default-light"
-            label={_(msg`Disable autoplay for videos and GIFs`)}
-            labelType="lg"
-            isSelected={autoplayDisabled}
-            onPress={() => setAutoplayDisabled(!autoplayDisabled)}
-          />
-        </View>
-        {isNative && (
-          <>
-            <Text type="xl-bold" style={[pal.text, styles.heading]}>
-              <Trans>Haptics</Trans>
-            </Text>
-            <View style={[pal.view, styles.toggleCard]}>
-              <ToggleButton
-                type="default-light"
-                label={_(msg`Disable haptic feedback`)}
-                labelType="lg"
-                isSelected={hapticsDisabled}
-                onPress={() => setHapticsDisabled(!hapticsDisabled)}
-              />
-            </View>
-          </>
-        )}
-      </ScrollView>
-    </Layout.Screen>
-  )
-}
-
-const styles = StyleSheet.create({
-  heading: {
-    paddingHorizontal: 18,
-    paddingTop: 14,
-    paddingBottom: 6,
-  },
-  toggleCard: {
-    paddingVertical: 8,
-    paddingHorizontal: 6,
-    marginBottom: 1,
-  },
-})
diff --git a/src/view/screens/AppPasswords.tsx b/src/view/screens/AppPasswords.tsx
deleted file mode 100644
index 09da3c1d2..000000000
--- a/src/view/screens/AppPasswords.tsx
+++ /dev/null
@@ -1,375 +0,0 @@
-import React from 'react'
-import {
-  ActivityIndicator,
-  StyleSheet,
-  TouchableOpacity,
-  View,
-} from 'react-native'
-import {ScrollView} from 'react-native-gesture-handler'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useFocusEffect} from '@react-navigation/native'
-import {NativeStackScreenProps} from '@react-navigation/native-stack'
-
-import {IS_INTERNAL} from '#/lib/app-info'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {CommonNavigatorParams} from '#/lib/routes/types'
-import {cleanError} from '#/lib/strings/errors'
-import {useModalControls} from '#/state/modals'
-import {
-  useAppPasswordDeleteMutation,
-  useAppPasswordsQuery,
-} from '#/state/queries/app-passwords'
-import {useSetMinimalShellMode} from '#/state/shell'
-import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
-import {Button} from '#/view/com/util/forms/Button'
-import {Text} from '#/view/com/util/text/Text'
-import * as Toast from '#/view/com/util/Toast'
-import {ViewHeader} from '#/view/com/util/ViewHeader'
-import {CenteredView} from '#/view/com/util/Views'
-import {AppPasswordsScreen as NewAppPasswordsScreen} from '#/screens/Settings/AppPasswords'
-import {atoms as a} from '#/alf'
-import {useDialogControl} from '#/components/Dialog'
-import * as Layout from '#/components/Layout'
-import * as Prompt from '#/components/Prompt'
-
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
-export function AppPasswords(props: Props) {
-  return IS_INTERNAL ? (
-    <NewAppPasswordsScreen {...props} />
-  ) : (
-    <Layout.Screen testID="AppPasswordsScreen">
-      <AppPasswordsInner />
-    </Layout.Screen>
-  )
-}
-
-function AppPasswordsInner() {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const setMinimalShellMode = useSetMinimalShellMode()
-  const {isTabletOrDesktop} = useWebMediaQueries()
-  const {openModal} = useModalControls()
-  const {data: appPasswords, error} = useAppPasswordsQuery()
-
-  useFocusEffect(
-    React.useCallback(() => {
-      setMinimalShellMode(false)
-    }, [setMinimalShellMode]),
-  )
-
-  const onAdd = React.useCallback(async () => {
-    openModal({name: 'add-app-password'})
-  }, [openModal])
-
-  if (error) {
-    return (
-      <CenteredView
-        style={[
-          styles.container,
-          isTabletOrDesktop && styles.containerDesktop,
-          pal.view,
-          pal.border,
-        ]}
-        testID="appPasswordsScreen">
-        <ErrorScreen
-          title={_(msg`Oops!`)}
-          message={_(msg`There was an issue with fetching your app passwords`)}
-          details={cleanError(error)}
-        />
-      </CenteredView>
-    )
-  }
-
-  // no app passwords (empty) state
-  if (appPasswords?.length === 0) {
-    return (
-      <CenteredView
-        style={[
-          styles.container,
-          isTabletOrDesktop && styles.containerDesktop,
-          pal.view,
-          pal.border,
-        ]}
-        testID="appPasswordsScreen">
-        <AppPasswordsHeader />
-        <View style={[styles.empty, pal.viewLight]}>
-          <Text type="lg" style={[pal.text, styles.emptyText]}>
-            <Trans>
-              You have not created any app passwords yet. You can create one by
-              pressing the button below.
-            </Trans>
-          </Text>
-        </View>
-        {!isTabletOrDesktop && <View style={styles.flex1} />}
-        <View
-          style={[
-            styles.btnContainer,
-            isTabletOrDesktop && styles.btnContainerDesktop,
-          ]}>
-          <Button
-            testID="appPasswordBtn"
-            type="primary"
-            label={_(msg`Add App Password`)}
-            style={styles.btn}
-            labelStyle={styles.btnLabel}
-            onPress={onAdd}
-          />
-        </View>
-      </CenteredView>
-    )
-  }
-
-  if (appPasswords?.length) {
-    // has app passwords
-    return (
-      <CenteredView
-        style={[
-          styles.container,
-          isTabletOrDesktop && styles.containerDesktop,
-          pal.view,
-          pal.border,
-        ]}
-        testID="appPasswordsScreen">
-        <AppPasswordsHeader />
-        <ScrollView
-          style={[
-            styles.scrollContainer,
-            pal.border,
-            !isTabletOrDesktop && styles.flex1,
-          ]}>
-          {appPasswords.map((password, i) => (
-            <AppPassword
-              key={password.name}
-              testID={`appPassword-${i}`}
-              name={password.name}
-              createdAt={password.createdAt}
-              privileged={password.privileged}
-            />
-          ))}
-          {isTabletOrDesktop && (
-            <View style={[styles.btnContainer, styles.btnContainerDesktop]}>
-              <Button
-                testID="appPasswordBtn"
-                type="primary"
-                label={_(msg`Add App Password`)}
-                style={styles.btn}
-                labelStyle={styles.btnLabel}
-                onPress={onAdd}
-              />
-            </View>
-          )}
-        </ScrollView>
-        {!isTabletOrDesktop && (
-          <View style={styles.btnContainer}>
-            <Button
-              testID="appPasswordBtn"
-              type="primary"
-              label={_(msg`Add App Password`)}
-              style={styles.btn}
-              labelStyle={styles.btnLabel}
-              onPress={onAdd}
-            />
-          </View>
-        )}
-      </CenteredView>
-    )
-  }
-
-  return (
-    <CenteredView
-      style={[
-        styles.container,
-        isTabletOrDesktop && styles.containerDesktop,
-        pal.view,
-        pal.border,
-      ]}
-      testID="appPasswordsScreen">
-      <ActivityIndicator />
-    </CenteredView>
-  )
-}
-
-function AppPasswordsHeader() {
-  const {isTabletOrDesktop} = useWebMediaQueries()
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  return (
-    <>
-      <ViewHeader title={_(msg`App Passwords`)} showOnDesktop />
-      <Text
-        type="sm"
-        style={[
-          styles.description,
-          pal.text,
-          isTabletOrDesktop && styles.descriptionDesktop,
-        ]}>
-        <Trans>
-          Use app passwords to login to other Bluesky clients without giving
-          full access to your account or password.
-        </Trans>
-      </Text>
-    </>
-  )
-}
-
-function AppPassword({
-  testID,
-  name,
-  createdAt,
-  privileged,
-}: {
-  testID: string
-  name: string
-  createdAt: string
-  privileged?: boolean
-}) {
-  const pal = usePalette('default')
-  const {_, i18n} = useLingui()
-  const control = useDialogControl()
-  const deleteMutation = useAppPasswordDeleteMutation()
-
-  const onDelete = React.useCallback(async () => {
-    await deleteMutation.mutateAsync({name})
-    Toast.show(_(msg`App password deleted`))
-  }, [deleteMutation, name, _])
-
-  const onPress = React.useCallback(() => {
-    control.open()
-  }, [control])
-
-  return (
-    <TouchableOpacity
-      testID={testID}
-      style={[styles.item, pal.border]}
-      onPress={onPress}
-      accessibilityRole="button"
-      accessibilityLabel={_(msg`Delete app password`)}
-      accessibilityHint="">
-      <View>
-        <Text type="md-bold" style={pal.text}>
-          {name}
-        </Text>
-        <Text type="md" style={[pal.text, styles.pr10]} numberOfLines={1}>
-          <Trans>
-            Created{' '}
-            {i18n.date(createdAt, {
-              year: 'numeric',
-              month: 'numeric',
-              day: 'numeric',
-              hour: '2-digit',
-              minute: '2-digit',
-              second: '2-digit',
-            })}
-          </Trans>
-        </Text>
-        {privileged && (
-          <View style={[a.flex_row, a.gap_sm, a.align_center, a.mt_xs]}>
-            <FontAwesomeIcon
-              icon="circle-exclamation"
-              color={pal.colors.textLight}
-              size={14}
-            />
-            <Text type="md" style={pal.textLight}>
-              <Trans>Allows access to direct messages</Trans>
-            </Text>
-          </View>
-        )}
-      </View>
-      <FontAwesomeIcon icon={['far', 'trash-can']} style={styles.trashIcon} />
-
-      <Prompt.Basic
-        control={control}
-        title={_(msg`Delete app password?`)}
-        description={_(
-          msg`Are you sure you want to delete the app password "${name}"?`,
-        )}
-        onConfirm={onDelete}
-        confirmButtonCta={_(msg`Delete`)}
-        confirmButtonColor="negative"
-      />
-    </TouchableOpacity>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-    paddingBottom: 100,
-  },
-  containerDesktop: {
-    borderLeftWidth: 1,
-    borderRightWidth: 1,
-    paddingBottom: 0,
-  },
-  title: {
-    textAlign: 'center',
-    marginTop: 12,
-    marginBottom: 12,
-  },
-  description: {
-    textAlign: 'center',
-    paddingHorizontal: 20,
-    marginBottom: 14,
-  },
-  descriptionDesktop: {
-    marginTop: 14,
-  },
-
-  scrollContainer: {
-    borderTopWidth: 1,
-    marginTop: 4,
-    marginBottom: 16,
-  },
-
-  flex1: {
-    flex: 1,
-  },
-  empty: {
-    paddingHorizontal: 20,
-    paddingVertical: 20,
-    borderRadius: 16,
-    marginHorizontal: 24,
-    marginTop: 10,
-  },
-  emptyText: {
-    textAlign: 'center',
-  },
-
-  item: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'space-between',
-    borderBottomWidth: 1,
-    paddingHorizontal: 20,
-    paddingVertical: 14,
-  },
-  pr10: {
-    marginRight: 10,
-  },
-  btnContainer: {
-    flexDirection: 'row',
-    justifyContent: 'center',
-  },
-  btnContainerDesktop: {
-    marginTop: 14,
-  },
-  btn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    borderRadius: 32,
-    paddingHorizontal: 60,
-    paddingVertical: 14,
-  },
-  btnLabel: {
-    fontSize: 18,
-  },
-
-  trashIcon: {
-    color: 'red',
-    minWidth: 16,
-  },
-})
diff --git a/src/view/screens/LanguageSettings.tsx b/src/view/screens/LanguageSettings.tsx
deleted file mode 100644
index f99cccee9..000000000
--- a/src/view/screens/LanguageSettings.tsx
+++ /dev/null
@@ -1,336 +0,0 @@
-import React from 'react'
-import {StyleSheet, View} from 'react-native'
-import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
-import {
-  FontAwesomeIcon,
-  FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useFocusEffect} from '@react-navigation/native'
-
-import {APP_LANGUAGES, LANGUAGES} from '#/lib/../locale/languages'
-import {IS_INTERNAL} from '#/lib/app-info'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
-import {s} from '#/lib/styles'
-import {sanitizeAppLanguageSetting} from '#/locale/helpers'
-import {useModalControls} from '#/state/modals'
-import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
-import {useSetMinimalShellMode} from '#/state/shell'
-import {Button} from '#/view/com/util/forms/Button'
-import {Text} from '#/view/com/util/text/Text'
-import {ViewHeader} from '#/view/com/util/ViewHeader'
-import {CenteredView} from '#/view/com/util/Views'
-import {LanguageSettingsScreen as NewLanguageSettingsScreen} from '#/screens/Settings/LanguageSettings'
-import * as Layout from '#/components/Layout'
-
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
-
-export function LanguageSettingsScreen(props: Props) {
-  return IS_INTERNAL ? (
-    <NewLanguageSettingsScreen {...props} />
-  ) : (
-    <LegacyLanguageSettingsScreen {...props} />
-  )
-}
-
-function LegacyLanguageSettingsScreen(_props: Props) {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const langPrefs = useLanguagePrefs()
-  const setLangPrefs = useLanguagePrefsApi()
-  const {isTabletOrDesktop} = useWebMediaQueries()
-  const setMinimalShellMode = useSetMinimalShellMode()
-  const {openModal} = useModalControls()
-
-  useFocusEffect(
-    React.useCallback(() => {
-      setMinimalShellMode(false)
-    }, [setMinimalShellMode]),
-  )
-
-  const onPressContentLanguages = React.useCallback(() => {
-    openModal({name: 'content-languages-settings'})
-  }, [openModal])
-
-  const onChangePrimaryLanguage = React.useCallback(
-    (value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
-      if (!value) return
-      if (langPrefs.primaryLanguage !== value) {
-        setLangPrefs.setPrimaryLanguage(value)
-      }
-    },
-    [langPrefs, setLangPrefs],
-  )
-
-  const onChangeAppLanguage = React.useCallback(
-    (value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
-      if (!value) return
-      if (langPrefs.appLanguage !== value) {
-        setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
-      }
-    },
-    [langPrefs, setLangPrefs],
-  )
-
-  const myLanguages = React.useMemo(() => {
-    return (
-      langPrefs.contentLanguages
-        .map(lang => LANGUAGES.find(l => l.code2 === lang))
-        .filter(Boolean)
-        // @ts-ignore
-        .map(l => l.name)
-        .join(', ')
-    )
-  }, [langPrefs.contentLanguages])
-
-  return (
-    <Layout.Screen testID="PreferencesLanguagesScreen">
-      <CenteredView
-        style={[
-          pal.view,
-          pal.border,
-          styles.container,
-          isTabletOrDesktop && styles.desktopContainer,
-        ]}>
-        <ViewHeader title={_(msg`Language Settings`)} showOnDesktop />
-
-        <View style={{paddingTop: 20, paddingHorizontal: 20}}>
-          {/* APP LANGUAGE */}
-          <View style={{paddingBottom: 20}}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <Trans>App Language</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Select your app language for the default text to display in the
-                app.
-              </Trans>
-            </Text>
-
-            <View style={{position: 'relative'}}>
-              <RNPickerSelect
-                placeholder={{}}
-                value={sanitizeAppLanguageSetting(langPrefs.appLanguage)}
-                onValueChange={onChangeAppLanguage}
-                items={APP_LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
-                  label: l.name,
-                  value: l.code2,
-                  key: l.code2,
-                }))}
-                style={{
-                  inputAndroid: {
-                    backgroundColor: pal.viewLight.backgroundColor,
-                    color: pal.text.color,
-                    fontSize: 14,
-                    letterSpacing: 0.5,
-                    fontWeight: '600',
-                    paddingHorizontal: 14,
-                    paddingVertical: 8,
-                    borderRadius: 24,
-                  },
-                  inputIOS: {
-                    backgroundColor: pal.viewLight.backgroundColor,
-                    color: pal.text.color,
-                    fontSize: 14,
-                    letterSpacing: 0.5,
-                    fontWeight: '600',
-                    paddingHorizontal: 14,
-                    paddingVertical: 8,
-                    borderRadius: 24,
-                  },
-
-                  inputWeb: {
-                    cursor: 'pointer',
-                    // @ts-ignore web only
-                    '-moz-appearance': 'none',
-                    '-webkit-appearance': 'none',
-                    appearance: 'none',
-                    outline: 0,
-                    borderWidth: 0,
-                    backgroundColor: pal.viewLight.backgroundColor,
-                    color: pal.text.color,
-                    fontSize: 14,
-                    fontFamily: 'inherit',
-                    letterSpacing: 0.5,
-                    fontWeight: '600',
-                    paddingHorizontal: 14,
-                    paddingVertical: 8,
-                    borderRadius: 24,
-                  },
-                }}
-              />
-
-              <View
-                style={{
-                  position: 'absolute',
-                  top: 1,
-                  right: 1,
-                  bottom: 1,
-                  width: 40,
-                  backgroundColor: pal.viewLight.backgroundColor,
-                  borderRadius: 24,
-                  pointerEvents: 'none',
-                  alignItems: 'center',
-                  justifyContent: 'center',
-                }}>
-                <FontAwesomeIcon
-                  icon="chevron-down"
-                  style={pal.text as FontAwesomeIconStyle}
-                />
-              </View>
-            </View>
-          </View>
-
-          <View
-            style={{
-              height: 1,
-              backgroundColor: pal.border.borderColor,
-              marginBottom: 20,
-            }}
-          />
-
-          {/* PRIMARY LANGUAGE */}
-          <View style={{paddingBottom: 20}}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <Trans>Primary Language</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Select your preferred language for translations in your feed.
-              </Trans>
-            </Text>
-
-            <View style={{position: 'relative'}}>
-              <RNPickerSelect
-                placeholder={{}}
-                value={langPrefs.primaryLanguage}
-                onValueChange={onChangePrimaryLanguage}
-                items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
-                  label: l.name,
-                  value: l.code2,
-                  key: l.code2 + l.code3,
-                }))}
-                style={{
-                  inputAndroid: {
-                    backgroundColor: pal.viewLight.backgroundColor,
-                    color: pal.text.color,
-                    fontSize: 14,
-                    letterSpacing: 0.5,
-                    fontWeight: '600',
-                    paddingHorizontal: 14,
-                    paddingVertical: 8,
-                    borderRadius: 24,
-                  },
-                  inputIOS: {
-                    backgroundColor: pal.viewLight.backgroundColor,
-                    color: pal.text.color,
-                    fontSize: 14,
-                    letterSpacing: 0.5,
-                    fontWeight: '600',
-                    paddingHorizontal: 14,
-                    paddingVertical: 8,
-                    borderRadius: 24,
-                  },
-                  inputWeb: {
-                    cursor: 'pointer',
-                    // @ts-ignore web only
-                    '-moz-appearance': 'none',
-                    '-webkit-appearance': 'none',
-                    appearance: 'none',
-                    outline: 0,
-                    borderWidth: 0,
-                    backgroundColor: pal.viewLight.backgroundColor,
-                    color: pal.text.color,
-                    fontSize: 14,
-                    fontFamily: 'inherit',
-                    letterSpacing: 0.5,
-                    fontWeight: '600',
-                    paddingHorizontal: 14,
-                    paddingVertical: 8,
-                    borderRadius: 24,
-                  },
-                }}
-              />
-
-              <View
-                style={{
-                  position: 'absolute',
-                  top: 1,
-                  right: 1,
-                  bottom: 1,
-                  width: 40,
-                  backgroundColor: pal.viewLight.backgroundColor,
-                  borderRadius: 24,
-                  pointerEvents: 'none',
-                  alignItems: 'center',
-                  justifyContent: 'center',
-                }}>
-                <FontAwesomeIcon
-                  icon="chevron-down"
-                  style={pal.text as FontAwesomeIconStyle}
-                />
-              </View>
-            </View>
-          </View>
-
-          <View
-            style={{
-              height: 1,
-              backgroundColor: pal.border.borderColor,
-              marginBottom: 20,
-            }}
-          />
-
-          {/* CONTENT LANGUAGES */}
-          <View style={{paddingBottom: 20}}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <Trans>Content Languages</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Select which languages you want your subscribed feeds to
-                include. If none are selected, all languages will be shown.
-              </Trans>
-            </Text>
-
-            <Button
-              type="default"
-              onPress={onPressContentLanguages}
-              style={styles.button}>
-              <FontAwesomeIcon
-                icon={myLanguages.length ? 'check' : 'plus'}
-                style={pal.text as FontAwesomeIconStyle}
-              />
-              <Text
-                type="button"
-                style={[pal.text, {flexShrink: 1, overflow: 'hidden'}]}
-                numberOfLines={1}>
-                {myLanguages.length ? myLanguages : _(msg`Select languages`)}
-              </Text>
-            </Button>
-          </View>
-        </View>
-      </CenteredView>
-    </Layout.Screen>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-    paddingBottom: 90,
-  },
-  desktopContainer: {
-    borderLeftWidth: 1,
-    borderRightWidth: 1,
-    paddingBottom: 40,
-  },
-  button: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    gap: 8,
-  },
-})
diff --git a/src/view/screens/PreferencesExternalEmbeds.tsx b/src/view/screens/PreferencesExternalEmbeds.tsx
deleted file mode 100644
index ef3f73b3c..000000000
--- a/src/view/screens/PreferencesExternalEmbeds.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import React from 'react'
-import {StyleSheet, View} from 'react-native'
-import {Trans} from '@lingui/macro'
-import {useFocusEffect} from '@react-navigation/native'
-
-import {IS_INTERNAL} from '#/lib/app-info'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
-import {
-  EmbedPlayerSource,
-  externalEmbedLabels,
-} from '#/lib/strings/embed-player'
-import {
-  useExternalEmbedsPrefs,
-  useSetExternalEmbedPref,
-} from '#/state/preferences'
-import {useSetMinimalShellMode} from '#/state/shell'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
-import {Text} from '#/view/com/util/text/Text'
-import {ScrollView} from '#/view/com/util/Views'
-import {ExternalMediaPreferencesScreen} from '#/screens/Settings/ExternalMediaPreferences'
-import {atoms as a} from '#/alf'
-import * as Layout from '#/components/Layout'
-
-type Props = NativeStackScreenProps<
-  CommonNavigatorParams,
-  'PreferencesExternalEmbeds'
->
-export function PreferencesExternalEmbeds(props: Props) {
-  return IS_INTERNAL ? (
-    <ExternalMediaPreferencesScreen {...props} />
-  ) : (
-    <LegacyPreferencesExternalEmbeds {...props} />
-  )
-}
-
-function LegacyPreferencesExternalEmbeds({}: Props) {
-  const pal = usePalette('default')
-  const setMinimalShellMode = useSetMinimalShellMode()
-  const {isTabletOrMobile} = useWebMediaQueries()
-
-  useFocusEffect(
-    React.useCallback(() => {
-      setMinimalShellMode(false)
-    }, [setMinimalShellMode]),
-  )
-
-  return (
-    <Layout.Screen testID="preferencesExternalEmbedsScreen">
-      <ScrollView
-        // @ts-ignore web only -prf
-        dataSet={{'stable-gutters': 1}}
-        contentContainerStyle={[pal.viewLight, {paddingBottom: 75}]}>
-        <SimpleViewHeader
-          showBackButton={isTabletOrMobile}
-          style={[pal.border, a.border_b]}>
-          <View style={a.flex_1}>
-            <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}>
-              <Trans>External Media Preferences</Trans>
-            </Text>
-            <Text style={pal.textLight}>
-              <Trans>Customize media from external sites.</Trans>
-            </Text>
-          </View>
-        </SimpleViewHeader>
-
-        <View style={[pal.view]}>
-          <View style={styles.infoCard}>
-            <Text style={pal.text}>
-              <Trans>
-                External media may allow websites to collect information about
-                you and your device. No information is sent or requested until
-                you press the "play" button.
-              </Trans>
-            </Text>
-          </View>
-        </View>
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Enable media players for</Trans>
-        </Text>
-        {Object.entries(externalEmbedLabels)
-          // TODO: Remove special case when we disable the old integration.
-          .filter(([key]) => key !== 'tenor')
-          .map(([key, label]) => (
-            <PrefSelector
-              source={key as EmbedPlayerSource}
-              label={label}
-              key={key}
-            />
-          ))}
-      </ScrollView>
-    </Layout.Screen>
-  )
-}
-
-function PrefSelector({
-  source,
-  label,
-}: {
-  source: EmbedPlayerSource
-  label: string
-}) {
-  const pal = usePalette('default')
-  const setExternalEmbedPref = useSetExternalEmbedPref()
-  const sources = useExternalEmbedsPrefs()
-
-  return (
-    <View>
-      <View style={[pal.view, styles.toggleCard]}>
-        <ToggleButton
-          type="default-light"
-          label={label}
-          labelType="lg"
-          isSelected={sources?.[source] === 'show'}
-          onPress={() =>
-            setExternalEmbedPref(
-              source,
-              sources?.[source] === 'show' ? 'hide' : 'show',
-            )
-          }
-        />
-      </View>
-    </View>
-  )
-}
-
-const styles = StyleSheet.create({
-  heading: {
-    paddingHorizontal: 18,
-    paddingTop: 14,
-    paddingBottom: 14,
-  },
-  spacer: {
-    height: 8,
-  },
-  infoCard: {
-    paddingHorizontal: 20,
-    paddingVertical: 14,
-  },
-  toggleCard: {
-    paddingVertical: 8,
-    paddingHorizontal: 6,
-    marginBottom: 1,
-  },
-})
diff --git a/src/view/screens/PreferencesFollowingFeed.tsx b/src/view/screens/PreferencesFollowingFeed.tsx
deleted file mode 100644
index c31a23c49..000000000
--- a/src/view/screens/PreferencesFollowingFeed.tsx
+++ /dev/null
@@ -1,249 +0,0 @@
-import React from 'react'
-import {StyleSheet, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {IS_INTERNAL} from '#/lib/app-info'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
-import {colors, s} from '#/lib/styles'
-import {
-  usePreferencesQuery,
-  useSetFeedViewPreferencesMutation,
-} from '#/state/queries/preferences'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
-import {Text} from '#/view/com/util/text/Text'
-import {ScrollView} from '#/view/com/util/Views'
-import {FollowingFeedPreferencesScreen} from '#/screens/Settings/FollowingFeedPreferences'
-import {atoms as a} from '#/alf'
-import * as Layout from '#/components/Layout'
-
-type Props = NativeStackScreenProps<
-  CommonNavigatorParams,
-  'PreferencesFollowingFeed'
->
-export function PreferencesFollowingFeed(props: Props) {
-  return IS_INTERNAL ? (
-    <FollowingFeedPreferencesScreen {...props} />
-  ) : (
-    <LegacyPreferencesFollowingFeed {...props} />
-  )
-}
-
-function LegacyPreferencesFollowingFeed({}: Props) {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const {isTabletOrMobile} = useWebMediaQueries()
-  const {data: preferences} = usePreferencesQuery()
-  const {mutate: setFeedViewPref, variables} =
-    useSetFeedViewPreferencesMutation()
-
-  const showReplies = !(
-    variables?.hideReplies ?? preferences?.feedViewPrefs?.hideReplies
-  )
-
-  return (
-    <Layout.Screen testID="preferencesHomeFeedScreen">
-      <ScrollView
-        // @ts-ignore web only -sfn
-        dataSet={{'stable-gutters': 1}}
-        contentContainerStyle={{paddingBottom: 75}}>
-        <SimpleViewHeader
-          showBackButton={isTabletOrMobile}
-          style={[pal.border, a.border_b]}>
-          <View style={a.flex_1}>
-            <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}>
-              <Trans>Following Feed Preferences</Trans>
-            </Text>
-            <Text style={pal.textLight}>
-              <Trans>
-                Fine-tune the content you see on your Following feed.
-              </Trans>
-            </Text>
-          </View>
-        </SimpleViewHeader>
-        <View style={styles.cardsContainer}>
-          <View style={[pal.viewLight, styles.card]}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <Trans>Show Replies</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Set this setting to "No" to hide all replies from your feed.
-              </Trans>
-            </Text>
-            <ToggleButton
-              testID="toggleRepliesBtn"
-              type="default-light"
-              label={showReplies ? _(msg`Yes`) : _(msg`No`)}
-              isSelected={showReplies}
-              onPress={() =>
-                setFeedViewPref({
-                  hideReplies: !(
-                    variables?.hideReplies ??
-                    preferences?.feedViewPrefs?.hideReplies
-                  ),
-                })
-              }
-            />
-          </View>
-          <View style={[pal.viewLight, styles.card]}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <Trans>Show Reposts</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Set this setting to "No" to hide all reposts from your feed.
-              </Trans>
-            </Text>
-            <ToggleButton
-              type="default-light"
-              label={
-                variables?.hideReposts ??
-                preferences?.feedViewPrefs?.hideReposts
-                  ? _(msg`No`)
-                  : _(msg`Yes`)
-              }
-              isSelected={
-                !(
-                  variables?.hideReposts ??
-                  preferences?.feedViewPrefs?.hideReposts
-                )
-              }
-              onPress={() =>
-                setFeedViewPref({
-                  hideReposts: !(
-                    variables?.hideReposts ??
-                    preferences?.feedViewPrefs?.hideReposts
-                  ),
-                })
-              }
-            />
-          </View>
-
-          <View style={[pal.viewLight, styles.card]}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <Trans>Show Quote Posts</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Set this setting to "No" to hide all quote posts from your feed.
-                Reposts will still be visible.
-              </Trans>
-            </Text>
-            <ToggleButton
-              type="default-light"
-              label={
-                variables?.hideQuotePosts ??
-                preferences?.feedViewPrefs?.hideQuotePosts
-                  ? _(msg`No`)
-                  : _(msg`Yes`)
-              }
-              isSelected={
-                !(
-                  variables?.hideQuotePosts ??
-                  preferences?.feedViewPrefs?.hideQuotePosts
-                )
-              }
-              onPress={() =>
-                setFeedViewPref({
-                  hideQuotePosts: !(
-                    variables?.hideQuotePosts ??
-                    preferences?.feedViewPrefs?.hideQuotePosts
-                  ),
-                })
-              }
-            />
-          </View>
-
-          <View style={[pal.viewLight, styles.card]}>
-            <Text type="title-sm" style={[pal.text, s.pb5]}>
-              <FontAwesomeIcon icon="flask" color={pal.colors.text} />{' '}
-              <Trans>Show Posts from My Feeds</Trans>
-            </Text>
-            <Text style={[pal.text, s.pb10]}>
-              <Trans>
-                Set this setting to "Yes" to show samples of your saved feeds in
-                your Following feed. This is an experimental feature.
-              </Trans>
-            </Text>
-            <ToggleButton
-              type="default-light"
-              label={
-                variables?.lab_mergeFeedEnabled ??
-                preferences?.feedViewPrefs?.lab_mergeFeedEnabled
-                  ? _(msg`Yes`)
-                  : _(msg`No`)
-              }
-              isSelected={
-                !!(
-                  variables?.lab_mergeFeedEnabled ??
-                  preferences?.feedViewPrefs?.lab_mergeFeedEnabled
-                )
-              }
-              onPress={() =>
-                setFeedViewPref({
-                  lab_mergeFeedEnabled: !(
-                    variables?.lab_mergeFeedEnabled ??
-                    preferences?.feedViewPrefs?.lab_mergeFeedEnabled
-                  ),
-                })
-              }
-            />
-          </View>
-        </View>
-      </ScrollView>
-    </Layout.Screen>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-  },
-  desktopContainer: {
-    borderLeftWidth: 1,
-    borderRightWidth: 1,
-  },
-  titleSection: {
-    paddingBottom: 30,
-  },
-  title: {
-    textAlign: 'center',
-    marginBottom: 5,
-  },
-  description: {
-    textAlign: 'center',
-    paddingHorizontal: 32,
-  },
-  cardsContainer: {
-    paddingHorizontal: 20,
-    paddingVertical: 16,
-  },
-  card: {
-    padding: 16,
-    borderRadius: 10,
-    marginBottom: 20,
-  },
-  btn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    borderRadius: 32,
-    padding: 14,
-    backgroundColor: colors.blue3,
-  },
-  btnDesktop: {
-    marginHorizontal: 'auto',
-    paddingHorizontal: 80,
-  },
-  btnContainer: {
-    paddingTop: 20,
-  },
-  dimmed: {
-    opacity: 0.3,
-  },
-})
diff --git a/src/view/screens/PreferencesThreads.tsx b/src/view/screens/PreferencesThreads.tsx
deleted file mode 100644
index f511f4c59..000000000
--- a/src/view/screens/PreferencesThreads.tsx
+++ /dev/null
@@ -1,198 +0,0 @@
-import React from 'react'
-import {ActivityIndicator, StyleSheet, View} from 'react-native'
-import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {IS_INTERNAL} from '#/lib/app-info'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
-import {colors, s} from '#/lib/styles'
-import {
-  usePreferencesQuery,
-  useSetThreadViewPreferencesMutation,
-} from '#/state/queries/preferences'
-import {RadioGroup} from '#/view/com/util/forms/RadioGroup'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
-import {Text} from '#/view/com/util/text/Text'
-import {ScrollView} from '#/view/com/util/Views'
-import {ThreadPreferencesScreen} from '#/screens/Settings/ThreadPreferences'
-import {atoms as a} from '#/alf'
-import * as Layout from '#/components/Layout'
-
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'PreferencesThreads'>
-export function PreferencesThreads(props: Props) {
-  return IS_INTERNAL ? (
-    <ThreadPreferencesScreen {...props} />
-  ) : (
-    <LegacyPreferencesThreads {...props} />
-  )
-}
-
-function LegacyPreferencesThreads({}: Props) {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const {isTabletOrMobile} = useWebMediaQueries()
-  const {data: preferences} = usePreferencesQuery()
-  const {mutate: setThreadViewPrefs, variables} =
-    useSetThreadViewPreferencesMutation()
-
-  const prioritizeFollowedUsers = Boolean(
-    variables?.prioritizeFollowedUsers ??
-      preferences?.threadViewPrefs?.prioritizeFollowedUsers,
-  )
-  const treeViewEnabled = Boolean(
-    variables?.lab_treeViewEnabled ??
-      preferences?.threadViewPrefs?.lab_treeViewEnabled,
-  )
-
-  return (
-    <Layout.Screen testID="preferencesThreadsScreen">
-      <ScrollView
-        // @ts-ignore web only -prf
-        dataSet={{'stable-gutters': 1}}
-        contentContainerStyle={{paddingBottom: 75}}>
-        <SimpleViewHeader
-          showBackButton={isTabletOrMobile}
-          style={[pal.border, a.border_b]}>
-          <View style={a.flex_1}>
-            <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}>
-              <Trans>Thread Preferences</Trans>
-            </Text>
-            <Text style={pal.textLight}>
-              <Trans>Fine-tune the discussion threads.</Trans>
-            </Text>
-          </View>
-        </SimpleViewHeader>
-
-        {preferences ? (
-          <View style={styles.cardsContainer}>
-            <View style={[pal.viewLight, styles.card]}>
-              <Text type="title-sm" style={[pal.text, s.pb5]}>
-                <Trans>Sort Replies</Trans>
-              </Text>
-              <Text style={[pal.text, s.pb10]}>
-                <Trans>Sort replies to the same post by:</Trans>
-              </Text>
-              <View style={[pal.view, {borderRadius: 8, paddingVertical: 6}]}>
-                <RadioGroup
-                  type="default-light"
-                  items={[
-                    {key: 'oldest', label: _(msg`Oldest replies first`)},
-                    {key: 'newest', label: _(msg`Newest replies first`)},
-                    {
-                      key: 'most-likes',
-                      label: _(msg`Most-liked replies first`),
-                    },
-                    {
-                      key: 'random',
-                      label: _(msg`Random (aka "Poster's Roulette")`),
-                    },
-                  ]}
-                  onSelect={key => setThreadViewPrefs({sort: key})}
-                  initialSelection={preferences?.threadViewPrefs?.sort}
-                />
-              </View>
-            </View>
-
-            <View style={[pal.viewLight, styles.card]}>
-              <Text type="title-sm" style={[pal.text, s.pb5]}>
-                <Trans>Prioritize Your Follows</Trans>
-              </Text>
-              <Text style={[pal.text, s.pb10]}>
-                <Trans>
-                  Show replies by people you follow before all other replies.
-                </Trans>
-              </Text>
-              <ToggleButton
-                type="default-light"
-                label={prioritizeFollowedUsers ? _(msg`Yes`) : _(msg`No`)}
-                isSelected={prioritizeFollowedUsers}
-                onPress={() =>
-                  setThreadViewPrefs({
-                    prioritizeFollowedUsers: !prioritizeFollowedUsers,
-                  })
-                }
-              />
-            </View>
-
-            <View style={[pal.viewLight, styles.card]}>
-              <Text type="title-sm" style={[pal.text, s.pb5]}>
-                <FontAwesomeIcon icon="flask" color={pal.colors.text} />{' '}
-                <Trans>Threaded Mode</Trans>
-              </Text>
-              <Text style={[pal.text, s.pb10]}>
-                <Trans>
-                  Set this setting to "Yes" to show replies in a threaded view.
-                  This is an experimental feature.
-                </Trans>
-              </Text>
-              <ToggleButton
-                type="default-light"
-                label={treeViewEnabled ? _(msg`Yes`) : _(msg`No`)}
-                isSelected={treeViewEnabled}
-                onPress={() =>
-                  setThreadViewPrefs({
-                    lab_treeViewEnabled: !treeViewEnabled,
-                  })
-                }
-              />
-            </View>
-          </View>
-        ) : (
-          <ActivityIndicator style={a.flex_1} />
-        )}
-      </ScrollView>
-    </Layout.Screen>
-  )
-}
-
-const styles = StyleSheet.create({
-  container: {
-    flex: 1,
-  },
-  desktopContainer: {
-    borderLeftWidth: 1,
-    borderRightWidth: 1,
-  },
-  titleSection: {
-    paddingBottom: 30,
-  },
-  title: {
-    textAlign: 'center',
-    marginBottom: 5,
-  },
-  description: {
-    textAlign: 'center',
-    paddingHorizontal: 32,
-  },
-  cardsContainer: {
-    paddingHorizontal: 20,
-    paddingVertical: 16,
-  },
-  card: {
-    padding: 16,
-    borderRadius: 10,
-    marginBottom: 20,
-  },
-  btn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    borderRadius: 32,
-    padding: 14,
-    backgroundColor: colors.blue3,
-  },
-  btnDesktop: {
-    marginHorizontal: 'auto',
-    paddingHorizontal: 80,
-  },
-  btnContainer: {
-    paddingTop: 20,
-  },
-  dimmed: {
-    opacity: 0.3,
-  },
-})
diff --git a/src/view/screens/Settings/Email2FAToggle.tsx b/src/view/screens/Settings/Email2FAToggle.tsx
deleted file mode 100644
index f6ed19a21..000000000
--- a/src/view/screens/Settings/Email2FAToggle.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react'
-import {msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-
-import {useModalControls} from '#/state/modals'
-import {useAgent, useSession} from '#/state/session'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {useDialogControl} from '#/components/Dialog'
-import {DisableEmail2FADialog} from './DisableEmail2FADialog'
-
-export function Email2FAToggle() {
-  const {_} = useLingui()
-  const {currentAccount} = useSession()
-  const {openModal} = useModalControls()
-  const disableDialogCtrl = useDialogControl()
-  const agent = useAgent()
-
-  const enableEmailAuthFactor = React.useCallback(async () => {
-    if (currentAccount?.email) {
-      await agent.com.atproto.server.updateEmail({
-        email: currentAccount.email,
-        emailAuthFactor: true,
-      })
-      await agent.resumeSession(agent.session!)
-    }
-  }, [currentAccount, agent])
-
-  const onToggle = React.useCallback(() => {
-    if (!currentAccount) {
-      return
-    }
-    if (currentAccount.emailAuthFactor) {
-      disableDialogCtrl.open()
-    } else {
-      if (!currentAccount.emailConfirmed) {
-        openModal({
-          name: 'verify-email',
-          onSuccess: enableEmailAuthFactor,
-        })
-        return
-      }
-      enableEmailAuthFactor()
-    }
-  }, [currentAccount, enableEmailAuthFactor, openModal, disableDialogCtrl])
-
-  return (
-    <>
-      <DisableEmail2FADialog control={disableDialogCtrl} />
-      <ToggleButton
-        type="default-light"
-        label={_(msg`Require email code to log into your account`)}
-        labelType="lg"
-        isSelected={!!currentAccount?.emailAuthFactor}
-        onPress={onToggle}
-      />
-    </>
-  )
-}
diff --git a/src/view/screens/Settings/index.tsx b/src/view/screens/Settings/index.tsx
deleted file mode 100644
index 7ec7b5dce..000000000
--- a/src/view/screens/Settings/index.tsx
+++ /dev/null
@@ -1,1077 +0,0 @@
-import React from 'react'
-import {
-  Platform,
-  Pressable,
-  StyleSheet,
-  TextStyle,
-  TouchableOpacity,
-  View,
-  ViewStyle,
-} from 'react-native'
-import {setStringAsync} from 'expo-clipboard'
-import {
-  FontAwesomeIcon,
-  FontAwesomeIconStyle,
-} from '@fortawesome/react-native-fontawesome'
-import {msg, Trans} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
-import {useFocusEffect, useNavigation} from '@react-navigation/native'
-import {useQueryClient} from '@tanstack/react-query'
-
-import {appVersion, BUNDLE_DATE, bundleInfo, IS_INTERNAL} from '#/lib/app-info'
-import {STATUS_PAGE_URL} from '#/lib/constants'
-import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
-import {useCustomPalette} from '#/lib/hooks/useCustomPalette'
-import {usePalette} from '#/lib/hooks/usePalette'
-import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
-import {HandIcon, HashtagIcon} from '#/lib/icons'
-import {makeProfileLink} from '#/lib/routes/links'
-import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
-import {NavigationProp} from '#/lib/routes/types'
-import {colors, s} from '#/lib/styles'
-import {isNative} from '#/platform/detection'
-import {useModalControls} from '#/state/modals'
-import {clearStorage} from '#/state/persisted'
-import {
-  useInAppBrowser,
-  useSetInAppBrowser,
-} from '#/state/preferences/in-app-browser'
-import {useDeleteActorDeclaration} from '#/state/queries/messages/actor-declaration'
-import {useClearPreferencesMutation} from '#/state/queries/preferences'
-import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile'
-import {useProfileQuery} from '#/state/queries/profile'
-import {SessionAccount, useSession, useSessionApi} from '#/state/session'
-import {useOnboardingDispatch, useSetMinimalShellMode} from '#/state/shell'
-import {useLoggedOutViewControls} from '#/state/shell/logged-out'
-import {useCloseAllActiveElements} from '#/state/util'
-import {AccountDropdownBtn} from '#/view/com/util/AccountDropdownBtn'
-import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
-import {Link, TextLink} from '#/view/com/util/Link'
-import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
-import {Text} from '#/view/com/util/text/Text'
-import * as Toast from '#/view/com/util/Toast'
-import {UserAvatar} from '#/view/com/util/UserAvatar'
-import {ScrollView} from '#/view/com/util/Views'
-import {DeactivateAccountDialog} from '#/screens/Settings/components/DeactivateAccountDialog'
-import {SettingsScreen as NewSettingsScreen} from '#/screens/Settings/Settings'
-import {atoms as a, useTheme} from '#/alf'
-import {useDialogControl} from '#/components/Dialog'
-import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
-import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
-import * as Layout from '#/components/Layout'
-import {Email2FAToggle} from './Email2FAToggle'
-import {ExportCarDialog} from './ExportCarDialog'
-
-function SettingsAccountCard({
-  account,
-  pendingDid,
-  onPressSwitchAccount,
-}: {
-  account: SessionAccount
-  pendingDid: string | null
-  onPressSwitchAccount: (
-    account: SessionAccount,
-    logContext: 'Settings',
-  ) => void
-}) {
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const t = useTheme()
-  const {currentAccount} = useSession()
-  const {data: profile} = useProfileQuery({did: account.did})
-  const isCurrentAccount = account.did === currentAccount?.did
-
-  const contents = (
-    <View
-      style={[
-        pal.view,
-        styles.linkCard,
-        account.did === pendingDid && t.atoms.bg_contrast_25,
-      ]}>
-      <View style={styles.avi}>
-        <UserAvatar
-          size={40}
-          avatar={profile?.avatar}
-          type={profile?.associated?.labeler ? 'labeler' : 'user'}
-        />
-      </View>
-      <View style={[s.flex1]}>
-        <Text
-          emoji
-          type="md-bold"
-          style={[pal.text, a.self_start]}
-          numberOfLines={1}>
-          {profile?.displayName || account.handle}
-        </Text>
-        <Text emoji type="sm" style={pal.textLight} numberOfLines={1}>
-          {account.handle}
-        </Text>
-      </View>
-      <AccountDropdownBtn account={account} />
-    </View>
-  )
-
-  return isCurrentAccount ? (
-    <Link
-      href={makeProfileLink({
-        did: currentAccount?.did,
-        handle: currentAccount?.handle,
-      })}
-      title={_(msg`Your profile`)}
-      noFeedback>
-      {contents}
-    </Link>
-  ) : (
-    <TouchableOpacity
-      testID={`switchToAccountBtn-${account.handle}`}
-      key={account.did}
-      onPress={
-        pendingDid ? undefined : () => onPressSwitchAccount(account, 'Settings')
-      }
-      accessibilityRole="button"
-      accessibilityLabel={_(msg`Switch to ${account.handle}`)}
-      accessibilityHint={_(msg`Switches the account you are logged in to`)}
-      activeOpacity={0.8}>
-      {contents}
-    </TouchableOpacity>
-  )
-}
-
-type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
-export function SettingsScreen(props: Props) {
-  return IS_INTERNAL ? (
-    <NewSettingsScreen {...props} />
-  ) : (
-    <LegacySettingsScreen {...props} />
-  )
-}
-
-function LegacySettingsScreen({}: Props) {
-  const queryClient = useQueryClient()
-  const pal = usePalette('default')
-  const {_} = useLingui()
-  const setMinimalShellMode = useSetMinimalShellMode()
-  const inAppBrowserPref = useInAppBrowser()
-  const setUseInAppBrowser = useSetInAppBrowser()
-  const onboardingDispatch = useOnboardingDispatch()
-  const navigation = useNavigation<NavigationProp>()
-  const {isMobile} = useWebMediaQueries()
-  const {openModal} = useModalControls()
-  const {accounts, currentAccount} = useSession()
-  const {mutate: clearPreferences} = useClearPreferencesMutation()
-  const {setShowLoggedOut} = useLoggedOutViewControls()
-  const {logoutEveryAccount} = useSessionApi()
-  const closeAllActiveElements = useCloseAllActiveElements()
-  const exportCarControl = useDialogControl()
-  const birthdayControl = useDialogControl()
-  const {pendingDid, onPressSwitchAccount} = useAccountSwitcher()
-  const isSwitchingAccounts = !!pendingDid
-
-  // const primaryBg = useCustomPalette<ViewStyle>({
-  //   light: {backgroundColor: colors.blue0},
-  //   dark: {backgroundColor: colors.blue6},
-  // })
-  // const primaryText = useCustomPalette<TextStyle>({
-  //   light: {color: colors.blue3},
-  //   dark: {color: colors.blue2},
-  // })
-
-  const dangerBg = useCustomPalette<ViewStyle>({
-    light: {backgroundColor: colors.red1},
-    dark: {backgroundColor: colors.red7},
-  })
-  const dangerText = useCustomPalette<TextStyle>({
-    light: {color: colors.red4},
-    dark: {color: colors.red2},
-  })
-
-  useFocusEffect(
-    React.useCallback(() => {
-      setMinimalShellMode(false)
-    }, [setMinimalShellMode]),
-  )
-
-  const onPressAddAccount = React.useCallback(() => {
-    setShowLoggedOut(true)
-    closeAllActiveElements()
-  }, [setShowLoggedOut, closeAllActiveElements])
-
-  const onPressChangeHandle = React.useCallback(() => {
-    openModal({
-      name: 'change-handle',
-      onChanged() {
-        if (currentAccount) {
-          // refresh my profile
-          queryClient.invalidateQueries({
-            queryKey: RQKEY_PROFILE(currentAccount.did),
-          })
-        }
-      },
-    })
-  }, [queryClient, openModal, currentAccount])
-
-  const onPressExportRepository = React.useCallback(() => {
-    exportCarControl.open()
-  }, [exportCarControl])
-
-  const onPressLanguageSettings = React.useCallback(() => {
-    navigation.navigate('LanguageSettings')
-  }, [navigation])
-
-  const onPressDeleteAccount = React.useCallback(() => {
-    openModal({name: 'delete-account'})
-  }, [openModal])
-
-  const onPressLogoutEveryAccount = React.useCallback(() => {
-    logoutEveryAccount('Settings')
-  }, [logoutEveryAccount])
-
-  const onPressResetPreferences = React.useCallback(async () => {
-    clearPreferences()
-  }, [clearPreferences])
-
-  const onPressResetOnboarding = React.useCallback(async () => {
-    navigation.navigate('Home')
-    onboardingDispatch({type: 'start'})
-    Toast.show(_(msg`Onboarding reset`))
-  }, [navigation, onboardingDispatch, _])
-
-  const onPressBuildInfo = React.useCallback(() => {
-    setStringAsync(
-      `Build version: ${appVersion}; Bundle info: ${bundleInfo}; Bundle date: ${BUNDLE_DATE}; Platform: ${Platform.OS}`,
-    )
-    Toast.show(_(msg`Copied build version to clipboard`))
-  }, [_])
-
-  const openFollowingFeedPreferences = React.useCallback(() => {
-    navigation.navigate('PreferencesFollowingFeed')
-  }, [navigation])
-
-  const openThreadsPreferences = React.useCallback(() => {
-    navigation.navigate('PreferencesThreads')
-  }, [navigation])
-
-  const onPressAppPasswords = React.useCallback(() => {
-    navigation.navigate('AppPasswords')
-  }, [navigation])
-
-  const onPressSystemLog = React.useCallback(() => {
-    navigation.navigate('Log')
-  }, [navigation])
-
-  const onPressStorybook = React.useCallback(() => {
-    navigation.navigate('Debug')
-  }, [navigation])
-
-  const onPressDebugModeration = React.useCallback(() => {
-    navigation.navigate('DebugMod')
-  }, [navigation])
-
-  const onPressSavedFeeds = React.useCallback(() => {
-    navigation.navigate('SavedFeeds')
-  }, [navigation])
-
-  const onPressAccessibilitySettings = React.useCallback(() => {
-    navigation.navigate('AccessibilitySettings')
-  }, [navigation])
-
-  const onPressAppearanceSettings = React.useCallback(() => {
-    navigation.navigate('AppearanceSettings')
-  }, [navigation])
-
-  const onPressBirthday = React.useCallback(() => {
-    birthdayControl.open()
-  }, [birthdayControl])
-
-  const clearAllStorage = React.useCallback(async () => {
-    await clearStorage()
-    Toast.show(_(msg`Storage cleared, you need to restart the app now.`))
-  }, [_])
-
-  const deactivateAccountControl = useDialogControl()
-  const onPressDeactivateAccount = React.useCallback(() => {
-    deactivateAccountControl.open()
-  }, [deactivateAccountControl])
-
-  const {mutate: onPressDeleteChatDeclaration} = useDeleteActorDeclaration()
-
-  return (
-    <Layout.Screen testID="settingsScreen">
-      <ExportCarDialog control={exportCarControl} />
-      <BirthDateSettingsDialog control={birthdayControl} />
-
-      <SimpleViewHeader
-        showBackButton={isMobile}
-        style={[
-          pal.border,
-          {borderBottomWidth: StyleSheet.hairlineWidth},
-          !isMobile && {borderLeftWidth: 1, borderRightWidth: 1},
-        ]}>
-        <View style={{flex: 1}}>
-          <Text type="title-lg" style={[pal.text, {fontWeight: '600'}]}>
-            <Trans>Settings</Trans>
-          </Text>
-        </View>
-      </SimpleViewHeader>
-      <ScrollView
-        style={[isMobile && pal.viewLight]}
-        scrollIndicatorInsets={{right: 1}}
-        // @ts-ignore web only -prf
-        dataSet={{'stable-gutters': 1}}>
-        <View style={styles.spacer20} />
-        {currentAccount ? (
-          <>
-            <Text type="xl-bold" style={[pal.text, styles.heading]}>
-              <Trans>Account</Trans>
-            </Text>
-            <View style={[styles.infoLine]}>
-              <Text type="lg-medium" style={pal.text}>
-                <Trans>Email:</Trans>{' '}
-              </Text>
-              {currentAccount.emailConfirmed && (
-                <>
-                  <FontAwesomeIcon
-                    icon="check"
-                    size={10}
-                    style={{color: colors.green3, marginRight: 2}}
-                  />
-                </>
-              )}
-              <Text
-                type="lg"
-                numberOfLines={1}
-                style={[
-                  pal.text,
-                  {overflow: 'hidden', marginRight: 4, flex: 1},
-                ]}>
-                {currentAccount.email || '(no email)'}
-              </Text>
-              <Link onPress={() => openModal({name: 'change-email'})}>
-                <Text type="lg" style={pal.link}>
-                  <Trans context="action">Change</Trans>
-                </Text>
-              </Link>
-            </View>
-            <View style={[styles.infoLine]}>
-              <Text type="lg-medium" style={pal.text}>
-                <Trans>Birthday:</Trans>{' '}
-              </Text>
-              <Link onPress={onPressBirthday}>
-                <Text type="lg" style={pal.link}>
-                  <Trans>Show</Trans>
-                </Text>
-              </Link>
-            </View>
-            <View style={styles.spacer20} />
-
-            {!currentAccount.emailConfirmed && <EmailConfirmationNotice />}
-
-            <View style={[s.flexRow, styles.heading]}>
-              <Text type="xl-bold" style={pal.text} numberOfLines={1}>
-                <Trans>Signed in as</Trans>
-              </Text>
-              <View style={s.flex1} />
-            </View>
-            <View pointerEvents={pendingDid ? 'none' : 'auto'}>
-              <SettingsAccountCard
-                account={currentAccount}
-                onPressSwitchAccount={onPressSwitchAccount}
-                pendingDid={pendingDid}
-              />
-            </View>
-          </>
-        ) : null}
-
-        <View pointerEvents={pendingDid ? 'none' : 'auto'}>
-          {accounts.length > 1 && (
-            <View style={[s.flexRow, styles.heading, a.mt_sm]}>
-              <Text type="xl-bold" style={pal.text} numberOfLines={1}>
-                <Trans>Other accounts</Trans>
-              </Text>
-              <View style={s.flex1} />
-            </View>
-          )}
-
-          {accounts
-            .filter(a => a.did !== currentAccount?.did)
-            .map(account => (
-              <SettingsAccountCard
-                key={account.did}
-                account={account}
-                onPressSwitchAccount={onPressSwitchAccount}
-                pendingDid={pendingDid}
-              />
-            ))}
-
-          <TouchableOpacity
-            testID="switchToNewAccountBtn"
-            style={[styles.linkCard, pal.view]}
-            onPress={isSwitchingAccounts ? undefined : onPressAddAccount}
-            accessibilityRole="button"
-            accessibilityLabel={_(msg`Add account`)}
-            accessibilityHint={_(msg`Create a new Bluesky account`)}>
-            <View style={[styles.iconContainer, pal.btn]}>
-              <FontAwesomeIcon
-                icon="plus"
-                style={pal.text as FontAwesomeIconStyle}
-              />
-            </View>
-            <Text type="lg" style={pal.text}>
-              <Trans>Add account</Trans>
-            </Text>
-          </TouchableOpacity>
-
-          <TouchableOpacity
-            style={[styles.linkCard, pal.view]}
-            onPress={
-              isSwitchingAccounts ? undefined : onPressLogoutEveryAccount
-            }
-            accessibilityRole="button"
-            accessibilityLabel={_(msg`Sign out of all accounts`)}
-            accessibilityHint={undefined}>
-            <View style={[styles.iconContainer, pal.btn]}>
-              <FontAwesomeIcon
-                icon="arrow-right-from-bracket"
-                style={pal.text as FontAwesomeIconStyle}
-              />
-            </View>
-            <Text type="lg" style={pal.text}>
-              {accounts.length > 1 ? (
-                <Trans>Sign out of all accounts</Trans>
-              ) : (
-                <Trans>Sign out</Trans>
-              )}
-            </Text>
-          </TouchableOpacity>
-        </View>
-
-        <View style={styles.spacer20} />
-
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Basics</Trans>
-        </Text>
-        <TouchableOpacity
-          testID="accessibilitySettingsBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={
-            isSwitchingAccounts ? undefined : onPressAccessibilitySettings
-          }
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Accessibility settings`)}
-          accessibilityHint={_(msg`Opens accessibility settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="universal-access"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Accessibility</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="appearanceSettingsBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={isSwitchingAccounts ? undefined : onPressAppearanceSettings}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Appearance settings`)}
-          accessibilityHint={_(msg`Opens appearance settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="paint-roller"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Appearance</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="languageSettingsBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={isSwitchingAccounts ? undefined : onPressLanguageSettings}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Language settings`)}
-          accessibilityHint={_(msg`Opens configurable language settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="language"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Languages</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="moderationBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={
-            isSwitchingAccounts
-              ? undefined
-              : () => navigation.navigate('Moderation')
-          }
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Moderation settings`)}
-          accessibilityHint={_(msg`Opens moderation settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <HandIcon style={pal.text} size={18} strokeWidth={6} />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Moderation</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="preferencesHomeFeedButton"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={openFollowingFeedPreferences}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Following feed preferences`)}
-          accessibilityHint={_(msg`Opens the Following feed preferences`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="sliders"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Following Feed Preferences</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="preferencesThreadsButton"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={openThreadsPreferences}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Thread preferences`)}
-          accessibilityHint={_(msg`Opens the threads preferences`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon={['far', 'comments']}
-              style={pal.text as FontAwesomeIconStyle}
-              size={18}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Thread Preferences</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="savedFeedsBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={onPressSavedFeeds}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`My saved feeds`)}
-          accessibilityHint={_(msg`Opens screen with all saved feeds`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <HashtagIcon style={pal.text} size={18} strokeWidth={3} />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>My Saved Feeds</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="linkToChatSettingsBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={
-            isSwitchingAccounts
-              ? undefined
-              : () => navigation.navigate('MessagesSettings')
-          }
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Chat settings`)}
-          accessibilityHint={_(msg`Opens chat settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon={['far', 'comment-dots']}
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>Chat Settings</Trans>
-          </Text>
-        </TouchableOpacity>
-
-        <View style={styles.spacer20} />
-
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Privacy</Trans>
-        </Text>
-
-        <TouchableOpacity
-          testID="externalEmbedsBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={
-            isSwitchingAccounts
-              ? undefined
-              : () => navigation.navigate('PreferencesExternalEmbeds')
-          }
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`External media settings`)}
-          accessibilityHint={_(msg`Opens external embeds settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon={['far', 'circle-play']}
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>External Media Preferences</Trans>
-          </Text>
-        </TouchableOpacity>
-
-        <View style={styles.spacer20} />
-
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Advanced</Trans>
-        </Text>
-        <TouchableOpacity
-          testID="appPasswordBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={onPressAppPasswords}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`App password settings`)}
-          accessibilityHint={_(msg`Opens the app password settings`)}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="lock"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text}>
-            <Trans>App Passwords</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="changeHandleBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={isSwitchingAccounts ? undefined : onPressChangeHandle}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Change handle`)}
-          accessibilityHint={_(
-            msg`Opens modal for choosing a new Bluesky handle`,
-          )}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="at"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text} numberOfLines={1}>
-            <Trans>Change Handle</Trans>
-          </Text>
-        </TouchableOpacity>
-        {isNative && (
-          <View style={[pal.view, styles.toggleCard]}>
-            <ToggleButton
-              type="default-light"
-              label={_(msg`Open links with in-app browser`)}
-              labelType="lg"
-              isSelected={inAppBrowserPref ?? false}
-              onPress={() => setUseInAppBrowser(!inAppBrowserPref)}
-            />
-          </View>
-        )}
-        <View style={styles.spacer20} />
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Two-factor authentication</Trans>
-        </Text>
-        <View style={[pal.view, styles.toggleCard]}>
-          <Email2FAToggle />
-        </View>
-        <View style={styles.spacer20} />
-        <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          <Trans>Account</Trans>
-        </Text>
-        <TouchableOpacity
-          testID="changePasswordBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={() => openModal({name: 'change-password'})}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Change password`)}
-          accessibilityHint={_(
-            msg`Opens modal for changing your Bluesky password`,
-          )}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="lock"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text} numberOfLines={1}>
-            <Trans>Change Password</Trans>
-          </Text>
-        </TouchableOpacity>
-        <TouchableOpacity
-          testID="exportRepositoryBtn"
-          style={[
-            styles.linkCard,
-            pal.view,
-            isSwitchingAccounts && styles.dimmed,
-          ]}
-          onPress={isSwitchingAccounts ? undefined : onPressExportRepository}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Export my data`)}
-          accessibilityHint={_(
-            msg`Opens modal for downloading your Bluesky account data (repository)`,
-          )}>
-          <View style={[styles.iconContainer, pal.btn]}>
-            <FontAwesomeIcon
-              icon="download"
-              style={pal.text as FontAwesomeIconStyle}
-            />
-          </View>
-          <Text type="lg" style={pal.text} numberOfLines={1}>
-            <Trans>Export My Data</Trans>
-          </Text>
-        </TouchableOpacity>
-
-        <TouchableOpacity
-          style={[pal.view, styles.linkCard]}
-          onPress={onPressDeactivateAccount}
-          accessible={true}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Deactivate account`)}
-          accessibilityHint={_(
-            msg`Opens modal for account deactivation confirmation`,
-          )}>
-          <View style={[styles.iconContainer, dangerBg]}>
-            <FontAwesomeIcon
-              icon={'users-slash'}
-              style={dangerText as FontAwesomeIconStyle}
-              size={18}
-            />
-          </View>
-          <Text type="lg" style={dangerText}>
-            <Trans>Deactivate my account</Trans>
-          </Text>
-        </TouchableOpacity>
-        <DeactivateAccountDialog control={deactivateAccountControl} />
-
-        <TouchableOpacity
-          style={[pal.view, styles.linkCard]}
-          onPress={onPressDeleteAccount}
-          accessible={true}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Delete account`)}
-          accessibilityHint={_(
-            msg`Opens modal for account deletion confirmation. Requires email code`,
-          )}>
-          <View style={[styles.iconContainer, dangerBg]}>
-            <FontAwesomeIcon
-              icon={['far', 'trash-can']}
-              style={dangerText as FontAwesomeIconStyle}
-              size={18}
-            />
-          </View>
-          <Text type="lg" style={dangerText}>
-            <Trans>Delete My Account…</Trans>
-          </Text>
-        </TouchableOpacity>
-        <View style={styles.spacer20} />
-        <TouchableOpacity
-          style={[pal.view, styles.linkCardNoIcon]}
-          onPress={onPressSystemLog}
-          accessibilityRole="button"
-          accessibilityLabel={_(msg`Open system log`)}
-          accessibilityHint={_(msg`Opens the system log page`)}>
-          <Text type="lg" style={pal.text}>
-            <Trans>System log</Trans>
-          </Text>
-        </TouchableOpacity>
-        {__DEV__ ? (
-          <>
-            <TouchableOpacity
-              style={[pal.view, styles.linkCardNoIcon]}
-              onPress={onPressStorybook}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Open storybook page`)}
-              accessibilityHint={_(msg`Opens the storybook page`)}>
-              <Text type="lg" style={pal.text}>
-                <Trans>Storybook</Trans>
-              </Text>
-            </TouchableOpacity>
-            <TouchableOpacity
-              style={[pal.view, styles.linkCardNoIcon]}
-              onPress={onPressDebugModeration}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Open storybook page`)}
-              accessibilityHint={_(msg`Opens the storybook page`)}>
-              <Text type="lg" style={pal.text}>
-                <Trans>Debug Moderation</Trans>
-              </Text>
-            </TouchableOpacity>
-            <TouchableOpacity
-              style={[pal.view, styles.linkCardNoIcon]}
-              onPress={onPressResetPreferences}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Reset preferences state`)}
-              accessibilityHint={_(msg`Resets the preferences state`)}>
-              <Text type="lg" style={pal.text}>
-                <Trans>Reset preferences state</Trans>
-              </Text>
-            </TouchableOpacity>
-            <TouchableOpacity
-              style={[pal.view, styles.linkCardNoIcon]}
-              onPress={() => onPressDeleteChatDeclaration()}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Delete chat declaration record`)}
-              accessibilityHint={_(msg`Deletes the chat declaration record`)}>
-              <Text type="lg" style={pal.text}>
-                <Trans>Delete chat declaration record</Trans>
-              </Text>
-            </TouchableOpacity>
-            <TouchableOpacity
-              style={[pal.view, styles.linkCardNoIcon]}
-              onPress={onPressResetOnboarding}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Reset onboarding state`)}
-              accessibilityHint={_(msg`Resets the onboarding state`)}>
-              <Text type="lg" style={pal.text}>
-                <Trans>Reset onboarding state</Trans>
-              </Text>
-            </TouchableOpacity>
-            <TouchableOpacity
-              style={[pal.view, styles.linkCardNoIcon]}
-              onPress={clearAllStorage}
-              accessibilityRole="button"
-              accessibilityLabel={_(msg`Clear all storage data`)}
-              accessibilityHint={_(msg`Clears all storage data`)}>
-              <Text type="lg" style={pal.text}>
-                <Trans>Clear all storage data (restart after this)</Trans>
-              </Text>
-            </TouchableOpacity>
-          </>
-        ) : null}
-        <View style={[styles.footer]}>
-          <TouchableOpacity
-            accessibilityRole="button"
-            onPress={onPressBuildInfo}>
-            <Text type="sm" style={[styles.buildInfo, pal.textLight]}>
-              <Trans>
-                Version {appVersion} {bundleInfo}
-              </Trans>
-            </Text>
-          </TouchableOpacity>
-        </View>
-
-        <View
-          style={[
-            {flexWrap: 'wrap', gap: 12, paddingHorizontal: 18},
-            s.flexRow,
-          ]}>
-          <TextLink
-            type="md"
-            style={pal.link}
-            href="https://bsky.social/about/support/tos"
-            text={_(msg`Terms of Service`)}
-          />
-          <TextLink
-            type="md"
-            style={pal.link}
-            href="https://bsky.social/about/support/privacy-policy"
-            text={_(msg`Privacy Policy`)}
-          />
-          <TextLink
-            type="md"
-            style={pal.link}
-            href={STATUS_PAGE_URL}
-            text={_(msg`Status Page`)}
-          />
-        </View>
-        <View style={s.footerSpacer} />
-      </ScrollView>
-    </Layout.Screen>
-  )
-}
-
-function EmailConfirmationNotice() {
-  const pal = usePalette('default')
-  const palInverted = usePalette('inverted')
-  const {_} = useLingui()
-  const {isMobile} = useWebMediaQueries()
-  const verifyEmailDialogControl = useDialogControl()
-
-  return (
-    <View style={{marginBottom: 20}}>
-      <Text type="xl-bold" style={[pal.text, styles.heading]}>
-        <Trans>Verify email</Trans>
-      </Text>
-      <View
-        style={[
-          {
-            paddingVertical: isMobile ? 12 : 0,
-            paddingHorizontal: 18,
-          },
-          pal.view,
-        ]}>
-        <View style={{flexDirection: 'row', marginBottom: 8}}>
-          <Pressable
-            style={[
-              palInverted.view,
-              {
-                flexDirection: 'row',
-                gap: 6,
-                borderRadius: 6,
-                paddingHorizontal: 12,
-                paddingVertical: 10,
-                alignItems: 'center',
-              },
-              isMobile && {flex: 1},
-            ]}
-            accessibilityRole="button"
-            accessibilityLabel={_(msg`Verify my email`)}
-            accessibilityHint={_(msg`Opens modal for email verification`)}
-            onPress={() => verifyEmailDialogControl.open()}>
-            <FontAwesomeIcon
-              icon="envelope"
-              color={palInverted.colors.text}
-              size={16}
-            />
-            <Text type="button" style={palInverted.text}>
-              <Trans>Verify My Email</Trans>
-            </Text>
-          </Pressable>
-        </View>
-        <Text style={pal.textLight}>
-          <Trans>Protect your account by verifying your email.</Trans>
-        </Text>
-      </View>
-      <VerifyEmailDialog control={verifyEmailDialogControl} />
-    </View>
-  )
-}
-
-const styles = StyleSheet.create({
-  dimmed: {
-    opacity: 0.5,
-  },
-  spacer20: {
-    height: 20,
-  },
-  heading: {
-    paddingHorizontal: 18,
-    paddingBottom: 6,
-  },
-  infoLine: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingHorizontal: 18,
-    paddingBottom: 6,
-  },
-  profile: {
-    flexDirection: 'row',
-    marginVertical: 6,
-    borderRadius: 4,
-    paddingVertical: 10,
-    paddingHorizontal: 10,
-  },
-  linkCard: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingVertical: 12,
-    paddingHorizontal: 18,
-    marginBottom: 1,
-  },
-  linkCardNoIcon: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    paddingVertical: 20,
-    paddingHorizontal: 18,
-    marginBottom: 1,
-  },
-  toggleCard: {
-    paddingVertical: 8,
-    paddingHorizontal: 6,
-    marginBottom: 1,
-  },
-  avi: {
-    marginRight: 12,
-  },
-  iconContainer: {
-    alignItems: 'center',
-    justifyContent: 'center',
-    width: 40,
-    height: 40,
-    borderRadius: 30,
-    marginRight: 12,
-  },
-  buildInfo: {
-    paddingVertical: 8,
-  },
-
-  colorModeText: {
-    marginLeft: 10,
-    marginBottom: 6,
-  },
-
-  selectableBtns: {
-    flexDirection: 'row',
-  },
-
-  btn: {
-    flexDirection: 'row',
-    alignItems: 'center',
-    justifyContent: 'center',
-    width: '100%',
-    borderRadius: 32,
-    padding: 14,
-    backgroundColor: colors.gray1,
-  },
-  toggleBtn: {
-    paddingHorizontal: 0,
-  },
-  footer: {
-    flex: 1,
-    flexDirection: 'row',
-    paddingLeft: 18,
-  },
-})